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

Commit 226eabbb authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Automerger Merge Worker
Browse files

Merge "leaudio: Update metadata after stream reconfiguration" into main am: 3b39a01a

parents 3da1d0f5 3b39a01a
Loading
Loading
Loading
Loading
+29 −15
Original line number Diff line number Diff line
@@ -262,12 +262,16 @@ void LeAudioDeviceGroup::SetCigState(le_audio::types::CigState state) {
  cig_state_ = state;
}

bool LeAudioDeviceGroup::Activate(LeAudioContextType context_type) {
bool LeAudioDeviceGroup::Activate(
    LeAudioContextType context_type,
    const BidirectionalPair<AudioContexts>& metadata_context_types,
    BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
  bool is_activate = false;
  for (auto leAudioDevice : leAudioDevices_) {
    if (leAudioDevice.expired()) continue;

    bool activated = leAudioDevice.lock()->ActivateConfiguredAses(context_type);
    bool activated = leAudioDevice.lock()->ActivateConfiguredAses(
        context_type, metadata_context_types, ccid_lists);
    LOG_INFO("Device %s is %s",
             ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice.lock().get()->address_),
             activated ? "activated" : " not activated");
@@ -1656,18 +1660,7 @@ bool LeAudioDevice::ConfigureAses(
      ase->retrans_nb = ent.qos.retransmission_number;
      ase->max_transport_latency = ent.qos.max_transport_latency;

      /* Filter multidirectional audio context for each ase direction */
      auto directional_audio_context =
          metadata_context_types.get(ase->direction) &
          GetAvailableContexts(ase->direction);
      if (directional_audio_context.any()) {
        ase->metadata = GetMetadata(directional_audio_context,
                                    ccid_lists.get(ase->direction));
      } else {
        ase->metadata =
            GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED),
                        std::vector<uint8_t>());
      }
      SetMetadataToAse(ase, metadata_context_types, ccid_lists);
    }

    LOG_DEBUG(
@@ -2921,7 +2914,26 @@ void LeAudioDevice::SetAvailableContexts(
  avail_contexts_.source = contexts.source;
}

bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {
void LeAudioDevice::SetMetadataToAse(
    struct types::ase* ase,
    const BidirectionalPair<AudioContexts>& metadata_context_types,
    BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
  /* Filter multidirectional audio context for each ase direction */
  auto directional_audio_context = metadata_context_types.get(ase->direction) &
                                   GetAvailableContexts(ase->direction);
  if (directional_audio_context.any()) {
    ase->metadata =
        GetMetadata(directional_audio_context, ccid_lists.get(ase->direction));
  } else {
    ase->metadata = GetMetadata(AudioContexts(LeAudioContextType::UNSPECIFIED),
                                std::vector<uint8_t>());
  }
}

bool LeAudioDevice::ActivateConfiguredAses(
    LeAudioContextType context_type,
    const BidirectionalPair<AudioContexts>& metadata_context_types,
    BidirectionalPair<std::vector<uint8_t>> ccid_lists) {
  if (conn_id_ == GATT_INVALID_CONN_ID) {
    LOG_WARN(" Device %s is not connected ",
             ADDRESS_TO_LOGGABLE_CSTR(address_));
@@ -2939,6 +2951,8 @@ bool LeAudioDevice::ActivateConfiguredAses(LeAudioContextType context_type) {
          conn_id_, ase.id, ase.cis_id, ase.cis_conn_hdl);
      ase.active = true;
      ret = true;
      /* update metadata */
      SetMetadataToAse(&ase, metadata_context_types, ccid_lists);
    }
  }

+14 −2
Original line number Diff line number Diff line
@@ -216,7 +216,16 @@ class LeAudioDevice {
      types::BidirectionalPair<types::AudioContexts> cont_val);

  void DeactivateAllAses(void);
  bool ActivateConfiguredAses(types::LeAudioContextType context_type);
  bool ActivateConfiguredAses(
      types::LeAudioContextType context_type,
      const types::BidirectionalPair<types::AudioContexts>&
          metadata_context_types,
      types::BidirectionalPair<std::vector<uint8_t>> ccid_lists);
  void SetMetadataToAse(
      struct types::ase* ase,
      const types::BidirectionalPair<types::AudioContexts>&
          metadata_context_types,
      types::BidirectionalPair<std::vector<uint8_t>> ccid_lists);

  void PrintDebugState(void);
  void DumpPacsDebugState(std::stringstream& stream);
@@ -329,7 +338,10 @@ class LeAudioDeviceGroup {
  int Size(void) const;
  int NumOfConnected(types::LeAudioContextType context_type =
                         types::LeAudioContextType::RFU) const;
  bool Activate(types::LeAudioContextType context_type);
  bool Activate(types::LeAudioContextType context_type,
                const types::BidirectionalPair<types::AudioContexts>&
                    metadata_context_types,
                types::BidirectionalPair<std::vector<uint8_t>> ccid_lists);
  void Deactivate(void);
  types::CigState GetCigState(void) const;
  void SetCigState(le_audio::types::CigState state);
+2 −1
Original line number Diff line number Diff line
@@ -1590,7 +1590,8 @@ TEST_F(LeAudioAseConfigurationTest, test_reactivation_conversational) {
   * the same CIS ID can be used. This would lead to only activating group
   * without reconfiguring CIG.
   */
  group_->Activate(LeAudioContextType::CONVERSATIONAL);
  group_->Activate(LeAudioContextType::CONVERSATIONAL, audio_contexts,
                   ccid_lists);

  TestActiveAses();

+98 −0
Original line number Diff line number Diff line
@@ -5277,6 +5277,104 @@ TEST_F(UnicastTest, TwoEarbudsStreamingContextSwitchReconfigure) {
  Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_);
}

TEST_F(UnicastTest, TwoReconfigureAndVerifyEnableContextType) {
  uint8_t group_size = 2;
  int group_id = 2;

  /* Scenario
   * 1. Earbuds streaming MEDIA
   * 2. Reconfigure to VOIP
   * 3. Check if Metadata in Enable command are set to CONVERSATIONAL
   */

  // Report working CSIS
  ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
      .WillByDefault(Return(true));

  // First earbud
  const RawAddress test_address0 = GetTestAddress(0);
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address0, true))
      .Times(1);
  ConnectCsisDevice(test_address0, 1 /*conn_id*/,
                    codec_spec_conf::kLeAudioLocationFrontLeft,
                    codec_spec_conf::kLeAudioLocationFrontLeft, group_size,
                    group_id, 1 /* rank*/);

  // Second earbud
  const RawAddress test_address1 = GetTestAddress(1);
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true))
      .Times(1);
  ConnectCsisDevice(test_address1, 2 /*conn_id*/,
                    codec_spec_conf::kLeAudioLocationFrontRight,
                    codec_spec_conf::kLeAudioLocationFrontRight, group_size,
                    group_id, 2 /* rank*/, true /*connect_through_csis*/);

  constexpr int gmcs_ccid = 1;
  constexpr int gtbs_ccid = 2;

  ON_CALL(mock_csis_client_module_, GetDesiredSize(group_id))
      .WillByDefault(Invoke([&](int group_id) { return 2; }));

  // Start streaming MEDIA
  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();

  // Update metadata on local audio sink
  UpdateLocalSinkMetadata(AUDIO_SOURCE_MIC);

  types::BidirectionalPair<std::vector<uint8_t>> ccids = {.sink = {gmcs_ccid},
                                                          .source = {}};
  EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1);
  StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC, group_id);

  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_state_machine_);
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
  Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_);

  // Verify Data transfer on two peer sinks
  uint8_t cis_count_out = 2;
  uint8_t cis_count_in = 0;
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);

  // Conversational is a bidirectional scenario so expect GTBS CCID
  // in the metadata for both directions. Can be called twice when one
  // direction resume after the other and metadata is updated.
  ccids = {.sink = {gtbs_ccid}, .source = {gtbs_ccid}};
  types::BidirectionalPair<types::AudioContexts> conversiational_contexts = {
      .sink = types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL),
      .source =
          types::AudioContexts(types::LeAudioContextType::CONVERSATIONAL)};

  EXPECT_CALL(
      mock_state_machine_,
      ConfigureStream(_, types::LeAudioContextType::CONVERSATIONAL, _, _))
      .Times(AtLeast(1));

  // Update metadata and resume
  UpdateLocalSourceMetadata(AUDIO_USAGE_VOICE_COMMUNICATION,
                            AUDIO_CONTENT_TYPE_SPEECH, true);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_state_machine_);
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
  Mock::VerifyAndClearExpectations(&mock_le_audio_source_hal_client_);

  EXPECT_CALL(mock_state_machine_,
              StartStream(_, types::LeAudioContextType::CONVERSATIONAL,
                          conversiational_contexts, ccids))
      .Times(AtLeast(1));

  LocalAudioSourceResume(true);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_state_machine_);
}

TEST_F(UnicastTest, TwoEarbuds2ndLateConnect) {
  uint8_t group_size = 2;
  int group_id = 2;
+3 −1
Original line number Diff line number Diff line
@@ -176,8 +176,10 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
    switch (group->GetState()) {
      case AseState::BTA_LE_AUDIO_ASE_STATE_CODEC_CONFIGURED:
        if (group->IsConfiguredForContext(context_type)) {
          if (group->Activate(context_type)) {
          if (group->Activate(context_type, metadata_context_types,
                              ccid_lists)) {
            SetTargetState(group, AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);

            if (CigCreate(group)) {
              return true;
            }
Loading