Android startBluetoothSco no comienza sco pero isBluetoothScoOn devuelve true

He creado un repo GitHub con un proyecto de muestra que muestra el siguiente problema que estoy preguntando aquí:
Https://github.com/paulpv/audio-loopback/tree/simplified/src/com/twistpair/wave/experimental/loopback
(Póngase por favor con la rama "simplificada" y no tenga en cuenta la rama "principal"

Los dos archivos principales son:

  • Https://github.com/paulpv/audio-loopback/blob/simplified/src/com/twistpair/wave/experimental/loopback/MainActivity.java
  • Https://github.com/paulpv/audio-loopback/blob/simplified/src/com/twistpair/wave/experimental/loopback/AudioStateManager.java

Exención de responsabilidad: Actualmente sólo estoy usando un solo Samsung Epic SPH-D700 ejecutando CyanogenMod 10 Jelly Bean para codificar y probar esto con. No he probado esto en otros dispositivos, pero quizás eso podría ayudar a pararme de tirar de mi pelo hacia fuera y de ir loco.

He estado luchando para conseguir Android SCO Bluetooth para iniciar y detener de forma fiable y capturar / reproducir audio POR MESES !
Una vez que consiga el teléfono en el modo SCO, captura y reproducción a través de AudioRecord y AudioTrack (respectivamente) funciona bien según lo documentado.
El problema que estoy teniendo es que no puedo confiar el teléfono en el modo SCO!

Los ejemplos de "Internet" para usar startBluetoothSco () y setBluetoothScoOn (true) parecen sencillos y sencillos, pero cuando los uso en mi dispositivo casi nunca funcionan de manera confiable.
He creado mi propia aplicación de prueba que no hace nada más que iniciar y detener SCO, y no puedo ni siquiera conseguir esto para trabajar confiablemente!

Mi código escucha un BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED EXTRA_STATE==CONNECTED.
Puedo detectar de forma fiable cualquier auricular conectado o desconectado.

Al detectar una conexión mi manejador llama inmediatamente a startBluetoothSco ().
A podría jurar que al menos una vez esto ha pateado SCO_AUDIO_STATE a C O NNECTED, pero el 99% del tiempo sólo resulta en una transición de DISCONNECTED->CONNECTING->DISCONNECTED .

Esta es mi salida de registro anotada de mi aplicación de ejemplo de 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) 

Mi aplicación se inicia con el auricular Jawbone desactivado y actualiza la interfaz de usuario …

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

… actualización de la interfaz de usuario hecha
Difusión pegajosa que me dice el SCO_AUDIO_STATE actual …

 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 

… actual SCO_AUDIO_STATE == DESCONECTADO; Esperado, ya que mi auricular está apagado.
Mi detector de eventos SCO desconectado se llama y actualiza la interfaz de usuario con dos 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 

… actualización de la interfaz de usuario hecha

Después de ~ 20 segundos enciendo mi auricular 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 conectado; Mi detector de eventos se llama …

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

… ve que podemos SCO …

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

… y las llamadas automáticas startBluetoothSco ()
¡AQUÍ ESTÁ DÓNDE ESTÁ EL PROBLEMA! ¿Por qué esta llamada a startBluetoothSco no resulta en 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(); 

Mi oyente de evento termina w / a sendMessage para actualizar la interfaz de usuario con el estado BT actual …

 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 

… actualización de la interfaz de usuario hecha
El primer resultado de startBluetoothSco viene en …

 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) 

… pasó de DESCONECTADO a CONEXIÓN
El segundo resultado de startBluetoothSco viene en …

 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 

… pasó de CONECTAR a DESCONECTADO
¡Yo habría esperado que SCO pasara de CONECTAR a CONECTADO !
Mi detector de eventos se llama y actualiza la interfaz de usuario con dos 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 

… actualización de la interfaz de usuario hecha

Espero ~ 20 segundos para SCO conectado, pero nunca llega.
Presiono el botón "startBluetoothSco" de mi aplicación.
TENGA EN CUENTA QUE ESTO RESULTA EN LA LLAMADA EXACTA DE INICIO a startBluetoothSco () EN 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(); 

El primer resultado de startBluetoothSco viene en …

 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) 

… pasó de DESCONECTADO a CONEXIÓN
Aquí es donde las cosas difieren de la auto-llamada de startBluetoothSco () en 17: 00: 37.626
Obtenemos un evento 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) 

… pasó de DESCONECTADO a CONEXIÓN
Obtenemos otro evento 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) 

… pasó de CONECTAR a CONECTADO
El evento actualiza la UI w / one 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 

… actualización de la interfaz de usuario hecho (Para ser honesto, no estoy seguro de lo que está llamando isBluetoothScoOn una segunda vez)

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

El segundo resultado de startBluetoothSco viene en …

 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 

… pasó de CONECTAR a CONECTADO

¡FINALMENTE!
Mi detector de eventos se llama y actualiza la interfaz de usuario con dos 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 

… actualización de la interfaz de usuario hecha

Todo (esta vez) funciona cuando inicio "manualmente" SCO después de algún tiempo, pero no si comienzo automáticamente SCO inmediatamente después de conectar un auricular.

Para empeorar las cosas, cuando las cosas no funcionan como esperaba, veo un comportamiento extraño en los estados de la SCO:

  • Retrasar el startBluetoothSco () para unos 3-5 segundos resonable parece no hacer ninguna diferencia. No he intentado retrasarlo más de 5 segundos. Esperar más de 5 segundos para que el audio comience a fluir a su auricular BT es ridículo.
  • A veces llamar a isBluetoothScoOn () devuelve true, incluso cuando nunca he recibido un evento de difusión desde el último estado DISCONNECTED diciendo que el estado cambió a CONNECTED.
  • A veces "manualmente" llamando a startBluetoothSco () de la interfaz de usuario no hace nada, como si SCO ya está encendido, pero nunca recibí ningún evento de difusión desde el último estado DESCONECTADO diciendo que el estado cambiado a CONECTADO.
  • Intentar abrir AudioTrack o AudioRecord no produce sonido (este mismo código funciona bien cuando SCO no se está portando mal, es decir: el problema es el estado SCO, no las llamadas AudioTrack / AudioRecord).
  • Llamar stopBluetoothSco () no produce ningún estado de informe de evento DISCONNECTED.
  • SetBluetoothScoOn (false / true) no hace ninguna diferencia. Para ser honesto no entiendo la diferencia en el aparentemente redundante "startBluetoothSco () / stopBluetoothSco ()" y "setBluetoothScoOn (boolean)". Cuando las cosas funcionan, mi llamada startBluetoothSco () resulta en isBluetoothScoOn () devolviendo true haciéndome pensar que no necesito llamar a setBluetoothScoOn (true).
  • Reiniciar el teléfono no hace ninguna diferencia.
  • Reiniciar el auricular no hace ninguna diferencia.
  • Cambiar a otro auricular no hace ninguna diferencia.
  • A veces, el auricular pierde su emparejamiento y tiene que volver a emparejarse.

Teniendo en cuenta la trayectoria de Google / Android en el soporte Bluetooth, muy poco de esto me sorprende.

¿Puede alguien por favor me puso fuera de mi miseria y sin duda explicar cómo de forma fiable iniciar y detener bluetooth SCO en Android?

PS: ¿Existe un canal oficial para escalar temas como este [w / Google? Samsung?]? ¿O es StackOverflow mi mejor oportunidad de encontrar una respuesta real?

Hay muchas cosas que faltan en la documentación de Android, sin embargo, si llama a startBluetoothSco () y stopBluetoothSco () cada vez durante el enrutamiento de audio no debería haber ningún problema en el encaminamiento del audio correctamente. Incluso he visto cuando la conexión se mantiene inactiva por mucho tiempo y empezamos StartBluetoothSco () directamente obtener desconexión. Para resolver esto escribí una solución que está aquí: https://github.com/kodered/Bluetooth-Refresh-Logic

Espero que esto ayude.

  • ¿Howt para conectar dos dispositivos vía bluetooth que envía el código pairng por el parámetro? JAVA-Android
  • ¿Es posible conectar el dispositivo Android Wear con otro dispositivo BLE directamente sin interacción del dispositivo telefónico?
  • Implementar un tiempo de espera en BluetoothSocket inputstream.read () en Android
  • Android DroneKit sobre Bluetooth
  • Obtener la dirección MAC local de Bluetooth en Marshmallow
  • Conecte la PC y el teléfono Android con bluetooth (c #)
  • Problemas con Android Bluetooth LE Notificaciones
  • Cómo establecer la conexión con obd2 de bluetooth android
  • Alternar dispositivo A2DP (Android)
  • Voz al texto Convertir por auriculares Bluetooth
  • Conexión a un dispositivo HID bluetooth (ratón) mediante L2CAP
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.