1 /*
2 * Copyright 2021 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 <bluetooth/log.h>
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 #include <hardware/audio.h>
22
23 #include <chrono>
24
25 #include "bta/include/bta_le_audio_api.h"
26 #include "bta/include/bta_le_audio_broadcaster_api.h"
27 #include "bta/le_audio/audio_hal_client/audio_hal_client.h"
28 #include "bta/le_audio/broadcaster/broadcast_configuration_provider.h"
29 #include "bta/le_audio/broadcaster/mock_state_machine.h"
30 #include "bta/le_audio/content_control_id_keeper.h"
31 #include "bta/le_audio/le_audio_types.h"
32 #include "bta/le_audio/mock_codec_manager.h"
33 #include "hci/controller_interface_mock.h"
34 #include "stack/include/btm_iso_api.h"
35 #include "test/common/mock_functions.h"
36 #include "test/mock/mock_main_shim_entry.h"
37 #include "test/mock/mock_stack_btm_iso.h"
38
39 using namespace std::chrono_literals;
40
41 using bluetooth::le_audio::types::AudioContexts;
42 using bluetooth::le_audio::types::LeAudioContextType;
43
44 using testing::_;
45 using testing::AtLeast;
46 using testing::DoAll;
47 using testing::Invoke;
48 using testing::Matcher;
49 using testing::Mock;
50 using testing::NotNull;
51 using testing::Return;
52 using testing::ReturnRef;
53 using testing::SaveArg;
54 using testing::Test;
55
56 using namespace bluetooth::le_audio;
57 using namespace bluetooth;
58
59 using bluetooth::le_audio::DsaMode;
60 using bluetooth::le_audio::LeAudioCodecConfiguration;
61 using bluetooth::le_audio::LeAudioSourceAudioHalClient;
62 using bluetooth::le_audio::broadcaster::BigConfig;
63 using bluetooth::le_audio::broadcaster::BroadcastSubgroupCodecConfig;
64
65 // Disables most likely false-positives from base::SplitString()
__asan_default_options()66 extern "C" const char* __asan_default_options() {
67 return "detect_container_overflow=0";
68 }
69
70 static base::Callback<void(BT_OCTET8)> generator_cb;
71
btsnd_hcic_ble_rand(base::Callback<void (BT_OCTET8)> cb)72 void btsnd_hcic_ble_rand(base::Callback<void(BT_OCTET8)> cb) {
73 generator_cb = cb;
74 }
75
76 namespace server_configurable_flags {
GetServerConfigurableFlag(const std::string & experiment_category_name,const std::string & experiment_flag_name,const std::string & default_value)77 std::string GetServerConfigurableFlag(
78 const std::string& experiment_category_name,
79 const std::string& experiment_flag_name, const std::string& default_value) {
80 return "";
81 }
82 } // namespace server_configurable_flags
83
84 std::atomic<int> num_async_tasks;
85 bluetooth::common::MessageLoopThread message_loop_thread("test message loop");
get_main_thread()86 bluetooth::common::MessageLoopThread* get_main_thread() {
87 return &message_loop_thread;
88 }
invoke_switch_buffer_size_cb(bool is_low_latency_buffer_size)89 void invoke_switch_buffer_size_cb(bool is_low_latency_buffer_size) {}
90
do_in_main_thread(const base::Location & from_here,base::OnceClosure task)91 bt_status_t do_in_main_thread(const base::Location& from_here,
92 base::OnceClosure task) {
93 // Wrap the task with task counter so we could later know if there are
94 // any callbacks scheduled and we should wait before performing some actions
95 if (!message_loop_thread.DoInThread(
96 from_here,
97 base::BindOnce(
98 [](base::OnceClosure task, std::atomic<int>& num_async_tasks) {
99 std::move(task).Run();
100 num_async_tasks--;
101 },
102 std::move(task), std::ref(num_async_tasks)))) {
103 log::error("failed from {}", from_here.ToString());
104 return BT_STATUS_FAIL;
105 }
106 num_async_tasks++;
107 return BT_STATUS_SUCCESS;
108 }
109
110 static base::MessageLoop* message_loop_;
get_main_message_loop()111 base::MessageLoop* get_main_message_loop() { return message_loop_; }
112
init_message_loop_thread()113 static void init_message_loop_thread() {
114 num_async_tasks = 0;
115 message_loop_thread.StartUp();
116 if (!message_loop_thread.IsRunning()) {
117 FAIL() << "unable to create message loop thread.";
118 }
119
120 if (!message_loop_thread.EnableRealTimeScheduling())
121 log::error("Unable to set real time scheduling");
122
123 message_loop_ = message_loop_thread.message_loop();
124 if (message_loop_ == nullptr) FAIL() << "unable to get message loop.";
125 }
126
cleanup_message_loop_thread()127 static void cleanup_message_loop_thread() {
128 message_loop_ = nullptr;
129 message_loop_thread.ShutDown();
130 }
131
IsLeAudioClientRunning(void)132 bool LeAudioClient::IsLeAudioClientRunning(void) { return false; }
133
134 namespace bluetooth::le_audio {
135 namespace broadcaster {
GetBroadcastConfig(const std::vector<std::pair<types::LeAudioContextType,uint8_t>> & subgroup_quality)136 BroadcastConfiguration GetBroadcastConfig(
137 const std::vector<std::pair<types::LeAudioContextType, uint8_t>>&
138 subgroup_quality) {
139 BroadcastConfiguration config = {
140 .subgroups = {},
141 .qos = qos_config_4_60, // default QoS value for reliability
142 .data_path = lc3_data_path,
143 .sduIntervalUs = 10000,
144 .phy = 0x02, // PHY_LE_2M
145 .packing = 0, // Sequential
146 .framing = 0, // Unframed
147 };
148
149 for (auto [context, quality] : subgroup_quality) {
150 // Select QoS - Check for low latency contexts
151 if (AudioContexts(context).test_any(
152 types::LeAudioContextType::GAME | types::LeAudioContextType::LIVE |
153 types::LeAudioContextType::INSTRUCTIONAL |
154 types::LeAudioContextType::SOUNDEFFECTS)) {
155 config.qos = qos_config_2_10;
156 }
157
158 // Select codec quality
159 if (quality == bluetooth::le_audio::QUALITY_STANDARD) {
160 // STANDARD
161 config.subgroups.push_back(lc3_mono_16_2);
162 } else {
163 // HIGH
164 config.subgroups.push_back(lc3_stereo_48_4);
165 }
166 }
167 return config;
168 }
169 } // namespace broadcaster
170
171 class MockAudioHalClientEndpoint;
172 MockAudioHalClientEndpoint* mock_audio_source_;
173 bool is_audio_hal_acquired;
174 void (*iso_active_callback)(bool);
175
176 std::unique_ptr<LeAudioSourceAudioHalClient>
AcquireBroadcast()177 LeAudioSourceAudioHalClient::AcquireBroadcast() {
178 if (mock_audio_source_) {
179 std::unique_ptr<LeAudioSourceAudioHalClient> ptr(
180 (LeAudioSourceAudioHalClient*)mock_audio_source_);
181 is_audio_hal_acquired = true;
182 return std::move(ptr);
183 }
184 return nullptr;
185 }
186
187 static constexpr uint8_t default_ccid = 0xDE;
188 static constexpr auto default_context =
189 static_cast<std::underlying_type<LeAudioContextType>::type>(
190 LeAudioContextType::ALERTS);
191 std::vector<uint8_t> default_subgroup_qualities = {
192 bluetooth::le_audio::QUALITY_STANDARD};
193 static constexpr BroadcastCode default_code = {
194 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
195 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
196 static const std::vector<uint8_t> default_metadata = {
197 bluetooth::le_audio::types::kLeAudioMetadataStreamingAudioContextLen + 1,
198 bluetooth::le_audio::types::kLeAudioMetadataTypeStreamingAudioContext,
199 default_context & 0x00FF, (default_context & 0xFF00) >> 8};
200 static const std::vector<uint8_t> default_public_metadata = {
201 5, bluetooth::le_audio::types::kLeAudioMetadataTypeProgramInfo,
202 0x1, 0x2,
203 0x3, 0x4};
204 // bit 0: encrypted, bit 1: standard quality present
205 static const uint8_t test_public_broadcast_features = 0x3;
206
207 static constexpr uint8_t media_ccid = 0xC0;
208 static constexpr auto media_context =
209 static_cast<std::underlying_type<LeAudioContextType>::type>(
210 LeAudioContextType::MEDIA);
211 static const std::vector<uint8_t> media_metadata = {
212 bluetooth::le_audio::types::kLeAudioMetadataStreamingAudioContextLen + 1,
213 bluetooth::le_audio::types::kLeAudioMetadataTypeStreamingAudioContext,
214 media_context & 0x00FF, (media_context & 0xFF00) >> 8};
215 static const std::string test_broadcast_name = "Test";
216
217 class MockLeAudioBroadcasterCallbacks
218 : public bluetooth::le_audio::LeAudioBroadcasterCallbacks {
219 public:
220 MOCK_METHOD((void), OnBroadcastCreated, (uint32_t broadcast_id, bool success),
221 (override));
222 MOCK_METHOD((void), OnBroadcastDestroyed, (uint32_t broadcast_id),
223 (override));
224 MOCK_METHOD((void), OnBroadcastStateChanged,
225 (uint32_t broadcast_id,
226 bluetooth::le_audio::BroadcastState state),
227 (override));
228 MOCK_METHOD((void), OnBroadcastMetadataChanged,
229 (uint32_t broadcast_id,
230 const BroadcastMetadata& broadcast_metadata),
231 (override));
232 };
233
234 class MockAudioHalClientEndpoint : public LeAudioSourceAudioHalClient {
235 public:
236 MockAudioHalClientEndpoint() = default;
237 MOCK_METHOD((bool), Start,
238 (const LeAudioCodecConfiguration& codecConfiguration,
239 LeAudioSourceAudioHalClient::Callbacks* audioReceiver,
240 ::bluetooth::le_audio::DsaModes dsa_modes),
241 (override));
242 MOCK_METHOD((void), Stop, (), (override));
243 MOCK_METHOD((void), ConfirmStreamingRequest, (), (override));
244 MOCK_METHOD((void), CancelStreamingRequest, (), (override));
245 MOCK_METHOD((void), UpdateRemoteDelay, (uint16_t delay), (override));
246 MOCK_METHOD((void), UpdateAudioConfigToHal,
247 (const ::bluetooth::le_audio::offload_config&), (override));
248 MOCK_METHOD(
249 (std::optional<broadcaster::BroadcastConfiguration>), GetBroadcastConfig,
250 ((const std::vector<std::pair<types::LeAudioContextType, uint8_t>>&),
251 (const std::optional<
252 std::vector<::bluetooth::le_audio::types::acs_ac_record>>&)),
253 (const override));
254 MOCK_METHOD(
255 (std::optional<::le_audio::set_configurations::AudioSetConfiguration>),
256 GetUnicastConfig,
257 (const CodecManager::UnicastConfigurationRequirements& requirements),
258 (const override));
259 MOCK_METHOD((void), UpdateBroadcastAudioConfigToHal,
260 (const ::bluetooth::le_audio::broadcast_offload_config&),
261 (override));
262 MOCK_METHOD((void), SuspendedForReconfiguration, (), (override));
263 MOCK_METHOD((void), ReconfigurationComplete, (), (override));
264
265 MOCK_METHOD((void), OnDestroyed, ());
~MockAudioHalClientEndpoint()266 virtual ~MockAudioHalClientEndpoint() { OnDestroyed(); }
267 };
268
269 class BroadcasterTest : public Test {
270 protected:
SetUp()271 void SetUp() override {
272 init_message_loop_thread();
273
274 reset_mock_function_count_map();
275 bluetooth::hci::testing::mock_controller_ = &mock_controller_;
276 ON_CALL(mock_controller_, SupportsBleIsochronousBroadcaster)
277 .WillByDefault(Return(true));
278
279 iso_manager_ = bluetooth::hci::IsoManager::GetInstance();
280 ASSERT_NE(iso_manager_, nullptr);
281 iso_manager_->Start();
282
283 mock_iso_manager_ = MockIsoManager::GetInstance();
284 ON_CALL(*mock_iso_manager_, RegisterBigCallbacks(_))
285 .WillByDefault(SaveArg<0>(&big_callbacks_));
286
287 ConfigAudioHalClientMock();
288
289 EXPECT_CALL(*MockIsoManager::GetInstance(),
290 RegisterOnIsoTrafficActiveCallbacks)
291 .WillOnce(SaveArg<0>(&iso_active_callback));
292
293 ASSERT_FALSE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning());
294 LeAudioBroadcaster::Initialize(&mock_broadcaster_callbacks_,
295 base::Bind([]() -> bool { return true; }));
296
297 ContentControlIdKeeper::GetInstance()->Start();
298 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA,
299 media_ccid);
300
301 /* Simulate random generator */
302 uint8_t random[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
303 generator_cb.Run(random);
304
305 ConfigCodecManagerMock(types::CodecLocation::HOST);
306
307 ON_CALL(*mock_codec_manager_, UpdateActiveUnicastAudioHalClient(_, _, _))
308 .WillByDefault(Return(true));
309 ON_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(_, _))
310 .WillByDefault(Return(true));
311 ON_CALL(*mock_codec_manager_, GetBroadcastConfig)
312 .WillByDefault(
313 Invoke([](const bluetooth::le_audio::CodecManager::
314 BroadcastConfigurationRequirements& requirements) {
315 return std::make_unique<broadcaster::BroadcastConfiguration>(
316 bluetooth::le_audio::broadcaster::GetBroadcastConfig(
317 requirements.subgroup_quality));
318 }));
319 }
320
ConfigAudioHalClientMock()321 void ConfigAudioHalClientMock() {
322 is_audio_hal_acquired = false;
323 mock_audio_source_ = new MockAudioHalClientEndpoint();
324 ON_CALL(*mock_audio_source_, Start).WillByDefault(Return(true));
325 ON_CALL(*mock_audio_source_, OnDestroyed).WillByDefault([]() {
326 mock_audio_source_ = nullptr;
327 is_audio_hal_acquired = false;
328 });
329 }
330
ConfigCodecManagerMock(types::CodecLocation location)331 void ConfigCodecManagerMock(types::CodecLocation location) {
332 codec_manager_ = le_audio::CodecManager::GetInstance();
333 ASSERT_NE(codec_manager_, nullptr);
334 std::vector<bluetooth::le_audio::btle_audio_codec_config_t>
335 mock_offloading_preference(0);
336 codec_manager_->Start(mock_offloading_preference);
337 mock_codec_manager_ = MockCodecManager::GetInstance();
338 ASSERT_NE(mock_codec_manager_, nullptr);
339 ON_CALL(*mock_codec_manager_, GetCodecLocation())
340 .WillByDefault(Return(location));
341 }
342
TearDown()343 void TearDown() override {
344 // Message loop cleanup should wait for all the 'till now' scheduled calls
345 // so it should be called right at the very begginning of teardown.
346 cleanup_message_loop_thread();
347
348 // This is required since Stop() and Cleanup() may trigger some callbacks.
349 Mock::VerifyAndClearExpectations(&mock_broadcaster_callbacks_);
350
351 Mock::VerifyAndClearExpectations(MockIsoManager::GetInstance());
352 Mock::VerifyAndClearExpectations(
353 MockBroadcastStateMachine::GetLastInstance());
354
355 LeAudioBroadcaster::Stop();
356 LeAudioBroadcaster::Cleanup();
357 ASSERT_FALSE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning());
358
359 ContentControlIdKeeper::GetInstance()->Stop();
360
361 bluetooth::hci::testing::mock_controller_ = nullptr;
362 delete mock_audio_source_;
363 iso_active_callback = nullptr;
364 delete mock_audio_source_;
365 iso_manager_->Stop();
366 if (codec_manager_) {
367 codec_manager_->Stop();
368 mock_codec_manager_ = nullptr;
369 }
370 }
371
InstantiateBroadcast(std::vector<uint8_t> metadata=default_metadata,BroadcastCode code=default_code,std::vector<uint8_t> quality_array=default_subgroup_qualities,bool is_queued=false)372 uint32_t InstantiateBroadcast(
373 std::vector<uint8_t> metadata = default_metadata,
374 BroadcastCode code = default_code,
375 std::vector<uint8_t> quality_array = default_subgroup_qualities,
376 bool is_queued = false) {
377 uint32_t broadcast_id = LeAudioBroadcaster::kInstanceIdUndefined;
378 if (!is_queued) {
379 EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true))
380 .WillOnce(SaveArg<0>(&broadcast_id));
381 }
382
383 std::vector<std::vector<uint8_t>> metadata_array;
384 for (uint8_t i = 0; i < quality_array.size(); i++) {
385 // use the same default_metadata for each subgroup
386 metadata_array.push_back(metadata);
387 }
388
389 // Add multiple subgroup settings with the same content
390 LeAudioBroadcaster::Get()->CreateAudioBroadcast(
391 true, test_broadcast_name, code, default_public_metadata, quality_array,
392 metadata_array);
393
394 return broadcast_id;
395 }
396
InjectBigCreateComplete(uint8_t big_id,uint8_t status)397 void InjectBigCreateComplete(uint8_t big_id, uint8_t status) {
398 std::vector<uint16_t> conn_handles = {0x10, 0x12};
399
400 hci::iso_manager::big_create_cmpl_evt evt = {
401 .status = status,
402 .big_id = big_id,
403 .big_sync_delay = 1231,
404 .transport_latency_big = 1234,
405 .phy = 2,
406 .nse = 3,
407 .bn = 2,
408 .pto = 2,
409 .irc = 2,
410 .max_pdu = 128,
411 .iso_interval = 10,
412 .conn_handles = conn_handles,
413 };
414
415 big_callbacks_->OnBigEvent(
416 bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, &evt);
417 }
418
InjectBigTerminateComplete(uint8_t big_id,uint8_t reason)419 void InjectBigTerminateComplete(uint8_t big_id, uint8_t reason) {
420 hci::iso_manager::big_terminate_cmpl_evt evt = {.big_id = big_id,
421 .reason = reason};
422 big_callbacks_->OnBigEvent(
423 bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl, &evt);
424 }
425
426 protected:
427 MockLeAudioBroadcasterCallbacks mock_broadcaster_callbacks_;
428 bluetooth::hci::testing::MockControllerInterface mock_controller_;
429 bluetooth::hci::IsoManager* iso_manager_;
430 MockIsoManager* mock_iso_manager_;
431 bluetooth::hci::iso_manager::BigCallbacks* big_callbacks_ = nullptr;
432
433 le_audio::CodecManager* codec_manager_ = nullptr;
434 MockCodecManager* mock_codec_manager_ = nullptr;
435 };
436
TEST_F(BroadcasterTest,Initialize)437 TEST_F(BroadcasterTest, Initialize) {
438 ASSERT_NE(LeAudioBroadcaster::Get(), nullptr);
439 ASSERT_TRUE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning());
440 }
441
TEST_F(BroadcasterTest,GetStreamingPhy)442 TEST_F(BroadcasterTest, GetStreamingPhy) {
443 LeAudioBroadcaster::Get()->SetStreamingPhy(1);
444 ASSERT_EQ(LeAudioBroadcaster::Get()->GetStreamingPhy(), 1);
445 LeAudioBroadcaster::Get()->SetStreamingPhy(2);
446 ASSERT_EQ(LeAudioBroadcaster::Get()->GetStreamingPhy(), 2);
447 }
448
TEST_F(BroadcasterTest,CreateAudioBroadcast)449 TEST_F(BroadcasterTest, CreateAudioBroadcast) {
450 auto broadcast_id = InstantiateBroadcast();
451 ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined);
452 ASSERT_EQ(broadcast_id,
453 MockBroadcastStateMachine::GetLastInstance()->GetBroadcastId());
454
455 auto& instance_config = MockBroadcastStateMachine::GetLastInstance()->cfg;
456 ASSERT_EQ(instance_config.broadcast_code, default_code);
457 for (auto& subgroup : instance_config.announcement.subgroup_configs) {
458 ASSERT_EQ(types::LeAudioLtvMap(subgroup.metadata).RawPacket(),
459 default_metadata);
460 }
461 // Note: There shall be a separate test to verify audio parameters
462 }
463
TEST_F(BroadcasterTest,CreateAudioBroadcastMultiGroups)464 TEST_F(BroadcasterTest, CreateAudioBroadcastMultiGroups) {
465 // Test with two subgroups
466 auto broadcast_id =
467 InstantiateBroadcast(default_metadata, default_code,
468 {bluetooth::le_audio::QUALITY_STANDARD,
469 bluetooth::le_audio::QUALITY_STANDARD});
470 ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined);
471 ASSERT_EQ(broadcast_id,
472 MockBroadcastStateMachine::GetLastInstance()->GetBroadcastId());
473
474 auto& instance_config = MockBroadcastStateMachine::GetLastInstance()->cfg;
475 ASSERT_EQ(instance_config.broadcast_code, default_code);
476 ASSERT_EQ(instance_config.announcement.subgroup_configs.size(), (uint8_t) 2);
477 for (auto& subgroup : instance_config.announcement.subgroup_configs) {
478 ASSERT_EQ(types::LeAudioLtvMap(subgroup.metadata).RawPacket(),
479 default_metadata);
480 }
481 }
482
TEST_F(BroadcasterTest,SuspendAudioBroadcast)483 TEST_F(BroadcasterTest, SuspendAudioBroadcast) {
484 EXPECT_CALL(*mock_codec_manager_,
485 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true))
486 .Times(1);
487 auto broadcast_id = InstantiateBroadcast();
488 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
489 Mock::VerifyAndClearExpectations(mock_codec_manager_);
490
491 EXPECT_CALL(mock_broadcaster_callbacks_,
492 OnBroadcastStateChanged(broadcast_id, BroadcastState::CONFIGURED))
493 .Times(1);
494
495 EXPECT_CALL(*mock_audio_source_, Stop).Times(AtLeast(1));
496 EXPECT_CALL(*mock_codec_manager_,
497 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, _))
498 .Times(0);
499 LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id);
500 Mock::VerifyAndClearExpectations(mock_codec_manager_);
501 }
502
TEST_F(BroadcasterTest,StartAudioBroadcast)503 TEST_F(BroadcasterTest, StartAudioBroadcast) {
504 EXPECT_CALL(*mock_codec_manager_,
505 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true))
506 .Times(1);
507 auto broadcast_id = InstantiateBroadcast();
508 Mock::VerifyAndClearExpectations(mock_codec_manager_);
509
510 EXPECT_CALL(*mock_codec_manager_,
511 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true))
512 .Times(0);
513 EXPECT_CALL(*mock_codec_manager_,
514 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, false))
515 .Times(0);
516 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
517
518 EXPECT_CALL(mock_broadcaster_callbacks_,
519 OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING))
520 .Times(1);
521
522 LeAudioSourceAudioHalClient::Callbacks* audio_receiver;
523 EXPECT_CALL(*mock_audio_source_, Start)
524 .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)));
525
526 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
527 ASSERT_NE(audio_receiver, nullptr);
528
529 // NOTICE: This is really an implementation specific part, we fake the BIG
530 // config as the mocked state machine does not even call the
531 // IsoManager to prepare one (and that's good since IsoManager is also
532 // a mocked one).
533 BigConfig big_cfg;
534 big_cfg.big_id =
535 MockBroadcastStateMachine::GetLastInstance()->GetAdvertisingSid();
536 big_cfg.connection_handles = {0x10, 0x12};
537 big_cfg.max_pdu = 128;
538 MockBroadcastStateMachine::GetLastInstance()->SetExpectedBigConfig(big_cfg);
539
540 // Inject the audio and verify call on the Iso manager side.
541 EXPECT_CALL(*MockIsoManager::GetInstance(), SendIsoData).Times(1);
542 std::vector<uint8_t> sample_data(320, 0);
543 audio_receiver->OnAudioDataReady(sample_data);
544
545 Mock::VerifyAndClearExpectations(mock_codec_manager_);
546 }
547
TEST_F(BroadcasterTest,StartAudioBroadcastMedia)548 TEST_F(BroadcasterTest, StartAudioBroadcastMedia) {
549 EXPECT_CALL(*mock_codec_manager_,
550 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true))
551 .Times(1);
552 auto broadcast_id = InstantiateBroadcast(media_metadata, default_code,
553 {bluetooth::le_audio::QUALITY_HIGH});
554 Mock::VerifyAndClearExpectations(mock_codec_manager_);
555
556 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
557
558 EXPECT_CALL(mock_broadcaster_callbacks_,
559 OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING))
560 .Times(1);
561
562 LeAudioSourceAudioHalClient::Callbacks* audio_receiver;
563 EXPECT_CALL(*mock_audio_source_, Start)
564 .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)));
565 EXPECT_CALL(*mock_codec_manager_,
566 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true))
567 .Times(0);
568 EXPECT_CALL(*mock_codec_manager_,
569 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, false))
570 .Times(0);
571
572 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
573 ASSERT_NE(audio_receiver, nullptr);
574
575 // NOTICE: This is really an implementation specific part, we fake the BIG
576 // config as the mocked state machine does not even call the
577 // IsoManager to prepare one (and that's good since IsoManager is also
578 // a mocked one).
579
580 auto mock_state_machine = MockBroadcastStateMachine::GetLastInstance();
581 BigConfig big_cfg;
582 big_cfg.big_id = mock_state_machine->GetAdvertisingSid();
583 big_cfg.connection_handles = {0x10, 0x12};
584 big_cfg.max_pdu = 128;
585 mock_state_machine->SetExpectedBigConfig(big_cfg);
586
587 // Inject the audio and verify call on the Iso manager side.
588 EXPECT_CALL(*MockIsoManager::GetInstance(), SendIsoData).Times(2);
589 std::vector<uint8_t> sample_data(1920, 0);
590 audio_receiver->OnAudioDataReady(sample_data);
591 Mock::VerifyAndClearExpectations(mock_codec_manager_);
592 }
593
TEST_F(BroadcasterTest,StopAudioBroadcast)594 TEST_F(BroadcasterTest, StopAudioBroadcast) {
595 EXPECT_CALL(*mock_codec_manager_,
596 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true))
597 .Times(1);
598 EXPECT_CALL(*mock_codec_manager_,
599 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, false))
600 .Times(1);
601 auto broadcast_id = InstantiateBroadcast();
602 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
603
604 // NOTICE: This is really an implementation specific part, we fake the BIG
605 // config as the mocked state machine does not even call the
606 // IsoManager to prepare one (and that's good since IsoManager is also
607 // a mocked one).
608
609 auto mock_state_machine = MockBroadcastStateMachine::GetLastInstance();
610 BigConfig big_cfg;
611 big_cfg.big_id = mock_state_machine->GetAdvertisingSid();
612 big_cfg.connection_handles = {0x10, 0x12};
613 big_cfg.max_pdu = 128;
614 mock_state_machine->SetExpectedBigConfig(big_cfg);
615
616 InjectBigCreateComplete(big_cfg.big_id, 0x00);
617 EXPECT_CALL(mock_broadcaster_callbacks_,
618 OnBroadcastStateChanged(broadcast_id, BroadcastState::STOPPED))
619 .Times(1);
620
621 EXPECT_CALL(*mock_audio_source_, Stop).Times(AtLeast(1));
622 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
623 InjectBigTerminateComplete(big_cfg.big_id, 0x16);
624 Mock::VerifyAndClearExpectations(mock_codec_manager_);
625 }
626
TEST_F(BroadcasterTest,DestroyAudioBroadcast)627 TEST_F(BroadcasterTest, DestroyAudioBroadcast) {
628 EXPECT_CALL(*mock_codec_manager_,
629 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true))
630 .Times(1);
631
632 auto broadcast_id = InstantiateBroadcast();
633
634 Mock::VerifyAndClearExpectations(mock_codec_manager_);
635
636 EXPECT_CALL(*mock_codec_manager_,
637 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, false))
638 .Times(1);
639 EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastDestroyed(broadcast_id))
640 .Times(1);
641 LeAudioBroadcaster::Get()->DestroyAudioBroadcast(broadcast_id);
642
643 Mock::VerifyAndClearExpectations(mock_codec_manager_);
644 ASSERT_EQ(mock_audio_source_, nullptr);
645
646 /* Create a mock again for the test purpose */
647 ConfigAudioHalClientMock();
648
649 EXPECT_CALL(*mock_codec_manager_,
650 UpdateActiveBroadcastAudioHalClient(mock_audio_source_, _))
651 .Times(0);
652
653 // Expect not being able to interact with this Broadcast
654 EXPECT_CALL(mock_broadcaster_callbacks_,
655 OnBroadcastStateChanged(broadcast_id, _))
656 .Times(0);
657
658 EXPECT_CALL(*mock_audio_source_, Stop).Times(0);
659 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
660
661 EXPECT_CALL(*mock_audio_source_, Start).Times(0);
662 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
663
664 EXPECT_CALL(*mock_audio_source_, Stop).Times(0);
665 LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id);
666
667 Mock::VerifyAndClearExpectations(mock_codec_manager_);
668 Mock::VerifyAndClearExpectations(&mock_broadcaster_callbacks_);
669 // Verify the expectations before the CleanUp, which may call Stop()
670 Mock::VerifyAndClearExpectations(mock_audio_source_);
671 }
672
TEST_F(BroadcasterTest,GetBroadcastAllStates)673 TEST_F(BroadcasterTest, GetBroadcastAllStates) {
674 auto broadcast_id = InstantiateBroadcast();
675 auto broadcast_id2 = InstantiateBroadcast();
676 ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined);
677 ASSERT_NE(broadcast_id2, LeAudioBroadcaster::kInstanceIdUndefined);
678 ASSERT_NE(broadcast_id, broadcast_id2);
679
680 /* In the current implementation state machine switches to the correct state
681 * on itself, therefore here when we use mocked state machine this is not
682 * being verified.
683 */
684 EXPECT_CALL(mock_broadcaster_callbacks_,
685 OnBroadcastStateChanged(broadcast_id, _))
686 .Times(1);
687 EXPECT_CALL(mock_broadcaster_callbacks_,
688 OnBroadcastStateChanged(broadcast_id2, _))
689 .Times(1);
690
691 LeAudioBroadcaster::Get()->GetAllBroadcastStates();
692 }
693
TEST_F(BroadcasterTest,UpdateMetadata)694 TEST_F(BroadcasterTest, UpdateMetadata) {
695 auto broadcast_id = InstantiateBroadcast();
696 std::vector<uint8_t> ccid_list;
697 std::vector<uint8_t> expected_public_meta;
698 std::string expected_broadcast_name;
699
700 EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(),
701 UpdateBroadcastAnnouncement)
702 .WillOnce(
703 [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) {
704 for (auto subgroup : announcement.subgroup_configs) {
705 if (subgroup.metadata.count(
706 types::kLeAudioMetadataTypeCcidList)) {
707 ccid_list =
708 subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList);
709 break;
710 }
711 }
712 });
713
714 EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(),
715 UpdatePublicBroadcastAnnouncement)
716 .WillOnce([&](uint32_t broadcast_id, const std::string& broadcast_name,
717 const bluetooth::le_audio::PublicBroadcastAnnouncementData&
718 announcement) {
719 expected_broadcast_name = broadcast_name;
720 expected_public_meta =
721 types::LeAudioLtvMap(announcement.metadata).RawPacket();
722 });
723
724 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::ALERTS,
725 default_ccid);
726
727 LeAudioBroadcaster::Get()->UpdateMetadata(
728 broadcast_id, test_broadcast_name, default_public_metadata,
729 {std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04})});
730
731 ASSERT_EQ(2u, ccid_list.size());
732 ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), media_ccid));
733 ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), default_ccid));
734 ASSERT_EQ(expected_broadcast_name, test_broadcast_name);
735 ASSERT_EQ(expected_public_meta, default_public_metadata);
736 }
737
prepareAnnouncement(const BroadcastSubgroupCodecConfig & codec_config,std::map<uint8_t,std::vector<uint8_t>> metadata)738 static BasicAudioAnnouncementData prepareAnnouncement(
739 const BroadcastSubgroupCodecConfig& codec_config,
740 std::map<uint8_t, std::vector<uint8_t>> metadata) {
741 BasicAudioAnnouncementData announcement;
742
743 announcement.presentation_delay_us = 40000;
744 auto const& codec_id = codec_config.GetLeAudioCodecId();
745 auto const subgroup_codec_spec = codec_config.GetCommonBisCodecSpecData();
746
747 // Note: This is a single subgroup announcement.
748 announcement.subgroup_configs = {{
749 .codec_config =
750 {
751 .codec_id = codec_id.coding_format,
752 .vendor_company_id = codec_id.vendor_company_id,
753 .vendor_codec_id = codec_id.vendor_codec_id,
754 .codec_specific_params = subgroup_codec_spec.Values(),
755 },
756 .metadata = std::move(metadata),
757 .bis_configs = {},
758 }};
759
760 uint8_t bis_count = 0;
761 for (uint8_t cfg_idx = 0; cfg_idx < codec_config.GetAllBisConfigCount();
762 ++cfg_idx) {
763 for (uint8_t bis_num = 0; bis_num < codec_config.GetNumBis(cfg_idx);
764 ++bis_num) {
765 ++bis_count;
766
767 // Check for vendor byte array
768 bluetooth::le_audio::BasicAudioAnnouncementBisConfig bis_config;
769 auto vendor_config = codec_config.GetBisVendorCodecSpecData(bis_num);
770 if (vendor_config) {
771 bis_config.vendor_codec_specific_params = vendor_config.value();
772 }
773
774 // Check for non vendor LTVs
775 auto config_ltv = codec_config.GetBisCodecSpecData(bis_num, cfg_idx);
776 if (config_ltv) {
777 bis_config.codec_specific_params = config_ltv->Values();
778 }
779
780 // Internally BISes are indexed from 0 in each subgroup, but the BT spec
781 // requires the indices to be indexed from 1 in the entire BIG.
782 bis_config.bis_index = bis_count;
783 announcement.subgroup_configs[0].bis_configs.push_back(
784 std::move(bis_config));
785 }
786 }
787
788 return announcement;
789 }
790
TEST_F(BroadcasterTest,UpdateMetadataFromAudioTrackMetadata)791 TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) {
792 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA,
793 media_ccid);
794 auto broadcast_id = InstantiateBroadcast();
795
796 LeAudioSourceAudioHalClient::Callbacks* audio_receiver;
797 EXPECT_CALL(*mock_audio_source_, Start)
798 .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)));
799
800 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
801 ASSERT_NE(audio_receiver, nullptr);
802
803 auto sm = MockBroadcastStateMachine::GetLastInstance();
804 std::vector<uint8_t> ccid_list;
805 std::vector<uint8_t> context_types_map;
806 EXPECT_CALL(*sm, UpdateBroadcastAnnouncement)
807 .WillOnce(
808 [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) {
809 for (auto subgroup : announcement.subgroup_configs) {
810 if (subgroup.metadata.count(
811 types::kLeAudioMetadataTypeCcidList)) {
812 ccid_list =
813 subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList);
814 }
815 if (subgroup.metadata.count(
816 types::kLeAudioMetadataTypeStreamingAudioContext)) {
817 context_types_map = subgroup.metadata.at(
818 types::kLeAudioMetadataTypeStreamingAudioContext);
819 }
820 }
821 });
822
823 std::map<uint8_t, std::vector<uint8_t>> meta = {};
824 auto codec_config = broadcaster::lc3_mono_16_2;
825 auto announcement = prepareAnnouncement(codec_config, meta);
826
827 ON_CALL(*sm, GetBroadcastAnnouncement())
828 .WillByDefault(ReturnRef(announcement));
829
830 std::vector<struct playback_track_metadata> multitrack_source_metadata = {
831 {{AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_SONIFICATION, 0},
832 {AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, 0},
833 {AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING, AUDIO_CONTENT_TYPE_SPEECH,
834 0},
835 {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}}};
836
837 std::vector<playback_track_metadata_v7> tracks_vec;
838 tracks_vec.reserve(multitrack_source_metadata.size());
839 for (const auto& track : multitrack_source_metadata) {
840 playback_track_metadata_v7 desc_track = {
841 .base =
842 {
843 .usage = static_cast<audio_usage_t>(track.usage),
844 .content_type =
845 static_cast<audio_content_type_t>(track.content_type),
846 .gain = track.gain,
847 },
848 };
849 tracks_vec.push_back(desc_track);
850 }
851
852 audio_receiver->OnAudioMetadataUpdate(std::move(tracks_vec),
853 DsaMode::DISABLED);
854
855 // Verify ccid
856 ASSERT_NE(ccid_list.size(), 0u);
857 ASSERT_TRUE(std::find(ccid_list.begin(), ccid_list.end(), media_ccid) !=
858 ccid_list.end());
859
860 // Verify context type
861 ASSERT_NE(context_types_map.size(), 0u);
862 AudioContexts context_type;
863 auto pp = context_types_map.data();
864 STREAM_TO_UINT16(context_type.value_ref(), pp);
865 ASSERT_TRUE(context_type.test_all(LeAudioContextType::MEDIA |
866 LeAudioContextType::GAME));
867 }
868
TEST_F(BroadcasterTest,GetMetadata)869 TEST_F(BroadcasterTest, GetMetadata) {
870 auto broadcast_id = InstantiateBroadcast();
871 bluetooth::le_audio::BroadcastMetadata metadata;
872
873 static const uint8_t test_adv_sid = 0x14;
874 std::optional<bluetooth::le_audio::BroadcastCode> test_broadcast_code =
875 bluetooth::le_audio::BroadcastCode({1, 2, 3, 4, 5, 6});
876
877 auto sm = MockBroadcastStateMachine::GetLastInstance();
878
879 std::map<uint8_t, std::vector<uint8_t>> meta = {};
880 auto codec_config = broadcaster::lc3_mono_16_2;
881 auto announcement = prepareAnnouncement(codec_config, meta);
882
883 bool is_public_metadata_valid;
884 types::LeAudioLtvMap public_ltv = types::LeAudioLtvMap::Parse(
885 default_public_metadata.data(), default_public_metadata.size(),
886 is_public_metadata_valid);
887 PublicBroadcastAnnouncementData pb_announcement = {
888 .features = test_public_broadcast_features,
889 .metadata = public_ltv.Values()};
890
891 ON_CALL(*sm, IsPublicBroadcast()).WillByDefault(Return(true));
892 ON_CALL(*sm, GetBroadcastName()).WillByDefault(Return(test_broadcast_name));
893 ON_CALL(*sm, GetBroadcastCode()).WillByDefault(Return(test_broadcast_code));
894 ON_CALL(*sm, GetAdvertisingSid()).WillByDefault(Return(test_adv_sid));
895 ON_CALL(*sm, GetBroadcastAnnouncement())
896 .WillByDefault(ReturnRef(announcement));
897 ON_CALL(*sm, GetPublicBroadcastAnnouncement())
898 .WillByDefault(ReturnRef(pb_announcement));
899
900 EXPECT_CALL(mock_broadcaster_callbacks_,
901 OnBroadcastMetadataChanged(broadcast_id, _))
902 .Times(1)
903 .WillOnce(SaveArg<1>(&metadata));
904 LeAudioBroadcaster::Get()->GetBroadcastMetadata(broadcast_id);
905
906 ASSERT_NE(LeAudioBroadcaster::kInstanceIdUndefined, metadata.broadcast_id);
907 ASSERT_EQ(sm->GetBroadcastId(), metadata.broadcast_id);
908 ASSERT_EQ(sm->GetBroadcastCode(), metadata.broadcast_code);
909 ASSERT_EQ(sm->GetBroadcastAnnouncement(), metadata.basic_audio_announcement);
910 ASSERT_EQ(sm->GetPaInterval(), metadata.pa_interval);
911 ASSERT_EQ(sm->GetOwnAddress(), metadata.addr);
912 ASSERT_EQ(sm->GetOwnAddressType(), metadata.addr_type);
913 ASSERT_EQ(sm->GetAdvertisingSid(), metadata.adv_sid);
914 ASSERT_EQ(sm->IsPublicBroadcast(), metadata.is_public);
915 ASSERT_EQ(sm->GetBroadcastName(), metadata.broadcast_name);
916 ASSERT_EQ(sm->GetPublicBroadcastAnnouncement(), metadata.public_announcement);
917 }
918
TEST_F(BroadcasterTest,SetStreamingPhy)919 TEST_F(BroadcasterTest, SetStreamingPhy) {
920 LeAudioBroadcaster::Get()->SetStreamingPhy(2);
921 // From now on new streams should be using Phy = 2.
922 InstantiateBroadcast();
923 ASSERT_EQ(MockBroadcastStateMachine::GetLastInstance()->cfg.streaming_phy, 2);
924
925 // From now on new streams should be using Phy = 1.
926 LeAudioBroadcaster::Get()->SetStreamingPhy(1);
927 InstantiateBroadcast();
928 ASSERT_EQ(MockBroadcastStateMachine::GetLastInstance()->cfg.streaming_phy, 1);
929 ASSERT_EQ(LeAudioBroadcaster::Get()->GetStreamingPhy(), 1);
930 }
931
TEST_F(BroadcasterTest,StreamParamsAlerts)932 TEST_F(BroadcasterTest, StreamParamsAlerts) {
933 uint8_t expected_channels = 1u;
934 InstantiateBroadcast();
935 auto config = MockBroadcastStateMachine::GetLastInstance()->cfg;
936
937 // Check audio configuration
938 ASSERT_EQ(config.config.subgroups.at(0).GetNumChannelsTotal(),
939 expected_channels);
940
941 // Matches number of bises in the announcement
942 ASSERT_EQ(config.announcement.subgroup_configs[0].bis_configs.size(),
943 expected_channels);
944 // Note: Num of bises at IsoManager level is verified by state machine tests
945 }
946
TEST_F(BroadcasterTest,StreamParamsMedia)947 TEST_F(BroadcasterTest, StreamParamsMedia) {
948 uint8_t expected_channels = 2u;
949 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA,
950 media_ccid);
951 InstantiateBroadcast(media_metadata, default_code,
952 {bluetooth::le_audio::QUALITY_HIGH});
953
954 auto config = MockBroadcastStateMachine::GetLastInstance()->cfg;
955
956 // Check audio configuration
957 ASSERT_EQ(config.config.subgroups.at(0).GetNumBis(), expected_channels);
958 ASSERT_EQ(config.config.subgroups.at(0).GetNumChannelsTotal(),
959 expected_channels);
960 // Note there is one BIS configuration applied to both (stereo) BISes
961 ASSERT_EQ(config.config.subgroups.at(0).GetAllBisConfigCount(),
962 (unsigned long)1);
963 ASSERT_EQ(config.config.subgroups.at(0).GetNumBis(0),
964 (unsigned long)expected_channels);
965
966 // Matches number of bises in the announcement
967 ASSERT_EQ(config.announcement.subgroup_configs.size(), 1ul);
968
969 auto& announcement_subgroup = config.announcement.subgroup_configs[0];
970 ASSERT_EQ(announcement_subgroup.bis_configs.size(), expected_channels);
971 // Verify CCID for Media
972 auto ccid_list_opt =
973 types::LeAudioLtvMap(announcement_subgroup.metadata)
974 .Find(bluetooth::le_audio::types::kLeAudioMetadataTypeCcidList);
975 ASSERT_TRUE(ccid_list_opt.has_value());
976 auto ccid_list = ccid_list_opt.value();
977 ASSERT_EQ(1u, ccid_list.size());
978 ASSERT_EQ(media_ccid, ccid_list[0]);
979 // Note: Num of bises at IsoManager level is verified by state machine tests
980 }
981
TEST_F(BroadcasterTest,QueuedBroadcast)982 TEST_F(BroadcasterTest, QueuedBroadcast) {
983 uint32_t broadcast_id = LeAudioBroadcaster::kInstanceIdUndefined;
984
985 iso_active_callback(true);
986
987 EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true))
988 .WillOnce(SaveArg<0>(&broadcast_id));
989
990 /* Trigger broadcast create but due to active ISO, queue request */
991 InstantiateBroadcast(default_metadata, default_code,
992 default_subgroup_qualities, true);
993
994 /* Notify about ISO being free, check if broadcast would be created */
995 iso_active_callback(false);
996 ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined);
997 ASSERT_EQ(broadcast_id,
998 MockBroadcastStateMachine::GetLastInstance()->GetBroadcastId());
999
1000 auto& instance_config = MockBroadcastStateMachine::GetLastInstance()->cfg;
1001 ASSERT_EQ(instance_config.broadcast_code, default_code);
1002 for (auto& subgroup : instance_config.announcement.subgroup_configs) {
1003 ASSERT_EQ(types::LeAudioLtvMap(subgroup.metadata).RawPacket(),
1004 default_metadata);
1005 }
1006 }
1007
TEST_F(BroadcasterTest,QueuedBroadcastBusyIso)1008 TEST_F(BroadcasterTest, QueuedBroadcastBusyIso) {
1009 iso_active_callback(true);
1010
1011 EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true))
1012 .Times(0);
1013
1014 /* Trigger broadcast create but due to active ISO, queue request */
1015 InstantiateBroadcast(default_metadata, default_code,
1016 default_subgroup_qualities, true);
1017 }
1018
1019 constexpr types::LeAudioCodecId kLeAudioCodecIdVendor1 = {
1020 .coding_format = types::kLeAudioCodingFormatVendorSpecific,
1021 // Not a particualr vendor - just some random numbers
1022 .vendor_company_id = 0xC0,
1023 .vendor_codec_id = 0xDE,
1024 };
1025
1026 static const types::DataPathConfiguration vendor_data_path = {
1027 .dataPathId = bluetooth::hci::iso_manager::kIsoDataPathHci,
1028 .dataPathConfig = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
1029 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
1030 .isoDataPathConfig =
1031 {
1032 .codecId = kLeAudioCodecIdVendor1,
1033 .isTransparent = true,
1034 .controllerDelayUs = 0x00000000, // irrlevant for transparent mode
1035 .configuration = {0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x79, 0x88,
1036 0x97, 0xA6, 0xB5, 0xC4, 0xD3, 0xE2, 0xF1},
1037 },
1038 };
1039
1040 // Quality subgroup configurations
1041 static const broadcaster::BroadcastSubgroupCodecConfig vendor_stereo_16_2 =
1042 broadcaster::BroadcastSubgroupCodecConfig(
1043 kLeAudioCodecIdVendor1,
1044 {broadcaster::BroadcastSubgroupBisCodecConfig{
1045 // num_bis
1046 2,
1047 // bis_channel_cnt
1048 1,
1049 // codec_specific
1050 types::LeAudioLtvMap({
1051 LTV_ENTRY_SAMPLING_FREQUENCY(
1052 codec_spec_conf::kLeAudioSamplingFreq16000Hz),
1053 LTV_ENTRY_FRAME_DURATION(
1054 codec_spec_conf::kLeAudioCodecFrameDur10000us),
1055 LTV_ENTRY_OCTETS_PER_CODEC_FRAME(50),
1056 }),
1057 // vendor_codec_specific
1058 std::vector<uint8_t>{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
1059 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
1060 0xF0},
1061 }},
1062 // bits_per_sample
1063 24,
1064 // vendor_codec_specific
1065 std::vector<uint8_t>{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
1066 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF});
1067
1068 static const broadcaster::BroadcastConfiguration vendor_stereo_16_2_1 = {
1069 // subgroup list, qos configuration, data path configuration
1070 .subgroups = {vendor_stereo_16_2},
1071 .qos = broadcaster::qos_config_2_10,
1072 .data_path = vendor_data_path,
1073 .sduIntervalUs = 5000,
1074 .maxSduOctets = 128,
1075 .phy = 0x01, // PHY_LE_1M
1076 .packing = 1, // Interleaved
1077 .framing = 1, // Framed
1078 };
1079
TEST_F(BroadcasterTest,SanityTest)1080 TEST_F(BroadcasterTest, SanityTest) {
1081 ASSERT_EQ(broadcaster::lc3_mono_16_2_1, broadcaster::lc3_mono_16_2_1);
1082 ASSERT_EQ(vendor_stereo_16_2_1, vendor_stereo_16_2_1);
1083 }
1084
TEST_F(BroadcasterTest,VendorCodecConfig)1085 TEST_F(BroadcasterTest, VendorCodecConfig) {
1086 ON_CALL(*mock_codec_manager_, GetBroadcastConfig)
1087 .WillByDefault(Invoke([](const bluetooth::le_audio::CodecManager::
1088 BroadcastConfigurationRequirements&) {
1089 return std::make_unique<broadcaster::BroadcastConfiguration>(
1090 vendor_stereo_16_2_1);
1091 }));
1092 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA,
1093 media_ccid);
1094
1095 // iso_active_callback(false);
1096 auto broadcast_id = InstantiateBroadcast(media_metadata, default_code,
1097 {bluetooth::le_audio::QUALITY_HIGH});
1098 ASSERT_NE(LeAudioBroadcaster::kInstanceIdUndefined, broadcast_id);
1099
1100 auto mock_state_machine = MockBroadcastStateMachine::GetLastInstance();
1101 ASSERT_NE(nullptr, mock_state_machine);
1102
1103 // Verify the codec config
1104 ASSERT_EQ(vendor_stereo_16_2_1, mock_state_machine->cfg.config);
1105
1106 // Verify the basic audio announcement
1107 ASSERT_NE(0lu, mock_state_machine->cfg.announcement.presentation_delay_us);
1108
1109 // One subgroup
1110 ASSERT_EQ(1lu, mock_state_machine->cfg.announcement.subgroup_configs.size());
1111 auto const& subgroup =
1112 mock_state_machine->cfg.announcement.subgroup_configs.at(0);
1113
1114 auto const& expected_subgroup_codec_conf =
1115 vendor_stereo_16_2_1.subgroups.at(0);
1116 ASSERT_EQ(expected_subgroup_codec_conf.GetNumBis(),
1117 subgroup.bis_configs.size());
1118
1119 // Subgroup level codec configuration
1120 ASSERT_EQ(expected_subgroup_codec_conf.GetLeAudioCodecId().coding_format,
1121 subgroup.codec_config.codec_id);
1122 ASSERT_EQ(expected_subgroup_codec_conf.GetLeAudioCodecId().vendor_company_id,
1123 subgroup.codec_config.vendor_company_id);
1124 ASSERT_EQ(expected_subgroup_codec_conf.GetLeAudioCodecId().vendor_codec_id,
1125 subgroup.codec_config.vendor_codec_id);
1126
1127 // There should be no common set of parameters in the LTV format if there is
1128 // a vendor specific configuration
1129 ASSERT_TRUE(subgroup.codec_config.codec_specific_params.empty());
1130 ASSERT_TRUE(subgroup.codec_config.vendor_codec_specific_params.has_value());
1131 ASSERT_EQ(
1132 0, memcmp(expected_subgroup_codec_conf.GetVendorCodecSpecData()->data(),
1133 subgroup.codec_config.vendor_codec_specific_params->data(),
1134 subgroup.codec_config.vendor_codec_specific_params->size()));
1135
1136 // Subgroup metadata
1137 ASSERT_NE(0lu, subgroup.metadata.size());
1138
1139 // Verify the BISes
1140 ASSERT_EQ(expected_subgroup_codec_conf.GetNumBis(),
1141 subgroup.bis_configs.size());
1142
1143 // Verify BIS 1
1144 uint8_t bis_idx = 1;
1145 ASSERT_EQ(bis_idx, subgroup.bis_configs.at(0).bis_index);
1146 // Expect only the vendor specific data
1147 ASSERT_TRUE(subgroup.bis_configs.at(0).codec_specific_params.empty());
1148 ASSERT_TRUE(subgroup.bis_configs.at(0)
1149 .vendor_codec_specific_params
1150 .has_value()); // BIS vendor specific parameters
1151 ASSERT_NE(0lu,
1152 subgroup.bis_configs.at(0).vendor_codec_specific_params->size());
1153 ASSERT_EQ(expected_subgroup_codec_conf.GetBisVendorCodecSpecData(0)->size(),
1154 subgroup.bis_configs.at(0).vendor_codec_specific_params->size());
1155 ASSERT_EQ(
1156 0,
1157 memcmp(expected_subgroup_codec_conf.GetBisVendorCodecSpecData(0)->data(),
1158 subgroup.bis_configs.at(0).vendor_codec_specific_params->data(),
1159 subgroup.bis_configs.at(0).vendor_codec_specific_params->size()));
1160
1161 // Verify BIS 2
1162 bis_idx = 2;
1163 ASSERT_EQ(bis_idx, subgroup.bis_configs.at(1).bis_index);
1164 // Expect only the vendor specific data
1165 ASSERT_TRUE(subgroup.bis_configs.at(1).codec_specific_params.empty());
1166 ASSERT_TRUE(subgroup.bis_configs.at(1)
1167 .vendor_codec_specific_params
1168 .has_value()); // BIS vendor specific parameters
1169 ASSERT_NE(0lu,
1170 subgroup.bis_configs.at(1).vendor_codec_specific_params->size());
1171 ASSERT_EQ(expected_subgroup_codec_conf.GetBisVendorCodecSpecData(1)->size(),
1172 subgroup.bis_configs.at(1).vendor_codec_specific_params->size());
1173 ASSERT_EQ(
1174 0,
1175 memcmp(expected_subgroup_codec_conf.GetBisVendorCodecSpecData(1)->data(),
1176 subgroup.bis_configs.at(1).vendor_codec_specific_params->data(),
1177 subgroup.bis_configs.at(1).vendor_codec_specific_params->size()));
1178 }
1179
1180 // TODO: Add tests for:
1181 // ToRawPacket(BasicAudioAnnouncementData const& in, std::vector<uint8_t>& data)
1182
1183 } // namespace bluetooth::le_audio
1184