藍牙啟動的時候,會涉及到各個profile 的啟動。這篇文章分析一下,藍牙中a2dp profile的初始化流程。
我們從AdapterState.java中對於USER_TURN_ON 消息的處理說起:
switch(msg.what) { case USER_TURN_ON: notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON); mPendingCommandState.setTurningOn(true); transitionTo(mPendingCommandState); sendMessageDelayed(BREDR_START_TIMEOUT, BREDR_START_TIMEOUT_DELAY); adapterService.startCoreServices();//開始啟動核心的服務,就是各種profile break;
繼續看:
void startCoreServices() { debugLog("startCoreServices()"); Class[] supportedProfileServices = Config.getSupportedProfiles(); //Start profile services if (!mProfilesStarted && supportedProfileServices.length >0) { //Startup all profile services setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);//start all profile } ... }
看看setProfileServiceState的實現,他就是實現一個for 循環,在里面啟動所有的profile:
private void setProfileServiceState(Class[] services, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { debugLog("setProfileServiceState() - Invalid state, leaving..."); return; } int expectedCurrentState= BluetoothAdapter.STATE_OFF; int pendingState = BluetoothAdapter.STATE_TURNING_ON; if (state == BluetoothAdapter.STATE_OFF) { expectedCurrentState= BluetoothAdapter.STATE_ON; pendingState = BluetoothAdapter.STATE_TURNING_OFF; } for (int i=0; i <services.length;i++) { String serviceName = services[i].getName(); String simpleName = services[i].getSimpleName(); if (simpleName.equals("GattService")) continue; Integer serviceState = mProfileServicesState.get(serviceName); if(serviceState != null && serviceState != expectedCurrentState) { debugLog("setProfileServiceState() - Unable to " + (state == BluetoothAdapter.STATE_OFF ? "start" : "stop" ) + " service " + serviceName + ". Invalid state: " + serviceState); continue; } debugLog("setProfileServiceState() - " + (state == BluetoothAdapter.STATE_OFF ? "Stopping" : "Starting") + " service " + serviceName); mProfileServicesState.put(serviceName,pendingState); Intent intent = new Intent(this,services[i]); intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_STATE,state); startService(intent);//啟動服務 } }
startSerice 啟動服務,我們這里只分析a2dp的情況,其他的profile的啟動情況類似。a2dp 對應的service 文件是a2dpService.java,下面看看service的啟動:
public void onCreate() { if (DBG) log("onCreate"); super.onCreate(); mAdapter = BluetoothAdapter.getDefaultAdapter(); mBinder = initBinder();//生成一個Binder mAdapterService = AdapterService.getAdapterService(); if (mAdapterService != null) { mAdapterService.addProfile(this); } else { Log.w(TAG, "onCreate, null mAdapterService"); } }
我們看看a2dpService是如何實現這個mBInder的:
protected IProfileServiceBinder initBinder() { return new BluetoothA2dpBinder(this);//傳入一個 this 指針,那么也就是說a2dpService 這個類本身就是這個service }
看看這個BluetoothA2dpBinder 是一個什么樣的接口?其實他就是對原本的服務的一個封裝,包含了原來的服務
//Binder object: Must be static class or memory leak may occur private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub implements IProfileServiceBinder { private A2dpService mService; private A2dpService getService() { if (!Utils.checkCaller()) { Log.w(TAG,"A2dp call not allowed for non-active user"); return null; } if (mService != null && mService.isAvailable()) { return mService; } return null; } BluetoothA2dpBinder(A2dpService svc) { mService = svc;//構造函數傳入的this 參數 } public boolean cleanup() { mService = null; return true; } public boolean connect(BluetoothDevice device) { A2dpService service = getService(); if (service == null) return false; return service.connect(device); } public boolean disconnect(BluetoothDevice device) { A2dpService service = getService(); if (service == null) return false; return service.disconnect(device); } public List<BluetoothDevice> getConnectedDevices() { A2dpService service = getService(); if (service == null) return new ArrayList<BluetoothDevice>(0); return service.getConnectedDevices(); } public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { A2dpService service = getService(); if (service == null) return new ArrayList<BluetoothDevice>(0); return service.getDevicesMatchingConnectionStates(states); } public int getConnectionState(BluetoothDevice device) { A2dpService service = getService(); if (service == null) return BluetoothProfile.STATE_DISCONNECTED; return service.getConnectionState(device); } public boolean setPriority(BluetoothDevice device, int priority) { A2dpService service = getService(); if (service == null) return false; return service.setPriority(device, priority); } public int getPriority(BluetoothDevice device) { A2dpService service = getService(); if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; return service.getPriority(device); } public boolean isAvrcpAbsoluteVolumeSupported() { A2dpService service = getService(); if (service == null) return false; return service.isAvrcpAbsoluteVolumeSupported(); } public void adjustAvrcpAbsoluteVolume(int direction) { A2dpService service = getService(); if (service == null) return; service.adjustAvrcpAbsoluteVolume(direction); } public void setAvrcpAbsoluteVolume(int volume) { A2dpService service = getService(); if (service == null) return; service.setAvrcpAbsoluteVolume(volume); } public boolean isA2dpPlaying(BluetoothDevice device) { A2dpService service = getService(); if (service == null) return false; return service.isA2dpPlaying(device); } }
這個mBinder 會在別的應用程序綁定的時候,返回給對方。所以其就是對原本服務的一個封裝。
接着我們看onStartCommand:
public int onStartCommand(Intent intent, int flags, int startId) { ... String action = intent.getStringExtra(AdapterService.EXTRA_ACTION); if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) { int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); if(state==BluetoothAdapter.STATE_OFF) { Log.d(mName, "Received stop request...Stopping profile..."); doStop(intent); } else if (state == BluetoothAdapter.STATE_ON) { Log.d(mName, "Received start request. Starting profile..."); doStart(intent);//啟動 } } return PROFILE_SERVICE_MODE; }
繼續看:
private void doStart(Intent intent) { //Start service if (mAdapter == null) { Log.e(mName, "Error starting profile. BluetoothAdapter is null"); } else { if (DBG) log("start()"); mStartError = !start();//這個是虛函數,看看a2dpService 具體如何實現的 if (!mStartError) { notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON);上報狀態 } else { Log.e(mName, "Error starting profile. BluetoothAdapter is null"); } } }
上報的狀態的部分就不分析了,我們直接看 start的部分:
avrcp的部分暫時略過,
protected boolean start() { mAvrcp = Avrcp.make(this); mStateMachine = A2dpStateMachine.make(this, this);//啟動狀態機 setA2dpService(this);//設置a2dpService服務為本身sAd2dpService = this return true; }
看看狀態機make 函數到底干嘛?猜想應該是初始化狀態機:
static A2dpStateMachine make(A2dpService svc, Context context) { A2dpStateMachine a2dpSm = new A2dpStateMachine(svc, context);//新建一個狀態機 a2dpSm.start();//start return a2dpSm; }
這里的start就是讓狀態機轉起來,和a2dp 的關系不大,這里不分析 了,我們這里的重頭戲是new A2dpStateMachine,這里涉及到一些 變量、狀態的初始化,以及協議棧中關於a2dp的初始化。
private A2dpStateMachine(A2dpService svc, Context context) { super("A2dpStateMachine"); mService = svc;//a2dpService mContext = context;//a2dpService mAdapter = BluetoothAdapter.getDefaultAdapter(); initNative();//native 函數 mDisconnected = new Disconnected();//新建各種狀態,類中類 mPending = new Pending(); mConnected = new Connected(); addState(mDisconnected);//往狀態機中添加狀態 addState(mPending); addState(mConnected); setInitialState(mDisconnected);//設置初始狀態 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BluetoothA2dpService"); mIntentBroadcastHandler = new IntentBroadcastHandler(); mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); }
如果我們不往JNI 層以下分析的話,那么應用層的Service的初始化的流程已經完成了。
這里調用initNative其實就是 對JNI 層以及協議棧進行a2dp 的初始化,我們這里也分析一下:
static void initNative(JNIEnv *env, jobject object) { const bt_interface_t* btInf; bt_status_t status; ... if ( (sBluetoothA2dpInterface = (btav_interface_t *) btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) {//獲取a2dp的接口 ALOGE("Failed to get Bluetooth A2DP Interface"); return; } if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {//對接口進行初始化 ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status); sBluetoothA2dpInterface = NULL; return; } mCallbacksObj = env->NewGlobalRef(object); }
我們先看一下 這個接口實現在那里,其實現在btif_av.c中,從這里開始就是C代碼實現的了。
static const btav_interface_t bt_av_src_interface = { .size = sizeof(btav_interface_t), .init = init_src, .connect = src_connect_sink, .disconnect = disconnect, .cleanup = cleanup_src, };
那我們繼續看 其init的實現:
/******************************************************************************* ** ** Function init_src ** ** Description Initializes the AV interface for source mode ** ** Returns bt_status_t ** *******************************************************************************/ static bt_status_t init_src(btav_callbacks_t* callbacks) { bt_status_t status = btif_av_init(); if (status == BT_STATUS_SUCCESS) bt_av_src_callbacks = callbacks;//保存JNI層的callback
上面的callback 是JNI 層 注冊下來的,猜想,應該都是一些狀態上報的callback,我們看看 都有哪些函數:
static btav_callbacks_t sBluetoothA2dpCallbacks = { sizeof(sBluetoothA2dpCallbacks), bta2dp_connection_state_callback,//連接狀態上報 bta2dp_audio_state_callback//audio的狀態上報 };
下面我們關注一下btif_av_init的實現:
/******************************************************************************* ** ** Function btif_av_init ** ** Description Initializes btif AV if not already done ** ** Returns bt_status_t ** *******************************************************************************/ bt_status_t btif_av_init() { if (btif_av_cb.sm_handle == NULL) { if (!btif_a2dp_start_media_task())//開啟media 的線程 return BT_STATUS_FAIL; /* Also initialize the AV state machine */ btif_av_cb.sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);//初始化協議棧層面的btif里的狀態機 btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);//enable source service #if (BTA_AV_SINK_INCLUDED == TRUE) btif_enable_service(BTA_A2DP_SINK_SERVICE_ID); btif_a2dp_on_init();//啥也沒干 } return BT_STATUS_SUCCESS; }
這里還涉及到sink的部分,暫時不講。
上面的代碼流程分為兩個部分:
- 開啟media task的流程
- btif_sm 的初始化
- btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID)
我們先看第一部分:
開啟media task的流程
bool btif_a2dp_start_media_task(void) { ... btif_media_cmd_msg_queue = fixed_queue_new(SIZE_MAX);//新建一個隊列用於處理media 相關的cmd /* start a2dp media task */ worker_thread = thread_new("media_worker");//新建一個media_worker 縣城 fixed_queue_register_dequeue(btif_media_cmd_msg_queue, thread_get_reactor(worker_thread), btif_media_thread_handle_cmd, NULL);將隊列和thread綁定 thread_post(worker_thread, btif_media_thread_init, NULL);//post 到media 線程中繼續media 線程的init 行為 APPL_TRACE_EVENT("## A2DP MEDIA THREAD STARTED ##"); return true; }
這里我們看看,會有哪些cmd 會塞到這個隊列里面去處理:
/* BTIF media cmd event definition : BTIF_MEDIA_TASK_CMD */ enum { BTIF_MEDIA_START_AA_TX = 1, BTIF_MEDIA_STOP_AA_TX, BTIF_MEDIA_AA_RX_RDY, BTIF_MEDIA_UIPC_RX_RDY, BTIF_MEDIA_SBC_ENC_INIT, BTIF_MEDIA_SBC_ENC_UPDATE, BTIF_MEDIA_SBC_DEC_INIT, BTIF_MEDIA_VIDEO_DEC_INIT, BTIF_MEDIA_FLUSH_AA_TX, BTIF_MEDIA_FLUSH_AA_RX, BTIF_MEDIA_AUDIO_FEEDING_INIT, BTIF_MEDIA_AUDIO_RECEIVING_INIT, BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE, BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK }
下面我們分析下 btif_media_thread_init都做了哪些事情:
static void btif_media_thread_init(UNUSED_ATTR void *context) { memset(&btif_media_cb, 0, sizeof(btif_media_cb)); UIPC_Init(NULL); #if (BTA_AV_INCLUDED == TRUE) UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb);//打開了audio的控制通道 #endif raise_priority_a2dp(TASK_HIGH_MEDIA);//提升優先級 media_task_running = MEDIA_TASK_STATE_ON;//標志線程狀態 }
我們現在看看
btif_sm 的初始化
/***************************************************************************** ** ** Function btif_sm_init ** ** Description Initializes the state machine with the state handlers ** The caller should ensure that the table and the corresponding ** states match. The location that 'p_handlers' points to shall ** be available until the btif_sm_shutdown API is invoked. ** ** Returns Returns a pointer to the initialized state machine handle. ** ******************************************************************************/ btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers, btif_sm_state_t initial_state) { btif_sm_cb_t *p_cb; if (p_handlers == NULL) { BTIF_TRACE_ERROR("%s : p_handlers is NULL", __FUNCTION__); return NULL; } p_cb = (btif_sm_cb_t *)osi_malloc(sizeof(btif_sm_cb_t)); p_cb->state = initial_state;//初始狀態 p_cb->p_handlers = (btif_sm_handler_t*)p_handlers;一組函數指針 /* Send BTIF_SM_ENTER_EVT to the initial state */ p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL);//進入到初始狀態 return (btif_sm_handle_t)p_cb; }
這個函數 是要返回一個btif_sm_handle_t 結構給btif_av_cb.sm_handle,這個結構,里面包含一個state以及函數指針 ,如下:
typedef struct { btif_sm_state_t state; btif_sm_handler_t *p_handlers; } btif_sm_cb_t;
我們現在看看,這個函數進行初始化的時候傳入的函數指針 有哪些:
static const btif_sm_handler_t btif_av_state_handlers[] = { btif_av_state_idle_handler, btif_av_state_opening_handler, btif_av_state_opened_handler, btif_av_state_started_handler, btif_av_state_closing_handler };
我們發現是 不同狀態下的處理句柄。最后我們看看(BTIF_SM_ENTER_EVT)進入初始狀態,有執行什么操作:
static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) { BTIF_TRACE_DEBUG("%s event:%s flags %x", __FUNCTION__, dump_av_sm_event_name(event), btif_av_cb.flags); switch (event) { case BTIF_SM_ENTER_EVT: /* clear the peer_bda */ memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t)); btif_av_cb.flags = 0; btif_av_cb.edr = 0; btif_a2dp_on_idle();//btif_media_cb 設置為idle,reset audio_codec_config break;
下面我們看看
btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);
/******************************************************************************* ** ** Function btif_enable_service ** ** Description Enables the service 'service_ID' to the service_mask. ** Upon BT enable, BTIF core shall invoke the BTA APIs to ** enable the profiles ** ** Returns bt_status_t ** *******************************************************************************/ bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id) { tBTA_SERVICE_ID *p_id = &service_id; /* If BT is enabled, we need to switch to BTIF context and trigger the * enable for that profile * * Otherwise, we just set the flag. On BT_Enable, the DM will trigger * enable for the profiles that have been enabled */ btif_enabled_services |= (1 << service_id);//更新此全局變量 if (btif_is_enabled()) { btif_transfer_context(btif_dm_execute_service_request, BTIF_DM_ENABLE_SERVICE, (char*)p_id, sizeof(tBTA_SERVICE_ID), NULL); } return BT_STATUS_SUCCESS; }
我們繼續看btif_dm_execute_service_request:
void btif_dm_execute_service_request(UINT16 event, char *p_param) { BOOLEAN b_enable = FALSE; bt_status_t status; if (event == BTIF_DM_ENABLE_SERVICE) { b_enable = TRUE; } status = btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable); if (status == BT_STATUS_SUCCESS) { bt_property_t property; bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS]; /* Now send the UUID_PROPERTY_CHANGED event to the upper layer */ BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS, sizeof(local_uuids), local_uuids); btif_storage_get_adapter_property(&property); HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1, &property);//注意這里調用的是adapter_properties_cb,代表local的屬性,不是remote devices的 } return; }
我們繼續看btif_in_execute_service_request的實現:
bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id, BOOLEAN b_enable) { BTIF_TRACE_DEBUG("%s service_id: %d", __FUNCTION__, service_id); /* Check the service_ID and invoke the profile's BT state changed API */ switch (service_id) { case BTA_HFP_SERVICE_ID: case BTA_HSP_SERVICE_ID: { btif_hf_execute_service(b_enable); }break; case BTA_A2DP_SOURCE_SERVICE_ID: { btif_av_execute_service(b_enable); }break;
我們繼續看btif_av_execute_service:
/******************************************************************************* ** ** Function btif_av_execute_service ** ** Description Initializes/Shuts down the service ** ** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise ** *******************************************************************************/ bt_status_t btif_av_execute_service(BOOLEAN b_enable) { if (b_enable) { /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not * handle this request in order to allow incoming connections to succeed. * We need to put this back once support for this is added */ /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not * auto-suspend av streaming on AG events(SCO or Call). The suspend shall * be initiated by the app/audioflinger layers */ BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR|BTA_AV_FEAT_NO_SCO_SSPD|BTA_AV_FEAT_RCCT|BTA_AV_FEAT_ADV_CTRL,bte_av_callback);//enable BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback);//register } else { BTA_AvDeregister(btif_av_cb.bta_handle); BTA_AvDisable(); } return BT_STATUS_SUCCESS; }
上面的流程又可以分為兩個部分:
- BTA_AvEnable
- BTA_AvRegister
我們下面分別來分析這兩個部分:
BTA_AvEnable
void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, tBTA_AV_CBACK *p_cback) { tBTA_AV_API_ENABLE *p_buf; /* register with BTA system manager */ bta_sys_register(BTA_ID_AV, &bta_av_reg);//注冊了BTA_ID_AV模塊 if ((p_buf = (tBTA_AV_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AV_API_ENABLE))) != NULL) { p_buf->hdr.event = BTA_AV_API_ENABLE_EVT; p_buf->p_cback = p_cback; p_buf->features = features; p_buf->sec_mask = sec_mask; bta_sys_sendmsg(p_buf); } }
這里依然是熟悉的 線程間通信,這里發出的第一個event 是BTA_AV_API_ENABLE_EVT,
AV nsm event=0x122b(API_ENABLE)
處理這個狀態機的函數是bta_av_hdl_event,就是上面 剛剛注冊到sys里面的:
看看其實現:
/******************************************************************************* ** ** Function bta_av_hdl_event ** ** Description Advanced audio/video main event handling function. ** ** ** Returns BOOLEAN ** *******************************************************************************/ BOOLEAN bta_av_hdl_event(BT_HDR *p_msg) { UINT16 event = p_msg->event; UINT16 first_event = BTA_AV_FIRST_NSM_EVT; if (event > BTA_AV_LAST_EVT) { return TRUE; /* to free p_msg */ } if(event >= first_event)//BTA_AV_FIRST_NSM_EVT,這里不會在狀態機中處理 { /* non state machine events */ (*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) ((tBTA_AV_DATA *) p_msg); } else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT)//handled by the AV main state machine { /* state machine events */ bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA *) p_msg); } else //這里處理by AV stream state machine { /* stream state machine events */ bta_av_ssm_execute( bta_av_hndl_to_scb(p_msg->layer_specific), p_msg->event, (tBTA_AV_DATA *) p_msg); } return TRUE; }
分析上面的bta_av_hdl_event 處理,發現其把event 分成了三類,
- 一種是在AV main state machine里面處理的,即調用bta_av_sm_execute 來處理
- 第二種是stream state machine 里面處理的,即調用bta_av_ssm_execute
- 第三種是不在狀態機里面處理,即調用bta_av_nsm_act 里面的函數來處理
下面我們是各種情況對應的event:
bta_av_sm_execute處理如下的event:
/* these events are handled by the AV main state machine */ BTA_AV_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_AV),//0x1200 BTA_AV_API_REMOTE_CMD_EVT, BTA_AV_API_VENDOR_CMD_EVT, BTA_AV_API_VENDOR_RSP_EVT, BTA_AV_API_META_RSP_EVT, BTA_AV_API_RC_CLOSE_EVT, BTA_AV_AVRC_OPEN_EVT, BTA_AV_AVRC_MSG_EVT, BTA_AV_AVRC_NONE_EVT,//0x1208
bta_av_ssm_execute 處理如下的event:
/* these events are handled by the AV stream state machine */ BTA_AV_API_OPEN_EVT,//0x1209 BTA_AV_API_CLOSE_EVT, BTA_AV_AP_START_EVT, //0x120b /* the following 2 events must be in the same order as the *API_*EVT */ BTA_AV_AP_STOP_EVT, /*其含義就是從API的相關的狀態直接跳轉到相應的狀態機中執行*/ BTA_AV_API_RECONFIG_EVT, BTA_AV_API_PROTECT_REQ_EVT, BTA_AV_API_PROTECT_RSP_EVT, BTA_AV_API_RC_OPEN_EVT, BTA_AV_SRC_DATA_READY_EVT, BTA_AV_CI_SETCONFIG_OK_EVT, BTA_AV_CI_SETCONFIG_FAIL_EVT, BTA_AV_SDP_DISC_OK_EVT, BTA_AV_SDP_DISC_FAIL_EVT, BTA_AV_STR_DISC_OK_EVT, BTA_AV_STR_DISC_FAIL_EVT, BTA_AV_STR_GETCAP_OK_EVT, BTA_AV_STR_GETCAP_FAIL_EVT, BTA_AV_STR_OPEN_OK_EVT, BTA_AV_STR_OPEN_FAIL_EVT, BTA_AV_STR_START_OK_EVT, BTA_AV_STR_START_FAIL_EVT, BTA_AV_STR_CLOSE_EVT, BTA_AV_STR_CONFIG_IND_EVT, BTA_AV_STR_SECURITY_IND_EVT, BTA_AV_STR_SECURITY_CFM_EVT, BTA_AV_STR_WRITE_CFM_EVT, BTA_AV_STR_SUSPEND_CFM_EVT, BTA_AV_STR_RECONFIG_CFM_EVT, BTA_AV_AVRC_TIMER_EVT, BTA_AV_AVDT_CONNECT_EVT, BTA_AV_AVDT_DISCONNECT_EVT, BTA_AV_ROLE_CHANGE_EVT, BTA_AV_AVDT_DELAY_RPT_EVT, BTA_AV_ACP_CONNECT_EVT,
bta_av_nsm_act 處理如下的event:
/* these events are handled outside of the state machine */ BTA_AV_API_ENABLE_EVT, BTA_AV_API_REGISTER_EVT, BTA_AV_API_DEREGISTER_EVT, BTA_AV_API_DISCONNECT_EVT, BTA_AV_CI_SRC_DATA_READY_EVT, BTA_AV_SIG_CHG_EVT, BTA_AV_SIG_TIMER_EVT, BTA_AV_SDP_AVRC_DISC_EVT, BTA_AV_AVRC_CLOSE_EVT, BTA_AV_CONN_CHG_EVT, BTA_AV_DEREG_COMP_EVT, #if (BTA_AV_SINK_INCLUDED == TRUE) BTA_AV_API_SINK_ENABLE_EVT, #endif #if (AVDT_REPORTING == TRUE) BTA_AV_AVDT_RPT_CONN_EVT, #endif BTA_AV_API_START_EVT, //0x1238
下面我們繼續看BTA_AV_API_ENABLE_EVT的處理情況:
/******************************************************************************* ** ** Function bta_av_api_enable ** ** Description Handle an API enable event. ** ** ** Returns void ** *******************************************************************************/ static void bta_av_api_enable(tBTA_AV_DATA *p_data) { int i; tBTA_AV_ENABLE enable; /* initialize control block */ memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB));//bta_av_cb的生命線從此刻開始 for(i=0; i<BTA_AV_NUM_RCB; i++) bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE;//rcb avrcp control block bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE; /* store parameters */ bta_av_cb.p_cback = p_data->api_enable.p_cback;//bte_av_callback bta_av_cb.features = p_data->api_enable.features; bta_av_cb.sec_mask = p_data->api_enable.sec_mask; enable.features = bta_av_cb.features; /* Register for SCO change event */ if (!(bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD)) { bta_sys_sco_register(bta_av_sco_chg_cback); } /* call callback with enable event */ (*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, (tBTA_AV *)&enable);//調用回調,預示av enable 完成 }
回調函數處理的流程是 找對對應狀態的handler 來處理event,當前的btif_av狀態是idle對於BTA_AV_ENABLE_EVT 沒有處理,這里就不分析了。
下面我們看看
BTA_AvRegister
/******************************************************************************* ** ** Function BTA_AvRegister ** ** Description Register the audio or video service to stack. When the ** operation is complete the callback function will be ** called with a BTA_AV_REGISTER_EVT. This function must ** be called before AVDT stream is open. ** ** ** Returns void ** *******************************************************************************/ void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback) { tBTA_AV_API_REG *p_buf; if ((p_buf = (tBTA_AV_API_REG *) GKI_getbuf(sizeof(tBTA_AV_API_REG))) != NULL) { p_buf->hdr.layer_specific = chnl; p_buf->hdr.event = BTA_AV_API_REGISTER_EVT; if(p_service_name) { BCM_STRNCPY_S(p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name, BTA_SERVICE_NAME_LEN); p_buf->p_service_name[BTA_SERVICE_NAME_LEN-1] = 0;//保存名字 } else { p_buf->p_service_name[0] = 0; } p_buf->app_id = app_id; p_buf->p_app_data_cback = p_data_cback;//保存callback bta_sys_sendmsg(p_buf); } }
這里還是熟悉的線程間通信,由上面的分析得知,這個事件是由bta_av_nsm_act 來處理:
我們看看具體的實現,這個函數非常的長,里面主要涉及 結構的初始化,以及將結構注冊到AVDTP,
/******************************************************************************* ** ** Function bta_av_api_register ** ** Description allocate stream control block, ** register the service to stack ** create SDP record ** ** Returns void ** *******************************************************************************/ static void bta_av_api_register(tBTA_AV_DATA *p_data) { tBTA_AV_REGISTER registr; tBTA_AV_SCB *p_scb; /* stream control block */ tAVDT_REG reg; tAVDT_CS cs; char *p_service_name; tBTA_AV_CODEC codec_type; tBTA_UTL_COD cod; UINT8 index = 0; char p_avk_service_name[BTA_SERVICE_NAME_LEN+1]; BCM_STRNCPY_S(p_avk_service_name, sizeof(p_avk_service_name), BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN);//sink service name memset(&cs,0,sizeof(tAVDT_CS));//初始化cs,該項最終拷貝到p_scb->cfg,並且AVDT_CreateStream 會使用到 registr.status = BTA_AV_FAIL_RESOURCES;//register 記錄注冊的信息,回調的時候會上報 registr.app_id = p_data->api_reg.app_id;//0 registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;//audio 0x40 do //do...while(0)結構 { p_scb = bta_av_alloc_scb(registr.chnl);//分配了一個 stream control block :bta_av_cb.p_scb[xx] = p_scb registr.hndl = p_scb->hndl;//0x41 or 0x42 --- hndl = (tBTA_AV_HNDL)((xx + 1) | chnl); p_scb->app_id = registr.app_id;//0 /* initialize the stream control block */ p_scb->timer.p_cback = (TIMER_CBACK*)&bta_av_timer_cback; registr.status = BTA_AV_SUCCESS; if((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0)//開始沒有注冊等於0 { /* the first channel registered. register to AVDTP */ reg.ctrl_mtu = p_bta_av_cfg->sig_mtu; reg.ret_tout = BTA_AV_RET_TOUT; reg.sig_tout = BTA_AV_SIG_TOUT; reg.idle_tout = BTA_AV_IDLE_TOUT; reg.sec_mask = bta_av_cb.sec_mask; #if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) bta_ar_reg_avdt(®, bta_av_conn_cback, BTA_ID_AV);//AR module registration to AVDT. #endif bta_sys_role_chg_register(&bta_av_sys_rs_cback); /* create remote control TG service if required */ if (bta_av_cb.features & (BTA_AV_FEAT_RCTG)) { /* register with no authorization; let AVDTP use authorization instead */ #if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);//注冊到AVCT #endif bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL, p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV);//給AVRCP注冊一個sdp record #endif } /* Set the Capturing service class bit */ cod.service = BTM_COD_SERVICE_CAPTURING; utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); } /* if 1st channel */ /* get stream configuration and create stream */ /* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */ cs.cfg.num_codec = 1; cs.tsep = AVDT_TSEP_SRC;//src端 /* * memset of cs takes care setting call back pointers to null. cs.p_data_cback = NULL; cs.p_report_cback = NULL; */ cs.nsc_mask = AVDT_NSC_RECONFIG | ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY); APPL_TRACE_DEBUG("nsc_mask: 0x%x", cs.nsc_mask); p_service_name = p_data->api_reg.p_service_name; p_scb->suspend_sup = TRUE; p_scb->recfg_sup = TRUE; cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi];//根據不同的index 會調用不同bta_av_streamX_cback if(registr.chnl == BTA_AV_CHNL_AUDIO) { /* set up the audio stream control block */ p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;//保存action table p_scb->p_cos = &bta_av_a2d_cos; p_scb->media_type= AVDT_MEDIA_AUDIO; cs.cfg.psc_mask = AVDT_PSC_TRANS; cs.media_type = AVDT_MEDIA_AUDIO; cs.mtu = p_bta_av_cfg->audio_mtu; cs.flush_to = L2CAP_DEFAULT_FLUSH_TO; ... /* keep the configuration in the stream control block */ memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG)); while(index < BTA_AV_MAX_SEPS && (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info, &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)//bta_av_co_audio_init to to initialize audio paths { if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS)//Create a stream endpoint. { p_scb->seps[index].codec_type = codec_type; index++; } } if(!bta_av_cb.reg_audio)//為profile 創建相關的sdp record { /* create the SDP records on the 1st audio channel */ bta_av_cb.sdp_a2d_handle = SDP_CreateRecord(); A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL, A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle); bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE); /* start listening when A2DP is registered */ if (bta_av_cb.features & BTA_AV_FEAT_RCTG) bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); /* if the AV and AVK are both supported, it cannot support the CT role */ if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) { ... #if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) /* create an SDP record as AVRC CT. */ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV); #endif } } bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi); APPL_TRACE_DEBUG("reg_audio: 0x%x",bta_av_cb.reg_audio); } else { /*vedio*/ } } while (0); /* call callback with register event */ (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV *)®istr);//btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl }
上面代碼的大部分已經 謝了注解,這里解釋一下兩點:
- bta_av_a2d_cos.init
- AVDT_CreateStream
- 關於AVDTP的注冊bta_ar_reg_avdt(®, bta_av_conn_cback, BTA_ID_AV) (其實這個應該算第一點,因為只是一些注冊性的內容,所以最后講)
我們先看一下bta_av_a2d_cos.init的實現:
/******************************************************************************* ** ** Function bta_av_co_audio_init ** ** Description This callout function is executed by AV when it is ** started by calling BTA_AvRegister(). This function can be ** used by the phone to initialize audio paths or for other ** initialization purposes. ** ** ** Returns Stream codec and content protection capabilities info. ** *******************************************************************************/ BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index) { FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_init: %d", index); /* By default - no content protection info */ *p_num_protect = 0; *p_protect_info = 0; /* reset remote preference through setconfig */ bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE; switch (index) { case BTIF_SV_AV_AA_SBC_INDEX: /* Set up for SBC codec for SRC*/ *p_codec_type = BTA_AV_CODEC_SBC; /* This should not fail because we are using constants for parameters */ A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_caps, p_codec_info);//初始化和audio相關的參數 /* Codec is valid */ return TRUE; ... default: /* Not valid */ return FALSE; } }
我們再看一下AVDT_CreateStream 的行為:
/******************************************************************************* ** ** Function AVDT_CreateStream ** ** Description Create a stream endpoint. After a stream endpoint is ** created an application can initiate a connection between ** this endpoint and an endpoint on a peer device. In ** addition, a peer device can discover, get the capabilities, ** and connect to this endpoint. ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs) { UINT16 result = AVDT_SUCCESS; tAVDT_SCB *p_scb; /* Verify parameters; if invalid, return failure */ if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL)) { result = AVDT_BAD_PARAMS; } /* Allocate scb; if no scbs, return failure */ else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL)//分配avdt_cb.scb里面的節點 { result = AVDT_NO_RESOURCES; } else { *p_handle = avdt_scb_to_hdl(p_scb);//分配的節點在avdt_cb.scb里面的位置+1 是handle的值-->p_scb->seps[index].av_handle } return result; }
發現這個AVDT_CreateStream,本質上就是在AVDTP層創建stream control block 節點,並把這個節點用一個handle和bta_av_cb.p_scb 里面的節點 相關聯。
最后我們來簡單看一下
關於AVDTP的注冊bta_ar_reg_avdt(®, bta_av_conn_cback, BTA_ID_AV)
這里無非就是一些注冊性質的行為,我們簡單分析一下:
/******************************************************************************* ** ** Function bta_ar_reg_avdt ** ** Description AR module registration to AVDT. ** ** Returns void ** *******************************************************************************/ void bta_ar_reg_avdt(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback, tBTA_SYS_ID sys_id) { UINT8 mask = 0; if (sys_id == BTA_ID_AV) { bta_ar_cb.p_av_conn_cback = p_cback;//保存回調bta_av_conn_cback,其作用暫時不管 mask = BTA_AR_AV_MASK; } else if (sys_id == BTA_ID_AVK) { bta_ar_cb.p_avk_conn_cback = p_cback; mask = BTA_AR_AVK_MASK; } if (mask) { if (bta_ar_cb.avdt_registered == 0) { AVDT_Register(p_reg, bta_ar_avdt_cback);//注冊AVDTP } bta_ar_cb.avdt_registered |= mask; } }
我們繼續分析 AVDTP_Register,
/******************************************************************************* ** ** Function AVDT_Register ** ** Description This is the system level registration function for the ** AVDTP protocol. This function initializes AVDTP and ** prepares the protocol stack for its use. This function ** must be called once by the system or platform using AVDTP ** before the other functions of the API an be used. ** ** ** Returns void ** *******************************************************************************/ void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback) { /* register PSM with L2CAP */ L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO *) &avdt_l2c_appl); /* set security level */ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG); BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG); /* do not use security on the media channel */ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA); BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA); #if AVDT_REPORTING == TRUE /* do not use security on the reporting channel */ BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT); BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT); #endif /* initialize AVDTP data structures */ avdt_scb_init(); avdt_ccb_init(); avdt_ad_init(); /* copy registration struct */ memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG));//保存reg信息到avdt_cb.rcb里面 avdt_cb.p_conn_cback = p_cback;//保存回調bta_ar_avdt_cback,發現這個函數的實現就是調用bta_ar_cb.p_av_conn_cback }
下面我們分析一下,上面的初始化AVDTP 數據結構的三個函數,我們先看看avdt_scb_init,從名字上面看,應該是初始化stream control block,
/******************************************************************************* ** ** Function avdt_scb_init ** ** Description Initialize stream control block module. ** ** ** Returns Nothing. ** *******************************************************************************/ void avdt_scb_init(void) { memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS); avdt_cb.p_scb_act = (tAVDT_SCB_ACTION *) avdt_scb_action;//保存action,這個是為了之后狀態機中執行 }
繼續看avdt_ccb_init, 從名字上面看,應該是初始化channel control block,
/******************************************************************************* ** ** Function avdt_ccb_init ** ** Description Initialize channel control block module. ** ** ** Returns Nothing. ** *******************************************************************************/ void avdt_ccb_init(void) { memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS); avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION *) avdt_ccb_action;//為了后續在channel 狀態機中執行action 使用 }
最后,我們看看avdt_ad_init的實現:Initialize adaption layer
/******************************************************************************* ** ** Function avdt_ad_init ** ** Description Initialize adaption layer. ** ** ** Returns Nothing. ** *******************************************************************************/ void avdt_ad_init(void) { int i; tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl; memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD)); /* make sure the peer_mtu is a valid value */ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; } }
關於a2dp的JNI以下的初始化的過程,這里補了一張圖片:
好了,關於BTA_AvRegister 就講到這里,a2dp的初始化的工作也已經完成了。