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

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

leaudio: Extend storage for leaudio device

With this patch we store PACs and ASE information for bonded devices.
This will improve stream creation time after reconnection (BT OFF/ON)
and allows to configure complete set even not all devices are connected.

Bug: 225020659
Bug: 242645864
Test: atest BluetoothInstrumentationTests
Test: atest bluetooth_le_audio_client_test
Test: Manual audio stream creation
Tag: #feature

Change-Id: Ic05ca8179d3913eefdc10074ffff6e4ad793e12b
parent c1bc5b3f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ cc_library_static {
        "le_audio/devices.cc",
        "le_audio/hal_verifier.cc",
        "le_audio/state_machine.cc",
        "le_audio/storage_helper.cc",
        "le_audio/client_parser.cc",
        "le_audio/client_audio.cc",
        "le_audio/le_audio_utils.cc",
@@ -572,6 +573,8 @@ cc_test {
        "test/common/mock_controller.cc",
        "le_audio/state_machine.cc",
        "le_audio/state_machine_test.cc",
        "le_audio/storage_helper.cc",
        "le_audio/storage_helper_test.cc",
        "le_audio/mock_codec_manager.cc",
    ],
    data: [
@@ -638,6 +641,7 @@ cc_test {
        "le_audio/metrics_collector_test.cc",
        "le_audio/mock_iso_manager.cc",
        "le_audio/mock_state_machine.cc",
        "le_audio/storage_helper.cc",
        "test/common/btm_api_mock.cc",
        "test/common/bta_gatt_api_mock.cc",
        "test/common/bta_gatt_queue_mock.cc",
+16 −1
Original line number Diff line number Diff line
@@ -69,7 +69,22 @@ class LeAudioClient {
  virtual void SetInCall(bool in_call) = 0;

  virtual std::vector<RawAddress> GetGroupDevices(const int group_id) = 0;
  static void AddFromStorage(const RawAddress& addr, bool autoconnect);
  static void AddFromStorage(const RawAddress& addr, bool autoconnect,
                             int sink_audio_location, int source_audio_location,
                             int sink_supported_context_types,
                             int source_supported_context_types,
                             const std::vector<uint8_t>& handles,
                             const std::vector<uint8_t>& sink_pacs,
                             const std::vector<uint8_t>& source_pacs,
                             const std::vector<uint8_t>& ases);
  static bool GetHandlesForStorage(const RawAddress& addr,
                                   std::vector<uint8_t>& out);
  static bool GetSinkPacsForStorage(const RawAddress& addr,
                                    std::vector<uint8_t>& out);
  static bool GetSourcePacsForStorage(const RawAddress& addr,
                                      std::vector<uint8_t>& out);
  static bool GetAsesForStorage(const RawAddress& addr,
                                std::vector<uint8_t>& out);
  static bool IsLeAudioClientRunning();

  static void InitializeAudioSetConfigurationProvider(void);
+183 −13
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include "stack/btm/btm_sec.h"
#include "stack/include/btu.h"  // do_in_main_thread
#include "state_machine.h"
#include "storage_helper.h"

using base::Closure;
using bluetooth::Uuid;
@@ -385,10 +386,14 @@ class LeAudioClientImpl : public LeAudioClient {

  void UpdateContextAndLocations(LeAudioDeviceGroup* group,
                                 LeAudioDevice* leAudioDevice) {
    /* Make sure location and direction are updated for the group. */
    auto location_update = group->ReloadAudioLocations();
    group->ReloadAudioDirections();

    std::optional<AudioContexts> new_group_updated_contexts =
        group->UpdateActiveContextsMap(leAudioDevice->GetAvailableContexts());

    if (new_group_updated_contexts || group->ReloadAudioLocations()) {
    if (new_group_updated_contexts || location_update) {
      callbacks_->OnAudioConf(group->audio_directions_, group->group_id_,
                              group->snk_audio_locations_.to_ulong(),
                              group->src_audio_locations_.to_ulong(),
@@ -960,15 +965,31 @@ class LeAudioClientImpl : public LeAudioClient {
  }

  /* Restore paired device from storage to recreate groups */
  void AddFromStorage(const RawAddress& address, bool autoconnect) {
  void AddFromStorage(const RawAddress& address, bool autoconnect,
                      int sink_audio_location, int source_audio_location,
                      int sink_supported_context_types,
                      int source_supported_context_types,
                      const std::vector<uint8_t>& handles,
                      const std::vector<uint8_t>& sink_pacs,
                      const std::vector<uint8_t>& source_pacs,
                      const std::vector<uint8_t>& ases) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address);

    LOG(INFO) << __func__ << ", restoring: " << address;
    if (leAudioDevice) {
      LOG_ERROR("Device is already loaded. Nothing to do.");
      return;
    }

    LOG_INFO(
        "restoring: %s, autoconnect %d, sink_audio_location: %d, "
        "source_audio_location: %d, sink_supported_context_types : 0x%04x, "
        "source_supported_context_types 0x%04x ",
        address.ToString().c_str(), autoconnect, sink_audio_location,
        source_audio_location, sink_supported_context_types,
        source_supported_context_types);

    if (!leAudioDevice) {
    leAudioDevices_.Add(address, false);
    leAudioDevice = leAudioDevices_.FindByAddress(address);
    }

    int group_id = DeviceGroups::Get()->GetGroupId(
        address, le_audio::uuid::kCapServiceUuid);
@@ -976,11 +997,71 @@ class LeAudioClientImpl : public LeAudioClient {
      group_add_node(group_id, address);
    }

    leAudioDevice->snk_audio_locations_ = sink_audio_location;
    if (sink_audio_location != 0) {
      leAudioDevice->audio_directions_ |=
          le_audio::types::kLeAudioDirectionSink;
    }

    leAudioDevice->src_audio_locations_ = source_audio_location;
    if (source_audio_location != 0) {
      leAudioDevice->audio_directions_ |=
          le_audio::types::kLeAudioDirectionSource;
    }

    leAudioDevice->SetSupportedContexts(
        (uint16_t)sink_supported_context_types,
        (uint16_t)source_supported_context_types);

    /* Use same as or supported ones for now. */
    leAudioDevice->SetAvailableContexts(
        (uint16_t)sink_supported_context_types,
        (uint16_t)source_supported_context_types);

    if (!DeserializeHandles(leAudioDevice, handles)) {
      LOG_WARN("Could not load Handles");
    }

    if (!DeserializeSinkPacs(leAudioDevice, sink_pacs)) {
      LOG_WARN("Could not load sink pacs");
    }

    if (!DeserializeSourcePacs(leAudioDevice, source_pacs)) {
      LOG_WARN("Could not load source pacs");
    }

    if (!DeserializeAses(leAudioDevice, ases)) {
      LOG_WARN("Could not load ases");
    }

    if (autoconnect) {
      BTA_GATTC_Open(gatt_if_, address, false, false);
    }
  }

  bool GetHandlesForStorage(const RawAddress& addr, std::vector<uint8_t>& out) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(addr);
    return SerializeHandles(leAudioDevice, out);
  }

  bool GetSinkPacsForStorage(const RawAddress& addr,
                             std::vector<uint8_t>& out) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(addr);
    return SerializeSinkPacs(leAudioDevice, out);
  }

  bool GetSourcePacsForStorage(const RawAddress& addr,
                               std::vector<uint8_t>& out) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(addr);
    return SerializeSourcePacs(leAudioDevice, out);
  }

  bool GetAsesForStorage(const RawAddress& addr, std::vector<uint8_t>& out) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(addr);

    return SerializeAses(leAudioDevice, out);
  }

  void BackgroundConnectIfGroupConnected(LeAudioDevice* leAudioDevice) {
    DLOG(INFO) << __func__ << leAudioDevice->address_;
    auto group = aseGroups_.FindById(leAudioDevice->group_id_);
@@ -1099,7 +1180,7 @@ class LeAudioClientImpl : public LeAudioClient {
   * are dispatched to correct elements e.g. ASEs, PACs, audio locations etc.
   */
  void LeAudioCharValueHandle(uint16_t conn_id, uint16_t hdl, uint16_t len,
                              uint8_t* value) {
                              uint8_t* value, bool notify = false) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByConnId(conn_id);
    struct ase* ase;

@@ -1126,7 +1207,7 @@ class LeAudioClientImpl : public LeAudioClient {
      std::vector<struct le_audio::types::acs_ac_record> pac_recs;

      /* Guard consistency of PAC records structure */
      if (!le_audio::client_parser::pacs::ParsePac(pac_recs, len, value))
      if (!le_audio::client_parser::pacs::ParsePacs(pac_recs, len, value))
        return;

      LOG(INFO) << __func__ << ", Registering sink PACs";
@@ -1147,6 +1228,9 @@ class LeAudioClientImpl : public LeAudioClient {
                                group->src_audio_locations_.to_ulong(),
                                group->GetActiveContexts().to_ulong());
      }
      if (notify) {
        btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_);
      }
      return;
    }

@@ -1157,7 +1241,7 @@ class LeAudioClientImpl : public LeAudioClient {
      std::vector<struct le_audio::types::acs_ac_record> pac_recs;

      /* Guard consistency of PAC records structure */
      if (!le_audio::client_parser::pacs::ParsePac(pac_recs, len, value))
      if (!le_audio::client_parser::pacs::ParsePacs(pac_recs, len, value))
        return;

      LOG(INFO) << __func__ << ", Registering source PACs";
@@ -1178,6 +1262,10 @@ class LeAudioClientImpl : public LeAudioClient {
                                group->src_audio_locations_.to_ulong(),
                                group->GetActiveContexts().to_ulong());
      }

      if (notify) {
        btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_);
      }
      return;
    }

@@ -1203,6 +1291,14 @@ class LeAudioClientImpl : public LeAudioClient {
      LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);
      callbacks_->OnSinkAudioLocationAvailable(leAudioDevice->address_,
                                               snk_audio_locations.to_ulong());

      if (notify) {
        btif_storage_set_leaudio_audio_location(
            leAudioDevice->address_,
            leAudioDevice->snk_audio_locations_.to_ulong(),
            leAudioDevice->src_audio_locations_.to_ulong());
      }

      /* Read of source audio locations during initial attribute discovery.
       * Group would be assigned once service search is completed.
       */
@@ -1237,6 +1333,14 @@ class LeAudioClientImpl : public LeAudioClient {
      leAudioDevice->src_audio_locations_ = src_audio_locations;

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

      if (notify) {
        btif_storage_set_leaudio_audio_location(
            leAudioDevice->address_,
            leAudioDevice->snk_audio_locations_.to_ulong(),
            leAudioDevice->src_audio_locations_.to_ulong());
      }

      /* Read of source audio locations during initial attribute discovery.
       * Group would be assigned once service search is completed.
       */
@@ -1300,6 +1404,12 @@ class LeAudioClientImpl : public LeAudioClient {
      /* Just store if for now */
      leAudioDevice->SetSupportedContexts(supp_audio_contexts->snk_supp_cont,
                                          supp_audio_contexts->src_supp_cont);

      btif_storage_set_leaudio_supported_context_types(
          leAudioDevice->address_,
          supp_audio_contexts->snk_supp_cont.to_ulong(),
          supp_audio_contexts->src_supp_cont.to_ulong());

    } else if (hdl == leAudioDevice->ctp_hdls_.val_hdl) {
      auto ntf =
          std::make_unique<struct le_audio::client_parser::ascs::ctp_ntf>();
@@ -1913,6 +2023,8 @@ class LeAudioClientImpl : public LeAudioClient {
    }

    leAudioDevice->known_service_handles_ = true;
    btif_storage_leaudio_update_handles_bin(leAudioDevice->address_);

    leAudioDevice->notify_connected_after_read_ = true;

    /* If already known group id */
@@ -3348,6 +3460,16 @@ class LeAudioClientImpl : public LeAudioClient {
      LeAudioDevice* leAudioDevice =
          instance->leAudioDevices_.FindByConnId(conn_id);
      leAudioDevice->notify_connected_after_read_ = false;

      /* Update PACs and ASEs when all is read.*/
      btif_storage_leaudio_update_pacs_bin(leAudioDevice->address_);
      btif_storage_leaudio_update_ase_bin(leAudioDevice->address_);

      btif_storage_set_leaudio_audio_location(
          leAudioDevice->address_,
          leAudioDevice->snk_audio_locations_.to_ulong(),
          leAudioDevice->src_audio_locations_.to_ulong());

      instance->connectionReady(leAudioDevice);
    }
  }
@@ -3732,7 +3854,7 @@ void le_audio_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
    case BTA_GATTC_NOTIF_EVT:
      instance->LeAudioCharValueHandle(
          p_data->notify.conn_id, p_data->notify.handle, p_data->notify.len,
          static_cast<uint8_t*>(p_data->notify.value));
          static_cast<uint8_t*>(p_data->notify.value), true);

      if (!p_data->notify.is_notify)
        BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, p_data->notify.handle);
@@ -3897,13 +4019,61 @@ DeviceGroupsCallbacksImpl deviceGroupsCallbacksImpl;

}  // namespace

void LeAudioClient::AddFromStorage(const RawAddress& addr, bool autoconnect) {
void LeAudioClient::AddFromStorage(
    const RawAddress& addr, bool autoconnect, int sink_audio_location,
    int source_audio_location, int sink_supported_context_types,
    int source_supported_context_types, const std::vector<uint8_t>& handles,
    const std::vector<uint8_t>& sink_pacs,
    const std::vector<uint8_t>& source_pacs, const std::vector<uint8_t>& ases) {
  if (!instance) {
    LOG(ERROR) << "Not initialized yet";
    return;
  }

  instance->AddFromStorage(addr, autoconnect);
  instance->AddFromStorage(addr, autoconnect, sink_audio_location,
                           source_audio_location, sink_supported_context_types,
                           source_supported_context_types, handles, sink_pacs,
                           source_pacs, ases);
}

bool LeAudioClient::GetHandlesForStorage(const RawAddress& addr,
                                         std::vector<uint8_t>& out) {
  if (!instance) {
    LOG_ERROR("Not initialized yet");
    return false;
  }

  return instance->GetHandlesForStorage(addr, out);
}

bool LeAudioClient::GetSinkPacsForStorage(const RawAddress& addr,
                                          std::vector<uint8_t>& out) {
  if (!instance) {
    LOG_ERROR("Not initialized yet");
    return false;
  }

  return instance->GetSinkPacsForStorage(addr, out);
}

bool LeAudioClient::GetSourcePacsForStorage(const RawAddress& addr,
                                            std::vector<uint8_t>& out) {
  if (!instance) {
    LOG_ERROR("Not initialized yet");
    return false;
  }

  return instance->GetSourcePacsForStorage(addr, out);
}

bool LeAudioClient::GetAsesForStorage(const RawAddress& addr,
                                      std::vector<uint8_t>& out) {
  if (!instance) {
    LOG_ERROR("Not initialized yet");
    return false;
  }

  return instance->GetAsesForStorage(addr, out);
}

bool LeAudioClient::IsLeAudioClientRunning(void) { return instance != nullptr; }
+25 −1
Original line number Diff line number Diff line
@@ -53,7 +53,31 @@ void LeAudioClient::Initialize(
void LeAudioClient::Cleanup(base::Callback<void()> cleanupCb) {}
LeAudioClient* LeAudioClient::Get(void) { return nullptr; }
void LeAudioClient::DebugDump(int fd) {}
void LeAudioClient::AddFromStorage(const RawAddress& addr, bool autoconnect) {}
void LeAudioClient::AddFromStorage(const RawAddress& addr, bool autoconnect,
                                   int sink_audio_location,
                                   int source_audio_location,
                                   int sink_supported_context_types,
                                   int source_supported_context_types,
                                   const std::vector<uint8_t>& handles,
                                   const std::vector<uint8_t>& sink_pacs,
                                   const std::vector<uint8_t>& source_pacs,
                                   const std::vector<uint8_t>& ases) {}
bool LeAudioClient::GetHandlesForStorage(const RawAddress& addr,
                                         std::vector<uint8_t>& out) {
  return false;
}
bool LeAudioClient::GetSinkPacsForStorage(const RawAddress& addr,
                                          std::vector<uint8_t>& out) {
  return false;
}
bool LeAudioClient::GetSourcePacsForStorage(const RawAddress& addr,
                                            std::vector<uint8_t>& out) {
  return false;
}
bool LeAudioClient::GetAsesForStorage(const RawAddress& addr,
                                      std::vector<uint8_t>& out) {
  return false;
}
bool LeAudioClient::IsLeAudioClientRunning() { return false; }
void LeAudioClient::InitializeAudioSetConfigurationProvider(void) {}
void LeAudioClient::CleanupAudioSetConfigurationProvider(void) {}
+57 −44
Original line number Diff line number Diff line
@@ -543,26 +543,15 @@ bool PrepareAseCtpRelease(const std::vector<uint8_t>& ase_ids,

namespace pacs {

bool ParsePac(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
int ParseSinglePac(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
                   const uint8_t* value) {
  if (len < kAcsPacDiscoverRspMinLen) {
    LOG(ERROR) << "Wrong len of PAC characteristic";
    return false;
  }

  uint8_t pac_rec_nb;
  STREAM_TO_UINT8(pac_rec_nb, value);
  len -= kAcsPacDiscoverRspMinLen;

  pac_recs.reserve(pac_rec_nb);
  for (int i = 0; i < pac_rec_nb; i++) {
  struct acs_ac_record rec;
  uint8_t codec_spec_cap_len, metadata_len;

  if (len < kAcsPacRecordMinLen) {
      LOG(ERROR) << "Wrong len of PAC record";
    LOG_ERROR("Wrong len of PAC record (%d!=%d)", len, kAcsPacRecordMinLen);
    pac_recs.clear();
      return false;
    return -1;
  }

  STREAM_TO_UINT8(rec.codec_id.coding_format, value);
@@ -572,15 +561,16 @@ bool ParsePac(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
  len -= kAcsPacRecordMinLen - kAcsPacMetadataLenLen;

  if (len < codec_spec_cap_len + kAcsPacMetadataLenLen) {
      LOG(ERROR) << "Wrong len of PAC record (codec specific capabilities)";
    LOG_ERROR("Wrong len of PAC record (codec specific capabilities) (%d!=%d)",
              len, codec_spec_cap_len + kAcsPacMetadataLenLen);
    pac_recs.clear();
      return false;
    return -1;
  }

  bool parsed;
  rec.codec_spec_caps =
      types::LeAudioLtvMap::Parse(value, codec_spec_cap_len, parsed);
    if (!parsed) return false;
  if (!parsed) return -1;

  value += codec_spec_cap_len;
  len -= codec_spec_cap_len;
@@ -589,9 +579,9 @@ bool ParsePac(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
  len -= kAcsPacMetadataLenLen;

  if (len < metadata_len) {
      LOG(ERROR) << "Wrong len of PAC record (metadata)";
    LOG_ERROR("Wrong len of PAC record (metadata) (%d!=%d)", len, metadata_len);
    pac_recs.clear();
      return false;
    return -1;
  }

  rec.metadata = std::vector<uint8_t>(value, value + metadata_len);
@@ -599,6 +589,29 @@ bool ParsePac(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
  len -= metadata_len;

  pac_recs.push_back(std::move(rec));

  return len;
}

bool ParsePacs(std::vector<struct acs_ac_record>& pac_recs, uint16_t len,
               const uint8_t* value) {
  if (len < kAcsPacDiscoverRspMinLen) {
    LOG_ERROR("Wrong len of PAC characteristic (%d!=%d)", len,
              kAcsPacDiscoverRspMinLen);
    return false;
  }

  uint8_t pac_rec_nb;
  STREAM_TO_UINT8(pac_rec_nb, value);
  len -= kAcsPacDiscoverRspMinLen;

  pac_recs.reserve(pac_rec_nb);
  for (int i = 0; i < pac_rec_nb; i++) {
    int remaining_len = ParseSinglePac(pac_recs, len, value);
    if (remaining_len < 0) return false;

    value += (len - remaining_len);
    len = remaining_len;
  }

  return true;
Loading