zoukankan      html  css  js  c++  java
  • A2dp初始化流程源码分析

    蓝牙启动的时候,会涉及到各个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的部分,暂时不讲。

    上面的代码流程分为两个部分:

    1. 开启media task的流程
    2. btif_sm 的初始化
    3. 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;
    }

     上面的流程又可以分为两个部分:

    1. BTA_AvEnable
    2. 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 分成了三类,

    1. 一种是在AV main state machine里面处理的,即调用bta_av_sm_execute 来处理
    2. 第二种是stream state machine 里面处理的,即调用bta_av_ssm_execute 
    3. 第三种是不在状态机里面处理,即调用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(&reg, 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 *)&registr);//btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl 
    }

     上面代码的大部分已经 谢了注解,这里解释一下两点:

    1. bta_av_a2d_cos.init 
    2. AVDT_CreateStream 
    3. 关于AVDTP的注册bta_ar_reg_avdt(&reg, 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(&reg, 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的初始化的工作也已经完成了。 


  • 相关阅读:
    并行逻辑回归
    【math】梯度下降法(梯度下降法,牛顿法,高斯牛顿法,Levenberg-Marquardt算法)
    MATLAB 按条件进行加和
    MATLAB 统计不同区间中元素的个数
    MATLAB 统计元素出现的次数
    MATLAB 程序处理结果出现 NAN 问题
    Debug 路漫漫-07
    MATLAB 程序计算结果出现 复数(a+bi)问题
    关于安装 Microsoft Office
    关于推荐系统中的长尾商品
  • 原文地址:https://www.cnblogs.com/libs-liu/p/9406985.html
Copyright © 2011-2022 走看看