如何使用C++控制麦克风增强/自动增益控制(AGC)

4

我希望能够控制麦克风输入的增益/自动增益控制(AGC)设置。Windows 7音频属性显示它有一个AGC选项。

但是当我尝试通过C++访问它时,它会返回说该设备上没有AGC。

我正在使用DeviceTopology类,WASAPI没有任何API来控制AGC功能。

目前的代码如下(大部分从MSDN论坛示例中提取):

    #include <windows.h>
    #include <stdio.h>
    #include <mmdeviceapi.h>
    #include <devicetopology.h>

    HRESULT WalkTreeBackwardsFromPart(IPart *pPart, int iTabLevel = 0);
    HRESULT DisplayVolume(IAudioVolumeLevel *pVolume, int iTabLevel);
    HRESULT DisplayMute(IAudioMute *pMute, int iTabLevel);
    void Tab(int iTabLevel);

    int __cdecl main(void) {
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr)) {
        printf("Failed CoInitializeEx: hr = 0x%08x\n", hr);
        return __LINE__;
    }

    // get default render endpoint
    IMMDeviceEnumerator *pEnum = NULL;
    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
        (void**)&pEnum
    );
    if (FAILED(hr)) {
        printf("Couldn't get device enumerator: hr = 0x%08x\n", hr);
        CoUninitialize();
        return __LINE__;
    }
    IMMDevice *pDevice = NULL;
    hr = pEnum->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
    if (FAILED(hr)) {
        printf("Couldn't get default render device: hr = 0x%08x\n", hr);
        pEnum->Release();
        CoUninitialize();
        return __LINE__;
    }
    pEnum->Release();

    // get device topology object for that endpoint
    IDeviceTopology *pDT = NULL;
    hr = pDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, (void**)&pDT);
    if (FAILED(hr)) {
        printf("Couldn't get device topology object: hr = 0x%08x\n", hr);
        pDevice->Release();
        CoUninitialize();
        return __LINE__;
    }
    pDevice->Release();

    // get the single connector for that endpoint
    IConnector *pConnEndpoint = NULL;
    hr = pDT->GetConnector(0, &pConnEndpoint);
    if (FAILED(hr)) {
        printf("Couldn't get the connector on the endpoint: hr = 0x%08x\n", hr);
        pDT->Release();
        CoUninitialize();
        return __LINE__;
    }
    pDT->Release();

    // get the connector on the device that is
    // connected to
    // the connector on the endpoint
    IConnector *pConnDevice = NULL;
    hr = pConnEndpoint->GetConnectedTo(&pConnDevice);
    if (FAILED(hr)) {
        printf("Couldn't get the connector on the device: hr = 0x%08x\n", hr);
        pConnEndpoint->Release();
        CoUninitialize();
        return __LINE__;
    }
    pConnEndpoint->Release();

    // QI on the device's connector for IPart
    IPart *pPart = NULL;
    hr = pConnDevice->QueryInterface(__uuidof(IPart), (void**)&pPart);
    if (FAILED(hr)) {
        printf("Couldn't get the part: hr = 0x%08x\n", hr);
        pConnDevice->Release();
        CoUninitialize();
        return __LINE__;
    }
    pConnDevice->Release();

    // all the real work is done in this function
    hr = WalkTreeBackwardsFromPart(pPart);
    if (FAILED(hr)) {
        printf("Couldn't walk the tree: hr = 0x%08x\n", hr);
        pPart->Release();
        CoUninitialize();
        return __LINE__;
    }
    pPart->Release();

    CoUninitialize();

    system("pause");
    return 0;
    }

    HRESULT WalkTreeBackwardsFromPart(IPart *pPart, int iTabLevel /* = 0 */) {
    HRESULT hr = S_OK;

    Tab(iTabLevel);
    LPWSTR pwszPartName = NULL;
    hr = pPart->GetName(&pwszPartName);
    if (FAILED(hr)) {
        printf("Could not get part name: hr = 0x%08x", hr);
        return hr;
    }
    printf("Part name: %ws\n", *pwszPartName ? pwszPartName : L"(Unnamed)");
    CoTaskMemFree(pwszPartName);


    // Check AGC settings
    const IID IID_IAudioAutoGainControl = __uuidof(IAudioAutoGainControl);

    IAudioAutoGainControl *aGCcontrol = NULL;
    hr = pPart->Activate(CLSCTX_ALL, IID_IAudioAutoGainControl, (void**)&aGCcontrol);
    if (E_NOINTERFACE == hr) {
          printf("NO AGC CONTROL\n");
        // not a Microphone node
    } else if (FAILED(hr)) {
        printf("Unexpected failure trying to activate IAudioAutoGainControl : hr = 0x%08x\n", hr);
        return hr;
    } else {
        // it's an AGC node...
        printf("HAS AGC CONTROL");
        if (FAILED(hr)) {
            printf("AGC Failed: hr = 0x%08x", hr);
            aGCcontrol->Release();
            return hr;
        }

        aGCcontrol->Release();
    }


    return S_OK;
}
1个回答

4

我终于弄清楚了如何做到这一点。在上面的示例代码中,我省略了一些重要部分。

为了帮助其他人解决同样的问题,这里提供解决方案。只需将 MessageBox 语句替换为 printf 即可编译。

这里的重要点是,在枚举零件时务必知道其是否为输入或输出。否则,您永远找不到您要查找的零件。此示例正在查找 eCapture 端点的可用部件。

这是我的来源:http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/9741bae1-c330-4802-9860-2fd202dba797/enumeration-of-available-levels-for-a-specific-installed-sound-card?forum=windowspro-audiodevelopment

如果您在编译时遇到问题,请告诉我。

#include <windows.h>
#include <stdio.h>
#include <mmdeviceapi.h>
#include <devicetopology.h>

HRESULT WalkTreeBackwardsFromPart(IPart *pPart, int iTabLevel = 0);
HRESULT DisplayVolume(IAudioVolumeLevel *pVolume, int iTabLevel);
HRESULT DisplayMute(IAudioMute *pMute, int iTabLevel);
void Tab(int iTabLevel);

int __cdecl main(void) {
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr)) {
    printf("Failed CoInitializeEx: hr = 0x%08x\n", hr);
    return __LINE__;
}

// get default render endpoint
IMMDeviceEnumerator *pEnum = NULL;
hr = CoCreateInstance(
    __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
    (void**)&pEnum
);
if (FAILED(hr)) {
    printf("Couldn't get device enumerator: hr = 0x%08x\n", hr);
    CoUninitialize();
    return __LINE__;
}
IMMDevice *pDevice = NULL;
hr = pEnum->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
if (FAILED(hr)) {
    printf("Couldn't get default capture device: hr = 0x%08x\n", hr);
    pEnum->Release();
    CoUninitialize();
    return __LINE__;
}
pEnum->Release();

// get device topology object for that endpoint
IDeviceTopology *pDT = NULL;
hr = pDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, (void**)&pDT);
if (FAILED(hr)) {
    printf("Couldn't get device topology object: hr = 0x%08x\n", hr);
    pDevice->Release();
    CoUninitialize();
    return __LINE__;
}
pDevice->Release();

// get the single connector for that endpoint
IConnector *pConnEndpoint = NULL;
hr = pDT->GetConnector(0, &pConnEndpoint);
if (FAILED(hr)) {
    printf("Couldn't get the connector on the endpoint: hr = 0x%08x\n", hr);
    pDT->Release();
    CoUninitialize();
    return __LINE__;
}
pDT->Release();

// get the connector on the device that is
// connected to
// the connector on the endpoint
IConnector *pConnDevice = NULL;
hr = pConnEndpoint->GetConnectedTo(&pConnDevice);
if (FAILED(hr)) {
    printf("Couldn't get the connector on the device: hr = 0x%08x\n", hr);
    pConnEndpoint->Release();
    CoUninitialize();
    return __LINE__;
}
pConnEndpoint->Release();

// QI on the device's connector for IPart
IPart *pPart = NULL;
hr = pConnDevice->QueryInterface(__uuidof(IPart), (void**)&pPart);
if (FAILED(hr)) {
    printf("Couldn't get the part: hr = 0x%08x\n", hr);
    pConnDevice->Release();
    CoUninitialize();
    return __LINE__;
}
pConnDevice->Release();

// all the real work is done in this function
hr = WalkTreeBackwardsFromPart(pPart);
if (FAILED(hr)) {
    printf("Couldn't walk the tree: hr = 0x%08x\n", hr);
    pPart->Release();
    CoUninitialize();
    return __LINE__;
}
pPart->Release();

CoUninitialize();

system("pause");
return 0;
}

HRESULT WalkTreeBackwardsFromPart(IPart *pPart) {
HRESULT hr = S_OK;

LPWSTR pwszPartName = NULL;
hr = pPart->GetName(&pwszPartName);
if (FAILED(hr)) {
    printf("Could not get part name: hr = 0x%08x", hr);
    return hr;
}
printf("Part name: %ws\n", *pwszPartName ? pwszPartName : L"(Unnamed)");
CoTaskMemFree(pwszPartName);


// Check AGC settings
const IID IID_IAudioAutoGainControl = __uuidof(IAudioAutoGainControl);

IAudioAutoGainControl *aGCcontrol = NULL;
hr = pPart->Activate(CLSCTX_ALL, IID_IAudioAutoGainControl, (void**)&aGCcontrol);
if (E_NOINTERFACE == hr) {
      printf("NO AGC CONTROL\n");
    // not a Microphone node
} else if (FAILED(hr)) {
    printf("Unexpected failure trying to activate IAudioAutoGainControl : hr = 0x%08x\n", hr);
    return hr;
} else {
    // it's an AGC node...
    printf("HAS AGC CONTROL");
    aGCcontrol->SetEnabled(1, NULL);   //Activate it

    if (FAILED(hr)) {
        printf("AGC Failed: hr = 0x%08x", hr);
        aGCcontrol->Release();
        return hr;
    }

    aGCcontrol->Release();
}

// get the list of incoming parts
IPartsList *pOutgoingParts = NULL;
hr = pPart->EnumPartsOutgoing(&pOutgoingParts);

if (E_NOTFOUND == hr) {
    // not an error... we've just reached the end of the path
    MessageBox("No incoming parts at this part\n", MB_OK);
}
if (FAILED(hr)) {
    MessageBox("Couldn't enum outgoing parts", MB_OK);
}
UINT nParts = 0;
hr = pOutgoingParts->GetCount(&nParts);
if (FAILED(hr)) {
    MessageBox("Couldn't get count of outgoing parts", MB_OK);
    pOutgoingParts->Release();
    return hr;
}

// walk the tree on each incoming part recursively
for (UINT n = 0; n < nParts; n++) {
    IPart *pOutgoingPart = NULL;
    hr = pOutgoingParts->GetPart(n, &pOutgoingPart);
    if (FAILED(hr)) {
        MessageBox("Couldn't get part ", MB_OK);
        pOutgoingParts->Release();
        return hr;
    }

    hr = WalkTreeBackwardsFromPart(pOutgoingPart);
    if (FAILED(hr)) {
        MessageBox("Couldn't walk tree on part", MB_OK);
        pOutgoingPart->Release();
        pOutgoingParts->Release();
        return hr;
    }
    pOutgoingPart->Release();
}

pOutgoingParts->Release();

return S_OK;

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接