Loading system/bta/le_audio/client.cc +0 −11 Original line number Diff line number Diff line Loading @@ -955,17 +955,6 @@ public: return; } if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { log::warn("group {} was about to stream, but got canceled: {}", group_id, ToString(group->GetTargetState())); group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); } else { log::warn(", group {} already stopped: {}", group_id, ToString(group->GetState())); } return; } groupStateMachine_->StopStream(group); } Loading system/bta/le_audio/device_groups.cc +9 −2 Original line number Diff line number Diff line Loading @@ -1065,8 +1065,15 @@ bool LeAudioDeviceGroup::IsStreaming(void) const { } bool LeAudioDeviceGroup::IsReleasingOrIdle(void) const { return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) || (current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); /* If target state is IDLE then for sure group is either releasing or idle. * Otherwise, we have "idle states" - Idle or Configured when caching is * supported on the remote side. In both cases to check it is to make sure * group is not in transition. */ return target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE || ((current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE || current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) && !in_transition_); } bool LeAudioDeviceGroup::IsGroupStreamReady(void) const { Loading system/bta/le_audio/le_audio_client_test.cc +51 −0 Original line number Diff line number Diff line Loading @@ -1191,6 +1191,11 @@ protected: // Inject the state group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); if (block_qos_config) { return true; } group->SetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); streaming_groups[group->group_id_] = group; Loading Loading @@ -1432,6 +1437,7 @@ protected: SetUpMockCodecManager(codec_location); block_streaming_state_callback = false; block_qos_config = false; available_snk_context_types_ = 0xffff; available_src_context_types_ = 0xffff; Loading Loading @@ -2654,6 +2660,7 @@ protected: bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_; std::map<int, LeAudioDeviceGroup*> streaming_groups; bool block_streaming_state_callback = false; bool block_qos_config = false; bool attach_to_stream_scheduled = false; Loading Loading @@ -4788,6 +4795,50 @@ TEST_F(UnicastTest, GroupSetActive_SourcePacksEmpty) { Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_); } TEST_F(UnicastTest, GroupSetActive_and_InactiveDuringStreamConfiguration) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; empty_source_pack_ = true; /** * In this test we want to make sure that StopStream is called when group is set to inactive * while being between IDLE and CONFIGURED state */ default_channel_cnt = 1; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, 0 /*rank*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) .WillOnce(DoAll(SaveArg<1>(&group_id))); ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1); block_qos_config = true; LeAudioClient::Get()->GroupSetActive(group_id); StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, AUDIO_SOURCE_INVALID, false, false); SyncOnMainLoop(); EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_state_machine_); } TEST_F(UnicastTest, ChangeAvailableContextTypeWhenInCodecConfigured) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; Loading system/bta/le_audio/state_machine.cc +2 −1 Original line number Diff line number Diff line Loading @@ -314,7 +314,8 @@ public: void StopStream(LeAudioDeviceGroup* group) override { if (group->IsReleasingOrIdle()) { log::info("group: {} already in releasing process", group->group_id_); log::info("group: {} in_transition: {}, current_state {}", group->group_id_, group->IsInTransition(), ToString(group->GetState())); return; } Loading system/bta/le_audio/state_machine_test.cc +55 −0 Original line number Diff line number Diff line Loading @@ -8474,5 +8474,60 @@ TEST_F(StateMachineTest, testAutonomousDisable_GoToIdle) { testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } TEST_F(StateMachineTest, testStopStreamBeforeCodecConfigureIsArrived) { /* Device is banded headphones with 1x snk + 0x src ase * (1xunidirectional CIS with channel count 2 for stereo) */ const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; channel_count_ = kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); auto* leAudioDevice = group->GetFirstDevice(); /* * 1 - Configure ASE * 2 - Release ASE */ EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(2); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); // Validate GroupStreamStatus EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::IDLE)); // 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)})); // Stop the stream before Codec Configured arrived LeAudioGroupStateMachine::Get()->StopStream(group); testing::Mock::VerifyAndClearExpectations(&gatt_queue); InjectCachedConfigurationForActiveAses(group, leAudioDevice); InjectReleaseAndIdleStateForAGroup(group); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); ASSERT_EQ(2, get_func_call_count("alarm_cancel")); } } // namespace internal } // namespace bluetooth::le_audio Loading
system/bta/le_audio/client.cc +0 −11 Original line number Diff line number Diff line Loading @@ -955,17 +955,6 @@ public: return; } if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) { log::warn("group {} was about to stream, but got canceled: {}", group_id, ToString(group->GetTargetState())); group->SetTargetState(AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); } else { log::warn(", group {} already stopped: {}", group_id, ToString(group->GetState())); } return; } groupStateMachine_->StopStream(group); } Loading
system/bta/le_audio/device_groups.cc +9 −2 Original line number Diff line number Diff line Loading @@ -1065,8 +1065,15 @@ bool LeAudioDeviceGroup::IsStreaming(void) const { } bool LeAudioDeviceGroup::IsReleasingOrIdle(void) const { return (target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) || (current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); /* If target state is IDLE then for sure group is either releasing or idle. * Otherwise, we have "idle states" - Idle or Configured when caching is * supported on the remote side. In both cases to check it is to make sure * group is not in transition. */ return target_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE || ((current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE || current_state_ == AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED) && !in_transition_); } bool LeAudioDeviceGroup::IsGroupStreamReady(void) const { Loading
system/bta/le_audio/le_audio_client_test.cc +51 −0 Original line number Diff line number Diff line Loading @@ -1191,6 +1191,11 @@ protected: // Inject the state group->SetTargetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); if (block_qos_config) { return true; } group->SetState(types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); streaming_groups[group->group_id_] = group; Loading Loading @@ -1432,6 +1437,7 @@ protected: SetUpMockCodecManager(codec_location); block_streaming_state_callback = false; block_qos_config = false; available_snk_context_types_ = 0xffff; available_src_context_types_ = 0xffff; Loading Loading @@ -2654,6 +2660,7 @@ protected: bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_; std::map<int, LeAudioDeviceGroup*> streaming_groups; bool block_streaming_state_callback = false; bool block_qos_config = false; bool attach_to_stream_scheduled = false; Loading Loading @@ -4788,6 +4795,50 @@ TEST_F(UnicastTest, GroupSetActive_SourcePacksEmpty) { Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_); } TEST_F(UnicastTest, GroupSetActive_and_InactiveDuringStreamConfiguration) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; empty_source_pack_ = true; /** * In this test we want to make sure that StopStream is called when group is set to inactive * while being between IDLE and CONFIGURED state */ default_channel_cnt = 1; SetSampleDatabaseEarbudsValid( 1, test_address0, codec_spec_conf::kLeAudioLocationStereo, codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt, default_channel_cnt, 0x0004, /* source sample freq 16khz */ false /*add_csis*/, true /*add_cas*/, true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/, 0 /*rank*/); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnConnectionState(ConnectionState::CONNECTED, test_address0)) .Times(1); EXPECT_CALL(mock_audio_hal_client_callbacks_, OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) .WillOnce(DoAll(SaveArg<1>(&group_id))); ConnectLeAudio(test_address0); ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, _)).Times(1); block_qos_config = true; LeAudioClient::Get()->GroupSetActive(group_id); StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id, AUDIO_SOURCE_INVALID, false, false); SyncOnMainLoop(); EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_state_machine_); } TEST_F(UnicastTest, ChangeAvailableContextTypeWhenInCodecConfigured) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; Loading
system/bta/le_audio/state_machine.cc +2 −1 Original line number Diff line number Diff line Loading @@ -314,7 +314,8 @@ public: void StopStream(LeAudioDeviceGroup* group) override { if (group->IsReleasingOrIdle()) { log::info("group: {} already in releasing process", group->group_id_); log::info("group: {} in_transition: {}, current_state {}", group->group_id_, group->IsInTransition(), ToString(group->GetState())); return; } Loading
system/bta/le_audio/state_machine_test.cc +55 −0 Original line number Diff line number Diff line Loading @@ -8474,5 +8474,60 @@ TEST_F(StateMachineTest, testAutonomousDisable_GoToIdle) { testing::Mock::VerifyAndClearExpectations(&mock_callbacks_); } TEST_F(StateMachineTest, testStopStreamBeforeCodecConfigureIsArrived) { /* Device is banded headphones with 1x snk + 0x src ase * (1xunidirectional CIS with channel count 2 for stereo) */ const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4; channel_count_ = kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel; // Prepare fake connected device group auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); auto* leAudioDevice = group->GetFirstDevice(); /* * 1 - Configure ASE * 2 - Release ASE */ EXPECT_CALL(gatt_queue, WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, GATT_WRITE_NO_RSP, _, _)) .Times(2); EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(0); EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveIsoDataPath(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, DisconnectCis(_, _)).Times(0); EXPECT_CALL(*mock_iso_manager_, RemoveCig(_, _)).Times(0); InjectInitialIdleNotification(group); // Validate GroupStreamStatus EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::RELEASING)); EXPECT_CALL(mock_callbacks_, StatusReportCb(leaudio_group_id, bluetooth::le_audio::GroupStreamStatus::IDLE)); // 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)})); // Stop the stream before Codec Configured arrived LeAudioGroupStateMachine::Get()->StopStream(group); testing::Mock::VerifyAndClearExpectations(&gatt_queue); InjectCachedConfigurationForActiveAses(group, leAudioDevice); InjectReleaseAndIdleStateForAGroup(group); // Check if group has transitioned to a proper state ASSERT_EQ(group->GetState(), types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE); ASSERT_EQ(2, get_func_call_count("alarm_cancel")); } } // namespace internal } // namespace bluetooth::le_audio