Loading system/bta/le_audio/client.cc +41 −25 Original line number Diff line number Diff line Loading @@ -5121,15 +5121,42 @@ class LeAudioClientImpl : public LeAudioClient { bluetooth::common::ToString(audio_receiver_state_).c_str()); LeAudioDeviceGroup* group = aseGroups_.FindById(group_id); switch (status) { case GroupStreamStatus::STREAMING: case GroupStreamStatus::STREAMING: { ASSERT_LOG(group_id == active_group_id_, "invalid group id %d!=%d", group_id, active_group_id_); take_stream_time(); le_audio::MetricsCollector::Get()->OnStreamStarted( active_group_id_, configuration_context_type_); if (leAudioHealthStatus_) { leAudioHealthStatus_->AddStatisticForGroup( group_id, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); } if (!group) { LOG_ERROR("Group %d does not exist anymore. This shall not happen ", group_id); return; } if ((audio_sender_state_ == AudioState::IDLE) && (audio_receiver_state_ == AudioState::IDLE)) { /* Audio Framework is not interested in the stream anymore. * Just stop streaming */ LOG_WARN("Stopping stream for group %d as AF not interested.", group_id); groupStateMachine_->StopStream(group); return; } /* It might happen that the configuration has already changed, while * the group was in the ongoing reconfiguration. We should stop the * stream and reconfigure once again. */ if (group && group->GetConfigurationContextType() != if (group->GetConfigurationContextType() != configuration_context_type_) { LOG_DEBUG( "The configuration %s is no longer valid. Stopping the stream to" Loading @@ -5143,7 +5170,6 @@ class LeAudioClientImpl : public LeAudioClient { return; } if (group) { BidirectionalPair<uint16_t> delays_pair = { .sink = group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink), Loading @@ -5154,24 +5180,14 @@ class LeAudioClientImpl : public LeAudioClient { std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal, weak_factory_.GetWeakPtr(), std::placeholders::_1, std::placeholders::_2)); } if (audio_sender_state_ == AudioState::READY_TO_START) StartSendingAudio(group_id); if (audio_receiver_state_ == AudioState::READY_TO_START) StartReceivingAudio(group_id); take_stream_time(); le_audio::MetricsCollector::Get()->OnStreamStarted( active_group_id_, configuration_context_type_); if (leAudioHealthStatus_) { leAudioHealthStatus_->AddStatisticForGroup( group_id, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); } break; } case GroupStreamStatus::SUSPENDED: stream_setup_end_timestamp_ = 0; stream_setup_start_timestamp_ = 0; Loading system/bta/le_audio/le_audio_client_test.cc +76 −1 Original line number Diff line number Diff line Loading @@ -1111,6 +1111,8 @@ class UnicastTestNoInit : public Test { /* Assume CIG is created */ group->cig_state_ = le_audio::types::CigState::CREATED; if (block_streaming_state_callback) return true; do_in_main_thread( FROM_HERE, base::BindOnce( [](int group_id, Loading Loading @@ -1412,10 +1414,13 @@ class UnicastTestNoInit : public Test { SetUpMockGatt(); SetUpMockCodecManager(codec_location); block_streaming_state_callback = false; available_snk_context_types_ = 0xffff; available_src_context_types_ = 0xffff; supported_snk_context_types_ = 0xffff; supported_src_context_types_ = 0xffff; le_audio::AudioSetConfigurationProvider::Initialize(codec_location); ASSERT_FALSE(LeAudioClient::IsLeAudioClientRunning()); } Loading Loading @@ -1809,12 +1814,19 @@ class UnicastTestNoInit : public Test { SyncOnMainLoop(); } void LocalAudioSourceResume(bool expected_confirmation = true) { void LocalAudioSourceResume(bool expected_confirmation = true, bool expected_cancel = false) { ASSERT_NE(nullptr, mock_le_audio_source_hal_client_); if (expected_confirmation) { EXPECT_CALL(*mock_le_audio_source_hal_client_, ConfirmStreamingRequest()) .Times(1); } if (expected_cancel) { EXPECT_CALL(*mock_le_audio_source_hal_client_, CancelStreamingRequest()) .Times(1); } do_in_main_thread(FROM_HERE, base::BindOnce( [](LeAudioSourceAudioHalClient::Callbacks* cb) { Loading Loading @@ -2512,6 +2524,7 @@ class UnicastTestNoInit : public Test { uint16_t global_conn_id = 1; le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_; std::map<int, LeAudioDeviceGroup*> streaming_groups; bool block_streaming_state_callback = false; bluetooth::hci::IsoManager* iso_manager_; MockIsoManager* mock_iso_manager_; Loading Loading @@ -3713,6 +3726,68 @@ TEST_F(UnicastTest, GroupingAddRemove) { ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); } TEST_F(UnicastTest, DoubleResumeFromAF) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; 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); constexpr int gmcs_ccid = 1; constexpr int gtbs_ccid = 2; // Audio sessions are started only when device gets active EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1); LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); LeAudioClient::Get()->GroupSetActive(group_id); SyncOnMainLoop(); types::BidirectionalPair<std::vector<uint8_t>> ccids = {.sink = {gmcs_ccid}, .source = {}}; EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); block_streaming_state_callback = true; UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC); LocalAudioSourceResume(false); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); LocalAudioSourceResume(false, true); EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); do_in_main_thread( FROM_HERE, base::BindOnce( [](int group_id, le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks) { state_machine_callbacks->StatusReportCb( group_id, GroupStreamStatus::STREAMING); }, group_id, base::Unretained(state_machine_callbacks_))); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_state_machine_); } TEST_F(UnicastTest, RemoveNodeWhileStreaming) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; Loading Loading
system/bta/le_audio/client.cc +41 −25 Original line number Diff line number Diff line Loading @@ -5121,15 +5121,42 @@ class LeAudioClientImpl : public LeAudioClient { bluetooth::common::ToString(audio_receiver_state_).c_str()); LeAudioDeviceGroup* group = aseGroups_.FindById(group_id); switch (status) { case GroupStreamStatus::STREAMING: case GroupStreamStatus::STREAMING: { ASSERT_LOG(group_id == active_group_id_, "invalid group id %d!=%d", group_id, active_group_id_); take_stream_time(); le_audio::MetricsCollector::Get()->OnStreamStarted( active_group_id_, configuration_context_type_); if (leAudioHealthStatus_) { leAudioHealthStatus_->AddStatisticForGroup( group_id, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); } if (!group) { LOG_ERROR("Group %d does not exist anymore. This shall not happen ", group_id); return; } if ((audio_sender_state_ == AudioState::IDLE) && (audio_receiver_state_ == AudioState::IDLE)) { /* Audio Framework is not interested in the stream anymore. * Just stop streaming */ LOG_WARN("Stopping stream for group %d as AF not interested.", group_id); groupStateMachine_->StopStream(group); return; } /* It might happen that the configuration has already changed, while * the group was in the ongoing reconfiguration. We should stop the * stream and reconfigure once again. */ if (group && group->GetConfigurationContextType() != if (group->GetConfigurationContextType() != configuration_context_type_) { LOG_DEBUG( "The configuration %s is no longer valid. Stopping the stream to" Loading @@ -5143,7 +5170,6 @@ class LeAudioClientImpl : public LeAudioClient { return; } if (group) { BidirectionalPair<uint16_t> delays_pair = { .sink = group->GetRemoteDelay(le_audio::types::kLeAudioDirectionSink), Loading @@ -5154,24 +5180,14 @@ class LeAudioClientImpl : public LeAudioClient { std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal, weak_factory_.GetWeakPtr(), std::placeholders::_1, std::placeholders::_2)); } if (audio_sender_state_ == AudioState::READY_TO_START) StartSendingAudio(group_id); if (audio_receiver_state_ == AudioState::READY_TO_START) StartReceivingAudio(group_id); take_stream_time(); le_audio::MetricsCollector::Get()->OnStreamStarted( active_group_id_, configuration_context_type_); if (leAudioHealthStatus_) { leAudioHealthStatus_->AddStatisticForGroup( group_id, LeAudioHealthGroupStatType::STREAM_CREATE_SUCCESS); } break; } case GroupStreamStatus::SUSPENDED: stream_setup_end_timestamp_ = 0; stream_setup_start_timestamp_ = 0; Loading
system/bta/le_audio/le_audio_client_test.cc +76 −1 Original line number Diff line number Diff line Loading @@ -1111,6 +1111,8 @@ class UnicastTestNoInit : public Test { /* Assume CIG is created */ group->cig_state_ = le_audio::types::CigState::CREATED; if (block_streaming_state_callback) return true; do_in_main_thread( FROM_HERE, base::BindOnce( [](int group_id, Loading Loading @@ -1412,10 +1414,13 @@ class UnicastTestNoInit : public Test { SetUpMockGatt(); SetUpMockCodecManager(codec_location); block_streaming_state_callback = false; available_snk_context_types_ = 0xffff; available_src_context_types_ = 0xffff; supported_snk_context_types_ = 0xffff; supported_src_context_types_ = 0xffff; le_audio::AudioSetConfigurationProvider::Initialize(codec_location); ASSERT_FALSE(LeAudioClient::IsLeAudioClientRunning()); } Loading Loading @@ -1809,12 +1814,19 @@ class UnicastTestNoInit : public Test { SyncOnMainLoop(); } void LocalAudioSourceResume(bool expected_confirmation = true) { void LocalAudioSourceResume(bool expected_confirmation = true, bool expected_cancel = false) { ASSERT_NE(nullptr, mock_le_audio_source_hal_client_); if (expected_confirmation) { EXPECT_CALL(*mock_le_audio_source_hal_client_, ConfirmStreamingRequest()) .Times(1); } if (expected_cancel) { EXPECT_CALL(*mock_le_audio_source_hal_client_, CancelStreamingRequest()) .Times(1); } do_in_main_thread(FROM_HERE, base::BindOnce( [](LeAudioSourceAudioHalClient::Callbacks* cb) { Loading Loading @@ -2512,6 +2524,7 @@ class UnicastTestNoInit : public Test { uint16_t global_conn_id = 1; le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks_; std::map<int, LeAudioDeviceGroup*> streaming_groups; bool block_streaming_state_callback = false; bluetooth::hci::IsoManager* iso_manager_; MockIsoManager* mock_iso_manager_; Loading Loading @@ -3713,6 +3726,68 @@ TEST_F(UnicastTest, GroupingAddRemove) { ASSERT_NE(std::find(devs.begin(), devs.end(), test_address1), devs.end()); } TEST_F(UnicastTest, DoubleResumeFromAF) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; 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); constexpr int gmcs_ccid = 1; constexpr int gtbs_ccid = 2; // Audio sessions are started only when device gets active EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _)).Times(1); EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _)).Times(1); LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); LeAudioClient::Get()->GroupSetActive(group_id); SyncOnMainLoop(); types::BidirectionalPair<std::vector<uint8_t>> ccids = {.sink = {gmcs_ccid}, .source = {}}; EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); block_streaming_state_callback = true; UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC); LocalAudioSourceResume(false); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_); LocalAudioSourceResume(false, true); EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(1); do_in_main_thread( FROM_HERE, base::BindOnce( [](int group_id, le_audio::LeAudioGroupStateMachine::Callbacks* state_machine_callbacks) { state_machine_callbacks->StatusReportCb( group_id, GroupStreamStatus::STREAMING); }, group_id, base::Unretained(state_machine_callbacks_))); SyncOnMainLoop(); Mock::VerifyAndClearExpectations(&mock_state_machine_); } TEST_F(UnicastTest, RemoveNodeWhileStreaming) { const RawAddress test_address0 = GetTestAddress(0); int group_id = bluetooth::groups::kGroupUnknown; Loading