Windows 7控制麦克风的播放音量

时间:2013-04-07 12:21:36

标签: c# c++ windows-7 microphone naudio

我试图调整麦克风的播放音量;但不幸的是我不能。我可以通过使用NAudio库来控制麦克风的录音音量,但我想控制播放音量。有没有办法控制Windows 7上的麦克风播放音量.C ++或C#解决方案对我来说都是可以接受的。

以下是解决问题的一些尝试:

http://www.computercabal.com/2010/11/mute-microphone-from-c-on-windows.html(这家伙写了一个可以静音麦克风录音音量的小型图书馆)。

NAudio - Cannot set line control mute value(此解决方案只能将麦克风录音音量静音)。

这是通过使用NAudio来解决我的问题的另一个令人沮丧的尝试,这也只是使麦克风录音级别静音:

MMDeviceEnumerator DevEnum = new MMDeviceEnumerator();

MMDeviceCollection devices = DevEnum.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active);

MMDevice micDevice = null;

for (int i = 0; i < devices.Count; i++)
{
    MMDevice deviceAt = devices[i];
    Console.WriteLine(deviceAt.FriendlyName);
    if (deviceAt.FriendlyName.ToLower().StartsWith("mikrofon"))
    {
        micDevice = deviceAt;
    }
}

micDevice.AudioEndpointVolume.Mute = true;

1 个答案:

答案 0 :(得分:3)

我遇到了同样的问题,我通过使用IDeviceTopology界面找到了答案。

我使用了漂浮在网络上的WalkTreeBackwardsFromPart示例。

首先,您必须获取渲染设备(扬声器)的部件。

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;
IMMDeviceCollection *pDevices = NULL;

hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);

UINT  count;
hr = pDevices->GetCount(&count);

// Each loop prints the name of an endpoint device.
for (ULONG i = 0; i < count; i++)
{

        //hr = pEnum->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
    hr = pDevices->Item(i, &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();
}

调用WalkTreeBackwardsFromPart的最后一部分就是魔术发生的地方。

我的测试代码只是通过传入部件找到标有“Front Pink In”的部分(这是麦克风的插孔),当显示音量时,它会设置该部分的音量。这不是最好的代码,但我只是想找到合适的部分。

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);

// see if this is a volume node part
IAudioVolumeLevel *pVolume = NULL;
hr = pPart->Activate(CLSCTX_ALL, __uuidof(IAudioVolumeLevel), (void**)&pVolume);
if (E_NOINTERFACE == hr) {
    // not a volume node
} else if (FAILED(hr)) {
    printf("Unexpected failure trying to activate IAudioVolumeLevel: hr = 0x%08x\n", hr);
    return hr;
} else {
    // it's a volume node...
    hr = DisplayVolume(pVolume, iTabLevel, wcscmp(L"Front Pink In", pwszPartName) == 0);
    if (FAILED(hr)) {
        printf("DisplayVolume failed: hr = 0x%08x", hr);
        pVolume->Release();
        return hr;
    }

    if (wcscmp(L"Microphone Boost", pwszPartName) == 0)
    {
        SetVolume(pVolume);
    }

    pVolume->Release();
}

CoTaskMemFree(pwszPartName);

// see if this is a mute node part
IAudioMute *pMute = NULL;
hr = pPart->Activate(CLSCTX_ALL, __uuidof(IAudioMute), (void**)&pMute);
if (E_NOINTERFACE == hr) {
    // not a mute node
} else if (FAILED(hr)) {
    printf("Unexpected failure trying to activate IAudioMute: hr = 0x%08x\n", hr);
    return hr;
} else {
    // it's a mute node...
    hr = DisplayMute(pMute, iTabLevel);
    if (FAILED(hr)) {
        printf("DisplayMute failed: hr = 0x%08x", hr);
        pMute->Release();
        return hr;
    }

    pMute->Release();
}

// get the list of incoming parts
IPartsList *pIncomingParts = NULL;

//get the list of incoming parts    
//hr = pPart->EnumPartsOutgoing(&pIncomingParts);
hr = pPart->EnumPartsIncoming(&pIncomingParts);
if (E_NOTFOUND == hr) {
    // not an error... we've just reached the end of the path
    Tab(iTabLevel);
    printf("No incoming parts at this part\n");
    return S_OK;
}
else
{

    if (FAILED(hr)) {
        printf("Couldn't enum incoming parts: hr = 0x%08x\n", hr);
        return hr;
    }
    UINT nParts = 0;
    hr = pIncomingParts->GetCount(&nParts);
    if (FAILED(hr)) {
        printf("Couldn't get count of incoming parts: hr = 0x%08x\n", hr);
        pIncomingParts->Release();
        return hr;
    }

    // walk the tree on each incoming part recursively
    for (UINT n = 0; n < nParts; n++) {
        IPart *pIncomingPart = NULL;
        hr = pIncomingParts->GetPart(n, &pIncomingPart);
        if (FAILED(hr)) {
            printf("Couldn't get part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", n, nParts, hr);
            pIncomingParts->Release();
            return hr;
        }

        hr = WalkTreeBackwardsFromPart(pIncomingPart, iTabLevel + 1);
        if (FAILED(hr)) {
            printf("Couldn't walk tree on part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", n, nParts, hr);
            pIncomingPart->Release();
            pIncomingParts->Release();
            return hr;
        }
        pIncomingPart->Release();
    }

    pIncomingParts->Release();
}

return S_OK;
}

HRESULT SetVolume(IAudioVolumeLevel *pVolume)
{
HRESULT hr = S_OK;
UINT nChannels = 0;

hr = pVolume->SetLevel(0,20.0,NULL);
return hr;
}

HRESULT DisplayVolume(IAudioVolumeLevel *pVolume, int iTabLevel, bool setVolume) {
HRESULT hr = S_OK;
UINT nChannels = 0;

hr = pVolume->GetChannelCount(&nChannels);

if (FAILED(hr)) {
    printf("GetChannelCount failed: hr = %08x\n", hr);
    return hr;
}

for (UINT n = 0; n < nChannels; n++) {
    float fMinLevelDB, fMaxLevelDB, fStepping, fLevelDB;

    hr = pVolume->GetLevelRange(n, &fMinLevelDB, &fMaxLevelDB, &fStepping);
    if (FAILED(hr)) {
        printf("GetLevelRange failed: hr = 0x%08x\n", hr);
        return hr;
    }

    hr = pVolume->GetLevel(n, &fLevelDB);
    if (FAILED(hr)) {
        printf("GetLevel failed: hr = 0x%08x\n", hr);
        return hr;
    }

    float levetToSet = fMinLevelDB + ((fMaxLevelDB-fMinLevelDB) * 50 /100.0);

    if (setVolume && nChannels == 2)
    {
        if (n == 0)
        {
            hr = pVolume->SetLevel(n, fMinLevelDB,NULL);
        }
        else
        {
            hr = pVolume->SetLevel(n, fMaxLevelDB,NULL);
        }
    }

    Tab(iTabLevel);
    printf(
        "Channel %u volume is %.3f dB (range is %.3f dB to %.3f dB in increments of %.3f dB)\n",
        n, fLevelDB, fMinLevelDB, fMaxLevelDB, fStepping
        );
}

return S_OK;
}

HRESULT DisplayMute(IAudioMute *pMute, int iTabLevel) {
HRESULT hr = S_OK;
BOOL bMuted = FALSE;

hr = pMute->GetMute(&bMuted);

if (FAILED(hr)) {
    printf("GetMute failed: hr = 0x%08x\n", hr);
    return hr;
}

Tab(iTabLevel);
printf("Mute node: %s\n", bMuted ? "MUTED" : "NOT MUTED");

return S_OK;
}

void Tab(int iTabLevel) {
if (0 >= iTabLevel) { return; }
printf("\t");
Tab(iTabLevel - 1);
}

无论如何,当我设置此音量时,它正在改变HD Audio Manager Mic屏幕上的Playback Volume L和R以及音量滑块。