この問題を解決するための鍵は、サイドトーンミュート属性を設定する部分が見つかるまで、デバイストポロジーツリーを後方に歩くことでした。私のCPPプロジェクトでは、トポロジーツリー内のどこにSuperMix
の部分を探しているかを判断するためにいくつかの方法が協力していました。
SuperMix
はサイドトーンの一般的な名前のようで、私たちがサポートしている2つのヘッドセットで少なくとも使用されています。このツリーは両方のヘッドセットで同じですが、あなたの走行距離は異なる場合があります。これは、出力が
Part Name: SuperMix
Part Name: Volume
Part Name: Mute
は、ここですべての意図や目的のために、単に我々が現在見ている一部かどうかをチェックするWalkTreeBackwardsFromPartの私の修正版、です(this answerを参照)上記のWalkTreeBackwardsFromPart例からのように見えるかもしれないものですSuperMixであり、この部分の直接の子はボリュームノードです。これは誤った割り当てを防ぐためです。私たちのヘッドセットでは、SuperMixというノードが2つありますが、唯一の違いは、ボリュームがあったということですノードの子。
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()
は、指定された部分の子に、2番目のパラメータとして指定された名前の部分が含まれている場合に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