Bluetooth: Audio: Add bt_audio_codec_cap_get helper functions

Add helper function to get specific values from
a codec capability struct.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-09-21 13:12:19 +02:00 committed by Carles Cufí
parent b54951b86e
commit e51ac69156
3 changed files with 266 additions and 6 deletions

View file

@ -651,12 +651,7 @@ int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *cod
int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg *codec_cfg,
bool fallback_to_default);
/** @brief Lookup a specific codec configuration value based on type
* *
* Typically types used are:
* @ref bt_audio_codec_capability_type
* @ref bt_audio_codec_config_type
* @ref bt_audio_metadata_type
/** @brief Lookup a specific codec configuration value
*
* @param[in] codec_cfg The codec data to search in.
* @param[in] type The type id to look for
@ -853,6 +848,94 @@ int bt_audio_codec_meta_get_vendor(const uint8_t meta[], size_t meta_len,
const uint8_t **vendor_meta);
/** @} */ /* End of bt_audio_codec_meta */
/**
* @brief Audio codec capabilities APIs
* @defgroup bt_audio_codec_cap Codec capability parsing APIs
*
* Functions to parse codec capability data when formatted as LTV wrapped into @ref
* bt_audio_codec_cap.
*
* @{
*/
/**
* @brief Lookup a specific value based on type
*
* @param[in] codec_cap The codec data to search in.
* @param[in] type The type id to look for
* @param[out] data Pointer to the data-pointer to update when item is found
*
* @return Length of found @p data or 0 if not found
*/
uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type,
const uint8_t **data);
/**
* @brief Extract the frequency from a codec capability.
*
* @param codec_cap The codec configuration to extract data from.
*
* @retval Bitfield of supported frequencies 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 Extract the frequency from a codec capability.
*
* @param codec_cap The codec configuration 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);
/**
* @brief Extract the frequency from a codec capability.
*
* @param codec_cap The codec configuration to extract data from.
*
* @retval Bitfield of supported channel counts 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_supported_audio_chan_counts(const struct bt_audio_codec_cap *codec_cap);
/**
* @brief Extract the frequency from a codec capability.
*
* @param[in] codec_cap The codec configuration to extract data from.
* @param[out] codec_frame Struct to place the resulting values in
*
* @retval 0 on success
* @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_octets_per_frame(
const struct bt_audio_codec_cap *codec_cap,
struct bt_audio_codec_octets_per_codec_frame *codec_frame);
/**
* @brief Extract the frequency from a codec capability.
*
* @param codec_cap The codec configuration to extract data from.
*
* @retval Maximum number of codec frames per SDU supported
* @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_max_codec_frames_per_sdu(const struct bt_audio_codec_cap *codec_cap);
/** @} */ /* End of bt_audio_codec_cap */
#ifdef __cplusplus
}
#endif

View file

@ -26,6 +26,11 @@
extern "C" {
#endif
/**
* @brief LC3 codec ID
*/
#define BT_HCI_CODING_FORMAT_LC3 0x06
/**
* @brief Codec capability type id's
*
@ -145,6 +150,18 @@ enum bt_audio_codec_capability_type {
#define BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(...) \
((uint8_t)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1))
struct BT_AUDIO_CODEC_LC3_frame_len {
uint16_t min;
uint16_t max;
};
struct bt_audio_codec_octets_per_codec_frame {
/** Minimum number of octets supported per codec frame */
uint16_t min;
/** Maximum number of octets supported per codec frame */
uint16_t max;
};
/**
* @brief Codec configuration type IDs
*

View file

@ -545,3 +545,163 @@ int bt_audio_codec_meta_get_vendor(const uint8_t meta[], size_t meta_len,
#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
uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type,
const uint8_t **data)
{
struct search_type_param param = {
.type = type,
.data_len = 0,
.data = data,
};
int err;
CHECKIF(codec_cap == NULL) {
LOG_DBG("codec_cap is NULL");
return 0;
}
CHECKIF(data == NULL) {
LOG_DBG("data is NULL");
return 0;
}
*data = NULL;
err = bt_audio_data_parse(codec_cap->data, codec_cap->data_len, parse_cb, &param);
if (err != 0 && err != -ECANCELED) {
LOG_DBG("Could not parse the data: %d", err);
return 0;
}
if (param.data == NULL) {
LOG_DBG("Could not find the type %u", type);
return 0;
}
return param.data_len;
}
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_LC3_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_get_frame_duration(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_LC3_DURATION, &data);
if (data == NULL) {
return -ENODATA;
}
if (data_len != sizeof(uint8_t)) {
return -EBADMSG;
}
return data[0];
}
int bt_audio_codec_cap_get_supported_audio_chan_counts(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_LC3_CHAN_COUNT, &data);
if (data == NULL) {
return -ENODATA;
}
if (data_len != sizeof(uint8_t)) {
return -EBADMSG;
}
return data[0];
}
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_LC3_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_get_max_codec_frames_per_sdu(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_LC3_FRAME_COUNT, &data);
if (data == NULL) {
return -ENODATA;
}
if (data_len != sizeof(uint8_t)) {
return -EBADMSG;
}
return data[0];
}
#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 */