继续使用WASAPI获取Windows系统音频设备列表
获取默认扬声器或麦克风
int device_audios::get_default(bool input, std::string & id, std::string & name)
{
com_initialize com_obj;
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> device_enumerator = nullptr;
Microsoft::WRL::ComPtr<IMMDevice> device = nullptr;
Microsoft::WRL::ComPtr<IMMDeviceCollection> collection = nullptr;
LPWSTR current_device_id = NULL;
std::shared_ptr<void> raii_ptr(nullptr, [&](void*) {
collection = nullptr;
device = nullptr;
device_enumerator = nullptr;
});
int ret = AE_NO;
do {
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator), (void**)device_enumerator.GetAddressOf());
if (FAILED(hr)) {
ret = AE_CO_CREATE_FAILED;
break;
}
hr = device_enumerator->GetDefaultAudioEndpoint(input == true ? eCapture : eRender, eConsole, device.GetAddressOf());
if (FAILED(hr)) {
ret = AE_CO_GETENDPOINT_FAILED;
break;
}
hr = device_enumerator->EnumAudioEndpoints(input == true ? eCapture : eRender, DEVICE_STATE_ACTIVE, collection.GetAddressOf());
if (FAILED(hr)) {
ret = AE_CO_ENUMENDPOINT_FAILED;
break;
}
UINT count;
hr = collection->GetCount(&count);
if (FAILED(hr)) {
ret = AE_CO_GET_ENDPOINT_COUNT_FAILED;
break;
}
hr = device->GetId(¤t_device_id);
if (FAILED(hr)) {
ret = AE_CO_GET_ENDPOINT_ID_FAILED;
break;
}
id = utils_string::unicode_utf8(current_device_id);
CoTaskMemFree(current_device_id);
IPropertyStore *pPropertyStore = NULL;
PROPVARIANT pv;
PropVariantInit(&pv);
hr = device->OpenPropertyStore(STGM_READ, &pPropertyStore);
if (FAILED(hr)) {
ret = AE_CO_OPEN_PROPERTY_FAILED;
break;
}
hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
if (FAILED(hr)) {
ret = AE_CO_GET_VALUE_FAILED;
break;
}
if (pv.vt == VT_LPWSTR) {
name = utils_string::unicode_utf8(pv.pwszVal);
}
else if (pv.vt == VT_LPSTR) {
name = utils_string::ascii_utf8(pv.pszVal);
}
PropVariantClear(&pv);
} while (0);
if (ret != AE_NO)
al_debug("get_devices failed(%ld): %s", GetLastError(), err2str(ret));
return ret;
}
获取扬声器或麦克风列表
int device_audios::get_devices(bool input, std::list<DEVICE_AUDIOS>& devices)
{
com_initialize com_obj;
devices.clear();
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> device_enumerator = nullptr;
Microsoft::WRL::ComPtr<IMMDevice> device = nullptr;
Microsoft::WRL::ComPtr<IMMDeviceCollection> collection = nullptr;
LPWSTR current_device_id = NULL;
int ret = AE_NO;
do {
std::shared_ptr<void> raii_ptr(nullptr, [&](void*) {
collection = nullptr;
device = nullptr;
device_enumerator = nullptr;
});
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator), (void**)device_enumerator.GetAddressOf());
if (FAILED(hr)) {
ret = AE_CO_CREATE_FAILED;
break;
}
hr = device_enumerator->GetDefaultAudioEndpoint(input == true ? eCapture : eRender, eConsole, device.GetAddressOf());
if (FAILED(hr)) {
ret = AE_CO_GETENDPOINT_FAILED;
break;
}
hr = device_enumerator->EnumAudioEndpoints(input == true ? eCapture : eRender, DEVICE_STATE_ACTIVE, collection.GetAddressOf());
if (FAILED(hr)) {
ret = AE_CO_ENUMENDPOINT_FAILED;
break;
}
UINT count;
hr = collection->GetCount(&count);
if (FAILED(hr)) {
ret = AE_CO_GET_ENDPOINT_COUNT_FAILED;
break;
}
hr = device->GetId(¤t_device_id);
if (FAILED(hr)) {
ret = AE_CO_GET_ENDPOINT_ID_FAILED;
break;
}
std::string default_id = utils_string::unicode_utf8(current_device_id);
CoTaskMemFree(current_device_id);
for (int i = 0; i < count; ++i) {
IMMDevice* pEndpointDevice = NULL;
IDeviceTopology* deviceTopology = NULL;
IConnector* connector = NULL;
IPropertyStore *pPropertyStore = NULL;
PROPVARIANT pv;
PropVariantInit(&pv);
LPWSTR device_name = NULL;
LPWSTR device_id = NULL;
std::string str_name, str_id, str_friendly;
hr = collection->Item(i, &pEndpointDevice);
if (FAILED(hr)) continue;
/*hr = pEndpointDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_INPROC_SERVER, NULL,
(LPVOID*)&deviceTopology);
hr = deviceTopology->GetConnector(0, &connector);
hr = connector->GetConnectorIdConnectedTo(&device_name);
str_name = utils_string::unicode_utf8(device_name);*/
hr = pEndpointDevice->GetId(&device_id);
if (FAILED(hr)) continue;
str_id = utils_string::unicode_utf8(device_id);
hr = pEndpointDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
if (FAILED(hr)) continue;
hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
if (FAILED(hr)) {
PropVariantClear(&pv);
continue;
}
if (pv.vt == VT_LPWSTR) {
str_friendly = utils_string::unicode_utf8(pv.pwszVal);
}
else if (pv.vt == VT_LPSTR) {
str_friendly = utils_string::ascii_utf8(pv.pszVal);
}
devices.push_back({
str_id,
str_friendly,
str_id.compare(default_id) == 0
});
PropVariantClear(&pv);
CoTaskMemFree(device_name);
CoTaskMemFree(device_id);
}
} while (0);
//insert a default device both name and id 'Default'
if (ret == AE_NO && devices.size()) {
devices.push_front({
utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_ID),
utils_string::ascii_utf8(DEFAULT_AUDIO_INOUTPUT_NAME),
true
});
}
if (ret != AE_NO)
al_debug("get_devices failed(%ld): %s", GetLastError(), err2str(ret));
return ret;
}
需要注意的是,为了和FFMpeg保持一致,所有字符串传递均采用utf8编码,所以获取设备信息时均通过ascii_utf8函数进行了转换