解决此问题的关键是将设备拓扑树向后走,直到找到负责设置侧音静音属性的部分。所以在我的CPP项目中,我有几种方法一起工作,以确定我在拓扑树中的位置,寻找SuperMix
部分。
SuperMix
似乎是sidetone的通用名称,至少可以用于我们支持的两种耳机。这两个耳机的树相同,你的里程可能会有所不同。这是输出可能如同从上述WalkTreeBackwardsFromPart例子(见this answer)
Part Name: SuperMix
Part Name: Volume
Part Name: Mute
这里是我的WalkTreeBackwardsFromPart的修改版本,这对于所有意图和目的只是简单地检查我们是否将部分目前正在观察是SuperMix,这部分的直接子节点是一个音量节点,这是为了防止错误的分配,因为我发现对于我们的耳机,通常会有两个节点叫做SuperMix,唯一的区别是我们想要的音量有一个音量节点子节点。
HRESULT Sidetone::WalkTreeBackwardsFromPart(IPart *part) {
HRESULT hr;
if (wcscmp(this->getPartName(part), L"SuperMix") == 0 && this->treePeek(part, L"Volume")){
this->superMix = part;
IPart** superMixChildren = this->getChildParts(part);
int nSuperMixChildren = sizeof(superMixChildren)/sizeof(superMixChildren[0]);
if (nSuperMixChildren > 0){
for (int i = 0; i < nSuperMixChildren; i++){
if (wcscmp(this->getPartName(superMixChildren[i]), L"Volume") == 0){
this->volumeNode = this->getIPartAsIAudioVolumeLevel(superMixChildren[i]);
if (this->volumeNode != NULL){
IPart** volumeNodeChildren = this->getChildParts(superMixChildren[i]);
int nVolumeNodeChildren = sizeof(volumeNodeChildren)/sizeof(volumeNodeChildren[0]);
if (nVolumeNodeChildren > 0){
for (int j = 0; j < nVolumeNodeChildren; j++){
if (wcscmp(this->getPartName(volumeNodeChildren[j]), L"Mute") == 0){
this->muteNode = this->getIPartAsIAudioMute(volumeNodeChildren[j]);
break;
}
}
}
}
break;
}
}
}
delete[] superMixChildren;
this->muteNode; // = someotherfunc();
this->superMixFound = true;
return S_OK;
} else if(superMixFound == false){
IPartsList *pIncomingParts = NULL;
hr = part->EnumPartsIncoming(&pIncomingParts);
if (E_NOTFOUND == hr) {
// not an error... we've just reached the end of the path
//printf("%S - No incoming parts at this part: 0x%08x\n", this->MSGIDENTIFIER, hr);
return S_OK;
}
if (FAILED(hr)) {
printf("%S - Couldn't enum incoming parts: hr = 0x%08x\n", this->MSGIDENTIFIER, hr);
return hr;
}
UINT nParts = 0;
hr = pIncomingParts->GetCount(&nParts);
if (FAILED(hr)) {
printf("%S - Couldn't get count of incoming parts: hr = 0x%08x\n", this->MSGIDENTIFIER, 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("%S - Couldn't get part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", this->MSGIDENTIFIER, n, nParts, hr);
pIncomingParts->Release();
return hr;
}
hr = WalkTreeBackwardsFromPart(pIncomingPart);
if (FAILED(hr)) {
printf("%S - Couldn't walk tree on part #%u (0-based) of %u (1-basedSmile hr = 0x%08x\n", this->MSGIDENTIFIER, n, nParts, hr);
pIncomingPart->Release();
pIncomingParts->Release();
return hr;
}
pIncomingPart->Release();
}
pIncomingParts->Release();
}
return S_OK;
}
Sidetone::superMixFound
是用来快速突破我们的递归循环和防止我们走在设备结构树中的任何进一步的(浪费时间)一个布尔成员。
Sidetone::getPartName()
是一种简单的可重复使用的方法,用于返回零件名称的宽字符数组。
Sidetone::treePeek()
如果指定零件的子件包含名称指定为第二个参数的零件,则返回true。
Sidetone::getChildParts()
为给定零件的每个孩子返回一个指针数组。
搞清楚了这一点之后,它只是一个露出setMute
方法dllmain.cpp
,并通过JNA调用它,每当我们需要激活/关闭侧音,所以在开始和任何传输的结束的问题。
我打算使用[IDeviceTopology](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371376(v = vs.85).aspx)来查看如果该功能是可访问的 - 我会报告,如果这个工程。 – SeanIdzenga
我使用MSDN中发布的一个示例,展示了通过设备拓扑树“向后走”的方法,这让我有能力搜索具有getter/setter方法的静音节点。 虽然不是我发现的原始链接[这个Stackoverflow答案](http://stackoverflow.com/a/21607996/1867465)有我引用的walkTreeBackwardsFromPart()函数。 – SeanIdzenga