Android startBluetoothSco не запускает sco, но isBluetoothScoOn возвращает true
Я создал репозиторий GitHub с образцом проекта, который показывает ниже проблему, о которой я спрашиваю здесь:
https://github.com/paulpv/audio-loopback/tree/simplified/src/com/twistpair/wave/experimental/loopback
(пожалуйста, прикрепите к "упрощенной" ветке и не обращайте внимания на "ведущую" ветку)
Два основных файла:
Отказ от ответственности: В настоящее время я использую только один Samsung Epic SPH-D700, работающий с CyanogenMod 10 Jelly Bean для кодирования и тестирования этого. Я не пробовал это на других устройствах, но, возможно, это может помешать мне вытащить мои волосы и сходить с ума.
Я боролся с тем, чтобы Android Bluetooth SCO был надежно запускать и останавливать и захватывать/воспроизводить аудио ДЛЯ МЕСЯЦ!
Как только я могу подключить телефон к режиму SCO, захват и воспроизведение через AudioRecord и AudioTrack (соответственно) отлично работают, как описано.
Проблема, с которой я сталкиваюсь, заключается в том, что я не могу надежно подключить телефон к режиму SCO!
Примеры в "Интернетах" для использования startBluetoothSco() и setBluetoothScoOn (true) кажутся простыми и прямыми, но когда я использую их на своем устройстве, они почти никогда не работают надежно.
Я создал собственное тестовое приложение, которое ничего не делает, кроме запуска и остановки SCO, и я даже не могу заставить это работать с надежностью!
Мой код прослушивает BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED EXTRA_STATE==CONNECTED.
Я могу надежно обнаружить, когда какая-либо гарнитура подключена или отключена.
При обнаружении соединения мой обработчик немедленно вызывает startBluetoothSco().
A может поклясться, что по крайней мере однажды это пнуло SCO_AUDIO_STATE
до C O
NNECTED, но в 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)
My app начинает с гарнитуры Jawbone выключен и обновляет интерфейс...
10-03 17:00:16.568: D/MainActivity(29487): updateScreen()...
10-03 17:00:16.572: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=false
... обновление пользовательского интерфейса
Приличная трансляция, которая сообщает мне текущий 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 прослушиватель событий вызывается и обновляет UI w/two sendMessages...
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
... обновление пользовательского интерфейса
Через ~ 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)
Связанная челюсть; Мой прослушиватель событий называется...
10-03 17:00:37.626: I/MainActivity(29487): onBluetoothHeadsetConnected()
... видит, что мы можем SCO...
10-03 17:00:37.626: D/AudioStateManager(29487): mAudioManager.isBluetoothScoAvailableOffCall()=true
... и автовызов startBluetoothSco()
ЗДЕСЬ ГДЕ ПРОБЛЕМА! Почему этот вызов для запускаBluetoothSco не приводит к 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();
Мой прослушиватель событий заканчивает работу с sendMessage для обновления пользовательского интерфейса с текущим состоянием BT...
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
... обновление пользовательского интерфейса
Первый результат от 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 входит в...
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 в ОТКЛЮЧЕНО
Я бы ожидал, что ШОС перейдет от ПОДКЛЮЧЕНИЯ к ПОДКЛЮЧЕНА!
Вызывается мой прослушиватель событий и обновляет UI w/two sendMessages...
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
... обновление пользовательского интерфейса
Я жду ~ 20 секунд для подключения SCO, но он никогда не приходит.
Я нажимаю кнопку "startBluetoothSco" моего приложения.
ЗАМЕЧАНИЕ, ЧТО ЭТО РЕЗУЛЬТАТЫ В ТОЧНОМ ТОЧНОМ ЗВОНОК запускатьBluetoothSco() AT 17: 00: 37.626
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
Здесь ситуация отличается от автоматического вызова startBluetoothSco() в 17:00: 37.626
Мы получаем событие BluetoothHeadset.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 to CONNECTED
Событие обновляет пользовательский интерфейс с одним сообщением SendMessage
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
... Выполнено обновление пользовательского интерфейса (честно говоря, я не уверен, что вызывается isBluetoothScoOn во второй раз)
10-03 17:01:02.603: D/AudioStateManager(29487): mAudioManager.isBluetoothScoOn()=true
Второй результат от startBluetoothSco входит...
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
НАКОНЕЦ!
Вызывается мой прослушиватель событий и обновляет UI w/two sendMessages...
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
... обновление пользовательского интерфейса
Все (на этот раз) работает, когда я "вручную" запускаю SCO через некоторое время, но не, если я автоматически запускаю SCO сразу после подключения гарнитуры.
Чтобы ухудшить ситуацию, когда ситуация не работает должным образом, я вижу странное поведение в состояниях ШОС:
- Откладывание startBluetoothSco() для резонансных 3-5 секунд, похоже, не имеет значения. Я не пробовал откладывать его более 5 секунд. Ожидание более 5 секунд, когда звук начнет поступать на вашу гарнитуру BT, смешно.
- Иногда вызов isBluetoothScoOn() возвращает true, даже когда я никогда не получал широковещательное событие с момента последнего состояния DISCONNECTED, заявляющего, что состояние изменено на CONNECTED.
- Иногда "вручную" вызов startBluetoothSco() из пользовательского интерфейса ничего не делает, как будто SCO уже включен, но я никогда не получал никакого широковещательного события с момента последнего состояния DISCONNECTED, заявляющего, что состояние изменено на CONNECTED.
- При попытке открыть AudioTrack или AudioRecord нет звука (этот же код отлично работает, когда SCO не ошибается, т.е. проблема заключается в состоянии SCO, а не в вызовах AudioTrack/AudioRecord).
- Вызов stopBluetoothSco() не приводит к состоянию сообщения о событии ОТКЛЮЧЕН.
- setBluetoothScoOn (false/true) не имеет значения. Честно говоря, я не понимаю разницы в кажущемся избыточным "startBluetoothSco()/stopBluetoothSco()" и "setBluetoothScoOn (boolean)". Когда все работает, мой вызов startBluetoothSco() приводит к тому, что isBluetoothScoOn() возвращает true, заставляя меня думать, что мне не нужно вызывать setBluetoothScoOn (true).
- Перезагрузка телефона не имеет значения.
- Перезагрузка гарнитуры не имеет значения.
- Переход на другую гарнитуру не имеет значения.
- Иногда гарнитура теряет спаривание и должна быть повторно спарена.
Учитывая историю трека Google/Android в поддержке Bluetooth, это немного меня удивляет.
Может кто-то, пожалуйста, избавит меня от моего несчастья и определенно объяснит, как надежно начать и остановить Bluetooth SCO в Android?
PS: Есть ли официальный канал для эскалации таких проблем [w/Google? Samsung?] Или, есть ли StackOverflow мой лучший шанс найти фактический ответ?
Ответы
Ответ 1
В документации по Android многое отсутствует, однако, если вы звоните в startBluetoothSco() и stopBluetoothSco() каждый раз во время маршрутизации аудио, не должно быть проблем с правильной настройкой звука.
Даже я видел, когда соединение долгое время простаивает, и мы запускаем StartBluetoothSco(), мы напрямую получаем разъединение.
Чтобы решить эту проблему, я написал обходное решение, которое находится здесь: https://github.com/kodered/Bluetooth-Refresh-Logic
Надеюсь, что это поможет.