FFMPEG录屏(6)---- 获取音频设备列表(WASAPI)


继续使用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(&current_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(&current_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函数进行了转换

GitHub传送门

screen-recorder

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
敬告:该系列的课程在抓紧录制更新中,敬请大家关注。敬告: 该系列的课程涉及:FFmpeg,WebRTC,SRS,Nginx,Darwin,Live555,等。包括:音视频、流媒体、直播、Android、视频监控28181、等。  我将带领大家一起来学习:采集麦克风、PCM重采样、AAC或MP3音频编码存储、并直播。具体内容包括:1.FFmpeg采集麦克风并存储为PCM。2.PCM重采样原理及实战。3.采集麦克风并实时转码AAC或MP3并保存文件。4.采集麦克风并实时转码AAC并可以直播。 音视频与流媒体是一门很复杂的技术,涉及的概念、原理、理论非常多,很多初学者不学 基础理论,而是直接做项目,往往会看到c/c++的代码时一头雾水,不知道代码到底是什么意思,这是为什么呢? 因为没有学习音视频和流媒体的基础理论,就比如学习英语,不学习基本单词,而是天天听英语新闻,总也听不懂。所以呢,一定要认真学习基础理论,然后再学习播放器、转码器、非编、流媒体直播、视频监控、等等。 梅老师从事音视频与流媒体行业18年;曾在永新视博、中科大洋、百度、美国Harris广播事业部等公司就职,经验丰富;曾亲手主导广电直播全套项目,精通h.264/h.265/aac,曾亲自参与百度app上的网页播放器等实战产品。 目前全身心自主创业,主要聚焦音视频+流媒体行业,精通音视频加密、流媒体在线转码快编等热门产品。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值