A2dp播放音乐完整的Android 源码详解解析,请点击下面链接下载:
Android 蓝牙A2dp-Avrcp初始化-连接-播放源码分析文档大全 - 点击下载
android-蓝牙A2dp-avrcp-hfp-opp-配对流程-ble-rfcomm源码流程
一、A2dp卡音问题-环境因素 先确认问题概率。(低概率则可能为干扰引起,着重关注高概率/必现卡顿问题)确认是否是共存场景问题。(WiFi/BT共存,a2dp/hid共存等)确认BT RF是否正常。(NV错误导致卡顿问题)WIFI OTA (WIFI天线和芯片是一起的)指标满足要求。 二、传统蓝牙HCI流控(flow control)流控制用于在主机和主机控制器之间,避免传送到主机控制器的未应答远程设备的 ACL 数据溢出主机控制器数据缓冲区。主机(蓝牙协议栈)负责管理主机控制器(蓝牙芯片)的数据缓冲区。流控分为两种:
1)蓝牙协议栈到蓝牙芯片的流控
2)蓝牙芯片到蓝牙协议栈的流控
下面我们来一一介绍下:
1. 蓝牙协议栈到蓝牙芯片的流控
从host到Controller的数据流控分为两种:Packet-based Data Flow Control和Data-Block-Based Data Flow Control。通过HCI_Write_Flow_Control_Mode 命令来切换,
但是Packet-based data flow control对于BR/EDR芯片来说是默认的,所以你可以不下这个命令。但是我们既然讲到这个命令,还是看下这个命令的格式,如下图:
这个命令看截图已经很清晰了,一笔带过就好了,我们重点来说下协议栈到蓝牙芯片的流控原理(只说传统蓝牙的Packet-baseddata flow control):
在初始化时,主机将发送 Read_Buffer_Size 指令。通过该指令返回的两参数可以确定从主机发往主机控制器的 HCI ACL 和 SCO 数据分组(不包括报头)的最大长度。
另有两返回参数表示主机控制器可以缓存等待传输的 HCI ACL 和SCO 数据分组数。在至少有一个连接或处于本地回送的情况下,主机控制器利用Number Of Completed Packets 事件控制从主机发来的数据流。
事件分组包括一个连接句柄列表, 以及自从前一个事件返回后已经完成的 HCI 数据分组的相应数目(如果对于一个特定的连接句柄,没有事件返回发生,就从连接建立的时间算起 )。发送完成是指数据分组的传输、清除和回送至主机。
根据该事件返回的信息和Read Buffer Size 命令返回的参数(该参数决定可以存储在主机控制器中的 HCI ACL 和 SCO 数据分组的总数目)主机决定哪个连接句柄的 HCI 数据分组应该发送。
在 HCI 每次发送数据分组后,它就假设在主机控制器上所对应链路类型的存储空间减少一个 HCI 分组的量,当主机收到一个新的能提供关于有多少 HCI 数据分组已经完成的 Number Of Completed Packets 事件后,它就可以得到从上一次事件返回后缓冲器数量的减少信息,并可以计算当前的缓冲器的使用量。
当主机控制器在其缓存中存放有 HCI 数据分组时,它必须向主机周期性持续发送Number Of Completed Packets 事件, 直到最终所有 ACL 数据分组都已发送完毕或溢出。
事件发送频率由厂商指定。注意:如果 SCO 流控制失效,则 Number OfCompleted Packets 就不能在 SCO 连接句柄中进行报告。
看概念可能我们不会那么清晰,我们就以一个举一个列子,根据btsnoop的flow来说明下吧:
协议栈初始化的时候会采用Read_Buffer_Size来读取acl,sco的个数,以及acl,sco的每包size.如图,那此步骤分为切开两个小节:
①蓝牙芯片回应协议栈comand complete的event携带acl,sco的个数,以及acl,sco的每包size等信息,截图如下:
Bluetooth Controller 底层会有6个BR/EDR的ACL buffer,用于缓存数据。每次蓝牙reset后会初始化,host主动询问controller可以缓存多少包数据。
②同时,host也会主动告知controller,自己可以缓存20包ACL数据和10包SCO数据。
③BLE 的host也会主动询问controller可以缓存的LE数据的数量
当协议栈发送给蓝牙芯片ACL数据,acl的buffer size-1(注意此部分是维护在协议栈中),
而且只有通过frontline能看到剩余的acl buffer size(我试过ellisys以及Wireshark都不会显示,是因为Frontline的软件工具有算法会自动显示)
如图:在初始化的时候我们读到的acl buffer size是10,所以我们发送了一个acl数据,此部分变为9.
当蓝牙协议栈收到蓝牙芯片回送的Num of complete packet event后,协议栈更新acl buffer size数量,增加1,变为10。
音频流传输路径:bt侧每20ms 从audio的buf中拿pcm data,之后进行encoder,然后将encoder的数据入队,之后我们stack AVDTP 会将队列里的数据写进L2CAP的buff里,如果Controller 中NOCP(Number of complete packet)回的慢,L2CAP的buff就无法发送到peer,从而造成bt侧的queue内部overflow,进而BT侧就会清除queue中的数据,从而造成了声音不连续。所以此题需要看是否环境中有干扰造成NOCP回复慢。
==> 卡音原因是FW 那边回BT侧的NOCP 较慢,造成BT侧数据overflow,所以从HCIlog的wav音频会出现卡音
==>(NOCP是指蓝牙 HOST发送给FW一包数据后,FW tx数据到remote 设备完成时,FW回复给HOST的包:Event: HCI_Number_Of_Completed_Packets,此包回复后,HOST继续给FW发送数据)
从固件中查看remote dev回复:
发现是由于对方每隔60ms回复我们一包ACK,其他时间DUT在重传数据包,对方无响应,造成数据不能正常发送,进而BT这边塞包,形成卡顿。
三、将播放音乐此条ACL链路调整为高优先级,保证播放音乐可以发多个数据包1、首先蓝牙芯片重启.
①对应的HCI log:
②对应的Android 源码
//蓝牙新品重启
void BTM_DeviceReset(UNUSED_ATTR tBTM_CMPL_CB* p_cb) {
227 /* Flush all ACL connections */
228 btm_acl_device_down(); //断开所有的ACL链路
229
230 /* Clear the callback, so application would not hang on reset */
231 btm_db_reset();
232 //开始重启新品,重启完成,调用reset_complete函数处理
233 module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
234 bt_workqueue_thread, reset_complete);
235}
static void reset_complete(void* result) {
171 CHECK(result == FUTURE_SUCCESS);
172 const controller_t* controller = controller_get_interface();//获取到controller接口
173
174 /* Tell L2CAP that all connections are gone */
175 l2cu_device_reset();
176
177 /* Clear current security state */
178 list_foreach(btm_cb.sec_dev_rec, set_sec_state_idle, NULL);
179
180 /* After the reset controller should restore all parameters to defaults. */
//重启芯片后,所有的参数设置为默认值
181 btm_cb.btm_inq_vars.inq_counter = 1;
182 btm_cb.btm_inq_vars.inq_scan_window = HCI_DEF_INQUIRYSCAN_WINDOW;
183 btm_cb.btm_inq_vars.inq_scan_period = HCI_DEF_INQUIRYSCAN_INTERVAL;
184 btm_cb.btm_inq_vars.inq_scan_type = HCI_DEF_SCAN_TYPE;
185
186 btm_cb.btm_inq_vars.page_scan_window = HCI_DEF_PAGESCAN_WINDOW;
187 btm_cb.btm_inq_vars.page_scan_period = HCI_DEF_PAGESCAN_INTERVAL;
188 btm_cb.btm_inq_vars.page_scan_type = HCI_DEF_SCAN_TYPE;
189
190 btm_cb.ble_ctr_cb.conn_state = BLE_CONN_IDLE;
191 btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
192 gatt_reset_bgdev_list();
193
194 btm_pm_reset();
195 //获取到BR/EDR controller可接收得buff数量
196 l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic());
197
198#if (BLE_PRIVACY_SPT == TRUE)
199 /* Set up the BLE privacy settings */
200 if (controller->supports_ble() && controller->supports_ble_privacy() &&
201 controller->get_ble_resolving_list_max_size() > 0) {
202 btm_ble_resolving_list_init(controller->get_ble_resolving_list_max_size());
203 /* set the default random private address timeout */
204 btsnd_hcic_ble_set_rand_priv_addr_timeout(BTM_BLE_PRIVATE_ADDR_INT_MS /
205 1000);
206 }
207#endif
208
209 if (controller->supports_ble()) {
210 btm_ble_white_list_init(controller->get_ble_white_list_size());
//获取到BLE controller可接收得buff数量
211 l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble());
212 }
213
214 BTM_SetPinType(btm_cb.cfg.pin_type, btm_cb.cfg.pin_code,
215 btm_cb.cfg.pin_code_len);
216
217 for (int i = 0; i <= controller->get_last_features_classic_index(); i++) {
218 btm_decode_ext_features_page(i,
219 controller->get_features_classic(i)->as_array);
220 }
221
222 btm_report_device_status(BTM_DEV_STATUS_UP);
223}
此时调用下面两个函数,来获取Controller 可以接收buff数量。
BR/EDR : l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic())
BLE : l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble())
注意:br acl buff 为8个包,只用于br分配,ble acl buff 10个包,只用于ble。也有可能br和ble的buff在一起,这样就要一起进行分配。
2、设置A2dp L2cap链路优先级,并进行acl buff 分配
当AVDTP建立成功后,调用bta_av_start_ok(),调用bta_av_stream_chg(p_scb,true),在这个函数中,将此条播放音乐的a2dp acl链路调为HIGH优先级。
/*******************************************************************************
2213 *
2214 * Function bta_av_start_ok
2215 *
2216 * Description Stream started.
2217 *
2218 * Returns void
2219 *
2220 ******************************************************************************/
2221void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
2222 bool initiator = false;
2223 bool suspend = false;
2224 uint16_t flush_to;
2225 uint8_t new_role = p_scb->role;
2226 BT_HDR hdr;
2227 uint8_t clear_policy = 0;
2228 uint8_t cur_role;
2229 uint8_t local_tsep = p_scb->seps[p_scb->sep_idx].tsep;
。。。。。。。。
if (!suspend) {
2351 p_scb->q_tag = BTA_AV_Q_TAG_STREAM;
//调用bta_av_stream_chg(p_scb,true),在这个函数中,将此条播放音乐的a2dp acl链路调为HIGH优先级。
2352 bta_av_stream_chg(p_scb, true);//
2353 }
2354
/*******************************************************************************
1067 *
1068 * Function bta_av_stream_chg
1069 *
1070 * Description audio streaming status changed.
1071 *
1072 * Returns void
1073 *
1074 ******************************************************************************/
1075void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started) {
1076 uint8_t started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
1077
1078 APPL_TRACE_DEBUG("%s: peer %s started:%s started_msk:0x%x", __func__,
1079 p_scb->PeerAddress().ToString().c_str(),
1080 logbool(started).c_str(), started_msk);
1081
1082 if (started) {
1083 bta_av_cb.audio_streams |= started_msk;
1084 /* Let L2CAP know this channel is processed with high priority */
//如果stream stared ,就将此条链路调为高优先级
1085 L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_HIGH);
1086 } else {
1087 bta_av_cb.audio_streams &= ~started_msk;
1088 /* Let L2CAP know this channel is processed with low priority */
1089 L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_NORMAL);
1090 }
1091}
L2CA_SetAclPriority- 》l2cu_set_acl_priority(bd_addr, priority, false));
bool l2cu_set_acl_priority(const RawAddress& bd_addr, uint8_t priority,
2355 bool reset_after_rs) {
2356 tL2C_LCB* p_lcb;
2357 uint8_t* pp;
2358 uint8_t command[HCI_BRCM_ACL_PRIORITY_PARAM_SIZE];//优先级最多三个acl链路
2359 uint8_t vs_param;
2360
2361 APPL_TRACE_EVENT("SET ACL PRIORITY %d", priority);
2362
2363 /* Find the link control block for the acl channel */
2364 p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
2365 if (p_lcb == NULL) {
2366 L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_SetAclPriority");
2367 return (false);
2368 }
2369
2370 if (BTM_IS_BRCM_CONTROLLER()) {
//reset_after_rs:这个是角色转换标志位。此时是播放音乐,此标志位为false.
2371 /* Called from above L2CAP through API; send VSC if changed */
2372 if ((!reset_after_rs && (priority != p_lcb->acl_priority)) ||
2373 /* Called because of a master/slave role switch; if high resend VSC */
//当a link's master/slave role change event is received,如果需要,重置高优先级链接。只要这两种情况下会调节acl 链路优先级。
2374 (reset_after_rs && p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)) {
2375 pp = command;
2376 //如果当前acl优先级不是HIGH,将优先级置为HIGH priorify,并设置到controller中。
2377 vs_param = (priority == L2CAP_PRIORITY_HIGH) ? HCI_BRCM_ACL_PRIORITY_HIGH
2378 : HCI_BRCM_ACL_PRIORITY_LOW;
2379
2380 UINT16_TO_STREAM(pp, p_lcb->handle);
2381 UINT8_TO_STREAM(pp, vs_param);
2382
2383 BTM_VendorSpecificCommand(HCI_BRCM_SET_ACL_PRIORITY,
2384 HCI_BRCM_ACL_PRIORITY_PARAM_SIZE, command,
2385 NULL);
2386 }
2387 }
2388
2389 /* Adjust lmp buffer allocation for this channel if priority changed */
2390 if (p_lcb->acl_priority != priority) {
2391 p_lcb->acl_priority = priority;
//接下来调整链路层buffer数量为此信道,acl链路.
2392 l2c_link_adjust_allocation();
2393 }
2394 return (true);
2395}
2396
上面函数主要工作:如果当前acl优先级不是HIGH,将优先级置为HIGH priorify,并设置到controller中。
最最最重要的函数来了接下来调整此条A2dp链路层 controller 可接收buffer数量。一般只有A2dp这条链路为高优先级。
总结下 l2c_link_adjust_allocation()函数做的工作:
1、判断是否有active link。
2、若此刻没有链路,复位buff定额和芯片buff.
3、若此刻有链路,分别计算出高--低优先级链路数量
4.1如果存在低优先级链路,首先保留1个Buff
4.2当高优先级链路数乘以高优先级定额数加上低定额数(至少保证1个buff),大于总的acl 链路buff数量。此时需要将高优先级链路定额buff,依次减少1,直至满足这个while循环。
5、计算出高优先级定额总数-高优先级链路数乘以高优先级定额数
6、计算出低优先级定额总数- 总的定额数减去第5步高优先级定额数,若高优先级定额数不小于总的定额数,则至少保证1个buff
7、判断是否有低优先级链路数
8、如果低优先级链路数,大于低优先级定额的Buff,说明都不能保证一条acl 链路一个Buff,将剩下的buff,给到轮询算法中,并且qq_remainder 保留为1个
9、如果低优先级链路数大于0个,qq保存 = 所剩的低优先级定额除以低优先级链路上,取商(不用想,肯定是1)。起码保证每条链路有一个可用的Buff。将余数保存到qq_remainder中。
10、如果没有低优先级链路上,则qq_remainder为1
11、给每条链路分配buff
12、给高优先级链路赋值高优先级定额buff
13、如果是低优先级链路,并且qq = 0,意味着每条链路都分不到一个Buff,轮询算法中,未回复数增加1
14、若qq 不等于0,将qq的buff,赋值给每条acl链路,最后将剩余的qq_remainder中的buff依次给acl链路赠送。
总结:所以当手机同时连接一个蓝牙耳机,再连接一个蓝牙键盘、蓝牙鼠标时候,当播放音乐的时候,移动蓝牙鼠标,会有迟滞现象,因为此时会给a2dp这条链路分配5个buff,蓝牙键盘和蓝牙鼠标分配1个buff,所以会迟滞。
源码分析如下:void l2c_link_adjust_allocation(void) {
666 uint16_t qq, yy, qq_remainder;
667 tL2C_LCB* p_lcb;
668 uint16_t hi_quota, low_quota; //高优先级buff数量,低优先级buff数量
669 uint16_t num_lowpri_links = 0; //低优先级acl链路数量
670 uint16_t num_hipri_links = 0;//高优先级acl链路数量
671 uint16_t controller_xmit_quota = l2cb.num_lm_acl_bufs; //controller中总acl数量,由l2c_link_process_num_buff()函数获得。
672 uint16_t high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A; //高优先级的buff数量为5个buff.
673
674 /* If no links active, reset buffer quotas and controller buffers */
675 if (l2cb.num_links_active == 0) {
676 l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs;
677 l2cb.round_robin_quota = l2cb.round_robin_unacked = 0; //轮询调度Round-robin(负载均衡算法),采用这种模式,消息在队列中保存,以轮询的方式将消息发送给监听消息队列的消费者,可以动态的增加消费者以提高消息的处理能力。 此时,没有高优先级链路,所以不使用轮询调度算法,故对应的buff置为0.
return;
679 }
680
681 /* First, count the links */
682 for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
683 if (p_lcb->in_use) {
684 if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
685 num_hipri_links++;//计算出高优先级链路数。
686 else
687 num_lowpri_links++;//计算出低优先级链路数。
688 }
689 }
690
691 /* now adjust high priority link quota */
692 low_quota = num_lowpri_links ? 1 : 0; //如果存在低优先级链路,至少保留1个buff.
693 while ((num_hipri_links * high_pri_link_quota + low_quota) >
694 controller_xmit_quota) //当高优先级链路数乘以高优先级定额数(5个buff)加上低定额数(至少保证1个buff),大于总的acl 链路buff数量。
695 high_pri_link_quota--; //此时需要将高优先级链路定额buff,依次减少1,以至满足这个while循环。
696
697 /* Work out the xmit quota and buffer quota high and low priorities */
698 hi_quota = num_hipri_links * high_pri_link_quota; //高优先级链路数乘以高优先级定额数(5个buff),一般高优先级只有1条,所以结果是5。
699 low_quota =
700 (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1;//剩下的buff,就为低定额数buff(至少为1个)。
701
702 /* Work out and save the HCI xmit quota for each low priority link */
703
704 /* If each low priority link cannot have at least one buffer */
705 if (num_lowpri_links > low_quota) { //如果低优先级链路数,大于低优先级定额的buff,说明都不能保证一条acl 链路一个buff。
706 l2cb.round_robin_quota = low_quota;//将剩下的buff,给到轮询算法中。
707 qq = qq_remainder = 1;//遗留buff为1.
708 }
709 /* If each low priority link can have at least one buffer */
710 else if (num_lowpri_links > 0) { //如果低优先级链路数大于0个。
711 l2cb.round_robin_quota = 0;
712 l2cb.round_robin_unacked = 0;
713 qq = low_quota / num_lowpri_links;//qq保存 = 所剩的低优先级定额除以低优先级链路上,取商(不用想,肯定是1)。起码保证每条链路有一个可用的buff.
714 qq_remainder = low_quota % num_lowpri_links; //将余数保存到qq_remainder中。
715 }
716 /* If no low priority link */
717 else {
718 l2cb.round_robin_quota = 0;
719 l2cb.round_robin_unacked = 0;
720 qq = qq_remainder = 1; //如果没有低优先级链路上,则qq_remainder为1.
721 }
722
723 L2CAP_TRACE_EVENT(
724 "l2c_link_adjust_allocation num_hipri: %u num_lowpri: %u low_quota: "
725 "%u round_robin_quota: %u qq: %u",
726 num_hipri_links, num_lowpri_links, low_quota, l2cb.round_robin_quota, qq);
727
728 /* Now, assign the quotas to each link */ //现在给每条链路分配buff.
729 for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
730 if (p_lcb->in_use) {
731 if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) {
732 p_lcb->link_xmit_quota = high_pri_link_quota;//给高优先级链路赋值高优先级定额buff.
733 } else {
734 /* Safety check in case we switched to round-robin with something
735 * outstanding */
736 /* if sent_not_acked is added into round_robin_unacked then don't add it
737 * again */
738 /* l2cap keeps updating sent_not_acked for exiting from round robin */
739 if ((p_lcb->link_xmit_quota > 0) && (qq == 0)) //如果是低优先级链路,并且qq = 0,意味着每条链路都分不到一个buff.
740 l2cb.round_robin_unacked += p_lcb->sent_not_acked; //轮询算法中,未回复数增加1.
741
742 p_lcb->link_xmit_quota = qq; //若qq 不等于0,将qq的buff,赋值给每条acl链路。
743 if (qq_remainder > 0) { //最后将剩余的qq_remainder中的buff依次给acl链路赠送。
744 p_lcb->link_xmit_quota++;
745 qq_remainder--;
746 }
747 }
748
749 L2CAP_TRACE_EVENT(
750 "l2c_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d", yy,
751 p_lcb->acl_priority, p_lcb->link_xmit_quota);
752
753 L2CAP_TRACE_EVENT(" SentNotAcked: %d RRUnacked: %d",
754 p_lcb->sent_not_acked, l2cb.round_robin_unacked);
755
756 /* There is a special case where we have readjusted the link quotas and */
757 /* this link may have sent anything but some other link sent packets so */
758 /* so we may need a timer to kick off this link's transmissions. */
759 if ((p_lcb->link_state == LST_CONNECTED) &&
760 (!list_is_empty(p_lcb->link_xmit_data_q)) &&
761 (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) {
762 alarm_set_on_mloop(p_lcb->l2c_lcb_timer,
763 L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS,
764 l2c_lcb_timer_timeout, p_lcb);
765 }
766 }
767 }
768}
四、a2dp音乐播放 audio到蓝牙侧流程
最最最重要的函数来了
下图为audio音频流到蓝牙a2dp整个流程图
上图完整的Android 源码详解解析,请点击下面链接下载:
Android 蓝牙A2dp-Avrcp初始化-连接-播放源码分析文档大全 - 点击下载
图片解析:
1、蓝牙和AUDIO之间的接口
蓝牙和audio之间的通信是通过socket,管理socket中的文件是UIPC,UIPC管理两条socket.
A2DP_CTRL_PATH /data/misc/bluedroid/.a2dp_ctrl
A2DP_DATA_PATH /data/misc/bluedroid/.a2dp_data
这两个socket的作用就是接收audio的控制命令和音频数据。
2、a2dp初始化
首先初始化a2dp端的UIPC控制socket:btif_a2dp_control_init()->uipc_init()->uipc_main_init()
开启uipc服务线程:uipc_start_main_server_thread()->uipc_read_task();
并且注册控制信息回调UIPC_OPEN(btif_a2dp_ctrl_cb)。
3、a2dp codec初始化
开始设置编码格式:btif_a2dp_source_setup_codec(),btif_a2dp_source_setup_codec_delay()
在此函数中获取编码接口bta_av_co_get_encoder_interface()
在a2dp_sbc_encoder_init()函数中注册两个回调函数 :1、btif_a2dp_source_read_callback 底层编码消费数据
从这里通知读取数据。2、 btif_a2dp_source_enqueue_callback 负责将编码后的数据加入btif_a2dp_source_cb.tx_audio_queue,
并取数据使用。
4、audio获取蓝牙 module
当我们通过蓝牙耳机播放音频时,最终通过Audio Flinger 调用到openOutput函数来输出音频道蓝牙耳机。
openoutput()->.....->hal_module_methods->adev_open()。
5、audio收到a2dp连接成功通知
调用adev_open_output_stream()->...->连接控制通道skt_connect()。做了一个socket的连接,连接的path
是data/misc/bluedroid/.a2dp_data,当skt_connect连接后,后续的audio传下来的数据只要写到common->audio_fd
就可以了。
6、audio数据写入
out_write()-> a2dp_command(A2DP_CTRL_CMD_START) ,此处对应HCI command:AVDTP_START,a2dp控制
socket,收到消息进行回调,在UIPC的机制中,有数据来就会携带宏UIPC_RX_DATA_READY_EVT。
7、打开数据通道
在收到audio cmd start时候,打开数据通道socket。
8、avdtp协议的连接
BTA_AvStart()->....并将结果上报上层。
9、真正音频流写入
skt_write()-->btif_a2dp_data_cb()->...->btif_a2dp_source_audio_tx_start_event()
//#define A2DP_AAC_ENCODER_INTERVAL_MS 20 //A2DP AAC encoder interval in milliseconds
btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms()//每20ms 去读一次数据,而不是通过UIPC的回调函数来 *** 作。
btif_a2dp_source_alarm_cb。
10、读取数据
之前注册的回调函数,btif_a2dp_source_read_callback,通过UIPC_Read去读取数据,也就是从socket文件中读取,
-->SBC_Encode()进行编码,将编码好的数据加入发送队列,就是添加到btif_a2dp_source_cb.tx_audio中,如果这个队列数据溢出,
会打印以下log:
bt_btif_a2dp_source: btif_a2dp_source_enqueue_callback: TX queue buffer size now=22 adding=7 max=28
Cannot read RSSI
Cannot read Failed Contact Counter
Cannot read Automatic Flush Timeout
Cannot read Tx Power
然后通知协议栈数据好了,可以过来取数据了。
11、调用数据通道bta_av_data_path()来取数据。
其中最重要函数:调用数据通道bta_av_data_path()来取数据,给对端设备发送数据。
1、计算acl链路可缓存buff数量(l2c_buff),(a2dp acl链路优先级高,分配定额5个buff)。
2、判断a2dp_list队列是否有数据。
3、若有数据,取出a2dp_list链表头数据p_buff
4、若没有数据,调用bta_av_co_audio_source_data_path去btif_a2dp_source_cb.tx_audio_queue中读取数据,保存到p_buff
5、此时4的p_buff中有了数据。
6、判断acl链路可缓存buff数量(l2c_buff) 是否大于controller可接收buff总数(a2dp acl链路优先级高,分配定额5个buff)
7、若未超过定额5个buff,将取出来的数据p_buff,交给AVDTP,在AVDTP层,调用L2CA_DataWrite向下层发送数据,发送给对端设备
8、若超过定额5个buff,再次判断p_buff中数据,是从3中取出来的,还是从4中取出来的
9、将之前取出来的数据p_buff,继续放回到a2dp_list中
10、再次判断,此刻a2dp_list中数据是否小于3包
11、若小于3包,将之前取出来的数据p_buff,继续放回到a2dp_list中
12、若大于三包,丢弃掉之前取出来的数据p_buff
总结:若第6步,acl链路可缓存buff数量(l2c_buff) 等于controller可接收buff总数,证明协议栈5个包塞满了,没有发出去,
此时就不能从btif_a2dp_source_cb.tx_audio_queue中读取数据,这样,目前Android源生设定,每20ms发送一包音频数据,
audio给到蓝牙侧的数据会溢出overflow,会打印以下log:
bt_btif_a2dp_source: btif_a2dp_source_enqueue_callback: TX queue buffer size now=22 adding=7 max=28
Cannot read RSSI
Cannot read Failed Contact Counter
Cannot read Automatic Flush Timeout
Cannot read Tx Power
link_xmit_data_q只能发送5个L2CAP包,超出5个部分,将缓存到a2d_list中,如果a2d_list存在数据,那么就不会发送btif_a2dp_source_cb.tx_audio_queue里面的数据,
然后就出现数据包丢失和卡顿。如果收到controller上报的completed evt上报后,会主动去发送a2d_list已缓存的音频数据。
源码分析:
void bta_av_data_path(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
2098 BT_HDR* p_buf = NULL;
2099 uint32_t timestamp; //时间戳
2100 bool new_buf = false; //是否有新数据
2101 uint8_t m_pt = 0x60;
2102 tAVDT_DATA_OPT_MASK opt;
2103
2104 if (p_scb->cong) return;
2105
2106 if (p_scb->use_rtp_header_marker_bit) {
2107 m_pt |= AVDT_MARKER_SET;
2108 }
2109
2110 // Always get the current number of bufs que'd up
2111 p_scb->l2c_bufs =
2112 (uint8_t)L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET); //1、计算acl链路可缓存buff数量(l2c_buff),(a2dp acl链路
优先级高,分配定额5个buff)
2113
2114 if (!list_is_empty(p_scb->a2dp_list)) { //2、判断a2dp_list队列是否有数据,若有数据,
2115 p_buf = (BT_HDR*)list_front(p_scb->a2dp_list); //3、取出a2dp_list链表头数据p_buff
2116 list_remove(p_scb->a2dp_list, p_buf);
2117 /* use q_info.a2dp data, read the timestamp */
2118 timestamp = *(uint32_t*)(p_buf + 1);
2119 } else {
2120 new_buf = true;
2121 /* A2DP_list empty, call co_data, dup data to other channels */
//4、若没有数据,调用bta_av_co_audio_source_data_path去btif_a2dp_source_cb.tx_audio_queue中读取数据,保存到p_buff
2122 p_buf = p_scb->p_cos->data(p_scb->cfg.codec_info, ×tamp);
2123
2124 if (p_buf) {
2125 /* use the offset area for the time stamp */
2126 *(uint32_t*)(p_buf + 1) = timestamp;
2127
2128 /* dup the data to other channels */
2129 bta_av_dup_audio_buf(p_scb, p_buf);
2130 }
2131 }
2132
2133 if (p_buf) {
//6、判断acl链路可缓存buff数量(l2c_buff) 是否大于controller可接收buff总数(a2dp acl链路优先级高,分配定额5个buff(如果有多条高优先级链路,少于5个))
2134 if (p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM)) {//未超过定额数,7、将取出来的数据p_buff,交给AVDTP,发送给对端设备
2135 /* There's a buffer, just queue it to L2CAP.
2136 * There's no need to increment it here, it is always read from
2137 * L2CAP (see above).
2138 */
2139
2140 /* opt is a bit mask, it could have several options set */
2141 opt = AVDT_DATA_OPT_NONE;
2142 if (p_scb->no_rtp_header) {
2143 opt |= AVDT_DATA_OPT_NO_RTP;
2144 }
2145
2146 //
2147 // Fragment the payload if larger than the MTU.
2148 // NOTE: The fragmentation is RTP-compatibie.
2149 //
2150 size_t extra_fragments_n = 0;
2151 if (p_buf->len > 0) {
2152 extra_fragments_n = (p_buf->len / p_scb->stream_mtu) +
2153 ((p_buf->len % p_scb->stream_mtu) ? 1 : 0) - 1;
2154 }
2155 std::vector extra_fragments;
2156 extra_fragments.reserve(extra_fragments_n);
2157
2158 uint8_t* data_begin = (uint8_t*)(p_buf + 1) + p_buf->offset;
2159 uint8_t* data_end = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
2160 while (extra_fragments_n-- > 0) {
2161 data_begin += p_scb->stream_mtu;
2162 size_t fragment_len = data_end - data_begin;
2163 if (fragment_len > p_scb->stream_mtu) fragment_len = p_scb->stream_mtu;
2164
2165 BT_HDR* p_buf2 = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
2166 p_buf2->offset = p_buf->offset;
2167 p_buf2->len = 0;
2168 p_buf2->layer_specific = 0;
2169 uint8_t* packet2 =
2170 (uint8_t*)(p_buf2 + 1) + p_buf2->offset + p_buf2->len;
2171 memcpy(packet2, data_begin, fragment_len);
2172 p_buf2->len += fragment_len;
2173 extra_fragments.push_back(p_buf2);
2174 p_buf->len -= fragment_len;
2175 }
2176
2177 if (!extra_fragments.empty()) {
2178 // Reset the RTP Marker bit for all fragments except the last one
2179 m_pt &= ~AVDT_MARKER_SET;
2180 }
//7、将取出来的数据p_buff,交给AVDTP,发送给对端设备
2181 AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf, timestamp, m_pt, opt);
2182 for (size_t i = 0; i < extra_fragments.size(); i++) {
2183 if (i + 1 == extra_fragments.size()) {
2184 // Set the RTP Marker bit for the last fragment
2185 m_pt |= AVDT_MARKER_SET;
2186 }
2187 BT_HDR* p_buf2 = extra_fragments[i];
2188 AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf2, timestamp, m_pt, opt);
2189 }
2190 p_scb->cong = true;
2191 } else { //超过定额数,8、判断p_buff中数据,是从3中取出来的,还是从4中取出来的
2192 /* there's a buffer, but L2CAP does not seem to be moving data */
2193 if (new_buf) { / /new_buf == 1,说明从4取出来的, 证明之前a2dp_list为空
2194 /* just got this buffer from co_data,
2195 * put it in queue */
2196 list_append(p_scb->a2dp_list, p_buf); //9、将之前取出来的数据p_buff,继续放回到a2dp_list中
2197 } else { //若是从a2d_list中取出来的
2198 /* just dequeue it from the a2dp_list */
2199 if (list_length(p_scb->a2dp_list) < 3) { //10、再次判断,此刻a2dp_list中数据是否小于3包
2200 /* put it back to the queue */ //小于3包,11、将之前取出来的数据p_buff,继续放回到a2dp_list中
2201 list_prepend(p_scb->a2dp_list, p_buf);
2202 } else {
2203 /* too many buffers in a2dp_list, drop it. */
//大于等于3包,12、丢弃掉之前取出来的数据p_buff
2204 bta_av_co_audio_drop(p_scb->hndl, p_scb->PeerAddress());
2205 osi_free(p_buf);
2206 }
2207 }
2208 }
2209 }
2210}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)