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

一、注意事项

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 

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(&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& 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(&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& 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(&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;
}

 

你可能感兴趣的:(VC++,音频)