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