You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++实现Windows音频输入设备监听功能及输出设备配置求助

实现Windows音频输入设备的监听功能(C++)

核心思路

Windows的“监听此设备”功能,需要通过Core Audio API操作音频端点设备的监听属性,而非ChatGPT提到的不存在的PKEY_AudioEndpoint_Enable_Stereo_Mix。核心是为目标输入设备指定关联的输出设备,并启用监听状态。

实现步骤与代码示例

以下是完整的C++实现代码,包含设备枚举、监听设置的核心逻辑:

#include <windows.h>
#include <mmdeviceapi.h>
#include <propsys.h>
#include <functiondiscoverykeys_devpkey.h>
#include <iostream>

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

// 获取指定类型的设备(输入/输出)的ID
HRESULT GetDeviceID(EDataFlow deviceFlow, LPCWSTR deviceName, LPWSTR& deviceID)
{
    HRESULT hr = CoInitialize(nullptr);
    if (FAILED(hr)) return hr;

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

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

    UINT count = 0;
    hr = pCollection->GetCount(&count);
    if (FAILED(hr)) { pCollection->Release(); pEnumerator->Release(); CoUninitialize(); return hr; }

    for (UINT i = 0; i < count; i++)
    {
        IMMDevice* pDevice = nullptr;
        hr = pCollection->Item(i, &pDevice);
        if (FAILED(hr)) continue;

        IPropertyStore* pProps = nullptr;
        hr = pDevice->OpenPropertyStore(STGM_READ, &pProps);
        if (FAILED(hr)) { pDevice->Release(); continue; }

        PROPVARIANT varName;
        PropVariantInit(&varName);
        hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
        if (SUCCEEDED(hr) && varName.vt == VT_LPWSTR)
        {
            if (_wcsicmp(varName.pwszVal, deviceName) == 0)
            {
                hr = pDevice->GetId(&deviceID);
                PropVariantClear(&varName);
                pProps->Release();
                pDevice->Release();
                break;
            }
        }
        PropVariantClear(&varName);
        pProps->Release();
        pDevice->Release();
    }

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

// 设置输入设备的监听功能
HRESULT SetListenInFunction(LPCWSTR inputDeviceID, LPCWSTR outputDeviceID, BOOL enable)
{
    HRESULT hr = CoInitialize(nullptr);
    if (FAILED(hr)) return hr;

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

    IMMDevice* pInputDevice = nullptr;
    hr = pEnumerator->GetDevice(inputDeviceID, &pInputDevice);
    if (FAILED(hr)) { pEnumerator->Release(); CoUninitialize(); return hr; }

    IPropertyStore* pProps = nullptr;
    hr = pInputDevice->OpenPropertyStore(STGM_READWRITE, &pProps);
    if (FAILED(hr)) { pInputDevice->Release(); pEnumerator->Release(); CoUninitialize(); return hr; }

    // 设置监听的目标输出设备ID
    PROPVARIANT varOutputID;
    PropVariantInit(&varOutputID);
    varOutputID.vt = VT_LPWSTR;
    varOutputID.pwszVal = const_cast<LPWSTR>(outputDeviceID);
    hr = pProps->SetValue(PKEY_AudioEndpoint_ListenToDevice, varOutputID);
    if (FAILED(hr)) { PropVariantClear(&varOutputID); pProps->Release(); pInputDevice->Release(); pEnumerator->Release(); CoUninitialize(); return hr; }
    PropVariantClear(&varOutputID);

    // 启用/禁用监听
    PROPVARIANT varEnable;
    PropVariantInit(&varEnable);
    varEnable.vt = VT_BOOL;
    varEnable.boolVal = enable ? VARIANT_TRUE : VARIANT_FALSE;
    hr = pProps->SetValue(PKEY_AudioEndpoint_EnableListen, varEnable);
    if (FAILED(hr)) { PropVariantClear(&varEnable); pProps->Release(); pInputDevice->Release(); pEnumerator->Release(); CoUninitialize(); return hr; }
    PropVariantClear(&varEnable);

    // 提交属性更改
    hr = pProps->Commit();

    pProps->Release();
    pInputDevice->Release();
    pEnumerator->Release();
    CoUninitialize();
    return hr;
}

int main()
{
    // 示例:设置名为"麦克风"的输入设备,监听输出到"扬声器"
    LPWSTR inputDeviceID = nullptr;
    HRESULT hr = GetDeviceID(eCapture, L"麦克风", inputDeviceID);
    if (FAILED(hr)) { std::cout << "获取输入设备ID失败" << std::endl; return 1; }

    LPWSTR outputDeviceID = nullptr;
    hr = GetDeviceID(eRender, L"扬声器", outputDeviceID);
    if (FAILED(hr)) { CoTaskMemFree(inputDeviceID); std::cout << "获取输出设备ID失败" << std::endl; return 1; }

    hr = SetListenInFunction(inputDeviceID, outputDeviceID, TRUE);
    if (SUCCEEDED(hr))
    {
        std::cout << "监听功能已启用" << std::endl;
    }
    else
    {
        std::cout << "启用监听失败,错误码:" << hr << std::endl;
    }

    CoTaskMemFree(inputDeviceID);
    CoTaskMemFree(outputDeviceID);
    return 0;
}

关键说明

  1. 依赖与编译:需要链接ole32.lib、propsys.lib、mmdevapi.lib,并确保Windows SDK版本支持Core Audio API(Windows 7及以上)。
  2. 设备名称匹配:代码中通过设备友好名称(如"麦克风"、"扬声器")查找设备,你需要根据实际设备名称修改。
  3. 权限问题:普通用户权限通常可修改个人音频设备设置,若操作系统级设备可能需要管理员权限。
  4. 错误处理:代码中保留了HRESULT检查,实际使用时可根据错误码进一步排查问题(如设备不存在、权限不足)。

内容的提问来源于stack exchange,提问作者ZeTr0nIx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:29:59