一. 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 这个函数做的事情主要有:
- 根据参数 cid(Channel ID) 找到 对应的 ccb(Channel Control Block), 找不到返回 L2CAP_DW_FAILED
- 如果测试者 打开 TESTER 这个宏,发送任意数据,当数据大小 大于 MTU 最大值,也会返回L2CAP_DW_FAILED
- 通过检查 p_ccb->cong_sent 字段,TRUE,则说明当前 Channel 已经拥挤,此时L2CAP的这个Channel不在接收数据,返回 L2CAP_DW_FAILED
- 以上三个条件都通过,说明数据可发送,将数据通过 l2c_csm_execute 继续处理。进入 l2c_csm_execute 函数,标志着这笔数据已经成功交给 l2CAP 来处理,与上层已经没有关系了。
- 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)。
- 判断当前 Link 是否拥堵。
- 首先看看 Link 上的 link_xmit_data_q 队列有没有数据,有的话发送
- 如果 link_xmit_data_q 没有数据,在看看 Link 上的 CCB,通过 CCB 的链表,找到 CCB 上的队列,一直找,直到找到一个 数据包,发送之。
- 注意:上层在发送数据包,仅仅是调用一下这个函数,至于 是不是这个数据包,那不一定;反正每次上层调用都会发送一个,上层发下来的包总会发出去的。
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 主要做了这些事情:
- 如果当前数据包 p_buf 的长度小于 ACL 包的最大值,sent_not_acked 加1,整个 L2CAP 的 controller_xmit_window 减1。然后通过 L2C_LINK_SEND_ACL_DATA 将此数据包发送出去。
- 如果当前数据包 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 处理数据包的过程:
- 等待事件,事件到来后,如果是 TASK_MBOX_0_EVT_MASK(是不是 MBOX里的Task),那么从 mbox 中取出这个数据包,并判断是什么类型的 Event。
- 如果是 BT_EVT_TO_BTU_HCI_ACL,说明是 ACL 数据,交给 l2cap 来处理。
- 如果是 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 这个函数:
-
在收到的 ACL 包中找出 pkt_type(分包的话要另作处理) 和 handle。
-
若此 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这个函数都做了些什么呢?我们来深入代码了解一下整个过程。
- 通过 num_sent 来更新数据 controller_xmit_window,sent_not_acked。
- 既然又多了 credits(Snoop中的),那么自然调用 l2c_link_check_send_pkts 去找更多的包发送下去。
- 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-