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

Commit 51f33327 authored by Myles Watson's avatar Myles Watson
Browse files

SCO: Use std::vector for rx data

Bug: 283254594
Test: presubmit
Change-Id: Ice403b5233b65daa139ef474b6876bc8e3e398d6
parent afbb1cd8
Loading
Loading
Loading
Loading
+19 −52
Original line number Diff line number Diff line
@@ -78,29 +78,15 @@ const bluetooth::legacy::hci::Interface& GetLegacyHciInterface() {
};  // namespace

// forward declaration for dequeueing packets
void btm_route_sco_data(BT_HDR* p_msg);
void btm_route_sco_data(bluetooth::hci::ScoView valid_packet);

namespace cpp {
constexpr size_t kBtHdrSize = sizeof(BT_HDR);
bluetooth::common::BidiQueueEnd<bluetooth::hci::ScoBuilder,
                                bluetooth::hci::ScoView>* hci_sco_queue_end =
    nullptr;
static bluetooth::os::EnqueueBuffer<bluetooth::hci::ScoBuilder>*
    pending_sco_data = nullptr;

static BT_HDR* WrapPacketAndCopy(
    uint16_t event,
    bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian>* data) {
  size_t packet_size = data->size() + kBtHdrSize;
  BT_HDR* packet = reinterpret_cast<BT_HDR*>(osi_malloc(packet_size));
  packet->offset = 0;
  packet->len = data->size();
  packet->layer_specific = 0;
  packet->event = event;
  std::copy(data->begin(), data->end(), packet->data);
  return packet;
}

static void sco_data_callback() {
  if (hci_sco_queue_end == nullptr) {
    return;
@@ -111,8 +97,7 @@ static void sco_data_callback() {
    LOG_INFO("Dropping invalid packet of size %zu", packet->size());
    return;
  }
  auto data = WrapPacketAndCopy(0x1200 /* delete next CL */, packet.get());
  if (do_in_main_thread(FROM_HERE, base::Bind(&btm_route_sco_data, data)) !=
  if (do_in_main_thread(FROM_HERE, base::Bind(&btm_route_sco_data, *packet)) !=
      BT_STATUS_SUCCESS) {
    LOG_ERROR("do_in_main_thread failed from sco_data_callback");
  }
@@ -290,56 +275,39 @@ static tSCO_CONN* btm_get_active_sco() {
 * Returns          void
 *
 ******************************************************************************/
void btm_route_sco_data(BT_HDR* p_msg) {
  uint8_t* payload = p_msg->data;
  if (p_msg->len < 3) {
    LOG_ERROR("Received incomplete SCO header");
    osi_free(p_msg);
    return;
  }

  uint8_t data_len = 0;
  uint16_t handle_with_flags = 0;
  STREAM_TO_UINT16(handle_with_flags, payload);
  STREAM_TO_UINT8(data_len, payload);
  if (p_msg->len != data_len + 3) {
    LOG_ERROR("Received invalid SCO data of size: %hhu, dropping", data_len);
    osi_free(p_msg);
    return;
  }

  uint16_t handle = HCID_GET_HANDLE(handle_with_flags);
void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) {
  uint16_t handle = valid_packet.GetHandle();
  if (handle > HCI_HANDLE_MAX) {
    LOG_ERROR(
        "Receive invalid SCO data with handle: 0x%X, required to be <= 0x%X, "
        "dropping",
        handle, HCI_HANDLE_MAX);
    osi_free(p_msg);
    LOG_ERROR("Dropping SCO data with invalid handle: 0x%X > 0x%X, ", handle,
              HCI_HANDLE_MAX);
    return;
  }

  tSCO_CONN* active_sco = btm_get_active_sco();
  if (active_sco == nullptr) {
    LOG_ERROR("Received SCO data when there is no active SCO connection");
    osi_free(p_msg);
    return;
  }
  if (active_sco->hci_handle != handle) {
    LOG_ERROR(
        "Drop packet with handle(0x%X) different from the active handle(0x%X)",
    LOG_ERROR("Dropping packet with handle(0x%X) != active handle(0x%X)",
              handle, active_sco->hci_handle);
    osi_free(p_msg);
    return;
  }

  auto data = valid_packet.GetData();
  auto data_len = data.size();
  auto rx_data = data.data();
  const uint8_t* decoded = nullptr;
  size_t written = 0, rc = 0;
  if (active_sco->is_wbs()) {
    uint16_t status = HCID_GET_PKT_STATUS(handle_with_flags);
    auto status = valid_packet.GetPacketStatusFlag();

    if (status > 0) LOG_DEBUG("Packet corrupted with status(0x%X)", status);
    rc = bluetooth::audio::sco::wbs::enqueue_packet(payload, data_len,
                                                    status > 0);
    if (status != bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED) {
      LOG_DEBUG("Packet corrupted with status(%s)",
                PacketStatusFlagText(status).c_str());
    }
    rc = bluetooth::audio::sco::wbs::enqueue_packet(
        data, status != bluetooth::hci::PacketStatusFlag::CORRECTLY_RECEIVED);
    if (rc != data_len) LOG_DEBUG("Failed to enqueue packet");

    while (rc) {
@@ -352,9 +320,8 @@ void btm_route_sco_data(BT_HDR* p_msg) {
      written += bluetooth::audio::sco::write(decoded, rc);
    }
  } else {
    written = bluetooth::audio::sco::write(payload, data_len);
    written = bluetooth::audio::sco::write(rx_data, data_len);
  }
  osi_free(p_msg);

  /* 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 */
+3 −5
Original line number Diff line number Diff line
@@ -75,14 +75,12 @@ bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio);

/* Try to enqueue a packet to a buffer.
 * Args:
 *    data - Pointer to received packet data bytes.
 *    pkt_size - Length of input packet. Passing packet with inconsistent size
 *        from the pkt_size set in init() will fail the call.
 *    data - Vector of received packet data bytes.
 *    corrupted - If the current mSBC packet read is corrupted.
 * Returns:
 *    The length of enqueued bytes. 0 if failed.
 *    true if enqueued, false if it failed.
 */
size_t enqueue_packet(const uint8_t* data, size_t pkt_size, bool corrupted);
bool enqueue_packet(const std::vector<uint8_t>& data, bool corrupted);

/* Try to decode mSBC frames from the packets in the buffer.
 * Args:
+14 −19
Original line number Diff line number Diff line
@@ -484,14 +484,14 @@ struct tBTM_MSBC_INFO {
    }
  }

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

    std::copy(input, input + len, msbc_decode_buf + decode_buf_wo);
    decode_buf_wo += len;
    return len;
    std::copy(input.begin(), input.end(), msbc_decode_buf + decode_buf_wo);
    decode_buf_wo += input.size();
    return input.size();
  }

  const uint8_t* find_msbc_pkt_head() {
@@ -608,33 +608,28 @@ bool fill_plc_stats(int* num_decoded_frames, double* packet_loss_ratio) {
  return true;
}

size_t enqueue_packet(const uint8_t* data, size_t pkt_size, bool corrupted) {
bool enqueue_packet(const std::vector<uint8_t>& data, bool corrupted) {
  if (msbc_info == nullptr) {
    LOG_WARN("mSBC buffer uninitialized or cleaned");
    return 0;
    return false;
  }

  if (pkt_size != msbc_info->packet_size) {
  if (data.size() != msbc_info->packet_size) {
    LOG_WARN(
        "Ignoring the coming packet with size %lu that is inconsistent with "
        "the HAL reported packet size %lu",
        (unsigned long)pkt_size, (unsigned long)msbc_info->packet_size);
    return 0;
  }

  if (data == nullptr) {
    LOG_WARN("Invalid data to enqueue");
    return 0;
        (unsigned long)data.size(), (unsigned long)msbc_info->packet_size);
    return false;
  }

  msbc_info->read_corrupted |= corrupted;
  if (msbc_info->write(data, pkt_size) != pkt_size) {
  if (msbc_info->write(data) != data.size()) {
    LOG_DEBUG("Fail to write packet with size %lu to buffer",
              (unsigned long)pkt_size);
    return 0;
              (unsigned long)data.size());
    return false;
  }

  return pkt_size;
  return true;
}

size_t decode(const uint8_t** out_data) {
+24 −34
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ using testing::Ge;
using testing::Le;
using testing::Test;

const uint8_t msbc_zero_packet[] = {
const std::vector<uint8_t> msbc_zero_packet{
    0x01, 0x08, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77,
    0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb,
@@ -189,30 +189,17 @@ TEST_F(ScoHciWbsTest, WbsInit) {
}

TEST_F(ScoHciWbsTest, WbsEnqueuePacketWithoutInit) {
  uint8_t payload[60];
  std::vector<uint8_t> payload{60, 0};
  // Return 0 if buffer is uninitialized
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload),
                                                       false),
            size_t(0));
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false);
}

TEST_F(ScoHciWbsWithInitCleanTest, WbsEnqueuePacket) {
  uint8_t payload[60];
  // Return 0 if payload is invalid
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(nullptr, sizeof(payload),
                                                       false),
            size_t(0));
  // Return 0 if packet size is consistent
  ASSERT_EQ(
      bluetooth::audio::sco::wbs::enqueue_packet(payload, size_t(72), false),
      size_t(0));
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload),
                                                       false),
            size_t(60));
  std::vector<uint8_t> payload;
  for (size_t i = 0; i < 60; i++) payload.push_back(0);
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true);
  // Return 0 if buffer is full
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload),
                                                       false),
            size_t(0));
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false);
}

TEST_F(ScoHciWbsTest, WbsDecodeWithoutInit) {
@@ -224,15 +211,14 @@ TEST_F(ScoHciWbsTest, WbsDecodeWithoutInit) {

TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) {
  const uint8_t* decoded = nullptr;
  uint8_t payload[60] = {0};
  std::vector<uint8_t> payload;
  for (size_t i = 0; i < 60; i++) payload.push_back(0);

  // No data to decode
  ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
  ASSERT_EQ(decoded, nullptr);
  // Fill in invalid packet, all zeros.
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload),
                                                       false),
            sizeof(payload));
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true);

  // Return all zero frames when there comes an invalid packet.
  // This is expected even with PLC as there is no history in the PLC buffer.
@@ -244,9 +230,8 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) {
  }

  decoded = nullptr;
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet,
                                                       sizeof(payload), false),
            sizeof(msbc_zero_packet));
  ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet, false),
            true);
  ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
            size_t(BTM_MSBC_CODE_SIZE));
  ASSERT_NE(decoded, nullptr);
@@ -322,9 +307,10 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) {
                          0, -100, -200, -300, -400, -300, -200, -100};
  int16_t data[120];
  int16_t expect_data[120];
  std::vector<uint8_t> encoded_vec;
  for (size_t i = 0; i < 60; i++) encoded_vec.push_back(0);
  const uint8_t* encoded = nullptr;
  const uint8_t* decoded = nullptr;
  uint8_t invalid_pkt[60] = {0};
  size_t lost_pkt_idx = 17;

  // Simulate a run without any packet loss
@@ -339,8 +325,9 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) {
    ASSERT_NE(encoded, nullptr);

    // Simulate the reception of the packet
    ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(encoded, 60, false),
              size_t(60));
    std::copy(encoded, encoded + size_t(60), encoded_vec.data());
    ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(encoded_vec, false),
              true);
    ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
              size_t(BTM_MSBC_CODE_SIZE));
    ASSERT_NE(decoded, nullptr);
@@ -362,9 +349,11 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) {
    ASSERT_NE(encoded, nullptr);

    // Substitute to invalid packet to simulate packet loss.
    std::copy(encoded, encoded + size_t(60), encoded_vec.data());
    ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(
                  i != lost_pkt_idx ? encoded : invalid_pkt, 60, false),
              size_t(60));
                  i != lost_pkt_idx ? encoded_vec : std::vector<uint8_t>(60, 0),
                  false),
              true);
    ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
              size_t(BTM_MSBC_CODE_SIZE));
    decode_count++;
@@ -404,9 +393,10 @@ TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) {
    ASSERT_NE(encoded, nullptr);

    // Substitute to report packet corrupted to simulate packet loss.
    std::copy(encoded, encoded + size_t(60), encoded_vec.data());
    ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(
                  encoded, 60, i == corrupted_pkt_idx),
              size_t(60));
                  encoded_vec, i == corrupted_pkt_idx),
              true);
    ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
              size_t(BTM_MSBC_CODE_SIZE));
    decode_count++;