转
https://www.cnblogs.com/blogs-of-lxl/p/7429367.html
https://blog.csdn.net/zjjdyb/article/details/50379769

a2dp sink 丢包问题:
可查看打印:
adb shell logcat|grep bta_av_sink_data_cback | tee sink.log
01-01 08:05:12.986 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x562
01-01 08:05:13.006 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x563
01-01 08:05:13.028 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x564
01-01 08:05:13.050 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x565
01-01 08:05:13.073 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x566
01-01 08:05:13.092 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x567
01-01 08:05:13.113 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x568
01-01 08:05:13.134 902 1161 D bt_btif : bta_av_sink_data_cback: avdt_handle: 1 pkt_len=0x399 offset = 0x14 number of frames 0x8 sequence number 0x569
或分析seq number与时间戳time stamp
https://blog.csdn.net/chinaycheng/article/details/52910167
void bta_av_data_path(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
BT_HDR* p_buf = NULL;
uint32_t timestamp;
bool new_buf = false;
uint8_t m_pt = 0x60;
tAVDT_DATA_OPT_MASK opt;
if (p_scb->cong) return;
if (p_scb->current_codec->useRtpHeaderMarkerBit()) {
m_pt |= AVDT_MARKER_SET;
}
// Always get the current number of bufs que'd up
p_scb->l2c_bufs =
(uint8_t)L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET);
if (!list_is_empty(p_scb->a2dp_list)) {
p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
list_remove(p_scb->a2dp_list, p_buf);
/* use q_info.a2dp data, read the timestamp */
timestamp = *(uint32_t*)(p_buf + 1);
} else {
new_buf = true;
/* A2DP_list empty, call co_data, dup data to other channels */
p_buf = (BT_HDR*)p_scb->p_cos->data(p_scb->cfg.codec_info, ×tamp);
if (p_buf) {
/* use the offset area for the time stamp */
*(uint32_t*)(p_buf + 1) = timestamp;
/* dup the data to other channels */
bta_av_dup_audio_buf(p_scb, p_buf);
}
}
if (p_buf) {
if (p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM)) {
/* There's a buffer, just queue it to L2CAP.
* There's no need to increment it here, it is always read from
* L2CAP (see above).
*/
/* opt is a bit mask, it could have several options set */
opt = AVDT_DATA_OPT_NONE;
if (p_scb->no_rtp_hdr) {
opt |= AVDT_DATA_OPT_NO_RTP;
}
//
// Fragment the payload if larger than the MTU.
// NOTE: The fragmentation is RTP-compatibie.
//
size_t extra_fragments_n = 0;
if (p_buf->len > 0) {
extra_fragments_n = (p_buf->len / p_scb->stream_mtu) +
((p_buf->len % p_scb->stream_mtu) ? 1 : 0) - 1;
}
std::vector<BT_HDR*> extra_fragments;
extra_fragments.reserve(extra_fragments_n);
uint8_t* data_begin = (uint8_t*)(p_buf + 1) + p_buf->offset;
uint8_t* data_end = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
while (extra_fragments_n-- > 0) {
data_begin += p_scb->stream_mtu;
size_t fragment_len = data_end - data_begin;
if (fragment_len > p_scb->stream_mtu) fragment_len = p_scb->stream_mtu;
BT_HDR* p_buf2 = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
p_buf2->offset = p_buf->offset;
p_buf2->len = 0;
p_buf2->layer_specific = 0;
uint8_t* packet2 =
(uint8_t*)(p_buf2 + 1) + p_buf2->offset + p_buf2->len;
memcpy(packet2, data_begin, fragment_len);
p_buf2->len += fragment_len;
extra_fragments.push_back(p_buf2);
p_buf->len -= fragment_len;
}
if (!extra_fragments.empty()) {
// Reset the RTP Marker bit for all fragments except the last one
m_pt &= ~AVDT_MARKER_SET;
}
AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf, timestamp, m_pt, opt);
for (size_t i = 0; i < extra_fragments.size(); i++) {
if (i + 1 == extra_fragments.size()) {
// Set the RTP Marker bit for the last fragment
m_pt |= AVDT_MARKER_SET;
}
BT_HDR* p_buf2 = extra_fragments[i];
AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf2, timestamp, m_pt, opt);
}
p_scb->cong = true;
} else {
/* there's a buffer, but L2CAP does not seem to be moving data */
if (new_buf) {
/* just got this buffer from co_data,
* put it in queue */
list_append(p_scb->a2dp_list, p_buf);
} else {
/* just dequeue it from the a2dp_list */
if (list_length(p_scb->a2dp_list) < 3) {
/* put it back to the queue */
list_prepend(p_scb->a2dp_list, p_buf);
} else {
/* too many buffers in a2dp_list, drop it. */
bta_av_co_audio_drop(p_scb->hndl);
osi_free(p_buf);
}
}
}
}
}
问题原因,link_xmit_data_q只能发送5个L2CAP包,超出5个部分,将缓存到a2d_list中,如果a2d_list存在数据,那么就不会发送TxAaQ里面的数据,然后就出现数据包丢失和卡顿
其中
#define BTA_AV_QUEUE_DATA_CHK_NUM L2CAP_HIGH_PRI_MIN_XMIT_QUOTA
https://wenku.baidu.com/view/bfc0ee176ad97f192279168884868762caaebb87.html
蓝牙音频(audio+sink)设备音乐卡顿问题。
+分析方向:此问题可能的原因众多,排查确认工作也比较繁琐,原因有如下:
+1.手机打印日志(特别是HCI日志)导致卡顿。
+2.蓝牙wifi共存问题,wifi正在高速下载或者传输P2P文件。
+3.测试环境比较噪杂(2.4GHz信号较多,蓝牙跳频以及重传概率增加)干扰较多。
+4.导出A2DP音频文件查看是否有卡顿,若有卡顿求助音频组确认audioflinger传过来的数据是否正常。
+5.查找到HCI日志中AVDTP+Media列中两个音频数据包间隔较大的异常数据,然后跳转到HCI列中确认是没有收到对方发来的数据(Number+Of+Completed+Packets)还是缓冲区(Available+Host%60s+ACL+credits)充裕而上层host没有发数据