Bluetooth: Audio: Add codec cap set functions

Add set functions for codec capability, to set all
assigned number values in the bt_audio_codec_cap
struct.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-09-28 14:14:17 +02:00 committed by Carles Cufí
commit 06d5a625a6
3 changed files with 342 additions and 12 deletions

View file

@ -994,31 +994,57 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, u
/**
* @brief Extract the frequency from a codec capability.
*
* @param codec_cap The codec configuration to extract data from.
* @param codec_cap The codec capabilities to extract data from.
*
* @retval Bitfield of supported frequencies if 0 or positive
* @retval Bitfield of supported frequencies (@ref bt_audio_codec_cap_freq) if 0 or positive
* @retval -EINVAL if arguments are invalid
* @retval -ENODATA if not found
* @retval -EBADMSG if found value has invalid size or value
*/
int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap);
/**
* @brief Set the supported frequencies of a codec capability.
*
* @param codec_cap The codec capabilities to set data for.
* @param freq The supported frequencies to set.
*
* @retval The data_len of @p codec_cap 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_cap_set_freq(struct bt_audio_codec_cap *codec_cap,
enum bt_audio_codec_cap_freq freq);
/**
* @brief Extract the frequency from a codec capability.
*
* @param codec_cap The codec configuration to extract data from.
* @param codec_cap The codec capabilities to extract data from.
*
* @retval Bitfield of supported frame durations if 0 or positive
* @retval -EINVAL if arguments are invalid
* @retval -ENODATA if not found
* @retval -EBADMSG if found value has invalid size or value
*/
int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec_cap);
int bt_audio_codec_cap_get_frame_dur(const struct bt_audio_codec_cap *codec_cap);
/**
* @brief Set the frame duration of a codec capability.
*
* @param codec_cap The codec capabilities to set data for.
* @param frame_dur The frame duration to set.
*
* @retval The data_len of @p codec_cap 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_cap_set_frame_dur(struct bt_audio_codec_cap *codec_cap,
enum bt_audio_codec_cap_frame_dur frame_dur);
/**
* @brief Extract the frequency from a codec capability.
*
* @param codec_cap The codec configuration to extract data from.
* @param codec_cap The codec capabilities to extract data from.
*
* @retval Bitfield of supported channel counts if 0 or positive
* @retval -EINVAL if arguments are invalid
@ -1028,9 +1054,22 @@ int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec
int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap);
/**
* @brief Extract the frequency from a codec capability.
* @brief Set the channel count of a codec capability.
*
* @param[in] codec_cap The codec configuration to extract data from.
* @param codec_cap The codec capabilities to set data for.
* @param chan_count The channel count frequency to set.
*
* @retval The data_len of @p codec_cap 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_cap_set_supported_audio_chan_counts(
struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_cap_chan_count chan_count);
/**
* @brief Extract the supported octets per codec frame from a codec capability.
*
* @param[in] codec_cap The codec capabilities to extract data from.
* @param[out] codec_frame Struct to place the resulting values in
*
* @retval 0 on success
@ -1043,9 +1082,23 @@ int bt_audio_codec_cap_get_octets_per_frame(
struct bt_audio_codec_octets_per_codec_frame *codec_frame);
/**
* @brief Extract the frequency from a codec capability.
* @brief Set the octets per codec frame of a codec capability.
*
* @param codec_cap The codec configuration to extract data from.
* @param codec_cap The codec capabilities to set data for.
* @param codec_frame The octets per codec frame to set.
*
* @retval The data_len of @p codec_cap 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_cap_set_octets_per_frame(
struct bt_audio_codec_cap *codec_cap,
const struct bt_audio_codec_octets_per_codec_frame *codec_frame);
/**
* @brief Extract the maximum codec frames per SDU from a codec capability.
*
* @param codec_cap The codec capabilities to extract data from.
*
* @retval Maximum number of codec frames per SDU supported
* @retval -EINVAL if arguments are invalid
@ -1054,6 +1107,19 @@ int bt_audio_codec_cap_get_octets_per_frame(
*/
int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap);
/**
* @brief Set the maximum codec frames per SDU of a codec capability.
*
* @param codec_cap The codec capabilities to set data for.
* @param codec_frames_per_sdu The maximum codec frames per SDU to set.
*
* @retval The data_len of @p codec_cap 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_cap_set_max_codec_frames_per_sdu(struct bt_audio_codec_cap *codec_cap,
uint8_t codec_frames_per_sdu);
/** @brief Lookup a specific metadata value based on type
*
* @param[in] codec_cap The codec data to search in.
@ -1214,6 +1280,7 @@ int bt_audio_codec_cap_meta_get_extended(const struct bt_audio_codec_cap *codec_
*/
int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_cap,
const uint8_t **vendor_meta);
/** @} */ /* End of bt_audio_codec_cap */
#ifdef __cplusplus

View file

@ -1074,6 +1074,15 @@ int bt_audio_codec_cap_meta_get_vendor(const struct bt_audio_codec_cap *codec_ca
#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;
}
uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type,
const uint8_t **data)
{
@ -1110,6 +1119,37 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, u
return param.data_len;
}
int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, uint8_t 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_get_freq(const struct bt_audio_codec_cap *codec_cap)
{
const uint8_t *data;
@ -1132,7 +1172,28 @@ int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap)
return sys_get_le16(data);
}
int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec_cap)
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_LC3_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_LC3_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;
@ -1154,6 +1215,45 @@ int bt_audio_codec_cap_get_frame_duration(const struct bt_audio_codec_cap *codec
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_LC3_DURATION_ANY) == 0) {
LOG_DBG("Invalid frame_dur value: %d", frame_dur);
return -EINVAL;
}
if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5) != 0) {
if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_10) != 0) {
LOG_DBG("Cannot prefer both 7.5 and 10ms: %d", frame_dur);
return -EINVAL;
}
if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_7_5) == 0) {
LOG_DBG("Cannot prefer 7.5ms when not supported: %d", frame_dur);
return -EINVAL;
}
}
if ((frame_dur & BT_AUDIO_CODEC_LC3_DURATION_PREFER_10) != 0 &&
(frame_dur & BT_AUDIO_CODEC_LC3_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_LC3_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)
{
const uint8_t *data;
@ -1176,6 +1276,27 @@ int bt_audio_codec_cap_get_supported_audio_chan_counts(const struct bt_audio_cod
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_ALL) != 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_LC3_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)
@ -1208,6 +1329,34 @@ int bt_audio_codec_cap_get_octets_per_frame(
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_LC3_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)
{
const uint8_t *data;
@ -1230,4 +1379,16 @@ int bt_audio_codec_cap_get_max_codec_frames_per_sdu(const struct bt_audio_codec_
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_LC3_FRAME_COUNT,
&codec_frames_per_sdu, sizeof(codec_frames_per_sdu));
}
#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 */

View file

@ -376,7 +376,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_freq)
zassert_equal(ret, 4, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_frame_duration)
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_freq)
{
struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10,
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U,
(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
int ret;
ret = bt_audio_codec_cap_get_freq(&codec_cap);
zassert_equal(ret, 4, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_set_freq(&codec_cap, BT_AUDIO_CODEC_LC3_FREQ_22KHZ);
zassert_true(ret > 0, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_get_freq(&codec_cap);
zassert_equal(ret, 8, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_frame_dur)
{
const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10,
@ -385,10 +404,29 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_frame_duration)
int ret;
ret = bt_audio_codec_cap_get_frame_duration(&codec_cap);
ret = bt_audio_codec_cap_get_frame_dur(&codec_cap);
zassert_equal(ret, 2, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_frame_dur)
{
struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10,
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U,
(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
int ret;
ret = bt_audio_codec_cap_get_frame_dur(&codec_cap);
zassert_equal(ret, 2, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_set_frame_dur(&codec_cap, BT_AUDIO_CODEC_LC3_DURATION_7_5);
zassert_true(ret > 0, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_get_frame_dur(&codec_cap);
zassert_equal(ret, 1, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_supported_audio_chan_counts)
{
const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
@ -402,6 +440,26 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_supported_audio_chan_c
zassert_equal(ret, 2, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_supported_audio_chan_counts)
{
struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10,
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U,
(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
int ret;
ret = bt_audio_codec_cap_get_supported_audio_chan_counts(&codec_cap);
zassert_equal(ret, 1, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_set_frame_dur(&codec_cap,
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(2));
zassert_true(ret > 0, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_get_frame_dur(&codec_cap);
zassert_equal(ret, 2, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_octets_per_frame)
{
struct bt_audio_codec_octets_per_codec_frame expected = {
@ -424,6 +482,31 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_octets_per_frame)
codec_frame.max);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_octets_per_frame)
{
struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10,
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U,
(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
struct bt_audio_codec_octets_per_codec_frame codec_frame;
int ret;
ret = bt_audio_codec_cap_get_octets_per_frame(&codec_cap, &codec_frame);
zassert_equal(ret, 0, "Unexpected return value %d", ret);
zassert_equal(codec_frame.min, 40U, "Unexpected minimum value %d", codec_frame.min);
zassert_equal(codec_frame.max, 120U, "Unexpected maximum value %d", codec_frame.max);
codec_frame.min = 50U;
codec_frame.max = 100U;
ret = bt_audio_codec_cap_set_octets_per_frame(&codec_cap, &codec_frame);
zassert_true(ret > 0, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_get_octets_per_frame(&codec_cap, &codec_frame);
zassert_equal(ret, 0, "Unexpected return value %d", ret);
zassert_equal(codec_frame.min, 50U, "Unexpected minimum value %d", codec_frame.min);
zassert_equal(codec_frame.max, 100U, "Unexpected maximum value %d", codec_frame.max);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_max_codec_frames_per_sdu)
{
const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
@ -437,6 +520,25 @@ ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_get_max_codec_frames_per_s
zassert_equal(ret, 2, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_set_max_codec_frames_per_sdu)
{
struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
BT_AUDIO_CODEC_LC3_FREQ_16KHZ, BT_AUDIO_CODEC_LC3_DURATION_10,
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40U, 120U, 2U,
(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
int ret;
ret = bt_audio_codec_cap_get_max_codec_frames_per_sdu(&codec_cap);
zassert_equal(ret, 2, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_set_max_codec_frames_per_sdu(&codec_cap, 4U);
zassert_true(ret > 0, "Unexpected return value %d", ret);
ret = bt_audio_codec_cap_get_max_codec_frames_per_sdu(&codec_cap);
zassert_equal(ret, 4, "Unexpected return value %d", ret);
}
ZTEST(audio_codec_test_suite, test_bt_audio_codec_cap_meta_get_pref_context)
{
const enum bt_audio_context ctx =