Bluetooth 之 bluedroid A2DP Init

Posted by Vector Blog on September 20, 2017

1. init

@ btif_av.c

static bt_status_t init_src(btav_callbacks_t* callbacks, int max_a2dp_connections,
                            int a2dp_multicast_state, const char* offload_cap)
{
    .....
    	 //目前上层传下来的 offload_cap 为null
         if (offload_cap)
        {
            bt_split_a2dp_enabled = TRUE;
            //设定支援的 codec 
            get_offload_codec_capabilities(offload_cap);
            is_multicast_supported = FALSE; //Disable multicast in Split A2dp mode
        }
        status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);

    if (status == BT_STATUS_SUCCESS) {
    	// 保存 callback
        bt_av_src_callbacks = callbacks;
    }

    return status;
}

bt_status_t btif_av_init(int service_id)
{
    int i;
    // 为了支持多设备这里 btif_av_cb 变为数组
    if (btif_av_cb[0].sm_handle == NULL)
    {
        ......
        btif_av_cb[0].service = service_id;

        /* 初始化a2dp 的状态机 */
        for (i = 0; i < btif_max_av_clients; i++)
        {
            // 关键函数 ①
            btif_av_cb[i].sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers,
                                                    BTIF_AV_STATE_IDLE, i);
        }
	// 关键函数 ②
        btif_transfer_context(btif_av_handle_event, BTIF_AV_INIT_REQ_EVT,
                (char*)&service_id, sizeof(int), NULL);
	// 关键函数 ③
        btif_enable_service(service_id);
    }

    return BT_STATUS_SUCCESS;
}

分别来看以上3个关键函数

1.1 btif_sm_init

用来初始化 a2dp 的状态机, 将 btif_av_cb[i].sm_handle 指向一个 btif_sm_cb_t 结构体

typedef struct {
    btif_sm_state_t         state;	//初始状态为 BTIF_AV_STATE_IDLE 
    int                     index;		//a2dp 设备号
    //状态处理函数数组, 指向 btif_av_state_handlers
    btif_sm_handler_t       *p_handlers;	
} btif_sm_cb_t;

typedef enum {
    BTIF_AV_STATE_IDLE = 0x0,
    BTIF_AV_STATE_OPENING,
    BTIF_AV_STATE_OPENED,
    BTIF_AV_STATE_STARTED,
    BTIF_AV_STATE_CLOSING
} btif_av_state_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
};

a2dp 的连接状态切换都会由 btif_av_cb[i].sm_handle 来记录和处理。 在初始化状态机之后 btif_sm_init 最后会向初始状态发送 BTIF_SM_ENTER_EVT :

    /* Send BTIF_SM_ENTER_EVT to the initial state */
    p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL, index);

由 btif_av_state_idle_handler 来处理 , 其中做一些 cleanup 以及参数的初始化

1.2 btif_a2dp_start_media_task

btif_av_init 函数中还会调用到

        btif_transfer_context(btif_av_handle_event, BTIF_AV_INIT_REQ_EVT,
                (char*)&service_id, sizeof(int), NULL);

前面的笔记有分析 bluedroid 中线程及消息的处理, 这里不再详细分析其过程。 最终的处理是在

static void btif_av_handle_event(UINT16 event, char* p_param)
{
    ......
    switch (event)
    {
        case BTIF_AV_INIT_REQ_EVT:
            if(btif_a2dp_start_media_task())
                btif_a2dp_on_init();
            break;
}

btif_a2dp_start_media_task 中又会涉及很多的跨线程通信, 先不看这些内容, 直接看最后的调用 :

static void btif_media_thread_init(UNUSED_ATTR void *context) {
  // 仅支持 8 bits/byte
  assert(CHAR_BIT == 8);

  APPL_TRACE_IMP(" btif_media_thread_init");
  memset(&btif_media_cb, 0, sizeof(btif_media_cb));

  UIPC_Init(NULL);

  btif_media_cb.TxAaQ = fixed_queue_new(SIZE_MAX);
  btif_media_cb.RxSbcQ = fixed_queue_new(SIZE_MAX);
  UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb);

  raise_priority_a2dp(TASK_HIGH_MEDIA);
  media_task_running = MEDIA_TASK_STATE_ON;
  APPL_TRACE_DEBUG(" btif_media_thread_init complete");
}

这里主要函数为 UIPC_InitUIPC_Open , 他们的作用是什么呢?
Audio Flinger 加载 audio_a2dp_hw 来向 bluedroid 传输数据, 而他们通信的方式就是通过两个socket :

#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"

从名字可以看出一个是用来控制,另一个是用来传输。 UIPC_Init 中初始化 uipc_main , 这里的 UIPC_Open 中创建 a2dp_ctrl socket , 其事件处理函数为 btif_a2dp_ctrl_cb 。 来看一下这里的结构 :

static tUIPC_MAIN uipc_main;

typedef struct {
    pthread_t tid;     // event 处理线程 uipc_read_task
    int running;	     // uipc_read_task 状态
    pthread_mutex_t mutex;

    fd_set active_set;    // uipc_read_task 中监听的fd集合
    fd_set read_set;	   // 等于active_set
    int max_fd;
    int signal_fds[2];	  // interrupt socket pair

    tUIPC_CHAN ch[UIPC_CH_NUM];	 //包含 a2dp_ctrl , a2dp_data 的socket fd 的结构体
} tUIPC_MAIN;

其中两个 tUIPC_CHAN 变量, 分别对应 a2dp_ctrl , a2dp_data

typedef struct {
    int srvfd;	// server socket fd
    int fd;		// 连接的socket fd
    int read_poll_tmo_ms;
    int task_evt_flags;   /* event flags pending to be processed in read task */
    tUIPC_EVENT cond_flags;
    pthread_mutex_t cond_mutex;
    pthread_cond_t  cond;
    tUIPC_RCV_CBACK *cback;	   //event 处理函数
} tUIPC_CHAN;

1.3 btif_enable_service

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

看注释的意思: 如果此时 BT 还没有enable , 则仅设置 flag , 在后面 BT enable 之后 DM 将会把这些设置了 flag 的 profile enable 起来; 如果此时 BT 已经enable 则主动去 enable 该profile 。 实际抓到的 log 来看一般这里 BT 还没有enable 。

2. enable a2dp profile

在来看一下 BT enable 之后是如何 enable a2dp profile 的 , 当 enable 到一定阶段会发送 bluedroid 中会发送 BTA_DM_ENABLE_EVT

static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
{
    switch (event)
    {
        case BTA_DM_ENABLE_EVT:
        {
             /* 获取到所有需要enable profile 的mask , 然后enable profiles */
             service_mask = btif_get_enabled_services_mask();
             for (i=0; i <= BTA_MAX_SERVICE_ID; i++)
             {
                 if (service_mask &
                     (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i)))
                 {
                     btif_in_execute_service_request(i, TRUE);
                 }
             }
 	}
 }
 
 bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
                                                BOOLEAN b_enable)
{
         case BTA_A2DP_SOURCE_SERVICE_ID:
         {
              btif_av_execute_service(b_enable);
          ......
 }

a2dp profile enable 开始

bt_status_t btif_av_execute_service(BOOLEAN b_enable)
{
     if (b_enable)
     {
         BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_RCTG|...|BTA_AV_FEAT_ADV_CTRL
             ,bte_av_callback);
      
         BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
                                                             UUID_SERVCLASS_AUDIO_SOURCE);
     }
     else {
         BTA_AvDeregister(btif_av_cb.bta_handle);
         BTA_AvDisable();
     }
     return BT_STATUS_SUCCESS;
}

2.1 BTA_AvEnable

void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, tBTA_AV_CBACK *p_cback)
{
    tBTA_AV_API_ENABLE *p_buf =
        (tBTA_AV_API_ENABLE *)osi_malloc(sizeof(tBTA_AV_API_ENABLE));

    /* register with BTA system manager */
    bta_sys_register(BTA_ID_AV, &bta_av_reg);

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

bta_sys_register

在 bta 这一层每一个 profile 都会设置其event 处理函数 :

void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg)
{
    bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg;
    bta_sys_cb.is_reg[id] = TRUE;
}

static const tBTA_SYS_REG bta_av_reg =
{
    bta_av_hdl_event,
    BTA_AvDisable
};

BTA_AV_API_ENABLE_EVT

回头看 BTA_AvEnable 还会发送一个 BTA_AV_API_ENABLE_EVT 消息, 此外消息中的 p_cback 为 bte_av_callback
bta_sys_sendmsg 发送的消息最后都会由 bta_sys_event 来处理, 其中会根据 event 中的前8位service id 来交给 bta_sys_cb.reg[id]->evt_hdlr (每个profile 的 event handler)处理

void bta_sys_event(BT_HDR *p_msg)
{
    /* get subsystem id from event */
    id = (UINT8) (p_msg->event >> 8);

    if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
    {
        freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
    }
}

前面可以看到这里 a2dp 对应的 bta_sys_cb.reg[id]->evt_hdlr 就是 bta_av_reg.bta_av_hdl_event

再来看 bta_av_hdl_event 其中将 BTA AV event 分为3类来调用不同的处理函数 :

BOOLEAN bta_av_hdl_event(BT_HDR *p_msg)
{
    UINT16 event = p_msg->event;
    UINT16 first_event = BTA_AV_FIRST_NSM_EVT;

    if(event >= first_event)
    {
        /* 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)
    {
        /* state machine events */
        bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA *) p_msg);
    }
    else
    {
        /* 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_API_ENABLE_EVT 属于 “non state machine events” , (*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) 对应到 :

const tBTA_AV_NSM_ACT bta_av_nsm_act[] =
{
    bta_av_api_enable,      /* BTA_AV_API_ENABLE_EVT */
    bta_av_api_register,    /* BTA_AV_API_REGISTER_EVT */
    ......
static void bta_av_api_enable(tBTA_AV_DATA *p_data)
{
    /* initialize control block */
    memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB));

    for (int i = 0; i < BTA_AV_NUM_RCB; i++)
        bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE;

    bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;

    /*
     * TODO: The "disable" event handling is missing - there we need
     * to alarm_free() the alarms below.
     */
    bta_av_cb.link_signalling_timer = alarm_new("bta_av.link_signalling_timer");
    bta_av_cb.accept_signalling_timer =
        alarm_new("bta_av.accept_signalling_timer");

    /* 将之前传的数据取出赋值到 bta_av_cb*/
    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;

    tBTA_AV_ENABLE enable;
    enable.features = bta_av_cb.features;

    /* 注册 bta_sys_cb 中的 SCO 连接状态callback p_sco_cb */
    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);
}

这里主要是初始化 bta 中的 a2dp control block : bta_av_cb .
最后将 BTA_AV_ENABLE_EVT 交给 btif_av_cb[index].sm_handle 当前states 的 handler 来处理, 当前为 IDLE 状态由 btif_av_state_idle_handler 来处理, 这里的处理仅仅是打印了一行log :

static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data, int index)
{
        case BTA_AV_ENABLE_EVT:
            BTIF_TRACE_EVENT("AV is enabled now for index: %d", index);
            break;

2.2 BTA_AvRegister

继续 btif_av_execute_service 的第二个函数 BTA_AvRegister

BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback,
                                                             UUID_SERVCLASS_AUDIO_SOURCE);

void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
                    tBTA_AV_DATA_CBACK  *p_data_cback, UINT16 service_uuid)
{
    tBTA_AV_API_REG *p_buf =
        (tBTA_AV_API_REG *)osi_malloc(sizeof(tBTA_AV_API_REG));

    p_buf->hdr.layer_specific = chnl;
    p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
    ......

    bta_sys_sendmsg(p_buf);
}

发送 BTA_AV_API_REGISTER_EVT 到 bta 层 , 和前面一样最后根据event 中的 service id 交给对应的 handler 处理, a2dp 的处理函数为 bta_av_hdl_event , BTA_AV_API_REGISTER_EVT 对应的处理函数为 bta_av_api_register .

/*******************************************************************************
** Description      allocate stream control block,
**                  register the service to stack
**                  create SDP record
*******************************************************************************/
static void bta_av_api_register(tBTA_AV_DATA *p_data)
{
        if(registr.chnl == BTA_AV_CHNL_AUDIO)
        {
            /* set up the audio stream control block */
            APPL_TRACE_EVENT("AV: set up the audio stream control block ");
            // 后面的a2dp 相关的处理都会用到 bta_av_a2d_action
            p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;
            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;
            ......

            if(!bta_av_cb.reg_audio)
            {
                bta_av_cb.sdp_a2d_handle = 0;
                if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
                {
                    /* 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 */
                ......
            }

这里主要用来初始化 stream control block 即 bta_av_cb.p_scb , 其中包含 AVDTP END POINT 的信息, 此外在创建 “Advanced Audio” SDP record .

3.总结

自己总结一下开起 BT 时主要做的事情 :

  1. 初始化 btif av 状态机 btif_av_cb[i].sm_handle = btif_av_state_handlers (此处 i 为支持的支持连接的 a2dp client 数目),初始状态为 idle , 其状态包含 :
     BTIF_AV_STATE_IDLE = 0x0,
     BTIF_AV_STATE_OPENING,
     BTIF_AV_STATE_OPENED,
     BTIF_AV_STATE_STARTED,
     BTIF_AV_STATE_CLOSING
    
  2. 创建 a2dp_ctrl socket (/data/misc/bluedroid/.a2dp_ctrl)
  3. 设定 bta av 的 event 处理函数 bta_av_hdl_event ,bta 层向上层提供的 AV 接口就是向其发送event , 其中将 event 分为3类来处理 ,
    • non state machine events
    • state machine events
    • stream state machine events
  4. 注册 “Advanced Audio” SDP record , 并填充包含 AVDTP END POINT 的信息