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 <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <hardware/audio.h>
21
22 #include <chrono>
23
24 #include "bta/include/bta_le_audio_api.h"
25 #include "bta/include/bta_le_audio_broadcaster_api.h"
26 #include "bta/le_audio/broadcaster/mock_state_machine.h"
27 #include "bta/le_audio/content_control_id_keeper.h"
28 #include "bta/le_audio/le_audio_types.h"
29 #include "bta/le_audio/mock_iso_manager.h"
30 #include "bta/test/common/mock_controller.h"
31 #include "device/include/controller.h"
32 #include "stack/include/btm_iso_api.h"
33 #include "test/common/mock_functions.h"
34
35 using namespace std::chrono_literals;
36
37 using le_audio::types::AudioContexts;
38 using le_audio::types::LeAudioContextType;
39
40 using testing::_;
41 using testing::AtLeast;
42 using testing::DoAll;
43 using testing::Matcher;
44 using testing::Mock;
45 using testing::NotNull;
46 using testing::Return;
47 using testing::ReturnRef;
48 using testing::SaveArg;
49 using testing::Test;
50
51 using namespace bluetooth::le_audio;
52
53 using le_audio::LeAudioCodecConfiguration;
54 using le_audio::LeAudioSourceAudioHalClient;
55 using le_audio::broadcaster::BigConfig;
56 using le_audio::broadcaster::BroadcastCodecWrapper;
57
58 // Disables most likely false-positives from base::SplitString()
__asan_default_options()59 extern "C" const char* __asan_default_options() {
60 return "detect_container_overflow=0";
61 }
62
63 static base::Callback<void(BT_OCTET8)> generator_cb;
64
btsnd_hcic_ble_rand(base::Callback<void (BT_OCTET8)> cb)65 void btsnd_hcic_ble_rand(base::Callback<void(BT_OCTET8)> cb) {
66 generator_cb = cb;
67 }
68
69 std::atomic<int> num_async_tasks;
70 bluetooth::common::MessageLoopThread message_loop_thread("test message loop");
get_main_thread()71 bluetooth::common::MessageLoopThread* get_main_thread() {
72 return &message_loop_thread;
73 }
invoke_switch_buffer_size_cb(bool is_low_latency_buffer_size)74 void invoke_switch_buffer_size_cb(bool is_low_latency_buffer_size) {}
75
do_in_main_thread(const base::Location & from_here,base::OnceClosure task)76 bt_status_t do_in_main_thread(const base::Location& from_here,
77 base::OnceClosure task) {
78 // Wrap the task with task counter so we could later know if there are
79 // any callbacks scheduled and we should wait before performing some actions
80 if (!message_loop_thread.DoInThread(
81 from_here,
82 base::BindOnce(
83 [](base::OnceClosure task, std::atomic<int>& num_async_tasks) {
84 std::move(task).Run();
85 num_async_tasks--;
86 },
87 std::move(task), std::ref(num_async_tasks)))) {
88 LOG(ERROR) << __func__ << ": failed from " << from_here.ToString();
89 return BT_STATUS_FAIL;
90 }
91 num_async_tasks++;
92 return BT_STATUS_SUCCESS;
93 }
94
95 static base::MessageLoop* message_loop_;
get_main_message_loop()96 base::MessageLoop* get_main_message_loop() { return message_loop_; }
97
init_message_loop_thread()98 static void init_message_loop_thread() {
99 num_async_tasks = 0;
100 message_loop_thread.StartUp();
101 if (!message_loop_thread.IsRunning()) {
102 FAIL() << "unable to create message loop thread.";
103 }
104
105 if (!message_loop_thread.EnableRealTimeScheduling())
106 LOG(ERROR) << "Unable to set real time scheduling";
107
108 message_loop_ = message_loop_thread.message_loop();
109 if (message_loop_ == nullptr) FAIL() << "unable to get message loop.";
110 }
111
cleanup_message_loop_thread()112 static void cleanup_message_loop_thread() {
113 message_loop_ = nullptr;
114 message_loop_thread.ShutDown();
115 }
116
117 namespace le_audio {
118 class MockAudioHalClientEndpoint;
119 MockAudioHalClientEndpoint* mock_audio_source_;
120 bool is_audio_hal_acquired;
121
122 std::unique_ptr<LeAudioSourceAudioHalClient>
AcquireBroadcast()123 LeAudioSourceAudioHalClient::AcquireBroadcast() {
124 if (mock_audio_source_) {
125 std::unique_ptr<LeAudioSourceAudioHalClient> ptr(
126 (LeAudioSourceAudioHalClient*)mock_audio_source_);
127 is_audio_hal_acquired = true;
128 return std::move(ptr);
129 }
130 return nullptr;
131 }
132
133 static constexpr uint8_t default_ccid = 0xDE;
134 static constexpr auto default_context =
135 static_cast<std::underlying_type<LeAudioContextType>::type>(
136 LeAudioContextType::ALERTS);
137 static constexpr BroadcastCode default_code = {
138 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
139 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
140 static const std::vector<uint8_t> default_metadata = {
141 le_audio::types::kLeAudioMetadataStreamingAudioContextLen + 1,
142 le_audio::types::kLeAudioMetadataTypeStreamingAudioContext,
143 default_context & 0x00FF, (default_context & 0xFF00) >> 8};
144 static const std::vector<uint8_t> default_public_metadata = {
145 5, le_audio::types::kLeAudioMetadataTypeProgramInfo, 0x1, 0x2, 0x3, 0x4};
146 // bit 0: encrypted, bit 1: standard quality present
147 static const uint8_t test_public_broadcast_features = 0x3;
148
149 static constexpr uint8_t default_num_of_groups = 1;
150 static constexpr uint8_t media_ccid = 0xC0;
151 static constexpr auto media_context =
152 static_cast<std::underlying_type<LeAudioContextType>::type>(
153 LeAudioContextType::MEDIA);
154 static const std::vector<uint8_t> media_metadata = {
155 le_audio::types::kLeAudioMetadataStreamingAudioContextLen + 1,
156 le_audio::types::kLeAudioMetadataTypeStreamingAudioContext,
157 media_context & 0x00FF, (media_context & 0xFF00) >> 8};
158 static const std::string test_broadcast_name = "Test";
159
160 class MockLeAudioBroadcasterCallbacks
161 : public bluetooth::le_audio::LeAudioBroadcasterCallbacks {
162 public:
163 MOCK_METHOD((void), OnBroadcastCreated, (uint32_t broadcast_id, bool success),
164 (override));
165 MOCK_METHOD((void), OnBroadcastDestroyed, (uint32_t broadcast_id),
166 (override));
167 MOCK_METHOD((void), OnBroadcastStateChanged,
168 (uint32_t broadcast_id,
169 bluetooth::le_audio::BroadcastState state),
170 (override));
171 MOCK_METHOD((void), OnBroadcastMetadataChanged,
172 (uint32_t broadcast_id,
173 const BroadcastMetadata& broadcast_metadata),
174 (override));
175 };
176
177 class MockAudioHalClientEndpoint : public LeAudioSourceAudioHalClient {
178 public:
179 MockAudioHalClientEndpoint() = default;
180 MOCK_METHOD((bool), Start,
181 (const LeAudioCodecConfiguration& codecConfiguration,
182 LeAudioSourceAudioHalClient::Callbacks* audioReceiver),
183 (override));
184 MOCK_METHOD((void), Stop, (), (override));
185 MOCK_METHOD((void), ConfirmStreamingRequest, (), (override));
186 MOCK_METHOD((void), CancelStreamingRequest, (), (override));
187 MOCK_METHOD((void), UpdateRemoteDelay, (uint16_t delay), (override));
188 MOCK_METHOD((void), UpdateAudioConfigToHal,
189 (const ::le_audio::offload_config&), (override));
190 MOCK_METHOD((void), UpdateBroadcastAudioConfigToHal,
191 (const ::le_audio::broadcast_offload_config&), (override));
192 MOCK_METHOD((void), SuspendedForReconfiguration, (), (override));
193 MOCK_METHOD((void), ReconfigurationComplete, (), (override));
194
195 MOCK_METHOD((void), OnDestroyed, ());
~MockAudioHalClientEndpoint()196 virtual ~MockAudioHalClientEndpoint() { OnDestroyed(); }
197 };
198
199 class BroadcasterTest : public Test {
200 protected:
SetUp()201 void SetUp() override {
202 init_message_loop_thread();
203
204 reset_mock_function_count_map();
205 ON_CALL(controller_interface_, SupportsBleIsochronousBroadcaster)
206 .WillByDefault(Return(true));
207
208 controller::SetMockControllerInterface(&controller_interface_);
209 iso_manager_ = bluetooth::hci::IsoManager::GetInstance();
210 ASSERT_NE(iso_manager_, nullptr);
211 iso_manager_->Start();
212
213 is_audio_hal_acquired = false;
214 mock_audio_source_ = new MockAudioHalClientEndpoint();
215 ON_CALL(*mock_audio_source_, Start).WillByDefault(Return(true));
216 ON_CALL(*mock_audio_source_, OnDestroyed).WillByDefault([]() {
217 mock_audio_source_ = nullptr;
218 is_audio_hal_acquired = false;
219 });
220
221 ASSERT_FALSE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning());
222 LeAudioBroadcaster::Initialize(&mock_broadcaster_callbacks_,
223 base::Bind([]() -> bool { return true; }));
224
225 ContentControlIdKeeper::GetInstance()->Start();
226 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA,
227 media_ccid);
228
229 /* Simulate random generator */
230 uint8_t random[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
231 generator_cb.Run(random);
232 }
233
TearDown()234 void TearDown() override {
235 // Message loop cleanup should wait for all the 'till now' scheduled calls
236 // so it should be called right at the very begginning of teardown.
237 cleanup_message_loop_thread();
238
239 // This is required since Stop() and Cleanup() may trigger some callbacks.
240 Mock::VerifyAndClearExpectations(&mock_broadcaster_callbacks_);
241
242 LeAudioBroadcaster::Stop();
243 LeAudioBroadcaster::Cleanup();
244 ASSERT_FALSE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning());
245
246 iso_manager_->Stop();
247
248 controller::SetMockControllerInterface(nullptr);
249 }
250
InstantiateBroadcast(std::vector<uint8_t> metadata=default_metadata,BroadcastCode code=default_code,uint8_t num_of_groups=default_num_of_groups)251 uint32_t InstantiateBroadcast(
252 std::vector<uint8_t> metadata = default_metadata,
253 BroadcastCode code = default_code,
254 uint8_t num_of_groups = default_num_of_groups) {
255 uint32_t broadcast_id = LeAudioBroadcaster::kInstanceIdUndefined;
256 EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastCreated(_, true))
257 .WillOnce(SaveArg<0>(&broadcast_id));
258
259 std::vector<uint8_t> quality_array;
260 std::vector<std::vector<uint8_t>> metadata_array;
261
262 for (uint8_t i = 0; i < num_of_groups; i++) {
263 // set standard quality for each subgroup
264 quality_array.push_back(bluetooth::le_audio::QUALITY_STANDARD);
265 // use the same default_metadata for each subgroup
266 metadata_array.push_back(metadata);
267 }
268 // Add multiple subgroup settings with the same content
269 LeAudioBroadcaster::Get()->CreateAudioBroadcast(
270 true, test_broadcast_name, code, default_public_metadata, quality_array,
271 metadata_array);
272
273 return broadcast_id;
274 }
275
276 protected:
277 MockLeAudioBroadcasterCallbacks mock_broadcaster_callbacks_;
278 controller::MockControllerInterface controller_interface_;
279 bluetooth::hci::IsoManager* iso_manager_;
280 };
281
TEST_F(BroadcasterTest,Initialize)282 TEST_F(BroadcasterTest, Initialize) {
283 ASSERT_NE(LeAudioBroadcaster::Get(), nullptr);
284 ASSERT_TRUE(LeAudioBroadcaster::IsLeAudioBroadcasterRunning());
285 }
286
TEST_F(BroadcasterTest,GetStreamingPhy)287 TEST_F(BroadcasterTest, GetStreamingPhy) {
288 LeAudioBroadcaster::Get()->SetStreamingPhy(1);
289 ASSERT_EQ(LeAudioBroadcaster::Get()->GetStreamingPhy(), 1);
290 LeAudioBroadcaster::Get()->SetStreamingPhy(2);
291 ASSERT_EQ(LeAudioBroadcaster::Get()->GetStreamingPhy(), 2);
292 }
293
TEST_F(BroadcasterTest,CreateAudioBroadcast)294 TEST_F(BroadcasterTest, CreateAudioBroadcast) {
295 auto broadcast_id = InstantiateBroadcast();
296 ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined);
297 ASSERT_EQ(broadcast_id,
298 MockBroadcastStateMachine::GetLastInstance()->GetBroadcastId());
299
300 auto& instance_config = MockBroadcastStateMachine::GetLastInstance()->cfg;
301 ASSERT_EQ(instance_config.broadcast_code, default_code);
302 for (auto& subgroup : instance_config.announcement.subgroup_configs) {
303 ASSERT_EQ(types::LeAudioLtvMap(subgroup.metadata).RawPacket(),
304 default_metadata);
305 }
306 // Note: There shall be a separate test to verify audio parameters
307 }
308
TEST_F(BroadcasterTest,CreateAudioBroadcastMultiGroups)309 TEST_F(BroadcasterTest, CreateAudioBroadcastMultiGroups) {
310 // Test with two subgroups
311 auto broadcast_id = InstantiateBroadcast(default_metadata, default_code, 2);
312 ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined);
313 ASSERT_EQ(broadcast_id,
314 MockBroadcastStateMachine::GetLastInstance()->GetBroadcastId());
315
316 auto& instance_config = MockBroadcastStateMachine::GetLastInstance()->cfg;
317 ASSERT_EQ(instance_config.broadcast_code, default_code);
318 ASSERT_EQ(instance_config.announcement.subgroup_configs.size(), (uint8_t) 2);
319 for (auto& subgroup : instance_config.announcement.subgroup_configs) {
320 ASSERT_EQ(types::LeAudioLtvMap(subgroup.metadata).RawPacket(),
321 default_metadata);
322 }
323 }
324
TEST_F(BroadcasterTest,SuspendAudioBroadcast)325 TEST_F(BroadcasterTest, SuspendAudioBroadcast) {
326 auto broadcast_id = InstantiateBroadcast();
327 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
328
329 EXPECT_CALL(mock_broadcaster_callbacks_,
330 OnBroadcastStateChanged(broadcast_id, BroadcastState::CONFIGURED))
331 .Times(1);
332
333 EXPECT_CALL(*mock_audio_source_, Stop).Times(AtLeast(1));
334 LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id);
335 }
336
TEST_F(BroadcasterTest,StartAudioBroadcast)337 TEST_F(BroadcasterTest, StartAudioBroadcast) {
338 auto broadcast_id = InstantiateBroadcast();
339 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
340
341 EXPECT_CALL(mock_broadcaster_callbacks_,
342 OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING))
343 .Times(1);
344
345 LeAudioSourceAudioHalClient::Callbacks* audio_receiver;
346 EXPECT_CALL(*mock_audio_source_, Start)
347 .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)));
348
349 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
350 ASSERT_NE(audio_receiver, nullptr);
351
352 // NOTICE: This is really an implementation specific part, we fake the BIG
353 // config as the mocked state machine does not even call the
354 // IsoManager to prepare one (and that's good since IsoManager is also
355 // a mocked one).
356 BigConfig big_cfg;
357 big_cfg.big_id =
358 MockBroadcastStateMachine::GetLastInstance()->GetAdvertisingSid();
359 big_cfg.connection_handles = {0x10, 0x12};
360 big_cfg.max_pdu = 128;
361 MockBroadcastStateMachine::GetLastInstance()->SetExpectedBigConfig(big_cfg);
362
363 // Inject the audio and verify call on the Iso manager side.
364 EXPECT_CALL(*MockIsoManager::GetInstance(), SendIsoData).Times(1);
365 std::vector<uint8_t> sample_data(320, 0);
366 audio_receiver->OnAudioDataReady(sample_data);
367 }
368
TEST_F(BroadcasterTest,StartAudioBroadcastMedia)369 TEST_F(BroadcasterTest, StartAudioBroadcastMedia) {
370 auto broadcast_id = InstantiateBroadcast(media_metadata);
371 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
372
373 EXPECT_CALL(mock_broadcaster_callbacks_,
374 OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING))
375 .Times(1);
376
377 LeAudioSourceAudioHalClient::Callbacks* audio_receiver;
378 EXPECT_CALL(*mock_audio_source_, Start)
379 .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)));
380
381 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
382 ASSERT_NE(audio_receiver, nullptr);
383
384 // NOTICE: This is really an implementation specific part, we fake the BIG
385 // config as the mocked state machine does not even call the
386 // IsoManager to prepare one (and that's good since IsoManager is also
387 // a mocked one).
388 BigConfig big_cfg;
389 big_cfg.big_id =
390 MockBroadcastStateMachine::GetLastInstance()->GetAdvertisingSid();
391 big_cfg.connection_handles = {0x10, 0x12};
392 big_cfg.max_pdu = 128;
393 MockBroadcastStateMachine::GetLastInstance()->SetExpectedBigConfig(big_cfg);
394
395 // Inject the audio and verify call on the Iso manager side.
396 EXPECT_CALL(*MockIsoManager::GetInstance(), SendIsoData).Times(2);
397 std::vector<uint8_t> sample_data(1920, 0);
398 audio_receiver->OnAudioDataReady(sample_data);
399 }
400
TEST_F(BroadcasterTest,StopAudioBroadcast)401 TEST_F(BroadcasterTest, StopAudioBroadcast) {
402 auto broadcast_id = InstantiateBroadcast();
403 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
404
405 EXPECT_CALL(mock_broadcaster_callbacks_,
406 OnBroadcastStateChanged(broadcast_id, BroadcastState::STOPPED))
407 .Times(1);
408
409 EXPECT_CALL(*mock_audio_source_, Stop).Times(AtLeast(1));
410 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
411 }
412
TEST_F(BroadcasterTest,DestroyAudioBroadcast)413 TEST_F(BroadcasterTest, DestroyAudioBroadcast) {
414 auto broadcast_id = InstantiateBroadcast();
415
416 EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastDestroyed(broadcast_id))
417 .Times(1);
418 LeAudioBroadcaster::Get()->DestroyAudioBroadcast(broadcast_id);
419
420 // Expect not being able to interact with this Broadcast
421 EXPECT_CALL(mock_broadcaster_callbacks_,
422 OnBroadcastStateChanged(broadcast_id, _))
423 .Times(0);
424
425 EXPECT_CALL(*mock_audio_source_, Stop).Times(0);
426 LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id);
427
428 EXPECT_CALL(*mock_audio_source_, Start).Times(0);
429 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
430
431 EXPECT_CALL(*mock_audio_source_, Stop).Times(0);
432 LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id);
433 }
434
TEST_F(BroadcasterTest,GetBroadcastAllStates)435 TEST_F(BroadcasterTest, GetBroadcastAllStates) {
436 auto broadcast_id = InstantiateBroadcast();
437 auto broadcast_id2 = InstantiateBroadcast();
438 ASSERT_NE(broadcast_id, LeAudioBroadcaster::kInstanceIdUndefined);
439 ASSERT_NE(broadcast_id2, LeAudioBroadcaster::kInstanceIdUndefined);
440 ASSERT_NE(broadcast_id, broadcast_id2);
441
442 /* In the current implementation state machine switches to the correct state
443 * on itself, therefore here when we use mocked state machine this is not
444 * being verified.
445 */
446 EXPECT_CALL(mock_broadcaster_callbacks_,
447 OnBroadcastStateChanged(broadcast_id, _))
448 .Times(1);
449 EXPECT_CALL(mock_broadcaster_callbacks_,
450 OnBroadcastStateChanged(broadcast_id2, _))
451 .Times(1);
452
453 LeAudioBroadcaster::Get()->GetAllBroadcastStates();
454 }
455
TEST_F(BroadcasterTest,UpdateMetadata)456 TEST_F(BroadcasterTest, UpdateMetadata) {
457 auto broadcast_id = InstantiateBroadcast();
458 std::vector<uint8_t> ccid_list;
459 std::vector<uint8_t> expected_public_meta;
460 std::string expected_broadcast_name;
461
462 EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(),
463 UpdateBroadcastAnnouncement)
464 .WillOnce(
465 [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) {
466 for (auto subgroup : announcement.subgroup_configs) {
467 if (subgroup.metadata.count(
468 types::kLeAudioMetadataTypeCcidList)) {
469 ccid_list =
470 subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList);
471 break;
472 }
473 }
474 });
475
476 EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(),
477 UpdatePublicBroadcastAnnouncement)
478 .WillOnce([&](uint32_t broadcast_id, const std::string& broadcast_name,
479 const bluetooth::le_audio::PublicBroadcastAnnouncementData&
480 announcement) {
481 expected_broadcast_name = broadcast_name;
482 expected_public_meta =
483 types::LeAudioLtvMap(announcement.metadata).RawPacket();
484 });
485
486 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::ALERTS,
487 default_ccid);
488
489 LeAudioBroadcaster::Get()->UpdateMetadata(
490 broadcast_id, test_broadcast_name, default_public_metadata,
491 {std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04})});
492
493 ASSERT_EQ(2u, ccid_list.size());
494 ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), media_ccid));
495 ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), default_ccid));
496 ASSERT_EQ(expected_broadcast_name, test_broadcast_name);
497 ASSERT_EQ(expected_public_meta, default_public_metadata);
498 }
499
prepareAnnouncement(const BroadcastCodecWrapper & codec_config,std::map<uint8_t,std::vector<uint8_t>> metadata)500 static BasicAudioAnnouncementData prepareAnnouncement(
501 const BroadcastCodecWrapper& codec_config,
502 std::map<uint8_t, std::vector<uint8_t>> metadata) {
503 BasicAudioAnnouncementData announcement;
504
505 announcement.presentation_delay = 0x004E20;
506 auto const& codec_id = codec_config.GetLeAudioCodecId();
507
508 announcement.subgroup_configs = {{
509 .codec_config =
510 {
511 .codec_id = codec_id.coding_format,
512 .vendor_company_id = codec_id.vendor_company_id,
513 .vendor_codec_id = codec_id.vendor_codec_id,
514 .codec_specific_params =
515 codec_config.GetSubgroupCodecSpecData().Values(),
516 },
517 .metadata = std::move(metadata),
518 .bis_configs = {},
519 }};
520
521 for (uint8_t i = 0; i < codec_config.GetNumChannels(); ++i) {
522 announcement.subgroup_configs[0].bis_configs.push_back(
523 {.codec_specific_params =
524 codec_config.GetBisCodecSpecData(i + 1).Values(),
525 .bis_index = static_cast<uint8_t>(i + 1)});
526 }
527
528 return announcement;
529 }
530
TEST_F(BroadcasterTest,UpdateMetadataFromAudioTrackMetadata)531 TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) {
532 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA,
533 media_ccid);
534 auto broadcast_id = InstantiateBroadcast();
535
536 LeAudioSourceAudioHalClient::Callbacks* audio_receiver;
537 EXPECT_CALL(*mock_audio_source_, Start)
538 .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true)));
539
540 LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id);
541 ASSERT_NE(audio_receiver, nullptr);
542
543 auto sm = MockBroadcastStateMachine::GetLastInstance();
544 std::vector<uint8_t> ccid_list;
545 std::vector<uint8_t> context_types_map;
546 EXPECT_CALL(*sm, UpdateBroadcastAnnouncement)
547 .WillOnce(
548 [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) {
549 for (auto subgroup : announcement.subgroup_configs) {
550 if (subgroup.metadata.count(
551 types::kLeAudioMetadataTypeCcidList)) {
552 ccid_list =
553 subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList);
554 }
555 if (subgroup.metadata.count(
556 types::kLeAudioMetadataTypeStreamingAudioContext)) {
557 context_types_map = subgroup.metadata.at(
558 types::kLeAudioMetadataTypeStreamingAudioContext);
559 }
560 }
561 });
562
563 std::map<uint8_t, std::vector<uint8_t>> meta = {};
564 BroadcastCodecWrapper codec_config(
565 {.coding_format = le_audio::types::kLeAudioCodingFormatLC3,
566 .vendor_company_id = le_audio::types::kLeAudioVendorCompanyIdUndefined,
567 .vendor_codec_id = le_audio::types::kLeAudioVendorCodecIdUndefined},
568 {.num_channels = LeAudioCodecConfiguration::kChannelNumberMono,
569 .sample_rate = LeAudioCodecConfiguration::kSampleRate16000,
570 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
571 .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
572 32000, 40);
573 auto announcement = prepareAnnouncement(codec_config, meta);
574
575 ON_CALL(*sm, GetBroadcastAnnouncement())
576 .WillByDefault(ReturnRef(announcement));
577
578 std::vector<struct playback_track_metadata> multitrack_source_metadata = {
579 {{AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_SONIFICATION, 0},
580 {AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, 0},
581 {AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING, AUDIO_CONTENT_TYPE_SPEECH,
582 0},
583 {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}}};
584
585 audio_receiver->OnAudioMetadataUpdate(multitrack_source_metadata);
586
587 // Verify ccid
588 ASSERT_NE(ccid_list.size(), 0u);
589 ASSERT_TRUE(std::find(ccid_list.begin(), ccid_list.end(), media_ccid) !=
590 ccid_list.end());
591
592 // Verify context type
593 ASSERT_NE(context_types_map.size(), 0u);
594 AudioContexts context_type;
595 auto pp = context_types_map.data();
596 STREAM_TO_UINT16(context_type.value_ref(), pp);
597 ASSERT_TRUE(context_type.test_all(LeAudioContextType::MEDIA |
598 LeAudioContextType::GAME));
599 }
600
TEST_F(BroadcasterTest,GetMetadata)601 TEST_F(BroadcasterTest, GetMetadata) {
602 auto broadcast_id = InstantiateBroadcast();
603 bluetooth::le_audio::BroadcastMetadata metadata;
604
605 static const uint8_t test_adv_sid = 0x14;
606 std::optional<bluetooth::le_audio::BroadcastCode> test_broadcast_code =
607 bluetooth::le_audio::BroadcastCode({1, 2, 3, 4, 5, 6});
608
609 auto sm = MockBroadcastStateMachine::GetLastInstance();
610
611 std::map<uint8_t, std::vector<uint8_t>> meta = {};
612 BroadcastCodecWrapper codec_config(
613 {.coding_format = le_audio::types::kLeAudioCodingFormatLC3,
614 .vendor_company_id = le_audio::types::kLeAudioVendorCompanyIdUndefined,
615 .vendor_codec_id = le_audio::types::kLeAudioVendorCodecIdUndefined},
616 {.num_channels = LeAudioCodecConfiguration::kChannelNumberMono,
617 .sample_rate = LeAudioCodecConfiguration::kSampleRate16000,
618 .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16,
619 .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us},
620 32000, 40);
621 auto announcement = prepareAnnouncement(codec_config, meta);
622
623 bool is_public_metadata_valid;
624 types::LeAudioLtvMap public_ltv = types::LeAudioLtvMap::Parse(
625 default_public_metadata.data(), default_public_metadata.size(),
626 is_public_metadata_valid);
627 PublicBroadcastAnnouncementData pb_announcement = {
628 .features = test_public_broadcast_features,
629 .metadata = public_ltv.Values()};
630
631 ON_CALL(*sm, IsPublicBroadcast()).WillByDefault(Return(true));
632 ON_CALL(*sm, GetBroadcastName()).WillByDefault(Return(test_broadcast_name));
633 ON_CALL(*sm, GetBroadcastCode()).WillByDefault(Return(test_broadcast_code));
634 ON_CALL(*sm, GetAdvertisingSid()).WillByDefault(Return(test_adv_sid));
635 ON_CALL(*sm, GetBroadcastAnnouncement())
636 .WillByDefault(ReturnRef(announcement));
637 ON_CALL(*sm, GetPublicBroadcastAnnouncement())
638 .WillByDefault(ReturnRef(pb_announcement));
639
640 EXPECT_CALL(mock_broadcaster_callbacks_,
641 OnBroadcastMetadataChanged(broadcast_id, _))
642 .Times(1)
643 .WillOnce(SaveArg<1>(&metadata));
644 LeAudioBroadcaster::Get()->GetBroadcastMetadata(broadcast_id);
645
646 ASSERT_NE(LeAudioBroadcaster::kInstanceIdUndefined, metadata.broadcast_id);
647 ASSERT_EQ(sm->GetBroadcastId(), metadata.broadcast_id);
648 ASSERT_EQ(sm->GetBroadcastCode(), metadata.broadcast_code);
649 ASSERT_EQ(sm->GetBroadcastAnnouncement(), metadata.basic_audio_announcement);
650 ASSERT_EQ(sm->GetPaInterval(), metadata.pa_interval);
651 ASSERT_EQ(sm->GetOwnAddress(), metadata.addr);
652 ASSERT_EQ(sm->GetOwnAddressType(), metadata.addr_type);
653 ASSERT_EQ(sm->GetAdvertisingSid(), metadata.adv_sid);
654 ASSERT_EQ(sm->IsPublicBroadcast(), metadata.is_public);
655 ASSERT_EQ(sm->GetBroadcastName(), metadata.broadcast_name);
656 ASSERT_EQ(sm->GetPublicBroadcastAnnouncement(), metadata.public_announcement);
657 }
658
TEST_F(BroadcasterTest,SetStreamingPhy)659 TEST_F(BroadcasterTest, SetStreamingPhy) {
660 LeAudioBroadcaster::Get()->SetStreamingPhy(2);
661 // From now on new streams should be using Phy = 2.
662 InstantiateBroadcast();
663 ASSERT_EQ(MockBroadcastStateMachine::GetLastInstance()->cfg.streaming_phy, 2);
664
665 // From now on new streams should be using Phy = 1.
666 LeAudioBroadcaster::Get()->SetStreamingPhy(1);
667 InstantiateBroadcast();
668 ASSERT_EQ(MockBroadcastStateMachine::GetLastInstance()->cfg.streaming_phy, 1);
669 ASSERT_EQ(LeAudioBroadcaster::Get()->GetStreamingPhy(), 1);
670 }
671
TEST_F(BroadcasterTest,StreamParamsAlerts)672 TEST_F(BroadcasterTest, StreamParamsAlerts) {
673 uint8_t expected_channels = 1u;
674 InstantiateBroadcast();
675 auto config = MockBroadcastStateMachine::GetLastInstance()->cfg;
676
677 // Check audio configuration
678 ASSERT_EQ(config.codec_wrapper.GetNumChannels(), expected_channels);
679 // Matches number of bises in the announcement
680 ASSERT_EQ(config.announcement.subgroup_configs[0].bis_configs.size(),
681 expected_channels);
682 // Note: Num of bises at IsoManager level is verified by state machine tests
683 }
684
TEST_F(BroadcasterTest,StreamParamsMedia)685 TEST_F(BroadcasterTest, StreamParamsMedia) {
686 uint8_t expected_channels = 2u;
687 ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA,
688 media_ccid);
689 InstantiateBroadcast(media_metadata);
690 auto config = MockBroadcastStateMachine::GetLastInstance()->cfg;
691
692 // Check audio configuration
693 ASSERT_EQ(config.codec_wrapper.GetNumChannels(), expected_channels);
694
695 auto& subgroup = config.announcement.subgroup_configs[0];
696
697 // Matches number of bises in the announcement
698 ASSERT_EQ(subgroup.bis_configs.size(), expected_channels);
699 // Verify CCID for Media
700 auto ccid_list_opt = types::LeAudioLtvMap(subgroup.metadata)
701 .Find(le_audio::types::kLeAudioMetadataTypeCcidList);
702 ASSERT_TRUE(ccid_list_opt.has_value());
703 auto ccid_list = ccid_list_opt.value();
704 ASSERT_EQ(1u, ccid_list.size());
705 ASSERT_EQ(media_ccid, ccid_list[0]);
706 // Note: Num of bises at IsoManager level is verified by state machine tests
707 }
708
709 } // namespace le_audio
710