Loading system/bta/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,7 @@ cc_library_static { "le_audio/state_machine.cc", "le_audio/client_parser.cc", "le_audio/client_audio.cc", "le_audio/le_audio_utils.cc", "le_audio/le_audio_set_configuration_provider.cc", "le_audio/le_audio_set_configuration_provider_json.cc", "le_audio/le_audio_types.cc", Loading Loading @@ -629,6 +630,7 @@ cc_test { "le_audio/client_parser.cc", "le_audio/content_control_id_keeper.cc", "le_audio/devices.cc", "le_audio/le_audio_utils.cc", "le_audio/le_audio_client_test.cc", "le_audio/le_audio_set_configuration_provider_json.cc", "le_audio/le_audio_types.cc", Loading Loading @@ -772,6 +774,7 @@ cc_test { "le_audio/broadcaster/mock_state_machine.cc", "le_audio/content_control_id_keeper.cc", "le_audio/client_audio.cc", "le_audio/le_audio_utils.cc", "le_audio/le_audio_types.cc", "le_audio/metrics_collector_linux.cc", "le_audio/mock_iso_manager.cc", Loading system/bta/le_audio/broadcaster/broadcaster.cc +113 −12 Original line number Diff line number Diff line Loading @@ -20,8 +20,8 @@ #include "bta/include/bta_le_audio_api.h" #include "bta/include/bta_le_audio_broadcaster_api.h" #include "bta/le_audio/broadcaster/state_machine.h" #include "bta/le_audio/content_control_id_keeper.h" #include "bta/le_audio/le_audio_types.h" #include "bta/le_audio/le_audio_utils.h" #include "bta/le_audio/metrics_collector.h" #include "device/include/controller.h" #include "embdrv/lc3/include/lc3.h" Loading @@ -39,7 +39,6 @@ using bluetooth::hci::iso_manager::BigCallbacks; using bluetooth::le_audio::BasicAudioAnnouncementData; using bluetooth::le_audio::BroadcastId; using le_audio::CodecManager; using le_audio::ContentControlIdKeeper; using le_audio::broadcaster::BigConfig; using le_audio::broadcaster::BroadcastCodecWrapper; using le_audio::broadcaster::BroadcastQosConfig; Loading @@ -50,6 +49,8 @@ using le_audio::types::CodecLocation; using le_audio::types::kLeAudioCodingFormatLC3; using le_audio::types::LeAudioContextType; using le_audio::types::LeAudioLtvMap; using le_audio::utils::GetAllCcids; using le_audio::utils::GetAllowedAudioContextsFromSourceMetadata; namespace { class LeAudioBroadcasterImpl; Loading Loading @@ -166,6 +167,80 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { return announcement; } void UpdateStreamingContextTypeOnAllSubgroups(uint16_t context_type_map) { LOG_DEBUG("%s context_type_map=%d", __func__, context_type_map); auto ccids = GetAllCcids(context_type_map); if (ccids.empty()) { LOG_WARN("%s No content providers available for context_type_map=%d.", __func__, context_type_map); } std::vector<uint8_t> stream_context_vec(2); auto pp = stream_context_vec.data(); UINT16_TO_STREAM(pp, context_type_map); for (auto const& kv_it : broadcasts_) { auto& broadcast = kv_it.second; if (broadcast->GetState() == BroadcastStateMachine::State::STREAMING) { auto announcement = broadcast->GetBroadcastAnnouncement(); bool broadcast_update = false; // Replace context type and CCID list for (auto& subgroup : announcement.subgroup_configs) { auto subgroup_ltv = LeAudioLtvMap(subgroup.metadata); bool subgroup_update = false; auto existing_context = subgroup_ltv.Find( le_audio::types::kLeAudioMetadataTypeStreamingAudioContext); if (existing_context) { if (memcmp(stream_context_vec.data(), existing_context->data(), existing_context->size()) != 0) { subgroup_ltv.Add( le_audio::types::kLeAudioMetadataTypeStreamingAudioContext, stream_context_vec); subgroup_update = true; } } else { subgroup_ltv.Add( le_audio::types::kLeAudioMetadataTypeStreamingAudioContext, stream_context_vec); subgroup_update = true; } auto existing_ccid_list = subgroup_ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); if (existing_ccid_list) { if (ccids.empty()) { subgroup_ltv.Remove( le_audio::types::kLeAudioMetadataTypeCcidList); subgroup_update = true; } else if (!std::is_permutation(ccids.begin(), ccids.end(), existing_ccid_list->begin())) { subgroup_ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccids); subgroup_update = true; } } else if (!ccids.empty()) { subgroup_ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccids); subgroup_update = true; } if (subgroup_update) { subgroup.metadata = subgroup_ltv.Values(); broadcast_update = true; } } if (broadcast_update) { broadcast->UpdateBroadcastAnnouncement(std::move(announcement)); } } } } void UpdateMetadata(uint32_t broadcast_id, std::vector<uint8_t> metadata) override { if (broadcasts_.count(broadcast_id) == 0) { Loading @@ -186,6 +261,22 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { return; } uint16_t context_type = static_cast<std::underlying_type<LeAudioContextType>::type>( LeAudioContextType::MEDIA); auto stream_context_vec = ltv.Find(le_audio::types::kLeAudioMetadataTypeStreamingAudioContext); if (stream_context_vec) { auto pp = stream_context_vec.value().data(); STREAM_TO_UINT16(context_type, pp); } // Append the CCID list auto ccid_vec = GetAllCcids(context_type); if (!ccid_vec.empty()) { ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccid_vec); } BasicAudioAnnouncementData announcement = prepareAnnouncement(codec_config, std::move(ltv)); Loading Loading @@ -220,12 +311,9 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } // Append the CCID list // TODO: We currently support only one context (and CCID) at a time for both // Unicast and broadcast. auto ccid = ContentControlIdKeeper::GetInstance()->GetCcid(context_type); if (ccid != -1) { ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, {static_cast<uint8_t>(ccid)}); auto ccid_vec = GetAllCcids(context_type); if (!ccid_vec.empty()) { ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccid_vec); } if (CodecManager::GetInstance()->GetCodecLocation() == Loading Loading @@ -747,11 +835,24 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { const source_metadata_t& source_metadata) override { LOG_INFO(); if (!instance) return; do_update_metadata_promise.set_value(); /* TODO: We probably don't want to change stream type or update the * advertized metadata on each call. We should rather make sure we get * only a single content audio stream from the media frameworks. /* TODO: Should we take supported contexts from ASCS? */ auto supported_context_types = le_audio::types::kLeAudioContextAllTypes; auto contexts = GetAllowedAudioContextsFromSourceMetadata( source_metadata, static_cast<std::underlying_type<LeAudioContextType>::type>( supported_context_types)); if (contexts.any()) { /* NOTICE: We probably don't want to change the stream configuration * on each metadata change, so just update the context type metadata. * Since we are not able to identify individual track streams and * they are all mixed inside a single data stream, we will update * the metadata of all BIS subgroups with the same combined context. */ instance->UpdateStreamingContextTypeOnAllSubgroups(contexts.to_ulong()); } do_update_metadata_promise.set_value(); } private: Loading system/bta/le_audio/broadcaster/broadcaster_test.cc +103 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <hardware/audio.h> #include <chrono> Loading @@ -30,6 +31,8 @@ #include "device/include/controller.h" #include "stack/include/btm_iso_api.h" using namespace std::chrono_literals; using le_audio::types::LeAudioContextType; using testing::_; Loading Loading @@ -108,6 +111,7 @@ static void cleanup_message_loop_thread() { namespace le_audio { namespace broadcaster { namespace { static constexpr uint8_t default_ccid = 0xDE; static constexpr auto default_context = static_cast<std::underlying_type<LeAudioContextType>::type>( LeAudioContextType::ALERTS); Loading Loading @@ -203,6 +207,7 @@ class BroadcasterTest : public Test { base::Bind([]() -> bool { return true; })); ContentControlIdKeeper::GetInstance()->Start(); ContentControlIdKeeper::GetInstance()->SetCcid(0x0004, media_ccid); /* Simulate random generator */ uint8_t random[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; Loading Loading @@ -405,12 +410,29 @@ TEST_F(BroadcasterTest, GetBroadcastAllStates) { TEST_F(BroadcasterTest, UpdateMetadata) { auto broadcast_id = InstantiateBroadcast(); std::vector<uint8_t> ccid_list; EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(), UpdateBroadcastAnnouncement) .Times(1); .WillOnce( [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) { for (auto subgroup : announcement.subgroup_configs) { if (subgroup.metadata.count( types::kLeAudioMetadataTypeCcidList)) { ccid_list = subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList); break; } } }); ContentControlIdKeeper::GetInstance()->SetCcid(0x0400, default_ccid); LeAudioBroadcaster::Get()->UpdateMetadata( broadcast_id, std::vector<uint8_t>({0x02, 0x01, 0x02})); broadcast_id, std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04})); ASSERT_EQ(2u, ccid_list.size()); ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), media_ccid)); ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), default_ccid)); } static BasicAudioAnnouncementData prepareAnnouncement( Loading Loading @@ -444,10 +466,87 @@ static BasicAudioAnnouncementData prepareAnnouncement( return announcement; } TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) { ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); auto broadcast_id = InstantiateBroadcast(); LeAudioClientAudioSinkReceiver* audio_receiver; EXPECT_CALL(*mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); auto sm = MockBroadcastStateMachine::GetLastInstance(); std::vector<uint8_t> ccid_list; std::vector<uint8_t> context_types_map; EXPECT_CALL(*sm, UpdateBroadcastAnnouncement) .WillOnce( [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) { for (auto subgroup : announcement.subgroup_configs) { if (subgroup.metadata.count( types::kLeAudioMetadataTypeCcidList)) { ccid_list = subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList); } if (subgroup.metadata.count( types::kLeAudioMetadataTypeStreamingAudioContext)) { context_types_map = subgroup.metadata.at( types::kLeAudioMetadataTypeStreamingAudioContext); } } }); std::map<uint8_t, std::vector<uint8_t>> meta = {}; BroadcastCodecWrapper codec_config( {.coding_format = le_audio::types::kLeAudioCodingFormatLC3, .vendor_company_id = le_audio::types::kLeAudioVendorCompanyIdUndefined, .vendor_codec_id = le_audio::types::kLeAudioVendorCodecIdUndefined}, {.num_channels = LeAudioCodecConfiguration::kChannelNumberMono, .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, 32000, 40); auto announcement = prepareAnnouncement(codec_config, meta); ON_CALL(*sm, GetBroadcastAnnouncement()) .WillByDefault(ReturnRef(announcement)); std::promise<void> do_update_metadata_promise; struct playback_track_metadata tracks_[] = { {AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_SONIFICATION, 0}, {AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, 0}, {AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING, AUDIO_CONTENT_TYPE_SPEECH, 0}, {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}}; source_metadata_t multitrack_source_metadata = {.track_count = 4, .tracks = &tracks_[0]}; auto do_update_metadata_future = do_update_metadata_promise.get_future(); audio_receiver->OnAudioMetadataUpdate(std::move(do_update_metadata_promise), multitrack_source_metadata); do_update_metadata_future.wait_for(3s); // Verify ccid ASSERT_NE(ccid_list.size(), 0u); ASSERT_TRUE(std::find(ccid_list.begin(), ccid_list.end(), media_ccid) != ccid_list.end()); // Verify context type ASSERT_NE(context_types_map.size(), 0u); uint16_t context_type; auto pp = context_types_map.data(); STREAM_TO_UINT16(context_type, pp); ASSERT_NE(context_type & static_cast<std::underlying_type<LeAudioContextType>::type>( LeAudioContextType::MEDIA | LeAudioContextType::GAME), 0); } TEST_F(BroadcasterTest, GetMetadata) { auto broadcast_id = InstantiateBroadcast(); bluetooth::le_audio::BroadcastMetadata metadata; // bluetooth::le_audio::BasicAudioAnnouncementData announcement; static const uint8_t test_adv_sid = 0x14; std::optional<bluetooth::le_audio::BroadcastCode> test_broadcast_code = Loading system/bta/le_audio/broadcaster/mock_state_machine.h +1 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ class MockBroadcastStateMachine std::optional<le_audio::broadcaster::BigConfig> big_config_ = std::nullopt; le_audio::broadcaster::BroadcastStateMachineConfig cfg; le_audio::broadcaster::IBroadcastStateMachineCallbacks* cb; void SetExpectedState(BroadcastStateMachine::State state) { SetState(state); } void SetExpectedResult(bool result) { result_ = result; } void SetExpectedBigConfig( std::optional<le_audio::broadcaster::BigConfig> big_cfg) { Loading Loading
system/bta/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,7 @@ cc_library_static { "le_audio/state_machine.cc", "le_audio/client_parser.cc", "le_audio/client_audio.cc", "le_audio/le_audio_utils.cc", "le_audio/le_audio_set_configuration_provider.cc", "le_audio/le_audio_set_configuration_provider_json.cc", "le_audio/le_audio_types.cc", Loading Loading @@ -629,6 +630,7 @@ cc_test { "le_audio/client_parser.cc", "le_audio/content_control_id_keeper.cc", "le_audio/devices.cc", "le_audio/le_audio_utils.cc", "le_audio/le_audio_client_test.cc", "le_audio/le_audio_set_configuration_provider_json.cc", "le_audio/le_audio_types.cc", Loading Loading @@ -772,6 +774,7 @@ cc_test { "le_audio/broadcaster/mock_state_machine.cc", "le_audio/content_control_id_keeper.cc", "le_audio/client_audio.cc", "le_audio/le_audio_utils.cc", "le_audio/le_audio_types.cc", "le_audio/metrics_collector_linux.cc", "le_audio/mock_iso_manager.cc", Loading
system/bta/le_audio/broadcaster/broadcaster.cc +113 −12 Original line number Diff line number Diff line Loading @@ -20,8 +20,8 @@ #include "bta/include/bta_le_audio_api.h" #include "bta/include/bta_le_audio_broadcaster_api.h" #include "bta/le_audio/broadcaster/state_machine.h" #include "bta/le_audio/content_control_id_keeper.h" #include "bta/le_audio/le_audio_types.h" #include "bta/le_audio/le_audio_utils.h" #include "bta/le_audio/metrics_collector.h" #include "device/include/controller.h" #include "embdrv/lc3/include/lc3.h" Loading @@ -39,7 +39,6 @@ using bluetooth::hci::iso_manager::BigCallbacks; using bluetooth::le_audio::BasicAudioAnnouncementData; using bluetooth::le_audio::BroadcastId; using le_audio::CodecManager; using le_audio::ContentControlIdKeeper; using le_audio::broadcaster::BigConfig; using le_audio::broadcaster::BroadcastCodecWrapper; using le_audio::broadcaster::BroadcastQosConfig; Loading @@ -50,6 +49,8 @@ using le_audio::types::CodecLocation; using le_audio::types::kLeAudioCodingFormatLC3; using le_audio::types::LeAudioContextType; using le_audio::types::LeAudioLtvMap; using le_audio::utils::GetAllCcids; using le_audio::utils::GetAllowedAudioContextsFromSourceMetadata; namespace { class LeAudioBroadcasterImpl; Loading Loading @@ -166,6 +167,80 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { return announcement; } void UpdateStreamingContextTypeOnAllSubgroups(uint16_t context_type_map) { LOG_DEBUG("%s context_type_map=%d", __func__, context_type_map); auto ccids = GetAllCcids(context_type_map); if (ccids.empty()) { LOG_WARN("%s No content providers available for context_type_map=%d.", __func__, context_type_map); } std::vector<uint8_t> stream_context_vec(2); auto pp = stream_context_vec.data(); UINT16_TO_STREAM(pp, context_type_map); for (auto const& kv_it : broadcasts_) { auto& broadcast = kv_it.second; if (broadcast->GetState() == BroadcastStateMachine::State::STREAMING) { auto announcement = broadcast->GetBroadcastAnnouncement(); bool broadcast_update = false; // Replace context type and CCID list for (auto& subgroup : announcement.subgroup_configs) { auto subgroup_ltv = LeAudioLtvMap(subgroup.metadata); bool subgroup_update = false; auto existing_context = subgroup_ltv.Find( le_audio::types::kLeAudioMetadataTypeStreamingAudioContext); if (existing_context) { if (memcmp(stream_context_vec.data(), existing_context->data(), existing_context->size()) != 0) { subgroup_ltv.Add( le_audio::types::kLeAudioMetadataTypeStreamingAudioContext, stream_context_vec); subgroup_update = true; } } else { subgroup_ltv.Add( le_audio::types::kLeAudioMetadataTypeStreamingAudioContext, stream_context_vec); subgroup_update = true; } auto existing_ccid_list = subgroup_ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); if (existing_ccid_list) { if (ccids.empty()) { subgroup_ltv.Remove( le_audio::types::kLeAudioMetadataTypeCcidList); subgroup_update = true; } else if (!std::is_permutation(ccids.begin(), ccids.end(), existing_ccid_list->begin())) { subgroup_ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccids); subgroup_update = true; } } else if (!ccids.empty()) { subgroup_ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccids); subgroup_update = true; } if (subgroup_update) { subgroup.metadata = subgroup_ltv.Values(); broadcast_update = true; } } if (broadcast_update) { broadcast->UpdateBroadcastAnnouncement(std::move(announcement)); } } } } void UpdateMetadata(uint32_t broadcast_id, std::vector<uint8_t> metadata) override { if (broadcasts_.count(broadcast_id) == 0) { Loading @@ -186,6 +261,22 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { return; } uint16_t context_type = static_cast<std::underlying_type<LeAudioContextType>::type>( LeAudioContextType::MEDIA); auto stream_context_vec = ltv.Find(le_audio::types::kLeAudioMetadataTypeStreamingAudioContext); if (stream_context_vec) { auto pp = stream_context_vec.value().data(); STREAM_TO_UINT16(context_type, pp); } // Append the CCID list auto ccid_vec = GetAllCcids(context_type); if (!ccid_vec.empty()) { ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccid_vec); } BasicAudioAnnouncementData announcement = prepareAnnouncement(codec_config, std::move(ltv)); Loading Loading @@ -220,12 +311,9 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { } // Append the CCID list // TODO: We currently support only one context (and CCID) at a time for both // Unicast and broadcast. auto ccid = ContentControlIdKeeper::GetInstance()->GetCcid(context_type); if (ccid != -1) { ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, {static_cast<uint8_t>(ccid)}); auto ccid_vec = GetAllCcids(context_type); if (!ccid_vec.empty()) { ltv.Add(le_audio::types::kLeAudioMetadataTypeCcidList, ccid_vec); } if (CodecManager::GetInstance()->GetCodecLocation() == Loading Loading @@ -747,11 +835,24 @@ class LeAudioBroadcasterImpl : public LeAudioBroadcaster, public BigCallbacks { const source_metadata_t& source_metadata) override { LOG_INFO(); if (!instance) return; do_update_metadata_promise.set_value(); /* TODO: We probably don't want to change stream type or update the * advertized metadata on each call. We should rather make sure we get * only a single content audio stream from the media frameworks. /* TODO: Should we take supported contexts from ASCS? */ auto supported_context_types = le_audio::types::kLeAudioContextAllTypes; auto contexts = GetAllowedAudioContextsFromSourceMetadata( source_metadata, static_cast<std::underlying_type<LeAudioContextType>::type>( supported_context_types)); if (contexts.any()) { /* NOTICE: We probably don't want to change the stream configuration * on each metadata change, so just update the context type metadata. * Since we are not able to identify individual track streams and * they are all mixed inside a single data stream, we will update * the metadata of all BIS subgroups with the same combined context. */ instance->UpdateStreamingContextTypeOnAllSubgroups(contexts.to_ulong()); } do_update_metadata_promise.set_value(); } private: Loading
system/bta/le_audio/broadcaster/broadcaster_test.cc +103 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <hardware/audio.h> #include <chrono> Loading @@ -30,6 +31,8 @@ #include "device/include/controller.h" #include "stack/include/btm_iso_api.h" using namespace std::chrono_literals; using le_audio::types::LeAudioContextType; using testing::_; Loading Loading @@ -108,6 +111,7 @@ static void cleanup_message_loop_thread() { namespace le_audio { namespace broadcaster { namespace { static constexpr uint8_t default_ccid = 0xDE; static constexpr auto default_context = static_cast<std::underlying_type<LeAudioContextType>::type>( LeAudioContextType::ALERTS); Loading Loading @@ -203,6 +207,7 @@ class BroadcasterTest : public Test { base::Bind([]() -> bool { return true; })); ContentControlIdKeeper::GetInstance()->Start(); ContentControlIdKeeper::GetInstance()->SetCcid(0x0004, media_ccid); /* Simulate random generator */ uint8_t random[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; Loading Loading @@ -405,12 +410,29 @@ TEST_F(BroadcasterTest, GetBroadcastAllStates) { TEST_F(BroadcasterTest, UpdateMetadata) { auto broadcast_id = InstantiateBroadcast(); std::vector<uint8_t> ccid_list; EXPECT_CALL(*MockBroadcastStateMachine::GetLastInstance(), UpdateBroadcastAnnouncement) .Times(1); .WillOnce( [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) { for (auto subgroup : announcement.subgroup_configs) { if (subgroup.metadata.count( types::kLeAudioMetadataTypeCcidList)) { ccid_list = subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList); break; } } }); ContentControlIdKeeper::GetInstance()->SetCcid(0x0400, default_ccid); LeAudioBroadcaster::Get()->UpdateMetadata( broadcast_id, std::vector<uint8_t>({0x02, 0x01, 0x02})); broadcast_id, std::vector<uint8_t>({0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x04})); ASSERT_EQ(2u, ccid_list.size()); ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), media_ccid)); ASSERT_NE(0, std::count(ccid_list.begin(), ccid_list.end(), default_ccid)); } static BasicAudioAnnouncementData prepareAnnouncement( Loading Loading @@ -444,10 +466,87 @@ static BasicAudioAnnouncementData prepareAnnouncement( return announcement; } TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) { ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); auto broadcast_id = InstantiateBroadcast(); LeAudioClientAudioSinkReceiver* audio_receiver; EXPECT_CALL(*mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); auto sm = MockBroadcastStateMachine::GetLastInstance(); std::vector<uint8_t> ccid_list; std::vector<uint8_t> context_types_map; EXPECT_CALL(*sm, UpdateBroadcastAnnouncement) .WillOnce( [&](bluetooth::le_audio::BasicAudioAnnouncementData announcement) { for (auto subgroup : announcement.subgroup_configs) { if (subgroup.metadata.count( types::kLeAudioMetadataTypeCcidList)) { ccid_list = subgroup.metadata.at(types::kLeAudioMetadataTypeCcidList); } if (subgroup.metadata.count( types::kLeAudioMetadataTypeStreamingAudioContext)) { context_types_map = subgroup.metadata.at( types::kLeAudioMetadataTypeStreamingAudioContext); } } }); std::map<uint8_t, std::vector<uint8_t>> meta = {}; BroadcastCodecWrapper codec_config( {.coding_format = le_audio::types::kLeAudioCodingFormatLC3, .vendor_company_id = le_audio::types::kLeAudioVendorCompanyIdUndefined, .vendor_codec_id = le_audio::types::kLeAudioVendorCodecIdUndefined}, {.num_channels = LeAudioCodecConfiguration::kChannelNumberMono, .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample16, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us}, 32000, 40); auto announcement = prepareAnnouncement(codec_config, meta); ON_CALL(*sm, GetBroadcastAnnouncement()) .WillByDefault(ReturnRef(announcement)); std::promise<void> do_update_metadata_promise; struct playback_track_metadata tracks_[] = { {AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_SONIFICATION, 0}, {AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, 0}, {AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING, AUDIO_CONTENT_TYPE_SPEECH, 0}, {AUDIO_USAGE_UNKNOWN, AUDIO_CONTENT_TYPE_UNKNOWN, 0}}; source_metadata_t multitrack_source_metadata = {.track_count = 4, .tracks = &tracks_[0]}; auto do_update_metadata_future = do_update_metadata_promise.get_future(); audio_receiver->OnAudioMetadataUpdate(std::move(do_update_metadata_promise), multitrack_source_metadata); do_update_metadata_future.wait_for(3s); // Verify ccid ASSERT_NE(ccid_list.size(), 0u); ASSERT_TRUE(std::find(ccid_list.begin(), ccid_list.end(), media_ccid) != ccid_list.end()); // Verify context type ASSERT_NE(context_types_map.size(), 0u); uint16_t context_type; auto pp = context_types_map.data(); STREAM_TO_UINT16(context_type, pp); ASSERT_NE(context_type & static_cast<std::underlying_type<LeAudioContextType>::type>( LeAudioContextType::MEDIA | LeAudioContextType::GAME), 0); } TEST_F(BroadcasterTest, GetMetadata) { auto broadcast_id = InstantiateBroadcast(); bluetooth::le_audio::BroadcastMetadata metadata; // bluetooth::le_audio::BasicAudioAnnouncementData announcement; static const uint8_t test_adv_sid = 0x14; std::optional<bluetooth::le_audio::BroadcastCode> test_broadcast_code = Loading
system/bta/le_audio/broadcaster/mock_state_machine.h +1 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ class MockBroadcastStateMachine std::optional<le_audio::broadcaster::BigConfig> big_config_ = std::nullopt; le_audio::broadcaster::BroadcastStateMachineConfig cfg; le_audio::broadcaster::IBroadcastStateMachineCallbacks* cb; void SetExpectedState(BroadcastStateMachine::State state) { SetState(state); } void SetExpectedResult(bool result) { result_ = result; } void SetExpectedBigConfig( std::optional<le_audio::broadcaster::BigConfig> big_cfg) { Loading