轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/vnanyesheshou/article/details/71811288
上一篇說了下A2DP的一些基本操作星立,這篇分析下系統(tǒng)應(yīng)用取试、系統(tǒng)源碼是如何操作A2DP的贾铝。尤其是其連接過程,基于Android4.3源碼均唉。Andorid手機(jī)一般都是做為A2DP Audio Source端。
1 連接過程
媒體音頻也就是A2DP,首先連接的藍(lán)牙設(shè)備需要支持A2DP協(xié)議(并且做為A2DP Audio Sink端)辱挥,并且需要與該設(shè)備進(jìn)行配對(duì),如何進(jìn)行藍(lán)牙配對(duì)這里就不細(xì)說了边涕,可以參照我的其他文章晤碘。主要分析下其連接過程褂微。
對(duì)于系統(tǒng)自帶應(yīng)用Settings中已配對(duì)的藍(lán)牙設(shè)備界面(如下圖所示):
其對(duì)應(yīng)文件路徑:
packages/apps/Settings/src/com/android/settings/bluetooth/DeviceProfilesSettings.Java
點(diǎn)擊媒體音頻進(jìn)行連接,調(diào)用onPreferenceChange哼蛆。
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mDeviceNamePref) { //重命名
mCachedDevice.setName((String) newValue);
} else if (preference instanceof CheckBoxPreference) {//check box
LocalBluetoothProfile prof = getProfileOf(preference); //獲取對(duì)應(yīng)的profile
onProfileClicked(prof, (CheckBoxPreference) preference);
return false; // checkbox will update from onDeviceAttributesChanged() callback
} else {
return false;
}
return true;
}
接著看onProfileClicked()函數(shù)處理
private void onProfileClicked(LocalBluetoothProfile profile, CheckBoxPreference profilePref) {
BluetoothDevice device = mCachedDevice.getDevice(); //獲取配對(duì)的藍(lán)牙設(shè)備
int status = profile.getConnectionStatus(device); //獲取profile的連接狀態(tài)
boolean isConnected =
status == BluetoothProfile.STATE_CONNECTED;
if (isConnected) { //如果是連接狀態(tài)則斷開連接
askDisconnect(getActivity(), profile);
} else { //沒有連接
if (profile.isPreferred(device)) { //獲取profile是否是首選
// profile is preferred but not connected: disable auto-connect
profile.setPreferred(device, false); //設(shè)置對(duì)應(yīng)profile的PRIORITY 為off蕊梧,防止自動(dòng)連接
refreshProfilePreference(profilePref, profile); //刷新check box狀態(tài)
} else {
profile.setPreferred(device, true); //設(shè)置對(duì)應(yīng)profile的PRIORITY 為on
mCachedDevice.connectProfile(profile); //連接指定profile
}
}
}
接著查看CachedBluetoothDevice中的connectProfile函數(shù)連接某一profile。
void connectProfile(LocalBluetoothProfile profile) {
mConnectAttempted = SystemClock.elapsedRealtime();
// Reset the only-show-one-error-dialog tracking variable
mIsConnectingErrorPossible = true;
connectInt(profile); //連接profile
refresh(); // 刷新ui
}
synchronized void connectInt(LocalBluetoothProfile profile) {
//查看是否配對(duì)腮介,如果沒有配對(duì)則進(jìn)行配對(duì)肥矢,配對(duì)后進(jìn)行連接,
//如果配對(duì)則直接連接
if (!ensurePaired()) {
return;
}
if (profile.connect(mDevice)) {//連接
return;
}
}
connectProfile() ——>connectInt()
connectInt()函數(shù)中會(huì)先判斷是否配對(duì)叠洗,如果沒有配對(duì)則開始配對(duì)甘改,配對(duì)成功后連接profile。
如果已經(jīng)配對(duì)則直接連接profile灭抑。
對(duì)于profile.connect(mDevice)會(huì)根據(jù)profile調(diào)用各自對(duì)應(yīng)的connect方法十艾。(如手機(jī)音頻則對(duì)應(yīng)HeadsetProfile,媒體音頻對(duì)應(yīng)A2dpProfile)腾节。這里查看手機(jī)音頻的連接A2dpProfile忘嫉。
public boolean connect(BluetoothDevice device) {
if (mService == null) return false;
//獲取連接hfp的設(shè)備
List<BluetoothDevice> sinks = mService.getConnectedDevices();
if (sinks != null) {
for (BluetoothDevice sink : sinks) {
mService.disconnect(sink); //斷開連接
}
} //連接hfp。
return mService.connect(device);
}
A2dpProfile.java中的connect()方法案腺,mService是通過getProfileProxy獲取的BluetoothA2DP代理對(duì)象庆冕,通過其進(jìn)行A2DP相關(guān)操作。
mService.connect跳到Bluetooth應(yīng)用中劈榨,
代碼路徑:packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
先調(diào)用到內(nèi)部類BluetoothA2dpBinder的connect方法访递。
public boolean connect(BluetoothDevice device) {
A2dpService service = getService();
if (service == null) return false;
return service.connect(device);
}
該方法中很明顯是去調(diào)用A2dpService的connect方法。接著看A2dpService中的connect
public boolean connect(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
return false; //檢查priority
}
int connectionState = mStateMachine.getConnectionState(device);
if (connectionState == BluetoothProfile.STATE_CONNECTED ||
connectionState == BluetoothProfile.STATE_CONNECTING) {
return false; //檢查連接狀態(tài)
}
mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);
return true;
}
A2dpService的connect()函數(shù)會(huì)對(duì)priority和連接狀態(tài)進(jìn)行必要的檢查同辣,不符合條件則返回false拷姿。符合條件則向狀態(tài)機(jī)發(fā)送消息A2dpStateMachine.CONNECT。
此時(shí)A2dpStateMachine中狀態(tài)應(yīng)該是Disconnected旱函,所以查看Disconnected state中的處理
BluetoothDevice device = (BluetoothDevice) message.obj;
//發(fā)送廣播响巢,正在連接A2DP
broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTED);
//連接遠(yuǎn)端設(shè)備。
if (!connectA2dpNative(getByteAddress(device)) ) {
//連接失敗陡舅,向外發(fā)送連接失敗廣播
broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTING);
break;
}
synchronized (A2dpStateMachine.this) {
mTargetDevice = device; //mTargetDevice要連接的設(shè)備
transitionTo(mPending); //切換到pending狀態(tài)
} //超時(shí)處理
sendMessageDelayed(CONNECT_TIMEOUT, 30000);
A2DPStateMachine調(diào)用connectA2dpNative()函數(shù)來進(jìn)行媒體音頻的連接抵乓。connectA2dpNative是native方法,跳轉(zhuǎn)到com_android_bluetooth_a2dp.cpp中靶衍,調(diào)用對(duì)應(yīng)的方法connectA2dpNative
static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
jbyte *addr;
bt_bdaddr_t * btAddr;
bt_status_t status;
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) {
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
其中sBluetoothA2dpInterface->connect會(huì)跳到hardware灾炭、藍(lán)牙協(xié)議棧進(jìn)行連接,這就先不進(jìn)行分析了颅眶。
2 狀態(tài)回調(diào)##
當(dāng)協(xié)議棧連接狀態(tài)改變會(huì)回調(diào)com_android_bluetooth_a2dp.cpp中的方法bta2dp_connection_state_callback蜈出。
static void bta2dp_connection_state_callback(btav_connection_state_t state, bt_bdaddr_t* bd_addr) {
jbyteArray addr;
if (!checkCallbackThread()) { \
return; \
}
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
return;
}
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state,
addr);
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
sCallbackEnv->DeleteLocalRef(addr);
}
bta2dp_connection_state_callback方法中會(huì)從cpp層調(diào)用到j(luò)ava層,對(duì)應(yīng)于A2DPStateMachine中的onConnectionStateChanged函數(shù)
private void onConnectionStateChanged(int state, byte[] address) {
StackEvent event = new StackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED);
event.valueInt = state;
event.device = getDevice(address);
sendMessage(STACK_EVENT, event);
}
onConnectionStateChanged函數(shù)中發(fā)送消息STACK_EVENT(攜帶狀態(tài)和藍(lán)牙地址)涛酗,此時(shí)是Pending state铡原,收到該消息調(diào)用processConnectionEvent偷厦。
正常連接成功應(yīng)該會(huì)先收到CONNECTION_STATE_CONNECTING狀態(tài),然后收到CONNECTION_STATE_CONNECTED狀態(tài)燕刻。
//發(fā)送廣播只泼,連接成功
broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING);
synchronized (A2dpStateMachine.this) {
mCurrentDevice = mTargetDevice;//mCurrentDevice表示已連接的設(shè)備
mTargetDevice = null; //mTargetDevice表示要連接的設(shè)備
transitionTo(mConnected);//切換到Connected狀態(tài)
}
收到CONNECTION_STATE_CONNECTED狀態(tài),后向外發(fā)送連接成功的廣播卵洗,狀態(tài)機(jī)切換到Connected狀態(tài)请唱。
private void broadcastConnectionState(BluetoothDevice device, int newState, int prevState) {
//AudioManager設(shè)置A2DP的連接狀態(tài)
int delay = mAudioManager.setBluetoothA2dpDeviceConnectionState(device, newState);
mWakeLock.acquire();
//延時(shí)處理,發(fā)送廣播
mIntentBroadcastHandler.sendMessageDelayed(mIntentBroadcastHandler.
obtainMessage(MSG_CONNECTION_STATE_CHANGED,
prevState,newState,device),
delay);
}
broadcastConnectionState中會(huì)向AudioManager中設(shè)置A2DP的連接狀態(tài)过蹂,返回值用來延時(shí)發(fā)送廣播十绑。AudioManager設(shè)置A2DP的連接狀態(tài)非常重要,這樣音頻系統(tǒng)根據(jù)當(dāng)前狀態(tài)酷勺,判斷音頻從哪里發(fā)出(藍(lán)牙a2dp本橙、揚(yáng)聲器、耳機(jī))脆诉。
歡迎大家關(guān)注甚亭、評(píng)論、點(diǎn)贊击胜。
你們的支持是我堅(jiān)持的動(dòng)力狂鞋。