diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc index 80417eb93c316dc7cd8fede0579cbf4e02f70b97..c7c16e120b179fb3b26bc7cfb5b8404d40d11dc2 100644 --- a/system/bta/le_audio/state_machine.cc +++ b/system/bta/le_audio/state_machine.cc @@ -214,7 +214,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { case AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING: { /* This case just updates the metadata for the stream, in case - * stream configuration is satisfied + * stream configuration is satisfied. We can do that already for + * all the devices in a group, without any state transitions. */ if (!group->IsMetadataChanged(metadata_context_type, ccid_list)) return true; @@ -225,8 +226,11 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { return false; } - PrepareAndSendUpdateMetadata(group, leAudioDevice, - metadata_context_type, ccid_list); + while (leAudioDevice) { + PrepareAndSendUpdateMetadata(group, leAudioDevice, + metadata_context_type, ccid_list); + leAudioDevice = group->GetNextActiveDevice(leAudioDevice); + } break; } diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc index da848102846e41add8cae4746c69a06971818482..d9339e2c7466311abc7c2c533f07218d4aced05c 100644 --- a/system/bta/le_audio/state_machine_test.cc +++ b/system/bta/le_audio/state_machine_test.cc @@ -77,6 +77,8 @@ constexpr LeAudioContextType kContextTypeConversational = static_cast<LeAudioContextType>(0x0002); constexpr LeAudioContextType kContextTypeMedia = static_cast<LeAudioContextType>(0x0004); +constexpr LeAudioContextType kContextTypeSoundEffects = + static_cast<LeAudioContextType>(0x0080); constexpr LeAudioContextType kContextTypeRingtone = static_cast<LeAudioContextType>(0x0200); @@ -1622,6 +1624,80 @@ TEST_F(StateMachineTest, testStreamMultiple) { types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); } +TEST_F(StateMachineTest, testUpdateMetadataMultiple) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 4; + const auto num_devices = 2; + + // 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); + + EXPECT_CALL(*mock_iso_manager_, CreateCig(_, _)).Times(1); + EXPECT_CALL(*mock_iso_manager_, EstablishCis(_)).Times(AtLeast(1)); + EXPECT_CALL(*mock_iso_manager_, SetupIsoDataPath(_, _)).Times(2); + 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); + + auto* leAudioDevice = group->GetFirstDevice(); + auto expected_devices_written = 0; + while (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); + + // Validate 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, static_cast<LeAudioContextType>(context_type), + types::AudioContexts(context_type))); + + testing::Mock::VerifyAndClearExpectations(&gatt_queue); + + // Check if group has transitioned to a proper state + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING); + + // Make sure all devices get the metadata update + leAudioDevice = group->GetFirstDevice(); + expected_devices_written = 0; + while (leAudioDevice) { + EXPECT_CALL(gatt_queue, + WriteCharacteristic(leAudioDevice->conn_id_, + leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(1); + expected_devices_written++; + leAudioDevice = group->GetNextDevice(leAudioDevice); + } + ASSERT_EQ(expected_devices_written, num_devices); + + const auto metadata_context_type = + kContextTypeMedia | kContextTypeSoundEffects; + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, static_cast<LeAudioContextType>(context_type), + metadata_context_type)); +} + TEST_F(StateMachineTest, testDisableSingle) { const auto context_type = kContextTypeRingtone; const int leaudio_group_id = 4;