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