Loading system/stack/btm/btm_sco_hci.cc +108 −28 Original line number Diff line number Diff line Loading @@ -139,6 +139,14 @@ size_t write(const uint8_t* p_buf, uint32_t len) { return UIPC_Send(*sco_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len) ? len : 0; } enum decode_buf_state { DECODE_BUF_EMPTY, DECODE_BUF_FULL, // Neither empty nor full. DECODE_BUF_HALFFULL, }; namespace wbs { /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits Loading Loading @@ -396,14 +404,6 @@ 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 */ Loading Loading @@ -843,20 +843,43 @@ constexpr uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; * code ties to limited packet size values. Specifically list them out * to check against when setting packet size. The first entry is the default * value as a fallback. */ constexpr size_t btm_swb_supported_pkt_size[] = {BTM_LC3_PKT_LEN, 72, 0}; constexpr size_t btm_swb_supported_pkt_size[] = {BTM_LC3_PKT_LEN, 72, 24, 0}; /* Buffer size should be set to least common multiple of SCO packet size and * BTM_LC3_PKT_LEN for optimizing buffer copy. */ constexpr size_t btm_swb_lc3_buffer_size[] = {BTM_LC3_PKT_LEN, 360, 0}; constexpr size_t btm_swb_lc3_buffer_size[] = {BTM_LC3_PKT_LEN, 360, 120, 0}; /* Define the structure that contains LC3 data */ struct tBTM_LC3_INFO { size_t packet_size; /* SCO LC3 packet size supported by lower layer */ size_t buf_size; /* The size of the buffer, determined by the packet_size. */ uint8_t* packet_buf; /* Temporary buffer to store the data */ uint8_t* lc3_decode_buf; /* Buffer to store LC3 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 LC3 packet read is corrupted */ uint8_t* lc3_encode_buf; /* Buffer to store the encoded SCO packets */ Loading Loading @@ -902,6 +925,9 @@ struct tBTM_LC3_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; Loading @@ -909,6 +935,8 @@ struct tBTM_LC3_INFO { if (pkt_size == packet_size) return packet_size; packet_size = pkt_size; if (!packet_buf) packet_buf = (uint8_t*)osi_calloc(BTM_LC3_PKT_LEN); if (lc3_decode_buf) osi_free(lc3_decode_buf); lc3_decode_buf = (uint8_t*)osi_calloc(buf_size); Loading @@ -924,11 +952,44 @@ struct tBTM_LC3_INFO { void deinit() { if (lc3_decode_buf) osi_free(lc3_decode_buf); if (packet_buf) osi_free(packet_buf); if (lc3_encode_buf) osi_free(lc3_encode_buf); 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(); } uint8_t* fill_lc3_pkt_template() { uint8_t* wp = &lc3_encode_buf[encode_buf_wo]; Loading @@ -946,29 +1007,35 @@ struct tBTM_LC3_INFO { } void mark_pkt_decoded() { if (decode_buf_ro + BTM_LC3_PKT_LEN > decode_buf_wo) { if (decode_buf_data_len() < BTM_LC3_PKT_LEN) { log::error("Trying to mark read offset beyond write offset."); return; } decode_buf_ro += BTM_LC3_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_LC3_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()) { log::warn( "Cannot write input with size {} into decode_buf with {} empty " "space.", input.size(), buf_size - decode_buf_wo); input.size(), decode_buf_avail_len()); return 0; } if (buf_size - decode_buf_wo > input.size()) { std::copy(input.begin(), input.end(), lc3_decode_buf + decode_buf_wo); decode_buf_wo += input.size(); } else { std::copy(input.begin(), input.begin() + buf_size - decode_buf_wo, lc3_decode_buf + decode_buf_wo); std::copy(input.begin() + buf_size - decode_buf_wo, input.end(), lc3_decode_buf); } incr_buf_offset(decode_buf_wo, decode_buf_wo_mirror, buf_size, input.size()); return input.size(); } Loading @@ -979,10 +1046,12 @@ struct tBTM_LC3_INFO { } size_t rp = 0; while (rp < BTM_LC3_PKT_LEN && decode_buf_wo - (decode_buf_ro + rp) >= BTM_LC3_PKT_LEN) { if ((lc3_decode_buf[decode_buf_ro + rp] != BTM_LC3_H2_HEADER_0) || !verify_h2_header_seq_num(lc3_decode_buf[decode_buf_ro + rp + 1])) { size_t data_len = decode_buf_data_len(); while (rp < BTM_LC3_PKT_LEN && data_len - rp >= BTM_LC3_PKT_LEN) { if ((lc3_decode_buf[(decode_buf_ro + rp) % buf_size] != BTM_LC3_H2_HEADER_0) || !verify_h2_header_seq_num( lc3_decode_buf[(decode_buf_ro + rp + 1) % buf_size])) { rp++; continue; } Loading @@ -990,11 +1059,22 @@ struct tBTM_LC3_INFO { if (rp != 0) { log::warn("Skipped {} bytes of LC3 data ahead of a valid LC3 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_LC3_PKT_LEN) { return &lc3_decode_buf[decode_buf_ro]; } std::copy(lc3_decode_buf + decode_buf_ro, lc3_decode_buf + buf_size, packet_buf); std::copy(lc3_decode_buf, lc3_decode_buf + BTM_LC3_PKT_LEN - (buf_size - decode_buf_ro), packet_buf + (buf_size - decode_buf_ro)); return packet_buf; } return nullptr; } Loading Loading @@ -1099,7 +1179,7 @@ size_t decode(const uint8_t** out_data) { return 0; } if (lc3_info->decodable() < BTM_LC3_PKT_LEN) { if (lc3_info->decode_buf_data_len() < BTM_LC3_PKT_LEN) { return 0; } Loading system/stack/test/btm/sco_hci_test.cc +126 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <gtest/gtest.h> #include <algorithm> #include <map> #include <memory> #include "btif/include/core_callbacks.h" Loading Loading @@ -59,6 +60,16 @@ const std::vector<uint8_t> lc3_zero_packet{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0xf9, 0x4a, 0x0d, 0x00, 0x00, 0x03}; // Maps irregular packet size to expected decode buffer size. // See |btm_wbs_supported_pkt_size| and |btm_wbs_msbc_buffer_size|. const std::map<size_t, size_t> irregular_packet_to_buffer_size{ {72, 360}, {24, 120}, }; // The encoded packet size is 60 regardless of the codec. const int ENCODED_PACKET_SIZE = 60; struct MsbcCodecInterface : bluetooth::core::CodecInterface { MsbcCodecInterface() : bluetooth::core::CodecInterface(){}; Loading Loading @@ -354,6 +365,121 @@ TEST_F(ScoHciSwbWithInitCleanTest, SwbDecode) { ASSERT_EQ(decoded, nullptr); } TEST_F(ScoHciWbsTest, WbsDecodeWithIrregularOffset) { for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) { ASSERT_EQ(buf_size % pkt_size, 0u); bluetooth::audio::sco::wbs::init(pkt_size); const uint8_t* decoded = nullptr; // No data to decode ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); // Start the payload with an irregular offset that misaligns with the // packet size. std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0); while (payload.size() <= pkt_size) { payload.insert(payload.end(), msbc_zero_packet.begin(), msbc_zero_packet.end()); } size_t packet_offset = msbc_zero_packet.size() - (payload.size() - pkt_size); payload.resize(pkt_size); // Try to decode as many packets as to hit the boundary. for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size; ++iter) { ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true); decodable += payload.size() - !iter; // compensate for the first offset while (decodable >= ENCODED_PACKET_SIZE) { decoded = nullptr; ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE)); ASSERT_NE(decoded, nullptr); for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) { ASSERT_EQ(decoded[i], 0); } decodable -= ENCODED_PACKET_SIZE; } payload = std::vector<uint8_t>(msbc_zero_packet.begin() + packet_offset, msbc_zero_packet.end()); while (payload.size() < pkt_size) { payload.insert(payload.end(), msbc_zero_packet.begin(), msbc_zero_packet.end()); } packet_offset += msbc_zero_packet.size() - packet_offset; packet_offset += msbc_zero_packet.size() - (payload.size() - pkt_size) % msbc_zero_packet.size(); packet_offset %= msbc_zero_packet.size(); payload.resize(pkt_size); } bluetooth::audio::sco::wbs::cleanup(); } } TEST_F(ScoHciSwbTest, SwbDecodeWithIrregularOffset) { for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) { ASSERT_EQ(buf_size % pkt_size, 0u); bluetooth::audio::sco::swb::init(pkt_size); const uint8_t* decoded = nullptr; // No data to decode ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); // Start the payload with an irregular offset that misaligns with the // packet size. std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0); while (payload.size() <= pkt_size) { payload.insert(payload.end(), lc3_zero_packet.begin(), lc3_zero_packet.end()); } size_t packet_offset = lc3_zero_packet.size() - (payload.size() - pkt_size); payload.resize(pkt_size); // Try to decode as many packets as to hit the boundary. for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size; ++iter) { ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true); decodable += payload.size() - !iter; // compensate for the first offset while (decodable >= ENCODED_PACKET_SIZE) { decoded = nullptr; ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE)); ASSERT_NE(decoded, nullptr); for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) { ASSERT_EQ(decoded[i], 0); } decodable -= ENCODED_PACKET_SIZE; } payload = std::vector<uint8_t>(lc3_zero_packet.begin() + packet_offset, lc3_zero_packet.end()); while (payload.size() < pkt_size) { payload.insert(payload.end(), lc3_zero_packet.begin(), lc3_zero_packet.end()); } packet_offset += lc3_zero_packet.size() - packet_offset; packet_offset += lc3_zero_packet.size() - (payload.size() - pkt_size) % lc3_zero_packet.size(); packet_offset %= lc3_zero_packet.size(); payload.resize(pkt_size); } bluetooth::audio::sco::swb::cleanup(); } } TEST_F(ScoHciWbsTest, WbsEncodeWithoutInit) { int16_t data[120] = {0}; // Return 0 if buffer is uninitialized Loading Loading
system/stack/btm/btm_sco_hci.cc +108 −28 Original line number Diff line number Diff line Loading @@ -139,6 +139,14 @@ size_t write(const uint8_t* p_buf, uint32_t len) { return UIPC_Send(*sco_uipc, UIPC_CH_ID_AV_AUDIO, 0, p_buf, len) ? len : 0; } enum decode_buf_state { DECODE_BUF_EMPTY, DECODE_BUF_FULL, // Neither empty nor full. DECODE_BUF_HALFFULL, }; namespace wbs { /* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits Loading Loading @@ -396,14 +404,6 @@ 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 */ Loading Loading @@ -843,20 +843,43 @@ constexpr uint8_t btm_h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; * code ties to limited packet size values. Specifically list them out * to check against when setting packet size. The first entry is the default * value as a fallback. */ constexpr size_t btm_swb_supported_pkt_size[] = {BTM_LC3_PKT_LEN, 72, 0}; constexpr size_t btm_swb_supported_pkt_size[] = {BTM_LC3_PKT_LEN, 72, 24, 0}; /* Buffer size should be set to least common multiple of SCO packet size and * BTM_LC3_PKT_LEN for optimizing buffer copy. */ constexpr size_t btm_swb_lc3_buffer_size[] = {BTM_LC3_PKT_LEN, 360, 0}; constexpr size_t btm_swb_lc3_buffer_size[] = {BTM_LC3_PKT_LEN, 360, 120, 0}; /* Define the structure that contains LC3 data */ struct tBTM_LC3_INFO { size_t packet_size; /* SCO LC3 packet size supported by lower layer */ size_t buf_size; /* The size of the buffer, determined by the packet_size. */ uint8_t* packet_buf; /* Temporary buffer to store the data */ uint8_t* lc3_decode_buf; /* Buffer to store LC3 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 LC3 packet read is corrupted */ uint8_t* lc3_encode_buf; /* Buffer to store the encoded SCO packets */ Loading Loading @@ -902,6 +925,9 @@ struct tBTM_LC3_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; Loading @@ -909,6 +935,8 @@ struct tBTM_LC3_INFO { if (pkt_size == packet_size) return packet_size; packet_size = pkt_size; if (!packet_buf) packet_buf = (uint8_t*)osi_calloc(BTM_LC3_PKT_LEN); if (lc3_decode_buf) osi_free(lc3_decode_buf); lc3_decode_buf = (uint8_t*)osi_calloc(buf_size); Loading @@ -924,11 +952,44 @@ struct tBTM_LC3_INFO { void deinit() { if (lc3_decode_buf) osi_free(lc3_decode_buf); if (packet_buf) osi_free(packet_buf); if (lc3_encode_buf) osi_free(lc3_encode_buf); 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(); } uint8_t* fill_lc3_pkt_template() { uint8_t* wp = &lc3_encode_buf[encode_buf_wo]; Loading @@ -946,29 +1007,35 @@ struct tBTM_LC3_INFO { } void mark_pkt_decoded() { if (decode_buf_ro + BTM_LC3_PKT_LEN > decode_buf_wo) { if (decode_buf_data_len() < BTM_LC3_PKT_LEN) { log::error("Trying to mark read offset beyond write offset."); return; } decode_buf_ro += BTM_LC3_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_LC3_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()) { log::warn( "Cannot write input with size {} into decode_buf with {} empty " "space.", input.size(), buf_size - decode_buf_wo); input.size(), decode_buf_avail_len()); return 0; } if (buf_size - decode_buf_wo > input.size()) { std::copy(input.begin(), input.end(), lc3_decode_buf + decode_buf_wo); decode_buf_wo += input.size(); } else { std::copy(input.begin(), input.begin() + buf_size - decode_buf_wo, lc3_decode_buf + decode_buf_wo); std::copy(input.begin() + buf_size - decode_buf_wo, input.end(), lc3_decode_buf); } incr_buf_offset(decode_buf_wo, decode_buf_wo_mirror, buf_size, input.size()); return input.size(); } Loading @@ -979,10 +1046,12 @@ struct tBTM_LC3_INFO { } size_t rp = 0; while (rp < BTM_LC3_PKT_LEN && decode_buf_wo - (decode_buf_ro + rp) >= BTM_LC3_PKT_LEN) { if ((lc3_decode_buf[decode_buf_ro + rp] != BTM_LC3_H2_HEADER_0) || !verify_h2_header_seq_num(lc3_decode_buf[decode_buf_ro + rp + 1])) { size_t data_len = decode_buf_data_len(); while (rp < BTM_LC3_PKT_LEN && data_len - rp >= BTM_LC3_PKT_LEN) { if ((lc3_decode_buf[(decode_buf_ro + rp) % buf_size] != BTM_LC3_H2_HEADER_0) || !verify_h2_header_seq_num( lc3_decode_buf[(decode_buf_ro + rp + 1) % buf_size])) { rp++; continue; } Loading @@ -990,11 +1059,22 @@ struct tBTM_LC3_INFO { if (rp != 0) { log::warn("Skipped {} bytes of LC3 data ahead of a valid LC3 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_LC3_PKT_LEN) { return &lc3_decode_buf[decode_buf_ro]; } std::copy(lc3_decode_buf + decode_buf_ro, lc3_decode_buf + buf_size, packet_buf); std::copy(lc3_decode_buf, lc3_decode_buf + BTM_LC3_PKT_LEN - (buf_size - decode_buf_ro), packet_buf + (buf_size - decode_buf_ro)); return packet_buf; } return nullptr; } Loading Loading @@ -1099,7 +1179,7 @@ size_t decode(const uint8_t** out_data) { return 0; } if (lc3_info->decodable() < BTM_LC3_PKT_LEN) { if (lc3_info->decode_buf_data_len() < BTM_LC3_PKT_LEN) { return 0; } Loading
system/stack/test/btm/sco_hci_test.cc +126 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <gtest/gtest.h> #include <algorithm> #include <map> #include <memory> #include "btif/include/core_callbacks.h" Loading Loading @@ -59,6 +60,16 @@ const std::vector<uint8_t> lc3_zero_packet{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0xf9, 0x4a, 0x0d, 0x00, 0x00, 0x03}; // Maps irregular packet size to expected decode buffer size. // See |btm_wbs_supported_pkt_size| and |btm_wbs_msbc_buffer_size|. const std::map<size_t, size_t> irregular_packet_to_buffer_size{ {72, 360}, {24, 120}, }; // The encoded packet size is 60 regardless of the codec. const int ENCODED_PACKET_SIZE = 60; struct MsbcCodecInterface : bluetooth::core::CodecInterface { MsbcCodecInterface() : bluetooth::core::CodecInterface(){}; Loading Loading @@ -354,6 +365,121 @@ TEST_F(ScoHciSwbWithInitCleanTest, SwbDecode) { ASSERT_EQ(decoded, nullptr); } TEST_F(ScoHciWbsTest, WbsDecodeWithIrregularOffset) { for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) { ASSERT_EQ(buf_size % pkt_size, 0u); bluetooth::audio::sco::wbs::init(pkt_size); const uint8_t* decoded = nullptr; // No data to decode ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); // Start the payload with an irregular offset that misaligns with the // packet size. std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0); while (payload.size() <= pkt_size) { payload.insert(payload.end(), msbc_zero_packet.begin(), msbc_zero_packet.end()); } size_t packet_offset = msbc_zero_packet.size() - (payload.size() - pkt_size); payload.resize(pkt_size); // Try to decode as many packets as to hit the boundary. for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size; ++iter) { ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true); decodable += payload.size() - !iter; // compensate for the first offset while (decodable >= ENCODED_PACKET_SIZE) { decoded = nullptr; ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE)); ASSERT_NE(decoded, nullptr); for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) { ASSERT_EQ(decoded[i], 0); } decodable -= ENCODED_PACKET_SIZE; } payload = std::vector<uint8_t>(msbc_zero_packet.begin() + packet_offset, msbc_zero_packet.end()); while (payload.size() < pkt_size) { payload.insert(payload.end(), msbc_zero_packet.begin(), msbc_zero_packet.end()); } packet_offset += msbc_zero_packet.size() - packet_offset; packet_offset += msbc_zero_packet.size() - (payload.size() - pkt_size) % msbc_zero_packet.size(); packet_offset %= msbc_zero_packet.size(); payload.resize(pkt_size); } bluetooth::audio::sco::wbs::cleanup(); } } TEST_F(ScoHciSwbTest, SwbDecodeWithIrregularOffset) { for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) { ASSERT_EQ(buf_size % pkt_size, 0u); bluetooth::audio::sco::swb::init(pkt_size); const uint8_t* decoded = nullptr; // No data to decode ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); // Start the payload with an irregular offset that misaligns with the // packet size. std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0); while (payload.size() <= pkt_size) { payload.insert(payload.end(), lc3_zero_packet.begin(), lc3_zero_packet.end()); } size_t packet_offset = lc3_zero_packet.size() - (payload.size() - pkt_size); payload.resize(pkt_size); // Try to decode as many packets as to hit the boundary. for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size; ++iter) { ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true); decodable += payload.size() - !iter; // compensate for the first offset while (decodable >= ENCODED_PACKET_SIZE) { decoded = nullptr; ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE)); ASSERT_NE(decoded, nullptr); for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) { ASSERT_EQ(decoded[i], 0); } decodable -= ENCODED_PACKET_SIZE; } payload = std::vector<uint8_t>(lc3_zero_packet.begin() + packet_offset, lc3_zero_packet.end()); while (payload.size() < pkt_size) { payload.insert(payload.end(), lc3_zero_packet.begin(), lc3_zero_packet.end()); } packet_offset += lc3_zero_packet.size() - packet_offset; packet_offset += lc3_zero_packet.size() - (payload.size() - pkt_size) % lc3_zero_packet.size(); packet_offset %= lc3_zero_packet.size(); payload.resize(pkt_size); } bluetooth::audio::sco::swb::cleanup(); } } TEST_F(ScoHciWbsTest, WbsEncodeWithoutInit) { int16_t data[120] = {0}; // Return 0 if buffer is uninitialized Loading