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

Commit 74096f0c authored by shihchienc's avatar shihchienc Committed by Patrick Chang
Browse files

leaudio: Implement preferred config update logic

This patch implements the preferred config update logic. When setting
preferred config, we put it into requirements and find the first match
with ase config. After that with this preferred ase config, we could use
that to match with remote pac.

Multi Codec would also benifit from pushing preferred codec into
requirements as in the aidl layer they will try to return stack with the
one matched with preferred config (requirements).

Bug: 259191520
Bug: 353909820
Bug: 351229684
Flag: com.android.bluetooth.flags.leaudio_set_codec_config_preference
Test: atest bluetooth_le_audio_test bluetooth_le_audio_client_test
Change-Id: I8da2938d8e40fe38d3d83f6d09326f4f8fcb5ff4
parent aa05f024
Loading
Loading
Loading
Loading
+83 −18
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "bta_csis_api.h"
#include "btif/include/btif_profile_storage.h"
#include "btm_iso_api.h"
#include "common/strings.h"
#include "hci/controller_interface.h"
#include "internal_include/bt_trace.h"
#include "le_audio/codec_manager.h"
@@ -868,6 +869,20 @@ LeAudioDeviceGroup::GetAudioSetConfigurationRequirements(types::LeAudioContextTy
      CodecManager::UnicastConfigurationRequirements::DeviceDirectionRequirements config_req;
      config_req.params.Add(codec_spec_conf::kLeAudioLtvTypeAudioChannelAllocation,
                            (uint32_t)locations);
      if (preferred_config_.get(direction) &&
          preferred_config_.get(direction)->codec_priority != -1) {
        config_req.params.Add(
                codec_spec_conf::kLeAudioLtvTypeSamplingFreq,
                UINT8_TO_VEC_UINT8(codec_spec_conf::SingleSamplingFreqCapability2Config(
                        preferred_config_.get(direction)->sample_rate)));
        config_req.params.Add(
                codec_spec_conf::kLeAudioLtvTypeFrameDuration,
                UINT8_TO_VEC_UINT8(codec_spec_conf::SingleFrameDurationCapability2Config(
                        preferred_config_.get(direction)->frame_duration)));
        config_req.params.Add(
                codec_spec_conf::kLeAudioLtvTypeOctetsPerCodecFrame,
                UINT16_TO_VEC_UINT8(preferred_config_.get(direction)->octets_per_frame));
      }
      config_req.target_latency = utils::GetTargetLatencyForAudioContext(ctx_type);
      log::warn("Device {} pushes requirement, location: {}, direction: {}", device->address_,
                (int)locations, (int)direction);
@@ -902,38 +917,71 @@ LeAudioDeviceGroup::GetAudioSetConfigurationRequirements(types::LeAudioContextTy
  return new_req;
}

bool LeAudioDeviceGroup::UpdateAudioSetConfigurationCache(LeAudioContextType ctx_type) const {
bool LeAudioDeviceGroup::UpdateAudioSetConfigurationCache(LeAudioContextType ctx_type,
                                                          bool use_preference) const {
  auto requirements = GetAudioSetConfigurationRequirements(ctx_type);
  auto new_conf = CodecManager::GetInstance()->GetCodecConfig(
          requirements, std::bind(&LeAudioDeviceGroup::FindFirstSupportedConfiguration, this,
                                  std::placeholders::_1, std::placeholders::_2));
                                  std::placeholders::_1, std::placeholders::_2, use_preference));
  auto update_config = true;

  if (context_to_configuration_cache_map.count(ctx_type) != 0) {
    auto& [is_valid, existing_conf] = context_to_configuration_cache_map.at(ctx_type);
  auto& cached_map = use_preference ? context_to_preferred_configuration_cache_map_
                                    : context_to_configuration_cache_map_;

  if (cached_map.count(ctx_type) != 0) {
    auto& [is_valid, existing_conf] = cached_map.at(ctx_type);
    update_config = (new_conf.get() != existing_conf.get());
    /* Just mark it as still valid */
    if (!update_config && !is_valid) {
      context_to_configuration_cache_map.at(ctx_type).first = true;
      cached_map.at(ctx_type).first = true;
      return false;
    }
  }

  if (update_config) {
    log::info("config: {} -> {}", ToHexString(ctx_type),
              (new_conf ? new_conf->name.c_str() : "(none)"));
    context_to_configuration_cache_map.erase(ctx_type);
    log::info("config: {} -> {}, use_preference: {}", ToHexString(ctx_type),
              (new_conf ? new_conf->name.c_str() : "(none)"), use_preference);
    cached_map.erase(ctx_type);
    if (new_conf) {
      context_to_configuration_cache_map.insert(
              std::make_pair(ctx_type, std::make_pair(true, std::move(new_conf))));
      cached_map.insert(std::make_pair(ctx_type, std::make_pair(true, std::move(new_conf))));
    }
  }

  return update_config;
}

bool LeAudioDeviceGroup::SetPreferredAudioSetConfiguration(
        const bluetooth::le_audio::btle_audio_codec_config_t& input_codec_config,
        const bluetooth::le_audio::btle_audio_codec_config_t& output_codec_config) const {
  if (input_codec_config.codec_priority == -1 || output_codec_config.codec_priority == -1) {
    log::info("Clear codec config");
    ResetPreferredAudioSetConfiguration();
    return true;
  }

  preferred_config_.sink = std::make_unique<btle_audio_codec_config_t>(output_codec_config);
  preferred_config_.source = std::make_unique<btle_audio_codec_config_t>(input_codec_config);

  bool is_updated = false;

  for (LeAudioContextType ctx_type : types::kLeAudioContextAllTypesArray) {
    is_updated |= UpdateAudioSetConfigurationCache(ctx_type, true);
  }

  return is_updated;
}

void LeAudioDeviceGroup::ResetPreferredAudioSetConfiguration(void) const {
  log::info("Reset preferred configuration cached for all cotexts.");
  context_to_preferred_configuration_cache_map_.clear();
  preferred_config_.sink = nullptr;
  preferred_config_.source = nullptr;
}

void LeAudioDeviceGroup::InvalidateCachedConfigurations(void) {
  log::info("Group id: {}", group_id_);
  context_to_configuration_cache_map.clear();
  context_to_configuration_cache_map_.clear();
  ResetPreferredAudioSetConfiguration();
}

types::BidirectionalPair<AudioContexts> LeAudioDeviceGroup::GetLatestAvailableContexts() const {
@@ -1397,7 +1445,8 @@ bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,
 */
bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported(
        const CodecManager::UnicastConfigurationRequirements& requirements,
        const set_configurations::AudioSetConfiguration* audio_set_conf) const {
        const set_configurations::AudioSetConfiguration* audio_set_conf,
        bool use_preference) const {
  /* TODO For now: set ase if matching with first pac.
   * 1) We assume as well that devices will match requirements in order
   *    e.g. 1 Device - 1 Requirement, 2 Device - 2 Requirement etc.
@@ -1432,6 +1481,22 @@ bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported(
      }
    }

    // Match with requirement first if we have
    if (use_preference) {
      auto& direction_req = (direction == types::kLeAudioDirectionSink)
                                    ? requirements.sink_requirements
                                    : requirements.source_requirements;
      if (!direction_req.has_value() || !preferred_config_.get(direction)) {
        return false;
      }
      if (!utils::IsAseConfigMatchedWithPreferredRequirements(
                  ase_confs, direction_req.value(),
                  codec_spec_conf::SingleChannelCountCapability2Config(
                          preferred_config_.get(direction)->channel_count))) {
        return false;
      }
    }

    // In some tests we expect the configuration to be there even when the
    // contexts are not supported. Then we might want to configure the device
    // but use UNSPECIFIED which is always supported (but can be unavailable)
@@ -1640,8 +1705,8 @@ bool LeAudioDeviceGroup::ConfigureAses(

std::shared_ptr<const set_configurations::AudioSetConfiguration>
LeAudioDeviceGroup::GetCachedConfiguration(LeAudioContextType context_type) const {
  if (context_to_configuration_cache_map.count(context_type) != 0) {
    return context_to_configuration_cache_map.at(context_type).second;
  if (context_to_configuration_cache_map_.count(context_type) != 0) {
    return context_to_configuration_cache_map_.at(context_type).second;
  }
  return nullptr;
}
@@ -1661,8 +1726,8 @@ LeAudioDeviceGroup::GetConfiguration(LeAudioContextType context_type) const {
  bool is_valid = false;

  /* Refresh the cache if there is no valid configuration */
  if (context_to_configuration_cache_map.count(context_type) != 0) {
    auto& valid_config_pair = context_to_configuration_cache_map.at(context_type);
  if (context_to_configuration_cache_map_.count(context_type) != 0) {
    auto& valid_config_pair = context_to_configuration_cache_map_.at(context_type);
    is_valid = valid_config_pair.first;
    conf = valid_config_pair.second.get();
  }
@@ -1909,7 +1974,7 @@ bool LeAudioDeviceGroup::IsConfiguredForContext(LeAudioContextType context_type)
std::unique_ptr<set_configurations::AudioSetConfiguration>
LeAudioDeviceGroup::FindFirstSupportedConfiguration(
        const CodecManager::UnicastConfigurationRequirements& requirements,
        const set_configurations::AudioSetConfigurations* confs) const {
        const set_configurations::AudioSetConfigurations* confs, bool use_preference) const {
  log::assert_that(confs != nullptr, "confs should not be null");

  log::debug("context type: {},  number of connected devices: {}",
@@ -1918,7 +1983,7 @@ LeAudioDeviceGroup::FindFirstSupportedConfiguration(
  /* Filter out device set for each end every scenario */
  for (const auto& conf : *confs) {
    log::assert_that(conf != nullptr, "confs should not be null");
    if (IsAudioSetConfigurationSupported(requirements, conf)) {
    if (IsAudioSetConfigurationSupported(requirements, conf, use_preference)) {
      log::debug("found: {}", conf->name);
      return std::make_unique<set_configurations::AudioSetConfiguration>(*conf);
    }
+26 −4
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@
#include <utility>  // for std::pair
#include <vector>

#include "hardware/bt_le_audio.h"

#ifdef __ANDROID__
#include <android/sysprop/BluetoothProperties.sysprop.h>
#endif
@@ -124,6 +126,7 @@ public:
        group_user_allowed_context_mask_(
                {.sink = types::AudioContexts(types::kLeAudioContextAllTypes),
                 .source = types::AudioContexts(types::kLeAudioContextAllTypes)}),
        preferred_config_({.sink = nullptr, .source = nullptr}),
        target_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
        current_state_(types::AseState::BTA_LE_AUDIO_ASE_STATE_IDLE),
        in_transition_(false) {
@@ -204,9 +207,14 @@ public:
  bool GetPresentationDelay(uint32_t* delay, uint8_t direction) const;
  uint16_t GetRemoteDelay(uint8_t direction) const;
  bool UpdateAudioContextAvailability(void);
  bool UpdateAudioSetConfigurationCache(types::LeAudioContextType ctx_type) const;
  bool UpdateAudioSetConfigurationCache(types::LeAudioContextType ctx_type,
                                        bool use_preferred = false) const;
  CodecManager::UnicastConfigurationRequirements GetAudioSetConfigurationRequirements(
          types::LeAudioContextType ctx_type) const;
  bool SetPreferredAudioSetConfiguration(
          const bluetooth::le_audio::btle_audio_codec_config_t& input_codec_config,
          const bluetooth::le_audio::btle_audio_codec_config_t& output_codec_config) const;
  void ResetPreferredAudioSetConfiguration(void) const;
  bool ReloadAudioLocations(void);
  bool ReloadAudioDirections(void);
  std::shared_ptr<const set_configurations::AudioSetConfiguration> GetActiveConfiguration(
@@ -392,7 +400,7 @@ public:
   */
  std::unique_ptr<set_configurations::AudioSetConfiguration> FindFirstSupportedConfiguration(
          const CodecManager::UnicastConfigurationRequirements& requirements,
          const set_configurations::AudioSetConfigurations* confs) const;
          const set_configurations::AudioSetConfigurations* confs, bool use_preferred) const;

private:
  bool is_enabled_;
@@ -406,7 +414,8 @@ private:
                     const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists);
  bool IsAudioSetConfigurationSupported(
          const CodecManager::UnicastConfigurationRequirements& requirements,
          const set_configurations::AudioSetConfiguration* audio_set_configuration) const;
          const set_configurations::AudioSetConfiguration* audio_set_configuratio,
          bool use_preferred = false) const;
  uint32_t GetTransportLatencyUs(uint8_t direction) const;
  bool IsCisPartOfCurrentStream(uint16_t cis_conn_hdl) const;

@@ -438,7 +447,20 @@ private:
  mutable std::map<
          types::LeAudioContextType,
          std::pair<bool, const std::shared_ptr<set_configurations::AudioSetConfiguration>>>
          context_to_configuration_cache_map;
          context_to_configuration_cache_map_;

  /* Possible preferred configuration cache - refreshed on each group context
   * availability change. Stored as a pair of (is_valid_cache, configuration*).
   * `pair.first` being `false` means that the cached value should be refreshed.
   */
  mutable std::map<
          types::LeAudioContextType,
          std::pair<bool, const std::shared_ptr<set_configurations::AudioSetConfiguration>>>
          context_to_preferred_configuration_cache_map_;

  mutable types::BidirectionalPair<
          std::unique_ptr<const bluetooth::le_audio::btle_audio_codec_config_t>>
          preferred_config_;

  types::AseState target_state_;
  types::AseState current_state_;
+2 −0
Original line number Diff line number Diff line
@@ -858,6 +858,8 @@ template struct BidirectionalPair<bool>;
template struct BidirectionalPair<int>;
template struct BidirectionalPair<std::vector<set_configurations::AseConfiguration>>;
template struct BidirectionalPair<set_configurations::QosConfigSetting>;
template struct BidirectionalPair<
        std::unique_ptr<const bluetooth::le_audio::btle_audio_codec_config_t>>;

}  // namespace types
}  // namespace bluetooth::le_audio
+62 −0
Original line number Diff line number Diff line
@@ -604,5 +604,67 @@ const struct types::acs_ac_record* GetConfigurationSupportedPac(
  }
  return nullptr;
}

bool IsAseConfigMatchedWithPreferredRequirements(
        const std::vector<struct set_configurations::AseConfiguration>& ase_confs,
        const std::vector<
                CodecManager::UnicastConfigurationRequirements::DeviceDirectionRequirements>& reqs,
        uint8_t channel_cnt_per_ase) {
  if (ase_confs.empty() || reqs.empty() || ase_confs.size() != reqs.size()) {
    return false;
  }

  for (auto i = 0; i < static_cast<int>(ase_confs.size()); ++i) {
    const auto& ase_config = ase_confs.at(i).codec.params.GetAsCoreCodecConfig();
    const auto& req_config = reqs.at(i).params.GetAsCoreCodecConfig();

    /* Sampling frequency */
    if (!ase_config.sampling_frequency || !req_config.sampling_frequency) {
      log::debug("Missing sampling frequencies capability");
      return false;
    }
    if (ase_config.sampling_frequency.value() != req_config.sampling_frequency.value()) {
      log::debug("Ase cfg: SamplingFrequency= {:#x}", ase_config.sampling_frequency.value());
      log::debug("Req cfg: SamplingFrequency= {:#x}", req_config.sampling_frequency.value());
      log::debug("Sampling frequency not supported");
      return false;
    }

    /* Channel counts */
    if (ase_confs.at(i).codec.GetChannelCountPerIsoStream() != channel_cnt_per_ase) {
      log::debug("Ase cfg: Allocated channel count= {:#x}",
                 ase_confs.at(i).codec.GetChannelCountPerIsoStream());
      log::debug("Req cfg: Allocated channel counts= {:#x}", channel_cnt_per_ase);
      log::debug("Channel count not supported");
      return false;
    }

    /* Frame duration */
    if (!ase_config.frame_duration || !req_config.frame_duration) {
      log::debug("Missing frame duration capability");
      return false;
    }
    if (ase_config.frame_duration.value() != ase_config.frame_duration.value()) {
      log::debug("Ase cfg: FrameDuration= {:#x}", ase_config.frame_duration.value());
      log::debug("Req cfg: FrameDuration= {:#x}", req_config.frame_duration.value());
      log::debug("Frame duration not supported");
      return false;
    }

    /* Octets per frame */
    if (!ase_config.octets_per_codec_frame || !req_config.octets_per_codec_frame) {
      log::debug("Missing octets per codec frame");
      return false;
    }
    if (ase_config.octets_per_codec_frame.value() != req_config.octets_per_codec_frame.value()) {
      log::debug("Ase cfg: Octets per frame={}", ase_config.octets_per_codec_frame.value());
      log::debug("Req cfg: Octets per frame={}", req_config.octets_per_codec_frame.value());
      return false;
    }
  }

  return true;
}

}  // namespace utils
}  // namespace bluetooth::le_audio
+5 −0
Original line number Diff line number Diff line
@@ -87,5 +87,10 @@ GetAudioSessionCodecConfigFromAudioSetConfiguration(
const struct types::acs_ac_record* GetConfigurationSupportedPac(
        const ::bluetooth::le_audio::types::PublishedAudioCapabilities& pacs,
        const ::bluetooth::le_audio::set_configurations::CodecConfigSetting& codec_config_setting);
bool IsAseConfigMatchedWithPreferredRequirements(
        const std::vector<struct set_configurations::AseConfiguration>& ase_confs,
        const std::vector<
                CodecManager::UnicastConfigurationRequirements::DeviceDirectionRequirements>& reqs,
        uint8_t channel_cnt_per_ase);
}  // namespace utils
}  // namespace bluetooth::le_audio