• Bluedroid: 音频数据的传输流程


    一. UIPC:

      Audio Flinger获取到a2dp的hw module,然后蓝牙协议栈有专用于发送和接收media数据的线程,名称:btif_media_task.

      蓝牙与Audio的通信则采用了socket的方式,管理socket的中间文件为:UIPC。主要的作用就是,接收Audio的控制命令和音频数据发送给BT,即 Audio_a2dp_hw -> UIPC -> btif_media_task

      UIPC建立了两条socket,分别为:
        #define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
       
    #define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"

    1.control socket在btif media task启动的时创建:

    bool btif_a2dp_start_media_task(void)
    {
        ...
        thread_post(worker_thread, btif_media_thread_init, NULL);
    
        APPL_TRACE_EVENT("## A2DP MEDIA THREAD STARTED ##");
    
        return true;
        ...
    }
    
    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);
    #endif
    
      raise_priority_a2dp(TASK_HIGH_MEDIA);
      media_task_running = MEDIA_TASK_STATE_ON;
    }

    2.data socket在收到audio cmd start时创建:

            case A2DP_CTRL_CMD_START:
                /* Don't sent START request to stack while we are in call.
                   Some headsets like the Sony MW600, don't allow AVDTP START
                   in call and respond BAD_STATE. */
                if (!btif_hf_is_call_idle())
                {
                    a2dp_cmd_acknowledge(A2DP_CTRL_ACK_INCALL_FAILURE);
                    break;
                }
    
                if (btif_av_stream_ready() == TRUE)
                {
                    /* setup audio data channel listener */
                    UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
    
                    /* post start event and wait for audio path to open */
                    btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
    
    #if (BTA_AV_SINK_INCLUDED == TRUE)
                    if (btif_media_cb.peer_sep == AVDT_TSEP_SRC)
                        a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);//发送回执
    #endif
                }
                else if (btif_av_stream_started_ready())
                {
                    /* already started, setup audio data channel listener
                       and ack back immediately */
                    UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
    
                    a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);//发送回执
                }
                else
                {
                    a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
                    break;
                }
                break;


    3.UIPC接收command机制:
    (1) 启动时,创建一个thread,接收command:

    void UIPC_Init(void *p_data)
    {
        UNUSED(p_data);
    
        BTIF_TRACE_DEBUG("UIPC_Init");
    
        memset(&uipc_main, 0, sizeof(tUIPC_MAIN));
    
        uipc_main_init();
    
        uipc_start_main_server_thread();
    }
    
    int uipc_start_main_server_thread(void)
    {
        uipc_main.running = 1;
    
        if (pthread_create(&uipc_main.tid, (const pthread_attr_t *) NULL, (void*)uipc_read_task, NULL) < 0)
        {
            BTIF_TRACE_ERROR("uipc_thread_create pthread_create failed:%d", errno);
            return -1;
        }
    
        return 0;
    }

    (2)监听每一个socket,发现数据后,优先判断是不是音频,再判断是不是命令:

    static void uipc_read_task(void *arg)
    {
        while (uipc_main.running)
        {
        result = select(uipc_main.max_fd+1, &uipc_main.read_set, NULL, NULL, NULL);   //发现有数据
        /* make sure we service audio channel first */
        uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO);   //先确定是不是音频
    
        /* check for other connections */
        for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) {
            if (ch_id != UIPC_CH_ID_AV_AUDIO)
                uipc_check_fd_locked(ch_id);         //再确定是不是command
        }
    }
    static int uipc_check_fd_locked(tUIPC_CH_ID ch_id)
    {
        if (uipc_main.ch[ch_id].cback)
            //通知btif,有command过来
            uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
    }

    (3).通知btif去读取command并处理:

    static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event)
    {
        switch(event)
        {
            case UIPC_RX_DATA_READY_EVT:
                btif_recv_ctrl_data();      //去获取command
                break;
         }
    }
    
    static void btif_recv_ctrl_data(void)
    {
        UINT8 cmd = 0;
        int n;
        n = UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &cmd, 1);  //读取该socket上的命令
    }

    二、btif_media_task:

     1.btif_media_task是蓝牙协议栈接收HAL层音频数据的主处理线程,数据流程框图如下:

     

    • BTIF reads PCM data from audio flinger via Audio HAL.(Step 6)
    • BTIF calls SBC encoder to encode PCM data to SBC frames which are put in a queue.(Step 7 and 8)
    • BTIF notifies BTA that the source data is ready in the queue.(Step 9~13)
    • BTA gets the SBC frames from the queue, then adds SBC Header. Media PL is constructed now.(Step 15~17)
    • BTA writes Media PL to AVDTP.(Step 18)
    • AVDTP adds Media Packet Header.(Step 19)

    2.主要代码框架:

    • btif/src/btif_av.c                     Bluedroid AV HAL implementation which implements the interface defined in AOSP/hardware/bt_av.h.
    • btif/src/btif_media_task.c    This is the multimedia module for the BTIF system. It contains task implementations AV, HS and HF profiles' audio&video processing.
    • btif/co/bta_av_co.c               This is the advanced audio/video call-out function implementation for BTIF.
    • bta/av/bta_av_ci.c                This is the implementation for advanced audio/video call-in functions which are called from BTIF.
    • bta/av/bta_av_api.c             This is the implementation of the API for the advanced audio/video(AV) subsystem of BTA. This interface is called from btif_av.c.
    • bta/av/bta_av_mian.c          This is the main implementation file for BTA advanced audio/video.
    • bta/av/bta_av_ssm.c            This is the stream state machine for the BTA advanced audio/video.
    • bta/av/bta_av_aact.c            This file contains action functions for advanced audio/video stream.
    • bta/av/bta_av_sbc.c             This module contains utility functions for dealing with SBC data frames and codec capabilities.
    • stack/a2dp/a2d_api.c           This is the implementation of the API for the Advanced Audio Distribution Profile(A2DP)
    • stack/a2dp/a2d_sbc.c          This file contains utility functions to help build and parse SBC codec information element and media payload.
    • embdrv/sbc/sbc/encoder     This folder contains the files which implement SBC decoder.

    三、A2DP 数据处理流程:

    1.ACL 包发送流程:

    由前面所述,HAL层socket发送的音频数据通过a2dp继续下发到AVDTP:

    而在 AVDTP 中,所有的功能想发送 Data,必须调用 avdt_ad_write_req 这个函数:

    1 //当CCB或SCB给l2cap的 Channel 发送数据时,他们最终都会使用到L2CAP的 API:L2CA_Data_Write
     2 UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
     3 {
     4     UINT8   tcid;
     5 
     6     /* get tcid from type, scb */
     7     tcid = avdt_ad_type_to_tcid(type, p_scb);
     8 
     9 
    10     return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
    11 }
    12 //L2CA_DataWrite的返回形式有三种,分别是:
    13 //1. L2CAP_DW_SUCCESS:此数据写成功
    14 //2.L2CAP_DW_CONGESTED:写数据成功,但是当前信道拥堵
    15 //3.L2CAP_DW_FAILED:写数据失败
    16 UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data)
    17 {
    18     L2CAP_TRACE_API2 ("L2CA_DataWrite()  CID: 0x%04x  Len: %d", cid, p_data->len);
    19     return l2c_data_write (cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
    20 }

    当音频数据流到达 l2c_data_write 这个函数时,标志数据流正式进入到L2CAP层。

    l2c_data_write 这个函数做的事情主要有:

    1. 根据参数 cid(Channel ID) 找到 对应的 ccb(Channel Control Block), 找不到返回 L2CAP_DW_FAILED
    2. 如果测试者 打开 TESTER 这个宏,发送任意数据,当数据大小 大于 MTU 最大值,也会返回L2CAP_DW_FAILED
    3. 通过检查 p_ccb->cong_sent 字段,TRUE,则说明当前 Channel 已经拥挤,此时L2CAP的这个Channel不在接收数据,返回 L2CAP_DW_FAILED
    4. 以上三个条件都通过,说明数据可发送,将数据通过 l2c_csm_execute 继续处理。进入 l2c_csm_execute 函数,标志着这笔数据已经成功交给 l2CAP 来处理,与上层已经没有关系了。
    5. l2c_csm_execute 函数执行结束后,再次检查 p_ccb->cong_sent 字段,看看当前的 Channel 是否拥挤,如果拥挤则告诉上层 L2CAP_DW_CONGESTED,否则返回 L2CAP_DW_SUCCESS,表示数据已经成功发送。
    1 //返回的数据跟上面的 L2CA_DataWrite 作用相同
      2 UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flags)
      3 {
      4     tL2C_CCB        *p_ccb;
      5 
      6     //遍历l2cb.ccb_pool,通过Channel ID找到对应的Channel Control Block
      7     //l2cu_find_ccb_by_cid 见下面源码注释
      8     if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
      9     {
     10         L2CAP_TRACE_WARNING1 ("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
     11         GKI_freebuf (p_data);
     12         return (L2CAP_DW_FAILED);
     13     }
     14 
     15 #ifndef TESTER /* Tester may send any amount of data. otherwise sending message
     16                   bigger than mtu size of peer is a violation of protocol */
     17     if (p_data->len > p_ccb->peer_cfg.mtu)
     18     {
     19         L2CAP_TRACE_WARNING1 ("L2CAP - CID: 0x%04x  cannot send message bigger than peer's mtu size", cid);
     20         GKI_freebuf (p_data);
     21         return (L2CAP_DW_FAILED);
     22     }
     23 #endif
     24 
     25     /* channel based, packet based flushable or non-flushable */
     26     //Bluedroid中默认的是 L2CAP_FLUSHABLE_CH_BASED
     27     //这个 layer_specific 在 数据发送的 l2c_link_send_to_lower 中表示 ACL包分包 个数
     28     p_data->layer_specific = flags;
     29 
     30     //发现本 Channel 已经拥堵,直接返回L2CAP_DW_FAILED 告诉上层等会再发数据
     31     //当几个应用 共用 此 Channel 可能会出现这种情况
     32     if (p_ccb->cong_sent)
     33     {
     34         L2CAP_TRACE_ERROR3 ("L2CAP - CID: 0x%04x cannot send, already congested  xmit_hold_q.count: %u  buff_quota: %u",
     35                             p_ccb->local_cid, p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
     36 
     37         GKI_freebuf (p_data);
     38         return (L2CAP_DW_FAILED);
     39     }
     40     //毫无疑问啦,这个函数就是我们继续需要分析的函数
     41     l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data);
     42 
     43     //已经将上层的这笔数据发送完,如果此 Channel 拥挤了(之前发送这笔包还没拥挤)
     44     //返回 L2CAP_DW_CONGESTED 告诉上层当前信道拥挤,你要给我L2CAP层发数据,是不发下来的
     45     if (p_ccb->cong_sent)
     46         return (L2CAP_DW_CONGESTED);
     47 
     48     //成功发送,并且此时 Channel 并不拥挤
     49     return (L2CAP_DW_SUCCESS);
     50 }
     51 
     52 //通过 Channel ID 找到 Channel Control Block
     53 tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, UINT16 local_cid)
     54 {
     55     tL2C_CCB    *p_ccb = NULL;
     56 #if (L2CAP_UCD_INCLUDED == TRUE)
     57     UINT8 xx;
     58 #endif
     59 
     60     if (local_cid >= L2CAP_BASE_APPL_CID) //大于或等于 0x0040 说明不是 Fixed Channel
     61     {
     62         /* find the associated CCB by "index" */
     63         local_cid -= L2CAP_BASE_APPL_CID;
     64 
     65         if (local_cid >= MAX_L2CAP_CHANNELS)
     66             return NULL;
     67 
     68         p_ccb = l2cb.ccb_pool + local_cid; //直接通过地址偏移找到
     69 
     70         /* make sure the CCB is in use */
     71         if (!p_ccb->in_use)
     72         {
     73             p_ccb = NULL;
     74         }
     75         /* make sure it's for the same LCB */
     76         else if (p_lcb && p_lcb != p_ccb->p_lcb)
     77         {
     78             p_ccb = NULL;
     79         }
     80     }
     81 #if (L2CAP_UCD_INCLUDED == TRUE) //默认是关闭的,既然从上层来的都是 数据包了,我认为不会用到 Fixed Channel
     82     else
     83     {
     84         /* searching fixed channel */
     85         p_ccb = l2cb.ccb_pool;
     86         for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
     87         {
     88             if ((p_ccb->local_cid == local_cid)
     89               &&(p_ccb->in_use)
     90               &&(p_lcb == p_ccb->p_lcb))
     91                 break;
     92             else
     93                 p_ccb++;
     94         }
     95         if ( xx >= MAX_L2CAP_CHANNELS )
     96             return NULL;
     97     }
     98 #endif
     99 
    100     return (p_ccb);
    101 }

    首先进入了 L2CAP 层的状态机:

     1 void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
     2 {
     3     switch (p_ccb->chnl_state)
     4     {
     5     case CST_CLOSED:
     6         l2c_csm_closed (p_ccb, event, p_data);
     7         break;
     8 
     9     case CST_ORIG_W4_SEC_COMP:
    10         l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
    11         break;
    12 
    13     case CST_TERM_W4_SEC_COMP:
    14         l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
    15         break;
    16 
    17     case CST_W4_L2CAP_CONNECT_RSP:
    18         l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
    19         break;
    20 
    21     case CST_W4_L2CA_CONNECT_RSP:
    22         l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
    23         break;
    24 
    25     case CST_CONFIG:
    26         l2c_csm_config (p_ccb, event, p_data);
    27         break;
    28 
    29     case CST_OPEN:
    30         l2c_csm_open (p_ccb, event, p_data);
    31         break;
    32 
    33     case CST_W4_L2CAP_DISCONNECT_RSP:
    34         l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
    35         break;
    36 
    37     case CST_W4_L2CA_DISCONNECT_RSP:
    38         l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
    39         break;
    40 
    41     default:
    42         break;
    43     }
    44 }
    具体的 Channel 状态信息如下
    
     1 typedef enum
     2 {
     3     CST_CLOSED,                           /* Channel is in clodes state           */
     4     CST_ORIG_W4_SEC_COMP,                 /* Originator waits security clearence  */
     5     CST_TERM_W4_SEC_COMP,                 /* Acceptor waits security clearence    */
     6     CST_W4_L2CAP_CONNECT_RSP,             /* Waiting for peer conenct response    */
     7     CST_W4_L2CA_CONNECT_RSP,              /* Waiting for upper layer connect rsp  */
     8     CST_CONFIG,                           /* Negotiating configuration            */
     9     CST_OPEN,                             /* Data transfer state                  */
    10     CST_W4_L2CAP_DISCONNECT_RSP,          /* Waiting for peer disconnect rsp      */
    11     CST_W4_L2CA_DISCONNECT_RSP            /* Waiting for upper layer disc rsp     */
    12 } tL2C_CHNL_STATE;

    音频数据包在函数 l2c_csm_open 中流转,经过各种选择和判断,最后走的是 L2CEVT_L2CA_DATA_WRITE 这个 case。这个 case 调用了 l2c_enqueue_peer_data 让数据进入到当前 ccb 的 xmit_hold_q 队列中,暂存此数据包。l2c_link_check_send_pkts 这个函数发送数据包:

      1 //l2c_csm_open 处理 Channel 处于 OPEN 状态下的各种 Event
      2 static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
      3 {
      4     UINT16                  local_cid = p_ccb->local_cid;
      5     tL2CAP_CFG_INFO         *p_cfg;
      6     tL2C_CHNL_STATE         tempstate;
      7     UINT8                   tempcfgdone;
      8     UINT8                   cfg_result;
      9 
     10 #if (BT_TRACE_VERBOSE == TRUE)
     11     L2CAP_TRACE_EVENT2 ("L2CAP - LCID: 0x%04x  st: OPEN  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
     12 #else
     13     L2CAP_TRACE_EVENT1 ("L2CAP - st: OPEN evt: %d", event);
     14 #endif
     15 
     16 #if (L2CAP_UCD_INCLUDED == TRUE) //默认 UCD 是关闭的
     17     if ( local_cid == L2CAP_CONNECTIONLESS_CID )
     18     {
     19         /* check if this event can be processed by UCD */
     20         if ( l2c_ucd_process_event (p_ccb, event, p_data) )
     21         {
     22             /* The event is processed by UCD state machine */
     23             return;
     24         }
     25     }
     26 #endif
     27 
     28     switch (event)
     29     {
     30     case L2CEVT_LP_DISCONNECT_IND:  //Link 都断开连接了,自然 Channel也没有存在的必要了,各种清除 CCB 的工作
     31         L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
     32         l2cu_release_ccb (p_ccb);//释放 当前的 CCB 
     33         if (p_ccb->p_rcb)
     34             (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
     35         break;
     36 
     37     case L2CEVT_LP_QOS_VIOLATION_IND:               /* QOS violation         */
     38         /* Tell upper layer. If service guaranteed, then clear the channel   */
     39         if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
     40             (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr);
     41         break;
     42 
     43     case L2CEVT_L2CAP_CONFIG_REQ:                  /* Peer config request   */
     44         p_cfg = (tL2CAP_CFG_INFO *)p_data;
     45 
     46         tempstate = p_ccb->chnl_state;
     47         tempcfgdone = p_ccb->config_done;
     48         p_ccb->chnl_state = CST_CONFIG; //如果数据流中的数据是 L2CEVT_L2CAP_CONFIG_REQ,当然要转到 CST_CONFIG中继续处理
     49         p_ccb->config_done &= ~CFG_DONE_MASK;
     50         //启动一个 timer ,一段时间后,查看 cfg 的状态
     51         //如果配置处于 L2CAP_PEER_CFG_UNACCEPTABLE,继续尝试配置
     52         //如果配置处于断开状态,那当前 Channel 直接断开连接。
     53         btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
     54 
     55         if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
     56         {
     57             (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
     58         }
     59 
     60         /* Error in config parameters: reset state and config flag */
     61         else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE)
     62         {
     63             btu_stop_timer(&p_ccb->timer_entry);
     64             p_ccb->chnl_state = tempstate;
     65             p_ccb->config_done = tempcfgdone;
     66             l2cu_send_peer_config_rsp (p_ccb, p_cfg);
     67         }
     68         else    /* L2CAP_PEER_CFG_DISCONNECT */
     69         {
     70             /* Disconnect if channels are incompatible
     71              * Note this should not occur if reconfigure
     72              * since this should have never passed original config.
     73              */
     74             l2cu_disconnect_chnl (p_ccb);
     75         }
     76         break;
     77 
     78     case L2CEVT_L2CAP_DISCONNECT_REQ:                  /* Peer disconnected request */
     79 // btla-specific ++
     80         /* Make sure we are not in sniff mode */
     81 #if BTM_PWR_MGR_INCLUDED == TRUE
     82         {
     83             tBTM_PM_PWR_MD settings;
     84             settings.mode = BTM_PM_MD_ACTIVE;
     85             BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
     86         }
     87 #else
     88         BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
     89 #endif
     90 // btla-specific --
     91 
     92         p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP; //Peer 发送 Disconnect,我们要对此发 Response
     93         btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
     94         L2CAP_TRACE_API1 ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  Conf Needed", p_ccb->local_cid);
     95         (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
     96         break;
     97 
     98     case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
     99         //收到 Peer 传来的数据,当然要把这个数据通过回调送到上层应用去
    100         //pL2CA_DataInd_Cb 中定义了回调,交给上层处理收到的数据
    101         (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
    102         break;
    103 
    104     case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
    105         /* Make sure we are not in sniff mode */
    106 #if BTM_PWR_MGR_INCLUDED == TRUE
    107         {
    108             tBTM_PM_PWR_MD settings;
    109             settings.mode = BTM_PM_MD_ACTIVE;
    110             BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
    111         }
    112 #else
    113         BTM_CancelSniffMode (p_ccb->p_lcb->remote_bd_addr);
    114 #endif
    115 
    116         l2cu_send_peer_disc_req (p_ccb);
    117         p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
    118         btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
    119         break;
    120 
    121     case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */   //mike mark l2c
    122         //上层将数据发送给下层
    123         //我们的音乐数据就是走这个 case(为什么?看整个函数的参数就明白了)
    124         //首先将数据入队,下面会展开分析这个函数
    125         l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
    126         //最终调用 l2c_link_check_send_pkts 来发送我们的音乐数据包
    127         l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
    128         break;
    129 
    130     case L2CEVT_L2CA_CONFIG_REQ:                   /* Upper layer config req   */
    131         p_ccb->chnl_state = CST_CONFIG;
    132         p_ccb->config_done &= ~CFG_DONE_MASK;
    133         l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
    134         l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
    135         btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
    136         break;
    137 
    138     case L2CEVT_TIMEOUT:
    139         /* Process the monitor/retransmission time-outs in flow control/retrans mode */
    140         if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
    141             l2c_fcr_proc_tout (p_ccb);
    142         break;
    143 
    144     case L2CEVT_ACK_TIMEOUT:
    145         l2c_fcr_proc_ack_tout (p_ccb);
    146         break;
    147     }
    148 }

    l2c_enqueue_peer_data 函数的主要作用是将我们的音乐数据包入数据发送队列以及处理 FCR segmentation 和当前 Channel 是否拥堵的检测,其主要做了这么几件事:

    1. 组装好 p_buf 并入 当前 CCB 的 xmit_hold_q 队列。

    2. 检查当前 Channel 拥堵情况。

    3. 当前 Link 支持 RR,则检查当前ACL数据包所在 Channel 的权限,如果当前 CCB 中的权限高于 RR,则把 RR 中的权限设置为跟 CCB 相同。

    4. 若 Link 上没有发送窗口,则将 l2cb.check_round_robin 置为TRUE,下一次需要 RR。

     1 void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
      2 {
      3     UINT8       *p;
      4 
      5     if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
      6     {
      7         p_buf->event = 0;
      8     }
      9     else
     10     {
     11         /* Save the channel ID for faster counting */
     12         p_buf->event = p_ccb->local_cid;
     13 
     14         /* Step back to add the L2CAP header */
     15         p_buf->offset -= L2CAP_PKT_OVERHEAD;
     16         p_buf->len    += L2CAP_PKT_OVERHEAD;
     17 
     18         /* Set the pointer to the beginning of the data */
     19         p = (UINT8 *)(p_buf + 1) + p_buf->offset;
     20 
     21         /* Now the L2CAP header */
     22         UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
     23         UINT16_TO_STREAM (p, p_ccb->remote_cid);
     24     }
     25 
     26     GKI_enqueue (&p_ccb->xmit_hold_q, p_buf);//真正将组装好的 p_buf 入队
     27 
     28     l2cu_check_channel_congestion (p_ccb);  //检测当前 Channel 拥堵情况,下面会继续分析这个函数
     29 
     30 #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
     31     /* if new packet is higher priority than serving ccb and it is not overrun */
     32     if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority ) //当前数据包所在Channel的权限
     33       &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
     34     {
     35         /* send out higher priority packet */
     36         p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;//当前要发送的数据的Channel,设置为ccb_priority,比原来权限要高。
     37     }
     38 #endif
     39 
     40     //如果当前 link 上的 link_xmit_quota ==0(link上的发送窗口为0),那么有必要做一次 RR
     41     if (p_ccb->p_lcb->link_xmit_quota == 0)
     42         l2cb.check_round_robin = TRUE;
     43 }
     44 
     45 //check if any change in congestion status
     46 
     47 void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
     48 {
     49     UINT16 q_count = p_ccb->xmit_hold_q.count; //当前 CCB 中 发送数据队列中数据包的总数
     50 
     51 #if (L2CAP_UCD_INCLUDED == TRUE)
     52     if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
     53     {
     54         q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count;
     55     }
     56 #endif
     57 
     58     /* If the CCB queue limit is subject to a quota, check for congestion */
     59 
     60     /* if this channel has outgoing traffic */
     61     if ((p_ccb->p_rcb)&&(p_ccb->buff_quota != 0))
     62     {
     63         /* If this channel was congested */
     64         if ( p_ccb->cong_sent ) //当前 Channel 的这个字段为TRUE,是否真正拥堵,我们要继续判断
     65         {
     66             /* If the channel is not congested now, tell the app */
     67             //p_ccb->buff_quota = quota_per_weighted_chnls[HCI_ACL_POOL_ID] * p_ccb->tx_data_rate
     68             //在函数 l2c_link_adjust_chnl_allocation 中配置此值
     69             if (q_count <= (p_ccb->buff_quota / 2))//q_count为 CCB 中的xmit_hold_q
     70             {
     71                 p_ccb->cong_sent = FALSE; //当前CCB中的 xmit_hold_q 小于 buffer_quota 值的一半,就认为已经不拥堵了
     72                 if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
     73                 {
     74                     L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x  xmit_hold_q.count: %u  buff_quota: %u",
     75                                       p_ccb->local_cid, q_count, p_ccb->buff_quota);
     76 
     77                     /* Prevent recursive calling */
     78                     l2cb.is_cong_cback_context = TRUE;
     79                     (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE);
     80                     l2cb.is_cong_cback_context = FALSE;
     81                 }
     82 #if (L2CAP_UCD_INCLUDED == TRUE)
     83                 else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )//无连接的 CID
     84                 {
     85                     if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
     86                     {
     87                         L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
     88                                              p_ccb->p_lcb->ucd_out_sec_pending_q.count,
     89                                              p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
     90                         p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE );
     91                     }
     92                 }
     93 #endif
     94             }
     95         }
     96         else
     97         {
     98             /* If this channel was not congested but it is congested now, tell the app */
     99             if (q_count > p_ccb->buff_quota) //此时仍然处于拥堵状态
    100             {
    101                 p_ccb->cong_sent = TRUE;
    102                 if (p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
    103                 {
    104                     L2CAP_TRACE_DEBUG3 ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u",
    105                         p_ccb->local_cid, q_count, p_ccb->buff_quota);
    106 
    107                     (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE);
    108                 }
    109 #if (L2CAP_UCD_INCLUDED == TRUE)
    110                 else if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
    111                 {
    112                     if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
    113                     {
    114                         L2CAP_TRACE_DEBUG3 ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u",
    115                                              p_ccb->p_lcb->ucd_out_sec_pending_q.count,
    116                                              p_ccb->xmit_hold_q.count, p_ccb->buff_quota);
    117                         p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE );
    118                     }
    119                 }
    120 #endif
    121             }
    122         }
    123     }
    124 }

    正常情况下,我们听音乐的数据流发送的情况,这是最常见的一种情况,调用形式为 l2c_link_check_send_pkts (p_lcb, NULL, NULL)。

    1. 判断当前 Link 是否拥堵。
    2. 首先看看 Link 上的 link_xmit_data_q 队列有没有数据,有的话发送
    3. 如果 link_xmit_data_q 没有数据,在看看 Link 上的 CCB,通过 CCB 的链表,找到 CCB 上的队列,一直找,直到找到一个 数据包,发送之。
    4. 注意:上层在发送数据包,仅仅是调用一下这个函数,至于 是不是这个数据包,那不一定;反正每次上层调用都会发送一个,上层发下来的包总会发出去的。
     1 void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
      2 {
      3     int         xx;
      4     BOOLEAN     single_write = FALSE; //最后 Link Disc 用来把 CCB 中的数据包放到 Link 上的队列发,速度加快
      5     L2CAP_TRACE_DEBUG0("mike: in func-- l2c_link_check_send_pkts");
      6     /* Save the channel ID for faster counting */
      7     if (p_buf) //一般数据包都为空,只有发送 L2CAP 发送 command/response 或 发送 S-Frame 才用到
      8     {
      9         if (p_ccb != NULL) //这个 case 就是 当前 Link 即将断开的情况了
     10         {
     11             p_buf->event = p_ccb->local_cid;
     12             single_write = TRUE; //见上面注释
     13             L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_buf p_ccb not null");
     14         }
     15         else
     16             p_buf->event = 0;
     17 
     18         p_buf->layer_specific = 0;
     19         L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_buf->layer_specific=0");
     20         GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf); //把这个数据包放到 当前 link 上的 link_xmit_data_q队列中
     21 
     22         if (p_lcb->link_xmit_quota == 0){
     23             l2cb.check_round_robin = TRUE; // 没有发送窗口了,需要 RR 看看有没有别的数据包可以发送的
     24             L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- p_lcb->link_xmit_quota");
     25         }
     26     }
     27 
     28     /* If this is called from uncongested callback context break recursive calling.
     29     ** This LCB will be served when receiving number of completed packet event.
     30     */
     31     if (l2cb.is_cong_cback_context){//当前 Link 拥堵了,不发送数据包直接返回,几乎不会发生
     32         L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- l2cd.is_cong_cback_context");
     33         return;
     34     }
     35     /* If we are in a scenario where there are not enough buffers for each link to
     36     ** have at least 1, then do a round-robin for all the LCBs
     37     */
     38     if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) )
     39     {
     40         L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts-- (p_lcb == NULL) ||(p_lcb->link_xmit_quota == 0)");
     41         if (p_lcb == NULL)
     42             p_lcb = l2cb.lcb_pool;
     43         else if (!single_write)
     44             p_lcb++;
     45 
     46         /* Loop through, starting at the next */
     47         //哎呀,没有足够发送窗口了,在所有的 Link 上做一次 RR
     48         for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
     49         {
     50             L2CAP_TRACE_DEBUG1("mike: l2c_link_check_send_pkts--Loop through: xx = %d",xx);
     51             /* If controller window is full, nothing to do */
     52             if ( (l2cb.controller_xmit_window == 0
     53 #if (BLE_INCLUDED == TRUE)
     54                   && !p_lcb->is_ble_link
     55 #endif
     56                 )
     57 #if (BLE_INCLUDED == TRUE)
     58                 || (p_lcb->is_ble_link && l2cb.controller_le_xmit_window == 0 )
     59 #endif
     60               || (l2cb.round_robin_unacked >= l2cb.round_robin_quota) )
     61                 break;
     62 
     63             /* Check for wraparound */
     64             if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
     65                 p_lcb = &l2cb.lcb_pool[0];
     66 
     67             if ( (!p_lcb->in_use)
     68                || (p_lcb->partial_segment_being_sent)
     69                || (p_lcb->link_state != LST_CONNECTED)
     70                || (p_lcb->link_xmit_quota != 0)
     71                || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
     72                 continue;
     73 
     74             //首先从 当前 Link 上的 link_xmit_data_q 中取出数据包并发送  
     75             if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)
     76             {
     77                 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--if ((p_buf = (BT_HDR*)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)");
     78                 l2c_link_send_to_lower (p_lcb, p_buf);
     79             }
     80             else if (single_write) //如果是 single_write 设置为 TRUE,说明数据包 已经在 link_xmit_data_q 发送了,没必要在执行下面的 code 了
     81             {
     82                 /* If only doing one write, break out */
     83                 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--single write is true then break");
     84                 break;
     85             }
     86             //Link 上的 Queue 中没有东西可以发送,查找 CCB 中的 Queue,直到找到一个为止。
     87             else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
     88             {
     89                 L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--(p_buf=l2cu_get_next_buffer_to_send (p_lcb)) != NULL");
     90                 l2c_link_send_to_lower (p_lcb, p_buf);
     91             }
     92         }
     93 
     94         /* If we finished without using up our quota, no need for a safety check */
     95 #if (BLE_INCLUDED == TRUE)
     96         if ( ((l2cb.controller_xmit_window > 0 && !p_lcb->is_ble_link) ||
     97              (l2cb.controller_le_xmit_window > 0 && p_lcb->is_ble_link))
     98           && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
     99 #else
    100         if ( (l2cb.controller_xmit_window > 0)
    101           && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
    102 
    103 #endif
    104             l2cb.check_round_robin = FALSE;
    105     }
    106     else /* if this is not round-robin service */
    107     {
    108         /* If a partial segment is being sent, can't send anything else */
    109         if ( (p_lcb->partial_segment_being_sent)
    110           || (p_lcb->link_state != LST_CONNECTED)
    111           || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
    112             return;
    113 
    114         /* See if we can send anything from the link queue */
    115 #if (BLE_INCLUDED == TRUE)
    116         while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
    117                  (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
    118              && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    119 #else
    120         while ( (l2cb.controller_xmit_window != 0)
    121              && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    122 #endif
    123         {
    124             if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) == NULL)//发送Link上的数据包
    125                 break;
    126 
    127             if (!l2c_link_send_to_lower (p_lcb, p_buf))
    128                 break;
    129         }
    130 
    131         if (!single_write)//确保不是在 链路 disc 状态下
    132         {
    133             /* See if we can send anything for any channel */
    134 #if (BLE_INCLUDED == TRUE)
    135             while ( ((l2cb.controller_xmit_window != 0 && !p_lcb->is_ble_link) ||
    136                     (l2cb.controller_le_xmit_window != 0 && p_lcb->is_ble_link))
    137                     && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    138 #else
    139             while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    140 #endif
    141             {
    142                 if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)//找到一个数据包来发送
    143                     break;
    144 
    145                 if (!l2c_link_send_to_lower (p_lcb, p_buf))
    146                     break;
    147             }
    148         }
    149 
    150         /* There is a special case where we have readjusted the link quotas and  */
    151         /* this link may have sent anything but some other link sent packets so  */
    152         /* so we may need a timer to kick off this link's transmissions.         */
    153         if ( (p_lcb->link_xmit_data_q.count) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
    154             L2CAP_TRACE_DEBUG0("mike: l2c_link_check_send_pkts--a timer to kick off this link's transmissions");
    155             btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
    156     }
    157 
    158 }

    最终 l2c_link_check_send_pkts 把数据包交给了 l2c_link_send_to_lower 来做处理,我们的音乐数据包最终也被从某个 CCB 中的队列出队列给了 l2c_link_send_to_lower。l2c_link_send_to_lower 主要做了这些事情:

    1. 如果当前数据包 p_buf 的长度小于 ACL 包的最大值,sent_not_acked 加1,整个 L2CAP 的 controller_xmit_window 减1。然后通过 L2C_LINK_SEND_ACL_DATA 将此数据包发送出去。
    2. 如果当前数据包 p_buf 的长度大于 ACL 包的最大值,先看看能分成几个分包(为了求的几个窗口能容下),然后窗口值减掉这些分包个数,然后将整个数据包交给 L2C_LINK_SEND_ACL_DATA (大于ACL包长度),具体分包发送由 H5(串口) 部分来负责。
     1 /*******************************************************************************
      2 **
      3 ** Function         l2c_link_send_to_lower
      4 **
      5 ** Description      This function queues the buffer for HCI transmission
      6 **
      7 ** Returns          TRUE for success, FALSE for fail
      8 **
      9 *******************************************************************************/
     10 static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
     11 {
     12     UINT16      num_segs;
     13     UINT16      xmit_window, acl_data_size;
     14     L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower");
     15 #if (BLE_INCLUDED == TRUE)
     16     if ((!p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_acl_pkt_size)) ||
     17         (p_lcb->is_ble_link && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size)))
     18 #else
     19     if (p_buf->len <= btu_cb.hcit_acl_pkt_size) //一般都是走这条路径,p_buf一般不会超过 ACL 长度最大值
     20 #endif
     21     {
     22         if (p_lcb->link_xmit_quota == 0){ // Link 上没有窗口了,controller_xmit_window 窗口还是有的,此时就是 round_roubin_unack了(因为上面的数据已经下来了,必须得发送)
     23             L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower--if (p_lcb->link_xmit_quota == 0)");
     24             l2cb.round_robin_unacked++;
     25             L2CAP_TRACE_DEBUG1("mike: l2c_link_send_to_lower--l2cb.round_robin_unacked=%d",l2cb.round_robin_unacked);
     26         }
     27         p_lcb->sent_not_acked++; //整个 Link 已经发送但是没有回复的数据包个数
     28         L2CAP_TRACE_DEBUG1("mike:l2c_link_send_to_lower--p_lcb->sent_not_acked:",p_lcb->sent_not_acked);
     29         p_buf->layer_specific = 0;
     30 
     31 #if (BLE_INCLUDED == TRUE)
     32         if (p_lcb->is_ble_link)
     33         {
     34             l2cb.controller_le_xmit_window--;
     35             L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
     36         }
     37         else
     38 #endif
     39         {
     40             l2cb.controller_xmit_window--; //当前 controller 发送窗口减1
     41             L2CAP_TRACE_DEBUG1("mike:l2c_link_send_to_lower--,l2cb.controller_xmit_window=%d",l2cb.controller_xmit_window);
     42             L2CAP_TRACE_DEBUG0("mike: l2c_link_send_to_lower--L2C_LINK_SEND_ACL_DATA");
     43             L2C_LINK_SEND_ACL_DATA (p_buf); //发送当前这个数据包
     44         }
     45     }
     46     else
     47     {
     48 #if BLE_INCLUDED == TRUE
     49         if (p_lcb->is_ble_link)
     50         {
     51             acl_data_size = btu_cb.hcit_ble_acl_data_size;
     52             xmit_window = l2cb.controller_le_xmit_window;
     53 
     54         }
     55         else
     56 #endif
     57         {
     58             acl_data_size = btu_cb.hcit_acl_data_size;//ACL 包额度最大值
     59             xmit_window = l2cb.controller_xmit_window; //controller目前为止的可用窗口
     60         }
     61         num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
     62         L2CAP_TRACE_DEBUG3("mike: l2c_link_send_to_lower-- num_segs:%d, acl_data_size:%d,xmit_window=%d", num_segs,acl_data_size, xmit_window);
     63 
     64         /* If doing round-robin, then only 1 segment each time */
     65         if (p_lcb->link_xmit_quota == 0)
     66         {
     67             num_segs = 1;
     68             p_lcb->partial_segment_being_sent = TRUE;
     69         }
     70         else
     71         {
     72             /* Multi-segment packet. Make sure it can fit */
     73             if (num_segs > xmit_window)
     74             {
     75                 num_segs = xmit_window;//分包个数比 controller 窗口的个数还多,只能发 controller 个数的包
     76                 p_lcb->partial_segment_being_sent = TRUE; //标志位,还有分包,需要继续发送,Btu_task 中有个 Event 就是处理分包的
     77             }
     78 
     79             if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
     80             {
     81                 num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
     82                 p_lcb->partial_segment_being_sent = TRUE;
     83             }
     84         }
     85 
     86         p_buf->layer_specific        = num_segs;
     87 #if BLE_INCLUDED == TRUE
     88         if (p_lcb->is_ble_link)
     89         {
     90             l2cb.controller_le_xmit_window -= num_segs;
     91 
     92         }
     93         else
     94 #endif
     95         l2cb.controller_xmit_window -= num_segs;//分包占用的窗口数
     96 
     97         if (p_lcb->link_xmit_quota == 0)
     98             l2cb.round_robin_unacked += num_segs;
     99 
    100         p_lcb->sent_not_acked += num_segs;
    101 #if BLE_INCLUDED == TRUE
    102         if (p_lcb->is_ble_link)
    103         {
    104             L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
    105         }
    106         else
    107 #endif
    108         {
    109             L2C_LINK_SEND_ACL_DATA (p_buf);//发送数据包
    110         }
    111     }
    112 
    113 #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
    114 #if (BLE_INCLUDED == TRUE)
    115     if (p_lcb->is_ble_link)
    116     {
    117         L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
    118                 l2cb.controller_le_xmit_window,
    119                 p_lcb->handle,
    120                 p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
    121                 l2cb.round_robin_quota, l2cb.round_robin_unacked);
    122     }
    123     else
    124 #endif
    125     {
    126         L2CAP_TRACE_DEBUG6 ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
    127                 l2cb.controller_xmit_window,
    128                 p_lcb->handle,
    129                 p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
    130                 l2cb.round_robin_quota, l2cb.round_robin_unacked);
    131     }
    132 #endif
    133 
    134     return TRUE;
    135 }

    l2c_link_send_to_lower 把数据交给了 L2C_LINK_SEND_ACL_DATA,L2C_LINK_SEND_ACL_DATA 其实是 bte_main_hci_send 函数,bte_main_hci_send 函数通过调用 hci 的接口 transmit_buf 来转送数据包。transmit_buf 函数作用比较简单,将此数据包入 tx_q 队列,串口(H5)的守护线程 bt_hc_worker_thread 会从 tx_q 队列中获取数据包,并将其发送。

    1 static int transmit_buf(TRANSAC transac, char *p_buf, int len)
    2 {
    3     utils_enqueue(&tx_q, (void *) transac);
    4 
    5     bthc_signal_event(HC_EVENT_TX);
    6 
    7     return BT_HC_STATUS_SUCCESS;
    8 }

    到这里为止, ACL 包整个发送流程分析完了。

    2.ACL 包接收流程:

    有关 ACL 包接收的过程都是在 btu_task 这个守护线程中处理的。

    我们看到 btu_task 处理数据包的过程:

    1. 等待事件,事件到来后,如果是 TASK_MBOX_0_EVT_MASK(是不是 MBOX里的Task),那么从 mbox 中取出这个数据包,并判断是什么类型的 Event。
    2. 如果是 BT_EVT_TO_BTU_HCI_ACL,说明是 ACL 数据,交给 l2cap 来处理。
    3. 如果是 BT_EVT_TO_BTU_L2C_SEG_XMIT,说明是 L2CAP 的分包数据没有发送完,那继续发送分包数据。
    1 //部分 btu_task 源码
     2 ...........
     3    /* Wait for, and process, events */
     4     for (;;)
     5     {
     6         event = GKI_wait (0xFFFF, 0);
     7 
     8         if (event & TASK_MBOX_0_EVT_MASK)
     9         {
    10             /* Process all messages in the queue */
    11             while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
    12             {
    13                 /* Determine the input message type. */
    14                 switch (p_msg->event & BT_EVT_MASK)
    15                 {
    16                     case BT_EVT_TO_BTU_HCI_ACL:
    17                         /* All Acl Data goes to L2CAP */
    18                         l2c_rcv_acl_data (p_msg);//我们的 ACL 数据来了,关键分析这个函数
    19                         break;
    20 
    21                     case BT_EVT_TO_BTU_L2C_SEG_XMIT:
    22                         /* L2CAP segment transmit complete */
    23                         l2c_link_segments_xmitted (p_msg);
    24                         break;
    25 
    26                     case BT_EVT_TO_BTU_HCI_SCO:
    27 #if BTM_SCO_INCLUDED == TRUE
    28                         btm_route_sco_data (p_msg);
    29                         break;
    30 #endif
    31 
    32                     case BT_EVT_TO_BTU_HCI_EVT:
    33                         btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
    34                         GKI_freebuf(p_msg);
    35 
    36 ....

    l2c_rcv_acl_data 这个函数,处理收到的 ACL 包,下面我们来分析一下 l2c_rcv_acl_data 这个函数:

    1. 在收到的 ACL 包中找出 pkt_type(分包的话要另作处理) 和 handle。

    2. 若此 ACL 包是一个完整的数据包:

      • 首先通过 handle 找到 LCB
      • rcv_cid 大于 L2CAP_BASE_APPL_CID(0x0040),说明是上层应用普通数据包,通过 CID 找到当前包的 CCB。
      • hci_len 长度肯定要大于 L2CAP 头长度,否则肯定头部出错了。
      • 如果 rcv_cid 是 L2CAP_SIGNALLING_CID,说明数据包是 创建和建立 Channel 用的(上层应用传输数据),使用函数 process_l2cap_cmd 来处理。
      • 如果 rcv_cid 是 L2CAP_CONNECTIONLESS_CID 说明是 广播或单播,使用函数 tcs_proc_bcst_msg 处理。
      • 如果 rcv_cid 是 L2CAP_BLE_SIGNALLING_CID 说明是 BLE 的signalling包,交给函数 l2cble_process_sig_cmd 处理。
      • 普通数据包,直接交给 L2CAP 的数据流状态机 l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg) 来处理,找到 L2CEVT_L2CAP_DATA 的这个 case,原来通过回调,将此数据包交给上层了(如 RFCOMM,最终是交给 RFCOMM_BufDataInd函数作进一步处理)

    上述数据包,我们仅仅考虑了最普通的数据流。

     1 void l2c_rcv_acl_data (BT_HDR *p_msg)
      2 {
      3     UINT8       *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
      4     UINT16      handle, hci_len;
      5     UINT8       pkt_type;
      6     tL2C_LCB    *p_lcb;
      7     tL2C_CCB    *p_ccb = NULL;
      8     UINT16      l2cap_len, rcv_cid, psm;
      9 
     10     /* Extract the handle */
     11     STREAM_TO_UINT16 (handle, p);
     12     pkt_type = HCID_GET_EVENT (handle);
     13     handle   = HCID_GET_HANDLE (handle);
     14 
     15     /* Since the HCI Transport is putting segmented packets back together, we */
     16     /* should never get a valid packet with the type set to "continuation"    */
     17     if (pkt_type != L2CAP_PKT_CONTINUE)//数据包一定要是完整的,分包另作处理
     18     {
     19         /* Find the LCB based on the handle */
     20         if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
     21         {
     22             UINT8       cmd_code;
     23 
     24             /* There is a slight possibility (specifically with USB) that we get an */
     25             /* L2CAP connection request before we get the HCI connection complete.  */
     26             /* So for these types of messages, hold them for up to 2 seconds.       */
     27             STREAM_TO_UINT16 (hci_len, p);
     28             STREAM_TO_UINT16 (l2cap_len, p);
     29             STREAM_TO_UINT16 (rcv_cid, p);
     30             STREAM_TO_UINT8  (cmd_code, p);
     31 
     32             if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID)
     33                 && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ))
     34             {
     35                 L2CAP_TRACE_WARNING5 ("L2CAP - holding ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
     36                                     handle, p_msg->layer_specific, rcv_cid, cmd_code,
     37                                     l2cb.rcv_hold_q.count);
     38                 p_msg->layer_specific = 2;
     39                 GKI_enqueue (&l2cb.rcv_hold_q, p_msg);//添加到队列中,等待 connect 数据包到达,有种可能发生的 case
     40 
     41                 if (l2cb.rcv_hold_q.count == 1)
     42                     btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
     43 
     44                 return;
     45             }
     46             else
     47             {
     48                 L2CAP_TRACE_ERROR5 ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d opcode:%d cur count:%d",
     49                                     handle, p_msg->layer_specific, rcv_cid, cmd_code, l2cb.rcv_hold_q.count);
     50             }
     51             GKI_freebuf (p_msg);
     52             return;
     53         }
     54     }
     55     else
     56     {
     57         L2CAP_TRACE_WARNING1 ("L2CAP - expected pkt start or complete, got: %d", pkt_type);
     58         GKI_freebuf (p_msg);
     59         return;
     60     }
     61     //下面是我们把 ACL 数据包给部分拆包了,即除掉 L2CAP 的控制部分,还原上层的数据包。
     62     /* Extract the length and update the buffer header */
     63     STREAM_TO_UINT16 (hci_len, p);
     64     p_msg->offset += 4;
     65 
     66 #if (L2CAP_HOST_FLOW_CTRL == TRUE)
     67     /* Send ack if we hit the threshold */
     68     if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh)
     69         btu_hcif_send_host_rdy_for_data();
     70 #endif
     71 
     72     /* Extract the length and CID */
     73     STREAM_TO_UINT16 (l2cap_len, p);
     74     STREAM_TO_UINT16 (rcv_cid, p);
     75 
     76     /* Find the CCB for this CID */
     77     if (rcv_cid >= L2CAP_BASE_APPL_CID)// 说明此 rcv_cid 是上层应用普通数据流的 CID 
     78     {
     79         if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL)
     80         {
     81             L2CAP_TRACE_WARNING1 ("L2CAP - unknown CID: 0x%04x", rcv_cid);
     82             GKI_freebuf (p_msg);
     83             return;
     84         }
     85     }
     86 
     87     if (hci_len >= L2CAP_PKT_OVERHEAD)  //数据包长度肯定要大于 Head的值,否则必然是个错包
     88     {
     89         p_msg->len    = hci_len - L2CAP_PKT_OVERHEAD;
     90         p_msg->offset += L2CAP_PKT_OVERHEAD;
     91     }
     92     else
     93     {
     94         L2CAP_TRACE_WARNING0 ("L2CAP - got incorrect hci header" );
     95         GKI_freebuf (p_msg);
     96         return;
     97     }
     98 
     99     if (l2cap_len != p_msg->len) //长度不相等,那数据包传送过程肯定出现了差错,丢包吧
    100     {
    101         L2CAP_TRACE_WARNING2 ("L2CAP - bad length in pkt. Exp: %d  Act: %d",
    102                               l2cap_len, p_msg->len);
    103 
    104         GKI_freebuf (p_msg);
    105         return;
    106     }
    107 
    108     /* Send the data through the channel state machine */
    109     if (rcv_cid == L2CAP_SIGNALLING_CID)//控制创建和建立 Channel的 signalling
    110     {
    111         process_l2cap_cmd (p_lcb, p, l2cap_len); //此函数专门处理这个Channel的事件
    112         GKI_freebuf (p_msg);
    113     }
    114     else if (rcv_cid == L2CAP_CONNECTIONLESS_CID)
    115     {
    116         /* process_connectionless_data (p_lcb); */
    117         STREAM_TO_UINT16 (psm, p);
    118         L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ;
    119 #if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE)
    120         if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS)
    121         {
    122             p_msg->offset += L2CAP_BCST_OVERHEAD;
    123             p_msg->len -= L2CAP_BCST_OVERHEAD;
    124             tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ;
    125             GKI_freebuf (p_msg);
    126         }
    127         else
    128 #endif
    129 
    130 #if (L2CAP_UCD_INCLUDED == TRUE)
    131         /* if it is not broadcast, check UCD registration */
    132         if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) )
    133         {
    134             /* nothing to do */
    135         }
    136         else
    137 #endif
    138             GKI_freebuf (p_msg);
    139     }
    140 #if (BLE_INCLUDED == TRUE)
    141     else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) //LE 设备的专用 Channel
    142     {
    143         l2cble_process_sig_cmd (p_lcb, p, l2cap_len);
    144         GKI_freebuf (p_msg);
    145     }
    146 #endif
    147 #if (L2CAP_NUM_FIXED_CHNLS > 0)
    148     else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
    149              (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) )
    150     {
    151         /* If no CCB for this channel, allocate one */
    152         if (l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
    153         {
    154             p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
    155 
    156             if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
    157                 l2c_fcr_proc_pdu (p_ccb, p_msg);
    158             else
    159                 (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_lcb->remote_bd_addr, p_msg);
    160         }
    161         else
    162             GKI_freebuf (p_msg);
    163     }
    164 #endif
    165 
    166     else
    167     {
    168         if (p_ccb == NULL)
    169             GKI_freebuf (p_msg);
    170         else
    171         {
    172             /* Basic mode packets go straight to the state machine */
    173             if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
    174             //普通的数据流都是经过这条通路的,下面这个函数觉得很熟悉吧,因为在发送数据包的时候也调用了他。
    175                 l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg);
    176             else
    177             {
    178                 /* eRTM or streaming mode, so we need to validate states first */
    179                 if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
    180                     l2c_fcr_proc_pdu (p_ccb, p_msg);
    181                 else
    182                     GKI_freebuf (p_msg);
    183             }
    184         }
    185     }
    186 }

    l2c_link_process_num_completed_pkts这个函数都做了些什么呢?我们来深入代码了解一下整个过程。

    1. 通过 num_sent 来更新数据 controller_xmit_window,sent_not_acked。
    2. 既然又多了 credits(Snoop中的),那么自然调用 l2c_link_check_send_pkts 去找更多的包发送下去。
    3. l2c_link_process_num_completed_pkts 和 l2c_link_check_send_pkts 形成了一个递归式的调用,l2c_link_check_send_pkts 会产生 process num complete 这个event,l2c_link_process_num_completed_pkts找到 Link后在让 l2c_link_check_send_pkts 发包。
     1 void l2c_link_process_num_completed_pkts (UINT8 *p)
      2 {
      3     UINT8       num_handles, xx;
      4     UINT16      handle;
      5     UINT16      num_sent; //已经发下去的数据,这个数据要更新controller_xmit_window
      6     tL2C_LCB    *p_lcb;
      7 
      8     L2CAP_TRACE_DEBUG0("mike: l2c_link_process_num_completed_pkts");
      9     STREAM_TO_UINT8 (num_handles, p);
     10     L2CAP_TRACE_DEBUG1("mike: l2c_link_process_num_completed_pkts--number_handles:%d", num_handles);
     11     for (xx = 0; xx < num_handles; xx++)//handle 对应着每条逻辑链路(Link)
     12     {
     13         STREAM_TO_UINT16 (handle, p);
     14         STREAM_TO_UINT16 (num_sent, p);
     15 
     16         p_lcb = l2cu_find_lcb_by_handle (handle);
     17 
     18         /* Callback for number of completed packet event    */
     19         /* Originally designed for [3DSG]                   */
     20         if((p_lcb != NULL) && (p_lcb->p_nocp_cb))
     21         {
     22             L2CAP_TRACE_DEBUG0 ("L2CAP - calling NoCP callback");
     23             (*p_lcb->p_nocp_cb)(p_lcb->remote_bd_addr);
     24         }
     25 
     26         if (p_lcb)
     27         {
     28 #if (BLE_INCLUDED == TRUE)
     29             if (p_lcb->is_ble_link)
     30             {
     31                 l2cb.controller_le_xmit_window += num_sent;
     32             }
     33             else
     34 #endif
     35             {
     36                 /* Maintain the total window to the controller */
     37                 l2cb.controller_xmit_window += num_sent;
     38             }
     39             /* If doing round-robin, adjust communal counts */
     40             if (p_lcb->link_xmit_quota == 0)
     41             {
     42                 /* Don't go negative */
     43                 if (l2cb.round_robin_unacked > num_sent)
     44                     l2cb.round_robin_unacked -= num_sent;
     45                 else
     46                     l2cb.round_robin_unacked = 0;
     47             }
     48 
     49             /* Don't go negative */
     50             if (p_lcb->sent_not_acked > num_sent)
     51                 p_lcb->sent_not_acked -= num_sent; //更新
     52             else
     53                 p_lcb->sent_not_acked = 0;
     54 
     55             l2c_link_check_send_pkts (p_lcb, NULL, NULL);
     56 
     57             L2CAP_TRACE_DEBUG1("mike:l2c_link_process_num_completed_pkts--l2cb.controller_xmit_window=%d",l2cb.controller_xmit_window);
     58 
     59             /* If we were doing round-robin for low priority links, check 'em */
     60             if ( (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
     61               && (l2cb.check_round_robin)
     62               && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
     63             {
     64               l2c_link_check_send_pkts (NULL, NULL, NULL);
     65             }
     66         }
     67 
     68 #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
     69         if (p_lcb)
     70         {
     71 #if (BLE_INCLUDED == TRUE)
     72             if (p_lcb->is_ble_link)
     73             {
     74                 L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
     75                     l2cb.controller_le_xmit_window,
     76                     p_lcb->handle, p_lcb->sent_not_acked,
     77                     l2cb.check_round_robin, l2cb.round_robin_unacked);
     78             }
     79             else
     80 #endif
     81             {
     82                 L2CAP_TRACE_DEBUG5 ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
     83                     l2cb.controller_xmit_window,
     84                     p_lcb->handle, p_lcb->sent_not_acked,
     85                     l2cb.check_round_robin, l2cb.round_robin_unacked);
     86 
     87             }
     88         }
     89         else
     90         {
     91 #if (BLE_INCLUDED == TRUE)
     92             L2CAP_TRACE_DEBUG5 ("TotalWin=%d  LE_Win: %d, Handle=0x%x, RRCheck=%d, RRUnack=%d",
     93                 l2cb.controller_xmit_window,
     94                 l2cb.controller_le_xmit_window,
     95                 handle,
     96                 l2cb.check_round_robin, l2cb.round_robin_unacked);
     97 #else
     98             L2CAP_TRACE_DEBUG4 ("TotalWin=%d  Handle=0x%x  RRCheck=%d  RRUnack=%d",
     99                 l2cb.controller_xmit_window,
    100                 handle,
    101                 l2cb.check_round_robin, l2cb.round_robin_unacked);
    102 #endif
    103         }
    104 #endif
    105     }
    106 
    107 #if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
    108     /* only full stack can enable sleep mode */
    109     btu_check_bt_sleep ();
    110 #endif
    111 }

    ACL 包发送和接收部分源码分析完了!

    -end-

  • 相关阅读:
    创建 Smarty 对象
    C#设计模式——命令模式(Command Pattern)
    Spring.Net 简单入门学习
    设计模式六大原则(6):开闭原则
    设计模式六大原则(5):迪米特法则
    设计模式六大原则(4):接口隔离原则
    设计模式六大原则(3):依赖倒置原则
    设计模式六大原则(2):里氏替换原则
    设计模式六大原则(1): 单一职责原则
    超简单!asp.net core前后端分离项目使用gitlab-ci持续集成到IIS
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/7429367.html
Copyright © 2020-2023  润新知