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

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

leaudio: Fix handling active context type

Remote side provides us list of available context types.
For each of them, we search for best available configuration, however it
might happen that we might not find a configuration.
With this patch, when metadata changes to the context type which we
don't know configuration for, we will not proceed with it.

Bug: 232898053
Test: atest bluetooth_le_audio_test bluetooth_le_audio_client_test
Change-Id: I551bc46e7b1ac2c75be8ca90b31648f19c7db33b
parent ad5dcde1
Loading
Loading
Loading
Loading
+91 −41
Original line number Diff line number Diff line
@@ -81,6 +81,12 @@ using le_audio::client_parser::ascs::kCtpResponseInvalidAseCisMapping;
using le_audio::client_parser::ascs::kCtpResponseNoReason;

/* Enums */
enum class AudioReconfigurationResult {
  RECONFIGURATION_NEEDED = 0x00,
  RECONFIGURATION_NOT_NEEDED,
  RECONFIGURATION_NOT_POSSIBLE
};

enum class AudioState {
  IDLE = 0x00,
  READY_TO_START,
@@ -89,6 +95,25 @@ enum class AudioState {
  RELEASING,
};

std::ostream& operator<<(std::ostream& os,
                         const AudioReconfigurationResult& state) {
  switch (state) {
    case AudioReconfigurationResult::RECONFIGURATION_NEEDED:
      os << "RECONFIGURATION_NEEDED";
      break;
    case AudioReconfigurationResult::RECONFIGURATION_NOT_NEEDED:
      os << "RECONFIGURATION_NOT_NEEDED";
      break;
    case AudioReconfigurationResult::RECONFIGURATION_NOT_POSSIBLE:
      os << "RECONFIGRATION_NOT_POSSIBLE";
      break;
    default:
      os << "UNKNOWN";
      break;
  }
  return os;
}

std::ostream& operator<<(std::ostream& os, const AudioState& audio_state) {
  switch (audio_state) {
    case AudioState::IDLE:
@@ -2680,14 +2705,17 @@ class LeAudioClientImpl : public LeAudioClient {
    std::move(cleanupCb).Run();
  }

  bool UpdateConfigAndCheckIfReconfigurationIsNeeded(
  AudioReconfigurationResult UpdateConfigAndCheckIfReconfigurationIsNeeded(
      int group_id, LeAudioContextType context_type) {
    bool reconfiguration_needed = false;
    bool sink_cfg_available = true;
    bool source_cfg_available = true;

    auto group = aseGroups_.FindById(group_id);
    if (!group) {
      LOG(ERROR) << __func__
                 << ", Invalid group: " << static_cast<int>(group_id);
      return reconfiguration_needed;
      return AudioReconfigurationResult::RECONFIGURATION_NOT_NEEDED;
    }

    std::optional<LeAudioCodecConfiguration> source_configuration =
@@ -2707,11 +2735,7 @@ class LeAudioClientImpl : public LeAudioClient {
        current_source_codec_config = {0, 0, 0, 0};
        reconfiguration_needed = true;
      }

      LOG(INFO) << __func__
                << ", group does not supports source direction for"
                   " context: "
                << static_cast<int>(context_type);
      source_cfg_available = false;
    }

    if (sink_configuration) {
@@ -2725,20 +2749,28 @@ class LeAudioClientImpl : public LeAudioClient {
        reconfiguration_needed = true;
      }

      LOG(INFO) << __func__
                << ", group does not supports sink direction for"
                   " context: "
                << static_cast<int>(context_type);
      sink_cfg_available = false;
    }

    if (reconfiguration_needed) {
      LOG(INFO) << __func__
                << " Session reconfiguration needed group: " << group->group_id_
                << " for context type: " << static_cast<int>(context_type);
    LOG_DEBUG(
        " Context: %s Reconfigufation_needed = %d, sink_cfg_available = %d, "
        "source_cfg_available = %d",
        ToString(context_type).c_str(), reconfiguration_needed,
        sink_cfg_available, source_cfg_available);

    if (!reconfiguration_needed) {
      return AudioReconfigurationResult::RECONFIGURATION_NOT_NEEDED;
    }

    if (!sink_cfg_available && !source_cfg_available) {
      return AudioReconfigurationResult::RECONFIGURATION_NOT_POSSIBLE;
    }

    LOG_INFO(" Session reconfiguration needed group: %d for context type: %s",
             group->group_id_, ToString(context_type).c_str());

    current_context_type_ = context_type;
    return reconfiguration_needed;
    return AudioReconfigurationResult::RECONFIGURATION_NEEDED;
  }

  bool OnAudioResume(LeAudioDeviceGroup* group) {
@@ -3063,7 +3095,6 @@ class LeAudioClientImpl : public LeAudioClient {
  }

  LeAudioContextType AudioContentToLeAudioContext(
      LeAudioContextType current_context_type,
      audio_content_type_t content_type, audio_usage_t usage) {
    /* Check audio attribute usage of stream */
    switch (usage) {
@@ -3114,10 +3145,19 @@ class LeAudioClientImpl : public LeAudioClient {

  bool StopStreamIfNeeded(LeAudioDeviceGroup* group,
                          LeAudioContextType new_context_type) {
    DLOG(INFO) << __func__ << " context type " << int(new_context_type);
    if (!UpdateConfigAndCheckIfReconfigurationIsNeeded(group->group_id_,
                                                       new_context_type)) {
      DLOG(INFO) << __func__ << " reconfiguration not needed";
    auto reconfig_result = UpdateConfigAndCheckIfReconfigurationIsNeeded(
        group->group_id_, new_context_type);

    LOG_INFO("group_id %d, context type %s, reconfig_needed %s",
             group->group_id_, ToString(new_context_type).c_str(),
             ToString(reconfig_result).c_str());
    if (reconfig_result ==
        AudioReconfigurationResult::RECONFIGURATION_NOT_NEEDED) {
      return false;
    }

    if (reconfig_result ==
        AudioReconfigurationResult::RECONFIGURATION_NOT_POSSIBLE) {
      return false;
    }

@@ -3138,8 +3178,24 @@ class LeAudioClientImpl : public LeAudioClient {
    auto tracks = source_metadata.tracks;
    auto track_count = source_metadata.track_count;

    if (active_group_id_ == bluetooth::groups::kGroupUnknown) {
      LOG(WARNING) << ", cannot start streaming if no active group set";
      return;
    }

    auto group = aseGroups_.FindById(active_group_id_);
    if (!group) {
      LOG(ERROR) << __func__
                 << ", Invalid group: " << static_cast<int>(active_group_id_);
      return;
    }
    bool is_group_streaming =
        (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);

    std::vector<LeAudioContextType> contexts;

    auto supported_context_type = group->GetActiveContexts();

    while (track_count) {
      if (tracks->content_type == 0 && tracks->usage == 0) {
        --track_count;
@@ -3150,37 +3206,31 @@ class LeAudioClientImpl : public LeAudioClient {
      LOG_INFO("%s: usage=%d, content_type=%d, gain=%f", __func__,
               tracks->usage, tracks->content_type, tracks->gain);

      auto new_context = AudioContentToLeAudioContext(
          current_context_type_, tracks->content_type, tracks->usage);
      auto new_context =
          AudioContentToLeAudioContext(tracks->content_type, tracks->usage);

      /* Check only supported context types.*/
      if (static_cast<int>(new_context) & supported_context_type.to_ulong()) {
        contexts.push_back(new_context);
      } else {
        LOG_WARN(" Context type %s not supported by remote device",
                 ToString(new_context).c_str());
      }

      --track_count;
      ++tracks;
    }

    if (contexts.empty()) {
      DLOG(INFO) << __func__ << " invalid metadata update";
      LOG_WARN(" invalid/unknown metadata update");
      return;
    }

    auto new_context = ChooseContextType(contexts);
    DLOG(INFO) << __func__
               << " new_context_type: " << static_cast<int>(new_context);

    auto group = aseGroups_.FindById(active_group_id_);
    if (!group) {
      LOG(ERROR) << __func__
                 << ", Invalid group: " << static_cast<int>(active_group_id_);
      return;
    }
    LOG_DEBUG("new_context_type: %s", ToString(new_context).c_str());

    if (new_context == current_context_type_) {
      LOG(INFO) << __func__ << " Context did not changed.";
      return;
    }

    if (active_group_id_ == bluetooth::groups::kGroupUnknown) {
      LOG(WARNING) << ", cannot start streaming if no active group set";
      LOG_INFO("Context did not changed.");
      return;
    }

@@ -3189,7 +3239,7 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
    if (is_group_streaming) {
      /* Configuration is the same for new context, just will do update
       * metadata of stream
       */
+42 −1
Original line number Diff line number Diff line
@@ -808,7 +808,6 @@ class UnicastTestNoInit : public Test {

  void SetUp() override {
    init_message_loop_thread();

    ON_CALL(controller_interface_, SupportsBleConnectedIsochronousStreamCentral)
        .WillByDefault(Return(true));
    ON_CALL(controller_interface_,
@@ -3161,5 +3160,47 @@ TEST_F(UnicastTest, MicrophoneAttachToCurrentMediaScenario) {
  LeAudioClient::Get()->GroupSetActive(bluetooth::groups::kGroupUnknown);
  Mock::VerifyAndClearExpectations(mock_unicast_audio_source_);
}

TEST_F(UnicastTest, StartNotSupportedContextType) {
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;

  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
      codec_spec_conf::kLeAudioLocationStereo, 0x0004, false /*add_csis*/,
      true /*add_cas*/, true /*add_pacs*/, true /*add_ascs*/, 1 /*set_size*/,
      0 /*rank*/);
  EXPECT_CALL(mock_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
  EXPECT_CALL(mock_client_callbacks_,
              OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED))
      .WillOnce(DoAll(SaveArg<1>(&group_id)));

  ConnectLeAudio(test_address0);
  ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);

  // Start streaming
  uint8_t cis_count_out = 1;
  uint8_t cis_count_in = 0;

  // Audio sessions are started only when device gets active
  EXPECT_CALL(*mock_unicast_audio_source_, Start(_, _)).Times(1);
  EXPECT_CALL(*mock_audio_sink_, Start(_, _)).Times(1);
  LeAudioClient::Get()->GroupSetActive(group_id);

  StartStreaming(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
                 AUDIO_CONTENT_TYPE_UNKNOWN, group_id);

  Mock::VerifyAndClearExpectations(&mock_client_callbacks_);
  Mock::VerifyAndClearExpectations(mock_unicast_audio_source_);
  SyncOnMainLoop();

  // Verify Data transfer on one audio source cis
  TestAudioDataTransfer(group_id, cis_count_out, cis_count_in, 1920);

  EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0);
  UpdateMetadata(AUDIO_USAGE_GAME, AUDIO_CONTENT_TYPE_UNKNOWN);
}
}  // namespace
}  // namespace le_audio
+44 −1
Original line number Diff line number Diff line
@@ -469,6 +469,49 @@ std::ostream& operator<<(std::ostream& os,
     << ", AudioChanLoc=" << loghex(*config.audio_channel_allocation) << ")";
  return os;
}
std::ostream& operator<<(std::ostream& os, const LeAudioContextType& context) {
  switch (context) {
    case LeAudioContextType::UNINITIALIZED:
      os << "UNINITIALIZED";
      break;
    case LeAudioContextType::UNSPECIFIED:
      os << "UNSPECIFIED";
      break;
    case LeAudioContextType::CONVERSATIONAL:
      os << "CONVERSATIONAL";
      break;
    case LeAudioContextType::MEDIA:
      os << "MEDIA";
      break;
    case LeAudioContextType::GAME:
      os << "GAME";
      break;
    case LeAudioContextType::INSTRUCTIONAL:
      os << "INSTRUCTIONAL";
      break;
    case LeAudioContextType::VOICEASSISTANTS:
      os << "VOICEASSISTANTS";
      break;
    case LeAudioContextType::LIVE:
      os << "LIVE";
      break;
    case LeAudioContextType::SOUNDEFFECTS:
      os << "SOUNDEFFECTS";
      break;
    case LeAudioContextType::NOTIFICATIONS:
      os << "NOTIFICATIONS";
      break;
    case LeAudioContextType::RINGTONE:
      os << "RINGTONE";
      break;
    case LeAudioContextType::EMERGENCYALARM:
      os << "EMERGENCYALARM";
      break;
    default:
      os << "UNKNOWN";
      break;
  }
  return os;
}
}  // namespace types

}  // namespace le_audio
+1 −0
Original line number Diff line number Diff line
@@ -572,6 +572,7 @@ using AudioContexts = std::bitset<16>;
std::ostream& operator<<(std::ostream& os, const AseState& state);
std::ostream& operator<<(std::ostream& os, const CigState& state);
std::ostream& operator<<(std::ostream& os, const LeAudioLc3Config& config);
std::ostream& operator<<(std::ostream& os, const LeAudioContextType& context);
}  // namespace types

namespace set_configurations {
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "btm_api_mock.h"
#include "client_parser.h"
#include "fake_osi.h"
#include "gd/common/init_flags.h"
#include "le_audio_set_configuration_provider.h"
#include "mock_codec_manager.h"
#include "mock_controller.h"