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