Loading system/bta/le_audio/state_machine.cc +18 −27 Original line number Diff line number Diff line Loading @@ -1923,7 +1923,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { /* TODO: Config Codec */ break; case AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING: LeAudioDevice* leAudioDeviceNext; SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); ase->active = false; Loading @@ -1946,14 +1945,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } leAudioDeviceNext = group->GetNextActiveDevice(leAudioDevice); /* Configure ASEs for next device in group */ if (leAudioDeviceNext) { PrepareAndSendRelease(leAudioDeviceNext); } else { /* Last node is in releasing state*/ group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); /* Remote device has cache and keep staying in configured state after * release. Therefore, we assume this is a target state requested by Loading @@ -1974,7 +1966,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { state_machine_callbacks_->StatusReportCb( group->group_id_, GroupStreamStatus::CONFIGURED_AUTONOMOUS); } break; default: LOG(ERROR) << __func__ << ", invalid state transition, from: " Loading system/bta/le_audio/state_machine_test.cc +93 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,9 @@ class StateMachineTestBase : public Test { uint8_t overwrite_cis_status_idx_; std::vector<uint8_t> cis_status_; /* Keep ASE in releasing state */ bool stay_in_releasing_state_; virtual void SetUp() override { bluetooth::common::InitFlags::Load(test_flags); reset_mock_function_count_map(); Loading @@ -194,6 +197,7 @@ class StateMachineTestBase : public Test { overwrite_cis_status_idx_ = 0; overwrite_cis_status_ = false; do_not_send_cis_establish_event_ = false; stay_in_releasing_state_ = false; cis_status_.clear(); LeAudioGroupStateMachine::Initialize(&mock_callbacks_); Loading Loading @@ -1255,6 +1259,10 @@ class StateMachineTestBase : public Test { InjectAseStateNotification(ase, device, group, ascs::kAseStateReleasing, nullptr); if (stay_in_releasing_state_) { continue; } /* Check if codec configuration is cached */ if (cached_codec_configuration_map_.count(ase_id) > 0) { InjectAseStateNotification( Loading Loading @@ -3501,6 +3509,91 @@ TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) { } } TEST_F(StateMachineTest, testHandlingCachedCodecConfig2Devices) { const auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; const int num_of_devices = 2; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_of_devices); auto* firstDevice = group->GetFirstDevice(); auto* secondDevice = group->GetNextDevice(firstDevice); /* Since we prepared device with Conversional context in mind, Sink and Source * ASEs should have been configured. */ PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReceiverStartReady(group); PrepareReceiverStopReady(group); PrepareReleaseHandler(group); stay_in_releasing_state_ = true; /* Number of control point calls * 1. Codec Config * 2. QoS Config * 3. Enable * 4. Receiver Start Ready * 5. Release*/ EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_, firstDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(5); EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_, secondDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(5); InjectInitialIdleNotification(group); // Validate initial GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)})); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); /* Single disconnect as it is bidirectional Cis*/ EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); LOG_ERROR("STOP"); // Stop the stream LeAudioGroupStateMachine::Get()->StopStream(group); for (auto& ase : firstDevice->ases_) { LOG_ERROR("%s , %d, %s", ADDRESS_TO_LOGGABLE_CSTR(firstDevice->address_), ase.id, bluetooth::common::ToString(ase.state).c_str()); ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); // Simulate autonomus configured state. InjectAseStateNotification(&ase, firstDevice, group, ascs::kAseStateCodecConfigured, &cached_codec_configuration_map_[ase.id]); } for (auto& ase : secondDevice->ases_) { LOG_ERROR("%s , %d, %s", ADDRESS_TO_LOGGABLE_CSTR(firstDevice->address_), ase.id, bluetooth::common::ToString(ase.state).c_str()); ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); // Simulate autonomus configured state. InjectAseStateNotification(&ase, secondDevice, group, ascs::kAseStateCodecConfigured, &cached_codec_configuration_map_[ase.id]); } } TEST_F(StateMachineTest, testStateTransitionTimeoutOnIdleState) { const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; Loading Loading
system/bta/le_audio/state_machine.cc +18 −27 Original line number Diff line number Diff line Loading @@ -1923,7 +1923,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { /* TODO: Config Codec */ break; case AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING: LeAudioDevice* leAudioDeviceNext; SetAseState(leAudioDevice, ase, AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); ase->active = false; Loading @@ -1946,14 +1945,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return; } leAudioDeviceNext = group->GetNextActiveDevice(leAudioDevice); /* Configure ASEs for next device in group */ if (leAudioDeviceNext) { PrepareAndSendRelease(leAudioDeviceNext); } else { /* Last node is in releasing state*/ group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED); /* Remote device has cache and keep staying in configured state after * release. Therefore, we assume this is a target state requested by Loading @@ -1974,7 +1966,6 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { state_machine_callbacks_->StatusReportCb( group->group_id_, GroupStreamStatus::CONFIGURED_AUTONOMOUS); } break; default: LOG(ERROR) << __func__ << ", invalid state transition, from: " Loading
system/bta/le_audio/state_machine_test.cc +93 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,9 @@ class StateMachineTestBase : public Test { uint8_t overwrite_cis_status_idx_; std::vector<uint8_t> cis_status_; /* Keep ASE in releasing state */ bool stay_in_releasing_state_; virtual void SetUp() override { bluetooth::common::InitFlags::Load(test_flags); reset_mock_function_count_map(); Loading @@ -194,6 +197,7 @@ class StateMachineTestBase : public Test { overwrite_cis_status_idx_ = 0; overwrite_cis_status_ = false; do_not_send_cis_establish_event_ = false; stay_in_releasing_state_ = false; cis_status_.clear(); LeAudioGroupStateMachine::Initialize(&mock_callbacks_); Loading Loading @@ -1255,6 +1259,10 @@ class StateMachineTestBase : public Test { InjectAseStateNotification(ase, device, group, ascs::kAseStateReleasing, nullptr); if (stay_in_releasing_state_) { continue; } /* Check if codec configuration is cached */ if (cached_codec_configuration_map_.count(ase_id) > 0) { InjectAseStateNotification( Loading Loading @@ -3501,6 +3509,91 @@ TEST_F(StateMachineTest, testAseAutonomousRelease2Devices) { } } TEST_F(StateMachineTest, testHandlingCachedCodecConfig2Devices) { const auto context_type = kContextTypeConversational; const int leaudio_group_id = 4; const int num_of_devices = 2; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_of_devices); auto* firstDevice = group->GetFirstDevice(); auto* secondDevice = group->GetNextDevice(firstDevice); /* Since we prepared device with Conversional context in mind, Sink and Source * ASEs should have been configured. */ PrepareConfigureCodecHandler(group, 0, true); PrepareConfigureQosHandler(group); PrepareEnableHandler(group); PrepareDisableHandler(group); PrepareReceiverStartReady(group); PrepareReceiverStopReady(group); PrepareReleaseHandler(group); stay_in_releasing_state_ = true; /* Number of control point calls * 1. Codec Config * 2. QoS Config * 3. Enable * 4. Receiver Start Ready * 5. Release*/ EXPECT_CALL(gatt_queue, WriteCharacteristic(firstDevice->conn_id_, firstDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(5); EXPECT_CALL(gatt_queue, WriteCharacteristic(secondDevice->conn_id_, secondDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(5); InjectInitialIdleNotification(group); // Validate initial GroupStreamStatus EXPECT_CALL( mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::STREAMING)); // Start the configuration and stream Media content ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( group, context_type, {.sink = types::AudioContexts(context_type), .source = types::AudioContexts(context_type)})); testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); /* Single disconnect as it is bidirectional Cis*/ EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(2); LOG_ERROR("STOP"); // Stop the stream LeAudioGroupStateMachine::Get()->StopStream(group); for (auto& ase : firstDevice->ases_) { LOG_ERROR("%s , %d, %s", ADDRESS_TO_LOGGABLE_CSTR(firstDevice->address_), ase.id, bluetooth::common::ToString(ase.state).c_str()); ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); // Simulate autonomus configured state. InjectAseStateNotification(&ase, firstDevice, group, ascs::kAseStateCodecConfigured, &cached_codec_configuration_map_[ase.id]); } for (auto& ase : secondDevice->ases_) { LOG_ERROR("%s , %d, %s", ADDRESS_TO_LOGGABLE_CSTR(firstDevice->address_), ase.id, bluetooth::common::ToString(ase.state).c_str()); ASSERT_EQ(ase.state, types::AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING); // Simulate autonomus configured state. InjectAseStateNotification(&ase, secondDevice, group, ascs::kAseStateCodecConfigured, &cached_codec_configuration_map_[ase.id]); } } TEST_F(StateMachineTest, testStateTransitionTimeoutOnIdleState) { const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; Loading