Add a generic function to retrieve any data based on an assigned numbers type. This function can in theory be used for any data type, and not just LE Audio types, but since it relies on bt_audio_data_parse it was made specificially for LE Audio. The function can be used in cases where bt_audio_codec_cfg_get_val, bt_audio_codec_cfg_meta_get_val, bt_audio_codec_cap_get_val or bt_audio_codec_cap_meta_get_val (or their derivation) are not easily applicable due to the type constrainst. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
2276 lines
53 KiB
C
2276 lines
53 KiB
C
/*
|
|
* Copyright (c) 2022 Bose Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
/** @file
|
|
* @brief Bluetooth LE-Audio codec LTV parsing
|
|
*
|
|
* Helper functions to parse codec config data as specified in the Bluetooth assigned numbers for
|
|
* Generic Audio.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <zephyr/autoconf.h>
|
|
#include <zephyr/bluetooth/audio/audio.h>
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/net_buf.h>
|
|
#include <zephyr/sys/byteorder.h>
|
|
#include <zephyr/sys/check.h>
|
|
#include <zephyr/sys/util.h>
|
|
|
|
LOG_MODULE_REGISTER(bt_audio_codec, CONFIG_BT_AUDIO_CODEC_LOG_LEVEL);
|
|
|
|
int bt_audio_codec_cfg_freq_to_freq_hz(enum bt_audio_codec_cfg_freq freq)
|
|
{
|
|
switch (freq) {
|
|
case BT_AUDIO_CODEC_CFG_FREQ_8KHZ:
|
|
return 8000;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_11KHZ:
|
|
return 11025;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_16KHZ:
|
|
return 16000;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_22KHZ:
|
|
return 22050;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_24KHZ:
|
|
return 24000;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_32KHZ:
|
|
return 32000;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_44KHZ:
|
|
return 44100;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_48KHZ:
|
|
return 48000;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_88KHZ:
|
|
return 88200;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_96KHZ:
|
|
return 96000;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_176KHZ:
|
|
return 176400;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_192KHZ:
|
|
return 192000;
|
|
case BT_AUDIO_CODEC_CFG_FREQ_384KHZ:
|
|
return 384000;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
int bt_audio_codec_cfg_freq_hz_to_freq(uint32_t freq_hz)
|
|
{
|
|
switch (freq_hz) {
|
|
case 8000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_8KHZ;
|
|
case 11025U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_11KHZ;
|
|
case 16000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_16KHZ;
|
|
case 22050U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_22KHZ;
|
|
case 24000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_24KHZ;
|
|
case 32000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_32KHZ;
|
|
case 44100U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_44KHZ;
|
|
case 48000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_48KHZ;
|
|
case 88200U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_88KHZ;
|
|
case 96000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_96KHZ;
|
|
case 176400U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_176KHZ;
|
|
case 192000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_192KHZ;
|
|
case 384000U:
|
|
return BT_AUDIO_CODEC_CFG_FREQ_384KHZ;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
int bt_audio_codec_cfg_frame_dur_to_frame_dur_us(enum bt_audio_codec_cfg_frame_dur frame_dur)
|
|
{
|
|
switch (frame_dur) {
|
|
case BT_AUDIO_CODEC_CFG_DURATION_7_5:
|
|
return 7500;
|
|
case BT_AUDIO_CODEC_CFG_DURATION_10:
|
|
return 10000;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
int bt_audio_codec_cfg_frame_dur_us_to_frame_dur(uint32_t frame_dur_us)
|
|
{
|
|
switch (frame_dur_us) {
|
|
case 7500U:
|
|
return BT_AUDIO_CODEC_CFG_DURATION_7_5;
|
|
case 10000U:
|
|
return BT_AUDIO_CODEC_CFG_DURATION_10;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 || \
|
|
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \
|
|
CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 || \
|
|
CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0
|
|
|
|
static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t *data,
|
|
size_t data_len)
|
|
{
|
|
size_t new_buf_len;
|
|
|
|
for (uint16_t i = 0U; i < buf->len;) {
|
|
uint8_t *len = &buf->data[i++];
|
|
const uint8_t data_type = buf->data[i++];
|
|
const uint8_t value_len = *len - sizeof(data_type);
|
|
|
|
if (data_type == type) {
|
|
uint8_t *value = &buf->data[i];
|
|
|
|
if (data_len == value_len) {
|
|
memcpy(value, data, data_len);
|
|
} else {
|
|
const int16_t diff = data_len - value_len;
|
|
uint8_t *old_next_data_start;
|
|
uint8_t *new_next_data_start;
|
|
uint8_t data_len_to_move;
|
|
|
|
/* Check if this is the last value in the buffer */
|
|
if (value + value_len == buf->data + buf->len) {
|
|
data_len_to_move = 0U;
|
|
} else {
|
|
old_next_data_start = value + value_len;
|
|
new_next_data_start = value + data_len;
|
|
data_len_to_move =
|
|
buf->len - (old_next_data_start - buf->data);
|
|
}
|
|
|
|
if (diff < 0) {
|
|
/* In this case we need to move memory around after the copy
|
|
* to fit the new shorter data
|
|
*/
|
|
|
|
memcpy(value, data, data_len);
|
|
if (data_len_to_move > 0U) {
|
|
memmove(new_next_data_start, old_next_data_start,
|
|
data_len_to_move);
|
|
}
|
|
} else {
|
|
/* In this case we need to move memory around before
|
|
* the copy to fit the new longer data
|
|
*/
|
|
if ((buf->len + diff) > buf->size) {
|
|
LOG_DBG("Cannot fit data_len %zu in buf with len "
|
|
"%u and size %u",
|
|
data_len, buf->len, buf->size);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (data_len_to_move > 0) {
|
|
memmove(new_next_data_start, old_next_data_start,
|
|
data_len_to_move);
|
|
}
|
|
memcpy(value, data, data_len);
|
|
}
|
|
|
|
buf->len += diff;
|
|
*len += diff;
|
|
}
|
|
|
|
return buf->len;
|
|
}
|
|
|
|
i += value_len;
|
|
}
|
|
|
|
/* If we reach here, we did not find the data in the buffer, so we simply add it */
|
|
new_buf_len = buf->len + 1 /* len */ + sizeof(type) + data_len;
|
|
if (new_buf_len <= buf->size) {
|
|
net_buf_simple_add_u8(buf, data_len + sizeof(type)); /* len */
|
|
net_buf_simple_add_u8(buf, type); /* type */
|
|
if (data_len > 0) {
|
|
net_buf_simple_add_mem(buf, data, data_len); /* value */
|
|
}
|
|
} else {
|
|
LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len,
|
|
buf->len, buf->size);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return buf->len;
|
|
}
|
|
|
|
static int ltv_unset_val(struct net_buf_simple *buf, uint8_t type)
|
|
{
|
|
for (uint16_t i = 0U; i < buf->len;) {
|
|
uint8_t *ltv_start = &buf->data[i];
|
|
const uint8_t len = buf->data[i++];
|
|
const uint8_t data_type = buf->data[i++];
|
|
const uint8_t value_len = len - sizeof(data_type);
|
|
|
|
if (data_type == type) {
|
|
const uint8_t ltv_size = value_len + sizeof(data_type) + sizeof(len);
|
|
uint8_t *value = &buf->data[i];
|
|
|
|
/* Check if this is not the last value in the buffer */
|
|
if (value + value_len != buf->data + buf->len) {
|
|
uint8_t *next_data_start;
|
|
uint8_t data_len_to_move;
|
|
|
|
next_data_start = value + value_len;
|
|
data_len_to_move = buf->len - (next_data_start - buf->data);
|
|
memmove(ltv_start, next_data_start, data_len_to_move);
|
|
|
|
LOG_ERR("buf->data %p, ltv_start %p, value_len %u next_data_start "
|
|
"%p data_len_to_move %u",
|
|
buf->data, ltv_start, value_len, next_data_start,
|
|
data_len_to_move);
|
|
} /* else just reduce the length of the buffer */
|
|
|
|
buf->len -= ltv_size;
|
|
|
|
return buf->len;
|
|
}
|
|
|
|
i += value_len;
|
|
}
|
|
|
|
return buf->len;
|
|
}
|
|
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 || \
|
|
* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \
|
|
* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 || \
|
|
* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \
|
|
*/
|
|
|
|
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
|
|
|
static void init_net_buf_simple_from_codec_cfg(struct net_buf_simple *buf,
|
|
struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
buf->__buf = codec_cfg->data;
|
|
buf->data = codec_cfg->data;
|
|
buf->size = sizeof(codec_cfg->data);
|
|
buf->len = codec_cfg->data_len;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_codec_cfg_type type, const uint8_t **data)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data == NULL) {
|
|
LOG_DBG("data is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return bt_audio_data_get_val(codec_cfg->data, codec_cfg->data_len, (uint8_t)type, data);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_codec_cfg_type type, const uint8_t *data,
|
|
size_t data_len)
|
|
{
|
|
struct net_buf_simple buf;
|
|
int ret;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data == NULL) {
|
|
LOG_DBG("data is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data_len == 0U || data_len > UINT8_MAX) {
|
|
LOG_DBG("Invalid data_len %zu", data_len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
init_net_buf_simple_from_codec_cfg(&buf, codec_cfg);
|
|
|
|
ret = ltv_set_val(&buf, type, data, data_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->data_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_codec_cfg_type type)
|
|
{
|
|
struct net_buf_simple buf;
|
|
int ret;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
init_net_buf_simple_from_codec_cfg(&buf, codec_cfg);
|
|
|
|
ret = ltv_unset_val(&buf, type);
|
|
if (ret >= 0) {
|
|
codec_cfg->data_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
enum bt_audio_codec_cfg_freq freq;
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len = bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_FREQ, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
freq = data[0];
|
|
if (bt_audio_codec_cfg_freq_to_freq_hz(freq) < 0) {
|
|
LOG_DBG("Invalid freq value: 0x%02X", freq);
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_set_freq(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_codec_cfg_freq freq)
|
|
{
|
|
uint8_t freq_u8;
|
|
|
|
if (bt_audio_codec_cfg_freq_to_freq_hz(freq) < 0) {
|
|
LOG_DBG("Invalid freq value: %d", freq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
freq_u8 = (uint8_t)freq;
|
|
|
|
return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_FREQ, &freq_u8,
|
|
sizeof(freq_u8));
|
|
}
|
|
|
|
int bt_audio_codec_cfg_get_frame_dur(const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
enum bt_audio_codec_cfg_frame_dur frame_dur;
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len = bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_DURATION, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
frame_dur = data[0];
|
|
if (bt_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur) < 0) {
|
|
LOG_DBG("Invalid frame_dur value: 0x%02X", frame_dur);
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return frame_dur;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_set_frame_dur(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_codec_cfg_frame_dur frame_dur)
|
|
{
|
|
uint8_t frame_dur_u8;
|
|
|
|
if (bt_audio_codec_cfg_frame_dur_to_frame_dur_us(frame_dur) < 0) {
|
|
LOG_DBG("Invalid freq value: %d", frame_dur);
|
|
return -EINVAL;
|
|
}
|
|
|
|
frame_dur_u8 = (uint8_t)frame_dur;
|
|
|
|
return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_DURATION,
|
|
&frame_dur_u8, sizeof(frame_dur_u8));
|
|
}
|
|
|
|
int bt_audio_codec_cfg_get_chan_allocation(const struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_location *chan_allocation,
|
|
bool fallback_to_default)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
*chan_allocation = 0;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(chan_allocation == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len =
|
|
bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_CHAN_ALLOC, &data);
|
|
if (data == NULL) {
|
|
if (fallback_to_default && codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
|
|
*chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO;
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint32_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
*chan_allocation = sys_get_le32(data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_set_chan_allocation(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_location chan_allocation)
|
|
{
|
|
uint32_t chan_allocation_u32;
|
|
|
|
if ((chan_allocation & BT_AUDIO_LOCATION_ANY) != chan_allocation) {
|
|
LOG_DBG("Invalid chan_allocation value: 0x%08X", chan_allocation);
|
|
return -EINVAL;
|
|
}
|
|
|
|
chan_allocation_u32 = sys_cpu_to_le32((uint32_t)chan_allocation);
|
|
|
|
return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
|
|
(const uint8_t *)&chan_allocation_u32,
|
|
sizeof(chan_allocation_u32));
|
|
}
|
|
|
|
int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len =
|
|
bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CFG_FRAME_LEN, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint16_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return sys_get_le16(data);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_set_octets_per_frame(struct bt_audio_codec_cfg *codec_cfg,
|
|
uint16_t octets_per_frame)
|
|
{
|
|
uint16_t octets_per_frame_le16;
|
|
|
|
octets_per_frame_le16 = sys_cpu_to_le16(octets_per_frame);
|
|
|
|
return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_FRAME_LEN,
|
|
(uint8_t *)&octets_per_frame_le16,
|
|
sizeof(octets_per_frame_le16));
|
|
}
|
|
|
|
int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg *codec_cfg,
|
|
bool fallback_to_default)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len = bt_audio_codec_cfg_get_val(codec_cfg,
|
|
BT_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU, &data);
|
|
if (data == NULL) {
|
|
if (fallback_to_default && codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
|
|
return 1;
|
|
}
|
|
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return data[0];
|
|
}
|
|
|
|
int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec_cfg,
|
|
uint8_t frame_blocks)
|
|
{
|
|
return bt_audio_codec_cfg_set_val(codec_cfg, BT_AUDIO_CODEC_CFG_FRAME_BLKS_PER_SDU,
|
|
&frame_blocks, sizeof(frame_blocks));
|
|
}
|
|
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
|
|
|
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \
|
|
CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0
|
|
|
|
static void init_net_buf_simple_from_meta(struct net_buf_simple *buf, uint8_t meta[],
|
|
size_t meta_len, size_t meta_size)
|
|
{
|
|
buf->__buf = meta;
|
|
buf->data = meta;
|
|
buf->size = meta_size;
|
|
buf->len = meta_len;
|
|
}
|
|
|
|
static int codec_meta_get_val(const uint8_t meta[], size_t meta_len,
|
|
enum bt_audio_metadata_type type, const uint8_t **data)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data == NULL) {
|
|
LOG_DBG("data is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return bt_audio_data_get_val(meta, meta_len, (uint8_t)type, data);
|
|
}
|
|
|
|
static int codec_meta_set_val(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
enum bt_audio_metadata_type type, const uint8_t *data,
|
|
size_t data_len)
|
|
{
|
|
struct net_buf_simple buf;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data == NULL && data_len != 0) {
|
|
LOG_DBG("data is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data_len > UINT8_MAX) {
|
|
LOG_DBG("Invalid data_len %zu", data_len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
init_net_buf_simple_from_meta(&buf, meta, meta_len, meta_size);
|
|
|
|
return ltv_set_val(&buf, (uint8_t)type, data, data_len);
|
|
}
|
|
|
|
static int codec_meta_unset_val(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
enum bt_audio_metadata_type type)
|
|
{
|
|
struct net_buf_simple buf;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
init_net_buf_simple_from_meta(&buf, meta, meta_len, meta_size);
|
|
|
|
return ltv_unset_val(&buf, type);
|
|
}
|
|
|
|
static int codec_meta_get_pref_context(const uint8_t meta[], size_t meta_len)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (ret != sizeof(uint16_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return sys_get_le16(data);
|
|
}
|
|
|
|
static int codec_meta_set_pref_context(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
enum bt_audio_context ctx)
|
|
{
|
|
uint16_t ctx_le16;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) {
|
|
LOG_DBG("Invalid ctx value: %d", ctx);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ctx_le16 = sys_cpu_to_le16((uint16_t)ctx);
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT,
|
|
(const uint8_t *)&ctx_le16, sizeof(ctx_le16));
|
|
}
|
|
|
|
static int codec_meta_get_stream_context(const uint8_t meta[], size_t meta_len)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (ret != sizeof(uint16_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return sys_get_le16(data);
|
|
}
|
|
|
|
static int codec_meta_set_stream_context(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
enum bt_audio_context ctx)
|
|
{
|
|
uint16_t ctx_le16;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((ctx & BT_AUDIO_CONTEXT_TYPE_ANY) != ctx) {
|
|
LOG_DBG("Invalid ctx value: %d", ctx);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ctx_le16 = sys_cpu_to_le16((uint16_t)ctx);
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
|
(const uint8_t *)&ctx_le16, sizeof(ctx_le16));
|
|
}
|
|
|
|
static int codec_meta_get_program_info(const uint8_t meta[], size_t meta_len,
|
|
const uint8_t **program_info)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(program_info == NULL) {
|
|
LOG_DBG("program_info is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
*program_info = data;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int codec_meta_set_program_info(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
const uint8_t *program_info, size_t program_info_len)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(program_info == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO,
|
|
program_info, program_info_len);
|
|
}
|
|
|
|
static int codec_meta_get_lang(const uint8_t meta[], size_t meta_len, const uint8_t **lang)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(lang == NULL) {
|
|
LOG_DBG("lang is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_LANG, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (ret != BT_AUDIO_LANG_SIZE) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
*lang = data;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int codec_meta_set_lang(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
const uint8_t lang[BT_AUDIO_LANG_SIZE])
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(lang == NULL) {
|
|
LOG_DBG("lang is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_LANG, lang,
|
|
BT_AUDIO_LANG_SIZE);
|
|
}
|
|
|
|
static int codec_meta_get_ccid_list(const uint8_t meta[], size_t meta_len,
|
|
const uint8_t **ccid_list)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(ccid_list == NULL) {
|
|
LOG_DBG("ccid_list is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_CCID_LIST, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
*ccid_list = data;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int codec_meta_set_ccid_list(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
const uint8_t *ccid_list, size_t ccid_list_len)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(ccid_list == NULL) {
|
|
LOG_DBG("ccid_list is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_CCID_LIST,
|
|
ccid_list, ccid_list_len);
|
|
}
|
|
|
|
static int codec_meta_get_parental_rating(const uint8_t meta[], size_t meta_len)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (ret != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return data[0];
|
|
}
|
|
|
|
static int codec_meta_set_parental_rating(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
enum bt_audio_parental_rating parental_rating)
|
|
{
|
|
uint8_t parental_rating_u8;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (parental_rating > BT_AUDIO_PARENTAL_RATING_AGE_18_OR_ABOVE) {
|
|
LOG_DBG("Invalid parental_rating value: %d", parental_rating);
|
|
return -EINVAL;
|
|
}
|
|
|
|
parental_rating_u8 = (uint8_t)parental_rating;
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_PARENTAL_RATING,
|
|
&parental_rating_u8, sizeof(parental_rating_u8));
|
|
}
|
|
|
|
static int codec_meta_get_program_info_uri(const uint8_t meta[], size_t meta_len,
|
|
const uint8_t **program_info_uri)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(program_info_uri == NULL) {
|
|
LOG_DBG("program_info_uri is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
*program_info_uri = data;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int codec_meta_set_program_info_uri(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
const uint8_t *program_info_uri,
|
|
size_t program_info_uri_len)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(program_info_uri == NULL) {
|
|
LOG_DBG("program_info_uri is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size,
|
|
BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI, program_info_uri,
|
|
program_info_uri_len);
|
|
}
|
|
|
|
static int codec_meta_get_audio_active_state(const uint8_t meta[], size_t meta_len)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_AUDIO_STATE, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (ret != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return data[0];
|
|
}
|
|
|
|
static int codec_meta_set_audio_active_state(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
enum bt_audio_active_state state)
|
|
{
|
|
uint8_t state_u8;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (state != BT_AUDIO_ACTIVE_STATE_DISABLED && state != BT_AUDIO_ACTIVE_STATE_ENABLED) {
|
|
LOG_DBG("Invalid state value: %d", state);
|
|
return -EINVAL;
|
|
}
|
|
|
|
state_u8 = (uint8_t)state;
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_AUDIO_STATE,
|
|
&state_u8, sizeof(state_u8));
|
|
}
|
|
|
|
static int codec_meta_get_bcast_audio_immediate_rend_flag(const uint8_t meta[], size_t meta_len)
|
|
{
|
|
const uint8_t *data;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE,
|
|
&data);
|
|
}
|
|
|
|
static int codec_meta_set_bcast_audio_immediate_rend_flag(uint8_t meta[], size_t meta_len,
|
|
size_t meta_size)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size,
|
|
BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE, NULL, 0);
|
|
}
|
|
|
|
static int codec_meta_get_assisted_listening_stream(const uint8_t meta[], size_t meta_len)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM,
|
|
&data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (ret != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return data[0];
|
|
}
|
|
|
|
static int codec_meta_set_assisted_listening_stream(uint8_t meta[], size_t meta_len,
|
|
size_t meta_size,
|
|
enum bt_audio_assisted_listening_stream val)
|
|
{
|
|
uint8_t val_u8;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (val != BT_AUDIO_ASSISTED_LISTENING_STREAM_UNSPECIFIED) {
|
|
LOG_DBG("Invalid value: %d", val);
|
|
return -EINVAL;
|
|
}
|
|
|
|
val_u8 = (uint8_t)val;
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size,
|
|
BT_AUDIO_METADATA_TYPE_ASSISTED_LISTENING_STREAM, &val_u8,
|
|
sizeof(val_u8));
|
|
}
|
|
|
|
static int codec_meta_get_broadcast_name(const uint8_t meta[], size_t meta_len,
|
|
const uint8_t **broadcast_name)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(broadcast_name == NULL) {
|
|
LOG_DBG("broadcast_name is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_BROADCAST_NAME, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
*broadcast_name = data;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int codec_meta_set_broadcast_name(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
const uint8_t *broadcast_name, size_t broadcast_name_len)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(broadcast_name == NULL) {
|
|
LOG_DBG("broadcast_name is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_BROADCAST_NAME,
|
|
broadcast_name, broadcast_name_len);
|
|
}
|
|
|
|
static int codec_meta_get_extended(const uint8_t meta[], size_t meta_len,
|
|
const uint8_t **extended_meta)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(extended_meta == NULL) {
|
|
LOG_DBG("extended_meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_EXTENDED, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
*extended_meta = data;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int codec_meta_set_extended(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
const uint8_t *extended, size_t extended_len)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(extended == NULL) {
|
|
LOG_DBG("extended is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_EXTENDED,
|
|
extended, extended_len);
|
|
}
|
|
|
|
static int codec_meta_get_vendor(const uint8_t meta[], size_t meta_len, const uint8_t **vendor_meta)
|
|
{
|
|
const uint8_t *data;
|
|
int ret;
|
|
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(vendor_meta == NULL) {
|
|
LOG_DBG("vendor_meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_val(meta, meta_len, BT_AUDIO_METADATA_TYPE_VENDOR, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
*vendor_meta = data;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int codec_meta_set_vendor(uint8_t meta[], size_t meta_len, size_t meta_size,
|
|
const uint8_t *vendor, size_t vendor_len)
|
|
{
|
|
CHECKIF(meta == NULL) {
|
|
LOG_DBG("meta is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(vendor == NULL) {
|
|
LOG_DBG("vendor is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_set_val(meta, meta_len, meta_size, BT_AUDIO_METADATA_TYPE_VENDOR, vendor,
|
|
vendor_len);
|
|
}
|
|
|
|
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
|
int bt_audio_codec_cfg_meta_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
|
|
const uint8_t **data)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_val(codec_cfg->meta, codec_cfg->meta_len, type, data);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_metadata_type type, const uint8_t *data,
|
|
size_t data_len)
|
|
{
|
|
int ret;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_set_val(codec_cfg->meta, codec_cfg->meta_len, ARRAY_SIZE(codec_cfg->meta),
|
|
type, data, data_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_metadata_type type)
|
|
{
|
|
int ret;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_unset_val(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), type);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg,
|
|
bool fallback_to_default)
|
|
{
|
|
int ret;
|
|
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_get_pref_context(codec_cfg->meta, codec_cfg->meta_len);
|
|
|
|
if (ret == -ENODATA && fallback_to_default && codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
|
|
return BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_pref_context(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_context ctx)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_pref_context(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), ctx);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_stream_context(const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_stream_context(codec_cfg->meta, codec_cfg->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_stream_context(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_context ctx)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_stream_context(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), ctx);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_program_info(const struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t **program_info)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_program_info(codec_cfg->meta, codec_cfg->meta_len, program_info);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_program_info(struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t *program_info, size_t program_info_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_program_info(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), program_info,
|
|
program_info_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_lang(const struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t **lang)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_lang(codec_cfg->meta, codec_cfg->meta_len, lang);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_lang(struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t lang[BT_AUDIO_LANG_SIZE])
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_lang(codec_cfg->meta, codec_cfg->meta_len, ARRAY_SIZE(codec_cfg->meta),
|
|
lang);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_ccid_list(const struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t **ccid_list)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_ccid_list(codec_cfg->meta, codec_cfg->meta_len, ccid_list);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_ccid_list(struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t *ccid_list, size_t ccid_list_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_ccid_list(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), ccid_list, ccid_list_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_parental_rating(const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_parental_rating(codec_cfg->meta, codec_cfg->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_parental_rating(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_parental_rating parental_rating)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_parental_rating(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), parental_rating);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_program_info_uri(const struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t **program_info_uri)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_program_info_uri(codec_cfg->meta, codec_cfg->meta_len,
|
|
program_info_uri);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_program_info_uri(struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t *program_info_uri,
|
|
size_t program_info_uri_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_program_info_uri(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), program_info_uri,
|
|
program_info_uri_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_audio_active_state(const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_audio_active_state(codec_cfg->meta, codec_cfg->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_audio_active_state(struct bt_audio_codec_cfg *codec_cfg,
|
|
enum bt_audio_active_state state)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_audio_active_state(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), state);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_bcast_audio_immediate_rend_flag(
|
|
const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag(
|
|
struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta));
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_assisted_listening_stream(
|
|
const struct bt_audio_codec_cfg *codec_cfg)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_assisted_listening_stream(codec_cfg->meta, codec_cfg->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_assisted_listening_stream(
|
|
struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_assisted_listening_stream val)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_assisted_listening_stream(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), val);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_extended(const struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t **extended_meta)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_extended(codec_cfg->meta, codec_cfg->meta_len, extended_meta);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_extended(struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t *extended_meta, size_t extended_meta_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_extended(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), extended_meta,
|
|
extended_meta_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_vendor(const struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t **vendor_meta)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_vendor(codec_cfg->meta, codec_cfg->meta_len, vendor_meta);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t *vendor_meta, size_t vendor_meta_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_vendor(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), vendor_meta, vendor_meta_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_get_broadcast_name(const struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t **broadcast_name)
|
|
{
|
|
CHECKIF(codec_cfg == NULL) {
|
|
LOG_DBG("codec_cfg is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_broadcast_name(codec_cfg->meta, codec_cfg->meta_len, broadcast_name);
|
|
}
|
|
|
|
int bt_audio_codec_cfg_meta_set_broadcast_name(struct bt_audio_codec_cfg *codec_cfg,
|
|
const uint8_t *broadcast_name,
|
|
size_t broadcast_name_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_broadcast_name(codec_cfg->meta, codec_cfg->meta_len,
|
|
ARRAY_SIZE(codec_cfg->meta), broadcast_name,
|
|
broadcast_name_len);
|
|
if (ret >= 0) {
|
|
codec_cfg->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
|
|
|
|
#if CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0
|
|
int bt_audio_codec_cap_meta_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type,
|
|
const uint8_t **data)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_val(codec_cap->meta, codec_cap->meta_len, type, data);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_metadata_type type, const uint8_t *data,
|
|
size_t data_len)
|
|
{
|
|
int ret;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_set_val(codec_cap->meta, codec_cap->meta_len, ARRAY_SIZE(codec_cap->meta),
|
|
type, data, data_len);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_metadata_type type)
|
|
{
|
|
int ret;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = codec_meta_unset_val(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), type);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_pref_context(codec_cap->meta, codec_cap->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_pref_context(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_context ctx)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_pref_context(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), ctx);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_stream_context(const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_stream_context(codec_cap->meta, codec_cap->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_stream_context(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_context ctx)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_stream_context(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), ctx);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_program_info(const struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t **program_info)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_program_info(codec_cap->meta, codec_cap->meta_len, program_info);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_program_info(struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t *program_info, size_t program_info_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_program_info(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), program_info,
|
|
program_info_len);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_lang(const struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t **lang)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_lang(codec_cap->meta, codec_cap->meta_len, lang);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_lang(struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t lang[BT_AUDIO_LANG_SIZE])
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_lang(codec_cap->meta, codec_cap->meta_len, ARRAY_SIZE(codec_cap->meta),
|
|
lang);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_ccid_list(const struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t **ccid_list)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_ccid_list(codec_cap->meta, codec_cap->meta_len, ccid_list);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_ccid_list(struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t *ccid_list, size_t ccid_list_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_ccid_list(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), ccid_list, ccid_list_len);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_parental_rating(const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_parental_rating(codec_cap->meta, codec_cap->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_parental_rating(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_parental_rating parental_rating)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_parental_rating(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), parental_rating);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_program_info_uri(const struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t **program_info_uri)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_program_info_uri(codec_cap->meta, codec_cap->meta_len,
|
|
program_info_uri);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_program_info_uri(struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t *program_info_uri,
|
|
size_t program_info_uri_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_program_info_uri(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), program_info_uri,
|
|
program_info_uri_len);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_audio_active_state(const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_audio_active_state(codec_cap->meta, codec_cap->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_audio_active_state(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_active_state state)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_audio_active_state(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), state);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_bcast_audio_immediate_rend_flag(
|
|
const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_bcast_audio_immediate_rend_flag(
|
|
struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_bcast_audio_immediate_rend_flag(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta));
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_assisted_listening_stream(
|
|
const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_assisted_listening_stream(codec_cap->meta, codec_cap->meta_len);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_assisted_listening_stream(
|
|
struct bt_audio_codec_cap *codec_cap, enum bt_audio_assisted_listening_stream val)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_assisted_listening_stream(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), val);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t **extended_meta)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_extended(codec_cap->meta, codec_cap->meta_len, extended_meta);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_extended(struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t *extended_meta, size_t extended_meta_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_extended(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), extended_meta,
|
|
extended_meta_len);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t **vendor_meta)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_vendor(codec_cap->meta, codec_cap->meta_len, vendor_meta);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_vendor(struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t *vendor_meta, size_t vendor_meta_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_vendor(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), vendor_meta, vendor_meta_len);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_get_broadcast_name(const struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t **broadcast_name)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return codec_meta_get_broadcast_name(codec_cap->meta, codec_cap->meta_len, broadcast_name);
|
|
}
|
|
|
|
int bt_audio_codec_cap_meta_set_broadcast_name(struct bt_audio_codec_cap *codec_cap,
|
|
const uint8_t *broadcast_name,
|
|
size_t broadcast_name_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = codec_meta_set_broadcast_name(codec_cap->meta, codec_cap->meta_len,
|
|
ARRAY_SIZE(codec_cap->meta), broadcast_name,
|
|
broadcast_name_len);
|
|
if (ret >= 0) {
|
|
codec_cap->meta_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 */
|
|
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \
|
|
* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE > 0 \
|
|
*/
|
|
|
|
#if CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0
|
|
|
|
static void init_net_buf_simple_from_codec_cap(struct net_buf_simple *buf,
|
|
struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
buf->__buf = codec_cap->data;
|
|
buf->data = codec_cap->data;
|
|
buf->size = sizeof(codec_cap->data);
|
|
buf->len = codec_cap->data_len;
|
|
}
|
|
|
|
int bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_codec_cap_type type, const uint8_t **data)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data == NULL) {
|
|
LOG_DBG("data is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return bt_audio_data_get_val(codec_cap->data, codec_cap->data_len, (uint8_t)type, data);
|
|
}
|
|
|
|
int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_codec_cap_type type, const uint8_t *data,
|
|
size_t data_len)
|
|
{
|
|
struct net_buf_simple buf;
|
|
int ret;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data == NULL) {
|
|
LOG_DBG("data is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(data_len == 0U || data_len > UINT8_MAX) {
|
|
LOG_DBG("Invalid data_len %zu", data_len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
init_net_buf_simple_from_codec_cap(&buf, codec_cap);
|
|
|
|
ret = ltv_set_val(&buf, type, data, data_len);
|
|
if (ret >= 0) {
|
|
codec_cap->data_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_codec_cap_type type)
|
|
{
|
|
struct net_buf_simple buf;
|
|
int ret;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
init_net_buf_simple_from_codec_cap(&buf, codec_cap);
|
|
|
|
ret = ltv_unset_val(&buf, type);
|
|
if (ret >= 0) {
|
|
codec_cap->data_len = ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FREQ, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint16_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return sys_get_le16(data);
|
|
}
|
|
|
|
int bt_audio_codec_cap_set_freq(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_codec_cap_freq freq)
|
|
{
|
|
uint16_t freq_le16;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((freq & BT_AUDIO_CODEC_CAP_FREQ_ANY) != freq) {
|
|
LOG_DBG("Invalid freq value: %d", freq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
freq_le16 = sys_cpu_to_le16((uint16_t)freq);
|
|
|
|
return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FREQ,
|
|
(uint8_t *)&freq_le16, sizeof(freq_le16));
|
|
}
|
|
|
|
int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_DURATION, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return data[0];
|
|
}
|
|
|
|
int bt_audio_codec_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap,
|
|
enum bt_audio_codec_cap_frame_dur frame_dur)
|
|
{
|
|
uint8_t frame_dur_u8;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_ANY) == 0) {
|
|
LOG_DBG("Invalid frame_dur value: %d", frame_dur);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_PREFER_7_5) != 0) {
|
|
if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_PREFER_10) != 0) {
|
|
LOG_DBG("Cannot prefer both 7.5 and 10ms: %d", frame_dur);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_7_5) == 0) {
|
|
LOG_DBG("Cannot prefer 7.5ms when not supported: %d", frame_dur);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if ((frame_dur & BT_AUDIO_CODEC_CAP_DURATION_PREFER_10) != 0 &&
|
|
(frame_dur & BT_AUDIO_CODEC_CAP_DURATION_10) == 0) {
|
|
LOG_DBG("Cannot prefer 10ms when not supported: %d", frame_dur);
|
|
return -EINVAL;
|
|
}
|
|
|
|
frame_dur_u8 = (uint8_t)frame_dur;
|
|
|
|
return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_DURATION,
|
|
&frame_dur_u8, sizeof(frame_dur_u8));
|
|
}
|
|
|
|
int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap,
|
|
bool fallback_to_default)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT, &data);
|
|
if (data == NULL) {
|
|
if (fallback_to_default && codec_cap->id == BT_HCI_CODING_FORMAT_LC3) {
|
|
return 1;
|
|
}
|
|
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return data[0];
|
|
}
|
|
|
|
int bt_audio_codec_cap_set_supported_audio_chan_counts(
|
|
struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count)
|
|
{
|
|
uint8_t chan_count_u8;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((chan_count & BT_AUDIO_CODEC_CAP_CHAN_COUNT_ANY) != chan_count) {
|
|
LOG_DBG("Invalid chan_count value: %d", chan_count);
|
|
return -EINVAL;
|
|
}
|
|
|
|
chan_count_u8 = (uint8_t)chan_count;
|
|
|
|
return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT,
|
|
&chan_count_u8, sizeof(chan_count_u8));
|
|
}
|
|
|
|
int bt_audio_codec_cap_get_octets_per_frame(
|
|
const struct bt_audio_codec_cap *codec_cap,
|
|
struct bt_audio_codec_octets_per_codec_frame *codec_frame)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(codec_frame == NULL) {
|
|
LOG_DBG("codec_frame is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len = bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN, &data);
|
|
if (data == NULL) {
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint32_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
codec_frame->min = sys_get_le16(data);
|
|
codec_frame->max = sys_get_le16(data + sizeof(codec_frame->min));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_audio_codec_cap_set_octets_per_frame(
|
|
struct bt_audio_codec_cap *codec_cap,
|
|
const struct bt_audio_codec_octets_per_codec_frame *codec_frame)
|
|
{
|
|
uint8_t codec_frame_le32[4];
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(codec_frame == NULL) {
|
|
LOG_DBG("codec_frame is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (codec_frame->min > codec_frame->max) {
|
|
LOG_DBG("Invalid codec_frame values: %u/%u", codec_frame->min, codec_frame->max);
|
|
return -EINVAL;
|
|
}
|
|
|
|
sys_put_le16(codec_frame->min, codec_frame_le32);
|
|
sys_put_le16(codec_frame->max, codec_frame_le32 + 2);
|
|
|
|
return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN,
|
|
codec_frame_le32, sizeof(codec_frame_le32));
|
|
}
|
|
|
|
int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap,
|
|
bool fallback_to_default)
|
|
{
|
|
const uint8_t *data;
|
|
uint8_t data_len;
|
|
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data_len =
|
|
bt_audio_codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT, &data);
|
|
if (data == NULL) {
|
|
if (fallback_to_default && codec_cap->id == BT_HCI_CODING_FORMAT_LC3) {
|
|
return 1;
|
|
}
|
|
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (data_len != sizeof(uint8_t)) {
|
|
return -EBADMSG;
|
|
}
|
|
|
|
return data[0];
|
|
}
|
|
|
|
int bt_audio_codec_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap,
|
|
uint8_t codec_frames_per_sdu)
|
|
{
|
|
CHECKIF(codec_cap == NULL) {
|
|
LOG_DBG("codec_cap is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return bt_audio_codec_cap_set_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_COUNT,
|
|
&codec_frames_per_sdu, sizeof(codec_frames_per_sdu));
|
|
}
|
|
|
|
#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 */
|