Bluetooth: Audio: Refactor codec_cfg_get_freq

Refactor the codec_cfg_get_freq function to return the assigned
numbers value, instead of a converted value, but with
support for converting the value.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-09-25 12:25:22 +02:00 committed by Alberto Escolar
commit 85bb2624bc
10 changed files with 449 additions and 125 deletions

View file

@ -566,17 +566,50 @@ struct bt_audio_codec_qos_pref {
* @{ * @{
*/ */
/**
* @brief Convert assigned numbers frequency to frequency value.
*
* @param freq The assigned numbers frequency to convert.
*
* @retval -EINVAL if arguments are invalid.
* @retval The converted frequency value in Hz.
*/
int bt_audio_codec_cfg_freq_to_freq_hz(enum bt_audio_codec_config_freq freq);
/**
* @brief Convert frequency value to assigned numbers frequency.
*
* @param freq_hz The frequency value to convert.
*
* @retval -EINVAL if arguments are invalid.
* @retval The assigned numbers frequency (@ref bt_audio_codec_config_freq).
*/
int bt_audio_codec_cfg_freq_hz_to_freq(uint32_t freq_hz);
/**@brief Extract the frequency from a codec configuration. /**@brief Extract the frequency from a codec configuration.
* *
* @param codec_cfg The codec configuration to extract data from. * @param codec_cfg The codec configuration to extract data from.
* *
* @retval The frequency in Hz * @retval A @ref bt_audio_codec_config_freq value
* @retval -EINVAL if arguments are invalid * @retval -EINVAL if arguments are invalid
* @retval -ENODATA if not found * @retval -ENODATA if not found
* @retval -EBADMSG if found value has invalid size or value * @retval -EBADMSG if found value has invalid size or value
*/ */
int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg); int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg);
/**
* @brief Set the frequency of a codec configuration.
*
* @param codec_cfg The codec configuration to set data for.
* @param freq The assigned numbers frequency to set.
*
* @retval The data_len of @p codec_cfg on success
* @retval -EINVAL if arguments are invalid
* @retval -ENOMEM if the new value could not set or added due to memory
*/
int bt_audio_codec_cfg_set_freq(struct bt_audio_codec_cfg *codec_cfg,
enum bt_audio_codec_config_freq freq);
/** @brief Extract frame duration from BT codec config /** @brief Extract frame duration from BT codec config
* *
* @param codec_cfg The codec configuration to extract data from. * @param codec_cfg The codec configuration to extract data from.
@ -661,6 +694,21 @@ int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg
uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
const uint8_t **data); const uint8_t **data);
/**
* @brief Set or add a specific codec configuration value
*
* @param codec_cfg The codec data to set the value in.
* @param type The type id to set
* @param data Pointer to the data-pointer to set
* @param data_len Length of @p data
*
* @retval The data_len of @p codec_cfg on success
* @retval -EINVAL if arguments are invalid
* @retval -ENOMEM if the new value could not set or added due to memory
*/
int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
const uint8_t *data, size_t data_len);
/** @} */ /* End of bt_audio_codec_cfg */ /** @} */ /* End of bt_audio_codec_cfg */
/** /**

View file

@ -173,73 +173,75 @@ struct bt_audio_codec_octets_per_codec_frame {
enum bt_audio_codec_config_type { enum bt_audio_codec_config_type {
/** @brief LC3 Sample Frequency configuration type. */ /** @brief LC3 Sample Frequency configuration type. */
BT_AUDIO_CODEC_CONFIG_LC3_FREQ = 0x01, BT_AUDIO_CODEC_CONFIG_LC3_FREQ = 0x01,
/** @brief LC3 Frame Duration configuration type. */ /** @brief LC3 Frame Duration configuration type. */
BT_AUDIO_CODEC_CONFIG_LC3_DURATION = 0x02, BT_AUDIO_CODEC_CONFIG_LC3_DURATION = 0x02,
/** @brief LC3 channel Allocation configuration type. */ /** @brief LC3 channel Allocation configuration type. */
BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC = 0x03, BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC = 0x03,
/** @brief LC3 Frame Length configuration type. */ /** @brief LC3 Frame Length configuration type. */
BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN = 0x04, BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN = 0x04,
/** @brief Codec frame blocks, per SDU configuration type. */ /** @brief Codec frame blocks, per SDU configuration type. */
BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU = 0x05, BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU = 0x05,
}; };
/** enum bt_audio_codec_config_freq {
* @brief 8 Khz codec Sample Frequency configuration /**
*/ * @brief 8 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ 0x01 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ = 0x01,
* @brief 11.025 Khz codec Sample Frequency configuration /**
*/ * @brief 11.025 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ 0x02 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ = 0x02,
* @brief 16 Khz codec Sample Frequency configuration /**
*/ * @brief 16 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ 0x03 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ = 0x03,
* @brief 22.05 Khz codec Sample Frequency configuration /**
*/ * @brief 22.05 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ 0x04 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ = 0x04,
* @brief 24 Khz codec Sample Frequency configuration /**
*/ * @brief 24 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ 0x05 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ = 0x05,
* @brief 32 Khz codec Sample Frequency configuration /**
*/ * @brief 32 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ 0x06 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ = 0x06,
* @brief 44.1 Khz codec Sample Frequency configuration /**
*/ * @brief 44.1 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ 0x07 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ = 0x07,
* @brief 48 Khz codec Sample Frequency configuration /**
*/ * @brief 48 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ 0x08 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ = 0x08,
* @brief 88.2 Khz codec Sample Frequency configuration /**
*/ * @brief 88.2 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ 0x09 */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ = 0x09,
* @brief 96 Khz codec Sample Frequency configuration /**
*/ * @brief 96 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ 0x0a */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ = 0x0a,
* @brief 176.4 Khz codec Sample Frequency configuration /**
*/ * @brief 176.4 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ 0x0b */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ = 0x0b,
* @brief 192 Khz codec Sample Frequency configuration /**
*/ * @brief 192 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ 0x0c */
/** BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ = 0x0c,
* @brief 384 Khz codec Sample Frequency configuration /**
*/ * @brief 384 Khz codec Sample Frequency configuration
#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ 0x0d */
BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ = 0x0d,
};
/** /**
* @brief LC3 7.5 msec Frame Duration configuration * @brief LC3 7.5 msec Frame Duration configuration
@ -250,7 +252,6 @@ enum bt_audio_codec_config_type {
*/ */
#define BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10 0x01 #define BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10 0x01
/** /**
* @brief Helper to declare LC3 codec capability * @brief Helper to declare LC3 codec capability
* *

View file

@ -75,13 +75,18 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
codec_cfg->vid, codec_cfg->data_len); codec_cfg->vid, codec_cfg->data_len);
if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
/* LC3 uses the generic LTV format - other codecs might do as well */
enum bt_audio_location chan_allocation; enum bt_audio_location chan_allocation;
int ret;
/* LC3 uses the generic LTV format - other codecs might do as well */
bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data"); bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg)); ret = bt_audio_codec_cfg_get_freq(codec_cfg);
if (ret > 0) {
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_freq_to_freq_hz(ret));
}
printk(" Frame Duration: %d us\n", printk(" Frame Duration: %d us\n",
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) { if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) {

View file

@ -64,13 +64,18 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
codec_cfg->vid, codec_cfg->data_len); codec_cfg->vid, codec_cfg->data_len);
if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
/* LC3 uses the generic LTV format - other codecs might do as well */
enum bt_audio_location chan_allocation; enum bt_audio_location chan_allocation;
int ret;
/* LC3 uses the generic LTV format - other codecs might do as well */
bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data"); bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg)); ret = bt_audio_codec_cfg_get_freq(codec_cfg);
if (ret > 0) {
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_freq_to_freq_hz(ret));
}
printk(" Frame Duration: %d us\n", printk(" Frame Duration: %d us\n",
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) { if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) {

View file

@ -221,12 +221,19 @@ static void lc3_audio_timer_timeout(struct k_work *work)
} }
} }
static void init_lc3(void) static int init_lc3(void)
{ {
const struct bt_audio_codec_cfg *codec_cfg = &codec_configuration.codec_cfg; const struct bt_audio_codec_cfg *codec_cfg = &codec_configuration.codec_cfg;
unsigned int num_samples; unsigned int num_samples;
int ret;
ret = bt_audio_codec_cfg_get_freq(codec_cfg);
if (ret > 0) {
freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret);
} else {
return ret;
}
freq_hz = bt_audio_codec_cfg_get_freq(codec_cfg);
frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(codec_cfg); frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(codec_cfg);
octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
@ -271,7 +278,7 @@ static void init_lc3(void)
#else #else
#define init_lc3(...) #define init_lc3(...) 0
/** /**
* @brief Send audio data on timeout * @brief Send audio data on timeout
@ -979,7 +986,11 @@ static int set_stream_qos(void)
static int enable_streams(void) static int enable_streams(void)
{ {
if (IS_ENABLED(CONFIG_LIBLC3)) { if (IS_ENABLED(CONFIG_LIBLC3)) {
init_lc3(); int err = init_lc3();
if (err != 0) {
return err;
}
} }
for (size_t i = 0U; i < configured_stream_count; i++) { for (size_t i = 0U; i < configured_stream_count; i++) {

View file

@ -135,13 +135,18 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
codec_cfg->vid, codec_cfg->data_len); codec_cfg->vid, codec_cfg->data_len);
if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
/* LC3 uses the generic LTV format - other codecs might do as well */
enum bt_audio_location chan_allocation; enum bt_audio_location chan_allocation;
int ret;
/* LC3 uses the generic LTV format - other codecs might do as well */
bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data"); bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg)); ret = bt_audio_codec_cfg_get_freq(codec_cfg);
if (ret > 0) {
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_freq_to_freq_hz(ret));
}
printk(" Frame Duration: %d us\n", printk(" Frame Duration: %d us\n",
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) { if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) {
@ -349,15 +354,19 @@ static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t
#if defined(CONFIG_LIBLC3) #if defined(CONFIG_LIBLC3)
{ {
const int freq = bt_audio_codec_cfg_get_freq(stream->codec_cfg);
const int frame_duration_us = const int frame_duration_us =
bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg);
int freq;
int ret;
if (freq < 0) { ret = bt_audio_codec_cfg_get_freq(stream->codec_cfg);
if (ret > 0) {
freq = bt_audio_codec_cfg_freq_to_freq_hz(ret);
} else {
printk("Error: Codec frequency not set, cannot start codec."); printk("Error: Codec frequency not set, cannot start codec.");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID, *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC_DATA); BT_BAP_ASCS_REASON_CODEC_DATA);
return -1; return ret;
} }
if (frame_duration_us < 0) { if (frame_duration_us < 0) {

View file

@ -10,6 +10,8 @@
* Generic Audio. * Generic Audio.
*/ */
#include <stdlib.h>
#include <zephyr/bluetooth/audio/audio.h> #include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/sys/check.h> #include <zephyr/sys/check.h>
@ -18,6 +20,74 @@
LOG_MODULE_REGISTER(bt_audio_codec, CONFIG_BT_AUDIO_CODEC_LOG_LEVEL); 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_config_freq freq)
{
switch (freq) {
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ:
return 8000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ:
return 11025;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ:
return 16000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ:
return 22050;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ:
return 24000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ:
return 32000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ:
return 44100;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ:
return 48000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ:
return 88200;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ:
return 96000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ:
return 176400;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ:
return 192000;
case BT_AUDIO_CODEC_CONFIG_LC3_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_CONFIG_LC3_FREQ_8KHZ;
case 11025U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ;
case 16000U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ;
case 22050U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ;
case 24000U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ;
case 32000U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ;
case 44100U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ;
case 48000U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ;
case 88200U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ;
case 96000U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ;
case 176400U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ;
case 192000U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ;
case 384000U:
return BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ;
default:
return -EINVAL;
}
}
struct search_type_param { struct search_type_param {
bool found; bool found;
uint8_t type; uint8_t type;
@ -42,6 +112,15 @@ static bool parse_cb(struct bt_data *data, void *user_data)
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_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;
}
uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
const uint8_t **data) const uint8_t **data)
{ {
@ -79,8 +158,99 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, u
return param.data_len; return param.data_len;
} }
int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
const uint8_t *data, size_t data_len)
{
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;
}
for (uint16_t i = 0U; i < codec_cfg->data_len;) {
const uint8_t len = codec_cfg->data[i++];
const uint8_t data_type = codec_cfg->data[i++];
const uint8_t value_len = len - sizeof(data_type);
if (data_type == type) {
uint8_t *value = &codec_cfg->data[i];
if (data_len == value_len) {
memcpy(value, data, data_len);
} else {
const uint8_t *old_next_data_start = value + value_len + 1;
const uint8_t data_len_to_move =
codec_cfg->data_len -
(old_next_data_start - codec_cfg->data);
uint8_t *new_next_data_start = value + data_len + 1;
const int16_t diff = data_len - value_len;
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);
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 ((codec_cfg->data_len + diff) >
ARRAY_SIZE(codec_cfg->data)) {
LOG_DBG("Cannot fit data_len %zu in buf with len "
"%u and size %u",
data_len, codec_cfg->data_len,
ARRAY_SIZE(codec_cfg->data));
return -ENOMEM;
}
memmove(new_next_data_start, old_next_data_start,
data_len_to_move);
memcpy(value, data, data_len);
}
codec_cfg->data_len += diff;
}
return codec_cfg->data_len;
}
i += value_len;
}
/* If we reach here, we did not find the data in the buffer, so we simply add it */
if ((codec_cfg->data_len + data_len) <= ARRAY_SIZE(codec_cfg->data)) {
struct net_buf_simple buf;
init_net_buf_simple_from_codec_cfg(&buf, codec_cfg);
net_buf_simple_add_u8(&buf, data_len + sizeof(type));
net_buf_simple_add_u8(&buf, type);
net_buf_simple_add_mem(&buf, data, data_len);
codec_cfg->data_len = buf.len;
} else {
LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len,
codec_cfg->data_len, ARRAY_SIZE(codec_cfg->data));
return -ENOMEM;
}
return codec_cfg->data_len;
}
int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg) int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg)
{ {
enum bt_audio_codec_config_freq freq;
const uint8_t *data; const uint8_t *data;
uint8_t data_len; uint8_t data_len;
@ -98,36 +268,29 @@ int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg)
return -EBADMSG; return -EBADMSG;
} }
switch (data[0]) { freq = data[0];
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ: if (bt_audio_codec_cfg_freq_to_freq_hz(freq) < 0) {
return 8000; LOG_DBG("Invalid freq value: 0x%02X", freq);
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ:
return 11025;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ:
return 16000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ:
return 22050;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ:
return 24000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ:
return 32000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ:
return 44100;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ:
return 48000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ:
return 88200;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ:
return 96000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ:
return 176400;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ:
return 192000;
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ:
return 384000;
default:
return -EBADMSG; return -EBADMSG;
} }
return freq;
}
int bt_audio_codec_cfg_set_freq(struct bt_audio_codec_cfg *codec_cfg,
enum bt_audio_codec_config_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_CONFIG_LC3_FREQ, &freq_u8,
sizeof(freq_u8));
} }
int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *codec_cfg) int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *codec_cfg)

View file

@ -228,16 +228,23 @@ static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, in
} }
} }
static void init_lc3(const struct bt_bap_stream *stream) static int init_lc3(const struct bt_bap_stream *stream)
{ {
size_t num_samples; size_t num_samples;
int ret;
if (stream == NULL || stream->codec_cfg == NULL) { if (stream == NULL || stream->codec_cfg == NULL) {
shell_error(ctx_shell, "invalid stream to init LC3"); shell_error(ctx_shell, "invalid stream to init LC3");
return; return -EINVAL;
}
ret = bt_audio_codec_cfg_get_freq(stream->codec_cfg);
if (ret > 0) {
lc3_freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret);
} else {
return ret;
} }
lc3_freq_hz = bt_audio_codec_cfg_get_freq(stream->codec_cfg);
lc3_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); lc3_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg);
lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg);
lc3_frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); lc3_frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true);
@ -245,17 +252,17 @@ static void init_lc3(const struct bt_bap_stream *stream)
if (lc3_freq_hz < 0) { if (lc3_freq_hz < 0) {
printk("Error: Codec frequency not set, cannot start codec."); printk("Error: Codec frequency not set, cannot start codec.");
return; return -EINVAL;
} }
if (lc3_frame_duration_us < 0) { if (lc3_frame_duration_us < 0) {
printk("Error: Frame duration not set, cannot start codec."); printk("Error: Frame duration not set, cannot start codec.");
return; return -EINVAL;
} }
if (lc3_octets_per_frame < 0) { if (lc3_octets_per_frame < 0) {
printk("Error: Octets per frame not set, cannot start codec."); printk("Error: Octets per frame not set, cannot start codec.");
return; return -EINVAL;
} }
lc3_frame_duration_100us = lc3_frame_duration_us / 100; lc3_frame_duration_100us = lc3_frame_duration_us / 100;
@ -274,7 +281,10 @@ static void init_lc3(const struct bt_bap_stream *stream)
if (lc3_encoder == NULL) { if (lc3_encoder == NULL) {
printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n"); printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n");
return -EINVAL;
} }
return 0;
} }
static void lc3_audio_send_data(struct k_work *work) static void lc3_audio_send_data(struct k_work *work)
@ -2603,7 +2613,6 @@ static bool stream_start_sine_verify(const struct bt_bap_stream *bap_stream)
{ {
int stream_frame_duration_us; int stream_frame_duration_us;
struct bt_bap_ep_info info; struct bt_bap_ep_info info;
int stream_freq_hz;
int err; int err;
if (bap_stream == NULL || bap_stream->qos == NULL) { if (bap_stream == NULL || bap_stream->qos == NULL) {
@ -2619,8 +2628,12 @@ static bool stream_start_sine_verify(const struct bt_bap_stream *bap_stream)
return false; return false;
} }
stream_freq_hz = bt_audio_codec_cfg_get_freq(bap_stream->codec_cfg); err = bt_audio_codec_cfg_get_freq(bap_stream->codec_cfg);
if (stream_freq_hz != lc3_freq_hz) { if (err > 0) {
if (bt_audio_codec_cfg_freq_to_freq_hz(err) != lc3_freq_hz) {
return false;
}
} else {
return false; return false;
} }
@ -2671,7 +2684,13 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
struct bt_bap_stream *bap_stream = &unicast_streams[i].stream.bap_stream; struct bt_bap_stream *bap_stream = &unicast_streams[i].stream.bap_stream;
if (!lc3_initialized) { if (!lc3_initialized) {
init_lc3(bap_stream); err = init_lc3(bap_stream);
if (err != 0) {
shell_error(sh, "Failed to init LC3 %d", err);
return -ENOEXEC;
}
lc3_initialized = true; lc3_initialized = true;
} }
@ -2694,7 +2713,13 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
&broadcast_source_streams[i].stream.bap_stream; &broadcast_source_streams[i].stream.bap_stream;
if (!lc3_initialized) { if (!lc3_initialized) {
init_lc3(bap_stream); err = init_lc3(bap_stream);
if (err != 0) {
shell_error(sh, "Failed to init LC3 %d", err);
return -ENOEXEC;
}
lc3_initialized = true; lc3_initialized = true;
} }
@ -2717,7 +2742,12 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
return -ENOEXEC; return -ENOEXEC;
} }
init_lc3(default_stream); err = init_lc3(default_stream);
if (err != 0) {
shell_error(sh, "Failed to init LC3 %d", err);
return -ENOEXEC;
}
err = stream_start_sine(default_stream); err = stream_start_sine(default_stream);
if (err != 0) { if (err != 0) {

View file

@ -15,6 +15,37 @@ DEFINE_FFF_GLOBALS;
ZTEST_SUITE(audio_codec_test_suite, NULL, NULL, NULL, NULL, NULL); ZTEST_SUITE(audio_codec_test_suite, NULL, NULL, NULL, NULL, NULL);
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_freq_to_freq_hz)
{
const struct freq_test_input {
enum bt_audio_codec_config_freq freq;
uint32_t freq_hz;
} freq_test_inputs[] = {
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ, .freq_hz = 8000U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ, .freq_hz = 11025U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ, .freq_hz = 16000U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ, .freq_hz = 22050U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ, .freq_hz = 24000U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ, .freq_hz = 32000U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ, .freq_hz = 44100U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, .freq_hz = 48000U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ, .freq_hz = 88200U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ, .freq_hz = 96000U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ, .freq_hz = 176400U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ, .freq_hz = 192000U},
{.freq = BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ, .freq_hz = 384000U},
};
for (size_t i = 0U; i < ARRAY_SIZE(freq_test_inputs); i++) {
const struct freq_test_input *fti = &freq_test_inputs[i];
zassert_equal(bt_audio_codec_cfg_freq_to_freq_hz(fti->freq), fti->freq_hz,
"freq %d was not coverted to %u", fti->freq, fti->freq_hz);
zassert_equal(bt_audio_codec_cfg_freq_hz_to_freq(fti->freq_hz), fti->freq,
"freq_hz %u was not coverted to %d", fti->freq_hz, fti->freq);
}
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_freq) ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_freq)
{ {
const struct bt_bap_lc3_preset preset = const struct bt_bap_lc3_preset preset =
@ -23,7 +54,23 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_freq)
int ret; int ret;
ret = bt_audio_codec_cfg_get_freq(&preset.codec_cfg); ret = bt_audio_codec_cfg_get_freq(&preset.codec_cfg);
zassert_equal(ret, 16000u, "unexpected return value %d", ret); zassert_equal(ret, 0x03, "unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_set_freq)
{
struct bt_bap_lc3_preset preset = BT_BAP_LC3_UNICAST_PRESET_16_2_1(
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
int ret;
ret = bt_audio_codec_cfg_get_freq(&preset.codec_cfg);
zassert_equal(ret, 0x03, "Unexpected return value %d", ret);
ret = bt_audio_codec_cfg_set_freq(&preset.codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ);
zassert_true(ret > 0, "Unexpected return value %d", ret);
ret = bt_audio_codec_cfg_get_freq(&preset.codec_cfg);
zassert_equal(ret, 0x06, "Unexpected return value %d", ret);
} }
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_frame_duration_us) ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_frame_duration_us)
@ -47,8 +94,8 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_chan_allocation_val)
err = bt_audio_codec_cfg_get_chan_allocation_val(&preset.codec_cfg, &chan_allocation); err = bt_audio_codec_cfg_get_chan_allocation_val(&preset.codec_cfg, &chan_allocation);
zassert_false(err, "unexpected error %d", err); zassert_false(err, "unexpected error %d", err);
zassert_equal(chan_allocation, BT_AUDIO_LOCATION_FRONT_LEFT, zassert_equal(chan_allocation, BT_AUDIO_LOCATION_FRONT_LEFT, "unexpected return value %d",
"unexpected return value %d", chan_allocation); chan_allocation);
} }
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_octets_per_frame) ZTEST(audio_codec_test_suite, test_bt_audio_codec_cfg_get_octets_per_frame)

View file

@ -136,13 +136,18 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
codec_cfg->vid, codec_cfg->data_len); codec_cfg->vid, codec_cfg->data_len);
if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
/* LC3 uses the generic LTV format - other codecs might do as well */
enum bt_audio_location chan_allocation; enum bt_audio_location chan_allocation;
int ret;
/* LC3 uses the generic LTV format - other codecs might do as well */
bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data"); bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
LOG_DBG(" Frequency: %d Hz", bt_audio_codec_cfg_get_freq(codec_cfg)); ret = bt_audio_codec_cfg_get_freq(codec_cfg);
if (ret > 0) {
LOG_DBG(" Frequency: %d Hz", bt_audio_codec_cfg_freq_to_freq_hz(ret));
}
LOG_DBG(" Frame Duration: %d us", LOG_DBG(" Frame Duration: %d us",
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) { if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) {
@ -255,22 +260,22 @@ static void btp_send_ascs_ase_state_changed_ev(struct bt_conn *conn, uint8_t ase
static int validate_codec_parameters(const struct bt_audio_codec_cfg *codec_cfg) static int validate_codec_parameters(const struct bt_audio_codec_cfg *codec_cfg)
{ {
int freq_hz;
int frame_duration_us; int frame_duration_us;
int frames_per_sdu; int frames_per_sdu;
int octets_per_frame; int octets_per_frame;
int chan_allocation_err; int chan_allocation_err;
enum bt_audio_location chan_allocation; enum bt_audio_location chan_allocation;
int ret;
freq_hz = bt_audio_codec_cfg_get_freq(codec_cfg);
frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(codec_cfg); frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(codec_cfg);
chan_allocation_err = chan_allocation_err =
bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation); bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation);
octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
if (freq_hz < 0) { ret = bt_audio_codec_cfg_get_freq(codec_cfg);
LOG_DBG("Error: Invalid codec frequency."); if (ret < 0) {
LOG_DBG("Error: Invalid codec frequency: %d", ret);
return -EINVAL; return -EINVAL;
} }