解決此問題的關鍵是將設備拓撲樹向後走,直到找到負責設置側音靜音屬性的部分。所以在我的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