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

Commit 6efb65ca authored by Jakub Tyszkowski's avatar Jakub Tyszkowski
Browse files

LeAudio: Minor configuration update cleanup and unit test

This cleans up the code and adjust function naming for better
readability. New unit test are also added.

Bug: 281686787
Bug: 285647765
Test: atest bluetooth_le_audio_test bluetooth_le_audio_client_test
Change-Id: I83d0f40f8c7ddd7314e795a41a7db9a3fa3eae0e
parent 6507424a
Loading
Loading
Loading
Loading
+67 −109
Original line number Diff line number Diff line
@@ -534,22 +534,38 @@ class LeAudioClientImpl : public LeAudioClient {
    } while (leAudioDevice);
  }

  void UpdateContextAndLocations(LeAudioDeviceGroup* group,
                                 LeAudioDevice* leAudioDevice) {
    if (leAudioDevice->GetConnectionState() != DeviceConnectState::CONNECTED) {
      LOG_DEBUG("%s not yet connected ",
                ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      return;
  void UpdateLocationsAndContextsAvailability(LeAudioDeviceGroup* group,
                                              AudioContexts contexts) {
    bool group_conf_changed = group->ReloadAudioLocations();
    group_conf_changed |= group->ReloadAudioDirections();
    group_conf_changed |= group->UpdateAudioSetConfigurationCache(contexts);
    if (group_conf_changed) {
      callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                              group->snk_audio_locations_.to_ulong(),
                              group->src_audio_locations_.to_ulong(),
                              group->GetAvailableContexts().value());
    }
  }

    /* Make sure location and direction are updated for the group. */
    auto location_update = group->ReloadAudioLocations();
    group->ReloadAudioDirections();
  void UpdateLocationsAndContextsAvailability(int group_id) {
    LeAudioDeviceGroup* group = aseGroups_.FindById(group_id);
    if (group) {
      UpdateLocationsAndContextsAvailability(group,
                                             group->GetAvailableContexts());
    }
  }

    auto contexts_updated = group->UpdateAudioContextTypeAvailability(
        leAudioDevice->GetAvailableContexts());
  void UpdateLocationsAndContextsAvailability(int group_id,
                                              AudioContexts contexts) {
    LeAudioDeviceGroup* group = aseGroups_.FindById(group_id);
    if (group) {
      UpdateLocationsAndContextsAvailability(group, contexts);
    }
  }

    if (contexts_updated || location_update) {
  void UpdateContexts(LeAudioDeviceGroup* group, AudioContexts contexts) {
    bool group_conf_changed = group->UpdateAudioSetConfigurationCache(contexts);
    if (group_conf_changed) {
      callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                              group->snk_audio_locations_.to_ulong(),
                              group->src_audio_locations_.to_ulong(),
@@ -722,25 +738,16 @@ class LeAudioClientImpl : public LeAudioClient {
    if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID)
      AseInitialStateReadRequest(leAudioDevice);

    /* Group may be destroyed once moved its last node to new group */
    if (aseGroups_.FindById(old_group_id) != nullptr) {
      /* Removing node from group may touch its context integrity */
      auto contexts_updated = old_group->UpdateAudioContextTypeAvailability(
          old_group->GetAvailableContexts());

      bool group_conf_changed = old_group->ReloadAudioLocations();
      group_conf_changed |= old_group->ReloadAudioDirections();
      group_conf_changed |= contexts_updated;
    /* Group may be destroyed once moved its last node to new group, so don't
     * use `old_group` pointer anymore.
     * Removing node from group requires updating group context availability */
    UpdateLocationsAndContextsAvailability(old_group_id);

      if (group_conf_changed) {
        callbacks_->OnAudioConf(old_group->audio_directions_, old_group_id,
                                old_group->snk_audio_locations_.to_ulong(),
                                old_group->src_audio_locations_.to_ulong(),
                                old_group->GetAvailableContexts().value());
      }
    if (leAudioDevice->GetConnectionState() == DeviceConnectState::CONNECTED) {
      UpdateLocationsAndContextsAvailability(
          new_group, new_group->GetAvailableContexts() |
                         leAudioDevice->GetAvailableContexts());
    }

    UpdateContextAndLocations(new_group, leAudioDevice);
  }

  void GroupAddNode(const int group_id, const RawAddress& address) override {
@@ -791,19 +798,9 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    /* Removing node from group touch its context integrity */
    bool contexts_updated = group->UpdateAudioContextTypeAvailability(
    /* Removing node from group requires updating group context availability */
    UpdateLocationsAndContextsAvailability(group,
                                           group->GetAvailableContexts());

    bool group_conf_changed = group->ReloadAudioLocations();
    group_conf_changed |= group->ReloadAudioDirections();
    group_conf_changed |= contexts_updated;

    if (group_conf_changed)
      callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                              group->snk_audio_locations_.to_ulong(),
                              group->src_audio_locations_.to_ulong(),
                              group->GetAvailableContexts().value());
  }

  void GroupRemoveNode(const int group_id, const RawAddress& address) override {
@@ -1218,13 +1215,13 @@ class LeAudioClientImpl : public LeAudioClient {
     * If most recent scenario is not supported, try to find first supported.
     */
    LeAudioContextType default_context_type = configuration_context_type_;
    if (!group->IsContextSupported(default_context_type)) {
      if (group->IsContextSupported(LeAudioContextType::MEDIA)) {
    if (!group->IsAudioSetConfigurationAvailable(default_context_type)) {
      if (group->IsAudioSetConfigurationAvailable(LeAudioContextType::MEDIA)) {
        default_context_type = LeAudioContextType::MEDIA;
      } else {
        for (LeAudioContextType context_type :
             le_audio::types::kLeAudioContextAllTypesArray) {
          if (group->IsContextSupported(context_type)) {
          if (group->IsAudioSetConfigurationAvailable(context_type)) {
            default_context_type = context_type;
            break;
          }
@@ -1699,12 +1696,8 @@ class LeAudioClientImpl : public LeAudioClient {
       * Read of available context during initial attribute discovery.
       * Group would be assigned once service search is completed.
       */
      if (group && group->UpdateAudioContextTypeAvailability(
                       leAudioDevice->GetAvailableContexts())) {
        callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                                group->snk_audio_locations_.to_ulong(),
                                group->src_audio_locations_.to_ulong(),
                                group->GetAvailableContexts().value());
      if (group) {
        UpdateContexts(group, group->GetAvailableContexts());
      }
      if (notify) {
        btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_);
@@ -1733,14 +1726,9 @@ class LeAudioClientImpl : public LeAudioClient {
       * Read of available context during initial attribute discovery.
       * Group would be assigned once service search is completed.
       */
      if (group && group->UpdateAudioContextTypeAvailability(
                       leAudioDevice->GetAvailableContexts())) {
        callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                                group->snk_audio_locations_.to_ulong(),
                                group->src_audio_locations_.to_ulong(),
                                group->GetAvailableContexts().value());
      if (group) {
        UpdateContexts(group, group->GetAvailableContexts());
      }

      if (notify) {
        btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_);
      }
@@ -1766,7 +1754,6 @@ class LeAudioClientImpl : public LeAudioClient {
          le_audio::types::kLeAudioDirectionSink;
      leAudioDevice->snk_audio_locations_ = snk_audio_locations;

      LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);
      callbacks_->OnSinkAudioLocationAvailable(leAudioDevice->address_,
                                               snk_audio_locations.to_ulong());

@@ -1780,17 +1767,7 @@ class LeAudioClientImpl : public LeAudioClient {
      /* Read of source audio locations during initial attribute discovery.
       * Group would be assigned once service search is completed.
       */
      if (!group) return;

      bool group_conf_changed = group->ReloadAudioLocations();
      group_conf_changed |= group->ReloadAudioDirections();

      if (group_conf_changed) {
        callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                                group->snk_audio_locations_.to_ulong(),
                                group->src_audio_locations_.to_ulong(),
                                group->GetAvailableContexts().value());
      }
      UpdateLocationsAndContextsAvailability(leAudioDevice->group_id_);
    } else if (hdl == leAudioDevice->src_audio_locations_hdls_.val_hdl) {
      AudioLocations src_audio_locations;

@@ -1810,8 +1787,6 @@ class LeAudioClientImpl : public LeAudioClient {
          le_audio::types::kLeAudioDirectionSource;
      leAudioDevice->src_audio_locations_ = src_audio_locations;

      LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);

      if (notify) {
        btif_storage_set_leaudio_audio_location(
            leAudioDevice->address_,
@@ -1822,28 +1797,18 @@ class LeAudioClientImpl : public LeAudioClient {
      /* Read of source audio locations during initial attribute discovery.
       * Group would be assigned once service search is completed.
       */
      if (!group) return;

      bool group_conf_changed = group->ReloadAudioLocations();
      group_conf_changed |= group->ReloadAudioDirections();

      if (group_conf_changed) {
        callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                                group->snk_audio_locations_.to_ulong(),
                                group->src_audio_locations_.to_ulong(),
                                group->GetAvailableContexts().value());
      }
      UpdateLocationsAndContextsAvailability(leAudioDevice->group_id_);
    } else if (hdl == leAudioDevice->audio_avail_hdls_.val_hdl) {
      le_audio::client_parser::pacs::acs_available_audio_contexts
          avail_audio_contexts;
      le_audio::client_parser::pacs::ParseAvailableAudioContexts(
          avail_audio_contexts, len, value);

      auto updated_avail_contexts = leAudioDevice->SetAvailableContexts(
      auto updated_context_bits = leAudioDevice->SetAvailableContexts(
          avail_audio_contexts.snk_avail_cont,
          avail_audio_contexts.src_avail_cont);

      if (updated_avail_contexts.any()) {
      if (updated_context_bits.any()) {
        /* Update scenario map considering changed available context types */
        LeAudioDeviceGroup* group =
            aseGroups_.FindById(leAudioDevice->group_id_);
@@ -1858,18 +1823,12 @@ class LeAudioClientImpl : public LeAudioClient {
          if (group->IsInTransition() ||
              (group->GetState() ==
               AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING)) {
            group->SetPendingAvailableContextsChange(updated_avail_contexts);
            group->SetPendingAvailableContextsChange(updated_context_bits);
            return;
          }

          auto contexts_updated =
              group->UpdateAudioContextTypeAvailability(updated_avail_contexts);
          if (contexts_updated) {
            callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                                    group->snk_audio_locations_.to_ulong(),
                                    group->src_audio_locations_.to_ulong(),
                                    group->GetAvailableContexts().value());
          }
          /* Available contexts change requires audio set config invalidation */
          UpdateContexts(group, updated_context_bits);
        }
      }
    } else if (hdl == leAudioDevice->audio_supp_cont_hdls_.val_hdl) {
@@ -2993,7 +2952,8 @@ class LeAudioClientImpl : public LeAudioClient {
        get_num_of_devices_in_configuration(stream_conf->conf);

    if (num_of_devices < group->NumOfConnected() &&
        !group->IsConfigurationSupported(leAudioDevice, stream_conf->conf)) {
        !group->IsAudioSetConfigurationSupported(leAudioDevice,
                                                 stream_conf->conf)) {
      /* Reconfigure if newly connected member device cannot support current
       * codec configuration */
      group->SetPendingConfiguration();
@@ -3060,7 +3020,11 @@ class LeAudioClientImpl : public LeAudioClient {

    if (leAudioDevice->group_id_ != bluetooth::groups::kGroupUnknown) {
      LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);
      UpdateContextAndLocations(group, leAudioDevice);
      if (group) {
        UpdateLocationsAndContextsAvailability(
            group, group->GetAvailableContexts() |
                       leAudioDevice->GetAvailableContexts());
      }
      AttachToStreamingGroupIfNeeded(leAudioDevice);
    }
  }
@@ -5121,21 +5085,15 @@ class LeAudioClientImpl : public LeAudioClient {
  }

  void HandlePendingAvailableContextsChange(LeAudioDeviceGroup* group) {
    if (!group) return;
    if (!group) {
      LOG_ERROR("Invalid group: %d", active_group_id_);
      return;
    }

    /* Update group configuration with pending available context change */
    auto contexts = group->GetPendingAvailableContextsChange();
    if (contexts.any()) {
      auto success = group->UpdateAudioContextTypeAvailability(contexts);
      if (success) {
        callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                                group->snk_audio_locations_.to_ulong(),
                                group->src_audio_locations_.to_ulong(),
                                group->GetAvailableContexts().value());
      }
    UpdateContexts(group, group->GetPendingAvailableContextsChange());
    group->ClearPendingAvailableContextsChange();
  }
  }

  void HandlePendingDeviceRemove(LeAudioDeviceGroup* group) {
    for (auto device = group->GetFirstDevice(); device != nullptr;
+14 −12
Original line number Diff line number Diff line
@@ -776,15 +776,15 @@ uint16_t LeAudioDeviceGroup::GetRemoteDelay(uint8_t direction) {
  return remote_delay_ms;
}

void LeAudioDeviceGroup::UpdateAudioContextTypeAvailability(void) {
bool LeAudioDeviceGroup::UpdateAudioSetConfigurationCache(void) {
  LOG_DEBUG(" group id: %d, available contexts: %s", group_id_,
            group_available_contexts_.to_string().c_str());
  UpdateAudioContextTypeAvailability(group_available_contexts_);
  return UpdateAudioSetConfigurationCache(group_available_contexts_);
}

/* Returns true if support for any type in the whole group has changed,
 * otherwise false. */
bool LeAudioDeviceGroup::UpdateAudioContextTypeAvailability(
bool LeAudioDeviceGroup::UpdateAudioSetConfigurationCache(
    AudioContexts update_contexts) {
  auto new_contexts = AudioContexts();
  bool active_contexts_has_been_modified = false;
@@ -800,7 +800,8 @@ bool LeAudioDeviceGroup::UpdateAudioContextTypeAvailability(
    LOG_DEBUG("Checking context: %s", ToHexString(ctx_type).c_str());

    if (!update_contexts.test(ctx_type)) {
      LOG_DEBUG("Configuration not in updated context");
      LOG_DEBUG("%s config availability not updated for ",
                ToHexString(ctx_type).c_str());
      /* Fill context bitset for possible returned value if updated */
      if (available_context_to_configuration_map.count(ctx_type) > 0)
        new_contexts.set(ctx_type);
@@ -854,7 +855,7 @@ bool LeAudioDeviceGroup::UpdateAudioContextTypeAvailability(

  /* Some contexts have changed, return new available context bitset */
  if (active_contexts_has_been_modified) {
    group_available_contexts_ = new_contexts;
    SetAvailableContexts(new_contexts);
  }

  return active_contexts_has_been_modified;
@@ -1300,13 +1301,13 @@ bool CheckIfStrategySupported(types::LeAudioConfigurationStrategy strategy,
 * requirement for connected devices in the group and available ASEs
 * (no matter on the ASE state) and for given context type
 */
bool LeAudioDeviceGroup::IsConfigurationSupported(
bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported(
    const set_configurations::AudioSetConfiguration* audio_set_conf,
    types::LeAudioContextType context_type,
    types::LeAudioConfigurationStrategy required_snk_strategy) {
  if (!set_configurations::check_if_may_cover_scenario(
          audio_set_conf, NumOfConnected(context_type))) {
    LOG_DEBUG(" cannot cover scenario  %s: size of for context type %d",
    LOG_DEBUG(" cannot cover scenario  %s, num. of connected: %d",
              bluetooth::common::ToString(context_type).c_str(),
              +NumOfConnected(context_type));
    return false;
@@ -1798,12 +1799,12 @@ LeAudioDeviceGroup::GetCodecConfigurationByDirection(
  return group_config;
}

bool LeAudioDeviceGroup::IsContextSupported(
    types::LeAudioContextType group_context_type) {
bool LeAudioDeviceGroup::IsAudioSetConfigurationAvailable(
    types::LeAudioContextType group_context_type) const {
  auto iter = available_context_to_configuration_map.find(group_context_type);
  if (iter == available_context_to_configuration_map.end()) return false;

  return available_context_to_configuration_map[group_context_type] != nullptr;
  return available_context_to_configuration_map.count(group_context_type) != 0;
}

bool LeAudioDeviceGroup::IsMetadataChanged(
@@ -2126,7 +2127,7 @@ bool LeAudioDeviceGroup::IsConfiguredForContext(
  return (stream_conf.conf == GetActiveConfiguration());
}

bool LeAudioDeviceGroup::IsConfigurationSupported(
bool LeAudioDeviceGroup::IsAudioSetConfigurationSupported(
    LeAudioDevice* leAudioDevice,
    const set_configurations::AudioSetConfiguration* audio_set_conf) {
  for (const auto& ent : (*audio_set_conf).confs) {
@@ -2167,7 +2168,8 @@ LeAudioDeviceGroup::FindFirstSupportedConfiguration(

  auto required_snk_strategy = GetGroupStrategy(Size());
  for (const auto& conf : *confs) {
    if (IsConfigurationSupported(conf, context_type, required_snk_strategy)) {
    if (IsAudioSetConfigurationSupported(conf, context_type,
                                         required_snk_strategy)) {
      LOG_DEBUG("found: %s", conf->name.c_str());
      return conf;
    }
+12 −6
Original line number Diff line number Diff line
@@ -357,8 +357,9 @@ class LeAudioDeviceGroup {
  uint8_t GetTargetPhy(uint8_t direction);
  bool GetPresentationDelay(uint32_t* delay, uint8_t direction);
  uint16_t GetRemoteDelay(uint8_t direction);
  bool UpdateAudioContextTypeAvailability(types::AudioContexts contexts);
  void UpdateAudioContextTypeAvailability(void);
  bool UpdateAudioSetConfigurationCache(
      types::AudioContexts updated_context_bits);
  bool UpdateAudioSetConfigurationCache(void);
  bool ReloadAudioLocations(void);
  bool ReloadAudioDirections(void);
  const set_configurations::AudioSetConfiguration* GetActiveConfiguration(void);
@@ -369,12 +370,13 @@ class LeAudioDeviceGroup {
  void Disable(int gatt_if);
  void Enable(int gatt_if, tBTM_BLE_CONN_TYPE reconnection_mode);
  bool IsEnabled(void);
  bool IsConfigurationSupported(
  bool IsAudioSetConfigurationSupported(
      LeAudioDevice* leAudioDevice,
      const set_configurations::AudioSetConfiguration* audio_set_conf);
  std::optional<LeAudioCodecConfiguration> GetCodecConfigurationByDirection(
      types::LeAudioContextType group_context_type, uint8_t direction) const;
  bool IsContextSupported(types::LeAudioContextType group_context_type);
  bool IsAudioSetConfigurationAvailable(
      types::LeAudioContextType group_context_type) const;
  bool IsMetadataChanged(
      const types::BidirectionalPair<types::AudioContexts>& context_types,
      const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists);
@@ -431,7 +433,11 @@ class LeAudioDeviceGroup {
    return metadata_context_type_;
  }

  inline types::AudioContexts GetAvailableContexts(void) {
  inline void SetAvailableContexts(types::AudioContexts new_contexts) {
    group_available_contexts_ = new_contexts;
  }

  inline types::AudioContexts GetAvailableContexts(void) const {
    return group_available_contexts_;
  }

@@ -454,7 +460,7 @@ class LeAudioDeviceGroup {
      const types::BidirectionalPair<types::AudioContexts>&
          metadata_context_types,
      const types::BidirectionalPair<std::vector<uint8_t>>& ccid_lists);
  bool IsConfigurationSupported(
  bool IsAudioSetConfigurationSupported(
      const set_configurations::AudioSetConfiguration* audio_set_configuration,
      types::LeAudioContextType context_type,
      types::LeAudioConfigurationStrategy required_snk_strategy);
+206 −37

File changed.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Diff line number Diff line
@@ -672,7 +672,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
    if ((group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_IDLE) &&
        !group->IsInTransition()) {
      LOG_INFO("group: %d is in IDLE", group->group_id_);
      group->UpdateAudioContextTypeAvailability();
      group->UpdateAudioSetConfigurationCache();

      /* When OnLeAudioDeviceSetStateTimeout happens, group will transition
       * to IDLE, and after that an ACL disconnect will be triggered. We need
@@ -696,7 +696,7 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
    /* Update the current group audio context availability which could change
     * due to disconnected group member.
     */
    group->UpdateAudioContextTypeAvailability();
    group->UpdateAudioSetConfigurationCache();

    if (group->IsAnyDeviceConnected()) {
      /*
Loading