标签:指针 har obj following result and with down records
蓝牙启动的时候,会涉及到各个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的部分,暂时不讲。
上面的代码流程分为两个部分:
我们先看第一部分:
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;//标志线程状态 }
我们现在看看
/***************************************************************************** ** ** 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;
下面我们看看
/******************************************************************************* ** ** 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; }
上面的流程又可以分为两个部分:
我们下面分别来分析这两个部分:
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 分成了三类,
下面我们是各种情况对应的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 没有处理,这里就不分析了。
下面我们看看
/******************************************************************************* ** ** 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的实现:
/******************************************************************************* ** ** 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 里面的节点 相关联。
好了,关于BTA_AvRegister 就讲到这里,a2dp的初始化的工作也已经完成了。
标签:指针 har obj following result and with down records
原文地址:https://www.cnblogs.com/libs-liu/p/9406985.html