blob: 8ad74bf0570cd1545064458a4b510a1464adcdca [file]
/******************************************************************************
*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "storage_helper.h"
#include <bluetooth/log.h>
#include "client_parser.h"
#include "common/strings.h"
#include "le_audio_types.h"
#include "os/log.h"
#include "stack/include/bt_types.h"
using bluetooth::le_audio::types::hdl_pair;
namespace bluetooth::le_audio {
static constexpr uint8_t LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC = 0x00;
static constexpr uint8_t LEAUDIO_ASE_STORAGE_CURRENT_LAYOUT_MAGIC = 0x00;
static constexpr uint8_t LEAUDIO_HANDLES_STORAGE_CURRENT_LAYOUT_MAGIC = 0x00;
static constexpr uint8_t LEAUDIO_CODEC_ID_SZ = 5;
static constexpr size_t LEAUDIO_STORAGE_MAGIC_SZ =
sizeof(uint8_t) /* magic is always uint8_t */;
static constexpr size_t LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ =
LEAUDIO_STORAGE_MAGIC_SZ + sizeof(uint8_t); /* num_of_entries */
static constexpr size_t LEAUDIO_PACS_ENTRY_HDR_SZ =
sizeof(uint16_t) /*handle*/ + sizeof(uint16_t) /*ccc handle*/ +
sizeof(uint8_t) /* number of pack records in single characteristic */;
static constexpr size_t LEAUDIO_PACS_ENTRY_SZ =
sizeof(uint8_t) /* size of single pac record */ +
LEAUDIO_CODEC_ID_SZ /*codec id*/ +
sizeof(uint8_t) /*codec capabilities len*/ +
sizeof(uint8_t) /*metadata len*/;
static constexpr size_t LEAUDIO_ASES_ENTRY_SZ =
sizeof(uint16_t) /*handle*/ + sizeof(uint16_t) /*ccc handle*/ +
sizeof(uint8_t) /*direction*/ + sizeof(uint8_t) /*ase id*/;
static constexpr size_t LEAUDIO_STORAGE_HANDLES_ENTRIES_SZ =
LEAUDIO_STORAGE_MAGIC_SZ + sizeof(uint16_t) /*control point handle*/ +
sizeof(uint16_t) /*ccc handle*/ +
sizeof(uint16_t) /*sink audio location handle*/ +
sizeof(uint16_t) /*ccc handle*/ +
sizeof(uint16_t) /*source audio location handle*/ +
sizeof(uint16_t) /*ccc handle*/ +
sizeof(uint16_t) /*supported context type handle*/ +
sizeof(uint16_t) /*ccc handle*/ +
sizeof(uint16_t) /*available context type handle*/ +
sizeof(uint16_t) /*ccc handle*/ + sizeof(uint16_t) /* tmas handle */;
bool serializePacs(
const bluetooth::le_audio::types::PublishedAudioCapabilities& pacs,
std::vector<uint8_t>& out) {
auto num_of_pacs = pacs.size();
if (num_of_pacs == 0 || (num_of_pacs > std::numeric_limits<uint8_t>::max())) {
log::warn("No pacs available");
return false;
}
/* Calculate the total size */
auto pac_bin_size = LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ;
for (auto pac_tuple : pacs) {
auto& pac_recs = std::get<1>(pac_tuple);
pac_bin_size += LEAUDIO_PACS_ENTRY_HDR_SZ;
for (const auto& pac : pac_recs) {
pac_bin_size += LEAUDIO_PACS_ENTRY_SZ;
pac_bin_size += pac.metadata.size();
pac_bin_size += pac.codec_spec_caps_raw.size();
}
}
out.resize(pac_bin_size);
auto* ptr = out.data();
/* header */
UINT8_TO_STREAM(ptr, LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC);
UINT8_TO_STREAM(ptr, num_of_pacs);
/* pacs entries */
for (auto pac_tuple : pacs) {
auto& pac_recs = std::get<1>(pac_tuple);
uint16_t handle = std::get<0>(pac_tuple).val_hdl;
uint16_t ccc_handle = std::get<0>(pac_tuple).ccc_hdl;
UINT16_TO_STREAM(ptr, handle);
UINT16_TO_STREAM(ptr, ccc_handle);
UINT8_TO_STREAM(ptr, pac_recs.size());
log::verbose("Handle: 0x{:04x}, ccc handle: 0x{:04x}, pac count: {}",
handle, ccc_handle, static_cast<int>(pac_recs.size()));
for (const auto& pac : pac_recs) {
/* Pac len */
auto pac_len = LEAUDIO_PACS_ENTRY_SZ + pac.codec_spec_caps_raw.size() +
pac.metadata.size();
log::verbose("Pac size {}", static_cast<int>(pac_len));
UINT8_TO_STREAM(ptr, pac_len - 1 /* Minus size */);
/* Codec ID*/
UINT8_TO_STREAM(ptr, pac.codec_id.coding_format);
UINT16_TO_STREAM(ptr, pac.codec_id.vendor_company_id);
UINT16_TO_STREAM(ptr, pac.codec_id.vendor_codec_id);
/* Codec caps */
log::verbose("Codec capability size {}",
static_cast<int>(pac.codec_spec_caps_raw.size()));
UINT8_TO_STREAM(ptr, pac.codec_spec_caps_raw.size());
if (pac.codec_spec_caps_raw.size() > 0) {
ARRAY_TO_STREAM(ptr, pac.codec_spec_caps_raw.data(),
static_cast<int>(pac.codec_spec_caps_raw.size()));
}
/* Metadata */
log::verbose("Metadata size {}", static_cast<int>(pac.metadata.size()));
UINT8_TO_STREAM(ptr, pac.metadata.size());
if (pac.metadata.size() > 0) {
ARRAY_TO_STREAM(ptr, pac.metadata.data(), (int)pac.metadata.size());
}
}
}
return true;
}
bool SerializeSinkPacs(const bluetooth::le_audio::LeAudioDevice* leAudioDevice,
std::vector<uint8_t>& out) {
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
log::verbose("Device {}, num of PAC characteristics: {}",
leAudioDevice->address_,
static_cast<int>(leAudioDevice->snk_pacs_.size()));
return serializePacs(leAudioDevice->snk_pacs_, out);
}
bool SerializeSourcePacs(
const bluetooth::le_audio::LeAudioDevice* leAudioDevice,
std::vector<uint8_t>& out) {
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
log::verbose("Device {}, num of PAC characteristics: {}",
leAudioDevice->address_,
static_cast<int>(leAudioDevice->src_pacs_.size()));
return serializePacs(leAudioDevice->src_pacs_, out);
}
bool deserializePacs(LeAudioDevice* leAudioDevice,
types::PublishedAudioCapabilities& pacs_db,
const std::vector<uint8_t>& in) {
if (in.size() <
LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ + LEAUDIO_PACS_ENTRY_SZ) {
log::warn("There is not single PACS stored");
return false;
}
auto* ptr = in.data();
uint8_t magic;
STREAM_TO_UINT8(magic, ptr);
if (magic != LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC) {
log::error("Invalid magic ({}!={}) for device {}", magic,
LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC,
leAudioDevice->address_);
return false;
}
uint8_t num_of_pacs_chars;
STREAM_TO_UINT8(num_of_pacs_chars, ptr);
if (in.size() < LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ +
(num_of_pacs_chars * LEAUDIO_PACS_ENTRY_SZ)) {
log::error("Invalid persistent storage data for device {}",
leAudioDevice->address_);
return false;
}
/* pacs entries */
while (num_of_pacs_chars--) {
struct hdl_pair hdl_pair;
uint8_t pac_count;
STREAM_TO_UINT16(hdl_pair.val_hdl, ptr);
STREAM_TO_UINT16(hdl_pair.ccc_hdl, ptr);
STREAM_TO_UINT8(pac_count, ptr);
log::verbose("Handle: 0x{:04x}, ccc handle: 0x{:04x}, pac_count: {}",
hdl_pair.val_hdl, hdl_pair.ccc_hdl, pac_count);
pacs_db.push_back(std::make_tuple(
hdl_pair,
std::vector<struct bluetooth::le_audio::types::acs_ac_record>()));
auto hdl = hdl_pair.val_hdl;
auto pac_tuple_iter = std::find_if(
pacs_db.begin(), pacs_db.end(),
[&hdl](auto& pac_ent) { return std::get<0>(pac_ent).val_hdl == hdl; });
std::vector<struct bluetooth::le_audio::types::acs_ac_record> pac_recs;
while (pac_count--) {
uint8_t pac_len;
STREAM_TO_UINT8(pac_len, ptr);
log::verbose("Pac len {}", pac_len);
if (client_parser::pacs::ParseSinglePac(pac_recs, pac_len, ptr) < 0) {
log::error("Cannot parse stored PACs (impossible)");
return false;
}
ptr += pac_len;
}
leAudioDevice->RegisterPACs(&std::get<1>(*pac_tuple_iter), &pac_recs);
}
return true;
}
bool DeserializeSinkPacs(bluetooth::le_audio::LeAudioDevice* leAudioDevice,
const std::vector<uint8_t>& in) {
log::verbose("");
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
return deserializePacs(leAudioDevice, leAudioDevice->snk_pacs_, in);
}
bool DeserializeSourcePacs(bluetooth::le_audio::LeAudioDevice* leAudioDevice,
const std::vector<uint8_t>& in) {
log::verbose("");
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
return deserializePacs(leAudioDevice, leAudioDevice->src_pacs_, in);
}
bool SerializeAses(const bluetooth::le_audio::LeAudioDevice* leAudioDevice,
std::vector<uint8_t>& out) {
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
auto num_of_ases = leAudioDevice->ases_.size();
log::debug("device: {}, number of ases {}", leAudioDevice->address_,
static_cast<int>(num_of_ases));
if (num_of_ases == 0 || (num_of_ases > std::numeric_limits<uint8_t>::max())) {
log::warn("No ases available for device {}", leAudioDevice->address_);
return false;
}
/* Calculate the total size */
auto ases_bin_size = LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ +
num_of_ases * LEAUDIO_ASES_ENTRY_SZ;
out.resize(ases_bin_size);
auto* ptr = out.data();
/* header */
UINT8_TO_STREAM(ptr, LEAUDIO_ASE_STORAGE_CURRENT_LAYOUT_MAGIC);
UINT8_TO_STREAM(ptr, num_of_ases);
/* pacs entries */
for (const auto& ase : leAudioDevice->ases_) {
log::verbose(
"Storing ASE ID: {}, direction {}, handle 0x{:04x}, ccc_handle "
"0x{:04x}",
ase.id,
ase.direction == bluetooth::le_audio::types::kLeAudioDirectionSink
? "sink "
: "source",
ase.hdls.val_hdl, ase.hdls.ccc_hdl);
UINT16_TO_STREAM(ptr, ase.hdls.val_hdl);
UINT16_TO_STREAM(ptr, ase.hdls.ccc_hdl);
UINT8_TO_STREAM(ptr, ase.id);
UINT8_TO_STREAM(ptr, ase.direction);
}
return true;
}
bool DeserializeAses(bluetooth::le_audio::LeAudioDevice* leAudioDevice,
const std::vector<uint8_t>& in) {
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
if (in.size() <
LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ + LEAUDIO_ASES_ENTRY_SZ) {
log::warn("There is not single ASE stored for device {}",
leAudioDevice->address_);
return false;
}
auto* ptr = in.data();
uint8_t magic;
STREAM_TO_UINT8(magic, ptr);
if (magic != LEAUDIO_ASE_STORAGE_CURRENT_LAYOUT_MAGIC) {
log::error("Invalid magic ({}!={}", magic,
LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC);
return false;
}
uint8_t num_of_ases;
STREAM_TO_UINT8(num_of_ases, ptr);
if (in.size() < LEAUDIO_STORAGE_HEADER_WITH_ENTRIES_SZ +
(num_of_ases * LEAUDIO_ASES_ENTRY_SZ)) {
log::error("Invalid persistent storage data for device {}",
leAudioDevice->address_);
return false;
}
log::debug("Loading {} Ases for device {}", num_of_ases,
leAudioDevice->address_);
/* sets entries */
while (num_of_ases--) {
uint16_t handle;
uint16_t ccc_handle;
uint8_t direction;
uint8_t ase_id;
STREAM_TO_UINT16(handle, ptr);
STREAM_TO_UINT16(ccc_handle, ptr);
STREAM_TO_UINT8(ase_id, ptr);
STREAM_TO_UINT8(direction, ptr);
leAudioDevice->ases_.emplace_back(handle, ccc_handle, direction, ase_id);
log::verbose(
"Loading ASE ID: {}, direction {}, handle 0x{:04x}, ccc_handle "
"0x{:04x}",
ase_id,
direction == bluetooth::le_audio::types::kLeAudioDirectionSink
? "sink "
: "source",
handle, ccc_handle);
}
return true;
}
bool SerializeHandles(const LeAudioDevice* leAudioDevice,
std::vector<uint8_t>& out) {
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
/* Calculate the total size */
out.resize(LEAUDIO_STORAGE_HANDLES_ENTRIES_SZ);
auto* ptr = out.data();
/* header */
UINT8_TO_STREAM(ptr, LEAUDIO_HANDLES_STORAGE_CURRENT_LAYOUT_MAGIC);
if (leAudioDevice->ctp_hdls_.val_hdl == 0 ||
leAudioDevice->ctp_hdls_.ccc_hdl == 0) {
log::warn("Invalid control point handles for device {}",
leAudioDevice->address_);
return false;
}
UINT16_TO_STREAM(ptr, leAudioDevice->ctp_hdls_.val_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->ctp_hdls_.ccc_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->snk_audio_locations_hdls_.val_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->snk_audio_locations_hdls_.ccc_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->src_audio_locations_hdls_.val_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->src_audio_locations_hdls_.ccc_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->audio_supp_cont_hdls_.val_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->audio_supp_cont_hdls_.ccc_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->audio_avail_hdls_.val_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->audio_avail_hdls_.ccc_hdl);
UINT16_TO_STREAM(ptr, leAudioDevice->tmap_role_hdl_);
return true;
}
bool DeserializeHandles(LeAudioDevice* leAudioDevice,
const std::vector<uint8_t>& in) {
if (leAudioDevice == nullptr) {
log::warn("Skipping unknown device");
return false;
}
if (in.size() != LEAUDIO_STORAGE_HANDLES_ENTRIES_SZ) {
log::warn("There is not single ASE stored for device {}",
leAudioDevice->address_);
return false;
}
auto* ptr = in.data();
uint8_t magic;
STREAM_TO_UINT8(magic, ptr);
if (magic != LEAUDIO_HANDLES_STORAGE_CURRENT_LAYOUT_MAGIC) {
log::error("Invalid magic ({}!={}) for device {}", magic,
LEAUDIO_PACS_STORAGE_CURRENT_LAYOUT_MAGIC,
leAudioDevice->address_);
return false;
}
STREAM_TO_UINT16(leAudioDevice->ctp_hdls_.val_hdl, ptr);
STREAM_TO_UINT16(leAudioDevice->ctp_hdls_.ccc_hdl, ptr);
log::verbose("ctp.val_hdl: 0x{:04x}, ctp.ccc_hdl: 0x{:04x}",
leAudioDevice->ctp_hdls_.val_hdl,
leAudioDevice->ctp_hdls_.ccc_hdl);
STREAM_TO_UINT16(leAudioDevice->snk_audio_locations_hdls_.val_hdl, ptr);
STREAM_TO_UINT16(leAudioDevice->snk_audio_locations_hdls_.ccc_hdl, ptr);
log::verbose(
"snk_audio_locations_hdls_.val_hdl: "
"0x{:04x},snk_audio_locations_hdls_.ccc_hdl: 0x{:04x}",
leAudioDevice->snk_audio_locations_hdls_.val_hdl,
leAudioDevice->snk_audio_locations_hdls_.ccc_hdl);
STREAM_TO_UINT16(leAudioDevice->src_audio_locations_hdls_.val_hdl, ptr);
STREAM_TO_UINT16(leAudioDevice->src_audio_locations_hdls_.ccc_hdl, ptr);
log::verbose(
"src_audio_locations_hdls_.val_hdl: "
"0x{:04x},src_audio_locations_hdls_.ccc_hdl: 0x{:04x}",
leAudioDevice->src_audio_locations_hdls_.val_hdl,
leAudioDevice->src_audio_locations_hdls_.ccc_hdl);
STREAM_TO_UINT16(leAudioDevice->audio_supp_cont_hdls_.val_hdl, ptr);
STREAM_TO_UINT16(leAudioDevice->audio_supp_cont_hdls_.ccc_hdl, ptr);
log::verbose(
"audio_supp_cont_hdls_.val_hdl: 0x{:04x},audio_supp_cont_hdls_.ccc_hdl: "
"0x{:04x}",
leAudioDevice->audio_supp_cont_hdls_.val_hdl,
leAudioDevice->audio_supp_cont_hdls_.ccc_hdl);
STREAM_TO_UINT16(leAudioDevice->audio_avail_hdls_.val_hdl, ptr);
STREAM_TO_UINT16(leAudioDevice->audio_avail_hdls_.ccc_hdl, ptr);
log::verbose(
"audio_avail_hdls_.val_hdl: 0x{:04x},audio_avail_hdls_.ccc_hdl: 0x{:04x}",
leAudioDevice->audio_avail_hdls_.val_hdl,
leAudioDevice->audio_avail_hdls_.ccc_hdl);
STREAM_TO_UINT16(leAudioDevice->tmap_role_hdl_, ptr);
log::verbose("tmap_role_hdl_: 0x{:04x}", leAudioDevice->tmap_role_hdl_);
leAudioDevice->known_service_handles_ = true;
return true;
}
} // namespace bluetooth::le_audio