• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <base/logging.h>
20 #include <gtest/gtest.h>
21 #include <stdio.h>
22 
23 #include <chrono>
24 #include <cstdint>
25 #include <fstream>
26 #include <future>
27 #include <iomanip>
28 #include <map>
29 #include <string>
30 
31 #include "common/init_flags.h"
32 #include "common/testing/log_capture.h"
33 #include "common/time_util.h"
34 #include "os/log.h"
35 #include "osi/include/allocator.h"
36 #include "osi/test/AllocationTestHarness.h"
37 #include "stack/include/bt_hdr.h"
38 #include "stack/include/a2dp_sbc_decoder.h"
39 #include "stack/include/a2dp_sbc_encoder.h"
40 #include "stack/include/avdt_api.h"
41 #include "test_util.h"
42 #include "wav_reader.h"
43 
44 void allocation_tracker_uninit(void);
45 namespace {
46 constexpr uint32_t kSbcReadSize = 512;
47 constexpr uint32_t kA2dpTickUs = 23 * 1000;
48 constexpr char kWavFile[] = "test/a2dp/raw_data/pcm1644s.wav";
49 constexpr uint16_t kPeerMtu = 1000;
50 const uint8_t kCodecInfoSbcCapability[AVDT_CODEC_SIZE] = {
51     6,                   // Length (A2DP_SBC_INFO_LEN)
52     0,                   // Media Type: AVDT_MEDIA_TYPE_AUDIO
53     0,                   // Media Codec Type: A2DP_MEDIA_CT_SBC
54     0x20 | 0x01,         // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
55                          // Channel Mode: A2DP_SBC_IE_CH_MD_JOINT
56     0x10 | 0x04 | 0x01,  // Block Length: A2DP_SBC_IE_BLOCKS_16 |
57                          // Subbands: A2DP_SBC_IE_SUBBAND_8 |
58                          // Allocation Method: A2DP_SBC_IE_ALLOC_MD_L
59     2,                   // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
60     53,                  // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
61     7,                   // Fake
62     8,                   // Fake
63     9                    // Fake
64 };
Data(BT_HDR * packet)65 uint8_t* Data(BT_HDR* packet) { return packet->data + packet->offset; }
66 }  // namespace
67 
68 namespace bluetooth {
69 namespace testing {
70 
71 static BT_HDR* packet = nullptr;
72 static WavReader wav_reader = WavReader(GetWavFilePath(kWavFile).c_str());
73 static std::promise<void> promise;
74 
75 class A2dpSbcTest : public AllocationTestHarness {
76  protected:
SetUp()77   void SetUp() override {
78     AllocationTestHarness::SetUp();
79     common::InitFlags::SetAllForTesting();
80     // Disable our allocation tracker to allow ASAN full range
81     allocation_tracker_uninit();
82     SetCodecConfig();
83     encoder_iface_ = const_cast<tA2DP_ENCODER_INTERFACE*>(
84         A2DP_GetEncoderInterfaceSbc(kCodecInfoSbcCapability));
85     ASSERT_NE(encoder_iface_, nullptr);
86     decoder_iface_ = const_cast<tA2DP_DECODER_INTERFACE*>(
87         A2DP_GetDecoderInterfaceSbc(kCodecInfoSbcCapability));
88     ASSERT_NE(decoder_iface_, nullptr);
89   }
90 
TearDown()91   void TearDown() override {
92     if (a2dp_codecs_ != nullptr) {
93       delete a2dp_codecs_;
94     }
95     if (encoder_iface_ != nullptr) {
96       encoder_iface_->encoder_cleanup();
97     }
98     A2DP_UnloadEncoderSbc();
99     if (decoder_iface_ != nullptr) {
100       decoder_iface_->decoder_cleanup();
101     }
102     A2DP_UnloadDecoderSbc();
103     AllocationTestHarness::TearDown();
104   }
105 
SetCodecConfig()106   void SetCodecConfig() {
107     uint8_t codec_info_result[AVDT_CODEC_SIZE];
108     btav_a2dp_codec_index_t peer_codec_index;
109     a2dp_codecs_ = new A2dpCodecs(std::vector<btav_a2dp_codec_config_t>());
110 
111     ASSERT_TRUE(a2dp_codecs_->init());
112 
113     // Create the codec capability - SBC Sink
114     memset(codec_info_result, 0, sizeof(codec_info_result));
115     ASSERT_TRUE(A2DP_IsSinkCodecSupportedSbc(kCodecInfoSbcCapability));
116     peer_codec_index = A2DP_SinkCodecIndex(kCodecInfoSbcCapability);
117     ASSERT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
118     sink_codec_config_ = a2dp_codecs_->findSinkCodecConfig(kCodecInfoSbcCapability);
119     ASSERT_NE(sink_codec_config_, nullptr);
120     ASSERT_TRUE(a2dp_codecs_->setSinkCodecConfig(kCodecInfoSbcCapability, true,
121                                                  codec_info_result, true));
122     ASSERT_TRUE(a2dp_codecs_->setPeerSinkCodecCapabilities(kCodecInfoSbcCapability));
123     // Compare the result codec with the local test codec info
124     for (size_t i = 0; i < kCodecInfoSbcCapability[0] + 1; i++) {
125       ASSERT_EQ(codec_info_result[i], kCodecInfoSbcCapability[i]);
126     }
127     ASSERT_TRUE(a2dp_codecs_->setCodecConfig(kCodecInfoSbcCapability, true, codec_info_result, true));
128     source_codec_config_ = a2dp_codecs_->getCurrentCodecConfig();
129   }
130 
InitializeEncoder(bool peer_supports_3mbps,a2dp_source_read_callback_t read_cb,a2dp_source_enqueue_callback_t enqueue_cb)131   void InitializeEncoder(bool peer_supports_3mbps, a2dp_source_read_callback_t read_cb,
132                          a2dp_source_enqueue_callback_t enqueue_cb) {
133     tA2DP_ENCODER_INIT_PEER_PARAMS peer_params = {true, peer_supports_3mbps, kPeerMtu};
134     encoder_iface_->encoder_init(&peer_params, sink_codec_config_, read_cb,
135                                  enqueue_cb);
136   }
137 
InitializeDecoder(decoded_data_callback_t data_cb)138   void InitializeDecoder(decoded_data_callback_t data_cb) {
139     decoder_iface_->decoder_init(data_cb);
140   }
141 
AllocateL2capPacket(const std::vector<uint8_t> data) const142   BT_HDR* AllocateL2capPacket(const std::vector<uint8_t> data) const {
143     auto packet = AllocatePacket(data.size());
144     std::copy(data.cbegin(), data.cend(), Data(packet));
145     return packet;
146   }
147 
AllocatePacket(size_t packet_length) const148   BT_HDR* AllocatePacket(size_t packet_length) const {
149     BT_HDR* packet =
150         static_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + packet_length));
151     packet->len = packet_length;
152     return packet;
153   }
154   A2dpCodecConfig* sink_codec_config_;
155   A2dpCodecConfig* source_codec_config_;
156   A2dpCodecs* a2dp_codecs_;
157   tA2DP_ENCODER_INTERFACE* encoder_iface_;
158   tA2DP_DECODER_INTERFACE* decoder_iface_;
159   std::unique_ptr<LogCapture> log_capture_;
160 };
161 
TEST_F(A2dpSbcTest,a2dp_source_read_underflow)162 TEST_F(A2dpSbcTest, a2dp_source_read_underflow) {
163   promise = {};
164   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
165     // underflow
166     return 0;
167   };
168   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
169     promise.set_value();
170     osi_free(p_buf);
171     return false;
172   };
173   InitializeEncoder(true, read_cb, enqueue_cb);
174   uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
175   encoder_iface_->send_frames(timestamp_us);
176   usleep(kA2dpTickUs);
177   timestamp_us = bluetooth::common::time_gettimeofday_us();
178   encoder_iface_->send_frames(timestamp_us);
179   ASSERT_EQ(promise.get_future().wait_for(std::chrono::milliseconds(10)),
180             std::future_status::timeout);
181 }
182 
TEST_F(A2dpSbcTest,a2dp_enqueue_cb_is_invoked)183 TEST_F(A2dpSbcTest, a2dp_enqueue_cb_is_invoked) {
184   promise = {};
185   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
186     ASSERT(kSbcReadSize == len);
187     return len;
188   };
189   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
190     static bool first_invocation = true;
191     if (first_invocation) {
192       promise.set_value();
193     }
194     first_invocation = false;
195     osi_free(p_buf);
196     return false;
197   };
198   InitializeEncoder(true, read_cb, enqueue_cb);
199   uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
200   encoder_iface_->send_frames(timestamp_us);
201   usleep(kA2dpTickUs);
202   timestamp_us = bluetooth::common::time_gettimeofday_us();
203   encoder_iface_->send_frames(timestamp_us);
204   promise.get_future().wait();
205 }
206 
TEST_F(A2dpSbcTest,decoded_data_cb_not_invoked_when_empty_packet)207 TEST_F(A2dpSbcTest, decoded_data_cb_not_invoked_when_empty_packet) {
208   auto data_cb = +[](uint8_t* p_buf, uint32_t len) { FAIL(); };
209   InitializeDecoder(data_cb);
210   std::vector<uint8_t> data;
211   BT_HDR* packet = AllocateL2capPacket(data);
212   decoder_iface_->decode_packet(packet);
213   osi_free(packet);
214 }
215 
TEST_F(A2dpSbcTest,decoded_data_cb_invoked)216 TEST_F(A2dpSbcTest, decoded_data_cb_invoked) {
217   promise = {};
218   auto data_cb = +[](uint8_t* p_buf, uint32_t len) {};
219   InitializeDecoder(data_cb);
220 
221   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
222     static uint32_t counter = 0;
223     memcpy(p_buf, wav_reader.GetSamples() + counter, len);
224     counter += len;
225     return len;
226   };
227   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
228     static bool first_invocation = true;
229     if (first_invocation) {
230       packet = reinterpret_cast<BT_HDR*>(
231           osi_malloc(sizeof(*p_buf) + p_buf->len + 1));
232       memcpy(packet, p_buf, sizeof(*p_buf));
233       packet->offset = 0;
234       memcpy(packet->data + 1, p_buf->data + p_buf->offset, p_buf->len);
235       packet->data[0] = frames_n;
236       p_buf->len += 1;
237       promise.set_value();
238     }
239     first_invocation = false;
240     osi_free(p_buf);
241     return false;
242   };
243   InitializeEncoder(true, read_cb, enqueue_cb);
244 
245   uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
246   encoder_iface_->send_frames(timestamp_us);
247 
248   promise.get_future().wait();
249   decoder_iface_->decode_packet(packet);
250   osi_free(packet);
251 }
252 
TEST_F(A2dpSbcTest,set_source_codec_config_works)253 TEST_F(A2dpSbcTest, set_source_codec_config_works) {
254   uint8_t codec_info_result[AVDT_CODEC_SIZE];
255   ASSERT_TRUE(a2dp_codecs_->setCodecConfig(kCodecInfoSbcCapability, true, codec_info_result, true));
256   ASSERT_TRUE(A2DP_CodecTypeEqualsSbc(codec_info_result, kCodecInfoSbcCapability));
257   ASSERT_TRUE(A2DP_CodecEqualsSbc(codec_info_result, kCodecInfoSbcCapability));
258   auto* codec_config = a2dp_codecs_->findSourceCodecConfig(kCodecInfoSbcCapability);
259   ASSERT_EQ(codec_config->name(), source_codec_config_->name());
260   ASSERT_EQ(codec_config->getAudioBitsPerSample(), source_codec_config_->getAudioBitsPerSample());
261 }
262 
TEST_F(A2dpSbcTest,sink_supports_sbc)263 TEST_F(A2dpSbcTest, sink_supports_sbc) {
264   ASSERT_TRUE(A2DP_IsSinkCodecSupportedSbc(kCodecInfoSbcCapability));
265 }
266 
TEST_F(A2dpSbcTest,effective_mtu_when_peer_supports_3mbps)267 TEST_F(A2dpSbcTest, effective_mtu_when_peer_supports_3mbps) {
268   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
269     ASSERT(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(true, read_cb, enqueue_cb);
277   ASSERT_EQ(a2dp_sbc_get_effective_frame_size(), kPeerMtu);
278 }
279 
TEST_F(A2dpSbcTest,effective_mtu_when_peer_does_not_support_3mbps)280 TEST_F(A2dpSbcTest, effective_mtu_when_peer_does_not_support_3mbps) {
281   auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
282     ASSERT(kSbcReadSize == len);
283     return len;
284   };
285   auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
286     osi_free(p_buf);
287     return false;
288   };
289   InitializeEncoder(false, read_cb, enqueue_cb);
290   ASSERT_EQ(a2dp_sbc_get_effective_frame_size(), 663 /* MAX_2MBPS_AVDTP_MTU */);
291 }
292 
TEST_F(A2dpSbcTest,debug_codec_dump)293 TEST_F(A2dpSbcTest, debug_codec_dump) {
294   log_capture_ = std::make_unique<LogCapture>();
295   a2dp_codecs_->debug_codec_dump(2);
296   std::promise<void> promise;
297   log_capture_->WaitUntilLogContains(&promise,
298                                      "Current Codec: SBC");
299 }
300 
TEST_F(A2dpSbcTest,codec_info_string)301 TEST_F(A2dpSbcTest, codec_info_string) {
302   auto codec_info = A2DP_CodecInfoString(kCodecInfoSbcCapability);
303   ASSERT_NE(codec_info.find("samp_freq: 44100"), std::string::npos);
304   ASSERT_NE(codec_info.find("ch_mode: Joint"), std::string::npos);
305 }
306 
TEST_F(A2dpSbcTest,get_track_bits_per_sample)307 TEST_F(A2dpSbcTest, get_track_bits_per_sample) {
308   ASSERT_EQ(A2DP_GetTrackBitsPerSampleSbc(kCodecInfoSbcCapability), 16);
309 }
310 
311 }  // namespace testing
312 }  // namespace bluetooth
313