1 /*
2  *
3  *  Copyright 2022 The Android Open Source Project
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  */
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
22 #include <algorithm>
23 #include <map>
24 #include <memory>
25 
26 #include "btif/include/core_callbacks.h"
27 #include "btif/include/stack_manager_t.h"
28 #include "stack/btm/btm_sco.h"
29 #include "stack/include/hfp_lc3_decoder.h"
30 #include "stack/include/hfp_lc3_encoder.h"
31 #include "stack/include/hfp_msbc_decoder.h"
32 #include "stack/include/hfp_msbc_encoder.h"
33 #include "stack/test/btm/btm_test_fixtures.h"
34 #include "test/common/mock_functions.h"
35 #include "udrv/include/uipc.h"
36 
37 extern bluetooth::core::CoreInterface* GetInterfaceToProfiles();
38 extern std::unique_ptr<tUIPC_STATE> mock_uipc_init_ret;
39 extern uint32_t mock_uipc_read_ret;
40 extern bool mock_uipc_send_ret;
41 
42 namespace {
43 
44 using testing::AllOf;
45 using testing::Ge;
46 using testing::Le;
47 using testing::Test;
48 
49 const std::vector<uint8_t> msbc_zero_packet{
50     0x01, 0x08, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
51     0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77,
52     0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb,
53     0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6,
54     0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00};
55 
56 const std::vector<uint8_t> lc3_zero_packet{
57     0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61     0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0xf9, 0x4a, 0x0d, 0x00, 0x00, 0x03};
62 
63 // Maps irregular packet size to expected decode buffer size.
64 // See |btm_wbs_supported_pkt_size| and |btm_wbs_msbc_buffer_size|.
65 const std::map<size_t, size_t> irregular_packet_to_buffer_size{
66     {72, 360},
67     {24, 120},
68 };
69 
70 // The encoded packet size is 60 regardless of the codec.
71 const int ENCODED_PACKET_SIZE = 60;
72 
73 struct MsbcCodecInterface : bluetooth::core::CodecInterface {
MsbcCodecInterface__anon603819bf0111::MsbcCodecInterface74   MsbcCodecInterface() : bluetooth::core::CodecInterface(){};
75 
initialize__anon603819bf0111::MsbcCodecInterface76   void initialize() override {
77     hfp_msbc_decoder_init();
78     hfp_msbc_encoder_init();
79   }
80 
cleanup__anon603819bf0111::MsbcCodecInterface81   void cleanup() override {
82     hfp_msbc_decoder_cleanup();
83     hfp_msbc_encoder_cleanup();
84   }
85 
encodePacket__anon603819bf0111::MsbcCodecInterface86   uint32_t encodePacket(int16_t* input, uint8_t* output) {
87     return hfp_msbc_encode_frames(input, output);
88   }
89 
decodePacket__anon603819bf0111::MsbcCodecInterface90   bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) {
91     return hfp_msbc_decoder_decode_packet(i_buf, o_buf, out_len);
92   }
93 };
94 
95 struct Lc3CodecInterface : bluetooth::core::CodecInterface {
Lc3CodecInterface__anon603819bf0111::Lc3CodecInterface96   Lc3CodecInterface() : bluetooth::core::CodecInterface(){};
97 
initialize__anon603819bf0111::Lc3CodecInterface98   void initialize() override {
99     hfp_lc3_decoder_init();
100     hfp_lc3_encoder_init();
101   }
102 
cleanup__anon603819bf0111::Lc3CodecInterface103   void cleanup() override {
104     hfp_lc3_decoder_cleanup();
105     hfp_lc3_encoder_cleanup();
106   }
107 
encodePacket__anon603819bf0111::Lc3CodecInterface108   uint32_t encodePacket(int16_t* input, uint8_t* output) {
109     return hfp_lc3_encode_frames(input, output);
110   }
111 
decodePacket__anon603819bf0111::Lc3CodecInterface112   bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) {
113     return hfp_lc3_decoder_decode_packet(i_buf, o_buf, out_len);
114   }
115 };
116 
117 class ScoHciTest : public BtmWithMocksTest {
118  public:
119  protected:
SetUp()120   void SetUp() override {
121     BtmWithMocksTest::SetUp();
122     mock_uipc_init_ret = nullptr;
123     mock_uipc_read_ret = 0;
124     mock_uipc_send_ret = true;
125 
126     static auto msbc_codec = MsbcCodecInterface{};
127     static auto lc3_codec = Lc3CodecInterface{};
128     GetInterfaceToProfiles()->msbcCodec = &msbc_codec;
129     GetInterfaceToProfiles()->lc3Codec = &lc3_codec;
130   }
TearDown()131   void TearDown() override { BtmWithMocksTest::TearDown(); }
132 };
133 
134 class ScoHciWithOpenCleanTest : public ScoHciTest {
135  public:
136  protected:
SetUp()137   void SetUp() override {
138     ScoHciTest::SetUp();
139     mock_uipc_init_ret = std::make_unique<tUIPC_STATE>();
140     bluetooth::audio::sco::open();
141   }
TearDown()142   void TearDown() override { bluetooth::audio::sco::cleanup(); }
143 };
144 
145 class ScoHciWbsTest : public ScoHciTest {};
146 class ScoHciSwbTest : public ScoHciTest {};
147 
148 class ScoHciWbsWithInitCleanTest : public ScoHciTest {
149  public:
150  protected:
SetUp()151   void SetUp() override {
152     ScoHciTest::SetUp();
153     bluetooth::audio::sco::wbs::init(60);
154   }
TearDown()155   void TearDown() override { bluetooth::audio::sco::wbs::cleanup(); }
156 };
157 
158 class ScoHciSwbWithInitCleanTest : public ScoHciTest {
159  public:
160  protected:
SetUp()161   void SetUp() override {
162     ScoHciTest::SetUp();
163     bluetooth::audio::sco::swb::init(60);
164   }
TearDown()165   void TearDown() override { bluetooth::audio::sco::swb::cleanup(); }
166 };
167 
TEST_F(ScoHciTest,ScoOverHciOpenFail)168 TEST_F(ScoHciTest, ScoOverHciOpenFail) {
169   bluetooth::audio::sco::open();
170   ASSERT_EQ(get_func_call_count("UIPC_Init"), 1);
171   ASSERT_EQ(get_func_call_count("UIPC_Open"), 0);
172   bluetooth::audio::sco::cleanup();
173 
174   // UIPC is nullptr and shouldn't require an actual call of UIPC_Close;
175   ASSERT_EQ(get_func_call_count("UIPC_Close"), 0);
176 }
177 
TEST_F(ScoHciWithOpenCleanTest,ScoOverHciOpenClean)178 TEST_F(ScoHciWithOpenCleanTest, ScoOverHciOpenClean) {
179   ASSERT_EQ(get_func_call_count("UIPC_Init"), 1);
180   ASSERT_EQ(get_func_call_count("UIPC_Open"), 1);
181   ASSERT_EQ(mock_uipc_init_ret, nullptr);
182 
183   mock_uipc_init_ret = std::make_unique<tUIPC_STATE>();
184   // Double open will override uipc
185   bluetooth::audio::sco::open();
186   ASSERT_EQ(get_func_call_count("UIPC_Init"), 2);
187   ASSERT_EQ(get_func_call_count("UIPC_Open"), 2);
188   ASSERT_EQ(mock_uipc_init_ret, nullptr);
189 
190   bluetooth::audio::sco::cleanup();
191   ASSERT_EQ(get_func_call_count("UIPC_Close"), 1);
192 
193   // Double clean shouldn't fail
194   bluetooth::audio::sco::cleanup();
195   ASSERT_EQ(get_func_call_count("UIPC_Close"), 1);
196 }
197 
TEST_F(ScoHciTest,ScoOverHciReadNoOpen)198 TEST_F(ScoHciTest, ScoOverHciReadNoOpen) {
199   uint8_t buf[100];
200   ASSERT_EQ(bluetooth::audio::sco::read(buf, sizeof(buf)), size_t(0));
201   ASSERT_EQ(get_func_call_count("UIPC_Read"), 0);
202 }
203 
TEST_F(ScoHciWithOpenCleanTest,ScoOverHciRead)204 TEST_F(ScoHciWithOpenCleanTest, ScoOverHciRead) {
205   uint8_t buf[100];
206   // The UPIC should be ready
207   ASSERT_EQ(get_func_call_count("UIPC_Init"), 1);
208   ASSERT_EQ(get_func_call_count("UIPC_Open"), 1);
209   ASSERT_EQ(mock_uipc_init_ret, nullptr);
210 
211   mock_uipc_read_ret = sizeof(buf);
212   ASSERT_EQ(bluetooth::audio::sco::read(buf, sizeof(buf)), mock_uipc_read_ret);
213   ASSERT_EQ(get_func_call_count("UIPC_Read"), 1);
214 }
215 
TEST_F(ScoHciTest,ScoOverHciWriteNoOpen)216 TEST_F(ScoHciTest, ScoOverHciWriteNoOpen) {
217   uint8_t buf[100];
218   bluetooth::audio::sco::write(buf, sizeof(buf));
219   ASSERT_EQ(get_func_call_count("UIPC_Send"), 0);
220 }
221 
TEST_F(ScoHciWithOpenCleanTest,ScoOverHciWrite)222 TEST_F(ScoHciWithOpenCleanTest, ScoOverHciWrite) {
223   uint8_t buf[100];
224   // The UPIC should be ready
225   ASSERT_EQ(get_func_call_count("UIPC_Init"), 1);
226   ASSERT_EQ(get_func_call_count("UIPC_Open"), 1);
227   ASSERT_EQ(mock_uipc_init_ret, nullptr);
228 
229   ASSERT_EQ(bluetooth::audio::sco::write(buf, sizeof(buf)), sizeof(buf));
230   ASSERT_EQ(get_func_call_count("UIPC_Send"), 1);
231 
232   // Send fails
233   mock_uipc_send_ret = false;
234   ASSERT_EQ(bluetooth::audio::sco::write(buf, sizeof(buf)), size_t(0));
235   ASSERT_EQ(get_func_call_count("UIPC_Send"), 2);
236 }
237 
TEST_F(ScoHciWbsTest,WbsInit)238 TEST_F(ScoHciWbsTest, WbsInit) {
239   ASSERT_EQ(bluetooth::audio::sco::wbs::init(60), size_t(60));
240   ASSERT_EQ(bluetooth::audio::sco::wbs::init(72), size_t(72));
241   // Fallback to 60 if the packet size is not supported
242   ASSERT_EQ(bluetooth::audio::sco::wbs::init(48), size_t(60));
243   bluetooth::audio::sco::wbs::cleanup();
244 }
245 
TEST_F(ScoHciSwbTest,SwbInit)246 TEST_F(ScoHciSwbTest, SwbInit) {
247   ASSERT_EQ(bluetooth::audio::sco::swb::init(60), size_t(60));
248   ASSERT_EQ(bluetooth::audio::sco::swb::init(72), size_t(72));
249   // Fallback to 60 if the packet size is not supported
250   ASSERT_EQ(bluetooth::audio::sco::swb::init(48), size_t(60));
251   bluetooth::audio::sco::swb::cleanup();
252 }
253 
TEST_F(ScoHciWbsTest,WbsEnqueuePacketWithoutInit)254 TEST_F(ScoHciWbsTest, WbsEnqueuePacketWithoutInit) {
255   std::vector<uint8_t> payload{60, 0};
256   // Return 0 if buffer is uninitialized
257   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false);
258 }
259 
TEST_F(ScoHciSwbTest,SwbEnqueuePacketWithoutInit)260 TEST_F(ScoHciSwbTest, SwbEnqueuePacketWithoutInit) {
261   std::vector<uint8_t> payload{60, 0};
262   // Return 0 if buffer is uninitialized
263   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), false);
264 }
265 
TEST_F(ScoHciWbsWithInitCleanTest,WbsEnqueuePacket)266 TEST_F(ScoHciWbsWithInitCleanTest, WbsEnqueuePacket) {
267   std::vector<uint8_t> payload;
268   for (size_t i = 0; i < 60; i++) payload.push_back(0);
269   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true);
270   // Return 0 if buffer is full
271   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false);
272 }
273 
TEST_F(ScoHciSwbWithInitCleanTest,SwbEnqueuePacket)274 TEST_F(ScoHciSwbWithInitCleanTest, SwbEnqueuePacket) {
275   std::vector<uint8_t> payload;
276   for (size_t i = 0; i < 60; i++) payload.push_back(0);
277   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true);
278   // Return 0 if buffer is full
279   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), false);
280 }
281 
TEST_F(ScoHciWbsTest,WbsDecodeWithoutInit)282 TEST_F(ScoHciWbsTest, WbsDecodeWithoutInit) {
283   const uint8_t* decoded = nullptr;
284   // Return 0 if buffer is uninitialized
285   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
286   ASSERT_EQ(decoded, nullptr);
287 }
288 
TEST_F(ScoHciSwbTest,SwbDecodeWithoutInit)289 TEST_F(ScoHciSwbTest, SwbDecodeWithoutInit) {
290   const uint8_t* decoded = nullptr;
291   // Return 0 if buffer is uninitialized
292   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
293   ASSERT_EQ(decoded, nullptr);
294 }
295 
TEST_F(ScoHciWbsWithInitCleanTest,WbsDecode)296 TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) {
297   const uint8_t* decoded = nullptr;
298   std::vector<uint8_t> payload;
299   for (size_t i = 0; i < 60; i++) payload.push_back(0);
300 
301   // No data to decode
302   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
303   ASSERT_EQ(decoded, nullptr);
304   // Fill in invalid packet, all zeros.
305   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true);
306 
307   // Return all zero frames when there comes an invalid packet.
308   // This is expected even with PLC as there is no history in the PLC buffer.
309   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
310             size_t(BTM_MSBC_CODE_SIZE));
311   ASSERT_NE(decoded, nullptr);
312   for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) {
313     ASSERT_EQ(decoded[i], 0);
314   }
315 
316   decoded = nullptr;
317   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet, false),
318             true);
319   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
320             size_t(BTM_MSBC_CODE_SIZE));
321   ASSERT_NE(decoded, nullptr);
322   for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) {
323     ASSERT_EQ(decoded[i], 0);
324   }
325 
326   decoded = nullptr;
327   // No remaining data to decode
328   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
329   ASSERT_EQ(decoded, nullptr);
330 }
331 
TEST_F(ScoHciSwbWithInitCleanTest,SwbDecode)332 TEST_F(ScoHciSwbWithInitCleanTest, SwbDecode) {
333   const uint8_t* decoded = nullptr;
334   std::vector<uint8_t> payload;
335   for (size_t i = 0; i < 60; i++) payload.push_back(0);
336 
337   // No data to decode
338   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
339   ASSERT_EQ(decoded, nullptr);
340   // Fill in invalid packet, all zeros.
341   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true);
342 
343   // Return all zero frames when there comes an invalid packet.
344   // This is expected even with PLC as there is no history in the PLC buffer.
345   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded),
346             size_t(BTM_LC3_CODE_SIZE));
347   ASSERT_NE(decoded, nullptr);
348   for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) {
349     ASSERT_EQ(decoded[i], 0);
350   }
351 
352   decoded = nullptr;
353   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(lc3_zero_packet, false),
354             true);
355   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded),
356             size_t(BTM_LC3_CODE_SIZE));
357   ASSERT_NE(decoded, nullptr);
358   for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) {
359     ASSERT_EQ(decoded[i], 0);
360   }
361 
362   decoded = nullptr;
363   // No remaining data to decode
364   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
365   ASSERT_EQ(decoded, nullptr);
366 }
367 
TEST_F(ScoHciWbsTest,WbsDecodeWithIrregularOffset)368 TEST_F(ScoHciWbsTest, WbsDecodeWithIrregularOffset) {
369   for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) {
370     ASSERT_EQ(buf_size % pkt_size, 0u);
371 
372     bluetooth::audio::sco::wbs::init(pkt_size);
373 
374     const uint8_t* decoded = nullptr;
375 
376     // No data to decode
377     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
378     ASSERT_EQ(decoded, nullptr);
379 
380     // Start the payload with an irregular offset that misaligns with the
381     // packet size.
382     std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0);
383     while (payload.size() <= pkt_size) {
384       payload.insert(payload.end(), msbc_zero_packet.begin(),
385                      msbc_zero_packet.end());
386     }
387     size_t packet_offset =
388         msbc_zero_packet.size() - (payload.size() - pkt_size);
389     payload.resize(pkt_size);
390 
391     // Try to decode as many packets as to hit the boundary.
392     for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size;
393          ++iter) {
394       ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false),
395                 true);
396       decodable += payload.size() - !iter;  // compensate for the first offset
397 
398       while (decodable >= ENCODED_PACKET_SIZE) {
399         decoded = nullptr;
400         ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
401                   size_t(BTM_MSBC_CODE_SIZE));
402         ASSERT_NE(decoded, nullptr);
403         for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) {
404           ASSERT_EQ(decoded[i], 0);
405         }
406         decodable -= ENCODED_PACKET_SIZE;
407       }
408 
409       payload = std::vector<uint8_t>(msbc_zero_packet.begin() + packet_offset,
410                                      msbc_zero_packet.end());
411       while (payload.size() < pkt_size) {
412         payload.insert(payload.end(), msbc_zero_packet.begin(),
413                        msbc_zero_packet.end());
414       }
415       packet_offset += msbc_zero_packet.size() - packet_offset;
416       packet_offset += msbc_zero_packet.size() -
417                        (payload.size() - pkt_size) % msbc_zero_packet.size();
418       packet_offset %= msbc_zero_packet.size();
419       payload.resize(pkt_size);
420     }
421 
422     bluetooth::audio::sco::wbs::cleanup();
423   }
424 }
425 
TEST_F(ScoHciSwbTest,SwbDecodeWithIrregularOffset)426 TEST_F(ScoHciSwbTest, SwbDecodeWithIrregularOffset) {
427   for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) {
428     ASSERT_EQ(buf_size % pkt_size, 0u);
429 
430     bluetooth::audio::sco::swb::init(pkt_size);
431 
432     const uint8_t* decoded = nullptr;
433 
434     // No data to decode
435     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
436     ASSERT_EQ(decoded, nullptr);
437 
438     // Start the payload with an irregular offset that misaligns with the
439     // packet size.
440     std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0);
441     while (payload.size() <= pkt_size) {
442       payload.insert(payload.end(), lc3_zero_packet.begin(),
443                      lc3_zero_packet.end());
444     }
445     size_t packet_offset = lc3_zero_packet.size() - (payload.size() - pkt_size);
446     payload.resize(pkt_size);
447 
448     // Try to decode as many packets as to hit the boundary.
449     for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size;
450          ++iter) {
451       ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false),
452                 true);
453       decodable += payload.size() - !iter;  // compensate for the first offset
454 
455       while (decodable >= ENCODED_PACKET_SIZE) {
456         decoded = nullptr;
457         ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded),
458                   size_t(BTM_LC3_CODE_SIZE));
459         ASSERT_NE(decoded, nullptr);
460         for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) {
461           ASSERT_EQ(decoded[i], 0);
462         }
463         decodable -= ENCODED_PACKET_SIZE;
464       }
465 
466       payload = std::vector<uint8_t>(lc3_zero_packet.begin() + packet_offset,
467                                      lc3_zero_packet.end());
468       while (payload.size() < pkt_size) {
469         payload.insert(payload.end(), lc3_zero_packet.begin(),
470                        lc3_zero_packet.end());
471       }
472       packet_offset += lc3_zero_packet.size() - packet_offset;
473       packet_offset += lc3_zero_packet.size() -
474                        (payload.size() - pkt_size) % lc3_zero_packet.size();
475       packet_offset %= lc3_zero_packet.size();
476       payload.resize(pkt_size);
477     }
478 
479     bluetooth::audio::sco::swb::cleanup();
480   }
481 }
482 
TEST_F(ScoHciWbsTest,WbsEncodeWithoutInit)483 TEST_F(ScoHciWbsTest, WbsEncodeWithoutInit) {
484   int16_t data[120] = {0};
485   // Return 0 if buffer is uninitialized
486   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0));
487 }
488 
TEST_F(ScoHciSwbTest,SwbEncodeWithoutInit)489 TEST_F(ScoHciSwbTest, SwbEncodeWithoutInit) {
490   int16_t data[BTM_LC3_CODE_SIZE / 2] = {0};
491   // Return 0 if buffer is uninitialized
492   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), size_t(0));
493 }
494 
TEST_F(ScoHciWbsWithInitCleanTest,WbsEncode)495 TEST_F(ScoHciWbsWithInitCleanTest, WbsEncode) {
496   int16_t data[120] = {0};
497 
498   // Return 0 if data is invalid
499   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(nullptr, sizeof(data)),
500             size_t(0));
501   // Return 0 if data length is insufficient
502   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data) - 1),
503             size_t(0));
504   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)),
505             sizeof(data));
506 
507   // Return 0 if the packet buffer is full
508   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0));
509 }
510 
TEST_F(ScoHciSwbWithInitCleanTest,SwbEncode)511 TEST_F(ScoHciSwbWithInitCleanTest, SwbEncode) {
512   int16_t data[BTM_LC3_CODE_SIZE / 2] = {0};
513 
514   // Return 0 if data is invalid
515   ASSERT_EQ(bluetooth::audio::sco::swb::encode(nullptr, sizeof(data)),
516             size_t(0));
517   // Return 0 if data length is insufficient
518   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data) - 1),
519             size_t(0));
520   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)),
521             sizeof(data));
522 
523   // Return 0 if the packet buffer is full
524   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), size_t(0));
525 }
526 
TEST_F(ScoHciWbsTest,WbsDequeuePacketWithoutInit)527 TEST_F(ScoHciWbsTest, WbsDequeuePacketWithoutInit) {
528   const uint8_t* encoded = nullptr;
529   // Return 0 if buffer is uninitialized
530   ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0));
531   ASSERT_EQ(encoded, nullptr);
532 }
533 
TEST_F(ScoHciSwbTest,SwbDequeuePacketWithoutInit)534 TEST_F(ScoHciSwbTest, SwbDequeuePacketWithoutInit) {
535   const uint8_t* encoded = nullptr;
536   // Return 0 if buffer is uninitialized
537   ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(0));
538   ASSERT_EQ(encoded, nullptr);
539 }
540 
TEST_F(ScoHciWbsWithInitCleanTest,WbsDequeuePacket)541 TEST_F(ScoHciWbsWithInitCleanTest, WbsDequeuePacket) {
542   const uint8_t* encoded = nullptr;
543   // Return 0 if output pointer is invalid
544   ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(nullptr), size_t(0));
545   ASSERT_EQ(encoded, nullptr);
546 
547   // Return 0 if there is insufficient data to dequeue
548   ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0));
549   ASSERT_EQ(encoded, nullptr);
550 }
551 
TEST_F(ScoHciSwbWithInitCleanTest,SwbDequeuePacket)552 TEST_F(ScoHciSwbWithInitCleanTest, SwbDequeuePacket) {
553   const uint8_t* encoded = nullptr;
554   // Return 0 if output pointer is invalid
555   ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(nullptr), size_t(0));
556   ASSERT_EQ(encoded, nullptr);
557 
558   // Return 0 if there is insufficient data to dequeue
559   ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(0));
560   ASSERT_EQ(encoded, nullptr);
561 }
562 
TEST_F(ScoHciWbsWithInitCleanTest,WbsEncodeDequeuePackets)563 TEST_F(ScoHciWbsWithInitCleanTest, WbsEncodeDequeuePackets) {
564   uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8};
565   int16_t data[120] = {0};
566   const uint8_t* encoded = nullptr;
567 
568   for (size_t i = 0; i < 5; i++) {
569     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)),
570               sizeof(data));
571     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
572     ASSERT_NE(encoded, nullptr);
573     for (size_t j = 0; j < 60; j++) {
574       ASSERT_EQ(encoded[j],
575                 j == 1 ? h2_header_frames_count[i % 4] : msbc_zero_packet[j]);
576     }
577   }
578 }
579 
TEST_F(ScoHciSwbWithInitCleanTest,SwbEncodeDequeuePackets)580 TEST_F(ScoHciSwbWithInitCleanTest, SwbEncodeDequeuePackets) {
581   uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8};
582   int16_t data[BTM_LC3_CODE_SIZE / 2] = {0};
583   const uint8_t* encoded = nullptr;
584 
585   for (size_t i = 0; i < 5; i++) {
586     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)),
587               sizeof(data));
588     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
589     ASSERT_NE(encoded, nullptr);
590     for (size_t j = 0; j < 60; j++) {
591       ASSERT_EQ(encoded[j],
592                 j == 1 ? h2_header_frames_count[i % 4] : lc3_zero_packet[j]);
593     }
594   }
595 }
596 
TEST_F(ScoHciWbsWithInitCleanTest,WbsPlc)597 TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) {
598   int16_t triangle[16] = {0, 100,  200,  300,  400,  300,  200,  100,
599                           0, -100, -200, -300, -400, -300, -200, -100};
600   int16_t data[120];
601   int16_t expect_data[120];
602   std::vector<uint8_t> encoded_vec;
603   for (size_t i = 0; i < 60; i++) encoded_vec.push_back(0);
604   const uint8_t* encoded = nullptr;
605   const uint8_t* decoded = nullptr;
606   size_t lost_pkt_idx = 17;
607 
608   // Simulate a run without any packet loss
609   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
610     // Input data is a 1000Hz triangle wave
611     for (size_t j = 0; j < 120; j++, sample_idx++)
612       data[j] = triangle[sample_idx % 16];
613     // Build the packet
614     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)),
615               sizeof(data));
616     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
617     ASSERT_NE(encoded, nullptr);
618 
619     // Simulate the reception of the packet
620     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
621     ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(encoded_vec, false),
622               true);
623     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
624               size_t(BTM_MSBC_CODE_SIZE));
625     ASSERT_NE(decoded, nullptr);
626   }
627   // Store the decoded data we expect to get
628   std::copy((const int16_t*)decoded,
629             (const int16_t*)(decoded + BTM_MSBC_CODE_SIZE), expect_data);
630   // Start with the fresh WBS buffer
631   bluetooth::audio::sco::wbs::cleanup();
632   bluetooth::audio::sco::wbs::init(60);
633 
634   // check PLC returns gracefully with invalid parameters
635   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(nullptr, nullptr),
636             false);
637 
638   int num_decoded_frames;
639   double packet_loss_ratio;
640   // check PLC returns gracefully when there hasn't been decoded frames
641   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames,
642                                                        &packet_loss_ratio),
643             false);
644 
645   int decode_count = 0;
646   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
647     // Data is a 1000Hz triangle wave
648     for (size_t j = 0; j < 120; j++, sample_idx++)
649       data[j] = triangle[sample_idx % 16];
650     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)),
651               sizeof(data));
652     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
653     ASSERT_NE(encoded, nullptr);
654 
655     // Substitute to invalid packet to simulate packet loss.
656     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
657     ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(
658                   i != lost_pkt_idx ? encoded_vec : std::vector<uint8_t>(60, 0),
659                   false),
660               true);
661     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
662               size_t(BTM_MSBC_CODE_SIZE));
663     decode_count++;
664     ASSERT_NE(decoded, nullptr);
665   }
666 
667   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames,
668                                                        &packet_loss_ratio),
669             true);
670   ASSERT_EQ(num_decoded_frames, decode_count);
671   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
672 
673   int16_t* ptr = (int16_t*)decoded;
674   for (size_t i = 0; i < 120; i++) {
675     // The frames generated by PLC won't be perfect due to:
676     // 1. mSBC decoder is statefull
677     // 2. We apply overlap-add to glue the frames when packet loss happens
678     ASSERT_THAT(ptr[i] - expect_data[i], AllOf(Ge(-3), Le(3)))
679         << "PLC data " << ptr[i] << " deviates from expected " << expect_data[i]
680         << " at index " << i;
681   }
682 
683   size_t corrupted_pkt_idx = lost_pkt_idx;
684   // Start with the fresh WBS buffer
685   decode_count = 0;
686   bluetooth::audio::sco::wbs::cleanup();
687   bluetooth::audio::sco::wbs::init(60);
688   for (size_t i = 0, sample_idx = 0; i <= corrupted_pkt_idx; i++) {
689     // Data is a 1000Hz triangle wave
690     for (size_t j = 0; j < 120; j++, sample_idx++)
691       data[j] = triangle[sample_idx % 16];
692     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)),
693               sizeof(data));
694     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
695     ASSERT_NE(encoded, nullptr);
696 
697     // Substitute to report packet corrupted to simulate packet loss.
698     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
699     ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(
700                   encoded_vec, i == corrupted_pkt_idx),
701               true);
702     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded),
703               size_t(BTM_MSBC_CODE_SIZE));
704     decode_count++;
705     ASSERT_NE(decoded, nullptr);
706   }
707 
708   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames,
709                                                        &packet_loss_ratio),
710             true);
711   ASSERT_EQ(num_decoded_frames, decode_count);
712   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
713 
714   ptr = (int16_t*)decoded;
715   for (size_t i = 0; i < 120; i++) {
716     // The frames generated by PLC won't be perfect due to:
717     // 1. mSBC decoder is statefull
718     // 2. We apply overlap-add to glue the frames when packet loss happens
719     ASSERT_THAT(ptr[i] - expect_data[i], AllOf(Ge(-3), Le(3)))
720         << "PLC data " << ptr[i] << " deviates from expected " << expect_data[i]
721         << " at index " << i;
722   }
723 }
724 
725 // TODO(b/269970706): implement PLC validation with
726 // github.com/google/liblc3/issues/16 in mind.
TEST_F(ScoHciSwbWithInitCleanTest,SwbPlc)727 TEST_F(ScoHciSwbWithInitCleanTest, SwbPlc) {
728   int16_t triangle[16] = {0, 100,  200,  300,  400,  300,  200,  100,
729                           0, -100, -200, -300, -400, -300, -200, -100};
730   int16_t data[BTM_LC3_CODE_SIZE / 2];
731   int16_t expect_data[BTM_LC3_CODE_SIZE / 2];
732   std::vector<uint8_t> encoded_vec;
733   for (size_t i = 0; i < 60; i++) encoded_vec.push_back(0);
734   const uint8_t* encoded = nullptr;
735   const uint8_t* decoded = nullptr;
736   size_t lost_pkt_idx = 17;
737 
738   // Simulate a run without any packet loss
739   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
740     // Input data is a 1000Hz triangle wave
741     for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++)
742       data[j] = triangle[sample_idx % 16];
743     // Build the packet
744     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)),
745               sizeof(data));
746     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
747     ASSERT_NE(encoded, nullptr);
748 
749     // Simulate the reception of the packet
750     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
751     ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(encoded_vec, false),
752               true);
753     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded),
754               size_t(BTM_LC3_CODE_SIZE));
755     ASSERT_NE(decoded, nullptr);
756   }
757   // Store the decoded data we expect to get
758   std::copy((const int16_t*)decoded,
759             (const int16_t*)(decoded + BTM_LC3_CODE_SIZE), expect_data);
760   // Start with the fresh SWB buffer
761   bluetooth::audio::sco::swb::cleanup();
762   bluetooth::audio::sco::swb::init(60);
763 
764   // check PLC returns gracefully with invalid parameters
765   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(nullptr, nullptr),
766             false);
767 
768   int num_decoded_frames;
769   double packet_loss_ratio;
770   // check PLC returns gracefully when there hasn't been decoded frames
771   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames,
772                                                        &packet_loss_ratio),
773             false);
774 
775   int decode_count = 0;
776   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
777     // Data is a 1000Hz triangle wave
778     for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++)
779       data[j] = triangle[sample_idx % 16];
780     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)),
781               sizeof(data));
782     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
783     ASSERT_NE(encoded, nullptr);
784 
785     // Substitute to invalid packet to simulate packet loss.
786     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
787     ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(
788                   i != lost_pkt_idx ? encoded_vec : std::vector<uint8_t>(60, 0),
789                   false),
790               true);
791     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded),
792               size_t(BTM_LC3_CODE_SIZE));
793     decode_count++;
794     ASSERT_NE(decoded, nullptr);
795   }
796 
797   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames,
798                                                        &packet_loss_ratio),
799             true);
800   ASSERT_EQ(num_decoded_frames, decode_count);
801   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
802 
803   size_t corrupted_pkt_idx = lost_pkt_idx;
804   // Start with the fresh SWB buffer
805   decode_count = 0;
806   bluetooth::audio::sco::swb::cleanup();
807   bluetooth::audio::sco::swb::init(60);
808   for (size_t i = 0, sample_idx = 0; i <= corrupted_pkt_idx; i++) {
809     // Data is a 1000Hz triangle wave
810     for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++)
811       data[j] = triangle[sample_idx % 16];
812     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)),
813               sizeof(data));
814     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
815     ASSERT_NE(encoded, nullptr);
816 
817     // Substitute to report packet corrupted to simulate packet loss.
818     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
819     ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(
820                   encoded_vec, i == corrupted_pkt_idx),
821               true);
822     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded),
823               size_t(BTM_LC3_CODE_SIZE));
824     decode_count++;
825     ASSERT_NE(decoded, nullptr);
826   }
827 
828   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames,
829                                                        &packet_loss_ratio),
830             true);
831   ASSERT_EQ(num_decoded_frames, decode_count);
832   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
833 }
834 }  // namespace
835