diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc index b18bfa3ef38aa0f3dc165d4268afd5217b41ed08..af0c883ff7834b7ed1de357f93747c87901cfbde 100644 --- a/system/bta/le_audio/client.cc +++ b/system/bta/le_audio/client.cc @@ -3657,9 +3657,9 @@ class LeAudioClientImpl : public LeAudioClient { bluetooth::common::ToString(configuration_context_type_).c_str(), configuration_context_type_); dprintf(fd, " local source metadata context type mask: %s\n", - local_metadata_context_types_.sink.to_string().c_str()); - dprintf(fd, " local sink metadata context type mask: %s\n", local_metadata_context_types_.source.to_string().c_str()); + dprintf(fd, " local sink metadata context type mask: %s\n", + local_metadata_context_types_.sink.to_string().c_str()); dprintf(fd, " TBS state: %s\n", in_call_ ? " In call" : "No calls"); dprintf(fd, " Start time: "); for (auto t : stream_start_history_queue_) { diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc index 3d0aaaa600a798dbfe07bc9cc5e49f1653ec929d..03bbe237a398cbb49d86959ff301ff2bd847bc9b 100644 --- a/system/bta/le_audio/state_machine.cc +++ b/system/bta/le_audio/state_machine.cc @@ -2444,15 +2444,24 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine { auto directional_audio_context = context_types.get(ase->direction) & leAudioDevice->GetAvailableContexts(ase->direction); + + std::vector<uint8_t> new_metadata; if (directional_audio_context.any()) { - ase->metadata = leAudioDevice->GetMetadata( + new_metadata = leAudioDevice->GetMetadata( directional_audio_context, ccid_lists.get(ase->direction)); } else { - ase->metadata = leAudioDevice->GetMetadata( + new_metadata = leAudioDevice->GetMetadata( AudioContexts(LeAudioContextType::UNSPECIFIED), std::vector<uint8_t>()); } + /* Do not update if metadata did not changed. */ + if (ase->metadata == new_metadata) { + continue; + } + + ase->metadata = new_metadata; + struct le_audio::client_parser::ascs::ctp_update_metadata conf; conf.ase_id = ase->id; diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc index 6be9171c48056783533c3aea0e694d0b4e5c6a11..a20ab63625a1a4c84a7256335b590be1d13189f8 100644 --- a/system/bta/le_audio/state_machine_test.cc +++ b/system/bta/le_audio/state_machine_test.cc @@ -2097,9 +2097,12 @@ TEST_F(StateMachineTest, testUpdateMetadataMultiple) { const auto leaudio_group_id = 4; const auto num_devices = 2; + auto supported_contexts = + types::AudioContexts(kContextTypeMedia | kContextTypeSoundEffects); + // Prepare multiple fake connected devices in a group - auto* group = - PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, num_devices); + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, + num_devices, supported_contexts); ASSERT_EQ(group->Size(), num_devices); PrepareConfigureCodecHandler(group); @@ -2173,6 +2176,90 @@ TEST_F(StateMachineTest, testUpdateMetadataMultiple) { ASSERT_EQ(0, get_func_call_count("alarm_cancel")); } +TEST_F(StateMachineTest, testUpdateMetadataMultiple_NoUpdatesOnKeyTouch) { + const auto context_type = kContextTypeMedia; + const auto leaudio_group_id = 4; + const auto num_devices = 2; + + /* Only Media is supported and available, */ + auto supported_contexts = types::AudioContexts(kContextTypeMedia); + + // Prepare multiple fake connected devices in a group + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type, + num_devices, supported_contexts); + 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, context_type, + {.sink = types::AudioContexts(context_type), + .source = 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); + + ASSERT_EQ(1, get_func_call_count("alarm_cancel")); + reset_mock_function_count_map(); + + // 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(0); + 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, context_type, + {.sink = metadata_context_type, .source = metadata_context_type})); + + /* This is just update metadata - watchdog is not used */ + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); +} + TEST_F(StateMachineTest, testDisableSingle) { /* Device is banded headphones with 2x snk + 0x src ase * (2xunidirectional CIS)