Loading system/bta/le_audio/devices_test.cc +157 −9 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ using ::le_audio::types::AseState; using ::le_audio::types::AudioContexts; using ::le_audio::types::AudioLocations; using ::le_audio::types::BidirectionalPair; using ::le_audio::types::CisType; using ::le_audio::types::LeAudioContextType; using testing::_; using testing::Invoke; Loading Loading @@ -430,7 +431,8 @@ class LeAudioAseConfigurationTest : public Test { LeAudioDevice* AddTestDevice(int snk_ase_num, int src_ase_num, int snk_ase_num_cached = 0, int src_ase_num_cached = 0) { int src_ase_num_cached = 0, bool invert_ases_emplacement = false) { int index = group_->Size() + 1; auto device = (std::make_shared<LeAudioDevice>( GetTestAddress(index), DeviceConnectState::DISCONNECTED)); Loading @@ -442,24 +444,42 @@ class LeAudioAseConfigurationTest : public Test { group_->AddNode(device); int ase_id = 1; for (int i = 0; i < src_ase_num; i++) { device->ases_.emplace_back(0x0000, 0x0000, kLeAudioDirectionSource, for (int i = 0; i < (invert_ases_emplacement ? snk_ase_num : src_ase_num); i++) { device->ases_.emplace_back(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSink : kLeAudioDirectionSource, ase_id++); } for (int i = 0; i < snk_ase_num; i++) { device->ases_.emplace_back(0x0000, 0x0000, kLeAudioDirectionSink, for (int i = 0; i < (invert_ases_emplacement ? src_ase_num : snk_ase_num); i++) { device->ases_.emplace_back(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSource : kLeAudioDirectionSink, ase_id++); } for (int i = 0; i < src_ase_num_cached; i++) { struct ase ase(0x0000, 0x0000, kLeAudioDirectionSource, ase_id++); for (int i = 0; i < (invert_ases_emplacement ? snk_ase_num_cached : src_ase_num_cached); i++) { struct ase ase(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSink : kLeAudioDirectionSource, ase_id++); ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; device->ases_.push_back(ase); } for (int i = 0; i < snk_ase_num_cached; i++) { struct ase ase(0x0000, 0x0000, kLeAudioDirectionSink, ase_id++); for (int i = 0; i < (invert_ases_emplacement ? src_ase_num_cached : snk_ase_num_cached); i++) { struct ase ase(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSource : kLeAudioDirectionSink, ase_id++); ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; device->ases_.push_back(ase); } Loading Loading @@ -792,6 +812,18 @@ class LeAudioAseConfigurationTest : public Test { } } void SetAsesToCachedConfiguration(LeAudioDevice* device, LeAudioContextType context_type, uint8_t directions) { for (struct ase& ase : device->ases_) { if (ase.direction & directions) { ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; ase.active = false; ase.configured_for_context_type = context_type; } } } const int group_id_ = 6; std::vector<std::shared_ptr<LeAudioDevice>> devices_; std::vector<RawAddress> addresses_; Loading Loading @@ -1218,6 +1250,122 @@ TEST_F(LeAudioAseConfigurationTest, test_reconnection_media) { TestActiveAses(); } /* * Failure happens when restarting conversational scenario and when * remote device uses caching. * * Failing scenario. * 1. Conversational scenario set up with * - ASE 1 and ASE 5 using bidirectional CIS 0 * - ASE 2 being unidirectional on CIS 1 * 2. Stop stream and go to CONFIGURED STATE. * 3. Trying to configure ASES again would end up in incorrectly assigned * CISes * - ASE 1 and ASE 5 set to CIS 0 * - ASE 2 stay on CIS 1 but ASE 5 got reassigned to CIS 1 (error) * * The problem is finding matching_bidir_ase which shall not be just next * active ase with different direction, but it shall be also available (Cis * not assigned) or assigned to the same CIS ID as the opposite direction. */ TEST_F(LeAudioAseConfigurationTest, test_reactivation_conversational) { LeAudioDevice* tws_headset = AddTestDevice(0, 0, 2, 1, true); /* Change location as by default it is stereo */ tws_headset->snk_audio_locations_ = kChannelAllocationStereo; tws_headset->src_audio_locations_ = ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft; group_->ReloadAudioLocations(); auto all_configurations = ::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( LeAudioContextType::CONVERSATIONAL); ASSERT_NE(nullptr, all_configurations); ASSERT_NE(all_configurations->end(), all_configurations->begin()); /* Pick TWS configuration for conversational */ auto iter = std::find_if(all_configurations->begin(), all_configurations->end(), [](auto& configuration) { return configuration->name == "SingleDev_OneChanStereoSnk_OneChanMonoSrc_" "16_2_Low_Latency"; }); ASSERT_NE(iter, all_configurations->end()); auto conversational_configuration = *iter; // Build PACs for device PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder; snk_pac_builder.Reset(); src_pac_builder.Reset(); /* Create PACs for conversational scenario which covers also media. Single * PAC for each direction is enough. */ for (const auto& entry : (*conversational_configuration).confs) { if (entry.direction == kLeAudioDirectionSink) { snk_pac_builder.Add(entry.codec, 1); } else { src_pac_builder.Add(entry.codec, 1); } } tws_headset->snk_pacs_ = snk_pac_builder.Get(); tws_headset->src_pacs_ = src_pac_builder.Get(); ::le_audio::types::AudioLocations group_snk_audio_locations = 0; ::le_audio::types::AudioLocations group_src_audio_locations = 0; uint8_t number_of_already_active_ases = 0; BidirectionalPair<AudioLocations> group_audio_locations = { .sink = group_snk_audio_locations, .source = group_src_audio_locations}; /* Get entry for the sink direction and use it to set configuration */ BidirectionalPair<std::vector<uint8_t>> ccid_lists = {{}, {}}; BidirectionalPair<AudioContexts> audio_contexts = {AudioContexts(), AudioContexts()}; /* Get entry for the sink direction and use it to set configuration */ for (auto& ent : conversational_configuration->confs) { tws_headset->ConfigureAses(ent, group_->GetConfigurationContextType(), &number_of_already_active_ases, group_audio_locations, audio_contexts, ccid_lists, false); } /* Generate CISes, simulate CIG creation and assign cis handles to ASEs.*/ std::vector<uint16_t> handles = {0x0012, 0x0013}; group_->CigGenerateCisIds(LeAudioContextType::CONVERSATIONAL); group_->CigAssignCisConnHandles(handles); group_->CigAssignCisIds(tws_headset); TestActiveAses(); /* Simulate stopping stream with caching codec configuration in ASEs */ group_->CigUnassignCis(tws_headset); SetAsesToCachedConfiguration(tws_headset, LeAudioContextType::CONVERSATIONAL, kLeAudioDirectionSink | kLeAudioDirectionSource); /* As context type is the same as previous and no changes were made in PACs * the same CIS ID can be used. This would lead to only activating group * without reconfiguring CIG. */ group_->Activate(LeAudioContextType::CONVERSATIONAL); TestActiveAses(); /* Verify ASEs assigned CISes by counting assigned to bi-directional CISes */ int bi_dir_ases_count = std::count_if( tws_headset->ases_.begin(), tws_headset->ases_.end(), [=](auto& ase) { return this->group_->cises_[ase.cis_id].type == CisType::CIS_TYPE_BIDIRECTIONAL; }); /* Only two ASEs can be bonded to one bi-directional CIS */ ASSERT_EQ(bi_dir_ases_count, 2); } } // namespace } // namespace internal } // namespace le_audio Loading Loading
system/bta/le_audio/devices_test.cc +157 −9 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ using ::le_audio::types::AseState; using ::le_audio::types::AudioContexts; using ::le_audio::types::AudioLocations; using ::le_audio::types::BidirectionalPair; using ::le_audio::types::CisType; using ::le_audio::types::LeAudioContextType; using testing::_; using testing::Invoke; Loading Loading @@ -430,7 +431,8 @@ class LeAudioAseConfigurationTest : public Test { LeAudioDevice* AddTestDevice(int snk_ase_num, int src_ase_num, int snk_ase_num_cached = 0, int src_ase_num_cached = 0) { int src_ase_num_cached = 0, bool invert_ases_emplacement = false) { int index = group_->Size() + 1; auto device = (std::make_shared<LeAudioDevice>( GetTestAddress(index), DeviceConnectState::DISCONNECTED)); Loading @@ -442,24 +444,42 @@ class LeAudioAseConfigurationTest : public Test { group_->AddNode(device); int ase_id = 1; for (int i = 0; i < src_ase_num; i++) { device->ases_.emplace_back(0x0000, 0x0000, kLeAudioDirectionSource, for (int i = 0; i < (invert_ases_emplacement ? snk_ase_num : src_ase_num); i++) { device->ases_.emplace_back(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSink : kLeAudioDirectionSource, ase_id++); } for (int i = 0; i < snk_ase_num; i++) { device->ases_.emplace_back(0x0000, 0x0000, kLeAudioDirectionSink, for (int i = 0; i < (invert_ases_emplacement ? src_ase_num : snk_ase_num); i++) { device->ases_.emplace_back(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSource : kLeAudioDirectionSink, ase_id++); } for (int i = 0; i < src_ase_num_cached; i++) { struct ase ase(0x0000, 0x0000, kLeAudioDirectionSource, ase_id++); for (int i = 0; i < (invert_ases_emplacement ? snk_ase_num_cached : src_ase_num_cached); i++) { struct ase ase(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSink : kLeAudioDirectionSource, ase_id++); ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; device->ases_.push_back(ase); } for (int i = 0; i < snk_ase_num_cached; i++) { struct ase ase(0x0000, 0x0000, kLeAudioDirectionSink, ase_id++); for (int i = 0; i < (invert_ases_emplacement ? src_ase_num_cached : snk_ase_num_cached); i++) { struct ase ase(0x0000, 0x0000, invert_ases_emplacement ? kLeAudioDirectionSource : kLeAudioDirectionSink, ase_id++); ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; device->ases_.push_back(ase); } Loading Loading @@ -792,6 +812,18 @@ class LeAudioAseConfigurationTest : public Test { } } void SetAsesToCachedConfiguration(LeAudioDevice* device, LeAudioContextType context_type, uint8_t directions) { for (struct ase& ase : device->ases_) { if (ase.direction & directions) { ase.state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; ase.active = false; ase.configured_for_context_type = context_type; } } } const int group_id_ = 6; std::vector<std::shared_ptr<LeAudioDevice>> devices_; std::vector<RawAddress> addresses_; Loading Loading @@ -1218,6 +1250,122 @@ TEST_F(LeAudioAseConfigurationTest, test_reconnection_media) { TestActiveAses(); } /* * Failure happens when restarting conversational scenario and when * remote device uses caching. * * Failing scenario. * 1. Conversational scenario set up with * - ASE 1 and ASE 5 using bidirectional CIS 0 * - ASE 2 being unidirectional on CIS 1 * 2. Stop stream and go to CONFIGURED STATE. * 3. Trying to configure ASES again would end up in incorrectly assigned * CISes * - ASE 1 and ASE 5 set to CIS 0 * - ASE 2 stay on CIS 1 but ASE 5 got reassigned to CIS 1 (error) * * The problem is finding matching_bidir_ase which shall not be just next * active ase with different direction, but it shall be also available (Cis * not assigned) or assigned to the same CIS ID as the opposite direction. */ TEST_F(LeAudioAseConfigurationTest, test_reactivation_conversational) { LeAudioDevice* tws_headset = AddTestDevice(0, 0, 2, 1, true); /* Change location as by default it is stereo */ tws_headset->snk_audio_locations_ = kChannelAllocationStereo; tws_headset->src_audio_locations_ = ::le_audio::codec_spec_conf::kLeAudioLocationFrontLeft; group_->ReloadAudioLocations(); auto all_configurations = ::le_audio::AudioSetConfigurationProvider::Get()->GetConfigurations( LeAudioContextType::CONVERSATIONAL); ASSERT_NE(nullptr, all_configurations); ASSERT_NE(all_configurations->end(), all_configurations->begin()); /* Pick TWS configuration for conversational */ auto iter = std::find_if(all_configurations->begin(), all_configurations->end(), [](auto& configuration) { return configuration->name == "SingleDev_OneChanStereoSnk_OneChanMonoSrc_" "16_2_Low_Latency"; }); ASSERT_NE(iter, all_configurations->end()); auto conversational_configuration = *iter; // Build PACs for device PublishedAudioCapabilitiesBuilder snk_pac_builder, src_pac_builder; snk_pac_builder.Reset(); src_pac_builder.Reset(); /* Create PACs for conversational scenario which covers also media. Single * PAC for each direction is enough. */ for (const auto& entry : (*conversational_configuration).confs) { if (entry.direction == kLeAudioDirectionSink) { snk_pac_builder.Add(entry.codec, 1); } else { src_pac_builder.Add(entry.codec, 1); } } tws_headset->snk_pacs_ = snk_pac_builder.Get(); tws_headset->src_pacs_ = src_pac_builder.Get(); ::le_audio::types::AudioLocations group_snk_audio_locations = 0; ::le_audio::types::AudioLocations group_src_audio_locations = 0; uint8_t number_of_already_active_ases = 0; BidirectionalPair<AudioLocations> group_audio_locations = { .sink = group_snk_audio_locations, .source = group_src_audio_locations}; /* Get entry for the sink direction and use it to set configuration */ BidirectionalPair<std::vector<uint8_t>> ccid_lists = {{}, {}}; BidirectionalPair<AudioContexts> audio_contexts = {AudioContexts(), AudioContexts()}; /* Get entry for the sink direction and use it to set configuration */ for (auto& ent : conversational_configuration->confs) { tws_headset->ConfigureAses(ent, group_->GetConfigurationContextType(), &number_of_already_active_ases, group_audio_locations, audio_contexts, ccid_lists, false); } /* Generate CISes, simulate CIG creation and assign cis handles to ASEs.*/ std::vector<uint16_t> handles = {0x0012, 0x0013}; group_->CigGenerateCisIds(LeAudioContextType::CONVERSATIONAL); group_->CigAssignCisConnHandles(handles); group_->CigAssignCisIds(tws_headset); TestActiveAses(); /* Simulate stopping stream with caching codec configuration in ASEs */ group_->CigUnassignCis(tws_headset); SetAsesToCachedConfiguration(tws_headset, LeAudioContextType::CONVERSATIONAL, kLeAudioDirectionSink | kLeAudioDirectionSource); /* As context type is the same as previous and no changes were made in PACs * the same CIS ID can be used. This would lead to only activating group * without reconfiguring CIG. */ group_->Activate(LeAudioContextType::CONVERSATIONAL); TestActiveAses(); /* Verify ASEs assigned CISes by counting assigned to bi-directional CISes */ int bi_dir_ases_count = std::count_if( tws_headset->ases_.begin(), tws_headset->ases_.end(), [=](auto& ase) { return this->group_->cises_[ase.cis_id].type == CisType::CIS_TYPE_BIDIRECTIONAL; }); /* Only two ASEs can be bonded to one bi-directional CIS */ ASSERT_EQ(bi_dir_ases_count, 2); } } // namespace } // namespace internal } // namespace le_audio Loading