Вот мой оригинальный пост: (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);
}