Bluedroid: 音频数据的传输流程问题分析


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, &timestamp);

    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没有发数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值