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

Commit faef61d0 authored by John Lai's avatar John Lai Committed by Gerrit Code Review
Browse files

Merge "floss: Generalize PCM buffer" into main

parents a9575989 c695cb3e
Loading
Loading
Loading
Loading
+112 −44
Original line number Diff line number Diff line
@@ -204,12 +204,83 @@ void tSCO_CB::Free() {
/* Buffer used for reading PCM data from audio server that will be encoded into
 * mSBC packet. The BTM_SCO_DATA_SIZE_MAX should be set to a number divisible by
 * BTM_MSBC_CODE_SIZE(240) */
static int16_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0};
static uint8_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0};
static uint8_t packet_buf[BTM_SCO_DATA_SIZE_MAX] = {0};

/* The read and write offset for btm_pcm_buf.
 * They are only used for WBS and the unit is byte. */
static size_t btm_pcm_buf_read_offset = 0;
static size_t btm_pcm_buf_write_offset = 0;

static bool btm_pcm_buf_write_mirror = false;
static bool btm_pcm_buf_read_mirror = false;

enum btm_pcm_buf_state {
  DECODE_BUF_EMPTY,
  DECODE_BUF_FULL,

  // Neither empty nor full.
  DECODE_BUF_PARTIAL,
};

void incr_btm_pcm_buf_offset(size_t& offset, bool& mirror, size_t amount) {
  size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - offset;
  if (bytes_remaining > amount) {
    offset += amount;
    return;
  }

  mirror = !mirror;
  offset = amount - bytes_remaining;
}

btm_pcm_buf_state btm_pcm_buf_status() {
  if (btm_pcm_buf_read_offset == btm_pcm_buf_write_offset) {
    if (btm_pcm_buf_read_mirror == btm_pcm_buf_write_mirror)
      return DECODE_BUF_EMPTY;
    return DECODE_BUF_FULL;
  }
  return DECODE_BUF_PARTIAL;
}

size_t btm_pcm_buf_data_len() {
  switch (btm_pcm_buf_status()) {
    case DECODE_BUF_EMPTY:
      return 0;
    case DECODE_BUF_FULL:
      return BTM_SCO_DATA_SIZE_MAX;
    case DECODE_BUF_PARTIAL:
    default:
      if (btm_pcm_buf_write_offset > btm_pcm_buf_read_offset)
        return btm_pcm_buf_write_offset - btm_pcm_buf_read_offset;
      return BTM_SCO_DATA_SIZE_MAX -
             (btm_pcm_buf_read_offset - btm_pcm_buf_write_offset);
  };
}

size_t btm_pcm_buf_avail_len() {
  return BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_data_len();
}

size_t write_btm_pcm_buf(uint8_t* source, size_t amount) {
  if (btm_pcm_buf_avail_len() < amount) {
    return 0;
  }

  size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset;
  if (bytes_remaining > amount) {
    std::copy(source, source + amount, btm_pcm_buf + btm_pcm_buf_write_offset);
  } else {
    std::copy(source, source + bytes_remaining,
              btm_pcm_buf + btm_pcm_buf_write_offset);
    std::copy(source + bytes_remaining, source + amount, btm_pcm_buf);
  }

  incr_btm_pcm_buf_offset(btm_pcm_buf_write_offset, btm_pcm_buf_write_mirror,
                          amount);
  return amount;
}

/******************************************************************************/
/*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
/******************************************************************************/
@@ -341,6 +412,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) {
  auto rx_data = data.data();
  const uint8_t* decoded = nullptr;
  size_t written = 0, rc = 0;

  if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) {
    auto status = valid_packet.GetPacketStatusFlag();

@@ -370,24 +442,21 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) {

  /* For Chrome OS, we send the outgoing data after receiving an incoming one.
   * server, so that we can keep the data read/write rate balanced */
  size_t read = 0, avail = 0;
  size_t read = 0;
  const uint8_t* encoded = nullptr;

  if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) {
    while (written) {
      avail = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset;
      size_t avail = btm_pcm_buf_avail_len();
      if (avail) {
        size_t to_read = written < avail ? written : avail;
        read = bluetooth::audio::sco::read(
            (uint8_t*)btm_pcm_buf + btm_pcm_buf_write_offset, to_read);
        if (read != to_read) {
          log::assert_that(
              btm_pcm_buf_write_offset + read <= BTM_SCO_DATA_SIZE_MAX,
              "Read more {} data ({}) than available buffer ({}) guarded by "
              "read",
              codec, (unsigned long)read,
              (unsigned long)(BTM_SCO_DATA_SIZE_MAX -
                              btm_pcm_buf_write_offset));

        // Read to the packet_buf first and then copy to the btm_pcm_buf.
        read = bluetooth::audio::sco::read(packet_buf, to_read);

        write_btm_pcm_buf(packet_buf, read);

        if (read != to_read) {
          log::info(
              "Requested to read {} bytes of {} data but got {} bytes of PCM "
              "data from audio server: WriteOffset:{} ReadOffset:{}",
@@ -404,25 +473,33 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) {
        log::warn(
            "Buffer is full when we try to read {} packet from audio server",
            codec);
        log::assert_that(
            btm_pcm_buf_write_offset - btm_pcm_buf_read_offset >=
                (codec_type == BTM_SCO_CODEC_MSBC ? BTM_MSBC_CODE_SIZE
                                                  : BTM_LC3_CODE_SIZE),
            "PCM buffer is full but fails to encode an {} packet. This is "
            "abnormal and can cause busy loop: WriteOffset:{}, ReadOffset:{}, "
            "BufferSize:{}",
            codec, (unsigned long)btm_pcm_buf_write_offset,
            (unsigned long)btm_pcm_buf_read_offset,
            (unsigned long)sizeof(btm_pcm_buf));
      }

      btm_pcm_buf_write_offset += read;

      auto encode = codec_type == BTM_SCO_CODEC_LC3
                        ? &bluetooth::audio::sco::swb::encode
                        : &bluetooth::audio::sco::wbs::encode;
      rc = encode(&btm_pcm_buf[btm_pcm_buf_read_offset / sizeof(*btm_pcm_buf)],
                  btm_pcm_buf_write_offset - btm_pcm_buf_read_offset);

      size_t data_len = btm_pcm_buf_data_len();

      if (data_len) {
        // Copy all data to the packet_buf first and then call encode.
        size_t bytes_remaining =
            BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_read_offset;

        if (bytes_remaining > data_len) {
          std::copy(btm_pcm_buf + btm_pcm_buf_read_offset,
                    btm_pcm_buf + btm_pcm_buf_read_offset + data_len,
                    packet_buf);
        } else {
          std::copy(btm_pcm_buf + btm_pcm_buf_read_offset,
                    btm_pcm_buf + BTM_SCO_DATA_SIZE_MAX, packet_buf);
          std::copy(btm_pcm_buf, btm_pcm_buf + data_len - bytes_remaining,
                    packet_buf + bytes_remaining);
        }

        rc = encode((int16_t*)packet_buf, data_len);
        incr_btm_pcm_buf_offset(btm_pcm_buf_read_offset,
                                btm_pcm_buf_read_mirror, rc);

        if (!rc)
          log::debug(
@@ -430,14 +507,6 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) {
              "WriteOffset:{}",
              codec, (unsigned long)btm_pcm_buf_read_offset,
              (unsigned long)btm_pcm_buf_write_offset);

      /* The offsets should reset some time as the buffer length should always
       * divisible by 480 and `encode` only returns 480(LC3), 240(MSBC), or 0.
       */
      btm_pcm_buf_read_offset += rc;
      if (btm_pcm_buf_write_offset == btm_pcm_buf_read_offset) {
        btm_pcm_buf_write_offset = 0;
        btm_pcm_buf_read_offset = 0;
      }

      /* Send all of the available SCO packets buffered in the queue */
@@ -455,7 +524,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) {
  } else {
    while (written) {
      read = bluetooth::audio::sco::read(
          (uint8_t*)btm_pcm_buf,
          btm_pcm_buf,
          written < BTM_SCO_DATA_SIZE_MAX ? written : BTM_SCO_DATA_SIZE_MAX);
      if (read == 0) {
        log::info("Failed to read {} bytes of PCM data from audio server",
@@ -470,8 +539,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) {
       * send PCM data directly to SCO.
       * We don't maintain buffer read/write offset for NB as we send all data
       * that we read from the audio server. */
      auto data = std::vector<uint8_t>((uint8_t*)btm_pcm_buf,
                                       (uint8_t*)btm_pcm_buf + read);
      auto data = std::vector<uint8_t>(btm_pcm_buf, btm_pcm_buf + read);
      btm_send_sco_packet(std::move(data));
    }
  }