首页 > 编程语言 >c++设置windons默认输出音频设备

c++设置windons默认输出音频设备

时间:2024-10-12 10:20:26浏览次数:10  
标签:std return hr deviceInfo nullptr c++ 音频设备 windons DeviceInfo

c++设置windons默认输出音频设备

主要功能是控制默认输出的音频设备进行切换。
windows自带的设置

本文主要教导如何使用c++进行控制

代码示例

#include <windows.h>
#include <mmdeviceapi.h>
#include <iostream>
#include <functiondiscoverykeys_devpkey.h>
#include <vector>
#include "PolicyConfig.h"
#include <Propidl.h>

#pragma comment(lib, "ole32.lib")

// 定义设备信息结构
struct DeviceInfo {
    wchar_t* name;
    wchar_t* id;
};

// Helper function to convert wide string to multi-byte string
std::string WStringToString(const std::wstring& wstr) {
    if (wstr.empty()) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}

// 获取设备的ID和名称
DeviceInfo GetDeviceInfo(IMMDevice* device) {
    DeviceInfo deviceInfo;
    deviceInfo.id = nullptr;
    deviceInfo.name = nullptr;

    LPWSTR deviceId = nullptr;
    device->GetId(&deviceId);

    IPropertyStore* pStore = nullptr;
    device->OpenPropertyStore(STGM_READ, &pStore);

    PROPVARIANT varName;
    PropVariantInit(&varName);
    pStore->GetValue(PKEY_Device_FriendlyName, &varName);
    deviceInfo.name = _wcsdup(varName.pwszVal);
    deviceInfo.id = _wcsdup(deviceId);  // 复制ID字符串

    PropVariantClear(&varName);
    pStore->Release();
    CoTaskMemFree(deviceId);  // 释放获取到的设备ID内存

    return deviceInfo;
}

// 获取当前默认音频播放设备的ID和名称
DeviceInfo GetCurrentDefaultAudioDevice() {
    IMMDeviceEnumerator* pEnum = nullptr;
    CoInitialize(nullptr);
    HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnum);
    if (FAILED(hr)) return { nullptr, nullptr };

    IMMDevice* pDefDevice = nullptr;
    hr = pEnum->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDefDevice);
    DeviceInfo deviceInfo = { nullptr, nullptr };
    if (SUCCEEDED(hr)) {
        deviceInfo = GetDeviceInfo(pDefDevice);
        pDefDevice->Release();
    }

    pEnum->Release();
    CoUninitialize();
    return deviceInfo;
}

// 获取所有音频输出设备
DeviceInfo* GetAudioOutputDevices(int* count) {
    std::vector<DeviceInfo> deviceList;
    HRESULT hr = CoInitialize(nullptr);
    if (FAILED(hr)) return nullptr;

    IMMDeviceEnumerator* pEnumerator = nullptr;
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
    if (FAILED(hr)) {
        CoUninitialize();
        return nullptr;
    }

    IMMDeviceCollection* pCollection = nullptr;
    hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);
    if (FAILED(hr)) {
        pEnumerator->Release();
        CoUninitialize();
        return nullptr;
    }

    UINT deviceCount;
    pCollection->GetCount(&deviceCount);
    *count = deviceCount; // 设置设备数量

    DeviceInfo* devices = new DeviceInfo[deviceCount]; // 动态分配数组

    for (UINT i = 0; i < deviceCount; ++i) {
        IMMDevice* pDevice = nullptr;
        hr = pCollection->Item(i, &pDevice);
        if (SUCCEEDED(hr)) {
            devices[i] = GetDeviceInfo(pDevice);
            pDevice->Release();
        }
    }

    pCollection->Release();
    pEnumerator->Release();
    CoUninitialize();
    return devices;
}



// 设置默认音频播放设备
bool SetDefaultAudioPlaybackDevice(LPCWSTR devID) {
    // 初始化 COM 库
    HRESULT comHr = CoInitialize(nullptr);
    if (FAILED(comHr)) {
        std::cerr << "COM库初始化失败,错误代码: " << comHr << std::endl;
        return false;
    }
    IPolicyConfigVista* pPolicyConfig;
    HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient), NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID*)&pPolicyConfig);
    if (SUCCEEDED(hr)) {
        hr = pPolicyConfig->SetDefaultEndpoint(devID, eConsole);
        pPolicyConfig->Release();
        if (FAILED(hr)) {
            std::cout << WStringToString(L"设置默认设备失败,错误代码: ") << hr << std::endl;
        }
        return SUCCEEDED(hr);
    }
    else {
        std::cout << WStringToString( L"创建 PolicyConfig 实例失败,错误代码: ") << hr << std::endl;
    }
    CoUninitialize();
    return false;
}

void FreeDeviceArray(DeviceInfo* devices, int count) {
    for (int i = 0; i < count; i++) {
        free(devices[i].name); // 释放设备名称内存
        free(devices[i].id);   // 释放设备ID内存
    }
    free(devices); // 释放设备数组内存
}

int main() {
    SetConsoleOutputCP(65001); // Set console output code page to UTF-8

    // 获取并显示当前默认设备
    DeviceInfo defaultDevice = GetCurrentDefaultAudioDevice();
    std::cout << WStringToString(L"当前默认音频设备: ") << WStringToString(defaultDevice.name)
        << " (ID: " << WStringToString(defaultDevice.id) << ")" << std::endl;

    // 获取可用设备列表
    int deviceCount;
    DeviceInfo* devices = GetAudioOutputDevices(&deviceCount);
    std::cout << WStringToString(L"可用音频输出设备:") << std::endl;

    for (int i = 0; i < deviceCount; ++i) {
        std::cout << i + 1 << ". " << WStringToString(devices[i].name) << std::endl;
    }

    int choice;
    std::cout << WStringToString(L"选择一个设备编号作为默认设备: ");
    std::cin >> choice;

    if (choice > 0 && choice <= deviceCount) {
        const auto& selectedDevice = devices[choice - 1];

        if (SetDefaultAudioPlaybackDevice(selectedDevice.id)) {
            std::cout << WStringToString(L"已将默认设备设置为: ") << WStringToString(selectedDevice.name) << std::endl;
        }
        else {
            std::cout << WStringToString(L"无法设置默认设备。") << std::endl;
        }
    }
    else {
        std::cout << WStringToString(L"无效选择。") << std::endl;
    }

    // 释放设备信息内存
    free(defaultDevice.name);  // 释放默认设备名称内存
    free(defaultDevice.id);    // 释放默认设备ID内存
    FreeDeviceArray(devices, deviceCount); // 释放设备数组内存

    return 0;
}

函数功能

GetCurrentDefaultAudioDevice: 获取当前默认音频播放设备的ID和名称。

GetAudioOutputDevices: 获取所有音频输出设备。

SetDefaultAudioPlaybackDevice: 设置默认音频播放设备。

这里引用了一个.h文件

#include “PolicyConfig.h”
CSDN下载地址

公众号搜索【牛马技术】回复音频领取 PolicyConfig.h

已经打包DLL出来,下载地址如下

DLL下载地址

标签:std,return,hr,deviceInfo,nullptr,c++,音频设备,windons,DeviceInfo
From: https://blog.csdn.net/qq_34147283/article/details/142868611

相关文章

  • C++指针的基本使用
    目录一、定义和使用二、指针占用的空间三、空指针和野指针1、空指针2、野指针四、const修饰指针五、指针和数组六、指针和函数七、结构体指针一、定义和使用指针变量定义语法:数据类型*变量名;intmain(){ //1、指针的定义 inta=10;//定义整型变量a ......
  • 南沙C++信奥赛陈老师解一本通题 1939:【07NOIP普及组】纪念品分组
    ​ 【题目描述】元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完......
  • 蓝桥杯真题 穿越时空之门(第十五届蓝桥杯省赛PythonB组A题) c++题解
    问题如下(附链接):穿越时空之门题解代码如下:#include<iostream>usingnamespacestd;intx1(inti){inta=0;while(i){a+=i%2;i/=2;}returna;}intx2(inti){intb=0;while(i){b+=i%4;i/=4;}returnb;}intmain()......
  • C++ 类(1)
    1.什么是类在C语言中,我们学过结构体,我们可以在结构体里面定义变量在C++中,我们还可以在结构体里面定义函数structAdd{inta;charb;doublec;int&cal(inta,intb){a=a+b;returna;}};intmain(void)......
  • 实验1 现代C++编程初体验
    实验1:task.cpp1#include<iostream>2#include<string>3#include<vector>4#include<algorithm>5usingnamespacestd;67template<typenameT>8voidoutput(constT&c);910voidtest1();11voidtest2();......
  • c++游戏——四子棋
    欢迎各位点赞和评论,若有问题,欢迎提出Code#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<iomanip>#include<termio.h>usingnamespacestd;constintBLACK=1;constintWHI......
  • C++入门教程
    C++入门教程----------------------------------------------------------一.初识C++---------------------------------------------------------1.什么是C++.c++是一种较为基础的编程语言,虽然没有Python,Scratch那么高级,但是它应用范围很广.不论是信息奥赛还是国......
  • C++常用库函数
    大小写转换islower/isupper函数用于检查一个字符是否为小写或大小字母,需要包含头文件<cctype>,也可以包含万能头文件<bits/stdc++.h>.函数返回值类型为bool类型。intmain(){ charch1='A'; charch2='b'; //使用islower函数判断是否为小写字母 if(islower......
  • 【C++】模板进阶
    【C++】模板进阶一.非类型模板参数二.模板的特化函数模板特化函数模板的特化步骤:类模板特化1.全特化2.偏特化(1)部分特化(2)参数更进一步的限制三.模板分离编译1.什么是分离编译2.模板的分离编译3.解决方法四.模板总结一.非类型模板参数模板参数分为:类类......
  • VS2019/2022配置C++ OpenCV4.10.0环境
    一、下载opencv4.10.0官网链接:https://opencv.org/ 安装的时候记住安装路径,本人安装到E盘 二、新建C++项目1、本人新建C++/CLR.Netframework项目 2、右击打开C++项目属性2.1、添加包含目录 此处本人配置的是绝对地址,拷贝build文件夹到程序目录,然后配置相对地......