1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "codec_manager.h"
18
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 #include <log/log.h>
22
23 #include "audio_hal_client/audio_hal_client.h"
24 #include "audio_hal_interface/le_audio_software.h"
25 #include "hci/controller_interface_mock.h"
26 #include "hci/hci_packets.h"
27 #include "internal_include/stack_config.h"
28 #include "le_audio/gmap_client.h"
29 #include "le_audio/gmap_server.h"
30 #include "le_audio/le_audio_types.h"
31 #include "le_audio_set_configuration_provider.h"
32 #include "osi/include/properties.h"
33 #include "test/mock/mock_legacy_hci_interface.h"
34 #include "test/mock/mock_main_shim_entry.h"
35
36 using ::testing::_;
37 using ::testing::Mock;
38 using ::testing::NiceMock;
39 using ::testing::Return;
40 using ::testing::Test;
41
42 using bluetooth::hci::OpCode;
43 using bluetooth::hci::iso_manager::kIsoDataPathHci;
44 using bluetooth::hci::iso_manager::kIsoDataPathPlatformDefault;
45 using bluetooth::le_audio::types::AudioSetConfiguration;
46 using bluetooth::le_audio::types::CodecLocation;
47 using bluetooth::le_audio::types::kLeAudioDirectionSink;
48 using bluetooth::le_audio::types::kLeAudioDirectionSource;
49
50 static const std::vector<AudioSetConfiguration> offload_capabilities_none(0);
51
52 const std::vector<AudioSetConfiguration>* offload_capabilities = &offload_capabilities_none;
53
54 const std::string kSmpOptions("mock smp options");
get_pts_avrcp_test(void)55 static bool get_pts_avrcp_test(void) { return false; }
get_pts_secure_only_mode(void)56 static bool get_pts_secure_only_mode(void) { return false; }
get_pts_conn_updates_disabled(void)57 static bool get_pts_conn_updates_disabled(void) { return false; }
get_pts_crosskey_sdp_disable(void)58 static bool get_pts_crosskey_sdp_disable(void) { return false; }
get_pts_smp_options(void)59 static const std::string* get_pts_smp_options(void) { return &kSmpOptions; }
get_pts_smp_failure_case(void)60 static int get_pts_smp_failure_case(void) { return 123; }
get_pts_force_eatt_for_notifications(void)61 static bool get_pts_force_eatt_for_notifications(void) { return false; }
get_pts_connect_eatt_unconditionally(void)62 static bool get_pts_connect_eatt_unconditionally(void) { return false; }
get_pts_connect_eatt_before_encryption(void)63 static bool get_pts_connect_eatt_before_encryption(void) { return false; }
get_pts_unencrypt_broadcast(void)64 static bool get_pts_unencrypt_broadcast(void) { return false; }
get_pts_eatt_peripheral_collision_support(void)65 static bool get_pts_eatt_peripheral_collision_support(void) { return false; }
get_pts_force_le_audio_multiple_contexts_metadata(void)66 static bool get_pts_force_le_audio_multiple_contexts_metadata(void) { return false; }
get_pts_le_audio_disable_ases_before_stopping(void)67 static bool get_pts_le_audio_disable_ases_before_stopping(void) { return false; }
get_all(void)68 static config_t* get_all(void) { return nullptr; }
69
70 stack_config_t mock_stack_config{
71 .get_pts_avrcp_test = get_pts_avrcp_test,
72 .get_pts_secure_only_mode = get_pts_secure_only_mode,
73 .get_pts_conn_updates_disabled = get_pts_conn_updates_disabled,
74 .get_pts_crosskey_sdp_disable = get_pts_crosskey_sdp_disable,
75 .get_pts_smp_options = get_pts_smp_options,
76 .get_pts_smp_failure_case = get_pts_smp_failure_case,
77 .get_pts_force_eatt_for_notifications = get_pts_force_eatt_for_notifications,
78 .get_pts_connect_eatt_unconditionally = get_pts_connect_eatt_unconditionally,
79 .get_pts_connect_eatt_before_encryption = get_pts_connect_eatt_before_encryption,
80 .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast,
81 .get_pts_eatt_peripheral_collision_support = get_pts_eatt_peripheral_collision_support,
82 .get_pts_force_le_audio_multiple_contexts_metadata =
83 get_pts_force_le_audio_multiple_contexts_metadata,
84 .get_pts_le_audio_disable_ases_before_stopping =
85 get_pts_le_audio_disable_ases_before_stopping,
86 .get_all = get_all,
87 };
88
stack_config_get_interface(void)89 const stack_config_t* stack_config_get_interface(void) { return &mock_stack_config; }
90
91 namespace bluetooth::audio::le_audio {
get_offload_capabilities()92 OffloadCapabilities get_offload_capabilities() {
93 return {*offload_capabilities, *offload_capabilities};
94 }
GetCodecConfigProviderInfo(void) const95 std::optional<bluetooth::le_audio::ProviderInfo> LeAudioClientInterface::GetCodecConfigProviderInfo(
96 void) const {
97 return std::nullopt;
98 }
Get()99 LeAudioClientInterface* LeAudioClientInterface::Get() { return nullptr; }
100 } // namespace bluetooth::audio::le_audio
101
102 namespace bluetooth::le_audio {
103
UpdateGmapOffloaderSupport(bool)104 void GmapClient::UpdateGmapOffloaderSupport(bool) {}
UpdateGmapOffloaderSupport(bool)105 void GmapServer::UpdateGmapOffloaderSupport(bool) {}
106
107 class MockLeAudioSourceHalClient;
108 MockLeAudioSourceHalClient* mock_le_audio_source_hal_client_;
109 std::unique_ptr<LeAudioSourceAudioHalClient> owned_mock_le_audio_source_hal_client_;
110 bool is_audio_unicast_source_acquired;
111 bool is_audio_broadcast_source_acquired;
112
AcquireUnicast()113 std::unique_ptr<LeAudioSourceAudioHalClient> LeAudioSourceAudioHalClient::AcquireUnicast() {
114 if (is_audio_unicast_source_acquired) {
115 return nullptr;
116 }
117 is_audio_unicast_source_acquired = true;
118 return std::move(owned_mock_le_audio_source_hal_client_);
119 }
120
121 MockLeAudioSourceHalClient* mock_broadcast_le_audio_source_hal_client_;
122 std::unique_ptr<LeAudioSourceAudioHalClient> owned_mock_broadcast_le_audio_source_hal_client_;
123
AcquireBroadcast()124 std::unique_ptr<LeAudioSourceAudioHalClient> LeAudioSourceAudioHalClient::AcquireBroadcast() {
125 if (is_audio_broadcast_source_acquired) {
126 return nullptr;
127 }
128 is_audio_broadcast_source_acquired = true;
129 return std::move(owned_mock_broadcast_le_audio_source_hal_client_);
130 }
131
DebugDump(int)132 void LeAudioSourceAudioHalClient::DebugDump(int /*fd*/) {}
133
134 class MockLeAudioSinkHalClient;
135 MockLeAudioSinkHalClient* mock_le_audio_sink_hal_client_;
136 std::unique_ptr<LeAudioSinkAudioHalClient> owned_mock_le_audio_sink_hal_client_;
137 bool is_audio_unicast_sink_acquired;
138
AcquireUnicast()139 std::unique_ptr<LeAudioSinkAudioHalClient> LeAudioSinkAudioHalClient::AcquireUnicast() {
140 if (is_audio_unicast_sink_acquired) {
141 return nullptr;
142 }
143 is_audio_unicast_sink_acquired = true;
144 return std::move(owned_mock_le_audio_sink_hal_client_);
145 }
146
147 class MockLeAudioSinkHalClient : public LeAudioSinkAudioHalClient {
148 public:
149 MockLeAudioSinkHalClient() = default;
150 MOCK_METHOD((bool), Start,
151 (const LeAudioCodecConfiguration& codecConfiguration,
152 LeAudioSinkAudioHalClient::Callbacks* audioReceiver, DsaModes dsa_modes),
153 (override));
154 MOCK_METHOD((void), Stop, (), (override));
155 MOCK_METHOD((size_t), SendData, (uint8_t* data, uint16_t size), (override));
156 MOCK_METHOD((void), ConfirmStreamingRequest, (), (override));
157 MOCK_METHOD((void), CancelStreamingRequest, (), (override));
158 MOCK_METHOD((void), UpdateRemoteDelay, (uint16_t delay), (override));
159 MOCK_METHOD((void), UpdateAudioConfigToHal, (const ::bluetooth::le_audio::stream_config&),
160 (override));
161 MOCK_METHOD((void), SuspendedForReconfiguration, (), (override));
162 MOCK_METHOD((void), ReconfigurationComplete, (), (override));
163
164 MOCK_METHOD((std::optional<broadcaster::BroadcastConfiguration>), GetBroadcastConfig,
165 ((const std::vector<std::pair<types::LeAudioContextType, uint8_t>>&),
166 (const std::optional<std::vector<::bluetooth::le_audio::types::acs_ac_record>>&)),
167 (const override));
168
169 MOCK_METHOD((std::optional<::bluetooth::le_audio::types::AudioSetConfiguration>),
170 GetUnicastConfig,
171 (types::LeAudioContextType,
172 std::optional<const ::bluetooth::le_audio::types::PublishedAudioCapabilities*>,
173 std::optional<const ::bluetooth::le_audio::types::PublishedAudioCapabilities*>),
174 (const override));
175
176 MOCK_METHOD((void), OnDestroyed, ());
~MockLeAudioSinkHalClient()177 virtual ~MockLeAudioSinkHalClient() override { OnDestroyed(); }
178 };
179
180 class MockLeAudioSourceHalClient : public LeAudioSourceAudioHalClient {
181 public:
182 MockLeAudioSourceHalClient() = default;
183 MOCK_METHOD((bool), Start,
184 (const LeAudioCodecConfiguration& codecConfiguration,
185 LeAudioSourceAudioHalClient::Callbacks* audioReceiver, DsaModes dsa_modes),
186 (override));
187 MOCK_METHOD((void), Stop, (), (override));
188 MOCK_METHOD((void), ConfirmStreamingRequest, (), (override));
189 MOCK_METHOD((void), CancelStreamingRequest, (), (override));
190 MOCK_METHOD((void), UpdateRemoteDelay, (uint16_t delay), (override));
191 MOCK_METHOD((void), UpdateAudioConfigToHal, (const ::bluetooth::le_audio::stream_config&),
192 (override));
193 MOCK_METHOD((void), UpdateBroadcastAudioConfigToHal,
194 (const ::bluetooth::le_audio::broadcast_offload_config&), (override));
195 MOCK_METHOD((void), SuspendedForReconfiguration, (), (override));
196 MOCK_METHOD((void), ReconfigurationComplete, (), (override));
197
198 MOCK_METHOD((std::optional<broadcaster::BroadcastConfiguration>), GetBroadcastConfig,
199 ((const std::vector<std::pair<types::LeAudioContextType, uint8_t>>&),
200 (const std::optional<std::vector<::bluetooth::le_audio::types::acs_ac_record>>&)),
201 (const override));
202
203 MOCK_METHOD((std::optional<::bluetooth::le_audio::types::AudioSetConfiguration>),
204 GetUnicastConfig, (const CodecManager::UnicastConfigurationRequirements&),
205 (const override));
206
207 MOCK_METHOD((void), OnDestroyed, ());
~MockLeAudioSourceHalClient()208 virtual ~MockLeAudioSourceHalClient() override { OnDestroyed(); }
209 };
210
211 static const types::LeAudioCodecId kLeAudioCodecIdLc3 = {
212 .coding_format = types::kLeAudioCodingFormatLC3,
213 .vendor_company_id = types::kLeAudioVendorCompanyIdUndefined,
214 .vendor_codec_id = types::kLeAudioVendorCodecIdUndefined};
215
216 static const types::LeAudioCodecId kLeAudioCodecIdVendor_C0DE = {
217 .coding_format = types::kLeAudioCodingFormatVendorSpecific,
218 .vendor_company_id = types::kLeAudioVendorCompanyIdGoogle,
219 .vendor_codec_id = 0xC0DE};
220
221 static const types::CodecConfigSetting lc3_16_2 = {
222 .id = kLeAudioCodecIdLc3,
223 .params = types::LeAudioLtvMap({
224 LTV_ENTRY_SAMPLING_FREQUENCY(codec_spec_conf::kLeAudioSamplingFreq16000Hz),
225 LTV_ENTRY_FRAME_DURATION(codec_spec_conf::kLeAudioCodecFrameDur10000us),
226 LTV_ENTRY_AUDIO_CHANNEL_ALLOCATION(codec_spec_conf::kLeAudioLocationStereo),
227 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(40),
228 }),
229 .channel_count_per_iso_stream = 1,
230 };
231
232 static const types::CodecConfigSetting lc3_24_2 = {
233 .id = kLeAudioCodecIdLc3,
234 .params = types::LeAudioLtvMap({
235 LTV_ENTRY_SAMPLING_FREQUENCY(codec_spec_conf::kLeAudioSamplingFreq24000Hz),
236 LTV_ENTRY_FRAME_DURATION(codec_spec_conf::kLeAudioCodecFrameDur10000us),
237 LTV_ENTRY_AUDIO_CHANNEL_ALLOCATION(codec_spec_conf::kLeAudioLocationStereo),
238 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(60),
239 }),
240 .channel_count_per_iso_stream = 1,
241 };
242
243 static const types::CodecConfigSetting lc3_32_2 = {
244 .id = kLeAudioCodecIdLc3,
245 .params = types::LeAudioLtvMap({
246 LTV_ENTRY_SAMPLING_FREQUENCY(codec_spec_conf::kLeAudioSamplingFreq32000Hz),
247 LTV_ENTRY_FRAME_DURATION(codec_spec_conf::kLeAudioCodecFrameDur10000us),
248 LTV_ENTRY_AUDIO_CHANNEL_ALLOCATION(codec_spec_conf::kLeAudioLocationStereo),
249 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(80),
250 }),
251 .channel_count_per_iso_stream = 1,
252 };
253
254 static const types::CodecConfigSetting lc3_48_2 = {
255 .id = kLeAudioCodecIdLc3,
256 .params = types::LeAudioLtvMap({
257 LTV_ENTRY_SAMPLING_FREQUENCY(codec_spec_conf::kLeAudioSamplingFreq48000Hz),
258 LTV_ENTRY_FRAME_DURATION(codec_spec_conf::kLeAudioCodecFrameDur10000us),
259 LTV_ENTRY_AUDIO_CHANNEL_ALLOCATION(codec_spec_conf::kLeAudioLocationStereo),
260 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(100),
261 }),
262 .channel_count_per_iso_stream = 1,
263 };
264
265 static const types::CodecConfigSetting vendor_code_48_2 = {
266 .id = kLeAudioCodecIdVendor_C0DE,
267 .params = types::LeAudioLtvMap({
268 LTV_ENTRY_SAMPLING_FREQUENCY(codec_spec_conf::kLeAudioSamplingFreq48000Hz),
269 LTV_ENTRY_FRAME_DURATION(codec_spec_conf::kLeAudioCodecFrameDur10000us),
270 LTV_ENTRY_AUDIO_CHANNEL_ALLOCATION(codec_spec_conf::kLeAudioLocationStereo),
271 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(100),
272 }),
273 .vendor_params = {03, 01, 02, 03},
274 .channel_count_per_iso_stream = 1,
275 };
276
set_mock_offload_capabilities(const std::vector<AudioSetConfiguration> & caps)277 static void set_mock_offload_capabilities(const std::vector<AudioSetConfiguration>& caps) {
278 offload_capabilities = ∩︀
279 }
280
281 static constexpr char kPropLeAudioOffloadSupported[] = "ro.bluetooth.leaudio_offload.supported";
282 static constexpr char kPropLeAudioCodecExtensibility[] =
283 "bluetooth.core.le_audio.codec_extension_aidl.enabled";
284 static constexpr char kPropLeAudioOffloadDisabled[] = "persist.bluetooth.leaudio_offload.disabled";
285 static constexpr char kPropLeAudioBidirSwbSupported[] =
286 "bluetooth.leaudio.dual_bidirection_swb.supported";
287
GetTestAddress(uint8_t index)288 static RawAddress GetTestAddress(uint8_t index) {
289 EXPECT_LT(index, UINT8_MAX);
290 RawAddress result = {{0xC0, 0xDE, 0xC0, 0xDE, 0x00, index}};
291 return result;
292 }
293
294 class CodecManagerTestBase : public Test {
295 public:
SetUp()296 virtual void SetUp() override {
297 __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
298 com::android::bluetooth::flags::provider_->reset_flags();
299 set_mock_offload_capabilities(offload_capabilities_none);
300
301 bluetooth::legacy::hci::testing::SetMock(legacy_hci_mock_);
302
303 bluetooth::hci::testing::mock_controller_ =
304 std::make_unique<NiceMock<bluetooth::hci::testing::MockControllerInterface>>();
305 ON_CALL(*bluetooth::hci::testing::mock_controller_, SupportsBleIsochronousBroadcaster)
306 .WillByDefault(Return(true));
307 ON_CALL(*bluetooth::hci::testing::mock_controller_, IsSupported(OpCode::CONFIGURE_DATA_PATH))
308 .WillByDefault(Return(true));
309
310 codec_manager = CodecManager::GetInstance();
311
312 RegisterSourceHalClientMock();
313 RegisterSinkHalClientMock();
314 }
315
TearDown()316 virtual void TearDown() override {
317 codec_manager->Stop();
318 bluetooth::hci::testing::mock_controller_.release();
319 }
320
321 CodecManager* codec_manager;
322 bluetooth::legacy::hci::testing::MockInterface legacy_hci_mock_;
323
324 protected:
RegisterSourceHalClientMock()325 void RegisterSourceHalClientMock() {
326 owned_mock_le_audio_source_hal_client_.reset(new NiceMock<MockLeAudioSourceHalClient>());
327 mock_le_audio_source_hal_client_ =
328 (MockLeAudioSourceHalClient*)owned_mock_le_audio_source_hal_client_.get();
329
330 is_audio_unicast_source_acquired = false;
331
332 owned_mock_broadcast_le_audio_source_hal_client_.reset(
333 new NiceMock<MockLeAudioSourceHalClient>());
334 mock_broadcast_le_audio_source_hal_client_ =
335 (MockLeAudioSourceHalClient*)owned_mock_broadcast_le_audio_source_hal_client_.get();
336 is_audio_broadcast_source_acquired = false;
337
338 ON_CALL(*mock_le_audio_source_hal_client_, OnDestroyed).WillByDefault([]() {
339 mock_le_audio_source_hal_client_ = nullptr;
340 is_audio_unicast_source_acquired = false;
341 });
342 }
343
RegisterSinkHalClientMock()344 void RegisterSinkHalClientMock() {
345 owned_mock_le_audio_sink_hal_client_.reset(new NiceMock<MockLeAudioSinkHalClient>());
346 mock_le_audio_sink_hal_client_ =
347 (MockLeAudioSinkHalClient*)owned_mock_le_audio_sink_hal_client_.get();
348
349 is_audio_unicast_sink_acquired = false;
350
351 ON_CALL(*mock_le_audio_sink_hal_client_, OnDestroyed).WillByDefault([]() {
352 mock_le_audio_sink_hal_client_ = nullptr;
353 is_audio_unicast_sink_acquired = false;
354 });
355 }
356 };
357
358 /*----------------- ADSP codec manager tests ------------------*/
359 class CodecManagerTestAdsp : public CodecManagerTestBase {
360 public:
SetUp()361 virtual void SetUp() override {
362 // Enable the HW offloader
363 osi_property_set_bool(kPropLeAudioOffloadSupported, true);
364 osi_property_set_bool(kPropLeAudioOffloadDisabled, false);
365
366 // Allow for bidir SWB configurations
367 osi_property_set_bool(kPropLeAudioBidirSwbSupported, true);
368
369 // Disable codec extensibility by default
370 osi_property_set_bool(kPropLeAudioCodecExtensibility, false);
371
372 CodecManagerTestBase::SetUp();
373 }
374 };
375
376 class CodecManagerTestAdspNoSwb : public CodecManagerTestBase {
377 public:
SetUp()378 virtual void SetUp() override {
379 // Enable the HW offloader
380 osi_property_set_bool(kPropLeAudioOffloadSupported, true);
381 osi_property_set_bool(kPropLeAudioOffloadDisabled, false);
382
383 // Allow for bidir SWB configurations
384 osi_property_set_bool(kPropLeAudioBidirSwbSupported, false);
385
386 CodecManagerTestBase::SetUp();
387 }
388 };
389
TEST_F(CodecManagerTestAdsp,test_init)390 TEST_F(CodecManagerTestAdsp, test_init) { ASSERT_EQ(codec_manager, CodecManager::GetInstance()); }
391
TEST_F(CodecManagerTestAdsp,test_start)392 TEST_F(CodecManagerTestAdsp, test_start) {
393 EXPECT_CALL(legacy_hci_mock_, ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER,
394 kIsoDataPathPlatformDefault, _))
395 .Times(1);
396 EXPECT_CALL(legacy_hci_mock_, ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST,
397 kIsoDataPathPlatformDefault, _))
398 .Times(1);
399
400 // Verify data path is reset on Stop()
401 EXPECT_CALL(legacy_hci_mock_,
402 ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, kIsoDataPathHci, _))
403 .Times(1);
404 EXPECT_CALL(legacy_hci_mock_,
405 ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, kIsoDataPathHci, _))
406 .Times(1);
407
408 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
409 codec_manager->Start(offloading_preference);
410
411 ASSERT_EQ(codec_manager->GetCodecLocation(), CodecLocation::ADSP);
412 }
413
TEST_F(CodecManagerTestAdsp,testStreamConfigurationAdspDownMix)414 TEST_F(CodecManagerTestAdsp, testStreamConfigurationAdspDownMix) {
415 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
416 codec_manager->Start(offloading_preference);
417
418 // Current CIS configuration for two earbuds
419 std::vector<struct types::cis> cises{
420 {
421 .id = 0x00,
422 .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
423 .conn_handle = 96,
424 },
425 {
426 .id = 0x01,
427 .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
428 .conn_handle = 97,
429 },
430 };
431
432 // Stream parameters
433 types::BidirectionalPair<stream_parameters> stream_params{
434 .sink =
435 {
436 .audio_channel_allocation = codec_spec_conf::kLeAudioLocationFrontLeft,
437 .stream_config =
438 {
439 .stream_map = {stream_map_info(
440 97, codec_spec_conf::kLeAudioLocationFrontLeft,
441 true)},
442 .bits_per_sample = 16,
443 .sampling_frequency_hz = 16000,
444 .frame_duration_us = 10000,
445 .octets_per_codec_frame = 40,
446 .codec_frames_blocks_per_sdu = 1,
447 .peer_delay_ms = 44,
448 },
449 .num_of_channels = 1,
450 .num_of_devices = 1,
451 },
452 .source =
453 {
454 .audio_channel_allocation = codec_spec_conf::kLeAudioLocationFrontLeft,
455 .stream_config =
456 {
457 .stream_map = {stream_map_info(
458 97, codec_spec_conf::kLeAudioLocationBackLeft,
459 true)},
460 .bits_per_sample = 16,
461 .sampling_frequency_hz = 16000,
462 .frame_duration_us = 10000,
463 .octets_per_codec_frame = 40,
464 .codec_frames_blocks_per_sdu = 1,
465 .peer_delay_ms = 44,
466 },
467 .num_of_channels = 1,
468 .num_of_devices = 1,
469 },
470 };
471
472 codec_manager->UpdateCisConfiguration(cises, stream_params.sink, kLeAudioDirectionSink);
473 codec_manager->UpdateCisConfiguration(cises, stream_params.source, kLeAudioDirectionSource);
474
475 // Verify the offloader config content
476 types::BidirectionalPair<std::optional<stream_config>> out_offload_configs;
477 codec_manager->UpdateActiveAudioConfig(
478 stream_params, [&out_offload_configs](const stream_config& config, uint8_t direction) {
479 out_offload_configs.get(direction) = config;
480 });
481
482 // Expect the same configuration for sink and source
483 ASSERT_TRUE(out_offload_configs.sink.has_value());
484 ASSERT_TRUE(out_offload_configs.source.has_value());
485 for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
486 bluetooth::le_audio::types::kLeAudioDirectionSource}) {
487 uint32_t allocation = 0;
488 auto& config = out_offload_configs.get(direction).value();
489 ASSERT_EQ(2lu, config.stream_map.size());
490 for (const auto& info : config.stream_map) {
491 if (info.stream_handle == 96) {
492 ASSERT_EQ(codec_spec_conf::kLeAudioLocationFrontRight, info.audio_channel_allocation);
493 // The disconnected should be inactive
494 ASSERT_FALSE(info.is_stream_active);
495
496 } else if (info.stream_handle == 97) {
497 ASSERT_EQ(codec_spec_conf::kLeAudioLocationFrontLeft, info.audio_channel_allocation);
498 // The connected should be active
499 ASSERT_TRUE(info.is_stream_active);
500
501 } else {
502 ASSERT_EQ(97, info.stream_handle);
503 }
504 allocation |= info.audio_channel_allocation;
505 }
506
507 ASSERT_EQ(16, config.bits_per_sample);
508 ASSERT_EQ(16000u, config.sampling_frequency_hz);
509 ASSERT_EQ(10000u, config.frame_duration_us);
510 ASSERT_EQ(40u, config.octets_per_codec_frame);
511 ASSERT_EQ(1, config.codec_frames_blocks_per_sdu);
512 ASSERT_EQ(44, config.peer_delay_ms);
513 ASSERT_EQ(codec_spec_conf::kLeAudioLocationStereo, allocation);
514 }
515
516 // Clear the CIS configuration map (no active CISes).
517 codec_manager->ClearCisConfiguration(kLeAudioDirectionSink);
518 codec_manager->ClearCisConfiguration(kLeAudioDirectionSource);
519 out_offload_configs.sink = std::nullopt;
520 out_offload_configs.source = std::nullopt;
521 codec_manager->UpdateActiveAudioConfig(
522 stream_params, [&out_offload_configs](const stream_config& config, uint8_t direction) {
523 out_offload_configs.get(direction) = config;
524 });
525
526 // Expect sink & source configurations with empty CIS channel allocation map.
527 ASSERT_TRUE(out_offload_configs.sink.has_value());
528 ASSERT_TRUE(out_offload_configs.source.has_value());
529 for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
530 bluetooth::le_audio::types::kLeAudioDirectionSource}) {
531 auto& config = out_offload_configs.get(direction).value();
532 ASSERT_EQ(0lu, config.stream_map.size());
533 ASSERT_EQ(16, config.bits_per_sample);
534 ASSERT_EQ(16000u, config.sampling_frequency_hz);
535 ASSERT_EQ(10000u, config.frame_duration_us);
536 ASSERT_EQ(40u, config.octets_per_codec_frame);
537 ASSERT_EQ(1, config.codec_frames_blocks_per_sdu);
538 ASSERT_EQ(44, config.peer_delay_ms);
539 }
540 }
541
TEST_F(CodecManagerTestAdsp,testStreamConfigurationMono)542 TEST_F(CodecManagerTestAdsp, testStreamConfigurationMono) {
543 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
544 codec_manager->Start(offloading_preference);
545
546 // Current CIS configuration for two earbuds
547 std::vector<struct types::cis> cises{
548 {
549 .id = 0x00,
550 .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
551 .conn_handle = 96,
552 .addr = RawAddress::kEmpty, // Disconnected
553 },
554 {
555 .id = 0x01,
556 .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
557 .conn_handle = 97,
558 .addr = GetTestAddress(1),
559 },
560 };
561
562 // Stream parameters
563 auto stream_map_entry_mono_bidir =
564 stream_map_info(97, codec_spec_conf::kLeAudioLocationMonoAudio, true);
565 stream_map_entry_mono_bidir.codec_config.id = kLeAudioCodecIdLc3;
566 types::BidirectionalPair<stream_parameters> stream_params{
567 .sink =
568 {
569 .audio_channel_allocation = codec_spec_conf::kLeAudioLocationMonoAudio,
570 .stream_config =
571 {
572 .stream_map = {stream_map_entry_mono_bidir},
573 .bits_per_sample = 16,
574 .sampling_frequency_hz = 16000,
575 .frame_duration_us = 10000,
576 .octets_per_codec_frame = 40,
577 .codec_frames_blocks_per_sdu = 1,
578 .peer_delay_ms = 44,
579 },
580 .num_of_channels = 1,
581 .num_of_devices = 1,
582 },
583 .source =
584 {
585 .audio_channel_allocation = codec_spec_conf::kLeAudioLocationMonoAudio,
586 .stream_config =
587 {
588 .stream_map = {stream_map_entry_mono_bidir},
589 .bits_per_sample = 16,
590 .sampling_frequency_hz = 16000,
591 .frame_duration_us = 10000,
592 .octets_per_codec_frame = 40,
593 .codec_frames_blocks_per_sdu = 1,
594 .peer_delay_ms = 44,
595 },
596 .num_of_channels = 1,
597 .num_of_devices = 1,
598 },
599 };
600
601 ASSERT_TRUE(
602 codec_manager->UpdateCisConfiguration(cises, stream_params.sink, kLeAudioDirectionSink));
603 ASSERT_TRUE(codec_manager->UpdateCisConfiguration(cises, stream_params.source,
604 kLeAudioDirectionSource));
605
606 // Verify the offloader config content
607 types::BidirectionalPair<std::optional<stream_config>> out_offload_configs;
608 codec_manager->UpdateActiveAudioConfig(
609 stream_params, [&out_offload_configs](const stream_config& config, uint8_t direction) {
610 out_offload_configs.get(direction) = config;
611 });
612
613 // Expect the same configuration for sink and source
614 ASSERT_TRUE(out_offload_configs.sink.has_value());
615 ASSERT_TRUE(out_offload_configs.source.has_value());
616 for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
617 bluetooth::le_audio::types::kLeAudioDirectionSource}) {
618 uint32_t allocation = 0;
619 auto& config = out_offload_configs.get(direction).value();
620 ASSERT_EQ(2lu, config.stream_map.size());
621 for (const auto& info : config.stream_map) {
622 if (info.stream_handle == 96) {
623 ASSERT_EQ(codec_spec_conf::kLeAudioLocationMonoAudio, info.audio_channel_allocation);
624 // The disconnected should be inactive
625 ASSERT_FALSE(info.is_stream_active);
626
627 } else if (info.stream_handle == 97) {
628 ASSERT_EQ(codec_spec_conf::kLeAudioLocationMonoAudio, info.audio_channel_allocation);
629 // The connected should be active
630 ASSERT_TRUE(info.is_stream_active);
631 ASSERT_EQ(info.codec_config.id.coding_format, kLeAudioCodecIdLc3.coding_format);
632
633 } else {
634 ASSERT_EQ(97, info.stream_handle);
635 }
636 allocation |= info.audio_channel_allocation;
637 }
638
639 ASSERT_EQ(16, config.bits_per_sample);
640 ASSERT_EQ(16000u, config.sampling_frequency_hz);
641 ASSERT_EQ(10000u, config.frame_duration_us);
642 ASSERT_EQ(40u, config.octets_per_codec_frame);
643 ASSERT_EQ(1, config.codec_frames_blocks_per_sdu);
644 ASSERT_EQ(44, config.peer_delay_ms);
645 ASSERT_EQ(codec_spec_conf::kLeAudioLocationMonoAudio, allocation);
646 }
647
648 // Clear the CIS configuration map (no active CISes).
649 codec_manager->ClearCisConfiguration(kLeAudioDirectionSink);
650 codec_manager->ClearCisConfiguration(kLeAudioDirectionSource);
651 out_offload_configs.sink = std::nullopt;
652 out_offload_configs.source = std::nullopt;
653 codec_manager->UpdateActiveAudioConfig(
654 stream_params, [&out_offload_configs](const stream_config& config, uint8_t direction) {
655 out_offload_configs.get(direction) = config;
656 });
657
658 // Expect sink & source configurations with empty CIS channel allocation map.
659 ASSERT_TRUE(out_offload_configs.sink.has_value());
660 ASSERT_TRUE(out_offload_configs.source.has_value());
661 for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
662 bluetooth::le_audio::types::kLeAudioDirectionSource}) {
663 auto& config = out_offload_configs.get(direction).value();
664 ASSERT_EQ(0lu, config.stream_map.size());
665 ASSERT_EQ(16, config.bits_per_sample);
666 ASSERT_EQ(16000u, config.sampling_frequency_hz);
667 ASSERT_EQ(10000u, config.frame_duration_us);
668 ASSERT_EQ(40u, config.octets_per_codec_frame);
669 ASSERT_EQ(1, config.codec_frames_blocks_per_sdu);
670 ASSERT_EQ(44, config.peer_delay_ms);
671 }
672 }
673
TEST_F(CodecManagerTestAdsp,test_capabilities_none)674 TEST_F(CodecManagerTestAdsp, test_capabilities_none) {
675 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
676 codec_manager->Start(offloading_preference);
677
678 bool has_null_config = false;
679 auto match_first_config =
680 [&](const CodecManager::UnicastConfigurationRequirements& /*requirements*/,
681 const types::AudioSetConfigurations* confs)
682 -> std::unique_ptr<types::AudioSetConfiguration> {
683 // Don't expect the matcher being called on nullptr
684 if (confs == nullptr) {
685 has_null_config = true;
686 }
687 if (confs && confs->size()) {
688 // For simplicity return the first element, the real matcher should
689 // check the group capabilities.
690 return std::make_unique<AudioSetConfiguration>(*(confs->at(0)));
691 }
692 return nullptr;
693 };
694
695 // Verify every context
696 for (::bluetooth::le_audio::types::LeAudioContextType ctx_type :
697 ::bluetooth::le_audio::types::kLeAudioContextAllTypesArray) {
698 has_null_config = false;
699 CodecManager::UnicastConfigurationRequirements requirements = {
700 .audio_context_type = ctx_type,
701 };
702 ASSERT_EQ(nullptr, codec_manager->GetCodecConfig(requirements, match_first_config));
703 ASSERT_FALSE(has_null_config);
704 }
705 }
706
TEST_F(CodecManagerTestAdsp,test_capabilities)707 TEST_F(CodecManagerTestAdsp, test_capabilities) {
708 for (auto test_context : ::bluetooth::le_audio::types::kLeAudioContextAllTypesArray) {
709 // Build the offloader capabilities vector using the configuration provider
710 // in HOST mode to get all the .json file configuration entries.
711 std::vector<AudioSetConfiguration> offload_capabilities;
712 AudioSetConfigurationProvider::Initialize(bluetooth::le_audio::types::CodecLocation::HOST);
713 auto all_local_configs = AudioSetConfigurationProvider::Get()->GetConfigurations(test_context);
714 ASSERT_NE(0lu, all_local_configs->size());
715
716 for (auto& cap : *all_local_configs) {
717 offload_capabilities.push_back(*cap);
718 }
719
720 ASSERT_NE(0u, offload_capabilities.size());
721 set_mock_offload_capabilities(offload_capabilities);
722 // Clean up before the codec manager starts it in ADSP mode.
723 AudioSetConfigurationProvider::Cleanup();
724
725 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
726 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
727 codec_manager->Start(offloading_preference);
728
729 auto output_capabilities = codec_manager->GetLocalAudioOutputCodecCapa();
730 bool is_multiplex_supported = false;
731 for (auto& capa : output_capabilities) {
732 if (capa.channel_count > bluetooth::le_audio::LE_AUDIO_CHANNEL_COUNT_INDEX_1) {
733 is_multiplex_supported = true;
734 break;
735 }
736 }
737
738 ASSERT_TRUE(is_multiplex_supported);
739
740 size_t available_configs_size = 0;
741 auto match_first_config =
742 [&available_configs_size](
743 const CodecManager::UnicastConfigurationRequirements& /*requirements*/,
744 const types::AudioSetConfigurations* confs)
745 -> std::unique_ptr<types::AudioSetConfiguration> {
746 if (confs && confs->size()) {
747 available_configs_size = confs->size();
748 // For simplicity return the first element, the real matcher should
749 // check the group capabilities.
750 return std::make_unique<AudioSetConfiguration>(*(confs->at(0)));
751 }
752 return nullptr;
753 };
754
755 CodecManager::UnicastConfigurationRequirements requirements = {
756 .audio_context_type = test_context,
757 };
758 auto cfg = codec_manager->GetCodecConfig(requirements, match_first_config);
759 ASSERT_NE(nullptr, cfg);
760 ASSERT_EQ(offload_capabilities.size(), available_configs_size);
761
762 // Clean up the before testing any other offload capabilities.
763 codec_manager->Stop();
764 }
765 }
766
TEST_F(CodecManagerTestAdsp,test_broadcast_config)767 TEST_F(CodecManagerTestAdsp, test_broadcast_config) {
768 static const types::CodecConfigSetting bc_lc3_48_2 = {
769 .id = kLeAudioCodecIdLc3,
770 .params = types::LeAudioLtvMap({
771 LTV_ENTRY_SAMPLING_FREQUENCY(codec_spec_conf::kLeAudioSamplingFreq48000Hz),
772 LTV_ENTRY_FRAME_DURATION(codec_spec_conf::kLeAudioCodecFrameDur10000us),
773 LTV_ENTRY_AUDIO_CHANNEL_ALLOCATION(codec_spec_conf::kLeAudioLocationStereo),
774 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(100),
775 }),
776 .channel_count_per_iso_stream = 2,
777 };
778
779 std::vector<AudioSetConfiguration> offload_capabilities = {{
780 .name = "Test_Broadcast_Config_No_Dev_lc3_48_2",
781 .confs = {.sink = {types::AseConfiguration(bc_lc3_48_2),
782 types::AseConfiguration(bc_lc3_48_2)},
783 .source = {}},
784 }};
785 set_mock_offload_capabilities(offload_capabilities);
786
787 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
788 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
789 codec_manager->Start(offloading_preference);
790
791 CodecManager::BroadcastConfigurationRequirements requirements = {
792 .subgroup_quality = {{types::LeAudioContextType::MEDIA, 1}}};
793 auto cfg = codec_manager->GetBroadcastConfig(requirements);
794 ASSERT_EQ(2, cfg->GetNumBisTotal());
795 ASSERT_EQ(2, cfg->GetNumChannelsMax());
796 ASSERT_EQ(48000u, cfg->GetSamplingFrequencyHzMax());
797 ASSERT_EQ(10000u, cfg->GetSduIntervalUs());
798 ASSERT_EQ(100u, cfg->GetMaxSduOctets());
799 ASSERT_EQ(1lu, cfg->subgroups.size());
800 ASSERT_EQ(2lu, cfg->subgroups.at(0).GetNumBis());
801 ASSERT_EQ(2lu, cfg->subgroups.at(0).GetNumChannelsTotal());
802
803 ASSERT_EQ(2lu, cfg->subgroups.at(0).GetBisCodecConfigs().at(0).GetNumBis());
804 ASSERT_EQ(2lu, cfg->subgroups.at(0).GetBisCodecConfigs().at(0).GetNumChannels());
805 ASSERT_EQ(1lu, cfg->subgroups.at(0).GetBisCodecConfigs().at(0).GetNumChannelsPerBis());
806
807 // Clean up the before testing any other offload capabilities.
808 codec_manager->Stop();
809 }
810
TEST_F(CodecManagerTestAdsp,test_update_broadcast_offloader)811 TEST_F(CodecManagerTestAdsp, test_update_broadcast_offloader) {
812 static const types::CodecConfigSetting bc_lc3_48_2 = {
813 .id = kLeAudioCodecIdLc3,
814 .params = types::LeAudioLtvMap({
815 LTV_ENTRY_SAMPLING_FREQUENCY(codec_spec_conf::kLeAudioSamplingFreq48000Hz),
816 LTV_ENTRY_FRAME_DURATION(codec_spec_conf::kLeAudioCodecFrameDur10000us),
817 LTV_ENTRY_AUDIO_CHANNEL_ALLOCATION(codec_spec_conf::kLeAudioLocationStereo),
818 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(100),
819 }),
820 .channel_count_per_iso_stream = 2,
821 };
822 std::vector<AudioSetConfiguration> offload_capabilities = {{
823 .name = "Test_Broadcast_Config_For_Offloader",
824 .confs = {.sink = {types::AseConfiguration(bc_lc3_48_2),
825 types::AseConfiguration(bc_lc3_48_2)},
826 .source = {}},
827 }};
828 set_mock_offload_capabilities(offload_capabilities);
829
830 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
831 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
832 codec_manager->Start(offloading_preference);
833
834 CodecManager::BroadcastConfigurationRequirements requirements = {
835 .subgroup_quality = {{types::LeAudioContextType::MEDIA, 1}}};
836 codec_manager->GetBroadcastConfig(requirements);
837
838 bool was_called = false;
839 bluetooth::le_audio::broadcast_offload_config bcast_config;
840 codec_manager->UpdateBroadcastConnHandle(
841 {0x0001, 0x0002}, [&](const bluetooth::le_audio::broadcast_offload_config& config) {
842 was_called = true;
843 bcast_config = config;
844 });
845
846 // Expect a call for ADSP encoding
847 ASSERT_TRUE(was_called);
848 ASSERT_EQ(2lu, bcast_config.stream_map.size());
849 ASSERT_EQ(16, bcast_config.bits_per_sample);
850 ASSERT_EQ(48000lu, bcast_config.sampling_rate);
851 ASSERT_EQ(10000lu, bcast_config.frame_duration);
852 ASSERT_EQ(100u, bcast_config.octets_per_frame);
853 ASSERT_EQ(1u, bcast_config.blocks_per_sdu);
854 ASSERT_NE(0u, bcast_config.retransmission_number);
855 ASSERT_NE(0u, bcast_config.max_transport_latency);
856 }
857
858 /*----------------- HOST codec manager tests ------------------*/
859 class CodecManagerTestHost : public CodecManagerTestBase {
860 public:
SetUp()861 virtual void SetUp() override {
862 // Enable the HW offloader
863 osi_property_set_bool(kPropLeAudioOffloadSupported, false);
864 osi_property_set_bool(kPropLeAudioOffloadDisabled, false);
865
866 // Allow for bidir SWB configurations
867 osi_property_set_bool(kPropLeAudioBidirSwbSupported, true);
868
869 // Codec extensibility disabled by default
870 osi_property_set_bool(kPropLeAudioCodecExtensibility, false);
871
872 CodecManagerTestBase::SetUp();
873 }
874 };
875
876 class CodecManagerTestHostNoSwb : public CodecManagerTestBase {
877 public:
SetUp()878 virtual void SetUp() override {
879 // Enable the HW offloader
880 osi_property_set_bool(kPropLeAudioOffloadSupported, true);
881 osi_property_set_bool(kPropLeAudioOffloadDisabled, false);
882
883 // Do not allow for bidir SWB configurations
884 osi_property_set_bool(kPropLeAudioBidirSwbSupported, false);
885
886 // Codec extensibility disabled by default
887 osi_property_set_bool(kPropLeAudioCodecExtensibility, false);
888
889 CodecManagerTestBase::SetUp();
890 }
891 };
892
TEST_F(CodecManagerTestHost,test_init)893 TEST_F(CodecManagerTestHost, test_init) { ASSERT_EQ(codec_manager, CodecManager::GetInstance()); }
894
TEST_F(CodecManagerTestHost,test_audio_session_update)895 TEST_F(CodecManagerTestHost, test_audio_session_update) {
896 ASSERT_EQ(codec_manager, CodecManager::GetInstance());
897
898 auto unicast_source = LeAudioSourceAudioHalClient::AcquireUnicast();
899 auto unicast_sink = LeAudioSinkAudioHalClient::AcquireUnicast();
900 auto broadcast_source = LeAudioSourceAudioHalClient::AcquireBroadcast();
901
902 // codec manager not started
903 ASSERT_FALSE(codec_manager->UpdateActiveUnicastAudioHalClient(unicast_source.get(),
904 unicast_sink.get(), true));
905 ASSERT_FALSE(codec_manager->UpdateActiveUnicastAudioHalClient(unicast_source.get(),
906 unicast_sink.get(), false));
907 ASSERT_FALSE(codec_manager->UpdateActiveBroadcastAudioHalClient(broadcast_source.get(), true));
908 ASSERT_FALSE(codec_manager->UpdateActiveBroadcastAudioHalClient(broadcast_source.get(), false));
909
910 std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
911
912 // Start codec manager
913 codec_manager->Start(offloading_preference);
914
915 ASSERT_TRUE(codec_manager->UpdateActiveUnicastAudioHalClient(unicast_source.get(),
916 unicast_sink.get(), true));
917 ASSERT_FALSE(codec_manager->UpdateActiveUnicastAudioHalClient(unicast_source.get(),
918 unicast_sink.get(), true));
919 ASSERT_TRUE(codec_manager->UpdateActiveUnicastAudioHalClient(unicast_source.get(),
920 unicast_sink.get(), false));
921 ASSERT_TRUE(
922 codec_manager->UpdateActiveUnicastAudioHalClient(unicast_source.get(), nullptr, true));
923 ASSERT_TRUE(codec_manager->UpdateActiveUnicastAudioHalClient(nullptr, unicast_sink.get(), true));
924 ASSERT_FALSE(codec_manager->UpdateActiveUnicastAudioHalClient(nullptr, nullptr, false));
925 ASSERT_FALSE(codec_manager->UpdateActiveUnicastAudioHalClient(nullptr, nullptr, true));
926 ASSERT_TRUE(codec_manager->UpdateActiveUnicastAudioHalClient(nullptr, unicast_sink.get(), false));
927 ASSERT_TRUE(
928 codec_manager->UpdateActiveUnicastAudioHalClient(unicast_source.get(), nullptr, false));
929
930 ASSERT_TRUE(codec_manager->UpdateActiveBroadcastAudioHalClient(broadcast_source.get(), true));
931 ASSERT_TRUE(codec_manager->UpdateActiveBroadcastAudioHalClient(broadcast_source.get(), false));
932 ASSERT_TRUE(codec_manager->UpdateActiveBroadcastAudioHalClient(broadcast_source.get(), true));
933 ASSERT_FALSE(codec_manager->UpdateActiveBroadcastAudioHalClient(broadcast_source.get(), true));
934 ASSERT_FALSE(codec_manager->UpdateActiveBroadcastAudioHalClient(unicast_source.get(), true));
935 ASSERT_FALSE(codec_manager->UpdateActiveBroadcastAudioHalClient(unicast_source.get(), false));
936 ASSERT_FALSE(codec_manager->UpdateActiveBroadcastAudioHalClient(nullptr, false));
937 ASSERT_FALSE(codec_manager->UpdateActiveBroadcastAudioHalClient(nullptr, true));
938 }
939
TEST_F(CodecManagerTestHost,test_start)940 TEST_F(CodecManagerTestHost, test_start) {
941 EXPECT_CALL(legacy_hci_mock_, ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER,
942 kIsoDataPathPlatformDefault, _))
943 .Times(0);
944 EXPECT_CALL(legacy_hci_mock_, ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST,
945 kIsoDataPathPlatformDefault, _))
946 .Times(0);
947
948 // Verify data path is NOT reset on Stop() for the Host encoding session
949 EXPECT_CALL(legacy_hci_mock_,
950 ConfigureDataPath(hci_data_direction_t::HOST_TO_CONTROLLER, kIsoDataPathHci, _))
951 .Times(0);
952 EXPECT_CALL(legacy_hci_mock_,
953 ConfigureDataPath(hci_data_direction_t::CONTROLLER_TO_HOST, kIsoDataPathHci, _))
954 .Times(0);
955
956 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
957 codec_manager->Start(offloading_preference);
958
959 ASSERT_EQ(codec_manager->GetCodecLocation(), CodecLocation::HOST);
960 }
961
TEST_F(CodecManagerTestHost,test_non_bidir_swb)962 TEST_F(CodecManagerTestHost, test_non_bidir_swb) {
963 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
964 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
965 codec_manager->Start(offloading_preference);
966
967 // NON-SWB configs
968 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
969 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)},
970 .source = {types::AseConfiguration(lc3_16_2),
971 types::AseConfiguration(lc3_16_2)}},
972 }));
973 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
974 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)},
975 .source = {types::AseConfiguration(lc3_16_2),
976 types::AseConfiguration(lc3_16_2)}},
977 }));
978 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
979 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)},
980 .source = {types::AseConfiguration(lc3_24_2),
981 types::AseConfiguration(lc3_24_2)}},
982 }));
983
984 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
985 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)},
986 .source = {types::AseConfiguration(lc3_32_2),
987 types::AseConfiguration(lc3_32_2)}},
988 }));
989 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
990 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)},
991 .source = {types::AseConfiguration(lc3_16_2),
992 types::AseConfiguration(lc3_16_2)}},
993 }));
994
995 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
996 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)},
997 .source = {types::AseConfiguration(lc3_24_2),
998 types::AseConfiguration(lc3_24_2)}},
999 }));
1000 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1001 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)},
1002 .source = {types::AseConfiguration(lc3_32_2),
1003 types::AseConfiguration(lc3_32_2)}},
1004 }));
1005 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1006 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)},
1007 .source = {types::AseConfiguration(lc3_24_2),
1008 types::AseConfiguration(lc3_24_2)}},
1009 }));
1010
1011 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1012 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)}},
1013 }));
1014 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1015 .confs = {.source = {types::AseConfiguration(lc3_16_2),
1016 types::AseConfiguration(lc3_16_2)}},
1017 }));
1018 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1019 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)}},
1020 }));
1021 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1022 .confs = {.source = {types::AseConfiguration(lc3_24_2),
1023 types::AseConfiguration(lc3_24_2)}},
1024 }));
1025 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1026 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)}},
1027 }));
1028 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1029 .confs = {.source = {types::AseConfiguration(lc3_32_2),
1030 types::AseConfiguration(lc3_32_2)}},
1031 }));
1032 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1033 .confs = {.sink = {types::AseConfiguration(lc3_48_2), types::AseConfiguration(lc3_48_2)}},
1034 }));
1035 ASSERT_FALSE(codec_manager->CheckCodecConfigIsBiDirSwb({
1036 .confs = {.source = {types::AseConfiguration(lc3_48_2),
1037 types::AseConfiguration(lc3_48_2)}},
1038 }));
1039
1040 // NON-DUAL-SWB configs
1041 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1042 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)},
1043 .source = {types::AseConfiguration(lc3_16_2),
1044 types::AseConfiguration(lc3_16_2)}},
1045 }));
1046 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1047 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)},
1048 .source = {types::AseConfiguration(lc3_16_2),
1049 types::AseConfiguration(lc3_16_2)}},
1050 }));
1051 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1052 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)},
1053 .source = {types::AseConfiguration(lc3_24_2),
1054 types::AseConfiguration(lc3_24_2)}},
1055 }));
1056
1057 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1058 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)},
1059 .source = {types::AseConfiguration(lc3_32_2),
1060 types::AseConfiguration(lc3_32_2)}},
1061 }));
1062 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1063 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)},
1064 .source = {types::AseConfiguration(lc3_16_2),
1065 types::AseConfiguration(lc3_16_2)}},
1066 }));
1067
1068 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1069 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)},
1070 .source = {types::AseConfiguration(lc3_24_2),
1071 types::AseConfiguration(lc3_24_2)}},
1072 }));
1073 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1074 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)},
1075 .source = {types::AseConfiguration(lc3_32_2),
1076 types::AseConfiguration(lc3_32_2)}},
1077 }));
1078 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1079 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)},
1080 .source = {types::AseConfiguration(lc3_24_2),
1081 types::AseConfiguration(lc3_24_2)}},
1082 }));
1083
1084 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1085 .confs = {.sink = {types::AseConfiguration(lc3_16_2), types::AseConfiguration(lc3_16_2)}},
1086 }));
1087 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1088 .confs = {.source = {types::AseConfiguration(lc3_16_2),
1089 types::AseConfiguration(lc3_16_2)}},
1090 }));
1091 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1092 .confs = {.sink = {types::AseConfiguration(lc3_24_2), types::AseConfiguration(lc3_24_2)}},
1093 }));
1094 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1095 .confs = {.source = {types::AseConfiguration(lc3_24_2),
1096 types::AseConfiguration(lc3_24_2)}},
1097 }));
1098 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1099 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)}},
1100 }));
1101 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1102 .confs = {.source = {types::AseConfiguration(lc3_32_2),
1103 types::AseConfiguration(lc3_32_2)}},
1104 }));
1105 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1106 .confs = {.sink = {types::AseConfiguration(lc3_48_2), types::AseConfiguration(lc3_48_2)}},
1107 }));
1108 ASSERT_FALSE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1109 .confs = {.source = {types::AseConfiguration(lc3_48_2),
1110 types::AseConfiguration(lc3_48_2)}},
1111 }));
1112 }
1113
TEST_F(CodecManagerTestHost,test_dual_bidir_swb)1114 TEST_F(CodecManagerTestHost, test_dual_bidir_swb) {
1115 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
1116 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
1117 codec_manager->Start(offloading_preference);
1118
1119 // Single Dev BiDir SWB configs
1120 ASSERT_TRUE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1121 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)},
1122 .source = {types::AseConfiguration(lc3_32_2),
1123 types::AseConfiguration(lc3_32_2)}},
1124 }));
1125 ASSERT_TRUE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1126 .confs = {.sink = {types::AseConfiguration(lc3_48_2), types::AseConfiguration(lc3_48_2)},
1127 .source = {types::AseConfiguration(lc3_32_2),
1128 types::AseConfiguration(lc3_32_2)}},
1129 }));
1130 ASSERT_TRUE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1131 .confs = {.sink = {types::AseConfiguration(lc3_32_2), types::AseConfiguration(lc3_32_2)},
1132 .source = {types::AseConfiguration(lc3_48_2),
1133 types::AseConfiguration(lc3_48_2)}},
1134 }));
1135 ASSERT_TRUE(codec_manager->CheckCodecConfigIsDualBiDirSwb({
1136 .confs = {.sink = {types::AseConfiguration(lc3_48_2), types::AseConfiguration(lc3_48_2)},
1137 .source = {types::AseConfiguration(lc3_48_2),
1138 types::AseConfiguration(lc3_48_2)}},
1139 }));
1140 }
1141
TEST_F(CodecManagerTestHost,test_dual_bidir_swb_supported)1142 TEST_F(CodecManagerTestHost, test_dual_bidir_swb_supported) {
1143 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
1144 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
1145 codec_manager->Start(offloading_preference);
1146
1147 int num_of_dual_bidir_swb_configs = 0;
1148 for (auto context : types::kLeAudioContextAllTypesArray) {
1149 bool got_null_cfgs_container = false;
1150 auto ptr = codec_manager->GetCodecConfig(
1151 {.audio_context_type = context},
1152 [&](const CodecManager::UnicastConfigurationRequirements& /*requirements*/,
1153 const types::AudioSetConfigurations* confs)
1154 -> std::unique_ptr<types::AudioSetConfiguration> {
1155 if (confs == nullptr) {
1156 got_null_cfgs_container = true;
1157 } else {
1158 num_of_dual_bidir_swb_configs +=
1159 std::count_if(confs->begin(), confs->end(), [&](auto const& cfg) {
1160 bool is_bidir = codec_manager->CheckCodecConfigIsDualBiDirSwb(*cfg);
1161 return codec_manager->CheckCodecConfigIsDualBiDirSwb(*cfg);
1162 });
1163 }
1164 // In this case the chosen configuration doesn't matter - select none
1165 return nullptr;
1166 });
1167 ASSERT_FALSE(got_null_cfgs_container);
1168 }
1169
1170 // Make sure some dual bidir SWB configs were returned
1171 ASSERT_NE(0, num_of_dual_bidir_swb_configs);
1172 }
1173
TEST_F(CodecManagerTestAdsp,test_dual_bidir_swb_supported)1174 TEST_F(CodecManagerTestAdsp, test_dual_bidir_swb_supported) {
1175 // Set the offloader capabilities
1176 std::vector<AudioSetConfiguration> offload_capabilities = {
1177 {
1178 .name = "Test_Bidir_SWB_Config_No_Dev_lc3_32_2",
1179 .confs = {.sink = {types::AseConfiguration(lc3_32_2),
1180 types::AseConfiguration(lc3_32_2)},
1181 .source = {types::AseConfiguration(lc3_32_2),
1182 types::AseConfiguration(lc3_32_2)}},
1183 },
1184 {
1185 .name = "Test_Bidir_Non_SWB_Config_No_Dev_lc3_16_2",
1186 .confs = {.sink = {types::AseConfiguration(lc3_16_2),
1187 types::AseConfiguration(lc3_16_2)},
1188 .source = {types::AseConfiguration(lc3_16_2),
1189 types::AseConfiguration(lc3_16_2)}},
1190 }};
1191 set_mock_offload_capabilities(offload_capabilities);
1192
1193 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
1194 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
1195 codec_manager->Start(offloading_preference);
1196
1197 int num_of_dual_bidir_swb_configs = 0;
1198 for (auto context : types::kLeAudioContextAllTypesArray) {
1199 bool got_null_cfgs_container = false;
1200 auto ptr = codec_manager->GetCodecConfig(
1201 {.audio_context_type = context},
1202 [&](const CodecManager::UnicastConfigurationRequirements& /*requirements*/,
1203 const types::AudioSetConfigurations* confs)
1204 -> std::unique_ptr<types::AudioSetConfiguration> {
1205 if (confs == nullptr) {
1206 got_null_cfgs_container = true;
1207 } else {
1208 num_of_dual_bidir_swb_configs +=
1209 std::count_if(confs->begin(), confs->end(), [&](auto const& cfg) {
1210 bool is_bidir = codec_manager->CheckCodecConfigIsDualBiDirSwb(*cfg);
1211 return codec_manager->CheckCodecConfigIsDualBiDirSwb(*cfg);
1212 });
1213 }
1214 // In this case the chosen configuration doesn't matter - select none
1215 return nullptr;
1216 });
1217 ASSERT_FALSE(got_null_cfgs_container);
1218 }
1219
1220 // Make sure some dual bidir SWB configs were returned
1221 ASSERT_NE(0, num_of_dual_bidir_swb_configs);
1222 }
1223
TEST_F(CodecManagerTestHostNoSwb,test_dual_bidir_swb_not_supported)1224 TEST_F(CodecManagerTestHostNoSwb, test_dual_bidir_swb_not_supported) {
1225 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
1226 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
1227 codec_manager->Start(offloading_preference);
1228
1229 int num_of_dual_bidir_swb_configs = 0;
1230 for (auto context : types::kLeAudioContextAllTypesArray) {
1231 bool got_null_cfgs_container = false;
1232 auto ptr = codec_manager->GetCodecConfig(
1233 {.audio_context_type = context},
1234 [&](const CodecManager::UnicastConfigurationRequirements& /*requirements*/,
1235 const types::AudioSetConfigurations* confs)
1236 -> std::unique_ptr<types::AudioSetConfiguration> {
1237 if (confs == nullptr) {
1238 got_null_cfgs_container = true;
1239 } else {
1240 num_of_dual_bidir_swb_configs +=
1241 std::count_if(confs->begin(), confs->end(), [&](auto const& cfg) {
1242 return codec_manager->CheckCodecConfigIsDualBiDirSwb(*cfg);
1243 });
1244 }
1245 // In this case the chosen configuration doesn't matter - select none
1246 return nullptr;
1247 });
1248 ASSERT_FALSE(got_null_cfgs_container);
1249 }
1250
1251 // Make sure no dual bidir SWB configs were returned
1252 ASSERT_EQ(0, num_of_dual_bidir_swb_configs);
1253 }
1254
TEST_F(CodecManagerTestAdspNoSwb,test_dual_bidir_swb_not_supported)1255 TEST_F(CodecManagerTestAdspNoSwb, test_dual_bidir_swb_not_supported) {
1256 // Set the offloader capabilities
1257 std::vector<AudioSetConfiguration> offload_capabilities = {
1258 {
1259 .name = "Test_Bidir_SWB_Config_No_Dev_lc3_32_2",
1260 .confs = {.sink = {types::AseConfiguration(lc3_32_2),
1261 types::AseConfiguration(lc3_32_2)},
1262 .source = {types::AseConfiguration(lc3_32_2),
1263 types::AseConfiguration(lc3_32_2)}},
1264 },
1265 {
1266 .name = "Test_Bidir_Non_SWB_Config_No_Dev_lc3_16_2",
1267 .confs = {.sink = {types::AseConfiguration(lc3_16_2),
1268 types::AseConfiguration(lc3_16_2)},
1269 .source = {types::AseConfiguration(lc3_16_2),
1270 types::AseConfiguration(lc3_16_2)}},
1271 }};
1272 set_mock_offload_capabilities(offload_capabilities);
1273
1274 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
1275 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
1276 codec_manager->Start(offloading_preference);
1277
1278 int num_of_dual_bidir_swb_configs = 0;
1279 for (auto context : types::kLeAudioContextAllTypesArray) {
1280 bool got_null_cfgs_container = false;
1281 auto ptr = codec_manager->GetCodecConfig(
1282 {.audio_context_type = context},
1283 [&](const CodecManager::UnicastConfigurationRequirements& /*requirements*/,
1284 const types::AudioSetConfigurations* confs)
1285 -> std::unique_ptr<types::AudioSetConfiguration> {
1286 if (confs == nullptr) {
1287 got_null_cfgs_container = true;
1288 } else {
1289 num_of_dual_bidir_swb_configs +=
1290 std::count_if(confs->begin(), confs->end(), [&](auto const& cfg) {
1291 return codec_manager->CheckCodecConfigIsDualBiDirSwb(*cfg);
1292 });
1293 }
1294 // In this case the chosen configuration doesn't matter - select none
1295 return nullptr;
1296 });
1297 ASSERT_FALSE(got_null_cfgs_container);
1298 }
1299
1300 // Make sure no dual bidir SWB configs were returned
1301 ASSERT_EQ(0, num_of_dual_bidir_swb_configs);
1302 }
1303
TEST_F(CodecManagerTestHost,test_dont_update_broadcast_offloader)1304 TEST_F(CodecManagerTestHost, test_dont_update_broadcast_offloader) {
1305 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {
1306 {.codec_type = bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3}};
1307 codec_manager->Start(offloading_preference);
1308
1309 bool was_called = false;
1310 codec_manager->UpdateBroadcastConnHandle(
1311 {0x0001, 0x0002}, [&](const bluetooth::le_audio::broadcast_offload_config& /*config*/) {
1312 was_called = true;
1313 });
1314
1315 // Expect no call for HOST encoding
1316 ASSERT_FALSE(was_called);
1317 }
1318
TEST_F(CodecManagerTestHost,test_dont_call_hal_for_config)1319 TEST_F(CodecManagerTestHost, test_dont_call_hal_for_config) {
1320 osi_property_set_bool(kPropLeAudioCodecExtensibility, true);
1321
1322 // Set the offloader capabilities
1323 std::vector<AudioSetConfiguration> offload_capabilities;
1324 set_mock_offload_capabilities(offload_capabilities);
1325
1326 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference = {};
1327 codec_manager->Start(offloading_preference);
1328 codec_manager->UpdateActiveUnicastAudioHalClient(mock_le_audio_source_hal_client_,
1329 mock_le_audio_sink_hal_client_, true);
1330
1331 EXPECT_CALL(*mock_le_audio_source_hal_client_, GetUnicastConfig(_)).Times(0);
1332 codec_manager->GetCodecConfig(
1333 {.audio_context_type = types::LeAudioContextType::MEDIA},
1334 [&](const CodecManager::UnicastConfigurationRequirements& /*requirements*/,
1335 const types::AudioSetConfigurations* /*confs*/)
1336 -> std::unique_ptr<types::AudioSetConfiguration> {
1337 // In this case the chosen configuration doesn't matter - select none
1338 return nullptr;
1339 });
1340 }
1341
TEST_F(CodecManagerTestAdsp,testStreamConfigurationVendor)1342 TEST_F(CodecManagerTestAdsp, testStreamConfigurationVendor) {
1343 osi_property_set_bool(kPropLeAudioCodecExtensibility, true);
1344
1345 const std::vector<bluetooth::le_audio::btle_audio_codec_config_t> offloading_preference(0);
1346 codec_manager->Start(offloading_preference);
1347
1348 // Current CIS configuration
1349 std::vector<struct types::cis> cises{
1350 // One earbud disconnected
1351 {
1352 .id = 0x00,
1353 .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
1354 .conn_handle = 96,
1355 .addr = GetTestAddress(1),
1356 },
1357 // Second earbud connected
1358 {
1359 .id = 0x00,
1360 .type = types::CisType::CIS_TYPE_BIDIRECTIONAL,
1361 .conn_handle = 97,
1362 .addr = GetTestAddress(1),
1363 },
1364 };
1365
1366 std::vector<uint8_t> metadata_vec;
1367 AppendMetadataLtvEntryForStreamingContext(metadata_vec,
1368 types::AudioContexts(types::LeAudioContextType::GAME));
1369
1370 stream_map_info stream_map_info_sink_left(cises[0].conn_handle,
1371 codec_spec_conf::kLeAudioLocationFrontLeft, false);
1372 stream_map_info_sink_left.codec_config = vendor_code_48_2;
1373 stream_map_info_sink_left.target_latency = 0x03;
1374 stream_map_info_sink_left.target_phy = PHY_LE_2M;
1375 stream_map_info_sink_left.address = cises[1].addr;
1376 stream_map_info_sink_left.address_type = BLE_ADDR_PUBLIC;
1377 stream_map_info_sink_left.metadata.Parse(metadata_vec.data(), metadata_vec.size());
1378
1379 stream_map_info stream_map_info_sink_right(cises[1].conn_handle,
1380 codec_spec_conf::kLeAudioLocationFrontRight, true);
1381 stream_map_info_sink_right.codec_config = vendor_code_48_2;
1382 stream_map_info_sink_right.target_latency = 0x03;
1383 stream_map_info_sink_right.target_phy = PHY_LE_2M;
1384 stream_map_info_sink_right.address = cises[1].addr;
1385 stream_map_info_sink_right.address_type = BLE_ADDR_PUBLIC;
1386 stream_map_info_sink_right.metadata.Parse(metadata_vec.data(), metadata_vec.size());
1387
1388 stream_map_info stream_map_info_source_right(cises[1].conn_handle,
1389 codec_spec_conf::kLeAudioLocationFrontRight, true);
1390 stream_map_info_source_right.codec_config = vendor_code_48_2;
1391 stream_map_info_source_right.target_latency = 0x03;
1392 stream_map_info_source_right.target_phy = PHY_LE_2M;
1393 stream_map_info_source_right.address = cises[1].addr;
1394 stream_map_info_source_right.address_type = BLE_ADDR_PUBLIC;
1395 stream_map_info_source_right.metadata.Parse(metadata_vec.data(), metadata_vec.size());
1396
1397 // Stream parameters
1398 types::BidirectionalPair<stream_parameters> stream_params{
1399 .sink =
1400 {
1401 .audio_channel_allocation = codec_spec_conf::kLeAudioLocationFrontRight,
1402 .stream_config =
1403 {
1404 .stream_map = {stream_map_info_sink_right},
1405 .bits_per_sample = 16,
1406 .sampling_frequency_hz = 48000,
1407 .frame_duration_us = 10000,
1408 .octets_per_codec_frame = 100,
1409 .codec_frames_blocks_per_sdu = 1,
1410 .peer_delay_ms = 44,
1411 },
1412 .num_of_channels = 2,
1413 .num_of_devices = 1,
1414 },
1415 .source =
1416 {
1417 .audio_channel_allocation = codec_spec_conf::kLeAudioLocationFrontRight,
1418 .stream_config =
1419 {
1420 .stream_map = {stream_map_info_source_right},
1421 .bits_per_sample = 16,
1422 .sampling_frequency_hz = 48000,
1423 .frame_duration_us = 10000,
1424 .octets_per_codec_frame = 100,
1425 .codec_frames_blocks_per_sdu = 1,
1426 .peer_delay_ms = 44,
1427 },
1428 .num_of_channels = 1,
1429 .num_of_devices = 1,
1430 },
1431 };
1432
1433 ASSERT_TRUE(
1434 codec_manager->UpdateCisConfiguration(cises, stream_params.sink, kLeAudioDirectionSink));
1435 ASSERT_TRUE(codec_manager->UpdateCisConfiguration(cises, stream_params.source,
1436 kLeAudioDirectionSource));
1437
1438 // Verify the offloader config content
1439 types::BidirectionalPair<std::optional<stream_config>> out_offload_configs;
1440 codec_manager->UpdateActiveAudioConfig(
1441 stream_params, [&out_offload_configs](const stream_config& config, uint8_t direction) {
1442 out_offload_configs.get(direction) = config;
1443 });
1444
1445 // Expect the same configuration for sink and source
1446 ASSERT_TRUE(out_offload_configs.sink.has_value());
1447 ASSERT_TRUE(out_offload_configs.source.has_value());
1448 for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
1449 bluetooth::le_audio::types::kLeAudioDirectionSource}) {
1450 uint32_t allocation = 0;
1451 auto& config = out_offload_configs.get(direction).value();
1452
1453 ASSERT_EQ(2lu, config.stream_map.size());
1454
1455 for (const auto& info : config.stream_map) {
1456 if (info.stream_handle == 96) {
1457 ASSERT_EQ(codec_spec_conf::kLeAudioLocationFrontLeft, info.audio_channel_allocation);
1458 // The disconnected should be inactive
1459 ASSERT_FALSE(info.is_stream_active);
1460
1461 } else if (info.stream_handle == 97) {
1462 ASSERT_EQ(codec_spec_conf::kLeAudioLocationFrontRight, info.audio_channel_allocation);
1463 // The connected should be active
1464 ASSERT_TRUE(info.is_stream_active);
1465
1466 ASSERT_EQ(vendor_code_48_2.id, info.codec_config.id);
1467 ASSERT_EQ(vendor_code_48_2.params, info.codec_config.params);
1468 ASSERT_EQ(vendor_code_48_2.vendor_params, info.codec_config.vendor_params);
1469 ASSERT_EQ(0x03, info.target_latency);
1470 ASSERT_EQ(PHY_LE_2M, info.target_phy);
1471 ASSERT_EQ(cises[1].addr, info.address);
1472 ASSERT_EQ(BLE_ADDR_PUBLIC, info.address_type);
1473 ASSERT_EQ(stream_map_info_sink_right.metadata, info.metadata);
1474
1475 } else {
1476 ASSERT_EQ(97, info.stream_handle);
1477 }
1478 allocation |= info.audio_channel_allocation;
1479 }
1480
1481 ASSERT_EQ(16, config.bits_per_sample);
1482 ASSERT_EQ(48000u, config.sampling_frequency_hz);
1483 ASSERT_EQ(10000u, config.frame_duration_us);
1484 ASSERT_EQ(100u, config.octets_per_codec_frame);
1485 ASSERT_EQ(1, config.codec_frames_blocks_per_sdu);
1486 ASSERT_EQ(44, config.peer_delay_ms);
1487 ASSERT_EQ(codec_spec_conf::kLeAudioLocationStereo, allocation);
1488 }
1489
1490 // Clear the CIS configuration map (no active CISes).
1491 codec_manager->ClearCisConfiguration(kLeAudioDirectionSink);
1492 codec_manager->ClearCisConfiguration(kLeAudioDirectionSource);
1493 out_offload_configs.sink = std::nullopt;
1494 out_offload_configs.source = std::nullopt;
1495 codec_manager->UpdateActiveAudioConfig(
1496 stream_params, [&out_offload_configs](const stream_config& config, uint8_t direction) {
1497 out_offload_configs.get(direction) = config;
1498 });
1499
1500 // Expect sink & source configurations with empty CIS channel allocation map.
1501 ASSERT_TRUE(out_offload_configs.sink.has_value());
1502 ASSERT_TRUE(out_offload_configs.source.has_value());
1503 for (auto direction : {bluetooth::le_audio::types::kLeAudioDirectionSink,
1504 bluetooth::le_audio::types::kLeAudioDirectionSource}) {
1505 auto& config = out_offload_configs.get(direction).value();
1506 ASSERT_EQ(0lu, config.stream_map.size());
1507 ASSERT_EQ(16, config.bits_per_sample);
1508 ASSERT_EQ(48000u, config.sampling_frequency_hz);
1509 ASSERT_EQ(10000u, config.frame_duration_us);
1510 ASSERT_EQ(100u, config.octets_per_codec_frame);
1511 ASSERT_EQ(1, config.codec_frames_blocks_per_sdu);
1512 ASSERT_EQ(44, config.peer_delay_ms);
1513 }
1514 }
1515
1516 } // namespace bluetooth::le_audio
1517