Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b981a875 authored by JohnLai's avatar JohnLai Committed by John Lai
Browse files

floss: Generalize mSBC decode buffer

When we begin transmitting data to the controller, the
controller generates some fake data to prevent overrun.
Occasionally, the size of this fake data is not aligned with
the mSBC audio packet, which disrupts the current assumption that
read/write pointer offsets are always multiples of 60 or 72.
This misalignment impedes our ability to enqueue the decode buffer.

The patch addresses this issue by introducing a more generalized
assumption for the mSBC decode buffer, enabling it to handle
such cases effectively.

Bug: 314266464
Tag: #floss
Flag: EXEMPT floss only changes
Test: m Bluetooth && Ran ChromeOS HFP tests and verified HFP WBS
works on devices with SCO packet size 60 and 72

Change-Id: I89b97617845f6685fb1332c619f3b64c2cc074c7
parent 9560404c
Loading
Loading
Loading
Loading
+107 −18
Original line number Diff line number Diff line
@@ -396,9 +396,40 @@ struct tBTM_MSBC_INFO {
  size_t packet_size; /* SCO mSBC packet size supported by lower layer */
  size_t buf_size; /* The size of the buffer, determined by the packet_size. */

  enum decode_buf_state {
    DECODE_BUF_EMPTY,
    DECODE_BUF_FULL,

    // Neither empty nor full.
    DECODE_BUF_HALFFULL,
  };

  uint8_t* packet_buf;      /* Temporary buffer to store the data */
  uint8_t* msbc_decode_buf; /* Buffer to store mSBC packets to decode */
  size_t decode_buf_wo;     /* Write offset of the decode buffer */
  size_t decode_buf_ro;     /* Read offset of the decode buffer */

  /* Within the circular buffer, which can be visualized as having
     two halves, mirror indicators track the pointer's location,
     signaling whether it resides in the first or second segment:

              [buf_size-1] ┼ - - -─┼ [0]
                           │       │
                           │       │
     wo = x, wo_mirror = 0 ^       v ro = x, ro_mirror = 1
                           │       │
                           │       │
                       [0] ┼ - - - ┼ [buf_size-1]
              (First Half)           (Second Half)
  */
  bool decode_buf_wo_mirror; /* The mirror indicator specifies whether
                                the write pointer is currently located
                                in the first or second half of the
                                circular buffer */
  bool decode_buf_ro_mirror; /* The mirror indicator specifies whether
                                the read pointer is currently located
                                in the first or second half of the
                                circular buffer */
  bool read_corrupted;      /* If the current mSBC packet read is corrupted */

  uint8_t* msbc_encode_buf; /* Buffer to store the encoded SCO packets */
@@ -444,6 +475,9 @@ struct tBTM_MSBC_INFO {
  size_t init(size_t pkt_size) {
    decode_buf_wo = 0;
    decode_buf_ro = 0;
    decode_buf_wo_mirror = false;
    decode_buf_ro_mirror = false;

    encode_buf_wo = 0;
    encode_buf_ro = 0;

@@ -451,6 +485,9 @@ struct tBTM_MSBC_INFO {
    if (pkt_size == packet_size) return packet_size;
    packet_size = pkt_size;

    if (packet_buf) osi_free(packet_buf);
    packet_buf = (uint8_t*)osi_calloc(packet_size);

    if (msbc_decode_buf) osi_free(msbc_decode_buf);
    msbc_decode_buf = (uint8_t*)osi_calloc(buf_size);

@@ -473,6 +510,7 @@ struct tBTM_MSBC_INFO {

  void deinit() {
    if (msbc_decode_buf) osi_free(msbc_decode_buf);
    if (packet_buf) osi_free(packet_buf);
    if (msbc_encode_buf) osi_free(msbc_encode_buf);
    if (plc) {
      plc->deinit();
@@ -481,28 +519,66 @@ struct tBTM_MSBC_INFO {
    if (pkt_status) osi_free_and_reset((void**)&pkt_status);
  }

  size_t decodable() { return decode_buf_wo - decode_buf_ro; }
  void incr_buf_offset(size_t& offset, bool& mirror, size_t bsize,
                       size_t amount) {
    if (bsize - offset > amount) {
      offset += amount;
      return;
    }

    mirror = !mirror;
    offset = amount - (bsize - offset);
  }

  decode_buf_state decode_buf_status() {
    if (decode_buf_ro == decode_buf_wo) {
      if (decode_buf_ro_mirror == decode_buf_wo_mirror) return DECODE_BUF_EMPTY;
      return DECODE_BUF_FULL;
    }
    return DECODE_BUF_HALFFULL;
  }

  size_t decode_buf_data_len() {
    switch (decode_buf_status()) {
      case DECODE_BUF_EMPTY:
        return 0;
      case DECODE_BUF_FULL:
        return buf_size;
      case DECODE_BUF_HALFFULL:
      default:
        if (decode_buf_wo > decode_buf_ro) return decode_buf_wo - decode_buf_ro;
        return buf_size - (decode_buf_ro - decode_buf_wo);
    };
  }

  size_t decode_buf_avail_len() { return buf_size - decode_buf_data_len(); }

  void mark_pkt_decoded() {
    if (decode_buf_ro + BTM_MSBC_PKT_LEN > decode_buf_wo) {
    if (decode_buf_data_len() < BTM_MSBC_PKT_LEN) {
      LOG_ERROR("Trying to mark read offset beyond write offset.");
      return;
    }

    decode_buf_ro += BTM_MSBC_PKT_LEN;
    if (decode_buf_ro == decode_buf_wo) {
      decode_buf_ro = 0;
      decode_buf_wo = 0;
    }
    incr_buf_offset(decode_buf_ro, decode_buf_ro_mirror, buf_size,
                    BTM_MSBC_PKT_LEN);
  }

  size_t write(const std::vector<uint8_t>& input) {
    if (input.size() > buf_size - decode_buf_wo) {
    if (input.size() > decode_buf_avail_len()) {
      return 0;
    }

    if (buf_size - decode_buf_wo > input.size()) {
      std::copy(input.begin(), input.end(), msbc_decode_buf + decode_buf_wo);
    decode_buf_wo += input.size();
    } else {
      std::copy(input.begin(), input.begin() + buf_size - decode_buf_wo,
                msbc_decode_buf + decode_buf_wo);
      std::copy(input.begin() + buf_size - decode_buf_wo, input.end(),
                msbc_decode_buf);
    }

    incr_buf_offset(decode_buf_wo, decode_buf_wo_mirror, buf_size,
                    input.size());
    return input.size();
  }

@@ -513,12 +589,14 @@ struct tBTM_MSBC_INFO {
    }

    size_t rp = 0;
    while (rp < BTM_MSBC_PKT_LEN &&
           decode_buf_wo - (decode_buf_ro + rp) >= BTM_MSBC_PKT_LEN) {
      if ((msbc_decode_buf[decode_buf_ro + rp] != BTM_MSBC_H2_HEADER_0) ||
    size_t data_len = decode_buf_data_len();
    while (rp < BTM_MSBC_PKT_LEN && data_len - rp >= BTM_MSBC_PKT_LEN) {
      if ((msbc_decode_buf[(decode_buf_ro + rp) % buf_size] !=
           BTM_MSBC_H2_HEADER_0) ||
          (!verify_h2_header_seq_num(
              msbc_decode_buf[decode_buf_ro + rp + 1])) ||
          (msbc_decode_buf[decode_buf_ro + rp + 2] != BTM_MSBC_SYNC_WORD)) {
              msbc_decode_buf[(decode_buf_ro + rp + 1) % buf_size])) ||
          (msbc_decode_buf[(decode_buf_ro + rp + 2) % buf_size] !=
           BTM_MSBC_SYNC_WORD)) {
        rp++;
        continue;
      }
@@ -526,11 +604,22 @@ struct tBTM_MSBC_INFO {
      if (rp != 0) {
        LOG_WARN("Skipped %lu bytes of mSBC data ahead of a valid mSBC frame",
                 (unsigned long)rp);
        decode_buf_ro += rp;
        incr_buf_offset(decode_buf_ro, decode_buf_ro_mirror, buf_size, rp);
      }

      // Get the frame head.
      if (buf_size - decode_buf_ro >= BTM_MSBC_PKT_LEN) {
        return &msbc_decode_buf[decode_buf_ro];
      }

      std::copy(msbc_decode_buf + decode_buf_ro, msbc_decode_buf + buf_size,
                packet_buf);
      std::copy(msbc_decode_buf,
                msbc_decode_buf + BTM_MSBC_PKT_LEN - (buf_size - decode_buf_ro),
                packet_buf + (buf_size - decode_buf_ro));
      return packet_buf;
    }

    return nullptr;
  }

@@ -650,7 +739,7 @@ size_t decode(const uint8_t** out_data) {
    return 0;
  }

  if (msbc_info->decodable() < BTM_MSBC_PKT_LEN) {
  if (msbc_info->decode_buf_data_len() < BTM_MSBC_PKT_LEN) {
    return 0;
  }