Android startBluetoothSco は sco を開始しませんが、isBluetoothScoOn は true を返します 質問する

Android startBluetoothSco は sco を開始しませんが、isBluetoothScoOn は true を返します 質問する

ここで質問している以下の問題を示すサンプル プロジェクトを含む GitHub リポジトリを作成しました。
https://github.com/paulpv/audio-loopback/tree/simplified/app/src/main/java/com/twistpair/wave/experimental/loopback(「簡略化された」ブランチに固執し、「マスター」ブランチは無視してください)

主な 2 つのファイルは次のとおりです。

免責事項:現在、私は CyanogenMod 10 Jelly Bean を実行している Samsung Epic SPH-D700 を 1 台だけ使用して、これをコーディングしてテストしています。他のデバイスで試したことはありません。でも、そうすれば、頭がおかしくなりそうになるのを防げるかもしれません。

私はAndroid Bluetooth SCOを確実にオーディオの開始と停止、キャプチャ/再生数ヶ月間!
電話を SCO モードにすると、AudioRecord と AudioTrack によるキャプチャと再生は、それぞれドキュメントどおりに正常に動作します。
私が抱えている問題は、電話を SCO モードに確実に移行できないことです。

「インターネット」にある startBluetoothSco() と setBluetoothScoOn(true) の使用例はすべてシンプルでわかりやすいように見えますが、自分のデバイスで使用すると、確実に動作することはほとんどありません。SCO の
開始と停止だけを行う独自のテスト アプリを作成しましたが、これを確実に動作させることさえできません。

BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED EXTRA_STATE==CONNECTED.
私のコードは、ヘッドセットが接続または切断されたときに確実に検出できるものをリッスンします。

接続を検出すると、ハンドラーはすぐに startBluetoothSco() を呼び出します。
少なくとも 1 回はSCO_AUDIO_STATEC ONNECTED に移行したと断言できますが、99% の時間は から への遷移に終わるだけですDISCONNECTED->CONNECTING->DISCONNECTED

以下は、GitHub サンプル アプリからの注釈付きログ出力です。

10-03 17:00:13.970: I/dalvikvm(29487): Debugger is active
10-03 17:00:14.158: I/System.out(29487): Debugger has connected
10-03 17:00:15.779: I/System.out(29487): waiting for debugger to settle...
10-03 17:00:15.978: I/System.out(29487): debugger has settled (1325)

私のアプリは Jawbone ヘッドセットがオフの状態で起動し、UI を更新します...

10-03 17:00:16.568: D/MainActivity(29487): updateScreen()...
10-03 17:00:16.572: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=false

...UI 更新が完了しました
現在の SCO_AUDIO_STATE を通知するスティッキー ブロードキャスト...

10-03 17:00:16.689: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.media.ACTION_SCO_AUDIO_STATE_UPDATED flg=0x10 (has extras) }
10-03 17:00:16.689: D/AudioStateManager(29487): extras={"android.media.extra.SCO_AUDIO_PREVIOUS_STATE"=2, "android.media.extra.SCO_AUDIO_STATE"=0}
10-03 17:00:16.689: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED
10-03 17:00:16.693: D/AudioStateManager(29487): ==> scoAudioStatePrevious=SCO_AUDIO_STATE_CONNECTING(2)
10-03 17:00:16.693: D/AudioStateManager(29487): ==> scoAudioState=SCO_AUDIO_STATE_DISCONNECTED(0)
10-03 17:00:16.693: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED: SCO_AUDIO_STATE_DISCONNECTED

...現在の SCO_AUDIO_STATE == DISCONNECTED。ヘッドセットがオフになっているため、これが予想されます。
私の SCO Disconnected イベント リスナーが呼び出され、2 つの sendMessages を使用して UI を更新します...

10-03 17:00:16.693: I/MainActivity(29487): onAudioManagerScoAudioDisconnected()
10-03 17:00:16.755: D/libEGL(29487): loaded /vendor/lib/egl/libEGL_POWERVR_SGX540_120.so
10-03 17:00:16.787: D/libEGL(29487): loaded /vendor/lib/egl/libGLESv1_CM_POWERVR_SGX540_120.so
10-03 17:00:16.791: D/libEGL(29487): loaded /vendor/lib/egl/libGLESv2_POWERVR_SGX540_120.so
10-03 17:00:16.888: D/OpenGLRenderer(29487): Enabling debug mode 0
10-03 17:00:16.912: D/MainActivity(29487): MSG_UPDATE_BLUETOOTH_INDICATION
10-03 17:00:16.912: D/MainActivity(29487): updateScreen()...
10-03 17:00:16.912: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=false
10-03 17:00:16.927: D/MainActivity(29487): MSG_UPDATE_AUDIO_OUTPUT_STREAM_TYPE
10-03 17:00:16.927: D/MainActivity(29487): updateScreen()...
10-03 17:00:16.931: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=false

...UI 更新が完了しました

約 20 秒後、Jawbone ヘッドセットをオンにします...

10-03 17:00:37.572: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED flg=0x10 (has extras) }
10-03 17:00:37.583: D/AudioStateManager(29487): extras={"android.bluetooth.device.extra.DEVICE"=00:21:3C:00:3E:02, "android.bluetooth.profile.extra.PREVIOUS_STATE"=0, "android.bluetooth.profile.extra.STATE"=1}
10-03 17:00:37.587: D/AudioStateManager(29487): mReceiver: BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED
10-03 17:00:37.587: D/AudioStateManager(29487): ==> bluetoothDevice=00:21:3C:00:3E:02
10-03 17:00:37.587: D/AudioStateManager(29487): ==> bluetoothHeadsetStatePrevious=STATE_DISCONNECTED(0)
10-03 17:00:37.587: D/AudioStateManager(29487): ==> bluetoothHeadsetState=STATE_CONNECTING(1)
10-03 17:00:37.619: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED flg=0x10 (has extras) }
10-03 17:00:37.623: D/AudioStateManager(29487): extras={"android.bluetooth.device.extra.DEVICE"=00:21:3C:00:3E:02, "android.bluetooth.profile.extra.PREVIOUS_STATE"=1, "android.bluetooth.profile.extra.STATE"=2}
10-03 17:00:37.623: D/AudioStateManager(29487): mReceiver: BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED
10-03 17:00:37.623: D/AudioStateManager(29487): ==> bluetoothDevice=00:21:3C:00:3E:02
10-03 17:00:37.626: D/AudioStateManager(29487): ==> bluetoothHeadsetStatePrevious=STATE_CONNECTING(1)
10-03 17:00:37.626: D/AudioStateManager(29487): ==> bluetoothHeadsetState=STATE_CONNECTED(2)

Jawbone が接続されました。イベント リスナーは次のように呼ばれます...

10-03 17:00:37.626: I/MainActivity(29487): onBluetoothHeadsetConnected()

...SCO が可能であることがわかります...

10-03 17:00:37.626: D/AudioStateManager(29487): mAudioManager.isBluetoothScoAvailableOffCall()=true

...そしてstartBluetoothSco()を自動的に呼び出します
問題はここにあります! startBluetoothSco の呼び出しで SCO_AUDIO_STATE == CONNECTED にならないのはなぜですか?!?!

10-03 17:00:37.626: D/AudioStateManager(29487): startBluetoothSco()
10-03 17:00:37.626: I/AudioStateManager(29487): mAudioManager.startBluetoothSco();

私のイベント リスナーは、現在の BT 状態で UI を更新するために sendMessage で終了します...

10-03 17:00:37.646: D/MainActivity(29487): MSG_UPDATE_BLUETOOTH_INDICATION
10-03 17:00:37.650: D/MainActivity(29487): updateScreen()...
10-03 17:00:37.650: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=false

...UI 更新が完了しました
startBluetoothSco からの最初の結果が届きました...

10-03 17:00:37.681: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.media.ACTION_SCO_AUDIO_STATE_UPDATED flg=0x10 (has extras) }
10-03 17:00:37.681: D/AudioStateManager(29487): extras={"android.media.extra.SCO_AUDIO_STATE"=2, "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"=0}
10-03 17:00:37.681: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED
10-03 17:00:37.685: D/AudioStateManager(29487): ==> scoAudioStatePrevious=SCO_AUDIO_STATE_DISCONNECTED(0)
10-03 17:00:37.685: D/AudioStateManager(29487): ==> scoAudioState=SCO_AUDIO_STATE_CONNECTING(2)

...「DISCONNECTED」から「CONNECTING」に移動しました
startBluetoothSco からの 2 番目の結果が届きました...

10-03 17:00:37.759: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.media.ACTION_SCO_AUDIO_STATE_UPDATED flg=0x10 (has extras) }
10-03 17:00:37.763: D/AudioStateManager(29487): extras={"android.media.extra.SCO_AUDIO_STATE"=0, "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"=2}
10-03 17:00:37.763: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED
10-03 17:00:37.763: D/AudioStateManager(29487): ==> scoAudioStatePrevious=SCO_AUDIO_STATE_CONNECTING(2)
10-03 17:00:37.763: D/AudioStateManager(29487): ==> scoAudioState=SCO_AUDIO_STATE_DISCONNECTED(0)
10-03 17:00:37.763: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED: SCO_AUDIO_STATE_DISCONNECTED

...CONNECTINGから切断
私はSCOがCONNECTINGから接続
イベント リスナーが呼び出され、2 つの sendMessages を使用して UI が更新されます...

10-03 17:00:37.763: I/MainActivity(29487): onAudioManagerScoAudioDisconnected()
10-03 17:00:37.767: D/MainActivity(29487): MSG_UPDATE_BLUETOOTH_INDICATION
10-03 17:00:37.767: D/MainActivity(29487): updateScreen()...
10-03 17:00:37.767: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=false
10-03 17:00:37.783: D/MainActivity(29487): MSG_UPDATE_AUDIO_OUTPUT_STREAM_TYPE
10-03 17:00:37.783: D/MainActivity(29487): updateScreen()...
10-03 17:00:37.783: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=false

...UI 更新が完了しました

SCO が接続されるまで約 20 秒待ちますが、接続されません。
アプリの「startBluetoothSco」ボタンを押します。
17:00:37.626 に startBluetoothSco() が呼び出されるのとまったく同じ結果になることに注意してください。

10-03 17:01:01.689: D/AudioStateManager(29487): startBluetoothSco()
10-03 17:01:01.689: I/AudioStateManager(29487): mAudioManager.startBluetoothSco();

startBluetoothSco からの最初の結果が届きました...

10-03 17:01:01.708: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.media.ACTION_SCO_AUDIO_STATE_UPDATED flg=0x10 (has extras) }
10-03 17:01:01.712: D/AudioStateManager(29487): extras={"android.media.extra.SCO_AUDIO_STATE"=2, "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"=0}
10-03 17:01:01.712: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED
10-03 17:01:01.712: D/AudioStateManager(29487): ==> scoAudioStatePrevious=SCO_AUDIO_STATE_DISCONNECTED(0)
10-03 17:01:01.712: D/AudioStateManager(29487): ==> scoAudioState=SCO_AUDIO_STATE_CONNECTING(2)

...「DISCONNECTED」から「CONNECTING」に移動しました
ここで、17:00:37.626 の startBluetoothSco() の自動呼び出しと異なる点があります。
私たちはBluetoothヘッドセット.ACTION_AUDIO_STATE_CHANGEDイベント...

10-03 17:01:01.716: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED flg=0x10 (has extras) }
10-03 17:01:01.720: D/AudioStateManager(29487): extras={"android.bluetooth.device.extra.DEVICE"=00:21:3C:00:3E:02, "android.bluetooth.profile.extra.PREVIOUS_STATE"=10, "android.bluetooth.profile.extra.STATE"=11}
10-03 17:01:01.720: D/AudioStateManager(29487): mReceiver: BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED
10-03 17:01:01.720: D/AudioStateManager(29487): ==> bluetoothDevice=00:21:3C:00:3E:02
10-03 17:01:01.720: D/AudioStateManager(29487): ==> bluetoothHeadsetAudioStatePrevious=STATE_AUDIO_DISCONNECTED(10)
10-03 17:01:01.720: D/AudioStateManager(29487): ==> bluetoothHeadsetAudioState=STATE_AUDIO_CONNECTING(11)

...「DISCONNECTED」から「CONNECTING」に移動しました
別の BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED イベントが発生します...

10-03 17:01:02.572: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED flg=0x10 (has extras) }
10-03 17:01:02.576: D/AudioStateManager(29487): extras={"android.bluetooth.device.extra.DEVICE"=00:21:3C:00:3E:02, "android.bluetooth.profile.extra.PREVIOUS_STATE"=11, "android.bluetooth.profile.extra.STATE"=12}
10-03 17:01:02.576: D/AudioStateManager(29487): mReceiver: BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED
10-03 17:01:02.576: D/AudioStateManager(29487): ==> bluetoothDevice=00:21:3C:00:3E:02
10-03 17:01:02.576: D/AudioStateManager(29487): ==> bluetoothHeadsetAudioStatePrevious=STATE_AUDIO_CONNECTING(11)
10-03 17:01:02.580: D/AudioStateManager(29487): ==> bluetoothHeadsetAudioState=STATE_AUDIO_CONNECTED(12)

...CONNECTINGからCONNECTEDへ移行
イベントは1つのsendMessageでUIを更新します

10-03 17:01:02.580: I/MainActivity(29487): onBluetoothHeadsetAudioConnected()
10-03 17:01:02.580: D/MainActivity(29487): MSG_UPDATE_BLUETOOTH_INDICATION
10-03 17:01:02.580: D/MainActivity(29487): updateScreen()...
10-03 17:01:02.583: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=true

...UI の更新が完了しました (正直に言うと、isBluetoothScoOn を 2 回目に呼び出す理由がよくわかりません)

10-03 17:01:02.603: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=true

startBluetoothSco からの 2 番目の結果が届きました...

10-03 17:01:02.603: D/AudioStateManager(29487): onReceive: intent=Intent { act=android.media.ACTION_SCO_AUDIO_STATE_UPDATED flg=0x10 (has extras) }
10-03 17:01:02.607: D/AudioStateManager(29487): extras={"android.media.extra.SCO_AUDIO_STATE"=1, "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"=2}
10-03 17:01:02.607: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED
10-03 17:01:02.607: D/AudioStateManager(29487): ==> scoAudioStatePrevious=SCO_AUDIO_STATE_CONNECTING(2)
10-03 17:01:02.607: D/AudioStateManager(29487): ==> scoAudioState=.SCO_AUDIO_STATE_CONNECTED(1)
10-03 17:01:02.607: D/AudioStateManager(29487): android.media.ACTION_SCO_AUDIO_STATE_UPDATED: SCO_AUDIO_STATE_CONNECTED

...CONNECTINGからCONNECTEDへ移行

ついに!
イベント リスナーが呼び出され、2 つの sendMessages を使用して UI が更新されます...

10-03 17:01:02.611: I/MainActivity(29487): onAudioManagerScoAudioConnected()
10-03 17:01:02.630: D/MainActivity(29487): MSG_UPDATE_BLUETOOTH_INDICATION
10-03 17:01:02.630: D/MainActivity(29487): updateScreen()...
10-03 17:01:02.634: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=true
10-03 17:01:02.650: D/MainActivity(29487): MSG_UPDATE_AUDIO_OUTPUT_STREAM_TYPE
10-03 17:01:02.650: D/MainActivity(29487): updateScreen()...
10-03 17:01:02.650: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=true

...UI 更新が完了しました

しばらくしてから SCO を「手動で」起動すると、すべて (今回は) 動作しますが、ヘッドセットが接続された直後に SCO を自動的に起動すると動作しません。

さらに悪いことに、期待どおりに動作しない場合、SCO の状態では奇妙な動作が見られます。

  • startBluetoothSco() を 3 ~ 5 秒遅らせても、違いはないようです。5 秒以上遅らせようとはしていません。BT ヘッドセットにオーディオが流れ始めるまで 5 秒以上待つのは馬鹿げています。
  • 最後の DISCONNECTED 状態以降に状態が CONNECTED に変更されたことを示すブロードキャスト イベントを受信して​​いない場合でも、isBluetoothScoOn() を呼び出すと true が返されることがあります。
  • 場合によっては、UI から startBluetoothSco() を「手動で」呼び出しても、SCO がすでにオンになっているかのように何も起こりませんが、最後の DISCONNECTED 状態以降、状態が CONNECTED に変更されたことを示すブロードキャスト イベントを受信したことはありません。
  • AudioTrack または AudioRecord を開こうとすると、音が出なくなります (SCO が誤動作していない場合は、この同じコードが正常に動作します。つまり、問題は AudioTrack/AudioRecord の呼び出しではなく、SCO の状態です)。
  • stopBluetoothSco() を呼び出しても、状態 DISCONNECTED を報告するイベントは発生しません。
  • setBluetoothScoOn(false/true) は違いがありません。正直に言うと、一見冗長な「startBluetoothSco()/stopBluetoothSco()」と「setBluetoothScoOn(boolean)」の違いがわかりません。うまくいけば、startBluetoothSco() を呼び出すと isBluetoothScoOn() が true を返すので、setBluetoothScoOn(true) を呼び出す必要はないと思います。
  • 電話を再起動しても何も変わりません。
  • ヘッドセットを再起動しても変化はありません。
  • 別のヘッドセットに変更しても違いはありません。
  • ヘッドセットのペアリングが失われ、再度ペアリングする必要がある場合があります。

Google/Android の Bluetooth サポートの実績を考えると、これに驚くことはほとんどありません。

誰か私をこの苦しみから解放し、Android で Bluetooth SCO を確実に開始および停止する方法をわかりやすく説明してくれませんか?

PS: このような問題をエスカレーションするための公式チャネルはありますか [Google や Samsung など]? それとも、StackOverflow が実際の回答を見つける最良の方法でしょうか?

ベストアンサー1

Android のドキュメントには多くの情報が欠けていますが、オーディオ ルーティング中に startBluetoothSco() と stopBluetoothSco() を毎回呼び出すと、オーディオを適切にルーティングするのに問題は発生しません。接続が長時間アイドル状態のままになり、StartBluetoothSco() を開始すると、すぐに切断されるのを見たことさえあります。この問題を解決するために、次の回避策を書きました。https://github.com/kodered/Bluetooth-Refresh-Logic

お役に立てれば。

おすすめ記事