蓝牙配对及A2DP连接
参考:蓝牙配置流程
当点击设置界面的某个蓝牙设备时会调用DeviceListPreferenceFragment里面:
最终调用BluetoothDevicePreference.onClicked(),主要代码如下:
上面的逻辑里会根据不同的情况执行不同的逻辑,一目了然。
蓝牙配对
调用CachedBluetoothDevice.startPairing()
配对之前,如果当前处于蓝牙扫描状态,则停止蓝牙扫描。然后调用createBond()开始绑定(即配对)了。
BluetoothDevice.createBond()>adapterservice.createBond()>adapterservice.createBond()>向状态机发送绑定消息》 BondStateMachine.createBond()>AdapterService.createBondNative()>JNI==>hw,
蓝牙连接
当配对成功之后,会发送BONDING_STATE_CHANGE消息到BondStateMachine:
BondStateMachine::PendingCommandState.processMessage()
调用BondStateMachine::PendingCommandState.sendIntent()发ACTION_BOND_STATE_CHANGED消息给应用软件:
上面先调用了AdapterProperties.onBondStateChanged(),其中调用setBondState更新远程设备的Bond状态。
ACTION_BOND_STATE_CHANGED消息给Setting软件的BluetoothEventManager处理,比如接收到bond完成事件BondStateChangedHandler,里面调用了
cachedDevice.onBondingStateChanged(bondState);
这里省略一些逻辑,之后调用到connectAutoConnectableProfiles()
for循环遍历了所以支持的蓝牙协议,如果该协议允许自动连接,则尝试connect。
连接成功会有以下打印:
这里了解一下A2dpProfile.connect()
先断开已经连接的A2DP远程设备,再连接指定的设备。
A2dpProfile.connect()–>BluetoothA2dp.connect()–>A2dpService.connect() 发送A2dpStateMachine.CONNECT给状态机–>A2dpStateMachine.Disconnected.processMessage() -->connectA2dpNative(),连接超时时间是30秒。
上面代码
(1)处是发送一个连接蓝牙状态改变事件。
(2)进行a2dp连接,很明显就要进入jni里了
(3)把要连接的远程蓝牙设备设置为目标设备mTargetDevice,状态转换到==》pending==>connected
这里只讲连接,所以下面要分析jni了。com_android_bluetooth_a2dp.cpp
static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {jbyte *addr;bt_bdaddr_t * btAddr;bt_status_t status;ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);if (!sBluetoothA2dpInterface) return JNI_FALSE;addr = env->GetByteArrayElements(address, NULL);btAddr = (bt_bdaddr_t *) addr;if (!addr) {jniThrowIOException(env, EINVAL);return JNI_FALSE;}if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {ALOGE("Failed HF connection, status: %d", status);}env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
那么这个sBluetoothA2dpInterface这个是什么呢?其实这个就相当于java中对外提供的api接口,只是在c中是头文件而已。既然是蓝牙肯定是在蓝牙的头文件里bt_av.h里
typedef struct {/** set to sizeof(btav_interface_t) */size_t size;/*** Register the BtAv callbacks*/bt_status_t (*init)( btav_callbacks_t* callbacks );/** connect to headset */bt_status_t (*connect)( bt_bdaddr_t *bd_addr );/** dis-connect from headset */bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr );/** Closes the interface. */void (*cleanup)( void );
} btav_interface_t;
接下来就调用到./btif/src/btif_av.c,此处省略。
蓝牙A2DP连接成功,bluedroid回调com_android_bluetooth_a2dp.cpp bta2dp_connection_state_callback(),然后回调A2dpStateMachine.onConnectionStateChanged()
发送STACK_EVENT消息,因当前状态是Pending,所以调用Pending.processMessage():
processConnectionEvent()
发送MSG_CONNECTION_STATE_CHANGED消息,留意下参数内容。
发送BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED广播,并把状态信息传递过去。另外会调用notifyProfileConnectionStateChanged(),修改Profile的优先级等(因为蓝牙带宽是有限的)。
在LocalBluetoothProfileManager.updateLocalProfiles()有注册接收BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED广播,由StateChangedHandler类处理广播:
cachedDevice.refresh()–>dispatchAttributesChanged()–>BluetoothDevicePreference.onDeviceAttributesChanged(),更新了UI界面关于蓝牙远程设备对应的Prcference。