1 /*
2 * Copyright 2020 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
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 #include "devices.h"
19
20 #include <bluetooth/log.h>
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 #include <log/log.h>
24
25 #include "btif_storage_mock.h"
26 #include "btm_api_mock.h"
27 #include "device_groups.h"
28 #include "hardware/bt_le_audio.h"
29 #include "hci/controller_interface_mock.h"
30 #include "le_audio/le_audio_utils.h"
31 #include "le_audio_set_configuration_provider.h"
32 #include "le_audio_types.h"
33 #include "mock_codec_manager.h"
34 #include "mock_csis_client.h"
35 #include "stack/btm/btm_int_types.h"
36 #include "test/mock/mock_main_shim_entry.h"
37
BTM_Sec_GetAddressWithType(const RawAddress & bd_addr)38 const tBLE_BD_ADDR BTM_Sec_GetAddressWithType(const RawAddress& bd_addr) {
39 return tBLE_BD_ADDR{.type = BLE_ADDR_PUBLIC, .bda = bd_addr};
40 }
41
42 namespace bluetooth {
43 namespace le_audio {
44 namespace internal {
45 namespace {
46
47 using ::bluetooth::le_audio::DeviceConnectState;
48 using ::bluetooth::le_audio::LeAudioDevice;
49 using ::bluetooth::le_audio::LeAudioDeviceGroup;
50 using ::bluetooth::le_audio::LeAudioDevices;
51 using ::bluetooth::le_audio::types::AseState;
52 using ::bluetooth::le_audio::types::AudioContexts;
53 using ::bluetooth::le_audio::types::AudioLocations;
54 using ::bluetooth::le_audio::types::BidirectionalPair;
55 using ::bluetooth::le_audio::types::CisType;
56 using ::bluetooth::le_audio::types::LeAudioContextType;
57 using testing::_;
58 using testing::Invoke;
59 using testing::NiceMock;
60 using testing::Return;
61 using testing::Test;
62
63 auto constexpr kVendorCodecIdOne = bluetooth::le_audio::types::LeAudioCodecId(
64 {.coding_format = types::kLeAudioCodingFormatVendorSpecific,
65 .vendor_company_id = 0xF00D,
66 .vendor_codec_id = 0x0001});
67
68 types::CodecConfigSetting kVendorCodecOne = {
69 .id = kVendorCodecIdOne,
70 .params = types::LeAudioLtvMap({
71 // Add the Sampling Freq and AudioChannelAllocation which are
72 // mandatory even for the Vendor codec provider (multicodec AIDL)
73 {codec_spec_conf::kLeAudioLtvTypeSamplingFreq,
74 UINT8_TO_VEC_UINT8(codec_spec_conf::kLeAudioSamplingFreq16000Hz)},
75 }),
76 // Some opaque data buffer
77 .vendor_params = std::vector<uint8_t>({0x01, 0xC0, 0xDE, 0xF0, 0x0D}),
78 .channel_count_per_iso_stream = 1,
79 };
80
81 types::CodecConfigSetting kVendorCodecOneSwb = {
82 .id = kVendorCodecIdOne,
83 .params = types::LeAudioLtvMap({
84 // Add the Sampling Freq and AudioChannelAllocation which are
85 // mandatory even for the Vendor codec provider (multicodec AIDL)
86 {codec_spec_conf::kLeAudioLtvTypeSamplingFreq,
87 UINT8_TO_VEC_UINT8(codec_spec_conf::kLeAudioSamplingFreq32000Hz)},
88 }),
89 // Some opaque data buffer
90 .vendor_params = std::vector<uint8_t>({0x01, 0xC0, 0xDE, 0xF0, 0x0F}),
91 .channel_count_per_iso_stream = 1,
92 };
93
GetTestAddress(int index)94 RawAddress GetTestAddress(int index) {
95 EXPECT_LT(index, UINT8_MAX);
96 RawAddress result = {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, static_cast<uint8_t>(index)}};
97 return result;
98 }
99
100 class LeAudioDevicesTest : public Test {
101 protected:
SetUp()102 void SetUp() override {
103 __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
104 com::android::bluetooth::flags::provider_->reset_flags();
105 devices_ = new LeAudioDevices();
106 bluetooth::manager::SetMockBtmInterface(&btm_interface);
107 bluetooth::storage::SetMockBtifStorageInterface(&mock_btif_storage_);
108 }
109
TearDown()110 void TearDown() override {
111 bluetooth::manager::SetMockBtmInterface(nullptr);
112 bluetooth::storage::SetMockBtifStorageInterface(nullptr);
113 delete devices_;
114 }
115
116 LeAudioDevices* devices_ = nullptr;
117 bluetooth::manager::MockBtmInterface btm_interface;
118 bluetooth::storage::MockBtifStorageInterface mock_btif_storage_;
119 };
120
TEST_F(LeAudioDevicesTest,test_add)121 TEST_F(LeAudioDevicesTest, test_add) {
122 RawAddress test_address_0 = GetTestAddress(0);
123 ASSERT_EQ((size_t)0, devices_->Size());
124 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
125 ASSERT_EQ((size_t)1, devices_->Size());
126 devices_->Add(GetTestAddress(1), DeviceConnectState::CONNECTING_BY_USER, 1);
127 ASSERT_EQ((size_t)2, devices_->Size());
128 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
129 ASSERT_EQ((size_t)2, devices_->Size());
130 devices_->Add(GetTestAddress(1), DeviceConnectState::CONNECTING_BY_USER, 2);
131 ASSERT_EQ((size_t)2, devices_->Size());
132 }
133
TEST_F(LeAudioDevicesTest,test_remove)134 TEST_F(LeAudioDevicesTest, test_remove) {
135 RawAddress test_address_0 = GetTestAddress(0);
136 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
137 RawAddress test_address_1 = GetTestAddress(1);
138 devices_->Add(test_address_1, DeviceConnectState::CONNECTING_BY_USER);
139 RawAddress test_address_2 = GetTestAddress(2);
140 devices_->Add(test_address_2, DeviceConnectState::CONNECTING_BY_USER);
141 ASSERT_EQ((size_t)3, devices_->Size());
142 devices_->Remove(test_address_0);
143 ASSERT_EQ((size_t)2, devices_->Size());
144 devices_->Remove(GetTestAddress(3));
145 ASSERT_EQ((size_t)2, devices_->Size());
146 devices_->Remove(test_address_0);
147 ASSERT_EQ((size_t)2, devices_->Size());
148 }
149
TEST_F(LeAudioDevicesTest,test_find_by_address_success)150 TEST_F(LeAudioDevicesTest, test_find_by_address_success) {
151 RawAddress test_address_0 = GetTestAddress(0);
152 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
153 RawAddress test_address_1 = GetTestAddress(1);
154 devices_->Add(test_address_1, DeviceConnectState::DISCONNECTED);
155 RawAddress test_address_2 = GetTestAddress(2);
156 devices_->Add(test_address_2, DeviceConnectState::CONNECTING_BY_USER);
157 LeAudioDevice* device = devices_->FindByAddress(test_address_1);
158 ASSERT_NE(nullptr, device);
159 ASSERT_EQ(test_address_1, device->address_);
160 }
161
TEST_F(LeAudioDevicesTest,test_find_by_address_failed)162 TEST_F(LeAudioDevicesTest, test_find_by_address_failed) {
163 RawAddress test_address_0 = GetTestAddress(0);
164 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
165 RawAddress test_address_2 = GetTestAddress(2);
166 devices_->Add(test_address_2, DeviceConnectState::CONNECTING_BY_USER);
167 LeAudioDevice* device = devices_->FindByAddress(GetTestAddress(1));
168 ASSERT_EQ(nullptr, device);
169 }
170
TEST_F(LeAudioDevicesTest,test_get_by_address_success)171 TEST_F(LeAudioDevicesTest, test_get_by_address_success) {
172 RawAddress test_address_0 = GetTestAddress(0);
173 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
174 RawAddress test_address_1 = GetTestAddress(1);
175 devices_->Add(test_address_1, DeviceConnectState::DISCONNECTED);
176 RawAddress test_address_2 = GetTestAddress(2);
177 devices_->Add(test_address_2, DeviceConnectState::CONNECTING_BY_USER);
178 std::shared_ptr<LeAudioDevice> device = devices_->GetByAddress(test_address_1);
179 ASSERT_NE(nullptr, device);
180 ASSERT_EQ(test_address_1, device->address_);
181 }
182
TEST_F(LeAudioDevicesTest,test_get_by_address_failed)183 TEST_F(LeAudioDevicesTest, test_get_by_address_failed) {
184 RawAddress test_address_0 = GetTestAddress(0);
185 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
186 RawAddress test_address_2 = GetTestAddress(2);
187 devices_->Add(test_address_2, DeviceConnectState::CONNECTING_BY_USER);
188 std::shared_ptr<LeAudioDevice> device = devices_->GetByAddress(GetTestAddress(1));
189 ASSERT_EQ(nullptr, device);
190 }
191
TEST_F(LeAudioDevicesTest,test_find_by_conn_id_success)192 TEST_F(LeAudioDevicesTest, test_find_by_conn_id_success) {
193 devices_->Add(GetTestAddress(1), DeviceConnectState::CONNECTING_BY_USER);
194 RawAddress test_address_0 = GetTestAddress(0);
195 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
196 devices_->Add(GetTestAddress(4), DeviceConnectState::CONNECTING_BY_USER);
197 LeAudioDevice* device = devices_->FindByAddress(test_address_0);
198 device->conn_id_ = 0x0005;
199 ASSERT_EQ(device, devices_->FindByConnId(0x0005));
200 }
201
TEST_F(LeAudioDevicesTest,test_find_by_conn_id_failed)202 TEST_F(LeAudioDevicesTest, test_find_by_conn_id_failed) {
203 devices_->Add(GetTestAddress(1), DeviceConnectState::CONNECTING_BY_USER);
204 devices_->Add(GetTestAddress(0), DeviceConnectState::CONNECTING_BY_USER);
205 devices_->Add(GetTestAddress(4), DeviceConnectState::CONNECTING_BY_USER);
206 ASSERT_EQ(nullptr, devices_->FindByConnId(0x0006));
207 }
208
TEST_F(LeAudioDevicesTest,test_get_device_model_name_success)209 TEST_F(LeAudioDevicesTest, test_get_device_model_name_success) {
210 RawAddress test_address_0 = GetTestAddress(0);
211 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
212 std::shared_ptr<LeAudioDevice> device = devices_->GetByAddress(test_address_0);
213 ASSERT_NE(nullptr, device);
214 device->model_name_ = "Test";
215 ON_CALL(mock_btif_storage_, GetRemoteDeviceProperty(_, _))
216 .WillByDefault(Return(BT_STATUS_SUCCESS));
217 device->GetDeviceModelName();
218 ASSERT_EQ("", device->model_name_);
219 }
220
TEST_F(LeAudioDevicesTest,test_get_device_model_name_failed)221 TEST_F(LeAudioDevicesTest, test_get_device_model_name_failed) {
222 RawAddress test_address_0 = GetTestAddress(0);
223 devices_->Add(test_address_0, DeviceConnectState::CONNECTING_BY_USER);
224 std::shared_ptr<LeAudioDevice> device = devices_->GetByAddress(test_address_0);
225 ASSERT_NE(nullptr, device);
226 device->model_name_ = "Test";
227 ON_CALL(mock_btif_storage_, GetRemoteDeviceProperty(_, _)).WillByDefault(Return(BT_STATUS_FAIL));
228 device->GetDeviceModelName();
229 ASSERT_EQ("Test", device->model_name_);
230 }
231
232 /* TODO: Add FindByCisConnHdl test cases (ASE) */
233
234 } // namespace
235
236 namespace {
237 using namespace ::bluetooth::le_audio::codec_spec_caps;
238 using namespace ::bluetooth::le_audio::types;
239
240 static const hdl_pair hdl_pair_nil = hdl_pair(0x0000, 0x0000);
241
242 enum class Lc3SettingId {
243 _BEGIN,
244 LC3_8_1 = _BEGIN,
245 LC3_8_2,
246 LC3_16_1,
247 LC3_16_2,
248 LC3_24_1,
249 LC3_24_2,
250 LC3_32_1,
251 LC3_32_2,
252 LC3_441_1,
253 LC3_441_2,
254 LC3_48_1,
255 LC3_48_2,
256 LC3_48_3,
257 LC3_48_4,
258 LC3_48_5,
259 LC3_48_6,
260 LC3_VND_1,
261 _END,
262 UNSUPPORTED = _END,
263 };
264 static constexpr int Lc3SettingIdBegin = static_cast<int>(Lc3SettingId::_BEGIN);
265 static constexpr int Lc3SettingIdEnd = static_cast<int>(Lc3SettingId::_END);
266
IsLc3SettingSupported(LeAudioContextType context_type,Lc3SettingId id)267 bool IsLc3SettingSupported(LeAudioContextType context_type, Lc3SettingId id) {
268 /* Update those values, on any change of codec linked with content type */
269 switch (context_type) {
270 case LeAudioContextType::RINGTONE:
271 case LeAudioContextType::CONVERSATIONAL:
272 if (id == Lc3SettingId::LC3_16_1 || id == Lc3SettingId::LC3_16_2 ||
273 id == Lc3SettingId::LC3_24_1 || id == Lc3SettingId::LC3_24_2 ||
274 id == Lc3SettingId::LC3_32_1 || id == Lc3SettingId::LC3_32_2 ||
275 id == Lc3SettingId::LC3_48_1 || id == Lc3SettingId::LC3_48_2 ||
276 id == Lc3SettingId::LC3_48_3 || id == Lc3SettingId::LC3_48_4 ||
277 id == Lc3SettingId::LC3_VND_1) {
278 return true;
279 }
280
281 break;
282
283 case LeAudioContextType::MEDIA:
284 case LeAudioContextType::ALERTS:
285 case LeAudioContextType::INSTRUCTIONAL:
286 case LeAudioContextType::NOTIFICATIONS:
287 case LeAudioContextType::EMERGENCYALARM:
288 case LeAudioContextType::UNSPECIFIED:
289 if (id == Lc3SettingId::LC3_16_1 || id == Lc3SettingId::LC3_16_2 ||
290 id == Lc3SettingId::LC3_48_4 || id == Lc3SettingId::LC3_48_1 ||
291 id == Lc3SettingId::LC3_48_2 || id == Lc3SettingId::LC3_VND_1 ||
292 id == Lc3SettingId::LC3_24_2) {
293 return true;
294 }
295
296 break;
297
298 default:
299 if (id == Lc3SettingId::LC3_16_2) {
300 return true;
301 }
302
303 break;
304 };
305
306 return false;
307 }
308
309 static constexpr uint8_t kLeAudioSamplingFreqRfu = 0x0E;
GetSamplingFrequency(Lc3SettingId id)310 uint8_t GetSamplingFrequency(Lc3SettingId id) {
311 switch (id) {
312 case Lc3SettingId::LC3_8_1:
313 case Lc3SettingId::LC3_8_2:
314 return codec_spec_conf::kLeAudioSamplingFreq8000Hz;
315 case Lc3SettingId::LC3_16_1:
316 case Lc3SettingId::LC3_16_2:
317 return codec_spec_conf::kLeAudioSamplingFreq16000Hz;
318 case Lc3SettingId::LC3_24_1:
319 case Lc3SettingId::LC3_24_2:
320 return codec_spec_conf::kLeAudioSamplingFreq24000Hz;
321 case Lc3SettingId::LC3_32_1:
322 case Lc3SettingId::LC3_32_2:
323 return codec_spec_conf::kLeAudioSamplingFreq32000Hz;
324 case Lc3SettingId::LC3_441_1:
325 case Lc3SettingId::LC3_441_2:
326 return codec_spec_conf::kLeAudioSamplingFreq44100Hz;
327 case Lc3SettingId::LC3_48_1:
328 case Lc3SettingId::LC3_48_2:
329 case Lc3SettingId::LC3_48_3:
330 case Lc3SettingId::LC3_48_4:
331 case Lc3SettingId::LC3_48_5:
332 case Lc3SettingId::LC3_48_6:
333 case Lc3SettingId::LC3_VND_1:
334 return codec_spec_conf::kLeAudioSamplingFreq48000Hz;
335 case Lc3SettingId::UNSUPPORTED:
336 return kLeAudioSamplingFreqRfu;
337 }
338 }
339
340 static constexpr uint8_t kLeAudioCodecFrameDurRfu = 0x02;
GetFrameDuration(Lc3SettingId id)341 uint8_t GetFrameDuration(Lc3SettingId id) {
342 switch (id) {
343 case Lc3SettingId::LC3_8_1:
344 case Lc3SettingId::LC3_16_1:
345 case Lc3SettingId::LC3_24_1:
346 case Lc3SettingId::LC3_32_1:
347 case Lc3SettingId::LC3_441_1:
348 case Lc3SettingId::LC3_48_1:
349 case Lc3SettingId::LC3_48_3:
350 case Lc3SettingId::LC3_48_5:
351 return codec_spec_conf::kLeAudioCodecFrameDur7500us;
352 case Lc3SettingId::LC3_8_2:
353 case Lc3SettingId::LC3_16_2:
354 case Lc3SettingId::LC3_24_2:
355 case Lc3SettingId::LC3_32_2:
356 case Lc3SettingId::LC3_441_2:
357 case Lc3SettingId::LC3_48_2:
358 case Lc3SettingId::LC3_48_4:
359 case Lc3SettingId::LC3_48_6:
360 case Lc3SettingId::LC3_VND_1:
361 return codec_spec_conf::kLeAudioCodecFrameDur10000us;
362 case Lc3SettingId::UNSUPPORTED:
363 return kLeAudioCodecFrameDurRfu;
364 }
365 }
366
367 static constexpr uint8_t kLeAudioCodecLC3OctetsPerCodecFrameInvalid = 0;
GetOctetsPerCodecFrame(Lc3SettingId id)368 uint16_t GetOctetsPerCodecFrame(Lc3SettingId id) {
369 switch (id) {
370 case Lc3SettingId::LC3_8_1:
371 return 26;
372 case Lc3SettingId::LC3_8_2:
373 case Lc3SettingId::LC3_16_1:
374 return 30;
375 case Lc3SettingId::LC3_16_2:
376 return 40;
377 case Lc3SettingId::LC3_24_1:
378 return 45;
379 case Lc3SettingId::LC3_24_2:
380 case Lc3SettingId::LC3_32_1:
381 return 60;
382 case Lc3SettingId::LC3_32_2:
383 return 80;
384 case Lc3SettingId::LC3_441_1:
385 return 97;
386 case Lc3SettingId::LC3_441_2:
387 return 130;
388 case Lc3SettingId::LC3_48_1:
389 return 75;
390 case Lc3SettingId::LC3_48_2:
391 case Lc3SettingId::LC3_VND_1:
392 return 100;
393 case Lc3SettingId::LC3_48_3:
394 return 90;
395 case Lc3SettingId::LC3_48_4:
396 return 120;
397 case Lc3SettingId::LC3_48_5:
398 return 116;
399 case Lc3SettingId::LC3_48_6:
400 return 155;
401 case Lc3SettingId::UNSUPPORTED:
402 return kLeAudioCodecLC3OctetsPerCodecFrameInvalid;
403 }
404 }
405
406 class PublishedAudioCapabilitiesBuilder {
407 public:
PublishedAudioCapabilitiesBuilder()408 PublishedAudioCapabilitiesBuilder() {}
409
Add(LeAudioCodecId codec_id,uint8_t conf_sampling_frequency,uint8_t conf_frame_duration,uint8_t audio_channel_counts,uint16_t octets_per_frame,uint8_t codec_frames_per_sdu=0)410 void Add(LeAudioCodecId codec_id, uint8_t conf_sampling_frequency, uint8_t conf_frame_duration,
411 uint8_t audio_channel_counts, uint16_t octets_per_frame,
412 uint8_t codec_frames_per_sdu = 0) {
413 uint16_t sampling_frequencies = SamplingFreqConfig2Capability(conf_sampling_frequency);
414 uint8_t frame_durations = FrameDurationConfig2Capability(conf_frame_duration);
415 uint8_t max_codec_frames_per_sdu = codec_frames_per_sdu;
416 uint32_t octets_per_frame_range = octets_per_frame | (octets_per_frame << 16);
417
418 auto ltv_map = LeAudioLtvMap();
419 ltv_map.Add(kLeAudioLtvTypeSupportedSamplingFrequencies, (uint16_t)sampling_frequencies)
420 .Add(kLeAudioLtvTypeSupportedFrameDurations, (uint8_t)frame_durations)
421 .Add(kLeAudioLtvTypeSupportedAudioChannelCounts, (uint8_t)audio_channel_counts)
422 .Add(kLeAudioLtvTypeSupportedOctetsPerCodecFrame, (uint32_t)octets_per_frame_range)
423 .Add(kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu, (uint8_t)max_codec_frames_per_sdu);
424
425 auto record = acs_ac_record(
426 {.codec_id = codec_id,
427 .codec_spec_caps = (codec_id.coding_format != kLeAudioCodingFormatVendorSpecific
428 ? ltv_map
429 : LeAudioLtvMap()),
430 .codec_spec_caps_raw = ltv_map.RawPacket(),
431 .metadata = LeAudioLtvMap()});
432 pac_records_.push_back(record);
433 }
434
Add(LeAudioCodecId codec_id,uint16_t capa_sampling_frequency,uint8_t capa_frame_duration,uint8_t audio_channel_counts,uint16_t octets_per_frame_min,uint16_t ocets_per_frame_max,uint8_t codec_frames_per_sdu=1)435 void Add(LeAudioCodecId codec_id, uint16_t capa_sampling_frequency, uint8_t capa_frame_duration,
436 uint8_t audio_channel_counts, uint16_t octets_per_frame_min,
437 uint16_t ocets_per_frame_max, uint8_t codec_frames_per_sdu = 1) {
438 uint32_t octets_per_frame_range = octets_per_frame_min | (ocets_per_frame_max << 16);
439
440 auto ltv_map = LeAudioLtvMap({
441 {kLeAudioLtvTypeSupportedSamplingFrequencies,
442 UINT16_TO_VEC_UINT8(capa_sampling_frequency)},
443 {kLeAudioLtvTypeSupportedFrameDurations, UINT8_TO_VEC_UINT8(capa_frame_duration)},
444 {kLeAudioLtvTypeSupportedAudioChannelCounts, UINT8_TO_VEC_UINT8(audio_channel_counts)},
445 {kLeAudioLtvTypeSupportedOctetsPerCodecFrame,
446 UINT32_TO_VEC_UINT8(octets_per_frame_range)},
447 {kLeAudioLtvTypeSupportedMaxCodecFramesPerSdu,
448 UINT8_TO_VEC_UINT8(codec_frames_per_sdu)},
449 });
450 pac_records_.push_back(
451 acs_ac_record({.codec_id = codec_id,
452 // Transparent LTV map capabilities only for the LC3 codec
453 .codec_spec_caps = (codec_id.coding_format == kLeAudioCodingFormatLC3)
454 ? ltv_map
455 : LeAudioLtvMap(),
456 .codec_spec_caps_raw = ltv_map.RawPacket(),
457 .metadata = LeAudioLtvMap()}));
458 }
459
Add(LeAudioCodecId codec_id,const std::vector<uint8_t> & vendor_data,uint8_t audio_channel_counts)460 void Add(LeAudioCodecId codec_id, const std::vector<uint8_t>& vendor_data,
461 uint8_t audio_channel_counts) {
462 pac_records_.push_back(
463 acs_ac_record({.codec_id = codec_id,
464 .codec_spec_caps = LeAudioLtvMap({
465 {kLeAudioLtvTypeSupportedAudioChannelCounts,
466 UINT8_TO_VEC_UINT8(audio_channel_counts)},
467 }),
468 // For now assume that vendor representation of codec capabilities
469 // equals the representation of codec settings
470 .codec_spec_caps_raw = vendor_data,
471 .metadata = LeAudioLtvMap()}));
472 }
473
Add(const CodecConfigSetting & setting,uint8_t audio_channel_counts)474 void Add(const CodecConfigSetting& setting, uint8_t audio_channel_counts) {
475 if (setting.id != LeAudioCodecIdLc3) {
476 Add(setting.id, setting.vendor_params, audio_channel_counts);
477 return;
478 }
479
480 const LeAudioCoreCodecConfig core_config = setting.params.GetAsCoreCodecConfig();
481 Add(setting.id, *core_config.sampling_frequency, *core_config.frame_duration,
482 audio_channel_counts, *core_config.octets_per_codec_frame);
483 }
484
Reset()485 void Reset() { pac_records_.clear(); }
486
Get()487 PublishedAudioCapabilities Get() {
488 return PublishedAudioCapabilities({{hdl_pair_nil, pac_records_}});
489 }
490
491 private:
492 std::vector<acs_ac_record> pac_records_;
493 };
494
495 struct TestGroupAseConfigurationData {
496 LeAudioDevice* device;
497 uint8_t audio_channel_counts_snk;
498 uint8_t audio_channel_counts_src;
499
500 /* Note, do not confuse ASEs with channels num. */
501 uint8_t expected_active_channel_num_snk;
502 uint8_t expected_active_channel_num_src;
503 };
504
505 class LeAudioAseConfigurationTest : public Test, public ::testing::WithParamInterface<uint16_t> {
506 protected:
507 uint16_t codec_coding_format_ = 0x0000;
508
SetUp()509 void SetUp() override {
510 __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
511 codec_coding_format_ = GetParam();
512
513 group_ = new LeAudioDeviceGroup(group_id_);
514 desired_group_size_ = -1;
515
516 bluetooth::manager::SetMockBtmInterface(&btm_interface_);
517
518 bluetooth::hci::testing::mock_controller_ =
519 std::make_unique<NiceMock<bluetooth::hci::testing::MockControllerInterface>>();
520
521 auto codec_location = ::bluetooth::le_audio::types::CodecLocation::HOST;
522 bluetooth::le_audio::AudioSetConfigurationProvider::Initialize(codec_location);
523 MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_);
524 ON_CALL(mock_csis_client_module_, Get()).WillByDefault(Return(&mock_csis_client_module_));
525 ON_CALL(mock_csis_client_module_, IsCsisClientRunning()).WillByDefault(Return(true));
526 ON_CALL(mock_csis_client_module_, GetDeviceList(_))
527 .WillByDefault(Invoke([this](int /*group_id*/) { return addresses_; }));
528 ON_CALL(mock_csis_client_module_, GetDesiredSize(_))
529 .WillByDefault(Invoke([this](int /*group_id*/) {
530 return desired_group_size_ > 0 ? desired_group_size_ : (int)(addresses_.size());
531 }));
532 SetUpMockCodecManager(codec_location);
533 }
534
GetVendorAseConfigurationsForRequirements(const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements & requirements,const CodecConfigSetting & codec,uint8_t direction)535 static std::vector<AseConfiguration> GetVendorAseConfigurationsForRequirements(
536 const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements& requirements,
537 const CodecConfigSetting& codec, uint8_t direction) {
538 std::vector<AseConfiguration> ase_confs;
539
540 auto const& required_pacs = (direction == kLeAudioDirectionSink) ? requirements.sink_pacs
541 : requirements.source_pacs;
542 auto direction_requirements = (direction == kLeAudioDirectionSink)
543 ? requirements.sink_requirements
544 : requirements.source_requirements;
545
546 if (std::count_if(required_pacs->begin(), required_pacs->end(),
547 [](auto const& pac) { return pac.codec_spec_caps_raw.empty(); })) {
548 return ase_confs;
549 }
550
551 if (!required_pacs.has_value() || (required_pacs->size() == 0)) {
552 return ase_confs;
553 }
554
555 AseConfiguration endpoint_cfg(codec, {.target_latency = kTargetLatencyLower,
556 .retransmission_number = 3,
557 .max_transport_latency = kMaxTransportLatencyMin});
558
559 // Finding the max channel count
560 uint32_t target_max_channel_counts_per_ase_bitmap = 0b1; // bit 0 - one channel
561 for (auto const& pac : *required_pacs) {
562 auto caps = pac.codec_spec_caps.GetAsCoreCodecCapabilities();
563 if (caps.HasSupportedAudioChannelCounts()) {
564 auto new_counts = caps.supported_audio_channel_counts.value();
565 if (new_counts > target_max_channel_counts_per_ase_bitmap) {
566 target_max_channel_counts_per_ase_bitmap = new_counts;
567 }
568 }
569 }
570
571 uint8_t target_max_channel_counts_per_ase = 0;
572 while (target_max_channel_counts_per_ase_bitmap) {
573 ++target_max_channel_counts_per_ase;
574 target_max_channel_counts_per_ase_bitmap = target_max_channel_counts_per_ase_bitmap >> 1;
575 }
576
577 // For sink we always put a requirement here, but for source there are
578 // some conditions
579 auto sourceAsesNeeded =
580 (!kLeAudioContextAllRemoteSinkOnly.test(requirements.audio_context_type) ||
581 (requirements.audio_context_type == LeAudioContextType::RINGTONE)) &&
582 (requirements.audio_context_type != types::LeAudioContextType::UNSPECIFIED);
583 if ((direction == kLeAudioDirectionSink) || sourceAsesNeeded) {
584 // Create ASE configurations with the proper audio channel allocation
585 uint8_t count = 0;
586 uint32_t allocations = 0;
587 for (auto const& req : *direction_requirements) {
588 auto req_allocations = VEC_UINT8_TO_UINT32(
589 req.params.At(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation));
590
591 // Create the list of requested audio allocations
592 std::list<uint32_t> split_allocations;
593 uint8_t bit_pos = 0;
594 while (req_allocations) {
595 if (req_allocations & 0b1) {
596 split_allocations.push_back(1 << bit_pos);
597 }
598 req_allocations = req_allocations >> 1;
599 bit_pos++;
600 }
601
602 if (split_allocations.empty()) {
603 // Add a single ASE mono configuration
604 endpoint_cfg.codec.params.Add(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation,
605 (uint32_t)codec_spec_conf::kLeAudioLocationMonoAudio);
606 ase_confs.push_back(endpoint_cfg);
607 continue;
608 }
609
610 // Pick a number of allocations from the list (depending on supported
611 // channel counts per ASE) and create an ASE configuration.
612 while (split_allocations.size()) {
613 auto num_of_allocations_per_ase =
614 std::min(target_max_channel_counts_per_ase, (uint8_t)split_allocations.size());
615 // Note: This is very important to set for the unit test
616 // Configuration provider
617 endpoint_cfg.codec.channel_count_per_iso_stream = num_of_allocations_per_ase;
618
619 // Consume the `num_of_allocations_per_ase` amount of allocations for
620 // this particular ASE
621 uint32_t ase_allocations = 0;
622 while (num_of_allocations_per_ase) {
623 ase_allocations |= split_allocations.front();
624 split_allocations.pop_front();
625 --num_of_allocations_per_ase;
626 }
627 endpoint_cfg.codec.params.Add(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation,
628 ase_allocations);
629
630 // Add the ASE configuration
631 ase_confs.push_back(endpoint_cfg);
632 }
633 }
634 }
635
636 return ase_confs;
637 }
638
MockVendorCodecProvider(const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements & requirements)639 static auto MockVendorCodecProvider(
640 const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements& requirements) {
641 AudioSetConfiguration cfg = {
642 .name = "Example Vendor Codec Configuration",
643 .packing = bluetooth::hci::kIsoCigPackingSequential,
644 .confs = {.sink = {}, .source = {}},
645 };
646
647 CodecConfigSetting codec =
648 bluetooth::le_audio::CodecManager::GetInstance()->IsDualBiDirSwbSupported()
649 ? kVendorCodecOneSwb
650 : kVendorCodecOne;
651 if (requirements.sink_requirements) {
652 cfg.confs.sink =
653 GetVendorAseConfigurationsForRequirements(requirements, codec, kLeAudioDirectionSink);
654 }
655
656 if (requirements.source_requirements) {
657 cfg.confs.source = GetVendorAseConfigurationsForRequirements(requirements, codec,
658 kLeAudioDirectionSource);
659 }
660
661 log::debug("{}: snk confs size: {}", cfg.name, cfg.confs.sink.size());
662 log::debug("{}: src confs size: {}", cfg.name, cfg.confs.source.size());
663 return (!cfg.confs.sink.empty() || !cfg.confs.source.empty())
664 ? std::make_unique<AudioSetConfiguration>(cfg)
665 : nullptr;
666 }
667
SetUpMockCodecManager(bluetooth::le_audio::types::CodecLocation location)668 void SetUpMockCodecManager(bluetooth::le_audio::types::CodecLocation location) {
669 codec_manager_ = bluetooth::le_audio::CodecManager::GetInstance();
670 ASSERT_NE(codec_manager_, nullptr);
671 std::vector<bluetooth::le_audio::btle_audio_codec_config_t> mock_offloading_preference(0);
672 codec_manager_->Start(mock_offloading_preference);
673 mock_codec_manager_ = MockCodecManager::GetInstance();
674 ASSERT_NE((void*)mock_codec_manager_, (void*)codec_manager_);
675 ASSERT_NE(mock_codec_manager_, nullptr);
676 ON_CALL(*mock_codec_manager_, GetCodecLocation()).WillByDefault(Return(location));
677
678 // Set up the config provider for the Lc3 codec
679 if (codec_coding_format_ == kLeAudioCodingFormatLC3) {
680 // Regardless of the codec location, return all the possible
681 // configurations
682 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported).WillByDefault(Return(true));
683 }
684
685 ON_CALL(*mock_codec_manager_, GetCodecConfig)
686 .WillByDefault(Invoke(
687 [&](const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements&
688 requirements,
689 bluetooth::le_audio::CodecManager::UnicastConfigurationProvider provider) {
690 if (codec_coding_format_ == kLeAudioCodingFormatLC3) {
691 auto filtered =
692 *bluetooth::le_audio::AudioSetConfigurationProvider::Get()
693 ->GetConfigurations(requirements.audio_context_type);
694 // Filter out the dual bidir SWB configurations
695 if (!bluetooth::le_audio::CodecManager::GetInstance()
696 ->IsDualBiDirSwbSupported()) {
697 filtered.erase(
698 std::remove_if(filtered.begin(), filtered.end(),
699 [](auto const& el) {
700 if (el->confs.source.empty()) {
701 return false;
702 }
703 return AudioSetConfigurationProvider::Get()
704 ->CheckConfigurationIsDualBiDirSwb(*el);
705 }),
706 filtered.end());
707 }
708 auto cfg = provider(requirements, &filtered);
709 if (cfg == nullptr) {
710 return std::unique_ptr<AudioSetConfiguration>(nullptr);
711 }
712 return std::make_unique<AudioSetConfiguration>(*cfg);
713 } else {
714 return MockVendorCodecProvider(requirements);
715 }
716 }));
717
718 ON_CALL(*mock_codec_manager_, CheckCodecConfigIsBiDirSwb)
719 .WillByDefault(
720 Invoke([](const bluetooth::le_audio::types::AudioSetConfiguration& config) {
721 return AudioSetConfigurationProvider::Get()->CheckConfigurationIsBiDirSwb(
722 config);
723 }));
724 ON_CALL(*mock_codec_manager_, CheckCodecConfigIsDualBiDirSwb)
725 .WillByDefault(
726 Invoke([](const bluetooth::le_audio::types::AudioSetConfiguration& config) {
727 return AudioSetConfigurationProvider::Get()->CheckConfigurationIsDualBiDirSwb(
728 config);
729 }));
730 }
731
TearDown()732 void TearDown() override {
733 bluetooth::manager::SetMockBtmInterface(nullptr);
734 devices_.clear();
735 addresses_.clear();
736 delete group_;
737 ::bluetooth::le_audio::AudioSetConfigurationProvider::Cleanup();
738
739 if (mock_codec_manager_) {
740 testing::Mock::VerifyAndClearExpectations(mock_codec_manager_);
741 }
742 if (codec_manager_) {
743 codec_manager_->Stop();
744 }
745
746 bluetooth::hci::testing::mock_controller_.reset();
747 }
748
AddTestDevice(int snk_ase_num,int src_ase_num,int snk_ase_num_cached=0,int src_ase_num_cached=0,bool invert_ases_emplacement=false,bool out_of_range_device=false,std::optional<uint32_t> snk_allocation=kChannelAllocationStereo,std::optional<uint32_t> src_allocation=kChannelAllocationStereo)749 LeAudioDevice* AddTestDevice(int snk_ase_num, int src_ase_num, int snk_ase_num_cached = 0,
750 int src_ase_num_cached = 0, bool invert_ases_emplacement = false,
751 bool out_of_range_device = false,
752 std::optional<uint32_t> snk_allocation = kChannelAllocationStereo,
753 std::optional<uint32_t> src_allocation = kChannelAllocationStereo) {
754 int index = group_->Size() + 1;
755 auto device = (std::make_shared<LeAudioDevice>(GetTestAddress(index),
756 DeviceConnectState::DISCONNECTED));
757 devices_.push_back(device);
758 addresses_.push_back(device->address_);
759 log::info("Number of devices {}", (int)(addresses_.size()));
760
761 if (out_of_range_device == false) {
762 group_->AddNode(device);
763 }
764
765 int ase_id = 1;
766 for (int i = 0; i < (invert_ases_emplacement ? snk_ase_num : src_ase_num); i++) {
767 device->ases_.emplace_back(
768 0x0000, 0x0000,
769 invert_ases_emplacement ? kLeAudioDirectionSink : kLeAudioDirectionSource, ase_id++);
770 }
771
772 for (int i = 0; i < (invert_ases_emplacement ? src_ase_num : snk_ase_num); i++) {
773 device->ases_.emplace_back(
774 0x0000, 0x0000,
775 invert_ases_emplacement ? kLeAudioDirectionSource : kLeAudioDirectionSink, ase_id++);
776 }
777
778 for (int i = 0; i < (invert_ases_emplacement ? snk_ase_num_cached : src_ase_num_cached); i++) {
779 struct ase ase(0x0000, 0x0000,
780 invert_ases_emplacement ? kLeAudioDirectionSink : kLeAudioDirectionSource,
781 ase_id++);
782 ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED;
783 device->ases_.push_back(ase);
784 }
785
786 for (int i = 0; i < (invert_ases_emplacement ? src_ase_num_cached : snk_ase_num_cached); i++) {
787 struct ase ase(0x0000, 0x0000,
788 invert_ases_emplacement ? kLeAudioDirectionSource : kLeAudioDirectionSink,
789 ase_id++);
790 ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED;
791 device->ases_.push_back(ase);
792 }
793
794 device->SetSupportedContexts({.sink = AudioContexts(kLeAudioContextAllTypes),
795 .source = AudioContexts(kLeAudioContextAllTypes)});
796 device->SetAvailableContexts({.sink = AudioContexts(kLeAudioContextAllTypes),
797 .source = AudioContexts(kLeAudioContextAllTypes)});
798
799 if (snk_allocation) {
800 device->audio_locations_.sink.emplace(hdl_pair(0x00ea, 0x0eb),
801 types::AudioLocations(snk_allocation.value()));
802 }
803
804 if (src_allocation) {
805 device->audio_locations_.source.emplace(hdl_pair(0x00fa, 0x00fb),
806 types::AudioLocations(src_allocation.value()));
807 }
808
809 device->conn_id_ = index;
810 device->SetConnectionState(out_of_range_device ? DeviceConnectState::DISCONNECTED
811 : DeviceConnectState::CONNECTED);
812 group_->ReloadAudioDirections();
813 group_->ReloadAudioLocations();
814 return device.get();
815 }
816
AddTestDevice(std::optional<std::pair<int,uint32_t>> sink,std::optional<std::pair<int,uint32_t>> source=std::nullopt)817 LeAudioDevice* AddTestDevice(std::optional<std::pair<int, uint32_t>> sink,
818 std::optional<std::pair<int, uint32_t>> source = std::nullopt) {
819 return AddTestDevice(sink ? sink->first : 0, source ? source->first : 0, 0, 0, false, false,
820 sink ? sink->second : 0, source ? source->second : 0);
821 }
822
TestGroupAseConfigurationVerdict(const TestGroupAseConfigurationData & data,uint8_t directions_to_verify)823 bool TestGroupAseConfigurationVerdict(const TestGroupAseConfigurationData& data,
824 uint8_t directions_to_verify) {
825 BidirectionalPair<uint8_t> active_channel_num = {0, 0};
826
827 if (directions_to_verify == 0) {
828 return false;
829 }
830 if (data.device->HaveActiveAse() == 0) {
831 return false;
832 }
833
834 for (ase* ase = data.device->GetFirstActiveAse(); ase;
835 ase = data.device->GetNextActiveAse(ase)) {
836 active_channel_num.get(ase->direction) += ase->codec_config.channel_count_per_iso_stream;
837 }
838
839 bool result = true;
840 if (directions_to_verify & kLeAudioDirectionSink) {
841 result &= (data.expected_active_channel_num_snk ==
842 active_channel_num.get(kLeAudioDirectionSink));
843 }
844 if (directions_to_verify & kLeAudioDirectionSource) {
845 result &= (data.expected_active_channel_num_src ==
846 active_channel_num.get(kLeAudioDirectionSource));
847 }
848 return result;
849 }
850
SetCisInformationToActiveAse(void)851 void SetCisInformationToActiveAse(void) {
852 uint8_t cis_id = 1;
853 uint16_t cis_conn_hdl = 0x0060;
854
855 for (auto& device : devices_) {
856 for (auto& ase : device->ases_) {
857 if (ase.active) {
858 ase.cis_id = cis_id++;
859 ase.cis_conn_hdl = cis_conn_hdl++;
860 }
861 }
862 }
863 }
864
PreparePreferredCodecConfig(const CodecConfigSetting & audio_set_codec_conf,const btle_audio_codec_config_t & preferred_config)865 const CodecConfigSetting PreparePreferredCodecConfig(
866 const CodecConfigSetting& audio_set_codec_conf,
867 const btle_audio_codec_config_t& preferred_config) {
868 constexpr uint8_t supported_codec_frames_per_sdu = 1;
869 return {.id = LeAudioCodecIdLc3,
870 .params = LeAudioLtvMap({
871 {codec_spec_conf::kLeAudioLtvTypeSamplingFreq,
872 UINT8_TO_VEC_UINT8(codec_spec_conf::SingleSamplingFreqCapability2Config(
873 preferred_config.sample_rate))},
874 {codec_spec_conf::kLeAudioLtvTypeFrameDuration,
875 UINT8_TO_VEC_UINT8(codec_spec_conf::SingleFrameDurationCapability2Config(
876 preferred_config.frame_duration))},
877 {codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame,
878 UINT16_TO_VEC_UINT8(preferred_config.octets_per_frame)},
879 {codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
880 UINT8_TO_VEC_UINT8(supported_codec_frames_per_sdu)},
881 }),
882 .channel_count_per_iso_stream = audio_set_codec_conf.GetChannelCountPerIsoStream()};
883 }
884
TestSingleAseConfiguration(LeAudioContextType context_type,TestGroupAseConfigurationData * data,uint8_t data_size,const AudioSetConfiguration * audio_set_conf,uint8_t directions_to_verify)885 void TestSingleAseConfiguration(LeAudioContextType context_type,
886 TestGroupAseConfigurationData* data, uint8_t data_size,
887 const AudioSetConfiguration* audio_set_conf,
888 uint8_t directions_to_verify) {
889 // the configuration should fail if there are no active ases expected
890 bool success_expected = data_size > 0;
891 uint8_t configuration_directions = 0;
892
893 for (int i = 0; i < data_size; i++) {
894 success_expected &= (data[i].expected_active_channel_num_snk +
895 data[i].expected_active_channel_num_src) > 0;
896
897 /* Prepare PAC's */
898 PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder;
899 for (const auto& entry : (*audio_set_conf).confs.sink) {
900 configuration_directions |= kLeAudioDirectionSink;
901 snk_pac_builder.Add(entry.codec, data[i].audio_channel_counts_snk);
902 }
903 for (const auto& entry : (*audio_set_conf).confs.source) {
904 configuration_directions |= kLeAudioDirectionSource;
905 src_pac_builder.Add(entry.codec, data[i].audio_channel_counts_src);
906 }
907
908 data[i].device->snk_pacs_ = snk_pac_builder.Get();
909 data[i].device->src_pacs_ = src_pac_builder.Get();
910 }
911
912 BidirectionalPair<AudioContexts> group_audio_locations = {
913 .sink = AudioContexts(context_type), .source = AudioContexts(context_type)};
914
915 ASSERT_EQ(success_expected, group_->Configure(context_type, group_audio_locations));
916
917 bool result = true;
918 for (int i = 0; i < data_size; i++) {
919 result &= TestGroupAseConfigurationVerdict(data[i],
920 directions_to_verify & configuration_directions);
921 }
922 ASSERT_TRUE(result);
923 }
924
getNumOfAses(LeAudioDevice * device,uint8_t direction)925 int getNumOfAses(LeAudioDevice* device, uint8_t direction) {
926 return std::count_if(device->ases_.begin(), device->ases_.end(),
927 [direction](auto& a) { return a.direction == direction; });
928 }
929
TestGroupAseVendorConfiguration(LeAudioContextType context_type,TestGroupAseConfigurationData * data,uint8_t data_size,uint8_t directions_to_verify=kLeAudioDirectionSink|kLeAudioDirectionSource)930 void TestGroupAseVendorConfiguration(LeAudioContextType context_type,
931 TestGroupAseConfigurationData* data, uint8_t data_size,
932 uint8_t directions_to_verify = kLeAudioDirectionSink |
933 kLeAudioDirectionSource) {
934 for (int i = 0; i < data_size; i++) {
935 /* Add PACs and check if each of the devices has activated ASEs as
936 * expected */
937 PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder;
938
939 // Prepare the PACs
940 for (auto direction : {kLeAudioDirectionSink, kLeAudioDirectionSource}) {
941 auto const& data_channel_counts = (direction == kLeAudioDirectionSink)
942 ? data[i].audio_channel_counts_snk
943 : data[i].audio_channel_counts_src;
944
945 PublishedAudioCapabilitiesBuilder pac_builder;
946 for (auto codec : {kVendorCodecOne, kVendorCodecOneSwb}) {
947 codec.channel_count_per_iso_stream = data_channel_counts;
948 pac_builder.Add(codec, data_channel_counts);
949 }
950
951 // Set the PACs
952 auto& dest_pacs = (direction == kLeAudioDirectionSink) ? data[i].device->snk_pacs_
953 : data[i].device->src_pacs_;
954 dest_pacs = pac_builder.Get();
955 }
956 }
957
958 // Verify if ASEs are configured
959 BidirectionalPair<AudioContexts> metadata = {.sink = AudioContexts(context_type),
960 .source = AudioContexts(context_type)};
961 ASSERT_EQ(true, group_->Configure(context_type, metadata));
962
963 for (int i = 0; i < data_size; i++) {
964 ASSERT_TRUE(TestGroupAseConfigurationVerdict(data[i], directions_to_verify));
965 }
966
967 group_->Deactivate();
968 TestAsesInactive();
969 }
970
TestGroupAseConfiguration(LeAudioContextType context_type,TestGroupAseConfigurationData * data,uint8_t data_size,uint8_t directions_to_verify=kLeAudioDirectionSink|kLeAudioDirectionSource,btle_audio_codec_config_t * preferred_codec_config=nullptr,bool should_use_preferred_codec=false)971 void TestGroupAseConfiguration(LeAudioContextType context_type,
972 TestGroupAseConfigurationData* data, uint8_t data_size,
973 uint8_t directions_to_verify = kLeAudioDirectionSink |
974 kLeAudioDirectionSource,
975 btle_audio_codec_config_t* preferred_codec_config = nullptr,
976 bool should_use_preferred_codec = false) {
977 if (codec_coding_format_ != kLeAudioCodingFormatLC3) {
978 return TestGroupAseVendorConfiguration(context_type, data, data_size, directions_to_verify);
979 }
980
981 const auto* configurations =
982 ::bluetooth::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations(
983 context_type);
984
985 bool is_expected_to_match_config = directions_to_verify != 0;
986 int num_of_matching_configurations = 0;
987 for (const auto& audio_set_conf : *configurations) {
988 bool interesting_configuration = true;
989 uint8_t expected_configuration_directions = 0;
990
991 /* Let's go thru devices in the group and configure them*/
992 for (int i = 0; i < data_size; i++) {
993 BidirectionalPair<int> num_of_ase{0, 0};
994
995 /* Prepare PAC's for each device. Also make sure configuration is in our
996 * interest to test */
997 for (auto direction : {kLeAudioDirectionSink, kLeAudioDirectionSource}) {
998 auto const& ase_confs = audio_set_conf->confs;
999 if (ase_confs.get(direction).size() == 0) {
1000 // Skip the direction if not available
1001 continue;
1002 }
1003
1004 /* Make sure the strategy is the expected one */
1005 auto ase_config_strategy = bluetooth::le_audio::utils::GetStrategyForAseConfig(
1006 ase_confs.get(direction), data_size);
1007 if (group_->GetGroupSinkStrategy() != ase_config_strategy) {
1008 log::debug("Sink strategy mismatch group!=cfg.entry ({}!={})",
1009 static_cast<int>(group_->GetGroupSinkStrategy()),
1010 static_cast<int>(ase_config_strategy));
1011 interesting_configuration = false;
1012 }
1013
1014 auto& dest_pacs = (direction == kLeAudioDirectionSink) ? data[i].device->snk_pacs_
1015 : data[i].device->src_pacs_;
1016 auto const& pacs_data_channel_counts = (direction == kLeAudioDirectionSink)
1017 ? data[i].audio_channel_counts_snk
1018 : data[i].audio_channel_counts_src;
1019
1020 if (((direction == kLeAudioDirectionSink)
1021 ? data[i].expected_active_channel_num_snk
1022 : data[i].expected_active_channel_num_src) > 0) {
1023 expected_configuration_directions |= direction;
1024 }
1025
1026 /* Add PAC records */
1027 PublishedAudioCapabilitiesBuilder pac_builder;
1028 for (const auto& entry : ase_confs.get(direction)) {
1029 pac_builder.Add(entry.codec, pacs_data_channel_counts);
1030 if (preferred_codec_config && should_use_preferred_codec) {
1031 const auto customized_codec_config =
1032 PreparePreferredCodecConfig(entry.codec, *preferred_codec_config);
1033 pac_builder.Add(customized_codec_config, pacs_data_channel_counts);
1034 }
1035 dest_pacs = pac_builder.Get();
1036 }
1037 num_of_ase.get(direction) += ase_confs.get(direction).size();
1038 num_of_ase.get(direction) /= data_size;
1039 }
1040
1041 /* Make sure configuration can satisfy number of expected active ASEs*/
1042 if (num_of_ase.sink > data[i].device->GetAseCount(kLeAudioDirectionSink)) {
1043 interesting_configuration = false;
1044 }
1045
1046 if (num_of_ase.source > data[i].device->GetAseCount(kLeAudioDirectionSource)) {
1047 interesting_configuration = false;
1048 }
1049 }
1050
1051 /* Set preferred codec*/
1052 if (preferred_codec_config) {
1053 group_->SetPreferredAudioSetConfiguration(*preferred_codec_config, *preferred_codec_config);
1054 }
1055
1056 group_->UpdateAudioSetConfigurationCache(context_type);
1057
1058 BidirectionalPair<AudioContexts> group_audio_locations = {
1059 .sink = AudioContexts(context_type), .source = AudioContexts(context_type)};
1060 auto configuration_result = group_->Configure(context_type, group_audio_locations);
1061
1062 /* In case of configuration #ase is same as the one we expected to be
1063 * activated verify, ASEs are actually active */
1064 uint8_t configuration_directions =
1065 (audio_set_conf->confs.sink.size() ? kLeAudioDirectionSink : 0) |
1066 (audio_set_conf->confs.source.size() ? kLeAudioDirectionSource : 0);
1067
1068 if (interesting_configuration &&
1069 (expected_configuration_directions == configuration_directions)) {
1070 ASSERT_TRUE(configuration_result);
1071 ASSERT_EQ(group_->GetPreferredConfiguration(context_type) != nullptr,
1072 should_use_preferred_codec);
1073 ASSERT_EQ(group_->IsUsingPreferredAudioSetConfiguration(context_type),
1074 should_use_preferred_codec);
1075 bool matching_conf = true;
1076 /* Check if each of the devices has activated ASEs as expected */
1077 for (int i = 0; i < data_size; i++) {
1078 matching_conf &= TestGroupAseConfigurationVerdict(data[i], configuration_directions);
1079 }
1080
1081 if (matching_conf) {
1082 num_of_matching_configurations++;
1083 }
1084 }
1085 group_->Deactivate();
1086
1087 TestAsesInactive();
1088 }
1089
1090 if (is_expected_to_match_config) {
1091 ASSERT_GT(num_of_matching_configurations, 0);
1092 } else {
1093 ASSERT_EQ(0, num_of_matching_configurations);
1094 }
1095 }
1096
TestGroupAseConfiguration(LeAudioContextType context_type,std::vector<TestGroupAseConfigurationData> data,uint8_t directions_to_verify=kLeAudioDirectionSink|kLeAudioDirectionSource,btle_audio_codec_config_t * preferred_codec_config=nullptr,bool should_use_preferred_codec=false)1097 auto TestGroupAseConfiguration(LeAudioContextType context_type,
1098 std::vector<TestGroupAseConfigurationData> data,
1099 uint8_t directions_to_verify = kLeAudioDirectionSink |
1100 kLeAudioDirectionSource,
1101 btle_audio_codec_config_t* preferred_codec_config = nullptr,
1102 bool should_use_preferred_codec = false) {
1103 return TestGroupAseConfiguration(context_type, data.data(), data.size(), directions_to_verify,
1104 preferred_codec_config, should_use_preferred_codec);
1105 }
1106
TestAsesActive(LeAudioCodecId codec_id,uint8_t sampling_frequency,uint8_t frame_duration,uint16_t octets_per_frame,uint8_t codec_frame_blocks_per_sdu=1)1107 void TestAsesActive(LeAudioCodecId codec_id, uint8_t sampling_frequency, uint8_t frame_duration,
1108 uint16_t octets_per_frame, uint8_t codec_frame_blocks_per_sdu = 1) {
1109 bool active_ase = false;
1110
1111 for (const auto& device : devices_) {
1112 for (const auto& ase : device->ases_) {
1113 if (!ase.active) {
1114 continue;
1115 }
1116
1117 /* Configure may request only partial ases to be activated */
1118 if (!active_ase && ase.active) {
1119 active_ase = true;
1120 }
1121
1122 ASSERT_EQ(ase.codec_config.id, codec_id);
1123
1124 /* FIXME: Validate other codec parameters than LC3 if any */
1125 ASSERT_EQ(ase.codec_config.id, LeAudioCodecIdLc3);
1126 if (ase.codec_config.id == LeAudioCodecIdLc3) {
1127 auto core_config = ase.codec_config.params.GetAsCoreCodecConfig();
1128 ASSERT_EQ(core_config.sampling_frequency, sampling_frequency);
1129 ASSERT_EQ(core_config.frame_duration, frame_duration);
1130 ASSERT_EQ(core_config.octets_per_codec_frame, octets_per_frame);
1131 ASSERT_EQ(core_config.codec_frames_blocks_per_sdu.value_or(0),
1132 codec_frame_blocks_per_sdu);
1133 }
1134 }
1135 }
1136
1137 ASSERT_TRUE(active_ase);
1138 }
1139
TestActiveAses(void)1140 void TestActiveAses(void) {
1141 for (auto& device : devices_) {
1142 for (const auto& ase : device->ases_) {
1143 if (ase.active) {
1144 ASSERT_FALSE(ase.cis_id == ::bluetooth::le_audio::kInvalidCisId);
1145 }
1146 }
1147 }
1148 }
1149
TestAsesInactivated(const LeAudioDevice * device)1150 void TestAsesInactivated(const LeAudioDevice* device) {
1151 for (const auto& ase : device->ases_) {
1152 ASSERT_FALSE(ase.active);
1153 ASSERT_TRUE(ase.cis_id == ::bluetooth::le_audio::kInvalidCisId);
1154 ASSERT_TRUE(ase.cis_conn_hdl == ::bluetooth::le_audio::kInvalidCisConnHandle);
1155 }
1156 }
1157
TestAsesInactive()1158 void TestAsesInactive() {
1159 for (const auto& device : devices_) {
1160 for (const auto& ase : device->ases_) {
1161 ASSERT_FALSE(ase.active);
1162 }
1163 }
1164 }
1165
TestLc3CodecConfig(LeAudioContextType context_type,uint8_t max_codec_frames_per_sdu=1)1166 void TestLc3CodecConfig(LeAudioContextType context_type, uint8_t max_codec_frames_per_sdu = 1) {
1167 for (int i = Lc3SettingIdBegin; i < Lc3SettingIdEnd; i++) {
1168 // test each configuration parameter against valid and invalid value
1169 std::array<Lc3SettingId, 2> test_variants = {static_cast<Lc3SettingId>(i),
1170 Lc3SettingId::UNSUPPORTED};
1171
1172 const bool is_lc3_setting_supported =
1173 IsLc3SettingSupported(context_type, static_cast<Lc3SettingId>(i));
1174
1175 for (const auto sf_variant : test_variants) {
1176 uint8_t sampling_frequency = GetSamplingFrequency(sf_variant);
1177 for (const auto fd_variant : test_variants) {
1178 uint8_t frame_duration = GetFrameDuration(fd_variant);
1179 for (const auto opcf_variant : test_variants) {
1180 uint16_t octets_per_frame = GetOctetsPerCodecFrame(opcf_variant);
1181
1182 PublishedAudioCapabilitiesBuilder pac_builder;
1183 pac_builder.Add(
1184 LeAudioCodecIdLc3, sampling_frequency, frame_duration,
1185 kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel,
1186 octets_per_frame, max_codec_frames_per_sdu);
1187 for (auto& device : devices_) {
1188 /* For simplicity configure both PACs with the same
1189 parameters*/
1190 device->snk_pacs_ = pac_builder.Get();
1191 device->src_pacs_ = pac_builder.Get();
1192 }
1193
1194 bool success_expected = is_lc3_setting_supported;
1195 if (is_lc3_setting_supported && (sf_variant == Lc3SettingId::UNSUPPORTED ||
1196 fd_variant == Lc3SettingId::UNSUPPORTED ||
1197 opcf_variant == Lc3SettingId::UNSUPPORTED)) {
1198 success_expected = false;
1199 }
1200
1201 group_->UpdateAudioSetConfigurationCache(context_type);
1202 BidirectionalPair<AudioContexts> group_audio_locations = {
1203 .sink = AudioContexts(context_type), .source = AudioContexts(context_type)};
1204 ASSERT_EQ(success_expected, group_->Configure(context_type, group_audio_locations));
1205 if (success_expected) {
1206 TestAsesActive(LeAudioCodecIdLc3, sampling_frequency, frame_duration,
1207 octets_per_frame, max_codec_frames_per_sdu);
1208 group_->Deactivate();
1209 }
1210
1211 TestAsesInactive();
1212 }
1213 }
1214 }
1215 }
1216 }
1217
TestSingleDevDualBidir(LeAudioDevice * device,LeAudioContextType context_type)1218 void TestSingleDevDualBidir(LeAudioDevice* device, LeAudioContextType context_type) {
1219 // Build PACs for device
1220 PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder;
1221 snk_pac_builder.Reset();
1222 src_pac_builder.Reset();
1223
1224 const uint32_t supported_octets_per_codec_frame_80 = 80;
1225 const uint32_t supported_octets_per_codec_frame_40 = 40;
1226 const uint32_t supported_codec_frames_per_sdu = 1;
1227 CodecConfigSetting swb = {
1228 .id = LeAudioCodecIdLc3,
1229 .params = LeAudioLtvMap({
1230 {codec_spec_conf::kLeAudioLtvTypeSamplingFreq,
1231 UINT8_TO_VEC_UINT8(codec_spec_conf::kLeAudioSamplingFreq32000Hz)},
1232 {codec_spec_conf::kLeAudioLtvTypeFrameDuration,
1233 UINT8_TO_VEC_UINT8(codec_spec_conf::kLeAudioCodecFrameDur10000us)},
1234 {codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame,
1235 UINT16_TO_VEC_UINT8(supported_octets_per_codec_frame_80)},
1236 {codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
1237 UINT8_TO_VEC_UINT8(supported_codec_frames_per_sdu)},
1238 }),
1239 .channel_count_per_iso_stream = 1};
1240
1241 auto swb_config = AudioSetConfiguration({
1242 .name = "Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_SWB",
1243 .confs = {.sink = {AseConfiguration(swb), AseConfiguration(swb)},
1244 .source = {AseConfiguration(swb), AseConfiguration(swb)}},
1245 });
1246
1247 auto swb_config_single = AudioSetConfiguration({
1248 .name = "One-OneChan-SnkAse-Lc3_32_2-One-OneChan-SrcAse-Lc3_32_2_SWB",
1249 .confs = {.sink =
1250 {
1251 AseConfiguration(swb),
1252 },
1253 .source =
1254 {
1255 AseConfiguration(swb),
1256 }},
1257 });
1258
1259 ASSERT_FALSE(swb.params.IsEmpty());
1260 ASSERT_TRUE(swb.params.Find(codec_spec_conf::kLeAudioLtvTypeSamplingFreq).has_value());
1261
1262 CodecConfigSetting non_swb = {
1263 .id = LeAudioCodecIdLc3,
1264 .params = LeAudioLtvMap({
1265 {codec_spec_conf::kLeAudioLtvTypeSamplingFreq,
1266 UINT8_TO_VEC_UINT8(codec_spec_conf::kLeAudioSamplingFreq16000Hz)},
1267 {codec_spec_conf::kLeAudioLtvTypeFrameDuration,
1268 UINT8_TO_VEC_UINT8(codec_spec_conf::kLeAudioCodecFrameDur10000us)},
1269 {codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame,
1270 UINT16_TO_VEC_UINT8(supported_octets_per_codec_frame_40)},
1271 {codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
1272 UINT8_TO_VEC_UINT8(supported_codec_frames_per_sdu)},
1273 }),
1274 .channel_count_per_iso_stream = 1};
1275 auto non_swb_config = AudioSetConfiguration({
1276 .name = "Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_NON_SWB",
1277 .confs = {.sink = {AseConfiguration(non_swb), AseConfiguration(non_swb)},
1278 .source = {AseConfiguration(non_swb), AseConfiguration(non_swb)}},
1279 });
1280 auto non_swb_config_single = AudioSetConfiguration({
1281 .name = "One-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_NON_SWB",
1282 .confs = {.sink = {AseConfiguration(non_swb)}, .source = {AseConfiguration(non_swb)}},
1283 });
1284 AudioSetConfigurations configs = {
1285 {&swb_config, &swb_config_single, &non_swb_config, &non_swb_config_single}};
1286
1287 // Support single channel per ASE to activate two ASES on both direction
1288 for (auto config : configs) {
1289 for (const auto& entry : config->confs.sink) {
1290 snk_pac_builder.Add(entry.codec, kLeAudioCodecChannelCountSingleChannel);
1291 }
1292 for (const auto& entry : config->confs.source) {
1293 src_pac_builder.Add(entry.codec, kLeAudioCodecChannelCountSingleChannel);
1294 }
1295 }
1296
1297 // Inject `configs` as there's no such config in the json file
1298 ON_CALL(*mock_codec_manager_, GetCodecConfig)
1299 .WillByDefault(Invoke([&configs](const bluetooth::le_audio::CodecManager::
1300 UnicastConfigurationRequirements& requirements,
1301 bluetooth::le_audio::CodecManager::
1302 UnicastConfigurationProvider provider) {
1303 auto filtered = configs;
1304 // Filter out the dual bidir SWB configurations
1305 if (!bluetooth::le_audio::CodecManager::GetInstance()->IsDualBiDirSwbSupported()) {
1306 filtered.erase(std::remove_if(filtered.begin(), filtered.end(),
1307 [](auto const& el) {
1308 if (el->confs.source.empty()) {
1309 return false;
1310 }
1311 return AudioSetConfigurationProvider::Get()
1312 ->CheckConfigurationIsDualBiDirSwb(*el);
1313 }),
1314 filtered.end());
1315 }
1316 auto cfg = provider(requirements, &filtered);
1317 if (cfg == nullptr) {
1318 return std::unique_ptr<AudioSetConfiguration>(nullptr);
1319 }
1320 return std::make_unique<AudioSetConfiguration>(*cfg);
1321 }));
1322
1323 // Make two ASES available in both directions with equal capabilities
1324 device->snk_pacs_ = snk_pac_builder.Get();
1325 device->src_pacs_ = src_pac_builder.Get();
1326
1327 ASSERT_TRUE(group_->Configure(context_type, {.sink = AudioContexts(context_type),
1328 .source = AudioContexts(context_type)}));
1329
1330 // Verify Dual-Bidir - the amount of ASES configured
1331 TestGroupAseConfigurationData data[] = {{device, kLeAudioCodecChannelCountSingleChannel,
1332 kLeAudioCodecChannelCountSingleChannel, 2, 2}};
1333 TestGroupAseConfigurationVerdict(data[0], kLeAudioDirectionSink | kLeAudioDirectionSource);
1334 }
1335
1336 /* Helper */
getSpecificConfiguration(const char * config_name,LeAudioContextType context)1337 static const AudioSetConfiguration* getSpecificConfiguration(const char* config_name,
1338 LeAudioContextType context) {
1339 auto all_configurations =
1340 ::bluetooth::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations(context);
1341
1342 if (all_configurations == nullptr) {
1343 return nullptr;
1344 }
1345 if (all_configurations->end() == all_configurations->begin()) {
1346 return nullptr;
1347 }
1348
1349 auto iter = std::find_if(
1350 all_configurations->begin(), all_configurations->end(),
1351 [config_name](auto& configuration) { return configuration->name == config_name; });
1352 if (iter == all_configurations->end()) {
1353 return nullptr;
1354 }
1355 return *iter;
1356 }
1357
TestDualDevDualBidir(LeAudioDevice * left,LeAudioDevice * right,LeAudioContextType context_type)1358 void TestDualDevDualBidir(LeAudioDevice* left, LeAudioDevice* right,
1359 LeAudioContextType context_type) {
1360 // Build PACs for device
1361 PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder;
1362 snk_pac_builder.Reset();
1363 src_pac_builder.Reset();
1364
1365 /* Create PACs for conversational scenario, SWB and non SWB */
1366 for (auto config :
1367 {getSpecificConfiguration("Two-OneChan-SnkAse-Lc3_16_2-Two-OneChan-SrcAse-Lc3_16_2_1",
1368 context_type),
1369 getSpecificConfiguration("Two-OneChan-SnkAse-Lc3_32_2-Two-OneChan-SrcAse-Lc3_32_2_1",
1370 context_type)}) {
1371 ASSERT_NE(nullptr, config);
1372 for (const auto& entry : (*config).confs.sink) {
1373 snk_pac_builder.Add(entry.codec, kLeAudioCodecChannelCountSingleChannel);
1374 }
1375 for (const auto& entry : (*config).confs.source) {
1376 src_pac_builder.Add(entry.codec, kLeAudioCodecChannelCountSingleChannel);
1377 }
1378 }
1379
1380 // Add pacs for remote to support the configs above
1381 for (auto& dev : {left, right}) {
1382 dev->snk_pacs_ = snk_pac_builder.Get();
1383 dev->src_pacs_ = src_pac_builder.Get();
1384 }
1385
1386 /* Change location as by default it is stereo */
1387 left->audio_locations_.sink->value = codec_spec_conf::kLeAudioLocationFrontLeft;
1388 left->audio_locations_.source->value = codec_spec_conf::kLeAudioLocationFrontLeft;
1389 right->audio_locations_.sink->value = codec_spec_conf::kLeAudioLocationFrontRight;
1390 right->audio_locations_.source->value = codec_spec_conf::kLeAudioLocationFrontRight;
1391 group_->ReloadAudioLocations();
1392
1393 ASSERT_TRUE(group_->Configure(context_type, {.sink = AudioContexts(context_type),
1394 .source = AudioContexts(context_type)}));
1395
1396 // Verify the amount of ASES configured
1397 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
1398 kLeAudioCodecChannelCountSingleChannel, 1, 1},
1399 {right, kLeAudioCodecChannelCountSingleChannel,
1400 kLeAudioCodecChannelCountSingleChannel, 1, 1}};
1401 TestGroupAseConfigurationVerdict(data[0], kLeAudioDirectionSink | kLeAudioDirectionSource);
1402 TestGroupAseConfigurationVerdict(data[1], kLeAudioDirectionSink | kLeAudioDirectionSource);
1403 }
1404
SetAsesToCachedConfiguration(LeAudioDevice * device,LeAudioContextType context_type,uint8_t directions)1405 void SetAsesToCachedConfiguration(LeAudioDevice* device, LeAudioContextType context_type,
1406 uint8_t directions) {
1407 for (struct ase& ase : device->ases_) {
1408 if (ase.direction & directions) {
1409 ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED;
1410 ase.active = false;
1411 ase.configured_for_context_type = context_type;
1412 }
1413 }
1414 }
1415
1416 const int group_id_ = 6;
1417 int desired_group_size_ = -1;
1418
1419 std::vector<std::shared_ptr<LeAudioDevice>> devices_;
1420 std::vector<RawAddress> addresses_;
1421 LeAudioDeviceGroup* group_ = nullptr;
1422 bluetooth::manager::MockBtmInterface btm_interface_;
1423 MockCsisClient mock_csis_client_module_;
1424
1425 bluetooth::le_audio::CodecManager* codec_manager_;
1426 MockCodecManager* mock_codec_manager_;
1427 };
1428
TEST_P(LeAudioAseConfigurationTest,test_context_update)1429 TEST_P(LeAudioAseConfigurationTest, test_context_update) {
1430 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1431 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1432 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
1433 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
1434
1435 ASSERT_EQ(2, group_->Size());
1436
1437 /* Put the PACS */
1438 auto conversational_configuration = getSpecificConfiguration(
1439 "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
1440 LeAudioContextType::CONVERSATIONAL);
1441 auto media_configuration = getSpecificConfiguration(
1442 "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability", LeAudioContextType::MEDIA);
1443 ASSERT_NE(nullptr, conversational_configuration);
1444 ASSERT_NE(nullptr, media_configuration);
1445
1446 /* Create PACs for conversational and media scenarios */
1447 PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder;
1448 for (auto const& cfg : {conversational_configuration, media_configuration}) {
1449 for (const auto& entry : cfg->confs.sink) {
1450 snk_pac_builder.Add(entry.codec, 1);
1451 }
1452 for (const auto& entry : cfg->confs.source) {
1453 src_pac_builder.Add(entry.codec, 1);
1454 }
1455 }
1456 left->snk_pacs_ = snk_pac_builder.Get();
1457 left->src_pacs_ = src_pac_builder.Get();
1458 right->snk_pacs_ = snk_pac_builder.Get();
1459 right->src_pacs_ = src_pac_builder.Get();
1460
1461 /* UNSPECIFIED must be supported, MEDIA is on the remote sink only... */
1462 auto remote_snk_supp_contexts =
1463 AudioContexts(LeAudioContextType::MEDIA | LeAudioContextType::CONVERSATIONAL |
1464 LeAudioContextType::SOUNDEFFECTS | LeAudioContextType::UNSPECIFIED);
1465 auto remote_src_supp_contexts =
1466 AudioContexts(LeAudioContextType::CONVERSATIONAL | LeAudioContextType::UNSPECIFIED);
1467
1468 left->SetSupportedContexts(
1469 {.sink = remote_snk_supp_contexts, .source = remote_src_supp_contexts});
1470
1471 auto right_bud_only_context = LeAudioContextType::ALERTS;
1472 right->SetSupportedContexts({.sink = remote_snk_supp_contexts | right_bud_only_context,
1473 .source = remote_src_supp_contexts | right_bud_only_context});
1474
1475 /* ...but UNSPECIFIED and SOUNDEFFECTS are unavailable */
1476 auto remote_snk_avail_contexts =
1477 AudioContexts(LeAudioContextType::MEDIA | LeAudioContextType::CONVERSATIONAL);
1478 auto remote_src_avail_contexts = AudioContexts(LeAudioContextType::CONVERSATIONAL);
1479
1480 left->SetAvailableContexts(
1481 {.sink = remote_snk_avail_contexts, .source = remote_src_avail_contexts});
1482 ASSERT_EQ(left->GetAvailableContexts(), remote_snk_avail_contexts | remote_src_avail_contexts);
1483
1484 // Make an additional context available on the right earbud sink
1485 right->SetAvailableContexts({.sink = remote_snk_avail_contexts | right_bud_only_context,
1486 .source = remote_src_avail_contexts});
1487 ASSERT_EQ(right->GetAvailableContexts(),
1488 remote_snk_avail_contexts | remote_src_avail_contexts | right_bud_only_context);
1489
1490 /* Now add the right earbud contexts - mind the extra context on that bud */
1491 ASSERT_NE(group_->GetAvailableContexts(), left->GetAvailableContexts());
1492 ASSERT_EQ(group_->GetAvailableContexts(),
1493 left->GetAvailableContexts() | right->GetAvailableContexts());
1494
1495 /* Since no device is being added or removed from the group this should not
1496 * change the configuration set.
1497 */
1498 ASSERT_EQ(group_->GetAvailableContexts(),
1499 left->GetAvailableContexts() | right->GetAvailableContexts());
1500
1501 /* MEDIA Available on remote sink direction only */
1502 auto config = group_->GetConfiguration(LeAudioContextType::MEDIA);
1503 ASSERT_NE(nullptr, config);
1504 ASSERT_TRUE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink).size());
1505 ASSERT_FALSE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSource).size());
1506 ASSERT_EQ(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink)
1507 .at(0)
1508 .codec.GetChannelCountPerIsoStream(),
1509 ::bluetooth::le_audio::LeAudioCodecConfiguration::kChannelNumberMono);
1510
1511 /* CONVERSATIONAL Available on both directions */
1512 config = group_->GetConfiguration(LeAudioContextType::CONVERSATIONAL);
1513 ASSERT_NE(nullptr, config);
1514 ASSERT_TRUE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink).size());
1515 ASSERT_TRUE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSource).size());
1516
1517 /* UNSPECIFIED Unavailable yet supported */
1518 config = group_->GetConfiguration(LeAudioContextType::UNSPECIFIED);
1519 ASSERT_NE(nullptr, config);
1520 ASSERT_TRUE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink).size());
1521 ASSERT_FALSE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSource).size());
1522
1523 /* SOUNDEFFECTS Unavailable yet supported on sink only */
1524 config = group_->GetConfiguration(LeAudioContextType::SOUNDEFFECTS);
1525 ASSERT_NE(nullptr, config);
1526 ASSERT_TRUE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink).size());
1527 ASSERT_FALSE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSource).size());
1528
1529 /* INSTRUCTIONAL Unavailable and not supported, while UNSPECIFIED not
1530 * available */
1531 config = group_->GetConfiguration(LeAudioContextType::INSTRUCTIONAL);
1532 ASSERT_NE(nullptr, config);
1533 ASSERT_TRUE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink).size());
1534 ASSERT_FALSE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSource).size());
1535
1536 /* ALERTS on sink only */
1537 config = group_->GetConfiguration(LeAudioContextType::ALERTS);
1538 ASSERT_NE(nullptr, config);
1539 ASSERT_TRUE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink).size());
1540 ASSERT_FALSE(config->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSource).size());
1541
1542 /* We should get the config for ALERTS for both channels as the other has
1543 * UNSPECIFIED context supported.
1544 */
1545 auto sink_configs = group_->GetConfiguration(LeAudioContextType::ALERTS)
1546 ->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink);
1547 ASSERT_EQ(2lu, sink_configs.size());
1548 ASSERT_TRUE(group_->IsAudioSetConfigurationAvailable(LeAudioContextType::ALERTS));
1549
1550 /* Turn off the ALERTS context */
1551 right->SetAvailableContexts(
1552 {.sink = right->GetAvailableContexts(
1553 ::bluetooth::le_audio::types::kLeAudioDirectionSink) &
1554 ~AudioContexts(LeAudioContextType::ALERTS),
1555 .source = right->GetAvailableContexts(
1556 ::bluetooth::le_audio::types::kLeAudioDirectionSource)});
1557
1558 /* Right one was changed but the config exist, just not available */
1559 ASSERT_EQ(group_->GetAvailableContexts(),
1560 left->GetAvailableContexts() | right->GetAvailableContexts());
1561 ASSERT_FALSE(group_->GetAvailableContexts().test(LeAudioContextType::ALERTS));
1562 ASSERT_TRUE(group_->GetConfiguration(LeAudioContextType::ALERTS)
1563 ->confs.get(bluetooth::le_audio::types::kLeAudioDirectionSink)
1564 .size());
1565 ASSERT_TRUE(group_->IsAudioSetConfigurationAvailable(LeAudioContextType::ALERTS));
1566 }
1567
TEST_P(LeAudioAseConfigurationTest,test_mono_speaker_ringtone_loc0)1568 TEST_P(LeAudioAseConfigurationTest, test_mono_speaker_ringtone_loc0) {
1569 /* mono location */
1570 LeAudioDevice* mono_speaker = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationMonoAudio}});
1571 TestGroupAseConfigurationData data({mono_speaker, kLeAudioCodecChannelCountSingleChannel,
1572 kLeAudioCodecChannelCountSingleChannel, 1, 0});
1573
1574 uint8_t direction_to_verify = kLeAudioDirectionSink;
1575
1576 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1, direction_to_verify);
1577 }
1578
TEST_P(LeAudioAseConfigurationTest,test_mono_speaker_ringtone)1579 TEST_P(LeAudioAseConfigurationTest, test_mono_speaker_ringtone) {
1580 /* left only location */
1581 LeAudioDevice* mono_speaker = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1582 TestGroupAseConfigurationData data({mono_speaker, kLeAudioCodecChannelCountSingleChannel,
1583 kLeAudioCodecChannelCountSingleChannel, 1, 0});
1584
1585 uint8_t direction_to_verify = kLeAudioDirectionSink;
1586
1587 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1, direction_to_verify);
1588 }
1589
TEST_P(LeAudioAseConfigurationTest,test_mono_speaker_conversational_loc0)1590 TEST_P(LeAudioAseConfigurationTest, test_mono_speaker_conversational_loc0) {
1591 /* mono location */
1592 LeAudioDevice* mono_speaker = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationMonoAudio}});
1593 TestGroupAseConfigurationData data({mono_speaker, kLeAudioCodecChannelCountSingleChannel,
1594 kLeAudioCodecChannelCountNone, 1, 0});
1595
1596 /* Microphone should be used on the phone */
1597 uint8_t direction_to_verify = kLeAudioDirectionSink;
1598 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1, direction_to_verify);
1599 }
1600
TEST_P(LeAudioAseConfigurationTest,test_mono_speaker_conversational)1601 TEST_P(LeAudioAseConfigurationTest, test_mono_speaker_conversational) {
1602 /* left only location */
1603 LeAudioDevice* mono_speaker = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1604 TestGroupAseConfigurationData data({mono_speaker, kLeAudioCodecChannelCountSingleChannel,
1605 kLeAudioCodecChannelCountNone, 1, 0});
1606
1607 /* Microphone should be used on the phone */
1608 uint8_t direction_to_verify = kLeAudioDirectionSink;
1609 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1, direction_to_verify);
1610 }
1611
TEST_P(LeAudioAseConfigurationTest,test_mono_speaker_media_loc0)1612 TEST_P(LeAudioAseConfigurationTest, test_mono_speaker_media_loc0) {
1613 /* mono location */
1614 LeAudioDevice* mono_speaker = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationMonoAudio}});
1615 TestGroupAseConfigurationData data({mono_speaker, kLeAudioCodecChannelCountSingleChannel,
1616 kLeAudioCodecChannelCountNone, 1, 0});
1617
1618 uint8_t direction_to_verify = kLeAudioDirectionSink;
1619 TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, direction_to_verify);
1620 }
1621
TEST_P(LeAudioAseConfigurationTest,test_mono_speaker_media)1622 TEST_P(LeAudioAseConfigurationTest, test_mono_speaker_media) {
1623 /* left only location */
1624 LeAudioDevice* mono_speaker = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1625 TestGroupAseConfigurationData data({mono_speaker, kLeAudioCodecChannelCountSingleChannel,
1626 kLeAudioCodecChannelCountNone, 1, 0});
1627
1628 uint8_t direction_to_verify = kLeAudioDirectionSink;
1629 TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, direction_to_verify);
1630 }
1631
TEST_P(LeAudioAseConfigurationTest,test_banded_headphones_ringtone)1632 TEST_P(LeAudioAseConfigurationTest, test_banded_headphones_ringtone) {
1633 LeAudioDevice* banded_headphones = AddTestDevice(2, 0);
1634 TestGroupAseConfigurationData data({banded_headphones, kLeAudioCodecChannelCountTwoChannel,
1635 kLeAudioCodecChannelCountSingleChannel, 2, 0});
1636
1637 uint8_t direction_to_verify = kLeAudioDirectionSink;
1638 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1, direction_to_verify);
1639 }
1640
TEST_P(LeAudioAseConfigurationTest,test_banded_headphones_conversational)1641 TEST_P(LeAudioAseConfigurationTest, test_banded_headphones_conversational) {
1642 LeAudioDevice* banded_headphones = AddTestDevice(2, 0);
1643 TestGroupAseConfigurationData data({banded_headphones, kLeAudioCodecChannelCountTwoChannel,
1644 kLeAudioCodecChannelCountNone, 2, 0});
1645
1646 uint8_t direction_to_verify = kLeAudioDirectionSink;
1647 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1, direction_to_verify);
1648 }
1649
TEST_P(LeAudioAseConfigurationTest,test_banded_headphones_media)1650 TEST_P(LeAudioAseConfigurationTest, test_banded_headphones_media) {
1651 LeAudioDevice* banded_headphones = AddTestDevice(2, 0);
1652 TestGroupAseConfigurationData data({banded_headphones, kLeAudioCodecChannelCountTwoChannel,
1653 kLeAudioCodecChannelCountNone, 2, 0});
1654
1655 uint8_t direction_to_verify = kLeAudioDirectionSink;
1656 TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, direction_to_verify);
1657 }
1658
TEST_P(LeAudioAseConfigurationTest,test_banded_headset_ringtone_mono_microphone)1659 TEST_P(LeAudioAseConfigurationTest, test_banded_headset_ringtone_mono_microphone) {
1660 /* mono source */
1661 LeAudioDevice* banded_headset = AddTestDevice({{2, codec_spec_conf::kLeAudioLocationStereo}},
1662 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1663 TestGroupAseConfigurationData data({banded_headset, kLeAudioCodecChannelCountTwoChannel,
1664 kLeAudioCodecChannelCountSingleChannel, 2, 1});
1665
1666 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1);
1667 }
1668
TEST_P(LeAudioAseConfigurationTest,test_banded_headset_ringtone_mono_microphone_loc0)1669 TEST_P(LeAudioAseConfigurationTest, test_banded_headset_ringtone_mono_microphone_loc0) {
1670 /* mono source */
1671 LeAudioDevice* banded_headset = AddTestDevice({{2, codec_spec_conf::kLeAudioLocationStereo}},
1672 {{1, codec_spec_conf::kLeAudioLocationMonoAudio}});
1673 TestGroupAseConfigurationData data({banded_headset, kLeAudioCodecChannelCountTwoChannel,
1674 kLeAudioCodecChannelCountSingleChannel, 2, 1});
1675
1676 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1);
1677 }
1678
TEST_P(LeAudioAseConfigurationTest,test_banded_headset_ringtone_stereo_microphone)1679 TEST_P(LeAudioAseConfigurationTest, test_banded_headset_ringtone_stereo_microphone) {
1680 LeAudioDevice* banded_headset = AddTestDevice(2, 2);
1681 TestGroupAseConfigurationData data(
1682 {banded_headset,
1683 kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel,
1684 kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel, 2, 2});
1685
1686 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1);
1687 }
1688
TEST_P(LeAudioAseConfigurationTest,test_earbuds_conversational_stereo_microphone_no_swb)1689 TEST_P(LeAudioAseConfigurationTest, test_earbuds_conversational_stereo_microphone_no_swb) {
1690 // Turn off the dual bidir SWB support
1691 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported).WillByDefault(Return(false));
1692 ASSERT_FALSE(CodecManager::GetInstance()->IsDualBiDirSwbSupported());
1693
1694 const auto context_type = LeAudioContextType::CONVERSATIONAL;
1695 TestDualDevDualBidir(AddTestDevice(1, 1), AddTestDevice(1, 1), context_type);
1696
1697 // Verify non-SWB config was selected
1698 auto config = group_->GetCachedConfiguration(context_type).get();
1699 ASSERT_NE(nullptr, config);
1700 ASSERT_FALSE(CodecManager::GetInstance()->CheckCodecConfigIsDualBiDirSwb(*config));
1701 }
1702
TEST_P(LeAudioAseConfigurationTest,test_earbuds_conversational_stereo_microphone_no_swb_one_bonded)1703 TEST_P(LeAudioAseConfigurationTest,
1704 test_earbuds_conversational_stereo_microphone_no_swb_one_bonded) {
1705 /* There will be 2 eabuds eventually but for the moment only 1 is bonded
1706 * Turn off the dual bidir SWB support
1707 */
1708 desired_group_size_ = 2;
1709 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported).WillByDefault(Return(false));
1710 ASSERT_FALSE(CodecManager::GetInstance()->IsDualBiDirSwbSupported());
1711
1712 const auto context_type = LeAudioContextType::CONVERSATIONAL;
1713 TestSingleDevDualBidir(
1714 AddTestDevice(1, 1, 0, 0, false, false, codec_spec_conf::kLeAudioLocationFrontLeft,
1715 codec_spec_conf::kLeAudioLocationFrontLeft),
1716 context_type);
1717
1718 // Verify non-SWB config was selected
1719 auto config = group_->GetCachedConfiguration(context_type).get();
1720 ASSERT_NE(nullptr, config);
1721 ASSERT_FALSE(CodecManager::GetInstance()->CheckCodecConfigIsDualBiDirSwb(*config));
1722 ASSERT_FALSE(CodecManager::GetInstance()->CheckCodecConfigIsBiDirSwb(*config));
1723 }
1724
TEST_P(LeAudioAseConfigurationTest,test_earbuds_conversational_stereo_microphone_swb)1725 TEST_P(LeAudioAseConfigurationTest, test_earbuds_conversational_stereo_microphone_swb) {
1726 // Turn on the dual bidir SWB support
1727 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported).WillByDefault(Return(true));
1728 ASSERT_TRUE(CodecManager::GetInstance()->IsDualBiDirSwbSupported());
1729
1730 const auto context_type = LeAudioContextType::CONVERSATIONAL;
1731 TestDualDevDualBidir(AddTestDevice(1, 1), AddTestDevice(1, 1), context_type);
1732
1733 // Verify SWB config was selected
1734 auto config = group_->GetCachedConfiguration(context_type).get();
1735 ASSERT_NE(nullptr, config);
1736 ASSERT_TRUE(CodecManager::GetInstance()->CheckCodecConfigIsDualBiDirSwb(*config));
1737 }
1738
TEST_P(LeAudioAseConfigurationTest,test_banded_headset_ringtone_stereo_microphone_no_swb)1739 TEST_P(LeAudioAseConfigurationTest, test_banded_headset_ringtone_stereo_microphone_no_swb) {
1740 // Turn off the dual bidir SWB support
1741 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported).WillByDefault(Return(false));
1742 ASSERT_FALSE(CodecManager::GetInstance()->IsDualBiDirSwbSupported());
1743
1744 // Verify non-SWB config was selected
1745 auto context_type = LeAudioContextType::CONVERSATIONAL;
1746 TestSingleDevDualBidir(AddTestDevice(2, 2), context_type);
1747 auto config = group_->GetCachedConfiguration(context_type).get();
1748 ASSERT_NE(nullptr, config);
1749 ASSERT_FALSE(CodecManager::GetInstance()->CheckCodecConfigIsDualBiDirSwb(*config));
1750 }
1751
TEST_P(LeAudioAseConfigurationTest,test_banded_headset_ringtone_stereo_microphone_swb)1752 TEST_P(LeAudioAseConfigurationTest, test_banded_headset_ringtone_stereo_microphone_swb) {
1753 // Turn on the dual bidir SWB support
1754 ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported).WillByDefault(Return(true));
1755 ASSERT_TRUE(CodecManager::GetInstance()->IsDualBiDirSwbSupported());
1756
1757 // Verify SWB config was selected
1758 auto context_type = LeAudioContextType::CONVERSATIONAL;
1759 TestSingleDevDualBidir(AddTestDevice(2, 2), context_type);
1760 auto config = group_->GetCachedConfiguration(context_type).get();
1761 ASSERT_NE(nullptr, config);
1762 ASSERT_TRUE(CodecManager::GetInstance()->CheckCodecConfigIsDualBiDirSwb(*config));
1763 }
1764
TEST_P(LeAudioAseConfigurationTest,test_banded_headset_conversational)1765 TEST_P(LeAudioAseConfigurationTest, test_banded_headset_conversational) {
1766 LeAudioDevice* banded_headset = AddTestDevice(2, 1);
1767 TestGroupAseConfigurationData data({banded_headset, kLeAudioCodecChannelCountTwoChannel,
1768 kLeAudioCodecChannelCountSingleChannel, 2, 1});
1769
1770 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1);
1771 }
1772
TEST_P(LeAudioAseConfigurationTest,test_banded_headset_media)1773 TEST_P(LeAudioAseConfigurationTest, test_banded_headset_media) {
1774 LeAudioDevice* banded_headset = AddTestDevice(2, 1);
1775 TestGroupAseConfigurationData data({banded_headset, kLeAudioCodecChannelCountTwoChannel,
1776 kLeAudioCodecChannelCountSingleChannel, 2, 0});
1777
1778 uint8_t directions_to_verify = kLeAudioDirectionSink;
1779 TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, directions_to_verify);
1780 }
1781
TEST_P(LeAudioAseConfigurationTest,test_earbuds_ringtone)1782 TEST_P(LeAudioAseConfigurationTest, test_earbuds_ringtone) {
1783 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1784 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1785 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
1786 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
1787 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
1788 kLeAudioCodecChannelCountSingleChannel, 1, 1},
1789 {right, kLeAudioCodecChannelCountSingleChannel,
1790 kLeAudioCodecChannelCountSingleChannel, 1, 1}};
1791
1792 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, data, 2);
1793 }
1794
TEST_P(LeAudioAseConfigurationTest,test_earbuds_conversational)1795 TEST_P(LeAudioAseConfigurationTest, test_earbuds_conversational) {
1796 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1797 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1798 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
1799 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
1800 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
1801 kLeAudioCodecChannelCountSingleChannel, 1, 1},
1802 {right, kLeAudioCodecChannelCountSingleChannel,
1803 kLeAudioCodecChannelCountSingleChannel, 1, 1}};
1804
1805 group_->ReloadAudioLocations();
1806
1807 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, data, 2);
1808 }
1809
TEST_P(LeAudioAseConfigurationTest,test_earbuds_media)1810 TEST_P(LeAudioAseConfigurationTest, test_earbuds_media) {
1811 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1812 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1813 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
1814 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
1815 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
1816 kLeAudioCodecChannelCountSingleChannel, 1, 0},
1817 {right, kLeAudioCodecChannelCountSingleChannel,
1818 kLeAudioCodecChannelCountSingleChannel, 1, 0}};
1819
1820 uint8_t directions_to_verify = kLeAudioDirectionSink;
1821 TestGroupAseConfiguration(LeAudioContextType::MEDIA, data, 2, directions_to_verify);
1822 }
1823
TEST_P(LeAudioAseConfigurationTest,test_handsfree_mono_ringtone)1824 TEST_P(LeAudioAseConfigurationTest, test_handsfree_mono_ringtone) {
1825 LeAudioDevice* handsfree = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1826 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1827 TestGroupAseConfigurationData data({handsfree, kLeAudioCodecChannelCountSingleChannel,
1828 kLeAudioCodecChannelCountSingleChannel, 1, 1});
1829
1830 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1);
1831 }
1832
TEST_P(LeAudioAseConfigurationTest,test_handsfree_stereo_ringtone)1833 TEST_P(LeAudioAseConfigurationTest, test_handsfree_stereo_ringtone) {
1834 LeAudioDevice* handsfree = AddTestDevice({{1, kChannelAllocationStereo}},
1835 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1836 TestGroupAseConfigurationData data(
1837 {handsfree, kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel,
1838 kLeAudioCodecChannelCountSingleChannel, 2, 1});
1839
1840 TestGroupAseConfiguration(LeAudioContextType::RINGTONE, &data, 1);
1841 }
1842
TEST_P(LeAudioAseConfigurationTest,test_handsfree_mono_conversational)1843 TEST_P(LeAudioAseConfigurationTest, test_handsfree_mono_conversational) {
1844 LeAudioDevice* handsfree = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1845 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1846 TestGroupAseConfigurationData data({handsfree, kLeAudioCodecChannelCountSingleChannel,
1847 kLeAudioCodecChannelCountSingleChannel, 1, 1});
1848
1849 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1);
1850 }
1851
TEST_P(LeAudioAseConfigurationTest,test_handsfree_stereo_conversational)1852 TEST_P(LeAudioAseConfigurationTest, test_handsfree_stereo_conversational) {
1853 LeAudioDevice* handsfree = AddTestDevice(1, 1);
1854 TestGroupAseConfigurationData data(
1855 {handsfree, kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel,
1856 kLeAudioCodecChannelCountSingleChannel, 2, 1});
1857
1858 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1);
1859 }
1860
TEST_P(LeAudioAseConfigurationTest,test_handsfree_full_cached_conversational)1861 TEST_P(LeAudioAseConfigurationTest, test_handsfree_full_cached_conversational) {
1862 LeAudioDevice* handsfree = AddTestDevice(0, 0, 1, 1);
1863 TestGroupAseConfigurationData data(
1864 {handsfree, kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel,
1865 kLeAudioCodecChannelCountSingleChannel, 2, 1});
1866
1867 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1);
1868 }
1869
TEST_P(LeAudioAseConfigurationTest,test_handsfree_partial_cached_conversational)1870 TEST_P(LeAudioAseConfigurationTest, test_handsfree_partial_cached_conversational) {
1871 LeAudioDevice* handsfree = AddTestDevice(1, 0, 0, 1);
1872 TestGroupAseConfigurationData data(
1873 {handsfree, kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel,
1874 kLeAudioCodecChannelCountSingleChannel, 2, 1});
1875
1876 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, &data, 1);
1877 }
1878
TEST_P(LeAudioAseConfigurationTest,test_handsfree_media_two_channels_allocation_stereo)1879 TEST_P(LeAudioAseConfigurationTest, test_handsfree_media_two_channels_allocation_stereo) {
1880 LeAudioDevice* handsfree = AddTestDevice(1, 1);
1881 TestGroupAseConfigurationData data(
1882 {handsfree, kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel,
1883 kLeAudioCodecChannelCountSingleChannel, 2, 0});
1884
1885 uint8_t directions_to_verify = kLeAudioDirectionSink;
1886 TestGroupAseConfiguration(LeAudioContextType::MEDIA, &data, 1, directions_to_verify);
1887 }
1888
TEST_P(LeAudioAseConfigurationTest,test_lc3_config_ringtone)1889 TEST_P(LeAudioAseConfigurationTest, test_lc3_config_ringtone) {
1890 if (codec_coding_format_ != kLeAudioCodingFormatLC3) {
1891 GTEST_SKIP();
1892 }
1893
1894 AddTestDevice(1, 1);
1895
1896 TestLc3CodecConfig(LeAudioContextType::RINGTONE);
1897 }
1898
TEST_P(LeAudioAseConfigurationTest,test_lc3_config_conversational)1899 TEST_P(LeAudioAseConfigurationTest, test_lc3_config_conversational) {
1900 if (codec_coding_format_ != kLeAudioCodingFormatLC3) {
1901 GTEST_SKIP();
1902 }
1903
1904 AddTestDevice(1, 1);
1905
1906 TestLc3CodecConfig(LeAudioContextType::CONVERSATIONAL);
1907 }
1908
TEST_P(LeAudioAseConfigurationTest,test_lc3_config_media)1909 TEST_P(LeAudioAseConfigurationTest, test_lc3_config_media) {
1910 if (codec_coding_format_ != kLeAudioCodingFormatLC3) {
1911 GTEST_SKIP();
1912 }
1913
1914 AddTestDevice(1, 1);
1915
1916 TestLc3CodecConfig(LeAudioContextType::MEDIA);
1917 }
1918
TEST_P(LeAudioAseConfigurationTest,test_use_codec_preference_earbuds_media)1919 TEST_P(LeAudioAseConfigurationTest, test_use_codec_preference_earbuds_media) {
1920 com::android::bluetooth::flags::provider_->leaudio_set_codec_config_preference(true);
1921
1922 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1923 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1924 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
1925 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
1926 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
1927 kLeAudioCodecChannelCountSingleChannel, 1, 0},
1928 {right, kLeAudioCodecChannelCountSingleChannel,
1929 kLeAudioCodecChannelCountSingleChannel, 1, 0}};
1930
1931 // this would be also built into pac record
1932 btle_audio_codec_config_t preferred_codec_config = {
1933 .codec_type = LE_AUDIO_CODEC_INDEX_SOURCE_LC3,
1934 .sample_rate = LE_AUDIO_SAMPLE_RATE_INDEX_16000HZ,
1935 .bits_per_sample = LE_AUDIO_BITS_PER_SAMPLE_INDEX_16,
1936 .channel_count = LE_AUDIO_CHANNEL_COUNT_INDEX_1,
1937 .frame_duration = LE_AUDIO_FRAME_DURATION_INDEX_10000US,
1938 .octets_per_frame = 40};
1939
1940 uint8_t directions_to_verify = kLeAudioDirectionSink;
1941 bool should_use_preferred_codec = true;
1942
1943 TestGroupAseConfiguration(LeAudioContextType::MEDIA, data, 2, directions_to_verify,
1944 &preferred_codec_config, should_use_preferred_codec);
1945 }
1946
TEST_P(LeAudioAseConfigurationTest,test_not_use_codec_preference_earbuds_media)1947 TEST_P(LeAudioAseConfigurationTest, test_not_use_codec_preference_earbuds_media) {
1948 com::android::bluetooth::flags::provider_->leaudio_set_codec_config_preference(true);
1949
1950 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1951 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1952 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
1953 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
1954 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
1955 kLeAudioCodecChannelCountSingleChannel, 1, 0},
1956 {right, kLeAudioCodecChannelCountSingleChannel,
1957 kLeAudioCodecChannelCountSingleChannel, 1, 0}};
1958
1959 // this would be also built into pac record
1960 btle_audio_codec_config_t preferred_codec_config = {
1961 .codec_type = LE_AUDIO_CODEC_INDEX_SOURCE_LC3,
1962 .sample_rate = LE_AUDIO_SAMPLE_RATE_INDEX_16000HZ,
1963 .bits_per_sample = LE_AUDIO_BITS_PER_SAMPLE_INDEX_16,
1964 .channel_count = LE_AUDIO_CHANNEL_COUNT_INDEX_1,
1965 .frame_duration = LE_AUDIO_FRAME_DURATION_INDEX_10000US,
1966 .octets_per_frame = 70};
1967
1968 uint8_t directions_to_verify = kLeAudioDirectionSink;
1969 bool should_use_preferred_codec = false;
1970
1971 TestGroupAseConfiguration(LeAudioContextType::MEDIA, data, 2, directions_to_verify,
1972 &preferred_codec_config, should_use_preferred_codec);
1973 }
1974
TEST_P(LeAudioAseConfigurationTest,test_use_codec_preference_earbuds_conv)1975 TEST_P(LeAudioAseConfigurationTest, test_use_codec_preference_earbuds_conv) {
1976 com::android::bluetooth::flags::provider_->leaudio_set_codec_config_preference(true);
1977
1978 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
1979 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
1980 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
1981 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
1982 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
1983 kLeAudioCodecChannelCountSingleChannel, 1, 1},
1984 {right, kLeAudioCodecChannelCountSingleChannel,
1985 kLeAudioCodecChannelCountSingleChannel, 1, 1}};
1986
1987 // this would be also built into pac record
1988 btle_audio_codec_config_t preferred_codec_config = {
1989 .codec_type = LE_AUDIO_CODEC_INDEX_SOURCE_LC3,
1990 .sample_rate = LE_AUDIO_SAMPLE_RATE_INDEX_32000HZ,
1991 .bits_per_sample = LE_AUDIO_BITS_PER_SAMPLE_INDEX_16,
1992 .channel_count = LE_AUDIO_CHANNEL_COUNT_INDEX_1,
1993 .frame_duration = LE_AUDIO_FRAME_DURATION_INDEX_10000US,
1994 .octets_per_frame = 80};
1995
1996 uint8_t directions_to_verify = kLeAudioDirectionBoth;
1997 bool should_use_preferred_codec = true;
1998
1999 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, data, 2, directions_to_verify,
2000 &preferred_codec_config, should_use_preferred_codec);
2001 }
2002
TEST_P(LeAudioAseConfigurationTest,test_not_use_codec_preference_earbuds_conv)2003 TEST_P(LeAudioAseConfigurationTest, test_not_use_codec_preference_earbuds_conv) {
2004 com::android::bluetooth::flags::provider_->leaudio_set_codec_config_preference(true);
2005
2006 LeAudioDevice* left = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontLeft}},
2007 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
2008 LeAudioDevice* right = AddTestDevice({{1, codec_spec_conf::kLeAudioLocationFrontRight}},
2009 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
2010 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
2011 kLeAudioCodecChannelCountSingleChannel, 1, 1},
2012 {right, kLeAudioCodecChannelCountSingleChannel,
2013 kLeAudioCodecChannelCountSingleChannel, 1, 1}};
2014
2015 // this would be also built into pac record
2016 btle_audio_codec_config_t preferred_codec_config = {
2017 .codec_type = LE_AUDIO_CODEC_INDEX_SOURCE_LC3,
2018 .sample_rate = LE_AUDIO_SAMPLE_RATE_INDEX_16000HZ,
2019 .bits_per_sample = LE_AUDIO_BITS_PER_SAMPLE_INDEX_16,
2020 .channel_count = LE_AUDIO_CHANNEL_COUNT_INDEX_1,
2021 .frame_duration = LE_AUDIO_FRAME_DURATION_INDEX_10000US,
2022 .octets_per_frame = 10};
2023
2024 uint8_t directions_to_verify = kLeAudioDirectionBoth;
2025 bool should_use_preferred_codec = false;
2026
2027 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, data, 2, directions_to_verify,
2028 &preferred_codec_config, should_use_preferred_codec);
2029 }
2030
TEST_P(LeAudioAseConfigurationTest,test_lc3_config_media_codec_extensibility_fb2)2031 TEST_P(LeAudioAseConfigurationTest, test_lc3_config_media_codec_extensibility_fb2) {
2032 if (codec_coding_format_ != kLeAudioCodingFormatLC3) {
2033 GTEST_SKIP();
2034 }
2035
2036 bool is_fb2_passed_as_requirement = false;
2037 auto max_codec_frames_per_sdu = 2;
2038
2039 // Mock the configuration provider to give us config with 2 frame blocks per
2040 // SDU if it receives the proper PAC entry in the requirements
2041 // ON_CALL(*mock_codec_manager_, IsUsingCodecExtensibility)
2042 // .WillByDefault(Return(true));
2043 ON_CALL(*mock_codec_manager_, GetCodecConfig)
2044 .WillByDefault(Invoke(
2045 [&](const bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements&
2046 requirements,
2047 bluetooth::le_audio::CodecManager::UnicastConfigurationProvider provider) {
2048 auto filtered = *bluetooth::le_audio::AudioSetConfigurationProvider::Get()
2049 ->GetConfigurations(requirements.audio_context_type);
2050 // Filter out the dual bidir SWB configurations
2051 if (!bluetooth::le_audio::CodecManager::GetInstance()
2052 ->IsDualBiDirSwbSupported()) {
2053 filtered.erase(
2054 std::remove_if(filtered.begin(), filtered.end(),
2055 [](auto const& el) {
2056 if (el->confs.source.empty()) {
2057 return false;
2058 }
2059 return AudioSetConfigurationProvider::Get()
2060 ->CheckConfigurationIsDualBiDirSwb(*el);
2061 }),
2062 filtered.end());
2063 }
2064 auto cfg = provider(requirements, &filtered);
2065 if (cfg == nullptr) {
2066 return std::unique_ptr<AudioSetConfiguration>(nullptr);
2067 }
2068
2069 auto config = *cfg;
2070
2071 if (requirements.sink_pacs.has_value()) {
2072 for (auto const& rec : requirements.sink_pacs.value()) {
2073 auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities();
2074 if (caps.HasSupportedMaxCodecFramesPerSdu()) {
2075 if (caps.supported_max_codec_frames_per_sdu.value() ==
2076 max_codec_frames_per_sdu) {
2077 // Inject the proper Codec Frames Per SDU as the json
2078 // configs are conservative and will always give us 1
2079 for (auto& entry : config.confs.sink) {
2080 entry.codec.params.Add(
2081 codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu,
2082 (uint8_t)max_codec_frames_per_sdu);
2083 }
2084 is_fb2_passed_as_requirement = true;
2085 }
2086 }
2087 }
2088 }
2089 return std::make_unique<AudioSetConfiguration>(config);
2090 }));
2091
2092 AddTestDevice(1, 1);
2093
2094 TestLc3CodecConfig(LeAudioContextType::MEDIA, max_codec_frames_per_sdu);
2095
2096 // Make sure the CodecManager mock gets the proper PAC record
2097 ASSERT_TRUE(is_fb2_passed_as_requirement);
2098 }
2099
TEST_P(LeAudioAseConfigurationTest,test_unsupported_codec)2100 TEST_P(LeAudioAseConfigurationTest, test_unsupported_codec) {
2101 if (codec_coding_format_ == kLeAudioCodingFormatVendorSpecific) {
2102 GTEST_SKIP();
2103 }
2104
2105 const LeAudioCodecId UnsupportedCodecId = {
2106 .coding_format = kLeAudioCodingFormatVendorSpecific,
2107 .vendor_company_id = 0xBAD,
2108 .vendor_codec_id = 0xC0DE,
2109 };
2110
2111 LeAudioDevice* device = AddTestDevice(1, 0);
2112
2113 PublishedAudioCapabilitiesBuilder pac_builder;
2114 pac_builder.Add(UnsupportedCodecId, GetSamplingFrequency(Lc3SettingId::LC3_16_2),
2115 GetFrameDuration(Lc3SettingId::LC3_16_2), kLeAudioCodecChannelCountSingleChannel,
2116 GetOctetsPerCodecFrame(Lc3SettingId::LC3_16_2));
2117 device->snk_pacs_ = pac_builder.Get();
2118 device->src_pacs_ = pac_builder.Get();
2119
2120 ASSERT_FALSE(group_->Configure(LeAudioContextType::RINGTONE,
2121 {AudioContexts(LeAudioContextType::RINGTONE),
2122 AudioContexts(LeAudioContextType::RINGTONE)}));
2123 TestAsesInactive();
2124 }
2125
PrepareStackMetadataLtvBase()2126 static auto PrepareStackMetadataLtvBase() {
2127 ::bluetooth::le_audio::types::LeAudioLtvMap metadata_ltvs;
2128 // Prepare the metadata LTVs
2129 metadata_ltvs
2130 .Add(::bluetooth::le_audio::types::kLeAudioMetadataTypeProgramInfo,
2131 std::string{"ProgramInfo"})
2132 .Add(::bluetooth::le_audio::types::kLeAudioMetadataTypeLanguage, std::string{"ice"})
2133 .Add(::bluetooth::le_audio::types::kLeAudioMetadataTypeparentalRating, (uint8_t)0x01)
2134 .Add(::bluetooth::le_audio::types::kLeAudioMetadataTypeProgramInfoUri,
2135 std::string{"ProgramInfoUri"})
2136 .Add(::bluetooth::le_audio::types::kLeAudioMetadataTypeAudioActiveState, false)
2137 .Add(::bluetooth::le_audio::types::
2138 kLeAudioMetadataTypeBroadcastAudioImmediateRenderingFlag,
2139 true)
2140 .Add(::bluetooth::le_audio::types::kLeAudioMetadataTypeExtendedMetadata,
2141 std::vector<uint8_t>{1, 2, 3})
2142 .Add(::bluetooth::le_audio::types::kLeAudioMetadataTypeVendorSpecific,
2143 std::vector<uint8_t>{1, 2, 3});
2144 return metadata_ltvs;
2145 }
2146
TEST_P(LeAudioAseConfigurationTest,test_reconnection_media)2147 TEST_P(LeAudioAseConfigurationTest, test_reconnection_media) {
2148 LeAudioDevice* left = AddTestDevice({{2, codec_spec_conf::kLeAudioLocationFrontLeft}},
2149 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
2150 LeAudioDevice* right = AddTestDevice({{2, codec_spec_conf::kLeAudioLocationFrontRight}},
2151 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
2152 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
2153 kLeAudioCodecChannelCountSingleChannel, 1, 0},
2154 {right, kLeAudioCodecChannelCountSingleChannel,
2155 kLeAudioCodecChannelCountSingleChannel, 1, 0}};
2156
2157 auto all_configurations =
2158 ::bluetooth::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations(
2159 LeAudioContextType::MEDIA);
2160 ASSERT_NE(nullptr, all_configurations);
2161 ASSERT_NE(all_configurations->end(), all_configurations->begin());
2162 auto configuration = *all_configurations->begin();
2163
2164 uint8_t direction_to_verify = kLeAudioDirectionSink;
2165 TestSingleAseConfiguration(LeAudioContextType::MEDIA, data, 2, configuration,
2166 direction_to_verify);
2167
2168 // Get the proper configuration for the group
2169 configuration = group_->GetConfiguration(LeAudioContextType::MEDIA).get();
2170
2171 /* Generate CISes, symulate CIG creation and assign cis handles to ASEs.*/
2172 group_->cig.GenerateCisIds(LeAudioContextType::MEDIA);
2173 std::vector<uint16_t> handles = {0x0012, 0x0013};
2174 group_->cig.AssignCisConnHandles(handles);
2175 group_->cig.AssignCisIds(left);
2176 group_->cig.AssignCisIds(right);
2177
2178 TestActiveAses();
2179 /* Left got disconnected */
2180 left->DeactivateAllAses();
2181
2182 /* Unassign from the group*/
2183 group_->cig.UnassignCis(left, 0x0012);
2184 group_->cig.UnassignCis(left, 0x0013);
2185
2186 TestAsesInactivated(left);
2187
2188 /* Prepare reconfiguration */
2189 uint8_t number_of_active_ases = 1; // Right one
2190 auto* ase = right->GetFirstActiveAseByDirection(kLeAudioDirectionSink);
2191 ASSERT_NE(nullptr, ase);
2192
2193 auto core_config = ase->codec_config.params.GetAsCoreCodecConfig();
2194 BidirectionalPair<AudioLocations> group_audio_locations = {
2195 .sink = *core_config.audio_channel_allocation,
2196 .source = *core_config.audio_channel_allocation};
2197
2198 /* Get entry for the sink direction and use it to set configuration */
2199 BidirectionalPair<std::vector<uint8_t>> ccid_lists = {{}, {}};
2200 BidirectionalPair<AudioContexts> audio_contexts = {AudioContexts(), AudioContexts()};
2201 if (!configuration->confs.sink.empty()) {
2202 left->ConfigureAses(configuration, group_->Size(), kLeAudioDirectionSink,
2203 group_->GetConfigurationContextType(), &number_of_active_ases,
2204 group_audio_locations.get(kLeAudioDirectionSink),
2205 audio_contexts.get(kLeAudioDirectionSink),
2206 ccid_lists.get(kLeAudioDirectionSink), false);
2207 }
2208 if (!configuration->confs.source.empty()) {
2209 left->ConfigureAses(configuration, group_->Size(), kLeAudioDirectionSource,
2210 group_->GetConfigurationContextType(), &number_of_active_ases,
2211 group_audio_locations.get(kLeAudioDirectionSource),
2212 audio_contexts.get(kLeAudioDirectionSource),
2213 ccid_lists.get(kLeAudioDirectionSource), false);
2214 }
2215
2216 ASSERT_EQ(number_of_active_ases, 2);
2217 ASSERT_EQ(group_audio_locations.sink, kChannelAllocationStereo);
2218
2219 uint8_t directions_to_verify = ::bluetooth::le_audio::types::kLeAudioDirectionSink;
2220 for (int i = 0; i < 2; i++) {
2221 TestGroupAseConfigurationVerdict(data[i], directions_to_verify);
2222 }
2223
2224 /* Before device is rejoining, and group already exist, cis handles are
2225 * assigned before sending codec config
2226 */
2227 group_->cig.AssignCisIds(left);
2228 group_->AssignCisConnHandlesToAses(left);
2229
2230 TestActiveAses();
2231 }
2232
TEST_P(LeAudioAseConfigurationTest,test_ase_metadata)2233 TEST_P(LeAudioAseConfigurationTest, test_ase_metadata) {
2234 /* Set desired size to 1 */
2235 desired_group_size_ = 1;
2236
2237 LeAudioDevice* headphones = AddTestDevice(2, 1);
2238
2239 AudioSetConfiguration media_configuration = *getSpecificConfiguration(
2240 "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability", LeAudioContextType::MEDIA);
2241
2242 // Build PACs for device
2243 PublishedAudioCapabilitiesBuilder snk_pac_builder;
2244 snk_pac_builder.Reset();
2245
2246 /* Create PACs for media. Single PAC for each direction is enough.
2247 */
2248 if (media_configuration.confs.sink.size()) {
2249 snk_pac_builder.Add(LeAudioCodecIdLc3, 0x00b5, 0x03, 0x03, 0x001a, 0x00f0, 2);
2250 }
2251
2252 headphones->snk_pacs_ = snk_pac_builder.Get();
2253
2254 ::bluetooth::le_audio::types::AudioLocations group_snk_audio_locations = 3;
2255 ::bluetooth::le_audio::types::AudioLocations group_src_audio_locations = 0;
2256 BidirectionalPair<AudioLocations> group_audio_locations = {.sink = group_snk_audio_locations,
2257 .source = group_src_audio_locations};
2258
2259 /* Get entry for the sink direction and use it to set configuration */
2260 BidirectionalPair<std::vector<uint8_t>> ccid_lists = {.sink = {0xC0}, .source = {}};
2261 BidirectionalPair<AudioContexts> audio_contexts = {
2262 .sink = AudioContexts(LeAudioContextType::MEDIA), .source = AudioContexts()};
2263
2264 /* Get entry for the sink direction and use it to set configuration */
2265 ASSERT_FALSE(media_configuration.confs.sink.empty());
2266 if (!media_configuration.confs.sink.empty()) {
2267 // Prepare a base metadata - as if it was received from the configuration provider
2268 for (auto& cfg : media_configuration.confs.sink) {
2269 cfg.metadata = PrepareStackMetadataLtvBase();
2270 }
2271 uint8_t number_of_already_active_ases = 0;
2272 headphones->ConfigureAses(&media_configuration, group_->Size(), kLeAudioDirectionSink,
2273 group_->GetConfigurationContextType(), &number_of_already_active_ases,
2274 group_audio_locations.get(kLeAudioDirectionSink),
2275 audio_contexts.get(kLeAudioDirectionSink),
2276 ccid_lists.get(kLeAudioDirectionSink), false);
2277 }
2278
2279 /* Generate CIS, simulate CIG creation and assign cis handles to ASEs.*/
2280 std::vector<uint16_t> handles = {0x0012};
2281 group_->cig.GenerateCisIds(LeAudioContextType::MEDIA);
2282
2283 /* Verify the metadata content */
2284 for (auto* ase = headphones->GetFirstActiveAse(); ase; ase = headphones->GetNextActiveAse(ase)) {
2285 /* The base metadata as if received from the audio set configuration provider */
2286 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().program_info, std::string("ProgramInfo"));
2287 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().language, std::string("ice"));
2288 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().parental_rating, 0x01);
2289 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().program_info_uri, std::string("ProgramInfoUri"));
2290 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().audio_active_state, false);
2291 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().broadcast_audio_immediate_rendering, true);
2292 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().extended_metadata,
2293 (std::vector<uint8_t>{1, 2, 3}));
2294 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().vendor_specific,
2295 (std::vector<uint8_t>{1, 2, 3}));
2296
2297 /* The adidtional metadata appended by the host stack */
2298 uint16_t streaming_context =
2299 ase->metadata.GetAsLeAudioMetadata().streaming_audio_context.value().value();
2300 ASSERT_EQ(streaming_context, (uint16_t)LeAudioContextType::MEDIA);
2301 ASSERT_EQ(ase->metadata.GetAsLeAudioMetadata().ccid_list, (std::vector<uint8_t>{0xC0}));
2302 }
2303 }
2304
2305 /*
2306 * Failure happens when restarting conversational scenario and when
2307 * remote device uses caching.
2308 *
2309 * Failing scenario.
2310 * 1. Conversational scenario set up with
2311 * - ASE 1 and ASE 5 using bidirectional CIS 0
2312 * - ASE 2 being unidirectional on CIS 1
2313 * 2. Stop stream and go to CONFIGURED STATE.
2314 * 3. Trying to configure ASES again would end up in incorrectly assigned
2315 * CISes
2316 * - ASE 1 and ASE 5 set to CIS 0
2317 * - ASE 2 stay on CIS 1 but ASE 5 got reassigned to CIS 1 (error)
2318 *
2319 * The problem is finding matching_bidir_ase which shall not be just next
2320 * active ase with different direction, but it shall be also available (Cis
2321 * not assigned) or assigned to the same CIS ID as the opposite direction.
2322 */
TEST_P(LeAudioAseConfigurationTest,test_reactivation_conversational)2323 TEST_P(LeAudioAseConfigurationTest, test_reactivation_conversational) {
2324 LeAudioDevice* tws_headset = AddTestDevice(0, 0, 2, 1, true, false, kChannelAllocationStereo,
2325 codec_spec_conf::kLeAudioLocationFrontLeft);
2326
2327 auto conversational_configuration = getSpecificConfiguration(
2328 "Two-OneChan-SnkAse-Lc3_16_2-One-OneChan-SrcAse-Lc3_16_2_Low_Latency",
2329 LeAudioContextType::CONVERSATIONAL);
2330 ASSERT_NE(nullptr, conversational_configuration);
2331
2332 // Build PACs for device
2333 PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder;
2334 snk_pac_builder.Reset();
2335 src_pac_builder.Reset();
2336
2337 /* Create PACs for conversational scenario which covers also media. Single
2338 * PAC for each direction is enough.
2339 */
2340 for (const auto& entry : (*conversational_configuration).confs.sink) {
2341 snk_pac_builder.Add(entry.codec, 1);
2342 }
2343 for (const auto& entry : (*conversational_configuration).confs.source) {
2344 src_pac_builder.Add(entry.codec, 1);
2345 }
2346
2347 tws_headset->snk_pacs_ = snk_pac_builder.Get();
2348 tws_headset->src_pacs_ = src_pac_builder.Get();
2349
2350 ::bluetooth::le_audio::types::AudioLocations group_snk_audio_locations = 0;
2351 ::bluetooth::le_audio::types::AudioLocations group_src_audio_locations = 0;
2352 BidirectionalPair<uint8_t> number_of_already_active_ases = {0, 0};
2353
2354 BidirectionalPair<AudioLocations> group_audio_locations = {.sink = group_snk_audio_locations,
2355 .source = group_src_audio_locations};
2356
2357 /* Get entry for the sink direction and use it to set configuration */
2358 BidirectionalPair<std::vector<uint8_t>> ccid_lists = {{}, {}};
2359 BidirectionalPair<AudioContexts> audio_contexts = {AudioContexts(), AudioContexts()};
2360
2361 /* Get entry for the sink direction and use it to set configuration */
2362 if (!conversational_configuration->confs.sink.empty()) {
2363 tws_headset->ConfigureAses(conversational_configuration, group_->Size(), kLeAudioDirectionSink,
2364 group_->GetConfigurationContextType(),
2365 &number_of_already_active_ases.get(kLeAudioDirectionSink),
2366 group_audio_locations.get(kLeAudioDirectionSink),
2367 audio_contexts.get(kLeAudioDirectionSink),
2368 ccid_lists.get(kLeAudioDirectionSink), false);
2369 }
2370 if (!conversational_configuration->confs.source.empty()) {
2371 tws_headset->ConfigureAses(conversational_configuration, group_->Size(),
2372 kLeAudioDirectionSource, group_->GetConfigurationContextType(),
2373 &number_of_already_active_ases.get(kLeAudioDirectionSource),
2374 group_audio_locations.get(kLeAudioDirectionSource),
2375 audio_contexts.get(kLeAudioDirectionSource),
2376 ccid_lists.get(kLeAudioDirectionSource), false);
2377 }
2378
2379 /* Generate CISes, simulate CIG creation and assign cis handles to ASEs.*/
2380 std::vector<uint16_t> handles = {0x0012, 0x0013};
2381 group_->cig.GenerateCisIds(LeAudioContextType::CONVERSATIONAL);
2382 group_->cig.AssignCisConnHandles(handles);
2383 group_->cig.AssignCisIds(tws_headset);
2384
2385 TestActiveAses();
2386
2387 /* Simulate stopping stream with caching codec configuration in ASEs */
2388 group_->cig.UnassignCis(tws_headset, 0x0012);
2389 group_->cig.UnassignCis(tws_headset, 0x0013);
2390 SetAsesToCachedConfiguration(tws_headset, LeAudioContextType::CONVERSATIONAL,
2391 kLeAudioDirectionSink | kLeAudioDirectionSource);
2392
2393 /* As context type is the same as previous and no changes were made in PACs
2394 * the same CIS ID can be used. This would lead to only activating group
2395 * without reconfiguring CIG.
2396 */
2397 group_->Activate(LeAudioContextType::CONVERSATIONAL, audio_contexts, ccid_lists);
2398
2399 TestActiveAses();
2400 ASSERT_NE(this->group_->cig.cises.size(), 0lu);
2401
2402 /* Verify ASEs assigned CISes by counting assigned to bi-directional CISes */
2403 int bi_dir_ases_count =
2404 std::count_if(tws_headset->ases_.begin(), tws_headset->ases_.end(), [this](auto& ase) {
2405 if (ase.cis_id == kInvalidCisId) {
2406 return false;
2407 }
2408 return this->group_->cig.cises[ase.cis_id].type == CisType::CIS_TYPE_BIDIRECTIONAL;
2409 });
2410
2411 /* Only two ASEs can be bonded to one bi-directional CIS */
2412 ASSERT_EQ(bi_dir_ases_count, 2);
2413 }
2414
TEST_P(LeAudioAseConfigurationTest,test_num_of_connected)2415 TEST_P(LeAudioAseConfigurationTest, test_num_of_connected) {
2416 auto device1 = AddTestDevice(2, 1);
2417 auto device2 = AddTestDevice(2, 1);
2418 ASSERT_EQ(2, group_->NumOfConnected());
2419
2420 // Drop the ACL connection
2421 device1->conn_id_ = GATT_INVALID_CONN_ID;
2422 ASSERT_EQ(1, group_->NumOfConnected());
2423
2424 // Fully disconnect the other device
2425 device2->SetConnectionState(DeviceConnectState::DISCONNECTING);
2426 ASSERT_EQ(0, group_->NumOfConnected());
2427 }
2428
2429 /*
2430 * Failure happens when there is no matching single device scenario for dual
2431 * device scanario. Stereo location for single earbud seems to be invalid but
2432 * possible and stack should handle it.
2433 *
2434 * Failing scenario:
2435 * 1. Connect two - stereo location earbuds
2436 * 2. Disconnect one of earbud
2437 * 3. CIS generator will look for dual device scenario with matching strategy
2438 * 4. There is no dual device scenario with strategy stereo channels per device
2439 */
TEST_P(LeAudioAseConfigurationTest,test_getting_cis_count)2440 TEST_P(LeAudioAseConfigurationTest, test_getting_cis_count) {
2441 /* Set desired size to 2 */
2442 desired_group_size_ = 2;
2443
2444 LeAudioDevice* left =
2445 AddTestDevice({{2, kChannelAllocationStereo}}, {{1, kChannelAllocationStereo}});
2446 LeAudioDevice* right = AddTestDevice(0, 0, 0, 0, false, true);
2447
2448 auto media_configuration = getSpecificConfiguration(
2449 "One-TwoChan-SnkAse-Lc3_48_4_High_Reliability", LeAudioContextType::MEDIA);
2450 ASSERT_NE(nullptr, media_configuration);
2451
2452 // Build PACs for device
2453 PublishedAudioCapabilitiesBuilder snk_pac_builder;
2454 snk_pac_builder.Reset();
2455
2456 /* Create PACs for media. Single PAC for each direction is enough.
2457 */
2458 if (media_configuration->confs.sink.size()) {
2459 snk_pac_builder.Add(LeAudioCodecIdLc3, 0x00b5, 0x03, 0x03, 0x001a, 0x00f0, 2);
2460 }
2461
2462 left->snk_pacs_ = snk_pac_builder.Get();
2463 right->snk_pacs_ = snk_pac_builder.Get();
2464
2465 ::bluetooth::le_audio::types::AudioLocations group_snk_audio_locations = 3;
2466 ::bluetooth::le_audio::types::AudioLocations group_src_audio_locations = 0;
2467 uint8_t number_of_already_active_ases = 0;
2468
2469 BidirectionalPair<AudioLocations> group_audio_locations = {.sink = group_snk_audio_locations,
2470 .source = group_src_audio_locations};
2471
2472 /* Get entry for the sink direction and use it to set configuration */
2473 BidirectionalPair<std::vector<uint8_t>> ccid_lists = {{}, {}};
2474 BidirectionalPair<AudioContexts> audio_contexts = {AudioContexts(), AudioContexts()};
2475
2476 /* Get entry for the sink direction and use it to set configuration */
2477 if (!media_configuration->confs.sink.empty()) {
2478 left->ConfigureAses(media_configuration, group_->Size(), kLeAudioDirectionSink,
2479 group_->GetConfigurationContextType(), &number_of_already_active_ases,
2480 group_audio_locations.get(kLeAudioDirectionSink),
2481 audio_contexts.get(kLeAudioDirectionSink),
2482 ccid_lists.get(kLeAudioDirectionSink), false);
2483 }
2484
2485 /* Generate CIS, simulate CIG creation and assign cis handles to ASEs.*/
2486 std::vector<uint16_t> handles = {0x0012};
2487 group_->cig.GenerateCisIds(LeAudioContextType::MEDIA);
2488
2489 /* Verify prepared CISes by counting generated entries */
2490 int snk_cis_count = std::count_if(
2491 this->group_->cig.cises.begin(), this->group_->cig.cises.end(),
2492 [](auto& cis) { return cis.type == CisType::CIS_TYPE_UNIDIRECTIONAL_SINK; });
2493
2494 /* Two CIS should be prepared for dual dev expected set */
2495 ASSERT_EQ(snk_cis_count, 2);
2496 }
2497
TEST_P(LeAudioAseConfigurationTest,test_config_support)2498 TEST_P(LeAudioAseConfigurationTest, test_config_support) {
2499 LeAudioDevice* left =
2500 AddTestDevice({{2, kChannelAllocationStereo}}, {{1, kChannelAllocationStereo}});
2501 LeAudioDevice* right = AddTestDevice(0, 0, 0, 0, false, true);
2502
2503 auto test_config = getSpecificConfiguration(
2504 "One-OneChan-SnkAse-Lc3_48_4-One-OneChan-SrcAse-Lc3_16_2_Balanced_Reliability",
2505 LeAudioContextType::VOICEASSISTANTS);
2506 ASSERT_NE(nullptr, test_config);
2507
2508 /* Create PACs for sink */
2509 PublishedAudioCapabilitiesBuilder snk_pac_builder;
2510 snk_pac_builder.Reset();
2511 for (const auto& entry : (*test_config).confs.sink) {
2512 snk_pac_builder.Add(entry.codec, 1);
2513 }
2514 left->snk_pacs_ = snk_pac_builder.Get();
2515 right->snk_pacs_ = snk_pac_builder.Get();
2516
2517 ASSERT_FALSE(left->IsAudioSetConfigurationSupported(test_config));
2518 ASSERT_FALSE(right->IsAudioSetConfigurationSupported(test_config));
2519
2520 /* Create PACs for source */
2521 PublishedAudioCapabilitiesBuilder src_pac_builder;
2522 src_pac_builder.Reset();
2523 for (const auto& entry : (*test_config).confs.source) {
2524 src_pac_builder.Add(entry.codec, 1);
2525 }
2526 left->src_pacs_ = src_pac_builder.Get();
2527 right->src_pacs_ = src_pac_builder.Get();
2528
2529 ASSERT_TRUE(left->IsAudioSetConfigurationSupported(test_config));
2530 ASSERT_TRUE(right->IsAudioSetConfigurationSupported(test_config));
2531 }
2532
TEST_P(LeAudioAseConfigurationTest,test_vendor_codec_configure_incomplete_group)2533 TEST_P(LeAudioAseConfigurationTest, test_vendor_codec_configure_incomplete_group) {
2534 // A group of two earbuds
2535 LeAudioDevice* left = AddTestDevice({{2, codec_spec_conf::kLeAudioLocationFrontLeft}},
2536 {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
2537 LeAudioDevice* right = AddTestDevice({{2, codec_spec_conf::kLeAudioLocationFrontRight}},
2538 {{1, codec_spec_conf::kLeAudioLocationFrontRight}});
2539
2540 // The Right earbud is currently disconnected
2541 right->SetConnectionState(DeviceConnectState::DISCONNECTED);
2542
2543 uint8_t direction_to_verify = kLeAudioDirectionSink;
2544 uint8_t devices_to_verify = 1;
2545 TestGroupAseConfigurationData data[] = {{left, kLeAudioCodecChannelCountSingleChannel,
2546 kLeAudioCodecChannelCountSingleChannel, 1, 0},
2547 {right, kLeAudioCodecChannelCountSingleChannel,
2548 kLeAudioCodecChannelCountSingleChannel, 0, 0}};
2549
2550 TestGroupAseConfiguration(LeAudioContextType::MEDIA, data, devices_to_verify,
2551 direction_to_verify);
2552 }
2553
TEST_P(LeAudioAseConfigurationTest,test_mono_microphone_conversational_loc0)2554 TEST_P(LeAudioAseConfigurationTest, test_mono_microphone_conversational_loc0) {
2555 /* Mono microphone - Speaker should be used on the phone */
2556 auto mono_microphone =
2557 AddTestDevice(std::nullopt, {{1, codec_spec_conf::kLeAudioLocationMonoAudio}});
2558 TestGroupAseConfigurationData data(
2559 {.device = mono_microphone,
2560 .audio_channel_counts_snk = kLeAudioCodecChannelCountNone,
2561 .audio_channel_counts_src = kLeAudioCodecChannelCountSingleChannel,
2562 .expected_active_channel_num_snk = 0,
2563 .expected_active_channel_num_src = 1});
2564 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, {data});
2565 }
2566
TEST_P(LeAudioAseConfigurationTest,test_mono_microphone_conversational)2567 TEST_P(LeAudioAseConfigurationTest, test_mono_microphone_conversational) {
2568 /* Mono microphone - Speaker should be used on the phone */
2569 auto mono_microphone =
2570 AddTestDevice(std::nullopt, {{1, codec_spec_conf::kLeAudioLocationFrontLeft}});
2571 TestGroupAseConfigurationData data(
2572 {.device = mono_microphone,
2573 .audio_channel_counts_snk = kLeAudioCodecChannelCountNone,
2574 .audio_channel_counts_src = kLeAudioCodecChannelCountSingleChannel,
2575 .expected_active_channel_num_snk = 0,
2576 .expected_active_channel_num_src = 1});
2577 TestGroupAseConfiguration(LeAudioContextType::CONVERSATIONAL, {data});
2578 }
2579
TEST_P(LeAudioAseConfigurationTest,test_get_metadata_no_ccid)2580 TEST_P(LeAudioAseConfigurationTest, test_get_metadata_no_ccid) {
2581 auto mono_microphone = AddTestDevice(1, 0);
2582 auto metadata = mono_microphone->GetMetadata(
2583 bluetooth::le_audio::types::AudioContexts(
2584 bluetooth::le_audio::types::LeAudioContextType::MEDIA),
2585 std::vector<uint8_t>());
2586 ASSERT_EQ(metadata.Find(types::kLeAudioMetadataTypeCcidList), std::nullopt);
2587 ASSERT_TRUE(metadata.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeStreamingAudioContext)
2588 .has_value());
2589 ASSERT_EQ(metadata.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeStreamingAudioContext)
2590 .value()[0],
2591 uint8_t(LeAudioContextType::MEDIA));
2592 ASSERT_EQ(metadata.Find(bluetooth::le_audio::types::kLeAudioMetadataTypeStreamingAudioContext)
2593 .value()[1],
2594 uint8_t((uint16_t)LeAudioContextType::MEDIA >> 8));
2595 }
2596
2597 INSTANTIATE_TEST_CASE_P(Test, LeAudioAseConfigurationTest,
2598 ::testing::Values(kLeAudioCodingFormatLC3,
2599 kLeAudioCodingFormatVendorSpecific));
2600
2601 } // namespace
2602 } // namespace internal
2603 } // namespace le_audio
2604 } // namespace bluetooth
2605