C++获取Windows音频设备列表

1 篇文章 0 订阅

一、注意事项

1、获取音频设备需要调用CoInitialize以及CoUninitialize。

2、由于C++没有finally关键字,代码中的CUSTOM_FINALLY为自定义宏,是为了实现类似try...catch...finally的效果,本身没有什么意义:

//定义空宏,处理finally
#ifndef CUSTOM_FINALLY
#define CUSTOM_FINALLY
#endif // CUSTOM_FINALLY

3、打印日志宏:

#define PNTLOG(format, ...) wprintf(format L"\n", __VA_ARGS__)
#define PNTERR(format, ...) PNTLOG(L"Error: " format, __VA_ARGS__)
#define PNTERRMSG(msg) wprintf(L"Error: %s \n", msg)

4、PKEY_Device_FriendlyName需要引用相应的头文件:

#include <functiondiscoverykeys_devpkey.h>

5、获取扬声器设备使用eRender枚举类型,获取麦克风设备使用eCapture枚举类型。

二、代码

1、获取默认扬声器

(1)获取设备指针

bool GetDefaultDevice(IMMDevice **ppMMDevice)
{
	bool ret = false;
	IMMDeviceEnumerator *pMMDeviceEnumerator = nullptr;
	wchar_t wszErrMsg[MAX_PATH] = { 0 };

	try
	{
		HRESULT hr = CoCreateInstance(
			__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
			__uuidof(IMMDeviceEnumerator),
			reinterpret_cast<void**>(&pMMDeviceEnumerator)
		);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x", hr);
			throw std::exception();
		}

		// get the default render endpoint
		hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(
			eRender, eConsole, ppMMDevice
		);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"IMMDeviceEnumerator::GetDefaultAudioEndpoint failed: hr = 0x%08x", hr);
			throw std::exception();
		}

		ret = true;
	}
	catch(std::exception&)
	{
		PNTERRMSG(wszErrMsg);
	}

	//释放资源
	CUSTOM_FINALLY
	{
		if (pMMDeviceEnumerator != nullptr)
		{
			pMMDeviceEnumerator->Release();
		}
	}

	return ret;
}

(2)获取设备Id和名称

bool GetDefaultDevice(wstring& deviceId, wstring& deviceName)
{
	IMMDevice* pMMDevice = nullptr;
	if (!GetDefaultDevice(&pMMDevice))
	{
		return false;
	}

	bool ret = true;
	wchar_t wszErrMsg[MAX_PATH] = { 0 };
	HRESULT hr;
	IPropertyStore* pPropertyStore = nullptr;
	PROPVARIANT pv;
	PropVariantInit(&pv);

	try
	{
		LPWSTR pwszDeviceId = nullptr;
		hr = pMMDevice->GetId(&pwszDeviceId);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"IMMDevice::GetId failed: hr = 0x%08x", hr);
			throw;
		}

		// open the property store on that device
		hr = pMMDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"IMMDevice::OpenPropertyStore failed: hr = 0x%08x", hr);
			throw;
		}

		// get the long name property
		hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"IPropertyStore::GetValue failed: hr = 0x%08x", hr);
			throw;
		}

		if (VT_LPWSTR != pv.vt)
		{
			wsprintf(wszErrMsg, L"PKEY_Device_FriendlyName variant type is %u - expected VT_LPWSTR", pv.vt);
			throw;
		}

		deviceId = pwszDeviceId;
		deviceName = pv.pwszVal;
	}
	catch (std::exception&)
	{
		PNTERRMSG(wszErrMsg);
		ret = false;
	}

	//释放资源
	CUSTOM_FINALLY
	{
		if (pMMDevice != nullptr)
		{
			pMMDevice->Release();
		}

		if (pPropertyStore != nullptr)
		{
			pPropertyStore->Release();
		}

		if (pv.vt != VT_EMPTY)
		{
			hr = PropVariantClear(&pv);
			if (FAILED(hr))
			{
				PNTERR(L"PropVariantClear failed: hr = 0x%08x", hr);
				ret = false;
			}
		}
	}

	return ret;
}

2、获取设备列表

bool GetDevices(map<wstring, wstring>& deviceMap)
{
	deviceMap.clear();

	bool ret = false;
	wchar_t wszErrMsg[MAX_PATH] = { 0 };
	IMMDeviceEnumerator *pMMDeviceEnumerator = nullptr;
	IMMDeviceCollection *pMMDeviceCollection = nullptr;	

	try
	{
		HRESULT hr = CoCreateInstance(
			__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
			__uuidof(IMMDeviceEnumerator),
			reinterpret_cast<void**>(&pMMDeviceEnumerator)
		);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x", hr);
			throw std::exception();
		}

		// get all the active render endpoints
		hr = pMMDeviceEnumerator->EnumAudioEndpoints(
			eRender, DEVICE_STATE_ACTIVE, &pMMDeviceCollection
		);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"IMMDeviceEnumerator::EnumAudioEndpoints failed: hr = 0x%08x", hr);
			throw std::exception();
		}

		ret = GetDevices(pMMDeviceCollection, deviceMap);
	}
	catch (std::exception&)
	{
		PNTERRMSG(wszErrMsg);
	}

	//释放资源
	CUSTOM_FINALLY
	{
		if (pMMDeviceEnumerator != nullptr)
		{
			pMMDeviceEnumerator->Release();
		}

		if (pMMDeviceCollection != nullptr)
		{
			pMMDeviceCollection->Release();
		}
	}

	return ret;
}

bool GetDevices(IMMDeviceCollection *pMMDeviceCollection, map<wstring, wstring>& deviceMap)
{
	bool ret = true;
	wchar_t wszErrMsg[MAX_PATH] = { 0 };

	UINT count;
	HRESULT hr = pMMDeviceCollection->GetCount(&count);
	if (FAILED(hr))
	{
		wsprintf(wszErrMsg, L"IMMDeviceCollection::GetCount failed: hr = 0x%08x", hr);
		PNTERRMSG(wszErrMsg);
		return false;
	}
	PNTLOG(L"Active render endpoints found: %u", count);

	for (UINT i = 0; i < count; i++)
	{		
		IMMDevice *pMMDevice = nullptr;
		IPropertyStore *pPropertyStore = nullptr;
		PROPVARIANT pv;
		PropVariantInit(&pv);

		try
		{
			// get the "n"th device
			hr = pMMDeviceCollection->Item(i, &pMMDevice);
			if (FAILED(hr))
			{
				wsprintf(wszErrMsg, L"IMMDeviceCollection::Item failed: hr = 0x%08x", hr);
				throw;
			}

			LPWSTR pwszDeviceId = nullptr;
			hr = pMMDevice->GetId(&pwszDeviceId);
			if (FAILED(hr))
			{
				wsprintf(wszErrMsg, L"IMMDeviceCollection::GetId failed: hr = 0x%08x", hr);
				throw;
			}

			// open the property store on that device
			hr = pMMDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
			if (FAILED(hr))
			{
				wsprintf(wszErrMsg, L"IMMDevice::OpenPropertyStore failed: hr = 0x%08x", hr);
				throw;
			}

			// get the long name property
			hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
			if (FAILED(hr))
			{
				wsprintf(wszErrMsg, L"IPropertyStore::GetValue failed: hr = 0x%08x", hr);
				throw;
			}

			if (VT_LPWSTR != pv.vt)
			{
				wsprintf(wszErrMsg, L"PKEY_Device_FriendlyName variant type is %u - expected VT_LPWSTR", pv.vt);
				throw;
			}

			deviceMap[pwszDeviceId] = pv.pwszVal;

			PNTLOG(L"    %ls", pv.pwszVal);
		}
		catch (std::exception&)
		{
			PNTERRMSG(wszErrMsg);
			ret = false;
		}

		//释放资源
		CUSTOM_FINALLY
		{
			if (pMMDevice != nullptr)
			{
				pMMDevice->Release();
			}

			if (pPropertyStore != nullptr)
			{
				pPropertyStore->Release();
			}

			if (pv.vt != VT_EMPTY)
			{
				hr = PropVariantClear(&pv);
				if (FAILED(hr))
				{
					PNTERR(L"PropVariantClear failed: hr = 0x%08x", hr);
					ret = false;
				}
			}
		}

		//出现异常
		if (!ret)
		{
			break;
		}
	}

	return ret;
}

3、获取指定设备

bool GetSpecificDevice(LPCWSTR pwszLongName, IMMDevice **ppMMDevice)
{
	bool ret = false;
	wchar_t wszErrMsg[MAX_PATH] = { 0 };
	IMMDeviceEnumerator *pMMDeviceEnumerator = nullptr;
	IMMDeviceCollection *pMMDeviceCollection = nullptr;
	*ppMMDevice = nullptr;

	try
	{
		HRESULT hr = CoCreateInstance(
			__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
			__uuidof(IMMDeviceEnumerator),
			reinterpret_cast<void**>(&pMMDeviceEnumerator)
		);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x", hr);
			throw std::exception();
		}

		// get all the active render endpoints
		hr = pMMDeviceEnumerator->EnumAudioEndpoints(
			eRender, DEVICE_STATE_ACTIVE, &pMMDeviceCollection
		);
		if (FAILED(hr))
		{
			wsprintf(wszErrMsg, L"IMMDeviceEnumerator::EnumAudioEndpoints failed: hr = 0x%08x", hr);
			throw std::exception();
		}

		ret = GetSpecificDevice(pMMDeviceCollection, pwszLongName, ppMMDevice);
	}
	catch (std::exception&)
	{
		PNTERRMSG(wszErrMsg);
	}

	//释放资源
	CUSTOM_FINALLY
	{
		if (pMMDeviceEnumerator != nullptr)
		{
			pMMDeviceEnumerator->Release();
		}

		if (pMMDeviceCollection != nullptr)
		{
			pMMDeviceCollection->Release();
		}
	}

	return ret;
}

bool GetSpecificDevice(IMMDeviceCollection *pMMDeviceCollection, LPCWSTR pwszLongName, IMMDevice **ppMMDevice)
{
	bool ret = true;
	wchar_t wszErrMsg[MAX_PATH] = { 0 };

	UINT count;
	HRESULT hr = pMMDeviceCollection->GetCount(&count);
	if (FAILED(hr))
	{
		wsprintf(wszErrMsg, L"IMMDeviceCollection::GetCount failed: hr = 0x%08x", hr);
		PNTERRMSG(wszErrMsg);
		return false;
	}
	PNTLOG(L"Active render endpoints found: %u", count);

	for (UINT i = 0; i < count; i++)
	{
		IMMDevice *pMMDevice = nullptr;
		IPropertyStore *pPropertyStore = nullptr;
		PROPVARIANT pv;
		PropVariantInit(&pv);

		try
		{
			// get the "n"th device
			hr = pMMDeviceCollection->Item(i, &pMMDevice);
			if (FAILED(hr))
			{
				wsprintf(wszErrMsg, L"IMMDeviceCollection::Item failed: hr = 0x%08x", hr);
				throw;
			}

			// open the property store on that device
			hr = pMMDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
			if (FAILED(hr))
			{
				wsprintf(wszErrMsg, L"IMMDevice::OpenPropertyStore failed: hr = 0x%08x", hr);
				throw;
			}

			// get the long name property
			hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
			if (FAILED(hr))
			{
				wsprintf(wszErrMsg, L"IPropertyStore::GetValue failed: hr = 0x%08x", hr);
				throw;
			}

			if (VT_LPWSTR != pv.vt)
			{
				wsprintf(wszErrMsg, L"PKEY_Device_FriendlyName variant type is %u - expected VT_LPWSTR", pv.vt);
				throw;
			}

			// is it a match?
			if (0 == _wcsicmp(pv.pwszVal, pwszLongName))
			{
				// did we already find it?
				if (nullptr == *ppMMDevice)
				{
					*ppMMDevice = pMMDevice;
					pMMDevice->AddRef();
				}
				else
				{
					wsprintf(wszErrMsg, L"Found (at least) two devices named %ls", pwszLongName);
					throw;
				}
			}
		}
		catch (std::exception&)
		{
			PNTERRMSG(wszErrMsg);
			ret = false;
		}

		//释放资源
		CUSTOM_FINALLY
		{
			if (pMMDevice != nullptr)
			{
				pMMDevice->Release();
			}

			if (pPropertyStore != nullptr)
			{
				pPropertyStore->Release();
			}

			if (pv.vt != VT_EMPTY)
			{
				hr = PropVariantClear(&pv);
				if (FAILED(hr))
				{
					PNTERR(L"PropVariantClear failed: hr = 0x%08x", hr);
					ret = false;
				}
			}
		}

		//出现异常
		if (!ret)
		{
			if (*ppMMDevice != nullptr)
			{
				(*ppMMDevice)->Release();
			}
			break;
		}
	}

	if (nullptr == *ppMMDevice)
	{
		PNTERR(L"Could not find a device named %ls", pwszLongName);
	}

	return ret;
}

 

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
可以使用Windows Core Audio API来获取音频播放设备列表。以下是一个使用C++编写的示例代码,可以列出所有音频播放设备的名称: ```c++ #include <Windows.h> #include <Mmdeviceapi.h> #include <Functiondiscoverykeys_devpkey.h> #include <vector> #include <string> #include <iostream> int main() { HRESULT hr = S_OK; IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pCollection = NULL; IMMDevice* pEndpoint = NULL; IPropertyStore* pProps = NULL; LPWSTR pwszID = NULL; // Create a multimedia device enumerator. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); if (FAILED(hr)) { std::cout << "CoCreateInstance failed: hr = 0x" << std::hex << hr << std::endl; return 1; } // Enumerate the audio endpoint devices. hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection); if (FAILED(hr)) { std::cout << "EnumAudioEndpoints failed: hr = 0x" << std::hex << hr << std::endl; pEnumerator->Release(); return 1; } UINT count; pCollection->GetCount(&count); std::vector<std::wstring> deviceNames; // Get the name of each endpoint device. for (ULONG i = 0; i < count; i++) { // Get pointer to endpoint number i. hr = pCollection->Item(i, &pEndpoint); if (FAILED(hr)) { std::cout << "IMMDeviceCollection::Item failed: hr = 0x" << std::hex << hr << std::endl; break; } // Get the endpoint ID string. hr = pEndpoint->GetId(&pwszID); if (FAILED(hr)) { std::cout << "IMMDevice::GetId failed: hr = 0x" << std::hex << hr << std::endl; break; } // Open the properties store. hr = pEndpoint->OpenPropertyStore(STGM_READ, &pProps); if (FAILED(hr)) { std::cout << "IMMDevice::OpenPropertyStore failed: hr = 0x" << std::hex << hr << std::endl; break; } PROPVARIANT varName; // Initialize container for property value. PropVariantInit(&varName); // Get the endpoint's friendly-name property. hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName); if (FAILED(hr)) { std::cout << "IPropertyStore::GetValue failed: hr = 0x" << std::hex << hr << std::endl; break; } // Get the endpoint's friendly name. std::wstring deviceName(varName.pwszVal); deviceNames.push_back(deviceName); // Free the endpoint ID string and property store. CoTaskMemFree(pwszID); pwszID = NULL; pProps->Release(); pProps = NULL; pEndpoint->Release(); pEndpoint = NULL; } // Clean up. pEnumerator->Release(); pCollection->Release(); // Print the list of device names. std::cout << "Audio playback devices:" << std::endl; for (size_t i = 0; i < deviceNames.size(); i++) { std::wcout << " " << deviceNames[i] << std::endl; } return 0; } ``` 这段代码使用了COM接口,需要在程序开头调用`CoInitialize`函数来初始化COM。另外,需要将`uuid.lib`和`ole32.lib`库链接到项目中。 运行此程序,将输出当前电脑上所有的音频播放设备名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值