A2DP

作者: 力卉编程 | 来源:发表于2020-01-12 14:15 被阅读0次

    蓝牙启动的时候,会涉及到各个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 是一个什么样的接口?其实他就是对原本的服务的一个封装,包含了原来的服务

    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;
        }
    

    上报的状态的部分就不分析了,我们直接看 start的部分:
    avrcp的部分暂时略过,

    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");
                }
            }
        }
    
    
    protected boolean start() {
            mAvrcp = Avrcp.make(this);
            mStateMachine = A2dpStateMachine.make(this, this);//启动状态机
            setA2dpService(this);//设置a2dpService服务为本身sAd2dpService = this
            return true;
        }
    

    初始化状态机
    这里的start就是让状态机转起来,和a2dp 的关系不大,这里不分析 了,我们这里的重头戏是new A2dpStateMachine,这里涉及到一些 变量、状态的初始化,以及协议栈中关于a2dp的初始化。

        static A2dpStateMachine make(A2dpService svc, Context context) {
            A2dpStateMachine a2dpSm = new A2dpStateMachine(svc, context);//新建一个状态机
            a2dpSm.start();//start
            return a2dpSm;
        }
    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);
        }
    

    initNative

    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
    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,
    };
    //sBluetoothA2dpCallbacks  类型
    static btav_callbacks_t sBluetoothA2dpCallbacks = {
        sizeof(sBluetoothA2dpCallbacks),
        bta2dp_connection_state_callback,//连接状态上报
        bta2dp_audio_state_callback//audio的状态上报
    };
    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 sBluetoothA2dpCallbacks 类型
       ...
    }
    

    btif_av_init

    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;
    }
    

    上面的代码流程分为两个部分:
    开启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都做了哪些事情:

    • 打开了audio的控制通道
    • 提升优先级
    • 标志线程状态
    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 的初始化

    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

    btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);

    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;
    }
    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;
    }
    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;
      ...
    }
    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;
    }
    

    参考:https://www.cnblogs.com/libs-liu/p/9406985.html

    相关文章

      网友评论

          本文标题:A2DP

          本文链接:https://www.haomeiwen.com/subject/xbwiactx.html