1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "stack/include/a2dp_sbc.h"
18 
19 #include <gtest/gtest.h>
20 
21 #include <chrono>
22 #include <cstdint>
23 #include <future>
24 #include <string>
25 
26 #include "common/init_flags.h"
27 #include "common/time_util.h"
28 #include "os/log.h"
29 #include "osi/include/allocator.h"
30 #include "stack/include/a2dp_sbc_decoder.h"
31 #include "stack/include/a2dp_sbc_encoder.h"
32 #include "stack/include/avdt_api.h"
33 #include "stack/include/bt_hdr.h"
34 #include "test_util.h"
35 #include "wav_reader.h"
36 
37 namespace {
38 constexpr uint32_t kSbcReadSize = 512;
39 constexpr uint32_t kA2dpTickUs = 23 * 1000;
40 constexpr char kWavFile[] = "test/a2dp/raw_data/pcm1644s.wav";
41 constexpr uint16_t kPeerMtu = 1000;
42 const uint8_t kCodecInfoSbcCapability[AVDT_CODEC_SIZE] = {
43     6,                   // Length (A2DP_SBC_INFO_LEN)
44     0,                   // Media Type: AVDT_MEDIA_TYPE_AUDIO
45     0,                   // Media Codec Type: A2DP_MEDIA_CT_SBC
46     0x20 | 0x01,         // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
47                          // Channel Mode: A2DP_SBC_IE_CH_MD_JOINT
48     0x10 | 0x04 | 0x01,  // Block Length: A2DP_SBC_IE_BLOCKS_16 |
49                          // Subbands: A2DP_SBC_IE_SUBBAND_8 |
50                          // Allocation Method: A2DP_SBC_IE_ALLOC_MD_L
51     2,                   // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
52     53,                  // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
53     7,                   // Fake
54     8,                   // Fake
55     9                    // Fake
56 };
Data(BT_HDR * packet)57 uint8_t* Data(BT_HDR* packet) { return packet->data + packet->offset; }
58 }  // namespace
59 
60 namespace bluetooth {
61 namespace testing {
62 
63 static BT_HDR* packet = nullptr;
64 static WavReader wav_reader = WavReader(GetWavFilePath(kWavFile).c_str());
65 static std::promise<void> promise;
66 
67 class A2dpSbcTest : public ::testing::Test {
68  protected:
SetUp()69   void SetUp() override {
70     common::InitFlags::SetAllForTesting();
71     SetCodecConfig();
72     encoder_iface_ = const_cast<tA2DP_ENCODER_INTERFACE*>(
73         A2DP_GetEncoderInterfaceSbc(kCodecInfoSbcCapability));
74     ASSERT_NE(encoder_iface_, nullptr);
75     decoder_iface_ = const_cast<tA2DP_DECODER_INTERFACE*>(
76         A2DP_GetDecoderInterfaceSbc(kCodecInfoSbcCapability));
77     ASSERT_NE(decoder_iface_, nullptr);
78   }
79 
TearDown()80   void TearDown() override {
81     if (a2dp_codecs_ != nullptr) {
82       delete a2dp_codecs_;
83     }
84     if (encoder_iface_ != nullptr) {
85       encoder_iface_->encoder_cleanup();
86     }
87     A2DP_UnloadEncoderSbc();
88     if (decoder_iface_ != nullptr) {
89       decoder_iface_->decoder_cleanup();
90     }
91     A2DP_UnloadDecoderSbc();
92   }
93 
SetCodecConfig()94   void SetCodecConfig() {
95     uint8_t codec_info_result[AVDT_CODEC_SIZE];
96     btav_a2dp_codec_index_t peer_codec_index;
97     a2dp_codecs_ = new A2dpCodecs(std::vector<btav_a2dp_codec_config_t>());
98 
99     ASSERT_TRUE(a2dp_codecs_->init());
100 
101     // Create the codec capability - SBC Sink
102     memset(codec_info_result, 0, sizeof(codec_info_result));
103     ASSERT_TRUE(A2DP_IsSinkCodecSupportedSbc(kCodecInfoSbcCapability));
104     peer_codec_index = A2DP_SinkCodecIndex(kCodecInfoSbcCapability);
105     ASSERT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
106     sink_codec_config_ = a2dp_codecs_->findSinkCodecConfig(kCodecInfoSbcCapability);
107     ASSERT_NE(sink_codec_config_, nullptr);
108     ASSERT_TRUE(a2dp_codecs_->setSinkCodecConfig(kCodecInfoSbcCapability, true,
109                                                  codec_info_result, true));
110     ASSERT_TRUE(a2dp_codecs_->setPeerSinkCodecCapabilities(kCodecInfoSbcCapability));
111     // Compare the result codec with the local test codec info
112     for (size_t i = 0; i < kCodecInfoSbcCapability[0] + 1; i++) {
113       ASSERT_EQ(codec_info_result[i], kCodecInfoSbcCapability[i]);
114     }
115     ASSERT_TRUE(a2dp_codecs_->setCodecConfig(kCodecInfoSbcCapability, true, codec_info_result, true));
116     source_codec_config_ = a2dp_codecs_->getCurrentCodecConfig();
117   }
118 
InitializeEncoder(bool peer_supports_3mbps,a2dp_source_read_callback_t read_cb,a2dp_source_enqueue_callback_t enqueue_cb)119   void InitializeEncoder(bool peer_supports_3mbps, a2dp_source_read_callback_t read_cb,
120                          a2dp_source_enqueue_callback_t enqueue_cb) {
121     tA2DP_ENCODER_INIT_PEER_PARAMS peer_params = {true, peer_supports_3mbps, kPeerMtu};
122     encoder_iface_->encoder_init(&peer_params, sink_codec_config_, read_cb,
123                                  enqueue_cb);
124   }
125 
InitializeDecoder(decoded_data_callback_t data_cb)126   void InitializeDecoder(decoded_data_callback_t data_cb) {
127     decoder_iface_->decoder_init(data_cb);
128   }
129 
AllocateL2capPacket(const std::vector<uint8_t> data) const130   BT_HDR* AllocateL2capPacket(const std::vector<uint8_t> data) const {
131     auto packet = AllocatePacket(data.size());
132     std::copy(data.cbegin(), data.cend(), Data(packet));
133     return packet;
134   }
135 
AllocatePacket(size_t packet_length) const136   BT_HDR* AllocatePacket(size_t packet_length) const {
137     BT_HDR* packet =
138         static_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + packet_length));
139     packet->len = packet_length;
140     return packet;
141   }
142   A2dpCodecConfig* sink_codec_config_;
143   A2dpCodecConfig* source_codec_config_;
144   A2dpCodecs* a2dp_codecs_;
145   tA2DP_ENCODER_INTERFACE* encoder_iface_;
146   tA2DP_DECODER_INTERFACE* decoder_iface_;
147 };
148 
TEST_F(A2dpSbcTest,a2dp_source_read_underflow)149 TEST_F(A2dpSbcTest, a2dp_source_read_underflow) {
150   promise = {};
151   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
152     // underflow
153     return 0;
154   };
155   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
156     promise.set_value();
157     osi_free(p_buf);
158     return false;
159   };
160   InitializeEncoder(true, read_cb, enqueue_cb);
161   uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
162   encoder_iface_->send_frames(timestamp_us);
163   usleep(kA2dpTickUs);
164   timestamp_us = bluetooth::common::time_gettimeofday_us();
165   encoder_iface_->send_frames(timestamp_us);
166   ASSERT_EQ(promise.get_future().wait_for(std::chrono::milliseconds(10)),
167             std::future_status::timeout);
168 }
169 
TEST_F(A2dpSbcTest,a2dp_enqueue_cb_is_invoked)170 TEST_F(A2dpSbcTest, a2dp_enqueue_cb_is_invoked) {
171   promise = {};
172   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
173     log::assert_that(kSbcReadSize == len, "assert failed: kSbcReadSize == len");
174     return len;
175   };
176   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
177     static bool first_invocation = true;
178     if (first_invocation) {
179       promise.set_value();
180     }
181     first_invocation = false;
182     osi_free(p_buf);
183     return false;
184   };
185   InitializeEncoder(true, read_cb, enqueue_cb);
186   uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
187   encoder_iface_->send_frames(timestamp_us);
188   usleep(kA2dpTickUs);
189   timestamp_us = bluetooth::common::time_gettimeofday_us();
190   encoder_iface_->send_frames(timestamp_us);
191   promise.get_future().wait();
192 }
193 
TEST_F(A2dpSbcTest,decoded_data_cb_not_invoked_when_empty_packet)194 TEST_F(A2dpSbcTest, decoded_data_cb_not_invoked_when_empty_packet) {
195   auto data_cb = +[](uint8_t* p_buf, uint32_t len) { FAIL(); };
196   InitializeDecoder(data_cb);
197   std::vector<uint8_t> data;
198   BT_HDR* packet = AllocateL2capPacket(data);
199   decoder_iface_->decode_packet(packet);
200   osi_free(packet);
201 }
202 
TEST_F(A2dpSbcTest,decoded_data_cb_invoked)203 TEST_F(A2dpSbcTest, decoded_data_cb_invoked) {
204   promise = {};
205   auto data_cb = +[](uint8_t* p_buf, uint32_t len) {};
206   InitializeDecoder(data_cb);
207 
208   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
209     static uint32_t counter = 0;
210     memcpy(p_buf, wav_reader.GetSamples() + counter, len);
211     counter += len;
212     return len;
213   };
214   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
215     static bool first_invocation = true;
216     if (first_invocation) {
217       packet = reinterpret_cast<BT_HDR*>(
218           osi_malloc(sizeof(*p_buf) + p_buf->len + 1));
219       memcpy(packet, p_buf, sizeof(*p_buf));
220       packet->offset = 0;
221       memcpy(packet->data + 1, p_buf->data + p_buf->offset, p_buf->len);
222       packet->data[0] = frames_n;
223       p_buf->len += 1;
224       promise.set_value();
225     }
226     first_invocation = false;
227     osi_free(p_buf);
228     return false;
229   };
230   InitializeEncoder(true, read_cb, enqueue_cb);
231 
232   uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
233   encoder_iface_->send_frames(timestamp_us);
234 
235   promise.get_future().wait();
236   decoder_iface_->decode_packet(packet);
237   osi_free(packet);
238 }
239 
TEST_F(A2dpSbcTest,set_source_codec_config_works)240 TEST_F(A2dpSbcTest, set_source_codec_config_works) {
241   uint8_t codec_info_result[AVDT_CODEC_SIZE];
242   ASSERT_TRUE(a2dp_codecs_->setCodecConfig(kCodecInfoSbcCapability, true, codec_info_result, true));
243   ASSERT_TRUE(A2DP_CodecTypeEqualsSbc(codec_info_result, kCodecInfoSbcCapability));
244   ASSERT_TRUE(A2DP_CodecEqualsSbc(codec_info_result, kCodecInfoSbcCapability));
245   auto* codec_config = a2dp_codecs_->findSourceCodecConfig(kCodecInfoSbcCapability);
246   ASSERT_EQ(codec_config->name(), source_codec_config_->name());
247   ASSERT_EQ(codec_config->getAudioBitsPerSample(), source_codec_config_->getAudioBitsPerSample());
248 }
249 
TEST_F(A2dpSbcTest,sink_supports_sbc)250 TEST_F(A2dpSbcTest, sink_supports_sbc) {
251   ASSERT_TRUE(A2DP_IsSinkCodecSupportedSbc(kCodecInfoSbcCapability));
252 }
253 
TEST_F(A2dpSbcTest,effective_mtu_when_peer_supports_3mbps)254 TEST_F(A2dpSbcTest, effective_mtu_when_peer_supports_3mbps) {
255   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
256     log::assert_that(kSbcReadSize == len, "assert failed: kSbcReadSize == len");
257     return len;
258   };
259   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
260     osi_free(p_buf);
261     return false;
262   };
263   InitializeEncoder(true, read_cb, enqueue_cb);
264   ASSERT_EQ(a2dp_sbc_get_effective_frame_size(), kPeerMtu);
265 }
266 
TEST_F(A2dpSbcTest,effective_mtu_when_peer_does_not_support_3mbps)267 TEST_F(A2dpSbcTest, effective_mtu_when_peer_does_not_support_3mbps) {
268   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
269     log::assert_that(kSbcReadSize == len, "assert failed: kSbcReadSize == len");
270     return len;
271   };
272   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
273     osi_free(p_buf);
274     return false;
275   };
276   InitializeEncoder(false, read_cb, enqueue_cb);
277   ASSERT_EQ(a2dp_sbc_get_effective_frame_size(), 663 /* MAX_2MBPS_AVDTP_MTU */);
278 }
279 
TEST_F(A2dpSbcTest,codec_info_string)280 TEST_F(A2dpSbcTest, codec_info_string) {
281   auto codec_info = A2DP_CodecInfoString(kCodecInfoSbcCapability);
282   ASSERT_NE(codec_info.find("samp_freq: 44100"), std::string::npos);
283   ASSERT_NE(codec_info.find("ch_mode: Joint"), std::string::npos);
284 }
285 
TEST_F(A2dpSbcTest,get_track_bits_per_sample)286 TEST_F(A2dpSbcTest, get_track_bits_per_sample) {
287   ASSERT_EQ(A2DP_GetTrackBitsPerSampleSbc(kCodecInfoSbcCapability), 16);
288 }
289 
290 }  // namespace testing
291 }  // namespace bluetooth
292