2017-04-10 26 views
1

私の現在のプロジェクトでは、JNA経由でアクセスするC++のネイティブ・ライブラリを実装していますが、このプロジェクトは低遅延の通信シミュレータです。シミュレータが基づいているハードウェアを模倣するために送信中にサイドトーンを有効にする必要があります。 もちろん、JAVAサウンドは、0に近いレイテンシを達成するのが難しいと証明しています(最善の場合は約120msです)。わかりやすいように、サイドトーンのレイテンシがゼロに近くなる必要があります。幸い、Windowsでは、完璧なサイドトーンを生成するUSB​​ヘッドセットのマイクを聴く方法があるようです。プログラムド・サイド・マイク・パススルーを有効にする方法

オーディオのプロパティ - >再生 - >ヘッドセットイヤホン - >プロパティ - >レベル

An example of what I mean here

(これはかなり悪い遅延を生成し「このデバイスを聴く」機能は異なることに注意してください)

私はCore Audio APIのMSDNの例を使用していて、デバイスを照会してチャネル、音量レベル、ミュート設定などを取得できましたが、マイクレベルのミュート/ミュートはされていませんコアのオーディオAPIからでもアクセスできます。

私の質問はこれは:プログラムでUSBヘッドセットのマイクレベル/ミュート設定とインターフェイスする方法はありますか?

私たちのシミュレータは標準化されているので、幅広いヘッドセット(現時点では2)をサポートすることを心配する必要はありません。

+1

[IDeviceTopology](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371376(v = vs.85).aspx)を使用して、その機能にアクセス可能な場合は、この機能があれば報告します。 – SeanIdzenga

+0

MSDNに掲載されている例を使って、デバイストポロジーツリーを「後方へ」歩く手段を示しています。getter/setterメソッドを持つミュートノードを検索することができます。 私は[このStackoverflow答え](http://stackoverflow.com/a/21607996/1867465)が私が参照したwalkTreeBackwardsFromPart()関数が見つかりました。 – SeanIdzenga

答えて

1

この問題を解決するための鍵は、サイドトーンミュート属性を設定する部分が見つかるまで、デバイストポロジーツリーを後方に歩くことでした。私の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経由で呼び出すことができたので、送信の開始時と終了時にそれを呼び出します。

関連する問題