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 
36 extern bluetooth::core::CoreInterface* GetInterfaceToProfiles();
37 
38 namespace {
39 
40 using testing::AllOf;
41 using testing::Ge;
42 using testing::Le;
43 using testing::Test;
44 
45 const std::vector<uint8_t> msbc_zero_packet{
46         0x01, 0x08, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd, 0xdb,
47         0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7,
48         0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb,
49         0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00};
50 
51 const std::vector<uint8_t> lc3_zero_packet{
52         0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0xf9, 0x4a, 0x0d, 0x00, 0x00, 0x03};
56 
57 // Maps irregular packet size to expected decode buffer size.
58 // See |btm_wbs_supported_pkt_size| and |btm_wbs_msbc_buffer_size|.
59 const std::map<size_t, size_t> irregular_packet_to_buffer_size{
60         {72, 360},
61         {24, 120},
62 };
63 
64 // The encoded packet size is 60 regardless of the codec.
65 const int ENCODED_PACKET_SIZE = 60;
66 
67 struct MsbcCodecInterface : bluetooth::core::CodecInterface {
MsbcCodecInterface__anonb28ba4f50111::MsbcCodecInterface68   MsbcCodecInterface() : bluetooth::core::CodecInterface() {}
69 
initialize__anonb28ba4f50111::MsbcCodecInterface70   void initialize() override {
71     hfp_msbc_decoder_init();
72     hfp_msbc_encoder_init();
73   }
74 
cleanup__anonb28ba4f50111::MsbcCodecInterface75   void cleanup() override {
76     hfp_msbc_decoder_cleanup();
77     hfp_msbc_encoder_cleanup();
78   }
79 
encodePacket__anonb28ba4f50111::MsbcCodecInterface80   uint32_t encodePacket(int16_t* input, uint8_t* output) {
81     return hfp_msbc_encode_frames(input, output);
82   }
83 
decodePacket__anonb28ba4f50111::MsbcCodecInterface84   bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) {
85     return hfp_msbc_decoder_decode_packet(i_buf, o_buf, out_len);
86   }
87 };
88 
89 struct Lc3CodecInterface : bluetooth::core::CodecInterface {
Lc3CodecInterface__anonb28ba4f50111::Lc3CodecInterface90   Lc3CodecInterface() : bluetooth::core::CodecInterface() {}
91 
initialize__anonb28ba4f50111::Lc3CodecInterface92   void initialize() override {
93     hfp_lc3_decoder_init();
94     hfp_lc3_encoder_init();
95   }
96 
cleanup__anonb28ba4f50111::Lc3CodecInterface97   void cleanup() override {
98     hfp_lc3_decoder_cleanup();
99     hfp_lc3_encoder_cleanup();
100   }
101 
encodePacket__anonb28ba4f50111::Lc3CodecInterface102   uint32_t encodePacket(int16_t* input, uint8_t* output) {
103     return hfp_lc3_encode_frames(input, output);
104   }
105 
decodePacket__anonb28ba4f50111::Lc3CodecInterface106   bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) {
107     return hfp_lc3_decoder_decode_packet(i_buf, o_buf, out_len);
108   }
109 };
110 
111 class ScoHciTest : public BtmWithMocksTest {
112 public:
113 protected:
SetUp()114   void SetUp() override {
115     BtmWithMocksTest::SetUp();
116 
117     static auto msbc_codec = MsbcCodecInterface{};
118     static auto lc3_codec = Lc3CodecInterface{};
119     GetInterfaceToProfiles()->msbcCodec = &msbc_codec;
120     GetInterfaceToProfiles()->lc3Codec = &lc3_codec;
121   }
TearDown()122   void TearDown() override { BtmWithMocksTest::TearDown(); }
123 };
124 
125 class ScoHciWithOpenCleanTest : public ScoHciTest {
126 public:
127 protected:
SetUp()128   void SetUp() override {
129     ScoHciTest::SetUp();
130     bluetooth::audio::sco::open();
131   }
TearDown()132   void TearDown() override { bluetooth::audio::sco::cleanup(); }
133 };
134 
135 class ScoHciWbsTest : public ScoHciTest {};
136 class ScoHciSwbTest : public ScoHciTest {};
137 
138 class ScoHciWbsWithInitCleanTest : public ScoHciTest {
139 public:
140 protected:
SetUp()141   void SetUp() override {
142     ScoHciTest::SetUp();
143     bluetooth::audio::sco::wbs::init(60);
144   }
TearDown()145   void TearDown() override { bluetooth::audio::sco::wbs::cleanup(); }
146 };
147 
148 class ScoHciSwbWithInitCleanTest : public ScoHciTest {
149 public:
150 protected:
SetUp()151   void SetUp() override {
152     ScoHciTest::SetUp();
153     bluetooth::audio::sco::swb::init(60);
154   }
TearDown()155   void TearDown() override { bluetooth::audio::sco::swb::cleanup(); }
156 };
157 
TEST_F(ScoHciWbsTest,WbsInit)158 TEST_F(ScoHciWbsTest, WbsInit) {
159   ASSERT_EQ(bluetooth::audio::sco::wbs::init(60), size_t(60));
160   ASSERT_EQ(bluetooth::audio::sco::wbs::init(72), size_t(72));
161   // Fallback to 60 if the packet size is not supported
162   ASSERT_EQ(bluetooth::audio::sco::wbs::init(48), size_t(60));
163   bluetooth::audio::sco::wbs::cleanup();
164 }
165 
TEST_F(ScoHciSwbTest,SwbInit)166 TEST_F(ScoHciSwbTest, SwbInit) {
167   ASSERT_EQ(bluetooth::audio::sco::swb::init(60), size_t(60));
168   ASSERT_EQ(bluetooth::audio::sco::swb::init(72), size_t(72));
169   // Fallback to 60 if the packet size is not supported
170   ASSERT_EQ(bluetooth::audio::sco::swb::init(48), size_t(60));
171   bluetooth::audio::sco::swb::cleanup();
172 }
173 
TEST_F(ScoHciWbsTest,WbsEnqueuePacketWithoutInit)174 TEST_F(ScoHciWbsTest, WbsEnqueuePacketWithoutInit) {
175   std::vector<uint8_t> payload{60, 0};
176   // Return 0 if buffer is uninitialized
177   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false);
178 }
179 
TEST_F(ScoHciSwbTest,SwbEnqueuePacketWithoutInit)180 TEST_F(ScoHciSwbTest, SwbEnqueuePacketWithoutInit) {
181   std::vector<uint8_t> payload{60, 0};
182   // Return 0 if buffer is uninitialized
183   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), false);
184 }
185 
TEST_F(ScoHciWbsWithInitCleanTest,WbsEnqueuePacket)186 TEST_F(ScoHciWbsWithInitCleanTest, WbsEnqueuePacket) {
187   std::vector<uint8_t> payload;
188   for (size_t i = 0; i < 60; i++) {
189     payload.push_back(0);
190   }
191   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true);
192   // Return 0 if buffer is full
193   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), false);
194 }
195 
TEST_F(ScoHciSwbWithInitCleanTest,SwbEnqueuePacket)196 TEST_F(ScoHciSwbWithInitCleanTest, SwbEnqueuePacket) {
197   std::vector<uint8_t> payload;
198   for (size_t i = 0; i < 60; i++) {
199     payload.push_back(0);
200   }
201   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true);
202   // Return 0 if buffer is full
203   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), false);
204 }
205 
TEST_F(ScoHciWbsTest,WbsDecodeWithoutInit)206 TEST_F(ScoHciWbsTest, WbsDecodeWithoutInit) {
207   const uint8_t* decoded = nullptr;
208   // Return 0 if buffer is uninitialized
209   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
210   ASSERT_EQ(decoded, nullptr);
211 }
212 
TEST_F(ScoHciSwbTest,SwbDecodeWithoutInit)213 TEST_F(ScoHciSwbTest, SwbDecodeWithoutInit) {
214   const uint8_t* decoded = nullptr;
215   // Return 0 if buffer is uninitialized
216   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
217   ASSERT_EQ(decoded, nullptr);
218 }
219 
TEST_F(ScoHciWbsWithInitCleanTest,WbsDecode)220 TEST_F(ScoHciWbsWithInitCleanTest, WbsDecode) {
221   const uint8_t* decoded = nullptr;
222   std::vector<uint8_t> payload;
223   for (size_t i = 0; i < 60; i++) {
224     payload.push_back(0);
225   }
226 
227   // No data to decode
228   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
229   ASSERT_EQ(decoded, nullptr);
230   // Fill in invalid packet, all zeros.
231   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true);
232 
233   // Return all zero frames when there comes an invalid packet.
234   // This is expected even with PLC as there is no history in the PLC buffer.
235   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE));
236   ASSERT_NE(decoded, nullptr);
237   for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) {
238     ASSERT_EQ(decoded[i], 0);
239   }
240 
241   decoded = nullptr;
242   ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(msbc_zero_packet, false), true);
243   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE));
244   ASSERT_NE(decoded, nullptr);
245   for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) {
246     ASSERT_EQ(decoded[i], 0);
247   }
248 
249   decoded = nullptr;
250   // No remaining data to decode
251   ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
252   ASSERT_EQ(decoded, nullptr);
253 }
254 
TEST_F(ScoHciSwbWithInitCleanTest,SwbDecode)255 TEST_F(ScoHciSwbWithInitCleanTest, SwbDecode) {
256   const uint8_t* decoded = nullptr;
257   std::vector<uint8_t> payload;
258   for (size_t i = 0; i < 60; i++) {
259     payload.push_back(0);
260   }
261 
262   // No data to decode
263   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
264   ASSERT_EQ(decoded, nullptr);
265   // Fill in invalid packet, all zeros.
266   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true);
267 
268   // Return all zero frames when there comes an invalid packet.
269   // This is expected even with PLC as there is no history in the PLC buffer.
270   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE));
271   ASSERT_NE(decoded, nullptr);
272   for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) {
273     ASSERT_EQ(decoded[i], 0);
274   }
275 
276   decoded = nullptr;
277   ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(lc3_zero_packet, false), true);
278   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE));
279   ASSERT_NE(decoded, nullptr);
280   for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) {
281     ASSERT_EQ(decoded[i], 0);
282   }
283 
284   decoded = nullptr;
285   // No remaining data to decode
286   ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
287   ASSERT_EQ(decoded, nullptr);
288 }
289 
TEST_F(ScoHciWbsTest,WbsDecodeWithIrregularOffset)290 TEST_F(ScoHciWbsTest, WbsDecodeWithIrregularOffset) {
291   for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) {
292     ASSERT_EQ(buf_size % pkt_size, 0u);
293 
294     bluetooth::audio::sco::wbs::init(pkt_size);
295 
296     const uint8_t* decoded = nullptr;
297 
298     // No data to decode
299     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(0));
300     ASSERT_EQ(decoded, nullptr);
301 
302     // Start the payload with an irregular offset that misaligns with the
303     // packet size.
304     std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0);
305     while (payload.size() <= pkt_size) {
306       payload.insert(payload.end(), msbc_zero_packet.begin(), msbc_zero_packet.end());
307     }
308     size_t packet_offset = msbc_zero_packet.size() - (payload.size() - pkt_size);
309     payload.resize(pkt_size);
310 
311     // Try to decode as many packets as to hit the boundary.
312     for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size; ++iter) {
313       ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(payload, false), true);
314       decodable += payload.size() - !iter;  // compensate for the first offset
315 
316       while (decodable >= ENCODED_PACKET_SIZE) {
317         decoded = nullptr;
318         ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE));
319         ASSERT_NE(decoded, nullptr);
320         for (size_t i = 0; i < BTM_MSBC_CODE_SIZE; i++) {
321           ASSERT_EQ(decoded[i], 0);
322         }
323         decodable -= ENCODED_PACKET_SIZE;
324       }
325 
326       payload = std::vector<uint8_t>(msbc_zero_packet.begin() + packet_offset,
327                                      msbc_zero_packet.end());
328       while (payload.size() < pkt_size) {
329         payload.insert(payload.end(), msbc_zero_packet.begin(), msbc_zero_packet.end());
330       }
331       packet_offset += msbc_zero_packet.size() - packet_offset;
332       packet_offset +=
333               msbc_zero_packet.size() - (payload.size() - pkt_size) % msbc_zero_packet.size();
334       packet_offset %= msbc_zero_packet.size();
335       payload.resize(pkt_size);
336     }
337 
338     bluetooth::audio::sco::wbs::cleanup();
339   }
340 }
341 
TEST_F(ScoHciSwbTest,SwbDecodeWithIrregularOffset)342 TEST_F(ScoHciSwbTest, SwbDecodeWithIrregularOffset) {
343   for (auto [pkt_size, buf_size] : irregular_packet_to_buffer_size) {
344     ASSERT_EQ(buf_size % pkt_size, 0u);
345 
346     bluetooth::audio::sco::swb::init(pkt_size);
347 
348     const uint8_t* decoded = nullptr;
349 
350     // No data to decode
351     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(0));
352     ASSERT_EQ(decoded, nullptr);
353 
354     // Start the payload with an irregular offset that misaligns with the
355     // packet size.
356     std::vector<uint8_t> payload = std::vector<uint8_t>(1, 0);
357     while (payload.size() <= pkt_size) {
358       payload.insert(payload.end(), lc3_zero_packet.begin(), lc3_zero_packet.end());
359     }
360     size_t packet_offset = lc3_zero_packet.size() - (payload.size() - pkt_size);
361     payload.resize(pkt_size);
362 
363     // Try to decode as many packets as to hit the boundary.
364     for (size_t iter = 0, decodable = 0; iter < 2 * buf_size / pkt_size; ++iter) {
365       ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(payload, false), true);
366       decodable += payload.size() - !iter;  // compensate for the first offset
367 
368       while (decodable >= ENCODED_PACKET_SIZE) {
369         decoded = nullptr;
370         ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE));
371         ASSERT_NE(decoded, nullptr);
372         for (size_t i = 0; i < BTM_LC3_CODE_SIZE; i++) {
373           ASSERT_EQ(decoded[i], 0);
374         }
375         decodable -= ENCODED_PACKET_SIZE;
376       }
377 
378       payload =
379               std::vector<uint8_t>(lc3_zero_packet.begin() + packet_offset, lc3_zero_packet.end());
380       while (payload.size() < pkt_size) {
381         payload.insert(payload.end(), lc3_zero_packet.begin(), lc3_zero_packet.end());
382       }
383       packet_offset += lc3_zero_packet.size() - packet_offset;
384       packet_offset +=
385               lc3_zero_packet.size() - (payload.size() - pkt_size) % lc3_zero_packet.size();
386       packet_offset %= lc3_zero_packet.size();
387       payload.resize(pkt_size);
388     }
389 
390     bluetooth::audio::sco::swb::cleanup();
391   }
392 }
393 
TEST_F(ScoHciWbsTest,WbsEncodeWithoutInit)394 TEST_F(ScoHciWbsTest, WbsEncodeWithoutInit) {
395   int16_t data[120] = {0};
396   // Return 0 if buffer is uninitialized
397   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0));
398 }
399 
TEST_F(ScoHciSwbTest,SwbEncodeWithoutInit)400 TEST_F(ScoHciSwbTest, SwbEncodeWithoutInit) {
401   int16_t data[BTM_LC3_CODE_SIZE / 2] = {0};
402   // Return 0 if buffer is uninitialized
403   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), size_t(0));
404 }
405 
TEST_F(ScoHciWbsWithInitCleanTest,WbsEncode)406 TEST_F(ScoHciWbsWithInitCleanTest, WbsEncode) {
407   int16_t data[120] = {0};
408 
409   // Return 0 if data is invalid
410   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(nullptr, sizeof(data)), size_t(0));
411   // Return 0 if data length is insufficient
412   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data) - 1), size_t(0));
413   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data));
414 
415   // Return 0 if the packet buffer is full
416   ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), size_t(0));
417 }
418 
TEST_F(ScoHciSwbWithInitCleanTest,SwbEncode)419 TEST_F(ScoHciSwbWithInitCleanTest, SwbEncode) {
420   int16_t data[BTM_LC3_CODE_SIZE / 2] = {0};
421 
422   // Return 0 if data is invalid
423   ASSERT_EQ(bluetooth::audio::sco::swb::encode(nullptr, sizeof(data)), size_t(0));
424   // Return 0 if data length is insufficient
425   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data) - 1), size_t(0));
426   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), sizeof(data));
427 
428   // Return 0 if the packet buffer is full
429   ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), size_t(0));
430 }
431 
TEST_F(ScoHciWbsTest,WbsDequeuePacketWithoutInit)432 TEST_F(ScoHciWbsTest, WbsDequeuePacketWithoutInit) {
433   const uint8_t* encoded = nullptr;
434   // Return 0 if buffer is uninitialized
435   ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0));
436   ASSERT_EQ(encoded, nullptr);
437 }
438 
TEST_F(ScoHciSwbTest,SwbDequeuePacketWithoutInit)439 TEST_F(ScoHciSwbTest, SwbDequeuePacketWithoutInit) {
440   const uint8_t* encoded = nullptr;
441   // Return 0 if buffer is uninitialized
442   ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(0));
443   ASSERT_EQ(encoded, nullptr);
444 }
445 
TEST_F(ScoHciWbsWithInitCleanTest,WbsDequeuePacket)446 TEST_F(ScoHciWbsWithInitCleanTest, WbsDequeuePacket) {
447   const uint8_t* encoded = nullptr;
448   // Return 0 if output pointer is invalid
449   ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(nullptr), size_t(0));
450   ASSERT_EQ(encoded, nullptr);
451 
452   // Return 0 if there is insufficient data to dequeue
453   ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(0));
454   ASSERT_EQ(encoded, nullptr);
455 }
456 
TEST_F(ScoHciSwbWithInitCleanTest,SwbDequeuePacket)457 TEST_F(ScoHciSwbWithInitCleanTest, SwbDequeuePacket) {
458   const uint8_t* encoded = nullptr;
459   // Return 0 if output pointer is invalid
460   ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(nullptr), size_t(0));
461   ASSERT_EQ(encoded, nullptr);
462 
463   // Return 0 if there is insufficient data to dequeue
464   ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(0));
465   ASSERT_EQ(encoded, nullptr);
466 }
467 
TEST_F(ScoHciWbsWithInitCleanTest,WbsEncodeDequeuePackets)468 TEST_F(ScoHciWbsWithInitCleanTest, WbsEncodeDequeuePackets) {
469   uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8};
470   int16_t data[120] = {0};
471   const uint8_t* encoded = nullptr;
472 
473   for (size_t i = 0; i < 5; i++) {
474     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data));
475     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
476     ASSERT_NE(encoded, nullptr);
477     for (size_t j = 0; j < 60; j++) {
478       ASSERT_EQ(encoded[j], j == 1 ? h2_header_frames_count[i % 4] : msbc_zero_packet[j]);
479     }
480   }
481 }
482 
TEST_F(ScoHciSwbWithInitCleanTest,SwbEncodeDequeuePackets)483 TEST_F(ScoHciSwbWithInitCleanTest, SwbEncodeDequeuePackets) {
484   uint8_t h2_header_frames_count[] = {0x08, 0x38, 0xc8, 0xf8};
485   int16_t data[BTM_LC3_CODE_SIZE / 2] = {0};
486   const uint8_t* encoded = nullptr;
487 
488   for (size_t i = 0; i < 5; i++) {
489     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), sizeof(data));
490     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
491     ASSERT_NE(encoded, nullptr);
492     for (size_t j = 0; j < 60; j++) {
493       ASSERT_EQ(encoded[j], j == 1 ? h2_header_frames_count[i % 4] : lc3_zero_packet[j]);
494     }
495   }
496 }
497 
TEST_F(ScoHciWbsWithInitCleanTest,WbsPlc)498 TEST_F(ScoHciWbsWithInitCleanTest, WbsPlc) {
499   int16_t triangle[16] = {0, 100,  200,  300,  400,  300,  200,  100,
500                           0, -100, -200, -300, -400, -300, -200, -100};
501   int16_t data[120];
502   int16_t expect_data[120];
503   std::vector<uint8_t> encoded_vec;
504   for (size_t i = 0; i < 60; i++) {
505     encoded_vec.push_back(0);
506   }
507   const uint8_t* encoded = nullptr;
508   const uint8_t* decoded = nullptr;
509   size_t lost_pkt_idx = 17;
510 
511   // Simulate a run without any packet loss
512   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
513     // Input data is a 1000Hz triangle wave
514     for (size_t j = 0; j < 120; j++, sample_idx++) {
515       data[j] = triangle[sample_idx % 16];
516     }
517     // Build the packet
518     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data));
519     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
520     ASSERT_NE(encoded, nullptr);
521 
522     // Simulate the reception of the packet
523     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
524     ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(encoded_vec, false), true);
525     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE));
526     ASSERT_NE(decoded, nullptr);
527   }
528   // Store the decoded data we expect to get
529   std::copy((const int16_t*)decoded, (const int16_t*)(decoded + BTM_MSBC_CODE_SIZE), expect_data);
530   // Start with the fresh WBS buffer
531   bluetooth::audio::sco::wbs::cleanup();
532   bluetooth::audio::sco::wbs::init(60);
533 
534   // check PLC returns gracefully with invalid parameters
535   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(nullptr, nullptr), false);
536 
537   int num_decoded_frames;
538   double packet_loss_ratio;
539   // check PLC returns gracefully when there hasn't been decoded frames
540   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames, &packet_loss_ratio),
541             false);
542 
543   int decode_count = 0;
544   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
545     // Data is a 1000Hz triangle wave
546     for (size_t j = 0; j < 120; j++, sample_idx++) {
547       data[j] = triangle[sample_idx % 16];
548     }
549     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data));
550     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
551     ASSERT_NE(encoded, nullptr);
552 
553     // Substitute to invalid packet to simulate packet loss.
554     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
555     ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(
556                       i != lost_pkt_idx ? encoded_vec : std::vector<uint8_t>(60, 0), false),
557               true);
558     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE));
559     decode_count++;
560     ASSERT_NE(decoded, nullptr);
561   }
562 
563   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames, &packet_loss_ratio),
564             true);
565   ASSERT_EQ(num_decoded_frames, decode_count);
566   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
567 
568   int16_t* ptr = (int16_t*)decoded;
569   for (size_t i = 0; i < 120; i++) {
570     // The frames generated by PLC won't be perfect due to:
571     // 1. mSBC decoder is statefull
572     // 2. We apply overlap-add to glue the frames when packet loss happens
573     ASSERT_THAT(ptr[i] - expect_data[i], AllOf(Ge(-3), Le(3)))
574             << "PLC data " << ptr[i] << " deviates from expected " << expect_data[i] << " at index "
575             << i;
576   }
577 
578   size_t corrupted_pkt_idx = lost_pkt_idx;
579   // Start with the fresh WBS buffer
580   decode_count = 0;
581   bluetooth::audio::sco::wbs::cleanup();
582   bluetooth::audio::sco::wbs::init(60);
583   for (size_t i = 0, sample_idx = 0; i <= corrupted_pkt_idx; i++) {
584     // Data is a 1000Hz triangle wave
585     for (size_t j = 0; j < 120; j++, sample_idx++) {
586       data[j] = triangle[sample_idx % 16];
587     }
588     ASSERT_EQ(bluetooth::audio::sco::wbs::encode(data, sizeof(data)), sizeof(data));
589     ASSERT_EQ(bluetooth::audio::sco::wbs::dequeue_packet(&encoded), size_t(60));
590     ASSERT_NE(encoded, nullptr);
591 
592     // Substitute to report packet corrupted to simulate packet loss.
593     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
594     ASSERT_EQ(bluetooth::audio::sco::wbs::enqueue_packet(encoded_vec, i == corrupted_pkt_idx),
595               true);
596     ASSERT_EQ(bluetooth::audio::sco::wbs::decode(&decoded), size_t(BTM_MSBC_CODE_SIZE));
597     decode_count++;
598     ASSERT_NE(decoded, nullptr);
599   }
600 
601   ASSERT_EQ(bluetooth::audio::sco::wbs::fill_plc_stats(&num_decoded_frames, &packet_loss_ratio),
602             true);
603   ASSERT_EQ(num_decoded_frames, decode_count);
604   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
605 
606   ptr = (int16_t*)decoded;
607   for (size_t i = 0; i < 120; i++) {
608     // The frames generated by PLC won't be perfect due to:
609     // 1. mSBC decoder is statefull
610     // 2. We apply overlap-add to glue the frames when packet loss happens
611     ASSERT_THAT(ptr[i] - expect_data[i], AllOf(Ge(-3), Le(3)))
612             << "PLC data " << ptr[i] << " deviates from expected " << expect_data[i] << " at index "
613             << i;
614   }
615 }
616 
617 // TODO(b/269970706): implement PLC validation with
618 // github.com/google/liblc3/issues/16 in mind.
TEST_F(ScoHciSwbWithInitCleanTest,SwbPlc)619 TEST_F(ScoHciSwbWithInitCleanTest, SwbPlc) {
620   int16_t triangle[16] = {0, 100,  200,  300,  400,  300,  200,  100,
621                           0, -100, -200, -300, -400, -300, -200, -100};
622   int16_t data[BTM_LC3_CODE_SIZE / 2];
623   int16_t expect_data[BTM_LC3_CODE_SIZE / 2];
624   std::vector<uint8_t> encoded_vec;
625   for (size_t i = 0; i < 60; i++) {
626     encoded_vec.push_back(0);
627   }
628   const uint8_t* encoded = nullptr;
629   const uint8_t* decoded = nullptr;
630   size_t lost_pkt_idx = 17;
631 
632   // Simulate a run without any packet loss
633   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
634     // Input data is a 1000Hz triangle wave
635     for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++) {
636       data[j] = triangle[sample_idx % 16];
637     }
638     // Build the packet
639     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), sizeof(data));
640     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
641     ASSERT_NE(encoded, nullptr);
642 
643     // Simulate the reception of the packet
644     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
645     ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(encoded_vec, false), true);
646     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE));
647     ASSERT_NE(decoded, nullptr);
648   }
649   // Store the decoded data we expect to get
650   std::copy((const int16_t*)decoded, (const int16_t*)(decoded + BTM_LC3_CODE_SIZE), expect_data);
651   // Start with the fresh SWB buffer
652   bluetooth::audio::sco::swb::cleanup();
653   bluetooth::audio::sco::swb::init(60);
654 
655   // check PLC returns gracefully with invalid parameters
656   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(nullptr, nullptr), false);
657 
658   int num_decoded_frames;
659   double packet_loss_ratio;
660   // check PLC returns gracefully when there hasn't been decoded frames
661   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames, &packet_loss_ratio),
662             false);
663 
664   int decode_count = 0;
665   for (size_t i = 0, sample_idx = 0; i <= lost_pkt_idx; i++) {
666     // Data is a 1000Hz triangle wave
667     for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++) {
668       data[j] = triangle[sample_idx % 16];
669     }
670     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), sizeof(data));
671     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
672     ASSERT_NE(encoded, nullptr);
673 
674     // Substitute to invalid packet to simulate packet loss.
675     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
676     ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(
677                       i != lost_pkt_idx ? encoded_vec : std::vector<uint8_t>(60, 0), false),
678               true);
679     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE));
680     decode_count++;
681     ASSERT_NE(decoded, nullptr);
682   }
683 
684   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames, &packet_loss_ratio),
685             true);
686   ASSERT_EQ(num_decoded_frames, decode_count);
687   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
688 
689   size_t corrupted_pkt_idx = lost_pkt_idx;
690   // Start with the fresh SWB buffer
691   decode_count = 0;
692   bluetooth::audio::sco::swb::cleanup();
693   bluetooth::audio::sco::swb::init(60);
694   for (size_t i = 0, sample_idx = 0; i <= corrupted_pkt_idx; i++) {
695     // Data is a 1000Hz triangle wave
696     for (size_t j = 0; j < BTM_LC3_CODE_SIZE / 2; j++, sample_idx++) {
697       data[j] = triangle[sample_idx % 16];
698     }
699     ASSERT_EQ(bluetooth::audio::sco::swb::encode(data, sizeof(data)), sizeof(data));
700     ASSERT_EQ(bluetooth::audio::sco::swb::dequeue_packet(&encoded), size_t(60));
701     ASSERT_NE(encoded, nullptr);
702 
703     // Substitute to report packet corrupted to simulate packet loss.
704     std::copy(encoded, encoded + size_t(60), encoded_vec.data());
705     ASSERT_EQ(bluetooth::audio::sco::swb::enqueue_packet(encoded_vec, i == corrupted_pkt_idx),
706               true);
707     ASSERT_EQ(bluetooth::audio::sco::swb::decode(&decoded), size_t(BTM_LC3_CODE_SIZE));
708     decode_count++;
709     ASSERT_NE(decoded, nullptr);
710   }
711 
712   ASSERT_EQ(bluetooth::audio::sco::swb::fill_plc_stats(&num_decoded_frames, &packet_loss_ratio),
713             true);
714   ASSERT_EQ(num_decoded_frames, decode_count);
715   ASSERT_EQ(packet_loss_ratio, (double)1 / decode_count);
716 }
717 }  // namespace
718