Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a637ca23 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Do not update metadata if not needed

In case remote device removes some available context types, code should
do double check on metadata which are about to send in update. Otherwise
we mind end up sending same metadata which is reduntant.

Bug: 296830689
Test: atest bluetooth_le_audio_test
Tag: #feature

Change-Id: I858edeaae54f477ce23aee917caf6b6449f3a0bf
parent a3eafb44
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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_) {
+11 −2
Original line number Diff line number Diff line
@@ -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;
+89 −2
Original line number Diff line number Diff line
@@ -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)