以下内容都是基于android6.0的基礎上講的,相對于android4.4架構有了很大改動。
先借用一下圖用一下。

上圖描述的是藍牙協定棧,通過該圖,檢視A2dp的代碼在協定棧的調用流程。其分層架構如下:
1.藍牙的系統服務service通過JNI與bluedroid協定棧進行通信。協定棧分為兩層,Bluetooth Embedded System(BTE)和Bluetooth Application Layer(BTA)。這兩層和framework層應用進行通信。
2.藍牙服務通過Binder IPC通信與應用程式互動。
3.系統服務給開發者提供了擷取各種profile的接口。
一、接下來将深入Framework層講解藍牙的連接配接
1)那就從connectInt()開始
synchronized void connectInt(LocalBluetoothProfile profile) {
if (!ensurePaired()) {
return;
}
if (profile.connect(mDevice)) {
if (Utils.D) {
Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
}
return;
}
Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
}
2)若profile為a2dpprofile,則A2dpProfile.connect()
public boolean connect(BluetoothDevice device) {
if (mService == null) return false;
List<BluetoothDevice> sinks = getConnectedDevices();
if (sinks != null) {
for (BluetoothDevice sink : sinks) {
mService.disconnect(sink);
}
}
return mService.connect(device);
}
上面的代碼就很好了解了,查詢已連接配接的裝置,然後斷開。隻有先把藍牙節點給釋放掉才能供給其它使用。
3)BluetoothA2dp.connect()
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
if (mService != null && isEnabled() &&
isValidDevice(device)) {
try {
return mService.connect(device);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
}
}
if (mService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
BluetoothA2dp類是幹什麼的呢?它是藍牙a2dp服務的代理對象,就是上層想要使用就必須用到它了。擷取BluetoothA2dp的方法就是BluetoothAdapter.getProfileProxy()
4.A2dpService.connect()
mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
發送一個藍牙連接配接的消息給A2dpStateMachine進行連接配接操作。a2dp連接配接之前肯定處于disconnect狀态,是以進行連接配接時要一步一個腳印。大家注意下面一段代碼是mDisconnected裡的。
switch(message.what) {
case CONNECT:
BluetoothDevice device = (BluetoothDevice) message.obj;
broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTED);----(1)
if (!connectA2dpNative(getByteAddress(device)) ) {-----(2)
broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTING);
break;
}
synchronized (A2dpStateMachine.this) {
mTargetDevice = device;
transitionTo(mPending);---------(3)
}
// TODO(BT) remove CONNECT_TIMEOUT when the stack
// sends back events consistently
sendMessageDelayed(CONNECT_TIMEOUT, 30000);
break;
上面的(1)處是發送一個連接配接藍牙狀态改變事件。
(2)進行a2dp連接配接,很明顯就要進入jni裡了
(3)狀态轉換到==》pending==>connected
JNI
5.這裡隻講連接配接,是以下面要分析jni了
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
static const btav_interface_t bt_av_src_interface = {
sizeof(btav_interface_t),
init_src,
src_connect_sink,
disconnect,
cleanup_src,
};
static const btav_interface_t bt_av_sink_interface = {
sizeof(btav_interface_t),
init_sink,
sink_connect_src,
disconnect,
cleanup_sink,
};
至于a2dp的斷開,流程和連接配接類似,請大家自行分析。
上面有兩個connect到底使用哪一個呢?那就要看你的機器是發送連接配接還是接收連接配接了。就到這了,接下來的東西其實我沒搞太明白,就不誤導大家了。
如果感覺不錯,就贊一下。