Вот мой оригинальный пост: (https://stackoverflow.com/questions/54817865/what-is-this-sidetone-setting-on-my-playback-device) Он был помечен на StackOverflow как не относящийся к теме, потому что это не программирование Они рекомендовали мне опубликовать здесь.

Я использую Core Audio API Windows (https://docs.microsoft.com/en-us/windows/desktop/CoreAudio/core-audio-apis-in-windows-vista) для управления настройками звука для обработки аудио / анализ приложения. Ниже моя модифицированная версия WalkTreeBackwardsFromPart. Я могу управлять настройкой боковых тонов из API, но я не знаю, что это на самом деле. Если это делает то, что я думаю, это может быть полезно для меня. Похоже, что это не то же самое, что настройка "прослушать это устройство". См. Строку 204, где я отключаю настройку. Благодарю.

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <mmdeviceapi.h>
#include <devicetopology.h>
#include <vector>

using namespace std;

struct AudioNode
{
    LPWSTR name;
    AudioNode *parent;
    vector<AudioNode *>children;
};

AudioNode *newAudioNode(LPWSTR name) {
    AudioNode *temp = new AudioNode;
    temp->name = name;
    temp->parent = NULL;
    return temp;
}

AudioNode *audioTreeHead;
//AudioNode *audioTreeCurrNode;

HRESULT WalkTreeBackwardsFromPart(IPart *pPart, EDataFlow deviceType, AudioNode *audioTreeCurrNode, int iTabLevel = 0);
//HRESULT DisplayVolume(IAudioVolumeLevel *pVolume, int iTabLevel);
HRESULT DisplayMute(IAudioMute *pMute, int iTabLevel);
int SetDeviceVolume(EDataFlow deviceType, float vol);
void Tab(int iTabLevel);

int __cdecl main(void) {
    //float volumes[] = {0, 5, 10, 15}
    printf("capture\n");
    int result = SetDeviceVolume(eCapture, -20);
    printf("render\n");
    result = SetDeviceVolume(eRender, -20);
    system("pause");
    return 0;
}

//HRESULT DisplayVolume(IAudioVolumeLevel *pVolume, int iTabLevel) {
//
//}

int SetDeviceVolume(EDataFlow deviceType, float vol) {
    audioTreeHead = newAudioNode(L"");
    AudioNode *audioTreeCurrNode = audioTreeHead;

    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(deviceType, 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, deviceType, audioTreeCurrNode);
    if (FAILED(hr)) {
        printf("Couldn't walk the tree: hr = 0x%08x\n", hr);
        pPart->Release();
        CoUninitialize();
        return __LINE__;
    }
    pPart->Release();

    CoUninitialize();

    return 0;
}

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

    LPWSTR pwszPartName = NULL;
    hr = pPart->GetName(&pwszPartName);
    if (FAILED(hr)) {
        Tab(iTabLevel);
        printf("Could not get part name: hr = 0x%08x\n", hr);
        return hr;
    }
    Tab(iTabLevel);
    printf("Part name: %ws\n", *pwszPartName ? pwszPartName : L"(Unnamed)");
    AudioNode * tempNode = newAudioNode(pwszPartName);
    //CoTaskMemFree(pwszPartName);
    tempNode->parent = audioTreeCurrNode;
    audioTreeCurrNode->children.push_back(tempNode);
    audioTreeCurrNode = tempNode;
    audioTreeCurrNode->name = pwszPartName;
    if (audioTreeCurrNode->parent != NULL) {
        Tab(iTabLevel);
        printf("my parent: %ws\n", audioTreeCurrNode->parent->name);
        if (audioTreeCurrNode->parent->parent != NULL) {
            Tab(iTabLevel);
            printf("my parent of parent: %ws\n", audioTreeCurrNode->parent->parent->name);
        }
    }
    else {
        Tab(iTabLevel);
        printf("parent is NULL!\n");
    }
    if (wcscmp(audioTreeCurrNode->name, L"Mute") == 0 &&
        audioTreeCurrNode->parent != NULL && audioTreeCurrNode->parent->parent != NULL &&
        wcscmp(audioTreeCurrNode->parent->name, L"Volume") == 0 &&
        wcscmp(audioTreeCurrNode->parent->parent->name, L"SuperMix") == 0) {
            Tab(iTabLevel);
            printf("found the mute I want!\n");
            Tab(iTabLevel);
            printf("parent: %ws\n", audioTreeCurrNode->parent->name);
            Tab(iTabLevel);
            printf("parent of parent: %ws\n", audioTreeCurrNode->parent->parent->name);
            Tab(iTabLevel);
            printf("muting passthrough...\n");

            const IID IID_IAudioMute = __uuidof(IAudioMute);
            IAudioMute *muteControl = NULL;
            hr = pPart->Activate(CLSCTX_ALL, IID_IAudioMute, (void**)&muteControl);
            if (E_NOINTERFACE == hr) {
                Tab(iTabLevel);
                printf("NO MUTE CONTROL\n");
            }
            else if (FAILED(hr)) {
                Tab(iTabLevel);
                printf("Unexpected failure trying to activate IAudioMute : hr = 0x%08x\n", hr);
                return hr;
            }
            else {
                Tab(iTabLevel);
                printf("HAS MUTE CONTROL\n");
                //LPCGUID pguidEventContext;
                BOOL muted;
                muteControl->SetMute(TRUE, NULL);
                muteControl->GetMute(&muted);
                Tab(iTabLevel);
                printf("%s\n", muted ? "MUTED" : "NOT MUTED");
            }
    }


    // 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) {
        Tab(iTabLevel);
        printf("NO AGC CONTROL\n");
        // not a Microphone node
    }
    else if (FAILED(hr)) {
        Tab(iTabLevel);
        printf("Unexpected failure trying to activate IAudioAutoGainControl : hr = 0x%08x\n", hr);
        return hr;
    }
    else {
        // it's an AGC node...
        Tab(iTabLevel);
        printf("HAS AGC CONTROL\n");
        aGCcontrol->SetEnabled(0, NULL);   //Disable it

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

        aGCcontrol->Release();
    }

    // Check Volume Settings
    const IID IID_IAudioVolumeLevel = __uuidof(IAudioVolumeLevel);

    IAudioVolumeLevel *volControl = NULL;
    hr = pPart->Activate(CLSCTX_ALL, IID_IAudioVolumeLevel, (void**)&volControl);
    if (E_NOINTERFACE == hr) {
        Tab(iTabLevel);
        printf("NO VOLUME CONTROL\n");
        // not a volume control
    }
    else if (FAILED(hr)) {
        Tab(iTabLevel);
        printf("Unexpected failure trying to activate IAudioVolumeLevel : hr = 0x%08x\n", hr);
        return hr;
    }
    else {
        // it's a volume control node
        Tab(iTabLevel);
        printf("HAS VOLUME CONTROL\n");
        UINT numChannels;
        float pfLevelDB;
        float minLevel;
        float maxLevel;
        float stepLevel;
        volControl->GetChannelCount(&numChannels);
        for (int i = 0; i < numChannels; i++) {
            volControl->GetLevel(i + 1, &pfLevelDB);
            volControl->GetLevelRange(i, &minLevel, &maxLevel, &stepLevel);
            Tab(iTabLevel);
            printf("Volume Level on %d: %f\n", i, pfLevelDB);
            Tab(iTabLevel);
            printf("Volume range: %f to %f steps of %f\n", minLevel, maxLevel, stepLevel);
        }
    }

    // get the list of incoming parts
    IPartsList *pOutgoingParts = NULL;
    if (deviceType == eCapture) {
        hr = pPart->EnumPartsOutgoing(&pOutgoingParts);
    }
    else {
        hr = pPart->EnumPartsIncoming(&pOutgoingParts);
    }


    if (E_NOTFOUND == hr) {
        return 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)) {
        return 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, deviceType, audioTreeCurrNode, iTabLevel + 1);
        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;
}

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

0