android bluetooth headset

Android startBluetoothSco no inicia sco pero isBluetoothScoOn devuelve true



headset (1)

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

Espero que esto ayude.

He creado un repositorio de GitHub con un proyecto de muestra que muestra el problema a continuación que estoy preguntando aquí:
https://github.com/paulpv/audio-loopback/tree/simplified/src/com/twistpair/wave/experimental/loopback
(por favor, pegue w / la rama "simplificada" e ignore la rama "maestra")

Los dos archivos principales son:

Descargo de responsabilidad: actualmente solo uso un solo Samsung Epic SPH-D700 con CyanogenMod 10 Jelly Bean para codificar y probar esto. No he probado esto en otros dispositivos, pero tal vez eso podría ayudar a evitar que me suelte el pelo y me vuelva loco.

¡He estado luchando para que Android Bluetooth SCO arranque y se detenga de manera confiable y capture / reproduzca audio POR MESES !
Una vez que puedo poner el teléfono en modo SCO, la captura y reproducción a través de AudioRecord y AudioTrack (respectivamente) funciona bien según lo documentado.
¡El problema que tengo es que no puedo poner el teléfono en modo SCO de manera confiable!

Los ejemplos en "The Internets" para usar startBluetoothSco () y setBluetoothScoOn (true) parecen simples y directos, pero cuando los uso en mi dispositivo casi nunca funcionan de manera confiable.
Creé mi propia aplicación de prueba que no hace más que iniciar y detener SCO, ¡y ni siquiera puedo hacer que esto funcione de manera confiable!

Mi código escucha un BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED EXTRA_STATE==CONNECTED.
Puedo detectar de manera confiable cuando cualquier auricular está conectado o desconectado.

Al detectar una conexión, mi controlador llama inmediatamente a startBluetoothSco ().
A podría jurar que al menos una vez que esto haya pateado SCO_AUDIO_STATE a C O NNECTADO, pero el 99% de las veces solo resulta en una transición de DISCONNECTED->CONNECTING->DISCONNECTED .

Aquí está mi salida del registro anotado de mi aplicación de ejemplo 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 apagado 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
Transmisió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

... SCO_AUDIO_STATE actual == DESCONECTADO; esperado, ya que mi auricular está apagado.
Se llama a mi detector de eventos SCO Disconnected y se actualiza la IU con dos mensajes de envío ...

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 mis auriculares 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 oyente 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 llamadas automáticas startBluetoothSco ()
¡AQUÍ ESTÁ DONDE ESTÁ EL PROBLEMA! ¿Por qué esta llamada a startBluetoothSco no produce SCO_AUDIO_STATE == CONECTADO?!?!

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

Mi detector de eventos termina con un mensaje de envío para actualizar la interfaz de usuario con el estado actual de 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

... 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)

... movido de DESCONECTADO a CONECTAR
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

... movido de CONECTAR a DESCONECTADO
¡Hubiera esperado que SCO pasara de CONECTARSE A CONECTADO !
Se llama a mi detector de eventos y actualiza la interfaz de usuario con dos mensajes de envío ...

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 que SCO se conecte, pero nunca llega.
Presiono el botón "startBluetoothSco" de mi aplicación.
TENGA EN CUENTA QUE ESTO RESULTA EN LA MISMA EXACTA, LLAME A startBluetoothSco () A LAS 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)

... movido de DESCONECTADO a CONECTAR
Aquí es donde las cosas difieren de la llamada automática de startBluetoothSco () a las 17: 00: 37.626
Obtenemos un evento Bluetooth Headset.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)

... movido de DESCONECTADO a CONECTAR
Obtenemos otro evento Bluetooth Headset.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)

... movido de CONECTAR a CONECTADO
Evento actualiza la interfaz de usuario con un envío de mensajes.

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 realizada (para ser honesto, no estoy seguro de lo que está llamando isBluetoothScoOn por 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

... movido de CONECTAR a CONECTADO

¡FINALMENTE!
Se llama a mi detector de eventos y actualiza la interfaz de usuario con dos mensajes de envío ...

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 SCO "manualmente" después de un tiempo, pero no si inicio automáticamente SCO inmediatamente después de conectar un auricular.

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

  • Retrasar el startBluetoothSco () durante 3-5 segundos razonables 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 hacia sus auriculares BT es ridículo.
  • A veces, llamar a isBluetoothScoOn () devuelve verdadero, incluso cuando nunca he recibido un evento de transmisión desde el último estado DESCONECTADO que dice que el estado cambió a CONECTADO.
  • A veces, hacer llamadas "manualmente" a startBluetoothSco () desde la interfaz de usuario no hace nada, como si SCO ya estuviera activado, pero nunca recibí ningún evento de transmisión desde el último estado DESCONECTADO que dice que el estado cambió a CONECTADO.
  • Intentar abrir AudioTrack o AudioRecord no produce ningún sonido (este mismo código funciona bien cuando SCO no se comporta mal, es decir: el problema es el estado SCO, no las llamadas AudioTrack / AudioRecord).
  • Llamar a stopBluetoothSco () no produce ningún estado de informe de eventos DESCONECTADO.
  • setBluetoothScoOn (false / true) no hace ninguna diferencia. Para ser honesto, no comprendo la diferencia en el aparentemente redundante "startBluetoothSco () / stopBluetoothSco ()" y "setBluetoothScoOn (boolean)". Cuando las cosas funcionan, mi llamada startBluetoothSco () da como resultado que isBluetoothScoOn () se vuelva verdadero, lo que me hace pensar que no necesito llamar a setBluetoothScoOn (verdadero).
  • 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.

Dado el historial de Google / Android en el soporte de Bluetooth, muy poco de esto me sorprende.

¿Alguien, por favor, puede sacarme de mi miseria y definitivamente explicar cómo iniciar y detener de manera confiable el SCO de Bluetooth en Android?

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