diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc index 03bbe237a398cbb49d86959ff301ff2bd847bc9b..a0ff6a1f7d431fcf65b16f273140c799d77c10a0 100644 --- a/system/bta/le_audio/state_machine.cc +++ b/system/bta/le_audio/state_machine.cc @@ -966,13 +966,11 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { ases_pair.sink->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { ases_pair.sink->state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; - ases_pair.sink->active = false; } if (ases_pair.source && ases_pair.source->state == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) { ases_pair.source->state = AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED; - ases_pair.source->active = false; } } diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc index a20ab63625a1a4c84a7256335b590be1d13189f8..6c55c6710f07a1f3d232b28a972647402f124003 100644 --- a/system/bta/le_audio/state_machine_test.cc +++ b/system/bta/le_audio/state_machine_test.cc @@ -490,6 +490,7 @@ class StateMachineTest : public Test { addresses_.clear(); cached_codec_configuration_map_.clear(); cached_ase_to_cis_id_map_.clear(); + cached_remote_qos_configuration_for_ase_.clear(); LeAudioGroupStateMachine::Cleanup(); ::le_audio::AudioSetConfigurationProvider::Cleanup(); } @@ -625,6 +626,8 @@ class StateMachineTest : public Test { UINT16_TO_STREAM(p, conf->max_transport_latency); UINT24_TO_STREAM(p, conf->pres_delay); + cached_remote_qos_configuration_for_ase_[ase] = notif_value; + LeAudioGroupStateMachine::Get()->ProcessGattNotifEvent( notif_value.data(), notif_value.size(), ase, device, group); } break; @@ -1280,6 +1283,8 @@ class StateMachineTest : public Test { cached_codec_configuration_map_; std::map<RawAddress, std::map<int, int>> cached_ase_to_cis_id_map_; + std::map<types::ase*, std::vector<uint8_t>> + cached_remote_qos_configuration_for_ase_; MockLeAudioGroupStateMachineCallbacks mock_callbacks_; std::vector<std::shared_ptr<LeAudioDevice>> le_audio_devices_; @@ -3705,6 +3710,120 @@ TEST_F(StateMachineTest, testAttachDeviceToTheStream) { ASSERT_NE(ase->retrans_nb, 0); } +TEST_F(StateMachineTest, + testAttachDeviceToTheStream_autonomusQoSConfiguredState) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 6; + const auto num_devices = 2; + + ContentControlIdKeeper::GetInstance()->SetCcid(media_context, media_ccid); + + // Prepare multiple fake connected devices in a group + auto* group = + PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + ASSERT_EQ(group->Size(), num_devices); + + PrepareConfigureCodecHandler(group); + PrepareConfigureQosHandler(group); + PrepareEnableHandler(group); + PrepareDisableHandler(group); + PrepareReleaseHandler(group); + + auto* leAudioDevice = group->GetFirstDevice(); + LeAudioDevice* lastDevice; + LeAudioDevice* fistDevice = leAudioDevice; + + auto expected_devices_written = 0; + while (leAudioDevice) { + /* Three Writes: + * 1: Codec Config + * 2: Codec QoS + * 3: Enabling + */ + lastDevice = leAudioDevice; + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(AtLeast(3)); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + + InjectInitialIdleNotification(group); + + // Start the configuration and stream Media content + LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)}, + {.sink = std::vector<uint8_t>(1, media_ccid), + .source = std::vector<uint8_t>(1, media_ccid)}); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + testing::Mock::VerifyAndClearExpectations(&mock_iso_manager_); + + // Inject CIS and ACL disconnection of first device + InjectCisDisconnected(group, lastDevice, HCI_ERR_CONNECTION_TOUT); + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Make sure ASE with disconnected CIS are not left in STREAMING + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSink, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + ASSERT_EQ(lastDevice->GetFirstAseWithState( + ::le_audio::types::kLeAudioDirectionSource, + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING), + nullptr); + + EXPECT_CALL(gatt_queue, WriteCharacteristic(lastDevice->conn_id_, + lastDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(1); + + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(1); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(1); + + for (auto& ase : lastDevice->ases_) { + if (cached_remote_qos_configuration_for_ase_.count(&ase) > 0) { + InjectAseStateNotification( + &ase, lastDevice, group, ascs::kAseStateQoSConfigured, + &(cached_remote_qos_configuration_for_ase_[&ase])); + } + } + + // Check if group keeps streaming + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Verify that the joining device receives the right CCID list + auto lastMeta = lastDevice->GetFirstActiveAse()->metadata; + bool parsedOk = false; + auto ltv = le_audio::types::LeAudioLtvMap::Parse(lastMeta.data(), + lastMeta.size(), parsedOk); + ASSERT_TRUE(parsedOk); + + auto ccids = ltv.Find(le_audio::types::kLeAudioMetadataTypeCcidList); + ASSERT_TRUE(ccids.has_value()); + ASSERT_NE(std::find(ccids->begin(), ccids->end(), media_ccid), ccids->end()); + + /* Verify that ASE of first device are still good*/ + auto ase = fistDevice->GetFirstActiveAse(); + ASSERT_NE(ase->max_transport_latency, 0); + ASSERT_NE(ase->retrans_nb, 0); +} + TEST_F(StateMachineTest, testAttachDeviceToTheStreamDoNotAttach) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 6;