Loading system/stack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -840,6 +840,7 @@ cc_test { ":TestMockStackHcic", ":TestMockStackL2cap", ":TestMockStackSmp", ":TestMockUdrv", "acl/acl.cc", "acl/ble_acl.cc", "acl/btm_acl.cc", Loading Loading @@ -871,6 +872,7 @@ cc_test { "btm/hfp_msbc_encoder.cc", "btm/hfp_msbc_decoder.cc", "metrics/stack_metrics_logging.cc", "test/btm/sco_hci_test.cc", "test/btm/stack_btm_test.cc", "test/btm/peer_packet_types_test.cc", "test/common/mock_eatt.cc", Loading system/stack/btm/btm_sco.h +6 −3 Original line number Diff line number Diff line Loading @@ -54,9 +54,12 @@ namespace bluetooth::audio::sco::wbs { * pkt_size - Length of the SCO packet. It is determined based on the BT-USB * adapter's capability and alt mode setting. The value should be queried * from HAL interface. It will be used to determine the size of the SCO * packet buffer. * packet buffer. Currently, the stack only supports 60 and 72. * Returns: * The selected packet size. Will fallback to the typical mSBC packet * length(60) if the pkt_size argument is not supported. */ void init(size_t pkt_size); size_t init(size_t pkt_size); /* Clean up when the SCO connection is done */ void cleanup(); Loading @@ -65,7 +68,7 @@ void cleanup(); * 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 trigger a reset of the buffer. * from the pkt_size set in init() will fail the call. * Returns: * The length of enqueued bytes. 0 if failed. */ Loading system/stack/btm/btm_sco_hci.cc +31 −4 Original line number Diff line number Diff line Loading @@ -71,7 +71,13 @@ void open() { if (sco_uipc != nullptr) { LOG_WARN("Re-opening UIPC that is already running"); } sco_uipc = UIPC_Init(); if (sco_uipc == nullptr) { LOG_ERROR("%s failed to init UIPC", __func__); return; } UIPC_Open(*sco_uipc, UIPC_CH_ID_AV_AUDIO, sco_data_cb, SCO_HOST_DATA_PATH); struct group* grp = getgrnam(SCO_HOST_DATA_GROUP); chmod(SCO_HOST_DATA_PATH, 0770); Loading Loading @@ -180,7 +186,7 @@ struct tBTM_MSBC_INFO { } public: void init(size_t pkt_size) { size_t init(size_t pkt_size) { decode_buf_wo = 0; decode_buf_ro = 0; encode_buf_wo = 0; Loading @@ -188,7 +194,7 @@ struct tBTM_MSBC_INFO { pkt_size = get_supported_packet_size(pkt_size, &buf_size); if (pkt_size != BTM_MSBC_PKT_LEN) check_alignment = true; if (pkt_size == packet_size) return; if (pkt_size == packet_size) return packet_size; packet_size = pkt_size; if (msbc_decode_buf) osi_free(msbc_decode_buf); Loading @@ -196,6 +202,7 @@ struct tBTM_MSBC_INFO { if (msbc_encode_buf) osi_free(msbc_encode_buf); msbc_encode_buf = (uint8_t*)osi_calloc(buf_size); return packet_size; } void deinit() { Loading Loading @@ -292,7 +299,7 @@ struct tBTM_MSBC_INFO { static tBTM_MSBC_INFO* msbc_info = nullptr; void init(size_t pkt_size) { size_t init(size_t pkt_size) { hfp_msbc_decoder_init(); hfp_msbc_encoder_init(); Loading @@ -303,7 +310,7 @@ void init(size_t pkt_size) { } msbc_info = (tBTM_MSBC_INFO*)osi_calloc(sizeof(*msbc_info)); msbc_info->init(pkt_size); return msbc_info->init(pkt_size); } void cleanup() { Loading Loading @@ -331,6 +338,11 @@ size_t enqueue_packet(const uint8_t* data, size_t pkt_size) { return 0; } if (data == nullptr) { LOG_WARN("Invalid data to enqueue"); return 0; } if (msbc_info->check_alignment) { if (data[0] != BTM_MSBC_H2_HEADER_0 || data[2] != BTM_MSBC_SYNC_WORD) { LOG_DEBUG("Waiting for valid mSBC frame head"); Loading @@ -356,6 +368,11 @@ size_t decode(const uint8_t** out_data) { return 0; } if (out_data == nullptr) { LOG_WARN("%s Invalid output pointer", __func__); return 0; } if (msbc_info->decodable() < BTM_MSBC_PKT_LEN) { LOG_DEBUG("No complete mSBC packet to decode"); return 0; Loading Loading @@ -395,6 +412,11 @@ size_t encode(int16_t* data, size_t len) { return 0; } if (data == nullptr) { LOG_WARN("Invalid data to encode"); return 0; } if (len < BTM_MSBC_CODE_SIZE) { LOG_DEBUG( "PCM frames with size %lu is insufficient to be encoded into a mSBC " Loading Loading @@ -425,6 +447,11 @@ size_t dequeue_packet(const uint8_t** output) { return 0; } if (output == nullptr) { LOG_WARN("%s Invalid output pointer", __func__); return 0; } *output = msbc_info->sco_pkt_read_ptr(); if (*output == nullptr) { LOG_DEBUG("Insufficient data to dequeue."); Loading system/stack/test/btm/sco_hci_test.cc 0 → 100644 +279 −0 Original line number Diff line number Diff line /* * * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <algorithm> #include <map> #include <memory> #include "stack/btm/btm_sco.h" #include "udrv/include/uipc.h" extern std::map<std::string, int> mock_function_count_map; extern std::unique_ptr<tUIPC_STATE> mock_uipc_init_ret; extern uint32_t mock_uipc_read_ret; extern bool mock_uipc_send_ret; namespace { using testing::Test; const 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, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00}; class ScoHciTest : public Test { public: protected: void SetUp() override { mock_function_count_map.clear(); mock_uipc_init_ret = nullptr; mock_uipc_read_ret = 0; mock_uipc_send_ret = true; } void TearDown() override {} }; class ScoHciWithOpenCleanTest : public ScoHciTest { public: protected: void SetUp() override { ScoHciTest::SetUp(); mock_uipc_init_ret = std::make_unique<tUIPC_STATE>(); bluetooth::audio::sco::open(); } void TearDown() override { bluetooth::audio::sco::cleanup(); } }; class ScoHciWbsWithInitCleanTest : public Test { public: protected: void SetUp() override { bluetooth::audio::sco::wbs::init(60); } void TearDown() override { bluetooth::audio::sco::wbs::cleanup(); } }; TEST_F(ScoHciTest, ScoOverHciOpenFail) { bluetooth::audio::sco::open(); ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 0); bluetooth::audio::sco::cleanup(); // UIPC is nullptr and shouldn't require an actual call of UIPC_Close; ASSERT_EQ(mock_function_count_map["UIPC_Close"], 0); } TEST_F(ScoHciWithOpenCleanTest, ScoOverHciOpenClean) { ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 1); ASSERT_EQ(mock_uipc_init_ret, nullptr); mock_uipc_init_ret = std::make_unique<tUIPC_STATE>(); // Double open will override uipc bluetooth::audio::sco::open(); ASSERT_EQ(mock_function_count_map["UIPC_Init"], 2); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 2); ASSERT_EQ(mock_uipc_init_ret, nullptr); bluetooth::audio::sco::cleanup(); ASSERT_EQ(mock_function_count_map["UIPC_Close"], 1); // Double clean shouldn't fail bluetooth::audio::sco::cleanup(); ASSERT_EQ(mock_function_count_map["UIPC_Close"], 1); } TEST_F(ScoHciTest, ScoOverHciReadNoOpen) { uint8_t buf[100]; ASSERT_EQ(bluetooth::audio::sco::read(buf, sizeof(buf)), size_t(0)); ASSERT_EQ(mock_function_count_map["UIPC_Read"], 0); } TEST_F(ScoHciWithOpenCleanTest, ScoOverHciRead) { uint8_t buf[100]; // The UPIC should be ready ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 1); ASSERT_EQ(mock_uipc_init_ret, nullptr); mock_uipc_read_ret = sizeof(buf); ASSERT_EQ(bluetooth::audio::sco::read(buf, sizeof(buf)), mock_uipc_read_ret); ASSERT_EQ(mock_function_count_map["UIPC_Read"], 1); } TEST_F(ScoHciTest, ScoOverHciWriteNoOpen) { uint8_t buf[100]; bluetooth::audio::sco::write(buf, sizeof(buf)); ASSERT_EQ(mock_function_count_map["UIPC_Send"], 0); } TEST_F(ScoHciWithOpenCleanTest, ScoOverHciWrite) { uint8_t buf[100]; // The UPIC should be ready ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 1); ASSERT_EQ(mock_uipc_init_ret, nullptr); ASSERT_EQ(bluetooth::audio::sco::write(buf, sizeof(buf)), sizeof(buf)); ASSERT_EQ(mock_function_count_map["UIPC_Send"], 1); // Send fails mock_uipc_send_ret = false; ASSERT_EQ(bluetooth::audio::sco::write(buf, sizeof(buf)), size_t(0)); ASSERT_EQ(mock_function_count_map["UIPC_Send"], 2); } TEST(ScoHciWbsTest, WbsInit) { ASSERT_EQ(bluetooth::audio::sco::wbs::init(60), size_t(60)); ASSERT_EQ(bluetooth::audio::sco::wbs::init(72), size_t(72)); // Fallback to 60 if the packet size is not supported ASSERT_EQ(bluetooth::audio::sco::wbs::init(48), size_t(60)); bluetooth::audio::sco::wbs::cleanup(); } TEST(ScoHciWbsTest, WbsEnqueuePacketWithoutInit) { uint8_t payload[60]; // Return 0 if buffer is uninitialized ASSERT_EQ( bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload)), size_t(0)); } 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)), size_t(0)); // Return 0 if packet size is consistent ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, 72), size_t(0)); ASSERT_EQ( bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload)), size_t(60)); // Return 0 if buffer is full ASSERT_EQ( bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload)), size_t(0)); } TEST(ScoHciWbsTest, WbsDecodeWithoutInit) { const uint8_t* decoded = nullptr; // Return 0 if buffer is uninitialized ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); } TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) { const uint8_t* decoded = nullptr; uint8_t payload[60] = {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)), sizeof(payload)); // Return all zero frames when there comes an invalid packet. 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); } decoded = nullptr; ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet, sizeof(payload)), sizeof(msbc_zero_packet)); 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); } decoded = nullptr; // No remaining data to decode ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); } TEST(ScoHciWbsTest, WbsEncodeWithoutInit) { int16_t data[120] = {0}; // Return 0 if buffer is uninitialized ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0)); } TEST_F(ScoHciWbsWithInitCleanTest, WbsEncode) { int16_t data[120] = {0}; // Return 0 if data is invalid ASSERT_EQ(bluetooth::audio::sco::wbs::encode(nullptr, sizeof(data)), size_t(0)); // Return 0 if data length is insufficient ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data) - 1), size_t(0)); ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data)); // Return 0 if the packet buffer is full ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0)); } TEST(ScoHciWbsTest, WbsDequeuePacketWithoutInit) { const uint8_t* encoded = nullptr; // Return 0 if buffer is uninitialized ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0)); ASSERT_EQ(encoded, nullptr); } TEST_F(ScoHciWbsWithInitCleanTest, WbsDequeuePacket) { const uint8_t* encoded = nullptr; // Return 0 if output pointer is invalid ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(nullptr), size_t(0)); ASSERT_EQ(encoded, nullptr); // Return 0 if there is insufficient data to dequeue ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0)); ASSERT_EQ(encoded, nullptr); } TEST_F(ScoHciWbsWithInitCleanTest, WbsEncodeDequeuePackets) { uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; int16_t data[120] = {0}; const uint8_t* encoded = nullptr; for (size_t i = 0; i < 5; i++) { ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data)); ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60)); ASSERT_NE(encoded, nullptr); for (size_t j = 0; j < 60; j++) { ASSERT_EQ(encoded[j], j == 1 ? h2_header_frames_count[i % 4] : msbc_zero_packet[j]); } } } } // namespace system/test/mock/mock_udrv_ulinux_uipc.cc +7 −3 Original line number Diff line number Diff line Loading @@ -31,6 +31,10 @@ extern std::map<std::string, int> mock_function_count_map; #define UNUSED_ATTR #endif std::unique_ptr<tUIPC_STATE> mock_uipc_init_ret; uint32_t mock_uipc_read_ret; bool mock_uipc_send_ret; bool UIPC_Open(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback, const char* socket_path) { mock_function_count_map[__func__]++; Loading @@ -40,7 +44,7 @@ bool UIPC_Send(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t msg_evt, const uint8_t* p_buf, uint16_t msglen) { mock_function_count_map[__func__]++; return false; return mock_uipc_send_ret; } int uipc_start_main_server_thread(tUIPC_STATE& uipc) { mock_function_count_map[__func__]++; Loading @@ -48,7 +52,7 @@ int uipc_start_main_server_thread(tUIPC_STATE& uipc) { } std::unique_ptr<tUIPC_STATE> UIPC_Init() { mock_function_count_map[__func__]++; return nullptr; return std::move(mock_uipc_init_ret); } const char* dump_uipc_event(tUIPC_EVENT event) { mock_function_count_map[__func__]++; Loading @@ -57,7 +61,7 @@ const char* dump_uipc_event(tUIPC_EVENT event) { uint32_t UIPC_Read(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint8_t* p_buf, uint32_t len) { mock_function_count_map[__func__]++; return 0; return mock_uipc_read_ret; } bool UIPC_Ioctl(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint32_t request, void* param) { Loading Loading
system/stack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -840,6 +840,7 @@ cc_test { ":TestMockStackHcic", ":TestMockStackL2cap", ":TestMockStackSmp", ":TestMockUdrv", "acl/acl.cc", "acl/ble_acl.cc", "acl/btm_acl.cc", Loading Loading @@ -871,6 +872,7 @@ cc_test { "btm/hfp_msbc_encoder.cc", "btm/hfp_msbc_decoder.cc", "metrics/stack_metrics_logging.cc", "test/btm/sco_hci_test.cc", "test/btm/stack_btm_test.cc", "test/btm/peer_packet_types_test.cc", "test/common/mock_eatt.cc", Loading
system/stack/btm/btm_sco.h +6 −3 Original line number Diff line number Diff line Loading @@ -54,9 +54,12 @@ namespace bluetooth::audio::sco::wbs { * pkt_size - Length of the SCO packet. It is determined based on the BT-USB * adapter's capability and alt mode setting. The value should be queried * from HAL interface. It will be used to determine the size of the SCO * packet buffer. * packet buffer. Currently, the stack only supports 60 and 72. * Returns: * The selected packet size. Will fallback to the typical mSBC packet * length(60) if the pkt_size argument is not supported. */ void init(size_t pkt_size); size_t init(size_t pkt_size); /* Clean up when the SCO connection is done */ void cleanup(); Loading @@ -65,7 +68,7 @@ void cleanup(); * 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 trigger a reset of the buffer. * from the pkt_size set in init() will fail the call. * Returns: * The length of enqueued bytes. 0 if failed. */ Loading
system/stack/btm/btm_sco_hci.cc +31 −4 Original line number Diff line number Diff line Loading @@ -71,7 +71,13 @@ void open() { if (sco_uipc != nullptr) { LOG_WARN("Re-opening UIPC that is already running"); } sco_uipc = UIPC_Init(); if (sco_uipc == nullptr) { LOG_ERROR("%s failed to init UIPC", __func__); return; } UIPC_Open(*sco_uipc, UIPC_CH_ID_AV_AUDIO, sco_data_cb, SCO_HOST_DATA_PATH); struct group* grp = getgrnam(SCO_HOST_DATA_GROUP); chmod(SCO_HOST_DATA_PATH, 0770); Loading Loading @@ -180,7 +186,7 @@ struct tBTM_MSBC_INFO { } public: void init(size_t pkt_size) { size_t init(size_t pkt_size) { decode_buf_wo = 0; decode_buf_ro = 0; encode_buf_wo = 0; Loading @@ -188,7 +194,7 @@ struct tBTM_MSBC_INFO { pkt_size = get_supported_packet_size(pkt_size, &buf_size); if (pkt_size != BTM_MSBC_PKT_LEN) check_alignment = true; if (pkt_size == packet_size) return; if (pkt_size == packet_size) return packet_size; packet_size = pkt_size; if (msbc_decode_buf) osi_free(msbc_decode_buf); Loading @@ -196,6 +202,7 @@ struct tBTM_MSBC_INFO { if (msbc_encode_buf) osi_free(msbc_encode_buf); msbc_encode_buf = (uint8_t*)osi_calloc(buf_size); return packet_size; } void deinit() { Loading Loading @@ -292,7 +299,7 @@ struct tBTM_MSBC_INFO { static tBTM_MSBC_INFO* msbc_info = nullptr; void init(size_t pkt_size) { size_t init(size_t pkt_size) { hfp_msbc_decoder_init(); hfp_msbc_encoder_init(); Loading @@ -303,7 +310,7 @@ void init(size_t pkt_size) { } msbc_info = (tBTM_MSBC_INFO*)osi_calloc(sizeof(*msbc_info)); msbc_info->init(pkt_size); return msbc_info->init(pkt_size); } void cleanup() { Loading Loading @@ -331,6 +338,11 @@ size_t enqueue_packet(const uint8_t* data, size_t pkt_size) { return 0; } if (data == nullptr) { LOG_WARN("Invalid data to enqueue"); return 0; } if (msbc_info->check_alignment) { if (data[0] != BTM_MSBC_H2_HEADER_0 || data[2] != BTM_MSBC_SYNC_WORD) { LOG_DEBUG("Waiting for valid mSBC frame head"); Loading @@ -356,6 +368,11 @@ size_t decode(const uint8_t** out_data) { return 0; } if (out_data == nullptr) { LOG_WARN("%s Invalid output pointer", __func__); return 0; } if (msbc_info->decodable() < BTM_MSBC_PKT_LEN) { LOG_DEBUG("No complete mSBC packet to decode"); return 0; Loading Loading @@ -395,6 +412,11 @@ size_t encode(int16_t* data, size_t len) { return 0; } if (data == nullptr) { LOG_WARN("Invalid data to encode"); return 0; } if (len < BTM_MSBC_CODE_SIZE) { LOG_DEBUG( "PCM frames with size %lu is insufficient to be encoded into a mSBC " Loading Loading @@ -425,6 +447,11 @@ size_t dequeue_packet(const uint8_t** output) { return 0; } if (output == nullptr) { LOG_WARN("%s Invalid output pointer", __func__); return 0; } *output = msbc_info->sco_pkt_read_ptr(); if (*output == nullptr) { LOG_DEBUG("Insufficient data to dequeue."); Loading
system/stack/test/btm/sco_hci_test.cc 0 → 100644 +279 −0 Original line number Diff line number Diff line /* * * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <algorithm> #include <map> #include <memory> #include "stack/btm/btm_sco.h" #include "udrv/include/uipc.h" extern std::map<std::string, int> mock_function_count_map; extern std::unique_ptr<tUIPC_STATE> mock_uipc_init_ret; extern uint32_t mock_uipc_read_ret; extern bool mock_uipc_send_ret; namespace { using testing::Test; const 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, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00}; class ScoHciTest : public Test { public: protected: void SetUp() override { mock_function_count_map.clear(); mock_uipc_init_ret = nullptr; mock_uipc_read_ret = 0; mock_uipc_send_ret = true; } void TearDown() override {} }; class ScoHciWithOpenCleanTest : public ScoHciTest { public: protected: void SetUp() override { ScoHciTest::SetUp(); mock_uipc_init_ret = std::make_unique<tUIPC_STATE>(); bluetooth::audio::sco::open(); } void TearDown() override { bluetooth::audio::sco::cleanup(); } }; class ScoHciWbsWithInitCleanTest : public Test { public: protected: void SetUp() override { bluetooth::audio::sco::wbs::init(60); } void TearDown() override { bluetooth::audio::sco::wbs::cleanup(); } }; TEST_F(ScoHciTest, ScoOverHciOpenFail) { bluetooth::audio::sco::open(); ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 0); bluetooth::audio::sco::cleanup(); // UIPC is nullptr and shouldn't require an actual call of UIPC_Close; ASSERT_EQ(mock_function_count_map["UIPC_Close"], 0); } TEST_F(ScoHciWithOpenCleanTest, ScoOverHciOpenClean) { ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 1); ASSERT_EQ(mock_uipc_init_ret, nullptr); mock_uipc_init_ret = std::make_unique<tUIPC_STATE>(); // Double open will override uipc bluetooth::audio::sco::open(); ASSERT_EQ(mock_function_count_map["UIPC_Init"], 2); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 2); ASSERT_EQ(mock_uipc_init_ret, nullptr); bluetooth::audio::sco::cleanup(); ASSERT_EQ(mock_function_count_map["UIPC_Close"], 1); // Double clean shouldn't fail bluetooth::audio::sco::cleanup(); ASSERT_EQ(mock_function_count_map["UIPC_Close"], 1); } TEST_F(ScoHciTest, ScoOverHciReadNoOpen) { uint8_t buf[100]; ASSERT_EQ(bluetooth::audio::sco::read(buf, sizeof(buf)), size_t(0)); ASSERT_EQ(mock_function_count_map["UIPC_Read"], 0); } TEST_F(ScoHciWithOpenCleanTest, ScoOverHciRead) { uint8_t buf[100]; // The UPIC should be ready ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 1); ASSERT_EQ(mock_uipc_init_ret, nullptr); mock_uipc_read_ret = sizeof(buf); ASSERT_EQ(bluetooth::audio::sco::read(buf, sizeof(buf)), mock_uipc_read_ret); ASSERT_EQ(mock_function_count_map["UIPC_Read"], 1); } TEST_F(ScoHciTest, ScoOverHciWriteNoOpen) { uint8_t buf[100]; bluetooth::audio::sco::write(buf, sizeof(buf)); ASSERT_EQ(mock_function_count_map["UIPC_Send"], 0); } TEST_F(ScoHciWithOpenCleanTest, ScoOverHciWrite) { uint8_t buf[100]; // The UPIC should be ready ASSERT_EQ(mock_function_count_map["UIPC_Init"], 1); ASSERT_EQ(mock_function_count_map["UIPC_Open"], 1); ASSERT_EQ(mock_uipc_init_ret, nullptr); ASSERT_EQ(bluetooth::audio::sco::write(buf, sizeof(buf)), sizeof(buf)); ASSERT_EQ(mock_function_count_map["UIPC_Send"], 1); // Send fails mock_uipc_send_ret = false; ASSERT_EQ(bluetooth::audio::sco::write(buf, sizeof(buf)), size_t(0)); ASSERT_EQ(mock_function_count_map["UIPC_Send"], 2); } TEST(ScoHciWbsTest, WbsInit) { ASSERT_EQ(bluetooth::audio::sco::wbs::init(60), size_t(60)); ASSERT_EQ(bluetooth::audio::sco::wbs::init(72), size_t(72)); // Fallback to 60 if the packet size is not supported ASSERT_EQ(bluetooth::audio::sco::wbs::init(48), size_t(60)); bluetooth::audio::sco::wbs::cleanup(); } TEST(ScoHciWbsTest, WbsEnqueuePacketWithoutInit) { uint8_t payload[60]; // Return 0 if buffer is uninitialized ASSERT_EQ( bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload)), size_t(0)); } 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)), size_t(0)); // Return 0 if packet size is consistent ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, 72), size_t(0)); ASSERT_EQ( bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload)), size_t(60)); // Return 0 if buffer is full ASSERT_EQ( bluetooth::audio::sco::wbs::enqueue_packet(payload, sizeof(payload)), size_t(0)); } TEST(ScoHciWbsTest, WbsDecodeWithoutInit) { const uint8_t* decoded = nullptr; // Return 0 if buffer is uninitialized ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); } TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) { const uint8_t* decoded = nullptr; uint8_t payload[60] = {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)), sizeof(payload)); // Return all zero frames when there comes an invalid packet. 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); } decoded = nullptr; ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet, sizeof(payload)), sizeof(msbc_zero_packet)); 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); } decoded = nullptr; // No remaining data to decode ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0)); ASSERT_EQ(decoded, nullptr); } TEST(ScoHciWbsTest, WbsEncodeWithoutInit) { int16_t data[120] = {0}; // Return 0 if buffer is uninitialized ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0)); } TEST_F(ScoHciWbsWithInitCleanTest, WbsEncode) { int16_t data[120] = {0}; // Return 0 if data is invalid ASSERT_EQ(bluetooth::audio::sco::wbs::encode(nullptr, sizeof(data)), size_t(0)); // Return 0 if data length is insufficient ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data) - 1), size_t(0)); ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data)); // Return 0 if the packet buffer is full ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0)); } TEST(ScoHciWbsTest, WbsDequeuePacketWithoutInit) { const uint8_t* encoded = nullptr; // Return 0 if buffer is uninitialized ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0)); ASSERT_EQ(encoded, nullptr); } TEST_F(ScoHciWbsWithInitCleanTest, WbsDequeuePacket) { const uint8_t* encoded = nullptr; // Return 0 if output pointer is invalid ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(nullptr), size_t(0)); ASSERT_EQ(encoded, nullptr); // Return 0 if there is insufficient data to dequeue ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0)); ASSERT_EQ(encoded, nullptr); } TEST_F(ScoHciWbsWithInitCleanTest, WbsEncodeDequeuePackets) { uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8}; int16_t data[120] = {0}; const uint8_t* encoded = nullptr; for (size_t i = 0; i < 5; i++) { ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data)); ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60)); ASSERT_NE(encoded, nullptr); for (size_t j = 0; j < 60; j++) { ASSERT_EQ(encoded[j], j == 1 ? h2_header_frames_count[i % 4] : msbc_zero_packet[j]); } } } } // namespace
system/test/mock/mock_udrv_ulinux_uipc.cc +7 −3 Original line number Diff line number Diff line Loading @@ -31,6 +31,10 @@ extern std::map<std::string, int> mock_function_count_map; #define UNUSED_ATTR #endif std::unique_ptr<tUIPC_STATE> mock_uipc_init_ret; uint32_t mock_uipc_read_ret; bool mock_uipc_send_ret; bool UIPC_Open(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback, const char* socket_path) { mock_function_count_map[__func__]++; Loading @@ -40,7 +44,7 @@ bool UIPC_Send(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t msg_evt, const uint8_t* p_buf, uint16_t msglen) { mock_function_count_map[__func__]++; return false; return mock_uipc_send_ret; } int uipc_start_main_server_thread(tUIPC_STATE& uipc) { mock_function_count_map[__func__]++; Loading @@ -48,7 +52,7 @@ int uipc_start_main_server_thread(tUIPC_STATE& uipc) { } std::unique_ptr<tUIPC_STATE> UIPC_Init() { mock_function_count_map[__func__]++; return nullptr; return std::move(mock_uipc_init_ret); } const char* dump_uipc_event(tUIPC_EVENT event) { mock_function_count_map[__func__]++; Loading @@ -57,7 +61,7 @@ const char* dump_uipc_event(tUIPC_EVENT event) { uint32_t UIPC_Read(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint8_t* p_buf, uint32_t len) { mock_function_count_map[__func__]++; return 0; return mock_uipc_read_ret; } bool UIPC_Ioctl(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint32_t request, void* param) { Loading