Android 通话与蓝牙的交互

一、telecom进程和bluetooth进程的交互方方式

1. telecom进程主动控制蓝牙的操作是通过跨进程调用bluetooth进程中HeadService的接口。

2. 蓝牙状态变更是通过广播通知telecom进程。

如下图:

进程交互

具体细节如下:

进程交互细节

telecom进程在创建时,TelecomService会创建BluetoothDeviceManager类来负责所有和bluetooth进程有关的操作:BluetoothAdapter的代理类BluetoothAdapterProxy创建BluetoothHeadset,负责跨进程调用HeadsetService中的接口,然后把它返回给一个代理类BluetoothHeadsetProxy,所有和蓝牙的有关操作都直接通过这个代理类处理。同时,TelecomService会创建一个专门用来接收蓝牙广播的类BluetoothStateReceiver,收到广播后通过BluetoothRouteManager来通知管理通话audio route的CallAudioRouteManager,然后通知界面更新。用户在通话界面切换声音模式时也是通过CallAudioRouteManager通知BluetoothRouteManager然后调用用BluetoothHeadset的接口来处理。BluetoothRouteManager是通话audio route和蓝牙相关信息的中转站。

二、Telecom接收的蓝牙广播

BluetoothHeadset.ACTIVE_ACTIVE_DEVICE_CHANGED

这个广播是在蓝牙打开,有蓝牙设备连接或者断开时发送。收到这个广播后,telecom会根据当前device的连接状态来判断是否要切换为bluetooth route。如下图:

active device changed

BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED

这个广播是蓝牙开关打开或关闭时发送。收到这个广播后telecom会更新当前支持的audio routes。如图:

connection state changed

BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED

这个广播是HFP连接或断开时发送。如图:

audio state changed

这个广播不仅会让telecom切换当前audio route也是唯一一个会引起 BluetoothRouteManager切换bluetooth StateMachine切换状态的广播。

三、BluetoothRouteManager StateMachine

先介绍一下StateMachine里面频繁用到的一个专有名词:HFP。

HFP(Hands-free Profile):让蓝牙设备可以控制电话,如接听、挂断、拒接、语音音拨号等,拒接、语音拨号要视蓝牙耳机及电话是否支持,是让蓝牙耳机进入高保真通话的一种可设置模式。

再来看SM的构成:

bluetooth statemachine

从图中可以看出:

1. CONNECT_HFP只能切换到AudioConnectingState,要等到HFP_IS_ON才会把状态切换成AudioConnectedState。DISCONNECT_HFP一定会把状态切换成AudioOffState,但HFP_LOST不一定。CONNECT_HFP DISCONNECT_HFP是通话主动发起的蓝牙状态连接或断开,而HFP_IS_ON HFP_LOST是蓝牙上报的设备audio连接或断开。

2. 不同的蓝牙设备分别有自己的AudioConnectingState和AudioConnectedState状态,但AudioOffState状态却不分设备。这就会引起一个问题:

例如:当一台手机连接两个蓝牙耳机A和B,目前通话正在使用A,用户在蓝牙设置界面选择切换成B。此时,蓝牙会先断开A的audio连接然后再建立B的audio连接。于是通话会先收到A的HFP_LOST然后再收到B的HFP_IS_ON,这里就会有一个time issue:当AudioConnectedState收到HFP_LOST时B的audio没有连接上,但进入到AudioOffState前B的audio连接上了,此时在AudioOffState的enter中会断开B的连接,导致声道切换成B失败,而从听筒出声。

原因:A和B没有自己的AudioOffState,导致状态混乱。

解决方法:给接收HFP_LOST断开的设备建立它自己的AudioOffState。

issue


四、通话中用户主动切换蓝牙声道

耳机切换至蓝牙

当用户主动切换到蓝牙声道时,CallAudioRouteStateMachine在切换到BluetoothRoute之前会先打开蓝牙,同时发送CONNECT_HFP消息,从AudioOffState切换到AudioConnectingState,这时会触发一个timeout,图中没有表示,具体可以去看代码。当蓝牙audio连接时,会发送BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED的广播,收到这个广播后会发送HFP_IS_ON的message给SM,然后从AudioConnectingState切换到AudioConnectedState。进入AudioConnectedState之后会通知CallAudioRouteStateMachine切换到BluetoothRoute。如下图:

耳机切换至蓝牙

蓝牙切换至耳机

进入非BluetoothRoute时会把蓝牙audio断开。如下图:

蓝牙切换至耳机

五、蓝牙主动上报状态更新

通话中,连接蓝牙设备

如上图:收到Bluetooth.ACTION_CONNECTION_STATE_CHANGED CONNECTED时更新可用的audioroutes,收到Bluetooth.ACTION_AUDIO_STATE_CHANGED CONNECTED时更新statemachine到AudioConnectedState和ActiveBluetoothRoute。

通话中连接蓝牙设备

非通话中,连接蓝牙设备

非通话中,连接蓝牙设备

如上图:收到Bluetooth.ACTION_CONNECTION_STATE_CHANGED CONNECTED时更新可用的audioroutes,收到Bluetooth.ACTION_DEVICE_STATE_CHANGED CONNECTED时更新statemachine到QuiescentBluetoothRoute。

当拨号或来电时会请求蓝牙audio连接,蓝牙audio连接后再切换到active或ringing bluetooth route。

蓝牙设备连接时,插入耳机

如下图,此时通话会默认切换到耳机通道

蓝牙设备连接时,插入耳机


原创内容欢迎转载,但请注明出处,谢谢!

你可能感兴趣的:(Android 通话与蓝牙的交互)