Bluetooth: Audio: Refactor bt_audio_codec_cfg to flat arrays
Refactor the bt_audio_codec_cfg to use flat arrays to store metadata and codec specific configurations. The purpose of this is to make it easier to copy the data between layers, but also to support non-LTV data for non-LC3 codec configurations. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
32b00dd6f4
commit
6ccd112c56
50 changed files with 1181 additions and 1824 deletions
|
@ -185,27 +185,6 @@ enum bt_audio_metadata_type {
|
|||
#define BT_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL 0x00
|
||||
#define BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED 0x01
|
||||
|
||||
/** @brief Codec configuration structure */
|
||||
struct bt_audio_codec_data {
|
||||
struct bt_data data;
|
||||
uint8_t value[CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper to declare elements of bt_audio_codec_data arrays
|
||||
*
|
||||
* This macro is mainly for creating an array of struct bt_audio_codec_data elements which is then
|
||||
* passed to the likes of bt_bap_stream_config() or bt_bap_stream_reconfig().
|
||||
*
|
||||
* @param _type Type of advertising data field
|
||||
* @param _bytes Variable number of single-byte parameters
|
||||
*/
|
||||
#define BT_AUDIO_CODEC_DATA(_type, _bytes...) \
|
||||
{ \
|
||||
.data = BT_DATA(_type, ((uint8_t[]){_bytes}), \
|
||||
sizeof((uint8_t[]){_bytes})) \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to declare elements of bt_audio_codec_cap arrays
|
||||
*
|
||||
|
@ -214,7 +193,7 @@ struct bt_audio_codec_data {
|
|||
* @param _type Type of advertising data field
|
||||
* @param _bytes Variable number of single-byte parameters
|
||||
*/
|
||||
#define BT_AUDIO_CODEC_CAP_DATA(_type, _bytes...) \
|
||||
#define BT_AUDIO_CODEC_DATA(_type, _bytes...) \
|
||||
(sizeof((uint8_t)_type) + sizeof((uint8_t[]){_bytes})), (_type), _bytes
|
||||
|
||||
/**
|
||||
|
@ -233,9 +212,9 @@ struct bt_audio_codec_data {
|
|||
.id = _id, \
|
||||
.cid = _cid, \
|
||||
.vid = _vid, \
|
||||
.data_count = ARRAY_SIZE(((struct bt_audio_codec_data[])_data)), \
|
||||
.data_len = sizeof((uint8_t[])_data), \
|
||||
.data = _data, \
|
||||
.meta_count = ARRAY_SIZE(((struct bt_audio_codec_data[])_meta)), \
|
||||
.meta_len = sizeof((uint8_t[])_meta), \
|
||||
.meta = _meta, \
|
||||
})
|
||||
|
||||
|
@ -371,20 +350,37 @@ struct bt_audio_codec_cfg {
|
|||
uint16_t cid;
|
||||
/** Codec Company Vendor ID */
|
||||
uint16_t vid;
|
||||
#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT)
|
||||
/** Codec Specific Configuration Data count */
|
||||
size_t data_count;
|
||||
/** Codec Specific Configuration Data */
|
||||
struct bt_audio_codec_data data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */
|
||||
#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT)
|
||||
/** Codec Specific Configuration Metadata count */
|
||||
size_t meta_count;
|
||||
/** Codec Specific Configuration Metadata */
|
||||
struct bt_audio_codec_data meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT */
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
/** Codec Specific Capabilities Data count */
|
||||
size_t data_len;
|
||||
/** Codec Specific Capabilities Data */
|
||||
uint8_t data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
||||
/** Codec Specific Capabilities Metadata count */
|
||||
size_t meta_len;
|
||||
/** Codec Specific Capabilities Metadata */
|
||||
uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper for parsing length-type-value data.
|
||||
*
|
||||
* @param ltv Length-type-value (LTV) encoded data.
|
||||
* @param size Size of the @p ltv data.
|
||||
* @param func Callback function which will be called for each element
|
||||
* that's found in the data. The callback should return
|
||||
* true to continue parsing, or false to stop parsing.
|
||||
* @param user_data User data to be passed to the callback.
|
||||
*
|
||||
* @retval 0 if all entries were parsed.
|
||||
* @retval -EINVAL if the data is incorrectly encoded
|
||||
* @retval -ECANCELED if parsing was prematurely cancelled by the callback
|
||||
*/
|
||||
int bt_audio_data_parse(const uint8_t ltv[], size_t size,
|
||||
bool (*func)(struct bt_data *data, void *user_data), void *user_data);
|
||||
|
||||
/** @brief Audio Capability type */
|
||||
enum bt_audio_dir {
|
||||
BT_AUDIO_DIR_SINK = 0x01,
|
||||
|
@ -561,22 +557,6 @@ struct bt_audio_codec_qos_pref {
|
|||
uint32_t pref_pd_max;
|
||||
};
|
||||
|
||||
/** @brief Turns an array of bt_audio_codec_data to a flat LTV encoded uint8_t array
|
||||
*
|
||||
* The resulting @p buf array can then be used to send over air.
|
||||
*
|
||||
* @param codec_data The codec data. Can either be codec configuration data,
|
||||
* or codec metadata.
|
||||
* @param count The number of elements in the @p codec_data array
|
||||
* @param buf The resulting buffer to put the LTV encoded data.
|
||||
* @param buf_size The size of @p buf.
|
||||
*
|
||||
* @retval The length of the encoded data if successful.
|
||||
* @retval -ENOMEM if the @p codec_data did not fit into the @p buf.
|
||||
*/
|
||||
ssize_t bt_audio_codec_data_to_buf(const struct bt_audio_codec_data *codec_data, size_t count,
|
||||
uint8_t *buf, size_t buf_size);
|
||||
|
||||
/**
|
||||
* @brief Audio codec Config APIs
|
||||
* @defgroup bt_audio_codec_cfg Codec config parsing APIs
|
||||
|
@ -695,7 +675,7 @@ int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg
|
|||
* @return True if the type is found, false otherwise.
|
||||
*/
|
||||
bool bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
|
||||
const struct bt_audio_codec_data **data);
|
||||
const uint8_t **data);
|
||||
|
||||
/** @} */ /* End of bt_audio_codec_cfg */
|
||||
|
||||
|
|
|
@ -660,13 +660,12 @@ int bt_bap_stream_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group);
|
|||
* created.
|
||||
*
|
||||
* @param stream Stream object
|
||||
* @param meta_count Number of metadata entries
|
||||
* @param meta Metadata entries
|
||||
* @param meta Metadata
|
||||
* @param meta_len Metadata length
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int bt_bap_stream_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count);
|
||||
int bt_bap_stream_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len);
|
||||
|
||||
/**
|
||||
* @brief Change Audio Stream Metadata
|
||||
|
@ -674,13 +673,12 @@ int bt_bap_stream_enable(struct bt_bap_stream *stream, struct bt_audio_codec_dat
|
|||
* This procedure is used by a unicast client or unicast server to change the metadata of a stream.
|
||||
*
|
||||
* @param stream Stream object
|
||||
* @param meta_count Number of metadata entries
|
||||
* @param meta Metadata entries
|
||||
* @param meta Metadata
|
||||
* @param meta_len Metadata length
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int bt_bap_stream_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count);
|
||||
int bt_bap_stream_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len);
|
||||
|
||||
/**
|
||||
* @brief Disable Audio Stream
|
||||
|
@ -865,15 +863,15 @@ struct bt_bap_unicast_server_cb {
|
|||
* Enable callback is called whenever an Audio Stream is requested to be enabled to stream.
|
||||
*
|
||||
* @param[in] stream Stream object being enabled.
|
||||
* @param[in] meta Metadata entries
|
||||
* @param[in] meta_count Number of metadata entries
|
||||
* @param[in] meta Metadata entries.
|
||||
* @param[in] meta_len Length of metadata.
|
||||
* @param[out] rsp Object for the ASE operation response. Only used if the return
|
||||
* value is non-zero.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int (*enable)(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp);
|
||||
int (*enable)(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp);
|
||||
|
||||
/**
|
||||
* @brief Stream Start request callback
|
||||
|
@ -894,15 +892,15 @@ struct bt_bap_unicast_server_cb {
|
|||
* Metadata callback is called whenever an Audio Stream is requested to update its metadata.
|
||||
*
|
||||
* @param[in] stream Stream object.
|
||||
* @param[in] meta Metadata entries
|
||||
* @param[in] meta_count Number of metadata entries
|
||||
* @param[in] meta Metadata entries.
|
||||
* @param[in] meta_len Length of metadata.
|
||||
* @param[out] rsp Object for the ASE operation response. Only used if the return
|
||||
* value is non-zero.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int (*metadata)(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp);
|
||||
int (*metadata)(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp);
|
||||
|
||||
/**
|
||||
* @brief Stream Disable request callback
|
||||
|
@ -1315,18 +1313,12 @@ int bt_bap_unicast_client_discover(struct bt_conn *conn, enum bt_audio_dir dir);
|
|||
struct bt_bap_base_bis_data {
|
||||
/* Unique index of the BIS */
|
||||
uint8_t index;
|
||||
#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT)
|
||||
/** Codec Specific Data count.
|
||||
*
|
||||
* Only valid if the data_count of struct bt_audio_codec_cfg in the subgroup is 0
|
||||
*/
|
||||
size_t data_count;
|
||||
/** Codec Specific Data
|
||||
*
|
||||
* Only valid if the data_count of struct bt_audio_codec_cfg in the subgroup is 0
|
||||
*/
|
||||
struct bt_audio_codec_data data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
/** Codec Specific Data length. */
|
||||
size_t data_len;
|
||||
/** Codec Specific Data */
|
||||
uint8_t data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
};
|
||||
|
||||
struct bt_bap_base_subgroup {
|
||||
|
@ -1334,7 +1326,7 @@ struct bt_bap_base_subgroup {
|
|||
size_t bis_count;
|
||||
/** Codec information for the subgroup
|
||||
*
|
||||
* If the data_count of the codec is 0, then codec specific data may be
|
||||
* If the data_len of the codec is 0, then codec specific data may be
|
||||
* found for each BIS in the bis_data.
|
||||
*/
|
||||
struct bt_audio_codec_cfg codec_cfg;
|
||||
|
@ -1382,17 +1374,17 @@ struct bt_bap_broadcast_source_stream_param {
|
|||
/** Audio stream */
|
||||
struct bt_bap_stream *stream;
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
/**
|
||||
* @brief The number of elements in the @p data array.
|
||||
*
|
||||
* The BIS specific data may be omitted and this set to 0.
|
||||
*/
|
||||
size_t data_count;
|
||||
size_t data_len;
|
||||
|
||||
/** BIS Codec Specific Configuration */
|
||||
struct bt_audio_codec_data *data;
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */
|
||||
uint8_t *data;
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
};
|
||||
|
||||
/** Broadcast Source subgroup parameters*/
|
||||
|
@ -1485,14 +1477,13 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
|
|||
* To update the metadata in the stopped state, use bt_bap_broadcast_source_reconfig().
|
||||
*
|
||||
* @param source Pointer to the broadcast source.
|
||||
* @param meta Metadata entries.
|
||||
* @param meta_count Number of metadata entries.
|
||||
* @param meta Metadata.
|
||||
* @param meta_len Length of metadata.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
|
||||
const struct bt_audio_codec_data meta[],
|
||||
size_t meta_count);
|
||||
const uint8_t meta[], size_t meta_len);
|
||||
|
||||
/**
|
||||
* @brief Start audio broadcast source.
|
||||
|
|
|
@ -241,15 +241,15 @@ struct bt_cap_unicast_audio_update_param {
|
|||
/** @brief Stream for the @p member */
|
||||
struct bt_cap_stream *stream;
|
||||
|
||||
/** The number of entries in @p meta. */
|
||||
size_t meta_count;
|
||||
/** The length of @p meta. */
|
||||
size_t meta_len;
|
||||
|
||||
/** @brief The new metadata.
|
||||
*
|
||||
* The metadata shall a list of CCIDs as
|
||||
* well as a non-0 context bitfield.
|
||||
*/
|
||||
struct bt_audio_codec_data *meta;
|
||||
uint8_t *meta;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -340,14 +340,14 @@ struct bt_cap_initiator_broadcast_stream_param {
|
|||
/** Audio stream */
|
||||
struct bt_cap_stream *stream;
|
||||
|
||||
/** The number of elements in the %p data array.
|
||||
/** The length of the %p data array.
|
||||
*
|
||||
* The BIS specific data may be omitted and this set to 0.
|
||||
*/
|
||||
size_t data_count;
|
||||
size_t data_len;
|
||||
|
||||
/** BIS Codec Specific Configuration */
|
||||
struct bt_audio_codec_data *data;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
struct bt_cap_initiator_broadcast_subgroup_param {
|
||||
|
@ -445,15 +445,14 @@ int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broad
|
|||
* to be enabled.
|
||||
*
|
||||
* @param broadcast_source The broadcast source to update.
|
||||
* @param meta_count The number of entries in @p meta.
|
||||
* @param meta The new metadata. The metadata shall contain a list
|
||||
* of CCIDs as well as a non-0 context bitfield.
|
||||
* @param meta_len The length of @p meta.
|
||||
*
|
||||
* @return 0 on success or negative error value on failure.
|
||||
*/
|
||||
int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source,
|
||||
const struct bt_audio_codec_data meta[],
|
||||
size_t meta_count);
|
||||
const uint8_t meta[], size_t meta_len);
|
||||
|
||||
/**
|
||||
* @brief Stop broadcast audio streams for a Common Audio Profile broadcast source.
|
||||
|
|
|
@ -258,14 +258,14 @@ enum bt_audio_codec_config_type {
|
|||
#define BT_AUDIO_CODEC_CAP_LC3_DATA(_freq, _duration, _chan_count, _len_min, _len_max, \
|
||||
_max_frames_per_sdu) \
|
||||
{ \
|
||||
BT_AUDIO_CODEC_CAP_DATA(BT_AUDIO_CODEC_LC3_FREQ, BT_BYTES_LIST_LE16(_freq)), \
|
||||
BT_AUDIO_CODEC_CAP_DATA(BT_AUDIO_CODEC_LC3_DURATION, (_duration)), \
|
||||
BT_AUDIO_CODEC_CAP_DATA(BT_AUDIO_CODEC_LC3_CHAN_COUNT, (_chan_count)), \
|
||||
BT_AUDIO_CODEC_CAP_DATA(BT_AUDIO_CODEC_LC3_FRAME_LEN, \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FREQ, BT_BYTES_LIST_LE16(_freq)), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_DURATION, (_duration)), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_CHAN_COUNT, (_chan_count)), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_LEN, \
|
||||
BT_BYTES_LIST_LE16(_len_min), \
|
||||
BT_BYTES_LIST_LE16(_len_max)), \
|
||||
COND_CODE_1(_max_frames_per_sdu, (), \
|
||||
(BT_AUDIO_CODEC_CAP_DATA(BT_AUDIO_CODEC_LC3_FRAME_COUNT, \
|
||||
(BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_COUNT, \
|
||||
(_max_frames_per_sdu)))), \
|
||||
}
|
||||
|
||||
|
@ -274,7 +274,7 @@ enum bt_audio_codec_config_type {
|
|||
*/
|
||||
#define BT_AUDIO_CODEC_CAP_LC3_META(_prefer_context) \
|
||||
{ \
|
||||
BT_AUDIO_CODEC_CAP_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \
|
||||
BT_BYTES_LIST_LE16(_prefer_context)) \
|
||||
}
|
||||
|
||||
|
@ -300,35 +300,33 @@ enum bt_audio_codec_config_type {
|
|||
/**
|
||||
* @brief Helper to declare LC3 codec data configuration
|
||||
*
|
||||
* _frame_blocks_per_sdu value is optional and will be included only if != 1
|
||||
* @param _freq Sampling frequency (BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*)
|
||||
* @param _duration Frame duration (BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*)
|
||||
* @param _loc Audio channel location bitfield (@ref bt_audio_location)
|
||||
* @param _len Octets per frame (16-bit integer)
|
||||
* @param _frames_per_sdu Frames per SDU (8-bit integer). This value is optional and will be
|
||||
* included only if != 1
|
||||
*/
|
||||
/* COND_CODE_1 is used to omit an LTV entry in case the _frame_blocks_per_sdu is 1.
|
||||
* COND_CODE_1 will evaluate to second argument if the flag parameter(first argument) is 1
|
||||
* - removing one layer of parentheses.
|
||||
* If the flags argument is != 1 it will evaluate to the third argument which inserts a LTV
|
||||
* entry for the _frame_blocks_per_sdu value.
|
||||
*/
|
||||
#define BT_AUDIO_CODEC_LC3_CONFIG_DATA(_freq, _duration, _loc, _len, _frame_blocks_per_sdu) \
|
||||
#define BT_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu) \
|
||||
{ \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, _freq), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_DURATION, _duration), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_BYTES_LIST_LE16(_freq)), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_DURATION, (_duration)), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, \
|
||||
BT_BYTES_LIST_LE32(_loc)), \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN, \
|
||||
BT_BYTES_LIST_LE16(_len)), \
|
||||
COND_CODE_1(_frame_blocks_per_sdu, (), \
|
||||
(, BT_AUDIO_CODEC_DATA( \
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU, \
|
||||
_frame_blocks_per_sdu))) \
|
||||
BT_BYTES_LIST_LE16(_len)) \
|
||||
COND_CODE_1(_frames_per_sdu, (), \
|
||||
(BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU, \
|
||||
(_frames_per_sdu)))), \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper to declare LC3 codec metadata configuration
|
||||
*/
|
||||
#define BT_AUDIO_CODEC_LC3_CONFIG_META(_stream_context) \
|
||||
#define BT_AUDIO_CODEC_CFG_LC3_META(_stream_context) \
|
||||
{ \
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, \
|
||||
BT_BYTES_LIST_LE16(_stream_context)) \
|
||||
BT_BYTES_LIST_LE16(_stream_context)), \
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -344,8 +342,8 @@ enum bt_audio_codec_config_type {
|
|||
#define BT_AUDIO_CODEC_LC3_CONFIG(_freq, _duration, _loc, _len, _frames_per_sdu, _stream_context) \
|
||||
BT_AUDIO_CODEC_CFG( \
|
||||
BT_AUDIO_CODEC_LC3_ID, 0x0000, 0x0000, \
|
||||
BT_AUDIO_CODEC_LC3_CONFIG_DATA(_freq, _duration, _loc, _len, _frames_per_sdu), \
|
||||
BT_AUDIO_CODEC_LC3_CONFIG_META(_stream_context))
|
||||
BT_AUDIO_CODEC_CFG_LC3_DATA(_freq, _duration, _loc, _len, _frames_per_sdu), \
|
||||
BT_AUDIO_CODEC_CFG_LC3_META(_stream_context))
|
||||
|
||||
/**
|
||||
* @brief Helper to declare LC3 8.1 codec configuration
|
||||
|
|
|
@ -108,7 +108,7 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source)
|
|||
for (size_t j = 0U; j < ARRAY_SIZE(stream_params); j++) {
|
||||
stream_params[j].stream = &streams[j];
|
||||
stream_params[j].data = NULL;
|
||||
stream_params[j].data_count = 0U;
|
||||
stream_params[j].data_len = 0U;
|
||||
bt_bap_stream_cb_register(stream_params[j].stream, &stream_ops);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,24 +58,29 @@ static void print_hex(const uint8_t *ptr, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static bool print_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
const char *str = (const char *)user_data;
|
||||
|
||||
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
|
||||
print_hex(data->data, data->data_len);
|
||||
printk("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid,
|
||||
codec_cfg->vid, codec_cfg->data_count);
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->data_count; i++) {
|
||||
printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type,
|
||||
codec_cfg->data[i].data.data_len);
|
||||
print_hex(codec_cfg->data[i].data.data,
|
||||
codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
codec_cfg->vid, codec_cfg->data_len);
|
||||
|
||||
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
/* LC3 uses the generic LTV format - other codecs might do as well */
|
||||
|
||||
enum bt_audio_location chan_allocation;
|
||||
|
||||
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));
|
||||
printk(" Frame Duration: %d us\n",
|
||||
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
|
||||
|
@ -87,15 +92,11 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
|||
bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
|
||||
printk(" Frames per SDU: %d\n",
|
||||
bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
|
||||
} else {
|
||||
print_hex(codec_cfg->data, codec_cfg->data_len);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->meta_count; i++) {
|
||||
printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type,
|
||||
codec_cfg->meta[i].data.data_len);
|
||||
print_hex(codec_cfg->meta[i].data.data,
|
||||
codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
|
||||
}
|
||||
|
||||
static void print_qos(const struct bt_audio_codec_qos *qos)
|
||||
|
@ -233,10 +234,10 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
|
||||
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -264,25 +265,26 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static bool data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
|
||||
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
const struct bt_audio_codec_data *data = &meta[i];
|
||||
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
|
||||
printk("Invalid metadata type %u or length %u\n",
|
||||
data->data.type, data->data.data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->data.type);
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
|
||||
}
|
||||
|
||||
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <zephyr/bluetooth/audio/tmap.h>
|
||||
|
||||
#define BROADCAST_ENQUEUE_COUNT 2U
|
||||
#define MOCK_CCID 0x1234
|
||||
#define MOCK_CCID 0xAB
|
||||
NET_BUF_POOL_FIXED_DEFINE(tx_pool,
|
||||
(BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT),
|
||||
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL);
|
||||
|
@ -27,16 +27,13 @@ static K_SEM_DEFINE(sem_broadcast_stopped, 0, 1);
|
|||
static struct bt_cap_stream broadcast_source_stream;
|
||||
static struct bt_cap_stream *broadcast_stream;
|
||||
|
||||
struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ);
|
||||
static uint8_t bis_codec_data[] = {BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ))};
|
||||
|
||||
const struct bt_audio_codec_data new_metadata[] = {
|
||||
static const uint8_t new_metadata[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST,
|
||||
(MOCK_CCID & 0xFFU),
|
||||
((MOCK_CCID >> 8) & 0xFFU))
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, MOCK_CCID),
|
||||
};
|
||||
|
||||
static struct bt_bap_lc3_preset broadcast_preset_48_2_1 =
|
||||
|
@ -252,8 +249,8 @@ void cap_initiator_setup(void)
|
|||
int err;
|
||||
|
||||
stream_params.stream = &broadcast_source_stream;
|
||||
stream_params.data_count = 1U;
|
||||
stream_params.data = &bis_codec_data;
|
||||
stream_params.data_len = ARRAY_SIZE(bis_codec_data);
|
||||
stream_params.data = bis_codec_data;
|
||||
|
||||
subgroup_param.stream_count = 1U;
|
||||
subgroup_param.stream_params = &stream_params;
|
||||
|
|
|
@ -180,27 +180,15 @@ static void print_hex(const uint8_t *ptr, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static void print_ltv_elem(const char *str, uint8_t type, uint8_t value_len, const uint8_t *value,
|
||||
size_t cnt)
|
||||
static bool print_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("%s #%zu: type 0x%02x value_len %u\n", str, cnt, type, value_len);
|
||||
print_hex(value, value_len);
|
||||
const char *str = (const char *)user_data;
|
||||
|
||||
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
|
||||
print_hex(data->data, data->data_len);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static void print_ltv_array(const char *str, const uint8_t *ltv_data, size_t ltv_data_len)
|
||||
{
|
||||
size_t cnt = 0U;
|
||||
|
||||
for (size_t i = 0U; i < ltv_data_len; i++) {
|
||||
const uint8_t len = ltv_data[i++];
|
||||
const uint8_t type = ltv_data[i++];
|
||||
const uint8_t *value = <v_data[i];
|
||||
const uint8_t value_len = len - sizeof(type);
|
||||
|
||||
print_ltv_elem(str, type, value_len, value, cnt++);
|
||||
i += value_len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_remote_codec(const struct bt_audio_codec_cap *codec_cap, enum bt_audio_dir dir)
|
||||
|
@ -209,14 +197,14 @@ static void print_remote_codec(const struct bt_audio_codec_cap *codec_cap, enum
|
|||
codec_cap->vid, codec_cap->data_len);
|
||||
|
||||
if (codec_cap->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
print_ltv_array("data", codec_cap->data, codec_cap->data_len);
|
||||
bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data");
|
||||
} else { /* If not LC3, we cannot assume it's LTV */
|
||||
printk("data: ");
|
||||
print_hex(codec_cap->data, codec_cap->data_len);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
print_ltv_array("meta", codec_cap->meta, codec_cap->meta_len);
|
||||
bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta");
|
||||
}
|
||||
|
||||
static void add_remote_sink(struct bt_bap_ep *ep)
|
||||
|
|
|
@ -48,23 +48,28 @@ static void print_hex(const uint8_t *ptr, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static bool print_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
const char *str = (const char *)user_data;
|
||||
|
||||
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
|
||||
print_hex(data->data, data->data_len);
|
||||
printk("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid,
|
||||
codec_cfg->vid, codec_cfg->data_count);
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->data_count; i++) {
|
||||
printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type,
|
||||
codec_cfg->data[i].data.data_len);
|
||||
print_hex(codec_cfg->data[i].data.data,
|
||||
codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
codec_cfg->vid, codec_cfg->data_len);
|
||||
|
||||
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
/* LC3 uses the generic LTV format - other codecs might do as well */
|
||||
|
||||
uint32_t chan_allocation;
|
||||
enum bt_audio_location chan_allocation;
|
||||
|
||||
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));
|
||||
printk(" Frame Duration: %d us\n",
|
||||
|
@ -77,15 +82,11 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
|||
bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
|
||||
printk(" Frames per SDU: %d\n",
|
||||
bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
|
||||
} else {
|
||||
print_hex(codec_cfg->data, codec_cfg->data_len);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->meta_count; i++) {
|
||||
printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type,
|
||||
codec_cfg->meta[i].data.data_len);
|
||||
print_hex(codec_cfg->meta[i].data.data,
|
||||
codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
|
||||
}
|
||||
|
||||
static void print_qos(const struct bt_audio_codec_qos *qos)
|
||||
|
@ -158,10 +159,10 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
|
||||
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -173,46 +174,63 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
struct data_func_param {
|
||||
struct bt_bap_ascs_rsp *rsp;
|
||||
bool stream_context_present;
|
||||
};
|
||||
|
||||
static bool data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
|
||||
bool stream_context_present = false;
|
||||
struct data_func_param *func_param = (struct data_func_param *)user_data;
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
const struct bt_audio_codec_data *data = &meta[i];
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
|
||||
*func_param->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->type);
|
||||
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
|
||||
printk("Invalid metadata type %u or length %u\n",
|
||||
data->data.type, data->data.data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->data.type);
|
||||
|
||||
return -EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->data.type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
|
||||
stream_context_present = true;
|
||||
if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
|
||||
func_param->stream_context_present = true;
|
||||
}
|
||||
|
||||
if (data->data.type == BT_AUDIO_METADATA_TYPE_CCID_LIST) {
|
||||
for (uint8_t j = 0; j < data->data.data_len; j++) {
|
||||
const uint8_t ccid = data->data.data[j];
|
||||
if (data->type == BT_AUDIO_METADATA_TYPE_CCID_LIST) {
|
||||
for (uint8_t j = 0; j < data->data_len; j++) {
|
||||
const uint8_t ccid = data->data[j];
|
||||
|
||||
if (!(IS_ENABLED(CONFIG_BT_TBS_CLIENT_CCID) &&
|
||||
bt_tbs_client_get_by_ccid(default_conn, ccid) != NULL)) {
|
||||
printk("CCID %u is unknown", ccid);
|
||||
*rsp = BT_BAP_ASCS_RSP(
|
||||
BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
*func_param->rsp =
|
||||
BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_context_present == false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
struct data_func_param func_param = {
|
||||
.rsp = rsp,
|
||||
.stream_context_present = false,
|
||||
};
|
||||
int err;
|
||||
|
||||
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
err = bt_audio_data_parse(meta, meta_len, data_func_cb, &func_param);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!func_param.stream_context_present) {
|
||||
printk("Stream audio context not present on peer!");
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
|
|
|
@ -353,27 +353,15 @@ static void print_hex(const uint8_t *ptr, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static void print_ltv_elem(const char *str, uint8_t type, uint8_t value_len, const uint8_t *value,
|
||||
size_t cnt)
|
||||
static bool print_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("%s #%zu: type 0x%02x value_len %u\n", str, cnt, type, value_len);
|
||||
print_hex(value, value_len);
|
||||
const char *str = (const char *)user_data;
|
||||
|
||||
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
|
||||
print_hex(data->data, data->data_len);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static void print_ltv_array(const char *str, const uint8_t *ltv_data, size_t ltv_data_len)
|
||||
{
|
||||
size_t cnt = 0U;
|
||||
|
||||
for (size_t i = 0U; i < ltv_data_len; i++) {
|
||||
const uint8_t len = ltv_data[i++];
|
||||
const uint8_t type = ltv_data[i++];
|
||||
const uint8_t *value = <v_data[i];
|
||||
const uint8_t value_len = len - sizeof(type);
|
||||
|
||||
print_ltv_elem(str, type, value_len, value, cnt++);
|
||||
i += value_len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
|
||||
|
@ -382,14 +370,14 @@ static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
|
|||
codec_cap->vid, codec_cap->data_len);
|
||||
|
||||
if (codec_cap->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
print_ltv_array("data", codec_cap->data, codec_cap->data_len);
|
||||
bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data");
|
||||
} else { /* If not LC3, we cannot assume it's LTV */
|
||||
printk("data: ");
|
||||
print_hex(codec_cap->data, codec_cap->data_len);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
print_ltv_array("meta", codec_cap->meta, codec_cap->meta_len);
|
||||
bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta");
|
||||
}
|
||||
|
||||
static bool check_audio_support_and_connect(struct bt_data *data,
|
||||
|
@ -998,7 +986,7 @@ static int enable_streams(void)
|
|||
int err;
|
||||
|
||||
err = bt_bap_stream_enable(&streams[i], codec_configuration.codec_cfg.meta,
|
||||
codec_configuration.codec_cfg.meta_count);
|
||||
codec_configuration.codec_cfg.meta_len);
|
||||
if (err != 0) {
|
||||
printk("Unable to enable stream: %d\n", err);
|
||||
return err;
|
||||
|
|
|
@ -118,24 +118,29 @@ void print_hex(const uint8_t *ptr, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static bool print_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
const char *str = (const char *)user_data;
|
||||
|
||||
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
|
||||
print_hex(data->data, data->data_len);
|
||||
printk("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid,
|
||||
codec_cfg->vid, codec_cfg->data_count);
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->data_count; i++) {
|
||||
printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type,
|
||||
codec_cfg->data[i].data.data_len);
|
||||
print_hex(codec_cfg->data[i].data.data,
|
||||
codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
codec_cfg->vid, codec_cfg->data_len);
|
||||
|
||||
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
/* LC3 uses the generic LTV format - other codecs might do as well */
|
||||
|
||||
enum bt_audio_location chan_allocation;
|
||||
|
||||
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));
|
||||
printk(" Frame Duration: %d us\n",
|
||||
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
|
||||
|
@ -147,15 +152,11 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
|||
bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
|
||||
printk(" Frames per SDU: %d\n",
|
||||
bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
|
||||
} else {
|
||||
print_hex(codec_cfg->data, codec_cfg->data_len);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->meta_count; i++) {
|
||||
printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type,
|
||||
codec_cfg->meta[i].data.data_len);
|
||||
print_hex(codec_cfg->meta[i].data.data,
|
||||
codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
|
||||
}
|
||||
|
||||
static void print_qos(const struct bt_audio_codec_qos *qos)
|
||||
|
@ -341,10 +342,10 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
|
||||
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
#if defined(CONFIG_LIBLC3)
|
||||
{
|
||||
|
@ -408,25 +409,26 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static bool data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
|
||||
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
const struct bt_audio_codec_data *data = &meta[i];
|
||||
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
|
||||
printk("Invalid metadata type %u or length %u\n",
|
||||
data->data.type, data->data.data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->data.type);
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
|
||||
}
|
||||
|
||||
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
||||
|
|
|
@ -38,29 +38,20 @@ config BT_BAP_UNICAST_CLIENT
|
|||
This option enables support for Bluetooth Unicast Audio Client
|
||||
using Isochronous channels.
|
||||
|
||||
config BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT
|
||||
int "Codec Specific Configuration Data Count"
|
||||
default 5
|
||||
range 1 128
|
||||
config BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE
|
||||
int "Codec Specific Configuration Data Size"
|
||||
default 19
|
||||
range 0 255
|
||||
help
|
||||
This option defines the maximum number of LTV entries a codec can
|
||||
store.
|
||||
Number of octets to support for Codec Specific Configuration data.
|
||||
The default value 19 matches the required fields for the LC3 codec.
|
||||
|
||||
config BT_AUDIO_CODEC_MAX_DATA_LEN
|
||||
int "Codec Capabilities Data Length"
|
||||
config BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE
|
||||
int "Codec Specific Configuration Metadata Size"
|
||||
default 4
|
||||
range 1 128
|
||||
range 0 255
|
||||
help
|
||||
This option defines the maximum value length of an LTV entry a codec
|
||||
can store.
|
||||
|
||||
config BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT
|
||||
int "Codec Specific Configuration Metadata Count"
|
||||
default 2
|
||||
range 1 128
|
||||
help
|
||||
This option defines the maximum number of LTV entries a metadata can
|
||||
store.
|
||||
Number of octets to support for Codec Specific Configuration metadata.
|
||||
|
||||
config BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE
|
||||
int "Codec Capabilities Data Size"
|
||||
|
@ -68,6 +59,7 @@ config BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE
|
|||
range 0 255
|
||||
help
|
||||
Number of octets to support for Codec Specific Capabilities data.
|
||||
The default value 19 matches the required fields for the LC3 codec.
|
||||
|
||||
config BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE
|
||||
int "Codec Capabilities Metadata Size"
|
||||
|
|
|
@ -66,13 +66,6 @@ static struct bt_ascs_ase {
|
|||
bool unexpected_iso_link_loss;
|
||||
} ase_pool[CONFIG_BT_ASCS_MAX_ACTIVE_ASES];
|
||||
|
||||
#define MAX_CODEC_CONFIG \
|
||||
MIN(UINT8_MAX, \
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN)
|
||||
#define MAX_METADATA \
|
||||
MIN(UINT8_MAX, \
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN)
|
||||
|
||||
/* Minimum state size when in the codec configured state */
|
||||
#define MIN_CONFIG_STATE_SIZE (1 + 1 + 1 + 1 + 1 + 2 + 3 + 3 + 3 + 3 + 5 + 1)
|
||||
/* Minimum state size when in the QoS configured state */
|
||||
|
@ -82,9 +75,10 @@ static struct bt_ascs_ase {
|
|||
* size of the Codec Configured state or the QoS Configured state, as either
|
||||
* of them can be the largest state
|
||||
*/
|
||||
#define ASE_BUF_SIZE MIN(BT_ATT_MAX_ATTRIBUTE_LEN, \
|
||||
MAX(MIN_CONFIG_STATE_SIZE + MAX_CODEC_CONFIG, \
|
||||
MIN_QOS_STATE_SIZE + MAX_METADATA))
|
||||
#define ASE_BUF_SIZE \
|
||||
MIN(BT_ATT_MAX_ATTRIBUTE_LEN, \
|
||||
MAX(MIN_CONFIG_STATE_SIZE + CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE, \
|
||||
MIN_QOS_STATE_SIZE + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE))
|
||||
|
||||
/* Verify that the prepare count is large enough to cover the maximum value we support a client
|
||||
* writing
|
||||
|
@ -538,25 +532,6 @@ int ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ascs_codec_data_add(struct net_buf_simple *buf, const char *prefix, uint8_t num,
|
||||
struct bt_audio_codec_data *data)
|
||||
{
|
||||
struct bt_ascs_codec_config *cc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct bt_data *d = &data[i].data;
|
||||
|
||||
LOG_DBG("#%u: %s type 0x%02x len %u", i, prefix, d->type, d->data_len);
|
||||
LOG_HEXDUMP_DBG(d->data, d->data_len, prefix);
|
||||
|
||||
cc = net_buf_simple_add(buf, sizeof(*cc));
|
||||
cc->len = d->data_len + sizeof(cc->type);
|
||||
cc->type = d->type;
|
||||
net_buf_simple_add_mem(buf, d->data, d->data_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ascs_ep_get_status_config(struct bt_bap_ep *ep, struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_ascs_ase_status_config *cfg;
|
||||
|
@ -582,9 +557,8 @@ static void ascs_ep_get_status_config(struct bt_bap_ep *ep, struct net_buf_simpl
|
|||
pref->latency, pref->pd_min, pref->pd_max, pref->pref_pd_min, pref->pref_pd_max,
|
||||
ep->stream->codec_cfg->id);
|
||||
|
||||
cfg->cc_len = buf->len;
|
||||
ascs_codec_data_add(buf, "data", ep->codec_cfg.data_count, ep->codec_cfg.data);
|
||||
cfg->cc_len = buf->len - cfg->cc_len;
|
||||
cfg->cc_len = ep->codec_cfg.data_len;
|
||||
net_buf_simple_add_mem(buf, ep->codec_cfg.data, ep->codec_cfg.data_len);
|
||||
}
|
||||
|
||||
static void ascs_ep_get_status_qos(struct bt_bap_ep *ep, struct net_buf_simple *buf)
|
||||
|
@ -617,9 +591,8 @@ static void ascs_ep_get_status_enable(struct bt_bap_ep *ep, struct net_buf_simpl
|
|||
enable->cig_id = ep->cig_id;
|
||||
enable->cis_id = ep->cis_id;
|
||||
|
||||
enable->metadata_len = buf->len;
|
||||
ascs_codec_data_add(buf, "meta", ep->codec_cfg.meta_count, ep->codec_cfg.meta);
|
||||
enable->metadata_len = buf->len - enable->metadata_len;
|
||||
enable->metadata_len = ep->codec_cfg.meta_len;
|
||||
net_buf_simple_add_mem(buf, ep->codec_cfg.meta, ep->codec_cfg.meta_len);
|
||||
|
||||
LOG_DBG("dir %s cig 0x%02x cis 0x%02x",
|
||||
bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id);
|
||||
|
@ -1302,40 +1275,6 @@ static void ascs_cp_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
|||
LOG_DBG("attr %p value 0x%04x", attr, value);
|
||||
}
|
||||
|
||||
static bool ascs_codec_config_store(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
struct bt_audio_codec_data *cdata;
|
||||
|
||||
if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) {
|
||||
LOG_ERR("No slot available for Codec Config");
|
||||
return false;
|
||||
}
|
||||
|
||||
cdata = &codec_cfg->data[codec_cfg->data_count];
|
||||
|
||||
if (data->data_len > sizeof(cdata->value)) {
|
||||
LOG_ERR("Not enough space for Codec Config: %u > %zu", data->data_len,
|
||||
sizeof(cdata->value));
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DBG("#%u type 0x%02x len %u", codec_cfg->data_count, data->type, data->data_len);
|
||||
|
||||
cdata->data.type = data->type;
|
||||
cdata->data.data_len = data->data_len;
|
||||
|
||||
/* Deep copy data contents */
|
||||
cdata->data.data = cdata->value;
|
||||
(void)memcpy(cdata->value, data->data, data->data_len);
|
||||
|
||||
LOG_HEXDUMP_DBG(cdata->value, data->data_len, "data");
|
||||
|
||||
codec_cfg->data_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct codec_cap_lookup_id_data {
|
||||
uint8_t id;
|
||||
uint16_t cid;
|
||||
|
@ -1360,7 +1299,6 @@ static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data)
|
|||
static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uint16_t vid,
|
||||
uint8_t *cc, uint8_t len, struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
struct net_buf_simple ad;
|
||||
struct bt_audio_codec_cfg *codec_cfg;
|
||||
struct codec_cap_lookup_id_data lookup_data = {
|
||||
.id = id,
|
||||
|
@ -1393,29 +1331,12 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin
|
|||
codec_cfg->id = id;
|
||||
codec_cfg->cid = cid;
|
||||
codec_cfg->vid = vid;
|
||||
codec_cfg->data_count = 0;
|
||||
codec_cfg->data_len = len;
|
||||
memcpy(codec_cfg->data, cc, len);
|
||||
codec_cfg->path_id = lookup_data.codec_cap->path_id;
|
||||
|
||||
if (len == 0) {
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
net_buf_simple_init_with_data(&ad, cc, len);
|
||||
|
||||
/* Parse LTV entries */
|
||||
bt_data_parse(&ad, ascs_codec_config_store, codec_cfg);
|
||||
|
||||
/* Check if all entries could be parsed */
|
||||
if (ad.len) {
|
||||
LOG_ERR("Unable to parse Codec Config: len %u", ad.len);
|
||||
(void)memset(codec_cfg, 0, sizeof(*codec_cfg));
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
|
||||
BT_BAP_ASCS_REASON_CODEC_DATA);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1448,6 +1369,12 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg->cc_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
|
||||
LOG_DBG("Can not store %u codec configuration data", cfg->cc_len);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
switch (ase->ep.status.state) {
|
||||
/* Valid only if ASE_State field = 0x00 (Idle) */
|
||||
case BT_BAP_EP_STATE_IDLE:
|
||||
|
@ -1546,37 +1473,6 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void copy_codec_cfg_pointers(struct bt_audio_codec_cfg *dst,
|
||||
struct bt_audio_codec_cfg *src)
|
||||
{
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
/* Need to update the `bt_data.data` pointer to the new value after copying the codec */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(dst->data); i++) {
|
||||
const struct bt_audio_codec_data *codec_data = &src->data[i];
|
||||
struct bt_audio_codec_data *data = &dst->data[i];
|
||||
const uint8_t data_len = codec_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, codec_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 */
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(dst->meta); i++) {
|
||||
const struct bt_audio_codec_data *meta_data = &src->meta[i];
|
||||
struct bt_audio_codec_data *data = &dst->meta[i];
|
||||
const uint8_t data_len = meta_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, meta_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 &&
|
||||
* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
*/
|
||||
}
|
||||
|
||||
int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream,
|
||||
struct bt_audio_codec_cfg *codec_cfg,
|
||||
const struct bt_audio_codec_qos_pref *qos_pref)
|
||||
|
@ -1629,9 +1525,6 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream,
|
|||
|
||||
(void)memcpy(&ep->codec_cfg, codec_cfg, sizeof(ep->codec_cfg));
|
||||
|
||||
/* TODO: Remove this after refactoring bt_audio_codec_cfg to use flat arrays */
|
||||
copy_codec_cfg_pointers(&ep->codec_cfg, codec_cfg);
|
||||
|
||||
ep->qos_pref = *qos_pref;
|
||||
|
||||
bt_bap_stream_attach(conn, stream, ep, &ep->codec_cfg);
|
||||
|
@ -1979,30 +1872,9 @@ static ssize_t ascs_qos(struct bt_conn *conn, struct net_buf_simple *buf)
|
|||
return buf->size;
|
||||
}
|
||||
|
||||
static bool ascs_codec_store_metadata(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
struct bt_audio_codec_data *meta;
|
||||
|
||||
meta = &codec_cfg->meta[codec_cfg->meta_count];
|
||||
meta->data.type = data->type;
|
||||
meta->data.data_len = data->data_len;
|
||||
|
||||
/* Deep copy data contents */
|
||||
meta->data.data = meta->value;
|
||||
(void)memcpy(meta->value, data->data, data->data_len);
|
||||
|
||||
LOG_DBG("#%zu: data: %s", codec_cfg->meta_count, bt_hex(meta->value, data->data_len));
|
||||
|
||||
codec_cfg->meta_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ascs_parse_result {
|
||||
int err;
|
||||
struct bt_bap_ascs_rsp *rsp;
|
||||
size_t count;
|
||||
const struct bt_bap_ep *ep;
|
||||
};
|
||||
|
||||
|
@ -2014,29 +1886,7 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data)
|
|||
const uint8_t data_type = data->type;
|
||||
const uint8_t *data_value = data->data;
|
||||
|
||||
result->count++;
|
||||
|
||||
LOG_DBG("#%u type 0x%02x len %u", result->count, data_type, data_len);
|
||||
|
||||
if (result->count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT) {
|
||||
LOG_ERR("Not enough buffers for Codec Config Metadata: %zu > %zu", result->count,
|
||||
CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN);
|
||||
*result->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
result->err = -ENOMEM;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data_len > CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN) {
|
||||
LOG_ERR("Not enough space for Codec Config Metadata: %u > %zu", data->data_len,
|
||||
CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN);
|
||||
*result->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
result->err = -ENOMEM;
|
||||
|
||||
return false;
|
||||
}
|
||||
LOG_DBG("type 0x%02x len %u", data_type, data_len);
|
||||
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data_type)) {
|
||||
LOG_WRN("Unknown metadata type 0x%02x", data_type);
|
||||
|
@ -2149,71 +1999,42 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int ascs_verify_metadata(const struct net_buf_simple *buf, struct bt_bap_ep *ep,
|
||||
static int ascs_verify_metadata(struct bt_bap_ep *ep, const struct bt_ascs_metadata *meta,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
struct ascs_parse_result result = {
|
||||
.rsp = rsp,
|
||||
.count = 0U,
|
||||
.err = 0,
|
||||
.ep = ep
|
||||
.ep = ep,
|
||||
};
|
||||
struct net_buf_simple meta_ltv;
|
||||
int err;
|
||||
|
||||
/* Clone the buf to avoid pulling data from the original buffer */
|
||||
net_buf_simple_clone(buf, &meta_ltv);
|
||||
if (meta->len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
|
||||
LOG_WRN("Not enough space for Codec Config Metadata: %u > %d", meta->len,
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Parse LTV entries */
|
||||
bt_data_parse(&meta_ltv, ascs_parse_metadata, &result);
|
||||
err = bt_audio_data_parse(meta->data, meta->len, ascs_parse_metadata, &result);
|
||||
if (err != 0 && err != -ECANCELED) {
|
||||
/* ECANCELED is called if the callback stops the parsing prematurely, in which case
|
||||
* result.err will be set
|
||||
*/
|
||||
LOG_DBG("Failed to parse metadata: %d", err);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_INVALID,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return result.err;
|
||||
}
|
||||
|
||||
static int ascs_ep_set_metadata(struct bt_bap_ep *ep, uint8_t *data, uint8_t len,
|
||||
struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
struct net_buf_simple meta_ltv;
|
||||
int err;
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||
|
||||
if (ep == NULL && codec_cfg == NULL) {
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOG_DBG("ep %p len %u codec %p", ep, len, codec_cfg);
|
||||
|
||||
if (len == 0) {
|
||||
(void)memset(codec_cfg->meta, 0, sizeof(codec_cfg->meta));
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codec_cfg == NULL) {
|
||||
codec_cfg = &ep->codec_cfg;
|
||||
}
|
||||
|
||||
/* Extract metadata LTV for this specific endpoint */
|
||||
net_buf_simple_init_with_data(&meta_ltv, data, len);
|
||||
|
||||
err = ascs_verify_metadata(&meta_ltv, ep, rsp);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* reset cached metadata */
|
||||
ep->codec_cfg.meta_count = 0;
|
||||
|
||||
/* store data contents */
|
||||
bt_data_parse(&meta_ltv, ascs_codec_store_metadata, codec_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta)
|
||||
{
|
||||
struct bt_audio_codec_data metadata_backup[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT];
|
||||
struct bt_bap_stream *stream;
|
||||
struct bt_bap_ep *ep;
|
||||
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
|
||||
|
@ -2239,22 +2060,15 @@ static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!meta->len) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Backup existing metadata */
|
||||
(void)memcpy(metadata_backup, ep->codec_cfg.meta, sizeof(metadata_backup));
|
||||
err = ascs_ep_set_metadata(ep, meta->data, meta->len, &ep->codec_cfg, &rsp);
|
||||
if (err) {
|
||||
ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = ep->stream;
|
||||
if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
|
||||
err = unicast_server_cb->metadata(stream, ep->codec_cfg.meta,
|
||||
ep->codec_cfg.meta_count, &rsp);
|
||||
|
||||
err = ascs_verify_metadata(ep, meta, &rsp);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Invalid metadata from client: %d", err);
|
||||
|
||||
/* rsp will be set by ascs_verify_metadata*/
|
||||
} else if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
|
||||
err = unicast_server_cb->metadata(stream, meta->data, meta->len, &rsp);
|
||||
} else {
|
||||
err = -ENOTSUP;
|
||||
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
|
||||
|
@ -2267,17 +2081,16 @@ static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta)
|
|||
BT_BAP_ASCS_REASON_NONE);
|
||||
}
|
||||
|
||||
/* Restore backup */
|
||||
(void)memcpy(ep->codec_cfg.meta, metadata_backup, sizeof(metadata_backup));
|
||||
|
||||
LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
|
||||
ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason);
|
||||
return;
|
||||
}
|
||||
|
||||
ep->codec_cfg.meta_len = meta->len;
|
||||
(void)memcpy(ep->codec_cfg.meta, meta->data, meta->len);
|
||||
|
||||
/* Set the state to the same state to trigger the notifications */
|
||||
ascs_ep_set_state(ep, ep->status.state);
|
||||
done:
|
||||
ascs_cp_rsp_success(ASE_ID(ase));
|
||||
}
|
||||
|
||||
|
@ -2302,16 +2115,15 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = ascs_ep_set_metadata(ep, meta->data, meta->len, &ep->codec_cfg, &rsp);
|
||||
if (err) {
|
||||
ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason);
|
||||
return err;
|
||||
}
|
||||
|
||||
stream = ep->stream;
|
||||
if (unicast_server_cb != NULL && unicast_server_cb->enable != NULL) {
|
||||
err = unicast_server_cb->enable(stream, ep->codec_cfg.meta,
|
||||
ep->codec_cfg.meta_count, &rsp);
|
||||
|
||||
err = ascs_verify_metadata(ep, meta, &rsp);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Invalid metadata from client: %d", err);
|
||||
|
||||
/* rsp will be set by ascs_verify_metadata*/
|
||||
} else if (unicast_server_cb != NULL && unicast_server_cb->enable != NULL) {
|
||||
err = unicast_server_cb->enable(stream, meta->data, meta->len, &rsp);
|
||||
} else {
|
||||
err = -ENOTSUP;
|
||||
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
|
||||
|
@ -2330,6 +2142,9 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta)
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
ep->codec_cfg.meta_len = meta->len;
|
||||
(void)memcpy(ep->codec_cfg.meta, meta->data, meta->len);
|
||||
|
||||
ascs_ep_set_state(ep, BT_BAP_EP_STATE_ENABLING);
|
||||
|
||||
ascs_cp_rsp_success(ASE_ID(ase));
|
||||
|
@ -2839,6 +2654,14 @@ static ssize_t ascs_metadata(struct bt_conn *conn, struct net_buf_simple *buf)
|
|||
meta = net_buf_simple_pull_mem(buf, sizeof(*meta));
|
||||
(void)net_buf_simple_pull(buf, meta->len);
|
||||
|
||||
if (meta->len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
|
||||
LOG_DBG("Cannot store %u octets of metadata", meta->len);
|
||||
|
||||
ascs_cp_rsp_add(meta->ase, BT_BAP_ASCS_RSP_CODE_NO_MEM,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_valid_ase_id(meta->ase)) {
|
||||
ascs_cp_rsp_add(meta->ase, BT_BAP_ASCS_RSP_CODE_INVALID_ASE,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
|
|
|
@ -18,6 +18,53 @@
|
|||
|
||||
LOG_MODULE_REGISTER(bt_audio, CONFIG_BT_AUDIO_LOG_LEVEL);
|
||||
|
||||
int bt_audio_data_parse(const uint8_t ltv[], size_t size,
|
||||
bool (*func)(struct bt_data *data, void *user_data), void *user_data)
|
||||
{
|
||||
CHECKIF(ltv == NULL) {
|
||||
LOG_DBG("ltv is NULL");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF(func == NULL) {
|
||||
LOG_DBG("func is NULL");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size;) {
|
||||
const uint8_t len = ltv[i++];
|
||||
struct bt_data data;
|
||||
|
||||
if (i + len > size || len < sizeof(data.type)) {
|
||||
LOG_DBG("Invalid len %u at i = %zu", len, i - 1);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data.type = ltv[i++];
|
||||
data.data_len = len - sizeof(data.type);
|
||||
|
||||
if (data.data_len > 0) {
|
||||
data.data = <v[i];
|
||||
} else {
|
||||
data.data = NULL;
|
||||
}
|
||||
|
||||
if (!func(&data, user_data)) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
/* Since we are incrementing i by the value_len, we don't need to increment it
|
||||
* further in the `for` statement
|
||||
*/
|
||||
i += data.data_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
|
||||
static uint8_t bt_audio_security_check(const struct bt_conn *conn)
|
||||
|
@ -109,56 +156,6 @@ ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr *
|
|||
/* Broadcast sink depends on Scan Delegator, so we can just guard it with the Scan Delegator */
|
||||
#if defined(CONFIG_BT_BAP_SCAN_DELEGATOR)
|
||||
|
||||
static int decode_codec_ltv(struct net_buf_simple *buf, struct bt_audio_codec_data *codec_data)
|
||||
{
|
||||
if (buf->len < sizeof(codec_data->data.data_len)) {
|
||||
LOG_DBG("Not enough data for LTV length field: %u", buf->len);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec_data->data.data_len = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if (buf->len < sizeof(codec_data->data.type)) {
|
||||
LOG_DBG("Not enough data for LTV type field: %u", buf->len);
|
||||
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* LTV structures include the data.type in the length field,
|
||||
* but we do not do that for the bt_data struct in Zephyr
|
||||
*/
|
||||
codec_data->data.data_len -= sizeof(codec_data->data.type);
|
||||
|
||||
codec_data->data.type = net_buf_simple_pull_u8(buf);
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
void *value;
|
||||
|
||||
codec_data->data.data = codec_data->value;
|
||||
|
||||
if (buf->len < codec_data->data.data_len) {
|
||||
LOG_DBG("Not enough data for LTV value field: %u/%zu", buf->len,
|
||||
codec_data->data.data_len);
|
||||
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
value = net_buf_simple_pull_mem(buf, codec_data->data.data_len);
|
||||
(void)memcpy(codec_data->value, value, codec_data->data.data_len);
|
||||
#else /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN == 0 */
|
||||
if (codec_data->data.data_len > 0) {
|
||||
LOG_DBG("Cannot store data");
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec_data->data.data = NULL;
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_data *bis)
|
||||
{
|
||||
uint8_t len;
|
||||
|
@ -186,43 +183,24 @@ static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_da
|
|||
}
|
||||
|
||||
if (len > 0) {
|
||||
#if CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
struct net_buf_simple ltv_buf;
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
||||
void *ltv_data;
|
||||
|
||||
/* Use an extra net_buf_simple to be able to decode until it
|
||||
* is empty (len = 0)
|
||||
*/
|
||||
if (len > sizeof(bis->data)) {
|
||||
LOG_DBG("Cannot store codec config data of length %u", len);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ltv_data = net_buf_simple_pull_mem(buf, len);
|
||||
net_buf_simple_init_with_data(<v_buf, ltv_data, len);
|
||||
|
||||
|
||||
while (ltv_buf.len != 0) {
|
||||
struct bt_audio_codec_data *bis_codec_data;
|
||||
int err;
|
||||
|
||||
if (bis->data_count >= ARRAY_SIZE(bis->data)) {
|
||||
LOG_WRN("BIS data overflow; discarding");
|
||||
break;
|
||||
}
|
||||
|
||||
bis_codec_data = &bis->data[bis->data_count];
|
||||
|
||||
err = decode_codec_ltv(<v_buf, bis_codec_data);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to decode BIS config data for entry[%u]: %d",
|
||||
bis->data_count, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bis->data_count++;
|
||||
}
|
||||
#else /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN == 0 */
|
||||
bis->data_len = len;
|
||||
memcpy(bis->data, ltv_data, len);
|
||||
#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE == 0 */
|
||||
LOG_DBG("Cannot store codec config data");
|
||||
|
||||
return -ENOMEM;
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE */
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -230,9 +208,7 @@ static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_da
|
|||
|
||||
static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgroup *subgroup)
|
||||
{
|
||||
struct net_buf_simple ltv_buf;
|
||||
struct bt_audio_codec_cfg *codec_cfg;
|
||||
void *ltv_data;
|
||||
uint8_t len;
|
||||
|
||||
codec_cfg = &subgroup->codec_cfg;
|
||||
|
@ -257,52 +233,26 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0
|
||||
/* Use an extra net_buf_simple to be able to decode until it
|
||||
* is empty (len = 0)
|
||||
*/
|
||||
ltv_data = net_buf_simple_pull_mem(buf, len);
|
||||
net_buf_simple_init_with_data(<v_buf, ltv_data, len);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
void *cfg_ltv_data;
|
||||
|
||||
/* The loop below is very similar to codec_config_store with notable
|
||||
* exceptions that it can do early termination, and also does not log
|
||||
* every LTV entry, which would simply be too much for handling
|
||||
* broadcasted BASEs
|
||||
*/
|
||||
while (ltv_buf.len != 0) {
|
||||
struct bt_audio_codec_data *codec_data;
|
||||
int err;
|
||||
|
||||
if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) {
|
||||
LOG_WRN("BIS codec data overflow; discarding");
|
||||
break;
|
||||
}
|
||||
|
||||
codec_data = &codec_cfg->data[codec_cfg->data_count];
|
||||
|
||||
err = decode_codec_ltv(<v_buf, codec_data);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to decode codec config data for entry %u: %d",
|
||||
codec_cfg->data_count, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
codec_cfg->data_count++;
|
||||
}
|
||||
|
||||
if (buf->len < sizeof(len)) {
|
||||
LOG_DBG("Cannot store BASE in buffer");
|
||||
if (len > sizeof(subgroup->codec_cfg.data)) {
|
||||
LOG_DBG("Cannot store codec config data of length %u", len);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT == 0 */
|
||||
|
||||
cfg_ltv_data = net_buf_simple_pull_mem(buf, len);
|
||||
|
||||
subgroup->codec_cfg.data_len = len;
|
||||
memcpy(subgroup->codec_cfg.data, cfg_ltv_data, len);
|
||||
#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE == 0 */
|
||||
if (len > 0) {
|
||||
LOG_DBG("Cannot store codec config data");
|
||||
LOG_DBG("Cannot store codec config data of length %u", len);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
/* codec metadata length */
|
||||
len = net_buf_simple_pull_u8(buf);
|
||||
|
@ -312,46 +262,26 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0
|
||||
/* Use an extra net_buf_simple to be able to decode until it
|
||||
* is empty (len = 0)
|
||||
*/
|
||||
ltv_data = net_buf_simple_pull_mem(buf, len);
|
||||
net_buf_simple_init_with_data(<v_buf, ltv_data, len);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
||||
void *meta_ltv_data;
|
||||
|
||||
/* The loop below is very similar to codec_config_store with notable
|
||||
* exceptions that it can do early termination, and also does not log
|
||||
* every LTV entry, which would simply be too much for handling
|
||||
* broadcasted BASEs
|
||||
*/
|
||||
while (ltv_buf.len != 0) {
|
||||
struct bt_audio_codec_data *metadata;
|
||||
int err;
|
||||
if (len > sizeof(subgroup->codec_cfg.meta)) {
|
||||
LOG_DBG("Cannot store codec config meta of length %u", len);
|
||||
|
||||
if (codec_cfg->meta_count >= ARRAY_SIZE(codec_cfg->meta)) {
|
||||
LOG_WRN("BIS codec metadata overflow; discarding");
|
||||
break;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
metadata = &codec_cfg->meta[codec_cfg->meta_count];
|
||||
meta_ltv_data = net_buf_simple_pull_mem(buf, len);
|
||||
|
||||
err = decode_codec_ltv(<v_buf, metadata);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to decode codec metadata for entry %u: %d",
|
||||
codec_cfg->meta_count, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
codec_cfg->meta_count++;
|
||||
}
|
||||
#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT == 0 */
|
||||
subgroup->codec_cfg.meta_len = len;
|
||||
memcpy(subgroup->codec_cfg.meta, meta_ltv_data, len);
|
||||
#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE == 0 */
|
||||
if (len > 0) {
|
||||
LOG_DBG("Cannot store metadata");
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE */
|
||||
|
||||
for (size_t i = 0U; i < subgroup->bis_count; i++) {
|
||||
const int err = decode_bis_data(buf, &subgroup->bis_data[i]);
|
||||
|
@ -433,31 +363,3 @@ int bt_bap_decode_base(struct bt_data *data, struct bt_bap_base *base)
|
|||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
|
||||
|
||||
ssize_t bt_audio_codec_data_to_buf(const struct bt_audio_codec_data *codec_data, size_t count,
|
||||
uint8_t *buf, size_t buf_size)
|
||||
{
|
||||
size_t total_len = 0;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const struct bt_data *ltv = &codec_data[i].data;
|
||||
const uint8_t length = ltv->data_len;
|
||||
const uint8_t type = ltv->type;
|
||||
const uint8_t *value = ltv->data;
|
||||
const size_t ltv_len = sizeof(length) + sizeof(type) + length;
|
||||
|
||||
/* Verify that the buffer can hold the next LTV structure */
|
||||
if (buf_size < total_len + ltv_len) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Copy data */
|
||||
buf[total_len++] = length + sizeof(type);
|
||||
buf[total_len++] = type;
|
||||
(void)memcpy(&buf[total_len], value, length);
|
||||
|
||||
total_len += length;
|
||||
}
|
||||
|
||||
return total_len;
|
||||
}
|
||||
|
|
|
@ -450,34 +450,10 @@ static int update_recv_state_base_copy_meta(const struct bt_bap_base *base,
|
|||
for (uint8_t i = 0U; i < base->subgroup_count; i++) {
|
||||
struct bt_bap_scan_delegator_subgroup *subgroup_param = ¶m->subgroups[i];
|
||||
const struct bt_bap_base_subgroup *subgroup = &base->subgroups[i];
|
||||
uint8_t *metadata_param = subgroup_param->metadata;
|
||||
size_t total_len;
|
||||
|
||||
/* Copy metadata into subgroup_param, changing it from an array
|
||||
* of bt_audio_codec_data to a uint8_t buffer
|
||||
*/
|
||||
total_len = 0U;
|
||||
for (size_t j = 0; j < subgroup->codec_cfg.meta_count; j++) {
|
||||
const struct bt_audio_codec_data *meta = &subgroup->codec_cfg.meta[j];
|
||||
const struct bt_data *data = &meta->data;
|
||||
const uint8_t len = data->data_len;
|
||||
const uint8_t type = data->type;
|
||||
const size_t ltv_len = sizeof(len) + sizeof(type) + len;
|
||||
|
||||
if (total_len + ltv_len > sizeof(subgroup_param->metadata)) {
|
||||
LOG_WRN("Could not fit entire metadata for subgroup[%u]", i);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
metadata_param[total_len++] = len + 1;
|
||||
metadata_param[total_len++] = type;
|
||||
(void)memcpy(&metadata_param[total_len], data->data,
|
||||
len);
|
||||
total_len += len;
|
||||
}
|
||||
|
||||
subgroup_param->metadata_len = total_len;
|
||||
subgroup_param->metadata_len = subgroup->codec_cfg.meta_len;
|
||||
memcpy(subgroup_param->metadata, subgroup->codec_cfg.meta,
|
||||
subgroup->codec_cfg.meta_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -307,7 +307,6 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
|
|||
const struct bt_audio_codec_cfg *codec_cfg;
|
||||
uint8_t stream_count;
|
||||
uint8_t bis_index;
|
||||
uint8_t *start;
|
||||
uint8_t len;
|
||||
|
||||
stream_count = 0;
|
||||
|
@ -322,28 +321,15 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
|
|||
net_buf_simple_add_le16(buf, codec_cfg->cid);
|
||||
net_buf_simple_add_le16(buf, codec_cfg->vid);
|
||||
|
||||
/* Insert codec configuration data in LTV format */
|
||||
start = net_buf_simple_add(buf, sizeof(len));
|
||||
|
||||
for (int i = 0; i < codec_cfg->data_count; i++) {
|
||||
const struct bt_data *codec_data = &codec_cfg->data[i].data;
|
||||
|
||||
if ((buf->size - buf->len) < (sizeof(codec_data->data_len) +
|
||||
sizeof(codec_data->type) +
|
||||
codec_data->data_len)) {
|
||||
LOG_DBG("No room for codec[%d] with len %u", i, codec_data->data_len);
|
||||
net_buf_simple_add_u8(buf, codec_cfg->data_len);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
if ((buf->size - buf->len) < codec_cfg->data_len) {
|
||||
LOG_DBG("No room for config data: %zu", codec_cfg->data_len);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
net_buf_simple_add_u8(buf, codec_data->data_len + sizeof(codec_data->type));
|
||||
net_buf_simple_add_u8(buf, codec_data->type);
|
||||
net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len);
|
||||
}
|
||||
/* Calculate length of codec config data */
|
||||
len = net_buf_simple_tail(buf) - start - sizeof(len);
|
||||
/* Update the length field */
|
||||
*start = len;
|
||||
net_buf_simple_add_mem(buf, codec_cfg->data, codec_cfg->data_len);
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
if ((buf->size - buf->len) < sizeof(len)) {
|
||||
LOG_DBG("No room for metadata length");
|
||||
|
@ -351,31 +337,21 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Insert codec metadata in LTV format*/
|
||||
start = net_buf_simple_add(buf, sizeof(len));
|
||||
for (int i = 0; i < codec_cfg->meta_count; i++) {
|
||||
const struct bt_data *metadata = &codec_cfg->meta[i].data;
|
||||
net_buf_simple_add_u8(buf, codec_cfg->meta_len);
|
||||
|
||||
if ((buf->size - buf->len) < (sizeof(metadata->data_len) +
|
||||
sizeof(metadata->type) +
|
||||
metadata->data_len)) {
|
||||
LOG_DBG("No room for metadata[%d] with len %u", i, metadata->data_len);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
||||
if ((buf->size - buf->len) < codec_cfg->meta_len) {
|
||||
LOG_DBG("No room for metadata data: %zu", codec_cfg->meta_len);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
net_buf_simple_add_u8(buf, metadata->data_len + sizeof(metadata->type));
|
||||
net_buf_simple_add_u8(buf, metadata->type);
|
||||
net_buf_simple_add_mem(buf, metadata->data, metadata->data_len);
|
||||
}
|
||||
/* Calculate length of codec config data */
|
||||
len = net_buf_simple_tail(buf) - start - sizeof(len);
|
||||
/* Update the length field */
|
||||
*start = len;
|
||||
net_buf_simple_add_mem(buf, codec_cfg->meta, codec_cfg->meta_len);
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
|
||||
|
||||
/* Create BIS index bitfield */
|
||||
bis_index = 0;
|
||||
for (int i = 0; i < stream_count; i++) {
|
||||
for (uint8_t i = 0U; i < stream_count; i++) {
|
||||
bis_index++;
|
||||
if ((buf->size - buf->len) < (sizeof(bis_index) + sizeof(uint8_t))) {
|
||||
LOG_DBG("No room for BIS[%d] index", i);
|
||||
|
@ -391,32 +367,16 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Insert codec configuration data in LTV format */
|
||||
start = net_buf_simple_add(buf, sizeof(len));
|
||||
|
||||
#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT)
|
||||
for (size_t j = 0U; j < stream_data[i].data_count; j++) {
|
||||
const struct bt_data *codec_data = &stream_data[i].data[j].data;
|
||||
|
||||
if ((buf->size - buf->len) < (sizeof(codec_data->data_len) +
|
||||
sizeof(codec_data->type) +
|
||||
codec_data->data_len)) {
|
||||
LOG_DBG("No room for BIS [%u] codec[%zu] with len %u", bis_index, j,
|
||||
codec_data->data_len);
|
||||
net_buf_simple_add_u8(buf, stream_data[i].data_len);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
if ((buf->size - buf->len) < stream_data[i].data_len) {
|
||||
LOG_DBG("No room for BIS[%u] data: %zu", i, stream_data[i].data_len);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
net_buf_simple_add_u8(buf, codec_data->data_len + sizeof(codec_data->type));
|
||||
net_buf_simple_add_u8(buf, codec_data->type);
|
||||
net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */
|
||||
|
||||
/* Calculate length of codec config data */
|
||||
len = net_buf_simple_tail(buf) - start - sizeof(len);
|
||||
/* Update the length field */
|
||||
*start = len;
|
||||
net_buf_simple_add_mem(buf, stream_data[i].data, stream_data[i].data_len);
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
streams_encoded++;
|
||||
}
|
||||
|
@ -602,34 +562,23 @@ static bool valid_create_param(const struct bt_bap_broadcast_source_create_param
|
|||
return false;
|
||||
}
|
||||
|
||||
CHECKIF(stream_param->data == NULL && stream_param->data_count != 0) {
|
||||
CHECKIF(stream_param->data == NULL && stream_param->data_len != 0) {
|
||||
LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data is "
|
||||
"NULL with count %zu",
|
||||
i, j, stream_param->data_count);
|
||||
"NULL with len %zu",
|
||||
i, j, stream_param->data_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0
|
||||
CHECKIF(stream_param->data_count >
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) {
|
||||
LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data_count too "
|
||||
"large: %zu/%d",
|
||||
i, j, stream_param->data_count,
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t k = 0U; k < stream_param->data_count; k++) {
|
||||
CHECKIF(!(bt_audio_valid_codec_data(&stream_param->data[k]))) {
|
||||
LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data[%zu]"
|
||||
" invalid",
|
||||
i, j, k);
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
CHECKIF(stream_param->data_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
|
||||
LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data_len too "
|
||||
"large: %zu > %d",
|
||||
i, j, stream_param->data_len,
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -755,14 +704,9 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *
|
|||
* only relevant for the broadcast source, and not used
|
||||
* for unicast or broadcast sink.
|
||||
*/
|
||||
(void)memcpy(source->stream_data[stream_count].data,
|
||||
stream_param->data,
|
||||
stream_param->data_count * sizeof(*stream_param->data));
|
||||
source->stream_data[stream_count].data_count = stream_param->data_count;
|
||||
for (uint8_t k = 0U; k < stream_param->data_count; k++) {
|
||||
source->stream_data[stream_count].data[k].data.data =
|
||||
source->stream_data[stream_count].data[k].value;
|
||||
}
|
||||
(void)memcpy(source->stream_data[stream_count].data, stream_param->data,
|
||||
stream_param->data_len * sizeof(*stream_param->data));
|
||||
source->stream_data[stream_count].data_len = stream_param->data_len;
|
||||
|
||||
sys_slist_append(&subgroup->streams, &stream->_node);
|
||||
stream_count++;
|
||||
|
@ -851,30 +795,8 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void broadcast_source_store_metadata(struct bt_audio_codec_cfg *codec_cfg,
|
||||
const struct bt_audio_codec_data meta[],
|
||||
size_t meta_count)
|
||||
{
|
||||
size_t old_meta_count;
|
||||
|
||||
old_meta_count = codec_cfg->meta_count;
|
||||
|
||||
/* Update metadata */
|
||||
codec_cfg->meta_count = meta_count;
|
||||
(void)memcpy(codec_cfg->meta, meta, meta_count * sizeof(*meta));
|
||||
if (old_meta_count > meta_count) {
|
||||
size_t meta_count_diff = old_meta_count - meta_count;
|
||||
|
||||
/* If we previously had more metadata entries we reset the
|
||||
* data that was not overwritten by the new metadata
|
||||
*/
|
||||
(void)memset(&codec_cfg->meta[meta_count], 0, meta_count_diff * sizeof(*meta));
|
||||
}
|
||||
}
|
||||
|
||||
int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
|
||||
const struct bt_audio_codec_data meta[],
|
||||
size_t meta_count)
|
||||
const uint8_t meta[], size_t meta_len)
|
||||
{
|
||||
struct bt_bap_broadcast_subgroup *subgroup;
|
||||
enum bt_bap_ep_state broadcast_state;
|
||||
|
@ -885,29 +807,19 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF((meta == NULL && meta_count != 0) ||
|
||||
(meta != NULL && meta_count == 0)) {
|
||||
LOG_DBG("Invalid metadata combination: %p %zu",
|
||||
meta, meta_count);
|
||||
CHECKIF((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) {
|
||||
LOG_DBG("Invalid metadata combination: %p %zu", meta, meta_len);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF(meta_count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT) {
|
||||
LOG_DBG("Invalid meta_count: %zu (max %d)", meta_count,
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT);
|
||||
CHECKIF(meta_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
|
||||
LOG_DBG("Invalid meta_len: %zu (max %d)", meta_len,
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
CHECKIF(meta[i].data.data_len > sizeof(meta[i].value)) {
|
||||
LOG_DBG("Invalid meta[%zu] data_len %u",
|
||||
i, meta[i].data.data_len);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
broadcast_state = broadcast_source_get_state(source);
|
||||
if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_STREAMING) {
|
||||
LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
|
||||
|
@ -919,7 +831,8 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour
|
|||
* for each subgroup individually
|
||||
*/
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
|
||||
broadcast_source_store_metadata(subgroup->codec_cfg, meta, meta_count);
|
||||
memset(subgroup->codec_cfg->meta, 0, sizeof(subgroup->codec_cfg->meta));
|
||||
memcpy(subgroup->codec_cfg->meta, meta, meta_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -66,14 +66,14 @@ struct bt_bap_unicast_group {
|
|||
sys_slist_t streams;
|
||||
};
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
struct bt_audio_broadcast_stream_data {
|
||||
#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT)
|
||||
/** Codec Specific Data count */
|
||||
size_t data_count;
|
||||
/** Codec Specific Data len */
|
||||
size_t data_len;
|
||||
/** Codec Specific Data */
|
||||
struct bt_audio_codec_data data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */
|
||||
uint8_t data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
|
||||
};
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
struct bt_bap_broadcast_source {
|
||||
uint8_t stream_count;
|
||||
|
@ -84,8 +84,10 @@ struct bt_bap_broadcast_source {
|
|||
struct bt_iso_big *big;
|
||||
struct bt_audio_codec_qos *qos;
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
/* The codec specific configured data for each stream in the subgroup */
|
||||
struct bt_audio_broadcast_stream_data stream_data[BROADCAST_STREAM_CNT];
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE];
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ struct bt_bap_iso_dir {
|
|||
struct bt_bap_ep *ep;
|
||||
struct bt_iso_chan_path path;
|
||||
struct bt_iso_chan_io_qos qos;
|
||||
uint8_t cc[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN];
|
||||
uint8_t cc[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
|
||||
};
|
||||
|
||||
struct bt_bap_iso {
|
||||
|
|
|
@ -131,10 +131,10 @@ static void bt_debug_dump_recv_state(const struct bass_recv_state_internal *recv
|
|||
for (int i = 0; i < state->num_subgroups; i++) {
|
||||
const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i];
|
||||
|
||||
LOG_DBG("\tSubgroup[%d]: BIS sync %u (requested %u), metadata_len %u, metadata: %s",
|
||||
LOG_DBG("\tSubgroup[%d]: BIS sync %u (requested %u), metadata_len %zu, metadata: "
|
||||
"%s",
|
||||
i, subgroup->bis_sync, recv_state->requested_bis_sync[i],
|
||||
subgroup->metadata_len,
|
||||
bt_hex(subgroup->metadata, subgroup->metadata_len));
|
||||
subgroup->metadata_len, bt_hex(subgroup->metadata, subgroup->metadata_len));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,36 +31,16 @@
|
|||
|
||||
LOG_MODULE_REGISTER(bt_bap_stream, CONFIG_BT_BAP_STREAM_LOG_LEVEL);
|
||||
|
||||
static uint8_t pack_bt_audio_codec_cc(const struct bt_audio_codec_cfg *codec_cfg, uint8_t cc[])
|
||||
{
|
||||
uint8_t len;
|
||||
|
||||
len = 0U;
|
||||
for (size_t i = 0U; i < codec_cfg->data_count; i++) {
|
||||
const struct bt_data *data = &codec_cfg->data[i].data;
|
||||
|
||||
/* We assume that data_len and data has previously been verified
|
||||
* and that based on the Kconfigs we can assume that the length
|
||||
* will always fit in `cc`
|
||||
*/
|
||||
cc[len++] = data->data_len + 1;
|
||||
cc[len++] = data->type;
|
||||
(void)memcpy(cc + len, data->data, data->data_len);
|
||||
len += data->data_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path,
|
||||
const struct bt_audio_codec_cfg *codec_cfg)
|
||||
struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
path->pid = codec_cfg->path_id;
|
||||
path->format = codec_cfg->id;
|
||||
path->cid = codec_cfg->cid;
|
||||
path->vid = codec_cfg->vid;
|
||||
path->delay = 0; /* TODO: Add to bt_audio_codec_cfg? Use presentation delay? */
|
||||
path->cc_len = pack_bt_audio_codec_cc(codec_cfg, path->cc);
|
||||
path->cc_len = codec_cfg->data_len;
|
||||
path->cc = codec_cfg->data;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \
|
||||
|
@ -208,19 +188,6 @@ enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_audio_codec_qos *qos
|
|||
return BT_BAP_ASCS_REASON_NONE;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
bool bt_audio_valid_codec_data(const struct bt_audio_codec_data *data)
|
||||
{
|
||||
if (data->data.data_len > ARRAY_SIZE(data->value)) {
|
||||
LOG_DBG("data invalid length: %zu/%zu", data->data.data_len,
|
||||
ARRAY_SIZE(data->value));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 */
|
||||
|
||||
bool bt_audio_valid_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
if (codec_cfg == NULL) {
|
||||
|
@ -228,33 +195,19 @@ bool bt_audio_valid_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
|||
return false;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0
|
||||
if (codec_cfg->data_count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) {
|
||||
LOG_DBG("codec_cfg->data_count (%zu) is invalid", codec_cfg->data_count);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
if (codec_cfg->data_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
|
||||
LOG_DBG("codec_cfg->data_len (%zu) is invalid", codec_cfg->data_len);
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
for (size_t i = 0U; i < codec_cfg->data_count; i++) {
|
||||
if (!bt_audio_valid_codec_data(&codec_cfg->data[i])) {
|
||||
LOG_DBG("codec_cfg->data[%zu] invalid", i);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
||||
if (codec_cfg->meta_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
|
||||
LOG_DBG("codec_cfg->meta_len (%zu) is invalid", codec_cfg->meta_len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0
|
||||
if (codec_cfg->meta_count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT) {
|
||||
LOG_DBG("codec_cfg->meta_count (%zu) is invalid", codec_cfg->meta_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0U; i < codec_cfg->meta_count; i++) {
|
||||
if (!bt_audio_valid_codec_data(&codec_cfg->meta[i])) {
|
||||
LOG_DBG("codec_cfg->meta[%zu] invalid", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -556,9 +509,7 @@ int bt_bap_stream_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_stream_enable(struct bt_bap_stream *stream,
|
||||
struct bt_audio_codec_data *meta,
|
||||
size_t meta_count)
|
||||
int bt_bap_stream_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len)
|
||||
{
|
||||
uint8_t role;
|
||||
int err;
|
||||
|
@ -582,7 +533,7 @@ int bt_bap_stream_enable(struct bt_bap_stream *stream,
|
|||
return -EBADMSG;
|
||||
}
|
||||
|
||||
err = bt_bap_unicast_client_enable(stream, meta, meta_count);
|
||||
err = bt_bap_unicast_client_enable(stream, meta, meta_len);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to enable stream: %d", err);
|
||||
return err;
|
||||
|
@ -720,24 +671,21 @@ int bt_bap_stream_start(struct bt_bap_stream *stream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_stream_metadata(struct bt_bap_stream *stream,
|
||||
struct bt_audio_codec_data *meta,
|
||||
size_t meta_count)
|
||||
int bt_bap_stream_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len)
|
||||
{
|
||||
uint8_t state;
|
||||
uint8_t role;
|
||||
int err;
|
||||
|
||||
LOG_DBG("stream %p metadata count %u", stream, meta_count);
|
||||
LOG_DBG("stream %p meta_len %zu", stream, meta_len);
|
||||
|
||||
CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
|
||||
LOG_DBG("Invalid stream");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF((meta == NULL && meta_count != 0U) ||
|
||||
(meta != NULL && meta_count == 0U)) {
|
||||
LOG_DBG("Invalid meta (%p) or count (%zu)", meta, meta_count);
|
||||
CHECKIF((meta == NULL && meta_len != 0U) || (meta != NULL && meta_len == 0U)) {
|
||||
LOG_DBG("Invalid meta (%p) or len (%zu)", meta, meta_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -755,9 +703,9 @@ int bt_bap_stream_metadata(struct bt_bap_stream *stream,
|
|||
|
||||
role = conn_get_role(stream->conn);
|
||||
if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
|
||||
err = bt_bap_unicast_client_metadata(stream, meta, meta_count);
|
||||
err = bt_bap_unicast_client_metadata(stream, meta, meta_len);
|
||||
} else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
|
||||
err = bt_bap_unicast_server_metadata(stream, meta, meta_count);
|
||||
err = bt_bap_unicast_server_metadata(stream, meta, meta_len);
|
||||
} else {
|
||||
err = -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
@ -18,14 +18,13 @@ void bt_bap_stream_attach(struct bt_conn *conn, struct bt_bap_stream *stream, st
|
|||
struct bt_audio_codec_cfg *codec_cfg);
|
||||
|
||||
void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path,
|
||||
const struct bt_audio_codec_cfg *codec_cfg);
|
||||
struct bt_audio_codec_cfg *codec_cfg);
|
||||
void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io,
|
||||
const struct bt_audio_codec_qos *codec_qos);
|
||||
|
||||
void bt_bap_stream_detach(struct bt_bap_stream *stream);
|
||||
|
||||
enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_audio_codec_qos *qos);
|
||||
bool bt_audio_valid_codec_data(const struct bt_audio_codec_data *data);
|
||||
bool bt_audio_valid_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg);
|
||||
bool bt_bap_stream_can_disconnect(const struct bt_bap_stream *stream);
|
||||
|
||||
|
|
|
@ -1146,68 +1146,6 @@ static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_si
|
|||
}
|
||||
}
|
||||
|
||||
static void unicast_client_codec_data_add(struct net_buf_simple *buf, const char *prefix,
|
||||
size_t num, const struct bt_audio_codec_data *data)
|
||||
{
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
const struct bt_data *d = &data[i].data;
|
||||
struct bt_ascs_codec_config *cc;
|
||||
|
||||
LOG_DBG("#%u: %s type 0x%02x len %u", i, prefix, d->type, d->data_len);
|
||||
LOG_HEXDUMP_DBG(d->data, d->data_len, prefix);
|
||||
|
||||
cc = net_buf_simple_add(buf, sizeof(*cc));
|
||||
cc->len = d->data_len + sizeof(cc->type);
|
||||
cc->type = d->type;
|
||||
net_buf_simple_add_mem(buf, d->data, d->data_len);
|
||||
}
|
||||
}
|
||||
|
||||
static bool unicast_client_codec_data_store(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_data *cdata = user_data;
|
||||
|
||||
if (data->data_len > sizeof(cdata->value)) {
|
||||
LOG_ERR("Not enough space for Codec Config: %u > %zu", data->data_len,
|
||||
sizeof(cdata->value));
|
||||
return false;
|
||||
}
|
||||
|
||||
cdata->data.type = data->type;
|
||||
cdata->data.data_len = data->data_len;
|
||||
|
||||
/* Deep copy data contents */
|
||||
cdata->data.data = cdata->value;
|
||||
(void)memcpy(cdata->value, data->data, data->data_len);
|
||||
|
||||
LOG_HEXDUMP_DBG(cdata->value, data->data_len, "data");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool unicast_client_codec_config_cfg_store(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
struct bt_audio_codec_data *cdata;
|
||||
|
||||
if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) {
|
||||
LOG_ERR("No slot available for Codec Config");
|
||||
return false;
|
||||
}
|
||||
|
||||
cdata = &codec_cfg->data[codec_cfg->data_count];
|
||||
|
||||
LOG_DBG("#%u type 0x%02x len %u", codec_cfg->data_count, data->type, data->data_len);
|
||||
|
||||
if (unicast_client_codec_data_store(data, cdata)) {
|
||||
codec_cfg->data_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool valid_ltv_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
/* just return true to continue parsing as bt_data_parse will validate for us */
|
||||
|
@ -1218,8 +1156,6 @@ static int unicast_client_ep_set_codec_cfg(struct bt_bap_ep *ep, uint8_t id, uin
|
|||
uint16_t vid, void *data, uint8_t len,
|
||||
struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
struct net_buf_simple ad;
|
||||
|
||||
if (!ep && !codec_cfg) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1230,34 +1166,20 @@ static int unicast_client_ep_set_codec_cfg(struct bt_bap_ep *ep, uint8_t id, uin
|
|||
codec_cfg = &ep->codec_cfg;
|
||||
}
|
||||
|
||||
if (len > sizeof(codec_cfg->data)) {
|
||||
LOG_DBG("Cannot store %u octets of codec data", len);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec_cfg->id = id;
|
||||
codec_cfg->cid = cid;
|
||||
codec_cfg->vid = vid;
|
||||
|
||||
/* Reset current metadata */
|
||||
codec_cfg->data_count = 0;
|
||||
(void)memset(codec_cfg->data, 0, sizeof(codec_cfg->data));
|
||||
|
||||
if (!len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
net_buf_simple_init_with_data(&ad, data, len);
|
||||
|
||||
/* Parse LTV entries */
|
||||
bt_data_parse(&ad, unicast_client_codec_config_cfg_store, codec_cfg);
|
||||
|
||||
/* Check if all entries could be parsed */
|
||||
if (ad.len) {
|
||||
LOG_ERR("Unable to parse Codec Config: len %u", ad.len);
|
||||
goto fail;
|
||||
}
|
||||
codec_cfg->data_len = len;
|
||||
memcpy(codec_cfg->data, data, len);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
(void)memset(codec_cfg, 0, sizeof(*codec_cfg));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int unicast_client_set_codec_cap(uint8_t id, uint16_t cid, uint16_t vid, void *data,
|
||||
|
@ -1291,7 +1213,7 @@ static int unicast_client_set_codec_cap(uint8_t id, uint16_t cid, uint16_t vid,
|
|||
* data For any non-LC3 codecs, we cannot verify anything
|
||||
*/
|
||||
if (id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
bt_data_parse(&buf, valid_ltv_cb, codec_cap);
|
||||
bt_data_parse(&buf, valid_ltv_cb, NULL);
|
||||
|
||||
/* Check if all entries could be parsed */
|
||||
if (buf.len) {
|
||||
|
@ -1310,7 +1232,7 @@ static int unicast_client_set_codec_cap(uint8_t id, uint16_t cid, uint16_t vid,
|
|||
|
||||
net_buf_simple_init_with_data(&buf, meta, meta_len);
|
||||
|
||||
bt_data_parse(&buf, valid_ltv_cb, codec_cap);
|
||||
bt_data_parse(&buf, valid_ltv_cb, NULL);
|
||||
|
||||
/* Check if all entries could be parsed */
|
||||
if (buf.len) {
|
||||
|
@ -1325,35 +1247,9 @@ static int unicast_client_set_codec_cap(uint8_t id, uint16_t cid, uint16_t vid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool unicast_client_codec_cfg_metadata_store(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
struct bt_audio_codec_data *meta;
|
||||
|
||||
if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) {
|
||||
LOG_ERR("No slot available for Codec Config");
|
||||
return false;
|
||||
}
|
||||
|
||||
meta = &codec_cfg->data[codec_cfg->meta_count];
|
||||
|
||||
LOG_DBG("#%u type 0x%02x len %u", codec_cfg->meta_count, data->type, data->data_len);
|
||||
|
||||
if (unicast_client_codec_data_store(data, meta)) {
|
||||
codec_cfg->meta_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint8_t len,
|
||||
struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
struct net_buf_simple meta;
|
||||
int err;
|
||||
|
||||
if (!ep && !codec_cfg) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1364,38 +1260,17 @@ static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint
|
|||
codec_cfg = &ep->codec_cfg;
|
||||
}
|
||||
|
||||
if (len > sizeof(codec_cfg->meta)) {
|
||||
LOG_DBG("Cannot store %u octets of metadata", len);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Reset current metadata */
|
||||
codec_cfg->meta_count = 0;
|
||||
(void)memset(codec_cfg->meta, 0, sizeof(codec_cfg->meta));
|
||||
|
||||
if (!len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
net_buf_simple_init_with_data(&meta, data, len);
|
||||
|
||||
/* Parse LTV entries */
|
||||
bt_data_parse(&meta, unicast_client_codec_cfg_metadata_store, codec_cfg);
|
||||
|
||||
/* Check if all entries could be parsed */
|
||||
if (meta.len) {
|
||||
LOG_ERR("Unable to parse Metadata: len %u", meta.len);
|
||||
err = -EINVAL;
|
||||
|
||||
if (meta.len > 2) {
|
||||
/* Value of the Metadata Type field in error */
|
||||
err = meta.data[2];
|
||||
}
|
||||
|
||||
goto fail;
|
||||
}
|
||||
codec_cfg->meta_len = len;
|
||||
(void)memcpy(codec_cfg->meta, data, len);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
codec_cfg->meta_count = 0;
|
||||
(void)memset(codec_cfg->meta, 0, sizeof(codec_cfg->meta));
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint8_t unicast_client_cp_notify(struct bt_conn *conn,
|
||||
|
@ -1881,8 +1756,8 @@ static int unicast_client_ep_config(struct bt_bap_ep *ep, struct net_buf_simple
|
|||
req->codec.vid = codec_cfg->vid;
|
||||
|
||||
cc_len = buf->len;
|
||||
unicast_client_codec_data_add(buf, "data", codec_cfg->data_count, codec_cfg->data);
|
||||
req->cc_len = buf->len - cc_len;
|
||||
req->cc_len = codec_cfg->data_len;
|
||||
net_buf_simple_add_mem(buf, codec_cfg->data, codec_cfg->data_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1934,11 +1809,11 @@ int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *bu
|
|||
}
|
||||
|
||||
static int unicast_client_ep_enable(struct bt_bap_ep *ep, struct net_buf_simple *buf,
|
||||
struct bt_audio_codec_data *meta, size_t meta_count)
|
||||
const uint8_t meta[], size_t meta_len)
|
||||
{
|
||||
struct bt_ascs_metadata *req;
|
||||
|
||||
LOG_DBG("ep %p buf %p metadata count %zu", ep, buf, meta_count);
|
||||
LOG_DBG("ep %p buf %p meta_len %zu", ep, buf, meta_len);
|
||||
|
||||
if (!ep) {
|
||||
return -EINVAL;
|
||||
|
@ -1954,19 +1829,18 @@ static int unicast_client_ep_enable(struct bt_bap_ep *ep, struct net_buf_simple
|
|||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->ase = ep->status.id;
|
||||
|
||||
req->len = buf->len;
|
||||
unicast_client_codec_data_add(buf, "meta", meta_count, meta);
|
||||
req->len = buf->len - req->len;
|
||||
req->len = meta_len;
|
||||
net_buf_simple_add_mem(buf, meta, meta_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unicast_client_ep_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf,
|
||||
struct bt_audio_codec_data *meta, size_t meta_count)
|
||||
const uint8_t meta[], size_t meta_len)
|
||||
{
|
||||
struct bt_ascs_metadata *req;
|
||||
|
||||
LOG_DBG("ep %p buf %p metadata count %zu", ep, buf, meta_count);
|
||||
LOG_DBG("ep %p buf %p meta_len %zu", ep, buf, meta_len);
|
||||
|
||||
if (!ep) {
|
||||
return -EINVAL;
|
||||
|
@ -1988,9 +1862,8 @@ static int unicast_client_ep_metadata(struct bt_bap_ep *ep, struct net_buf_simpl
|
|||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->ase = ep->status.id;
|
||||
|
||||
req->len = buf->len;
|
||||
unicast_client_codec_data_add(buf, "meta", meta_count, meta);
|
||||
req->len = buf->len - req->len;
|
||||
req->len = meta_len;
|
||||
net_buf_simple_add_mem(buf, meta, meta_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3019,8 +2892,8 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count)
|
||||
int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len)
|
||||
{
|
||||
struct bt_bap_ep *ep = stream->ep;
|
||||
struct net_buf_simple *buf;
|
||||
|
@ -3044,7 +2917,7 @@ int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_c
|
|||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x01;
|
||||
|
||||
err = unicast_client_ep_enable(ep, buf, meta, meta_count);
|
||||
err = unicast_client_ep_enable(ep, buf, meta, meta_len);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
@ -3052,8 +2925,8 @@ int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_c
|
|||
return bt_bap_unicast_client_ep_send(stream->conn, ep, buf);
|
||||
}
|
||||
|
||||
int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count)
|
||||
int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len)
|
||||
{
|
||||
struct bt_bap_ep *ep = stream->ep;
|
||||
struct net_buf_simple *buf;
|
||||
|
@ -3077,7 +2950,7 @@ int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_audio
|
|||
req = net_buf_simple_add(buf, sizeof(*req));
|
||||
req->num_ases = 0x01;
|
||||
|
||||
err = unicast_client_ep_metadata(ep, buf, meta, meta_count);
|
||||
err = unicast_client_ep_metadata(ep, buf, meta, meta_len);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ int bt_bap_unicast_client_config(struct bt_bap_stream *stream,
|
|||
|
||||
int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group);
|
||||
|
||||
int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count);
|
||||
int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len);
|
||||
|
||||
int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count);
|
||||
int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len);
|
||||
|
||||
int bt_bap_unicast_client_disable(struct bt_bap_stream *stream);
|
||||
|
||||
|
|
|
@ -112,30 +112,32 @@ int bt_bap_unicast_server_start(struct bt_bap_stream *stream)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data meta[],
|
||||
size_t meta_count)
|
||||
int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len)
|
||||
{
|
||||
struct bt_bap_ep *ep;
|
||||
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
|
||||
BT_BAP_ASCS_REASON_NONE);
|
||||
int err;
|
||||
|
||||
if (meta_len > sizeof(ep->codec_cfg.meta)) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
|
||||
err = unicast_server_cb->metadata(stream, meta, meta_count, &rsp);
|
||||
err = unicast_server_cb->metadata(stream, meta, meta_len, &rsp);
|
||||
} else {
|
||||
err = -ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
|
||||
return err;
|
||||
}
|
||||
|
||||
ep = stream->ep;
|
||||
for (size_t i = 0U; i < meta_count; i++) {
|
||||
(void)memcpy(&ep->codec_cfg.meta[i], &meta[i], sizeof(ep->codec_cfg.meta[i]));
|
||||
}
|
||||
(void)memcpy(ep->codec_cfg.meta, meta, meta_len);
|
||||
|
||||
/* Set the state to the same state to trigger the notifications */
|
||||
return ascs_ep_set_state(ep, ep->status.state);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream,
|
||||
const struct bt_audio_codec_cfg *codec_cfg);
|
||||
int bt_bap_unicast_server_start(struct bt_bap_stream *stream);
|
||||
int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data meta[],
|
||||
size_t meta_count);
|
||||
int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len);
|
||||
int bt_bap_unicast_server_disable(struct bt_bap_stream *stream);
|
||||
int bt_bap_unicast_server_release(struct bt_bap_stream *stream);
|
||||
|
|
|
@ -38,25 +38,35 @@ int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool cap_initiator_valid_metadata(const struct bt_audio_codec_data meta[], size_t meta_count)
|
||||
static bool data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
bool stream_context_found;
|
||||
bool *stream_context_found = (bool *)user_data;
|
||||
|
||||
LOG_DBG("meta %p count %zu", meta, meta_count);
|
||||
LOG_DBG("type %u len %u data %s", data->type, data->data_len,
|
||||
bt_hex(data->data, data->data_len));
|
||||
|
||||
/* Streaming Audio Context shall be present in CAP */
|
||||
stream_context_found = false;
|
||||
for (size_t i = 0U; i < meta_count; i++) {
|
||||
const struct bt_data *metadata = &meta[i].data;
|
||||
|
||||
LOG_DBG("metadata %p type %u len %u data %s",
|
||||
metadata, metadata->type, metadata->data_len,
|
||||
bt_hex(metadata->data, metadata->data_len));
|
||||
|
||||
if (metadata->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
|
||||
stream_context_found = true;
|
||||
break;
|
||||
if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
|
||||
if (data->data_len != 2) { /* Stream context size */
|
||||
return false;
|
||||
}
|
||||
|
||||
*stream_context_found = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cap_initiator_valid_metadata(const uint8_t meta[], size_t meta_len)
|
||||
{
|
||||
bool stream_context_found = false;
|
||||
int err;
|
||||
|
||||
LOG_DBG("meta %p len %zu", meta, meta_len);
|
||||
|
||||
err = bt_audio_data_parse(meta, meta_len, data_func_cb, &stream_context_found);
|
||||
if (err != 0 && err != -ECANCELED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream_context_found) {
|
||||
|
@ -91,7 +101,7 @@ static bool cap_initiator_broadcast_audio_start_valid_param(
|
|||
}
|
||||
|
||||
valid_metadata =
|
||||
cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_count);
|
||||
cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len);
|
||||
|
||||
CHECKIF(!valid_metadata) {
|
||||
LOG_DBG("Invalid metadata supplied for subgroup[%zu]", i);
|
||||
|
@ -141,13 +151,13 @@ static void cap_initiator_broadcast_to_bap_broadcast_param(
|
|||
&bap_subgroup_param->params[j];
|
||||
|
||||
bap_stream_param->stream = &cap_stream_param->stream->bap_stream;
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0
|
||||
bap_stream_param->data_count = cap_stream_param->data_count;
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
bap_stream_param->data_len = cap_stream_param->data_len;
|
||||
/* We do not need to copy the data, as that is the same type of struct, so
|
||||
* we can just point to the CAP parameter data
|
||||
*/
|
||||
bap_stream_param->data = cap_stream_param->data;
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -207,8 +217,7 @@ int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broad
|
|||
}
|
||||
|
||||
int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source,
|
||||
const struct bt_audio_codec_data meta[],
|
||||
size_t meta_count)
|
||||
const uint8_t meta[], size_t meta_len)
|
||||
{
|
||||
CHECKIF(broadcast_source == NULL) {
|
||||
LOG_DBG("broadcast_source is NULL");
|
||||
|
@ -220,13 +229,13 @@ int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broa
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!cap_initiator_valid_metadata(meta, meta_count)) {
|
||||
if (!cap_initiator_valid_metadata(meta, meta_len)) {
|
||||
LOG_DBG("Invalid metadata");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return bt_bap_broadcast_source_update_metadata(broadcast_source->bap_broadcast, meta,
|
||||
meta_count);
|
||||
meta_len);
|
||||
}
|
||||
|
||||
int bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source)
|
||||
|
@ -657,7 +666,7 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st
|
|||
return false;
|
||||
}
|
||||
|
||||
CHECKIF(!cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_count)) {
|
||||
CHECKIF(!cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len)) {
|
||||
LOG_DBG("param->stream_params[%zu].codec_cfg is invalid", i);
|
||||
return false;
|
||||
}
|
||||
|
@ -1019,7 +1028,7 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream)
|
|||
|
||||
/* TODO: Add metadata */
|
||||
err = bt_bap_stream_enable(bap_stream, bap_stream->codec_cfg->meta,
|
||||
bap_stream->codec_cfg->meta_count);
|
||||
bap_stream->codec_cfg->meta_len);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to enable stream %p: %d",
|
||||
cap_stream_active, err);
|
||||
|
@ -1194,7 +1203,7 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda
|
|||
}
|
||||
|
||||
CHECKIF(!cap_initiator_valid_metadata(params[i].meta,
|
||||
params[i].meta_count)) {
|
||||
params[i].meta_len)) {
|
||||
LOG_DBG("params[%zu].meta is invalid", i);
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -1232,7 +1241,7 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda
|
|||
active_proc.streams[i] = params[i].stream;
|
||||
|
||||
err = bt_bap_stream_metadata(¶ms[i].stream->bap_stream, params[i].meta,
|
||||
params[i].meta_count);
|
||||
params[i].meta_len);
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to update metadata for stream %p: %d",
|
||||
params[i].stream, err);
|
||||
|
|
|
@ -18,37 +18,71 @@
|
|||
|
||||
LOG_MODULE_REGISTER(bt_audio_codec, CONFIG_BT_AUDIO_CODEC_LOG_LEVEL);
|
||||
|
||||
bool bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
|
||||
const struct bt_audio_codec_data **data)
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
|
||||
struct search_type_param {
|
||||
uint8_t type;
|
||||
const uint8_t *data;
|
||||
};
|
||||
|
||||
static bool print_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct search_type_param *param = (struct search_type_param *)user_data;
|
||||
|
||||
if (param->type == data->type) {
|
||||
param->data = data->data;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type,
|
||||
const uint8_t **data)
|
||||
{
|
||||
struct search_type_param param = {
|
||||
.type = type,
|
||||
.data = NULL,
|
||||
};
|
||||
int err;
|
||||
|
||||
CHECKIF(codec_cfg == NULL) {
|
||||
LOG_DBG("codec is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->data_count; i++) {
|
||||
if (codec_cfg->data[i].data.type == type) {
|
||||
*data = &codec_cfg->data[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
err = bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, ¶m);
|
||||
if (err != 0 && err != -ECANCELED) {
|
||||
LOG_DBG("Could not parse the data: %d", err);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param.data == NULL) {
|
||||
LOG_DBG("Could not find the type %u", type);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = param.data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
const struct bt_audio_codec_data *element;
|
||||
const uint8_t *data;
|
||||
|
||||
CHECKIF(codec_cfg == NULL) {
|
||||
LOG_DBG("codec is NULL");
|
||||
return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &element)) {
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &data)) {
|
||||
const uint8_t freq = data[0];
|
||||
|
||||
switch (element->data.data[0]) {
|
||||
switch (freq) {
|
||||
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ:
|
||||
return 8000;
|
||||
case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ:
|
||||
|
@ -85,15 +119,17 @@ int bt_audio_codec_cfg_get_freq(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)
|
||||
{
|
||||
const struct bt_audio_codec_data *element;
|
||||
const uint8_t *data;
|
||||
|
||||
CHECKIF(codec_cfg == NULL) {
|
||||
LOG_DBG("codec is NULL");
|
||||
return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_DURATION, &element)) {
|
||||
switch (element->data.data[0]) {
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_DURATION, &data)) {
|
||||
const uint8_t duration = data[0];
|
||||
|
||||
switch (duration) {
|
||||
case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5:
|
||||
return 7500;
|
||||
case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10:
|
||||
|
@ -109,7 +145,7 @@ int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *co
|
|||
int bt_audio_codec_cfg_get_chan_allocation_val(const struct bt_audio_codec_cfg *codec_cfg,
|
||||
enum bt_audio_location *chan_allocation)
|
||||
{
|
||||
const struct bt_audio_codec_data *element;
|
||||
const uint8_t *data;
|
||||
|
||||
CHECKIF(codec_cfg == NULL) {
|
||||
LOG_DBG("codec is NULL");
|
||||
|
@ -120,29 +156,30 @@ int bt_audio_codec_cfg_get_chan_allocation_val(const struct bt_audio_codec_cfg *
|
|||
return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
*chan_allocation = 0;
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, &element)) {
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, &data)) {
|
||||
|
||||
*chan_allocation = sys_le32_to_cpu(*((uint32_t *)&element->data.data[0]));
|
||||
*chan_allocation = sys_get_le32(data);
|
||||
|
||||
return BT_AUDIO_CODEC_PARSE_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
*chan_allocation = 0;
|
||||
|
||||
return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
|
||||
}
|
||||
|
||||
int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
const struct bt_audio_codec_data *element;
|
||||
const uint8_t *data;
|
||||
|
||||
CHECKIF(codec_cfg == NULL) {
|
||||
LOG_DBG("codec is NULL");
|
||||
return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN, &element)) {
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN, &data)) {
|
||||
|
||||
return sys_le16_to_cpu(*((uint16_t *)&element->data.data[0]));
|
||||
return sys_get_le16(data);
|
||||
}
|
||||
|
||||
return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
|
||||
|
@ -151,7 +188,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)
|
||||
{
|
||||
const struct bt_audio_codec_data *element;
|
||||
const uint8_t *data;
|
||||
|
||||
CHECKIF(codec_cfg == NULL) {
|
||||
LOG_DBG("codec is NULL");
|
||||
|
@ -159,9 +196,9 @@ int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg
|
|||
}
|
||||
|
||||
if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU,
|
||||
&element)) {
|
||||
&data)) {
|
||||
|
||||
return element->data.data[0];
|
||||
return data[0];
|
||||
}
|
||||
|
||||
if (fallback_to_default) {
|
||||
|
@ -171,3 +208,4 @@ int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg
|
|||
|
||||
return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND;
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
|
|
@ -147,36 +147,41 @@ static inline void print_qos(const struct shell *sh, const struct bt_audio_codec
|
|||
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE || CONFIG_BT_BAP_UNICAST */
|
||||
}
|
||||
|
||||
static void print_ltv_elem(const struct shell *sh, const char *str, uint8_t type, uint8_t value_len,
|
||||
const uint8_t *value, size_t cnt)
|
||||
struct print_ltv_info {
|
||||
const struct shell *sh;
|
||||
const char *str;
|
||||
size_t cnt;
|
||||
};
|
||||
|
||||
static bool print_ltv_elem(struct bt_data *data, void *user_data)
|
||||
{
|
||||
shell_print(sh, "%s #%zu: type 0x%02x value_len %u", str, cnt, type, value_len);
|
||||
shell_hexdump(sh, value, value_len);
|
||||
struct print_ltv_info *ltv_info = user_data;
|
||||
|
||||
shell_print(ltv_info->sh, "%s #%zu: type 0x%02x value_len %u", ltv_info->str, ltv_info->cnt,
|
||||
data->type, data->data_len);
|
||||
shell_hexdump(ltv_info->sh, data->data, data->data_len);
|
||||
|
||||
ltv_info->cnt++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_ltv_array(const struct shell *sh, const char *str, const uint8_t *ltv_data,
|
||||
size_t ltv_data_len)
|
||||
{
|
||||
size_t cnt = 0U;
|
||||
struct print_ltv_info ltv_info = {
|
||||
.sh = sh,
|
||||
.str = str,
|
||||
.cnt = 0U,
|
||||
};
|
||||
|
||||
for (size_t i = 0U; i < ltv_data_len;) {
|
||||
const uint8_t len = ltv_data[i++];
|
||||
const uint8_t type = ltv_data[i++];
|
||||
const uint8_t *value = <v_data[i];
|
||||
const uint8_t value_len = len - sizeof(type);
|
||||
|
||||
print_ltv_elem(sh, str, type, value_len, value, cnt++);
|
||||
/* Since we are incrementing i by the value_len, we don't need to increment it
|
||||
* further in the `for` statement
|
||||
*/
|
||||
i += value_len;
|
||||
}
|
||||
bt_audio_data_parse(ltv_data, ltv_data_len, print_ltv_elem, <v_info);
|
||||
}
|
||||
|
||||
static inline void print_codec_cap(const struct shell *sh,
|
||||
const struct bt_audio_codec_cap *codec_cap)
|
||||
{
|
||||
shell_print(sh, "codec id 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cap->id,
|
||||
shell_print(sh, "codec cap id 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cap->id,
|
||||
codec_cap->cid, codec_cap->vid, codec_cap->data_len);
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0
|
||||
|
@ -195,26 +200,20 @@ static inline void print_codec_cap(const struct shell *sh,
|
|||
static inline void print_codec_cfg(const struct shell *sh,
|
||||
const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
shell_print(sh, "codec cfg id 0x%02x cid 0x%04x vid 0x%04x", codec_cfg->id, codec_cfg->cid,
|
||||
codec_cfg->vid);
|
||||
shell_print(sh, "codec cfg id 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cfg->id,
|
||||
codec_cfg->cid, codec_cfg->vid, codec_cfg->data_len);
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0
|
||||
shell_print(sh, "data_count %u", codec_cfg->data_count);
|
||||
for (size_t i = 0U; i < codec_cfg->data_count; i++) {
|
||||
shell_print(sh, "data #%u: type 0x%02x len %u", i, codec_cfg->data[i].data.type,
|
||||
codec_cfg->data[i].data.data_len);
|
||||
shell_hexdump(sh, codec_cfg->data[i].data.data, codec_cfg->data[i].data.data_len);
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
print_ltv_array(sh, "data", codec_cfg->data, codec_cfg->data_len);
|
||||
} else { /* If not LC3, we cannot assume it's LTV */
|
||||
shell_hexdump(sh, codec_cfg->data, codec_cfg->data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0
|
||||
shell_print(sh, "meta_count %u", codec_cfg->data_count);
|
||||
for (size_t i = 0U; i < codec_cfg->meta_count; i++) {
|
||||
shell_print(sh, "meta #%u: type 0x%02x len %u", i, codec_cfg->meta[i].data.type,
|
||||
codec_cfg->meta[i].data.data_len);
|
||||
shell_hexdump(sh, codec_cfg->meta[i].data.data, codec_cfg->meta[i].data.data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 */
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
||||
print_ltv_array(sh, "meta", codec_cfg->meta, codec_cfg->meta_len);
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||
|
@ -252,19 +251,9 @@ static inline void print_base(const struct shell *sh, const struct bt_bap_base *
|
|||
shell_print(sh, "BIS[%d] index 0x%02x", j, bis_data->index);
|
||||
bis_indexes[index_count++] = bis_data->index;
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0
|
||||
for (size_t k = 0U; k < bis_data->data_count; k++) {
|
||||
const struct bt_audio_codec_data *codec_data;
|
||||
|
||||
codec_data = &bis_data->data[k];
|
||||
|
||||
shell_print(sh, "data #%u: type 0x%02x len %u", k,
|
||||
codec_data->data.type, codec_data->data.data_len);
|
||||
shell_hexdump(sh, codec_data->data.data,
|
||||
codec_data->data.data_len -
|
||||
sizeof(codec_data->data.type));
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
shell_hexdump(sh, bis_data->data, bis_data->data_len);
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,37 +278,6 @@ static inline void copy_unicast_stream_preset(struct shell_stream *stream,
|
|||
{
|
||||
memcpy(&stream->qos, &named_preset->preset.qos, sizeof(stream->qos));
|
||||
memcpy(&stream->codec_cfg, &named_preset->preset.codec_cfg, sizeof(stream->codec_cfg));
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
/* Need to update the `bt_data.data` pointer to the new value after copying the codec */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.data); i++) {
|
||||
const struct bt_audio_codec_data *preset_data =
|
||||
&named_preset->preset.codec_cfg.data[i];
|
||||
struct bt_audio_codec_data *data = &stream->codec_cfg.data[i];
|
||||
const uint8_t data_len = preset_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, preset_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && \
|
||||
* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 \
|
||||
*/
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.meta); i++) {
|
||||
const struct bt_audio_codec_data *preset_data =
|
||||
&named_preset->preset.codec_cfg.meta[i];
|
||||
struct bt_audio_codec_data *data = &stream->codec_cfg.meta[i];
|
||||
const uint8_t data_len = preset_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, preset_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && \
|
||||
* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 \
|
||||
*/
|
||||
}
|
||||
|
||||
static inline void copy_broadcast_source_preset(struct broadcast_source *source,
|
||||
|
@ -327,73 +285,28 @@ static inline void copy_broadcast_source_preset(struct broadcast_source *source,
|
|||
{
|
||||
memcpy(&source->qos, &named_preset->preset.qos, sizeof(source->qos));
|
||||
memcpy(&source->codec_cfg, &named_preset->preset.codec_cfg, sizeof(source->codec_cfg));
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
/* Need to update the `bt_data.data` pointer to the new value after copying the codec */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(source->codec_cfg.data); i++) {
|
||||
const struct bt_audio_codec_data *preset_data =
|
||||
&named_preset->preset.codec_cfg.data[i];
|
||||
struct bt_audio_codec_data *data = &source->codec_cfg.data[i];
|
||||
const uint8_t data_len = preset_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, preset_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > \
|
||||
* 0 \
|
||||
*/
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(source->codec_cfg.meta); i++) {
|
||||
const struct bt_audio_codec_data *preset_data =
|
||||
&named_preset->preset.codec_cfg.meta[i];
|
||||
struct bt_audio_codec_data *data = &source->codec_cfg.meta[i];
|
||||
const uint8_t data_len = preset_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, preset_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > \
|
||||
* 0 \
|
||||
*/
|
||||
}
|
||||
|
||||
static inline void codec_data_set_chan_alloc(struct bt_audio_codec_data *data,
|
||||
enum bt_audio_location loc)
|
||||
{
|
||||
const uint32_t loc_32 = loc;
|
||||
|
||||
data->data.type = BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC;
|
||||
data->data.data_len = sizeof(loc_32);
|
||||
sys_put_le32(loc_32, data->value);
|
||||
}
|
||||
|
||||
static inline int codec_set_chan_alloc(struct bt_audio_codec_cfg *codec_cfg,
|
||||
enum bt_audio_location loc)
|
||||
{
|
||||
for (size_t i = 0U; i < codec_cfg->data_count; i++) {
|
||||
struct bt_audio_codec_data *data = &codec_cfg->data[i];
|
||||
for (size_t i = 0U; i < codec_cfg->data_len;) {
|
||||
const uint8_t len = codec_cfg->data[i++];
|
||||
const uint8_t type = codec_cfg->data[i++];
|
||||
uint8_t *value = &codec_cfg->data[i];
|
||||
const uint8_t value_len = len - sizeof(type);
|
||||
|
||||
/* Overwrite the location value */
|
||||
if (data->data.type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) {
|
||||
codec_data_set_chan_alloc(data, loc);
|
||||
if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) {
|
||||
const uint32_t loc_32 = loc;
|
||||
|
||||
sys_put_le32(loc_32, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
i += value_len;
|
||||
}
|
||||
|
||||
/* Not found, add new if possible */
|
||||
if (codec_cfg->data_count < CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) {
|
||||
struct bt_audio_codec_data *data = &codec_cfg->data[codec_cfg->data_count++];
|
||||
|
||||
codec_data_set_chan_alloc(data, loc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_AUDIO */
|
||||
|
|
|
@ -506,11 +506,11 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
shell_print(ctx_shell, "Enable: stream %p meta_count %zu", stream,
|
||||
meta_count);
|
||||
shell_print(ctx_shell, "Enable: stream %p meta_len %zu", stream,
|
||||
meta_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -522,26 +522,27 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
|
||||
static bool meta_data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
shell_print(ctx_shell, "Metadata: stream %p meta_count %zu", stream,
|
||||
meta_count);
|
||||
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
const struct bt_audio_codec_data *data = &meta[i];
|
||||
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
|
||||
shell_print(ctx_shell,
|
||||
"Invalid metadata type %u or length %u",
|
||||
data->data.type, data->data.data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->data.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
shell_print(ctx_shell, "Metadata: stream %p meta_len %zu", stream,
|
||||
meta_len);
|
||||
|
||||
return bt_audio_data_parse(meta, meta_len, meta_data_func_cb, rsp);
|
||||
}
|
||||
|
||||
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
||||
|
@ -636,7 +637,7 @@ static int set_metadata(struct bt_audio_codec_cfg *codec_cfg, const char *meta_s
|
|||
}
|
||||
|
||||
/* TODO: Check the type and only overwrite the streaming context */
|
||||
sys_put_le16(context, codec_cfg->meta[0].value);
|
||||
sys_put_le16(context, codec_cfg->meta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1088,18 +1089,37 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[])
|
|||
|
||||
/* If location has been modifed, we update the location in the codec configuration */
|
||||
if (location != BT_AUDIO_LOCATION_PROHIBITED) {
|
||||
for (size_t i = 0U; i < uni_stream->codec_cfg.data_count; i++) {
|
||||
struct bt_audio_codec_data *data = &uni_stream->codec_cfg.data[i];
|
||||
struct bt_audio_codec_cfg *codec_cfg = &uni_stream->codec_cfg;
|
||||
|
||||
/* Overwrite the location value */
|
||||
if (data->data.type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) {
|
||||
for (size_t i = 0U; i < codec_cfg->data_len;) {
|
||||
const uint8_t len = codec_cfg->data[i++];
|
||||
uint8_t *value;
|
||||
uint8_t data_len;
|
||||
uint8_t type;
|
||||
|
||||
if (len == 0 || len > codec_cfg->data_len - i) {
|
||||
/* Invalid len field */
|
||||
return false;
|
||||
}
|
||||
|
||||
type = codec_cfg->data[i++];
|
||||
value = &codec_cfg->data[i];
|
||||
|
||||
if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) {
|
||||
const uint32_t loc_32 = location;
|
||||
|
||||
sys_put_le32(loc_32, data->value);
|
||||
sys_put_le32(loc_32, value);
|
||||
|
||||
shell_print(sh, "Setting location to 0x%08X", location);
|
||||
break;
|
||||
}
|
||||
|
||||
data_len = len - sizeof(type);
|
||||
|
||||
/* Since we are incrementing i by the value_len, we don't need to increment
|
||||
* it further in the `for` statement
|
||||
*/
|
||||
i += data_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1355,7 +1375,7 @@ static int cmd_enable(const struct shell *sh, size_t argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
err = bt_bap_stream_enable(default_stream, codec_cfg->meta, codec_cfg->meta_count);
|
||||
err = bt_bap_stream_enable(default_stream, codec_cfg->meta, codec_cfg->meta_len);
|
||||
if (err) {
|
||||
shell_error(sh, "Unable to enable Channel");
|
||||
return -ENOEXEC;
|
||||
|
@ -1425,9 +1445,6 @@ static int cmd_preset(const struct shell *sh, size_t argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_META_DATA \
|
||||
(CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT * sizeof(struct bt_audio_codec_data))
|
||||
|
||||
static int cmd_metadata(const struct shell *sh, size_t argc, char *argv[])
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg;
|
||||
|
@ -1448,7 +1465,7 @@ static int cmd_metadata(const struct shell *sh, size_t argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
err = bt_bap_stream_metadata(default_stream, codec_cfg->meta, codec_cfg->meta_count);
|
||||
err = bt_bap_stream_metadata(default_stream, codec_cfg->meta, codec_cfg->meta_len);
|
||||
if (err) {
|
||||
shell_error(sh, "Unable to set Channel metadata");
|
||||
return -ENOEXEC;
|
||||
|
@ -1668,6 +1685,14 @@ static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct
|
|||
}
|
||||
}
|
||||
|
||||
static bool print_data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
shell_print(ctx_shell, "type 0x%02x len %u", data->type, data->data_len);
|
||||
shell_hexdump(ctx_shell, data->data, data->data_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base)
|
||||
{
|
||||
uint8_t bis_indexes[BROADCAST_SNK_STREAM_CNT] = { 0 };
|
||||
|
@ -1701,16 +1726,17 @@ static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_ba
|
|||
shell_print(ctx_shell, "%4sBIS[%d] index 0x%02x", "", i, bis_data->index);
|
||||
bis_indexes[index_count++] = bis_data->index;
|
||||
|
||||
for (int k = 0; k < bis_data->data_count; k++) {
|
||||
const struct bt_audio_codec_data *codec_data;
|
||||
if (subgroup->codec_cfg.id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
const int err =
|
||||
bt_audio_data_parse(bis_data->data, bis_data->data_len,
|
||||
print_data_func_cb, NULL);
|
||||
|
||||
codec_data = &bis_data->data[k];
|
||||
|
||||
shell_print(ctx_shell, "%6sdata #%u: type 0x%02x len %u", "", i,
|
||||
codec_data->data.type, codec_data->data.data_len);
|
||||
shell_hexdump(ctx_shell, codec_data->data.data,
|
||||
codec_data->data.data_len -
|
||||
sizeof(codec_data->data.type));
|
||||
if (err != 0) {
|
||||
shell_error(ctx_shell,
|
||||
"Failed to parse BIS codec config: %d", err);
|
||||
}
|
||||
} else {
|
||||
shell_hexdump(ctx_shell, bis_data->data, bis_data->data_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,8 +139,8 @@ static void bap_broadcast_assistant_recv_state_cb(
|
|||
const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i];
|
||||
struct net_buf_simple buf;
|
||||
|
||||
shell_print(ctx_shell, "\t[%d]: BIS sync 0x%04X, metadata_len %u",
|
||||
i, subgroup->bis_sync, subgroup->metadata_len);
|
||||
shell_print(ctx_shell, "\t[%d]: BIS sync 0x%04X, metadata_len %zu", i,
|
||||
subgroup->bis_sync, subgroup->metadata_len);
|
||||
|
||||
net_buf_simple_init_with_data(&buf, (void *)subgroup->metadata,
|
||||
subgroup->metadata_len);
|
||||
|
@ -871,17 +871,12 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh,
|
|||
|
||||
subgroup_param->bis_sync = subgroup_bis_indexes & bis_bitfield_req;
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0
|
||||
metadata_len = bt_audio_codec_data_to_buf(subgroup->codec_cfg.meta,
|
||||
subgroup->codec_cfg.meta_count,
|
||||
subgroup_param->metadata,
|
||||
sizeof(subgroup_param->metadata));
|
||||
if (metadata_len < 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
|
||||
metadata_len = subgroup->codec_cfg.meta_len;
|
||||
memcpy(subgroup_param->metadata, subgroup->codec_cfg.meta, metadata_len);
|
||||
#else
|
||||
metadata_len = 0U;
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 */
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
|
||||
subgroup_param->metadata_len = metadata_len;
|
||||
}
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc,
|
|||
}
|
||||
|
||||
params[count].meta = uni_stream->codec_cfg.meta;
|
||||
params[count].meta_count = uni_stream->codec_cfg.meta_count;
|
||||
params[count].meta_len = uni_stream->codec_cfg.meta_len;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
@ -434,7 +434,7 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc,
|
|||
}
|
||||
|
||||
params[count].meta = uni_stream->codec_cfg.meta;
|
||||
params[count].meta_count = uni_stream->codec_cfg.meta_count;
|
||||
params[count].meta_len = uni_stream->codec_cfg.meta_len;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
@ -1048,13 +1048,13 @@ static int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv,
|
|||
{
|
||||
/* TODO: Use CAP API when the CAP shell has broadcast support */
|
||||
struct bt_bap_broadcast_source_stream_param stream_params[BAP_UNICAST_AC_MAX_SRC] = {0};
|
||||
struct bt_audio_codec_data stereo_data =
|
||||
uint8_t stereo_data[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC,
|
||||
BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT);
|
||||
struct bt_audio_codec_data right_data = BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, BT_AUDIO_LOCATION_FRONT_RIGHT);
|
||||
struct bt_audio_codec_data left_data = BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, BT_AUDIO_LOCATION_FRONT_LEFT);
|
||||
BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT)};
|
||||
uint8_t right_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC,
|
||||
BT_AUDIO_LOCATION_FRONT_RIGHT)};
|
||||
uint8_t left_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC,
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT)};
|
||||
struct bt_bap_broadcast_source_subgroup_param subgroup_param = {0};
|
||||
struct bt_bap_broadcast_source_create_param create_param = {0};
|
||||
const struct named_lc3_preset *named_preset;
|
||||
|
@ -1083,14 +1083,16 @@ static int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv,
|
|||
|
||||
for (size_t i = 0U; i < param->stream_cnt; i++) {
|
||||
stream_params[i].stream = &broadcast_source_streams[i].stream.bap_stream;
|
||||
stream_params[i].data_count = 1U;
|
||||
|
||||
if (param->stream_cnt == 1U) {
|
||||
stream_params[i].data = &stereo_data;
|
||||
stream_params[i].data_len = ARRAY_SIZE(stereo_data);
|
||||
stream_params[i].data = stereo_data;
|
||||
} else if (i == 0U) {
|
||||
stream_params[i].data = &left_data;
|
||||
stream_params[i].data_len = ARRAY_SIZE(left_data);
|
||||
stream_params[i].data = left_data;
|
||||
} else if (i == 1U) {
|
||||
stream_params[i].data = &right_data;
|
||||
stream_params[i].data_len = ARRAY_SIZE(right_data);
|
||||
stream_params[i].data = right_data;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -440,10 +440,9 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_releasing)
|
|||
|
||||
ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_enabling)
|
||||
{
|
||||
struct bt_audio_codec_data meta[] = {
|
||||
const uint8_t meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
};
|
||||
struct bt_bap_stream *stream = &fixture->stream;
|
||||
struct bt_conn *conn = &fixture->conn;
|
||||
|
@ -506,10 +505,9 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_streaming)
|
|||
|
||||
ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_streaming)
|
||||
{
|
||||
struct bt_audio_codec_data meta[] = {
|
||||
const uint8_t meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
};
|
||||
struct bt_bap_stream *stream = &fixture->stream;
|
||||
struct bt_conn *conn = &fixture->conn;
|
||||
|
@ -1023,10 +1021,9 @@ ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_releasing)
|
|||
|
||||
ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_enabling)
|
||||
{
|
||||
struct bt_audio_codec_data meta[] = {
|
||||
const uint8_t meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
};
|
||||
struct bt_bap_stream *stream = &fixture->stream;
|
||||
struct bt_conn *conn = &fixture->conn;
|
||||
|
@ -1066,10 +1063,9 @@ ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_disabling)
|
|||
|
||||
ZTEST_F(test_source_ase_state_transition, test_server_streaming_to_streaming)
|
||||
{
|
||||
struct bt_audio_codec_data meta[] = {
|
||||
const uint8_t meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
};
|
||||
struct bt_bap_stream *stream = &fixture->stream;
|
||||
struct bt_conn *conn = &fixture->conn;
|
||||
|
|
|
@ -491,10 +491,9 @@ static void test_server_config_qos_expect_error(struct bt_bap_stream *stream)
|
|||
|
||||
static void test_server_enable_expect_error(struct bt_bap_stream *stream)
|
||||
{
|
||||
struct bt_audio_codec_data meta[] = {
|
||||
const uint8_t meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_RINGTONE & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_RINGTONE >> 8) & 0xFFU)),
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_RINGTONE)),
|
||||
};
|
||||
int err;
|
||||
|
||||
|
@ -517,10 +516,9 @@ static void test_server_receiver_stop_ready_expect_error(struct bt_bap_stream *s
|
|||
|
||||
static void test_server_update_metadata_expect_error(struct bt_bap_stream *stream)
|
||||
{
|
||||
struct bt_audio_codec_data meta[] = {
|
||||
const uint8_t meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_RINGTONE & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_RINGTONE >> 8) & 0xFFU)),
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_RINGTONE)),
|
||||
};
|
||||
int err;
|
||||
|
||||
|
|
|
@ -25,11 +25,11 @@ DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_reconfig, struct bt_bap_
|
|||
DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_qos, struct bt_bap_stream *,
|
||||
const struct bt_audio_codec_qos *, struct bt_bap_ascs_rsp *);
|
||||
DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_enable, struct bt_bap_stream *,
|
||||
const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *);
|
||||
const uint8_t *, size_t, struct bt_bap_ascs_rsp *);
|
||||
DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_start, struct bt_bap_stream *,
|
||||
struct bt_bap_ascs_rsp *);
|
||||
DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_metadata, struct bt_bap_stream *,
|
||||
const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *);
|
||||
const uint8_t *, size_t, struct bt_bap_ascs_rsp *);
|
||||
DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_disable, struct bt_bap_stream *,
|
||||
struct bt_bap_ascs_rsp *);
|
||||
DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_stop, struct bt_bap_stream *,
|
||||
|
|
|
@ -75,7 +75,7 @@ do {
|
|||
zassert_unreachable("Not implemented");)) \
|
||||
} while (0)
|
||||
|
||||
#define expect_bt_bap_unicast_server_cb_enable_called_once(_stream, _meta, _meta_count) \
|
||||
#define expect_bt_bap_unicast_server_cb_enable_called_once(_stream, _meta, _meta_len) \
|
||||
do { \
|
||||
const char *func_name = "bt_bap_unicast_server_cb.enable"; \
|
||||
\
|
||||
|
@ -90,12 +90,12 @@ do {
|
|||
/* TODO */ \
|
||||
zassert_unreachable("Not implemented");)) \
|
||||
\
|
||||
IF_NOT_EMPTY(_meta_count, ( \
|
||||
IF_NOT_EMPTY(_meta_len, ( \
|
||||
/* TODO */ \
|
||||
zassert_unreachable("Not implemented");)) \
|
||||
} while (0)
|
||||
|
||||
#define expect_bt_bap_unicast_server_cb_metadata_called_once(_stream, _meta, _meta_count) \
|
||||
#define expect_bt_bap_unicast_server_cb_metadata_called_once(_stream, _meta, _meta_len) \
|
||||
do { \
|
||||
const char *func_name = "bt_bap_unicast_server_cb.enable"; \
|
||||
\
|
||||
|
@ -110,7 +110,7 @@ do {
|
|||
/* TODO */ \
|
||||
zassert_unreachable("Not implemented");)) \
|
||||
\
|
||||
IF_NOT_EMPTY(_meta_count, ( \
|
||||
IF_NOT_EMPTY(_meta_len, ( \
|
||||
/* TODO */ \
|
||||
zassert_unreachable("Not implemented");)) \
|
||||
} while (0)
|
||||
|
|
|
@ -24,15 +24,15 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count)
|
||||
int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, uint8_t meta[],
|
||||
size_t meta_len)
|
||||
{
|
||||
zassert_unreachable("Unexpected call to '%s()' occurred", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta,
|
||||
size_t meta_count)
|
||||
int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, uint8_t meta[],
|
||||
size_t meta_len)
|
||||
{
|
||||
zassert_unreachable("Unexpected call to '%s()' occurred", __func__);
|
||||
return 0;
|
||||
|
|
|
@ -40,11 +40,11 @@ DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_reconfig, struct bt_bap_s
|
|||
DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_qos, struct bt_bap_stream *,
|
||||
const struct bt_audio_codec_qos *, struct bt_bap_ascs_rsp *);
|
||||
DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_enable, struct bt_bap_stream *,
|
||||
const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *);
|
||||
const uint8_t *, size_t, struct bt_bap_ascs_rsp *);
|
||||
DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_start, struct bt_bap_stream *,
|
||||
struct bt_bap_ascs_rsp *);
|
||||
DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_metadata, struct bt_bap_stream *,
|
||||
const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *);
|
||||
const uint8_t *, size_t, struct bt_bap_ascs_rsp *);
|
||||
DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_disable, struct bt_bap_stream *,
|
||||
struct bt_bap_ascs_rsp *);
|
||||
DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_stop, struct bt_bap_stream *,
|
||||
|
|
|
@ -61,10 +61,8 @@ CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4
|
|||
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2
|
||||
CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2
|
||||
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT=10
|
||||
CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN=40
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT=10
|
||||
CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN=40
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=255
|
||||
CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=255
|
||||
|
||||
CONFIG_BT_ASCS_ASE_SNK_COUNT=2
|
||||
CONFIG_BT_ASCS_ASE_SRC_COUNT=2
|
||||
|
|
|
@ -95,25 +95,28 @@ static void audio_send_timeout(struct k_work *work);
|
|||
K_THREAD_STACK_DEFINE(iso_data_thread_stack_area, ISO_DATA_THREAD_STACK_SIZE);
|
||||
static struct k_work_q iso_data_work_q;
|
||||
|
||||
static bool print_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
const char *str = (const char *)user_data;
|
||||
|
||||
LOG_DBG("%s: type 0x%02x value_len %u", str, data->type, data->data_len);
|
||||
LOG_HEXDUMP_DBG(data->data, data->data_len, "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
LOG_DBG("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %zu", codec_cfg->id, codec_cfg->cid,
|
||||
codec_cfg->vid, codec_cfg->data_count);
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->data_count; i++) {
|
||||
LOG_DBG("data #%zu: type 0x%02x len %u", i, codec_cfg->data[i].data.type,
|
||||
codec_cfg->data[i].data.data_len);
|
||||
LOG_HEXDUMP_DBG(codec_cfg->data[i].data.data,
|
||||
codec_cfg->data[i].data.data_len -
|
||||
sizeof(codec_cfg->data[i].data.type),
|
||||
"");
|
||||
}
|
||||
LOG_DBG("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cfg->id, codec_cfg->cid,
|
||||
codec_cfg->vid, codec_cfg->data_len);
|
||||
|
||||
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
/* LC3 uses the generic LTV format - other codecs might do as well */
|
||||
|
||||
enum bt_audio_location chan_allocation;
|
||||
|
||||
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));
|
||||
LOG_DBG(" Frame Duration: %d us",
|
||||
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
|
||||
|
@ -125,26 +128,11 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
|||
bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
|
||||
LOG_DBG(" Frames per SDU: %d",
|
||||
bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
|
||||
} else {
|
||||
LOG_HEXDUMP_DBG(codec_cfg->data, codec_cfg->data_len, "data");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < codec_cfg->meta_count; i++) {
|
||||
LOG_DBG("meta #%zu: type 0x%02x len %u", i, codec_cfg->meta[i].data.type,
|
||||
codec_cfg->meta[i].data.data_len);
|
||||
LOG_HEXDUMP_DBG(codec_cfg->meta[i].data.data,
|
||||
codec_cfg->meta[i].data.data_len -
|
||||
sizeof(codec_cfg->meta[i].data.type),
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_ltv_array(const uint8_t *ltv_data, size_t ltv_data_len)
|
||||
{
|
||||
for (size_t i = 0U; i < ltv_data_len;) {
|
||||
const uint8_t len = ltv_data[i] + 1;
|
||||
|
||||
LOG_HEXDUMP_DBG(<v_data[i], len, "");
|
||||
i += len;
|
||||
}
|
||||
bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
|
||||
}
|
||||
|
||||
static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
|
||||
|
@ -152,10 +140,13 @@ static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
|
|||
LOG_DBG("codec_cap 0x%02x cid 0x%04x vid 0x%04x count %zu", codec_cap->id, codec_cap->cid,
|
||||
codec_cap->vid, codec_cap->data_len);
|
||||
|
||||
LOG_DBG("data");
|
||||
print_ltv_array(codec_cap->data, codec_cap->data_len);
|
||||
LOG_DBG("meta");
|
||||
print_ltv_array(codec_cap->meta, codec_cap->meta_len);
|
||||
if (codec_cap->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data");
|
||||
} else {
|
||||
LOG_HEXDUMP_DBG(codec_cap->data, codec_cap->data_len, "data");
|
||||
}
|
||||
|
||||
bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta");
|
||||
}
|
||||
|
||||
static inline void print_qos(const struct bt_audio_codec_qos *qos)
|
||||
|
@ -374,35 +365,33 @@ static bool valid_metadata_type(uint8_t type, uint8_t len, const uint8_t *data)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int check_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp, uint8_t opcode)
|
||||
static bool data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
const struct bt_audio_codec_data *data = data = &meta[i];
|
||||
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
|
||||
|
||||
if (!valid_metadata_type(data->data.type, data->data.data_len, data->data.data)) {
|
||||
LOG_DBG("Invalid metadata type %u or length %u",
|
||||
data->data.type, data->data.data_len);
|
||||
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->data.type);
|
||||
|
||||
btp_send_ascs_operation_completed_ev(stream->conn, stream->ep->status.id,
|
||||
opcode, BTP_ASCS_STATUS_FAILED);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!valid_metadata_type(data->type, data->data_len, data->data)) {
|
||||
LOG_DBG("Invalid metadata type %u or length %u", data->type, data->data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
LOG_DBG("Enable: stream %p meta_count %zu", stream, meta_count);
|
||||
int err;
|
||||
|
||||
return check_metadata(stream, meta, meta_count, rsp, BT_ASCS_ENABLE_OP);
|
||||
LOG_DBG("Metadata: stream %p meta_len %zu", stream, meta_len);
|
||||
|
||||
err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
|
||||
if (err != 0) {
|
||||
btp_send_ascs_operation_completed_ev(stream->conn, stream->ep->status.id,
|
||||
BT_ASCS_ENABLE_OP, BTP_ASCS_STATUS_FAILED);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
||||
|
@ -412,12 +401,20 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
LOG_DBG("Metadata: stream %p meta_count %zu", stream, meta_count);
|
||||
int err;
|
||||
|
||||
return check_metadata(stream, meta, meta_count, rsp, BT_ASCS_METADATA_OP);
|
||||
LOG_DBG("Metadata: stream %p meta_count %zu", stream, meta_len);
|
||||
|
||||
err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
|
||||
if (err != 0) {
|
||||
btp_send_ascs_operation_completed_ev(stream->conn, stream->ep->status.id,
|
||||
BT_ASCS_METADATA_OP, BTP_ASCS_STATUS_FAILED);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
||||
|
@ -680,30 +677,50 @@ static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status
|
|||
tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev));
|
||||
}
|
||||
|
||||
struct search_type_param {
|
||||
uint8_t type;
|
||||
const uint8_t *data;
|
||||
};
|
||||
|
||||
static bool data_type_search_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct search_type_param *param = (struct search_type_param *)user_data;
|
||||
|
||||
if (param->type == data->type) {
|
||||
param->data = data->data;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type,
|
||||
const uint8_t **data)
|
||||
{
|
||||
if (codec_cap == NULL) {
|
||||
LOG_DBG("codec is NULL");
|
||||
struct search_type_param param = {
|
||||
.type = type,
|
||||
.data = NULL,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = bt_audio_data_parse(codec_cap->data, codec_cap->data_len, data_type_search_cb,
|
||||
¶m);
|
||||
if (err != 0 && err != -ECANCELED) {
|
||||
LOG_DBG("Could not parse the data: %d", err);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < codec_cap->data_len;) {
|
||||
const uint8_t len = codec_cap->data[i++];
|
||||
const uint8_t data_type = codec_cap->data[i++];
|
||||
const uint8_t *value = &codec_cap->data[i];
|
||||
const uint8_t value_len = len - 1;
|
||||
if (param.data == NULL) {
|
||||
LOG_DBG("Could not find the type %u", type);
|
||||
|
||||
i += value_len;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data_type == type) {
|
||||
*data = value;
|
||||
*data = param.data;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void btp_send_pac_codec_found_ev(struct bt_conn *conn,
|
||||
|
@ -720,17 +737,21 @@ static void btp_send_pac_codec_found_ev(struct bt_conn *conn,
|
|||
ev.dir = dir;
|
||||
ev.coding_format = codec_cap->id;
|
||||
|
||||
codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FREQ, &data);
|
||||
if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FREQ, &data)) {
|
||||
memcpy(&ev.frequencies, data, sizeof(ev.frequencies));
|
||||
}
|
||||
|
||||
codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_DURATION, &data);
|
||||
if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_DURATION, &data)) {
|
||||
memcpy(&ev.frame_durations, data, sizeof(ev.frame_durations));
|
||||
}
|
||||
|
||||
codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_LEN, &data);
|
||||
if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_FRAME_LEN, &data)) {
|
||||
memcpy(&ev.octets_per_frame, data, sizeof(ev.octets_per_frame));
|
||||
}
|
||||
|
||||
codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_CHAN_COUNT, &data);
|
||||
if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_LC3_CHAN_COUNT, &data)) {
|
||||
memcpy(&ev.channel_counts, data, sizeof(ev.channel_counts));
|
||||
}
|
||||
|
||||
tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_CODEC_CAP_FOUND, &ev, sizeof(ev));
|
||||
}
|
||||
|
@ -1263,40 +1284,6 @@ static int client_create_unicast_group(struct audio_connection *audio_conn, uint
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool codec_config_store(struct bt_data *data, void *user_data)
|
||||
{
|
||||
struct bt_audio_codec_cfg *codec_cfg = user_data;
|
||||
struct bt_audio_codec_data *cdata;
|
||||
|
||||
if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) {
|
||||
LOG_ERR("No slot available for Codec Config");
|
||||
return false;
|
||||
}
|
||||
|
||||
cdata = &codec_cfg->data[codec_cfg->data_count];
|
||||
|
||||
if (data->data_len > sizeof(cdata->value)) {
|
||||
LOG_ERR("Not enough space for Codec Config: %u > %zu", data->data_len,
|
||||
sizeof(cdata->value));
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DBG("#%u type 0x%02x len %u", codec_cfg->data_count, data->type, data->data_len);
|
||||
|
||||
cdata->data.type = data->type;
|
||||
cdata->data.data_len = data->data_len;
|
||||
|
||||
/* Deep copy data contents */
|
||||
cdata->data.data = cdata->value;
|
||||
(void)memcpy(cdata->value, data->data, data->data_len);
|
||||
|
||||
LOG_HEXDUMP_DBG(cdata->value, data->data_len, "data");
|
||||
|
||||
codec_cfg->data_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int client_configure_codec(struct audio_connection *audio_conn, struct bt_conn *conn,
|
||||
uint8_t ase_id, struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
|
@ -1378,7 +1365,6 @@ static uint8_t ascs_configure_codec(const void *cmd, uint16_t cmd_len,
|
|||
struct bt_conn_info conn_info;
|
||||
struct audio_connection *audio_conn;
|
||||
struct bt_audio_codec_cfg *codec_cfg;
|
||||
struct net_buf_simple buf;
|
||||
|
||||
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
|
||||
if (!conn) {
|
||||
|
@ -1398,18 +1384,8 @@ static uint8_t ascs_configure_codec(const void *cmd, uint16_t cmd_len,
|
|||
codec_cfg->cid = cp->cid;
|
||||
|
||||
if (cp->ltvs_len != 0) {
|
||||
net_buf_simple_init_with_data(&buf, (uint8_t *)cp->ltvs, cp->ltvs_len);
|
||||
|
||||
/* Parse LTV entries */
|
||||
bt_data_parse(&buf, codec_config_store, codec_cfg);
|
||||
|
||||
/* Check if all entries could be parsed */
|
||||
if (buf.len) {
|
||||
LOG_DBG("Unable to parse Codec Config: len %u", buf.len);
|
||||
bt_conn_unref(conn);
|
||||
|
||||
return BTP_STATUS_FAILED;
|
||||
}
|
||||
codec_cfg->data_len = cp->ltvs_len;
|
||||
memcpy(codec_cfg->data, cp->ltvs, cp->ltvs_len);
|
||||
}
|
||||
|
||||
if (conn_info.role == BT_HCI_ROLE_CENTRAL) {
|
||||
|
@ -1679,12 +1655,15 @@ static uint8_t ascs_release(const void *cmd, uint16_t cmd_len,
|
|||
|
||||
static uint8_t ascs_update_metadata(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
|
||||
{
|
||||
int err;
|
||||
const uint8_t meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_ANY)),
|
||||
};
|
||||
const struct btp_ascs_update_metadata_cmd *cp = cmd;
|
||||
struct audio_connection *audio_conn;
|
||||
struct audio_stream *stream;
|
||||
struct bt_audio_codec_data meta;
|
||||
struct bt_conn *conn;
|
||||
int err;
|
||||
|
||||
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
|
||||
if (!conn) {
|
||||
|
@ -1700,14 +1679,8 @@ static uint8_t ascs_update_metadata(const void *cmd, uint16_t cmd_len, void *rsp
|
|||
return BTP_STATUS_FAILED;
|
||||
}
|
||||
|
||||
meta.data.data = meta.value;
|
||||
meta.data.type = BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT;
|
||||
meta.data.data_len = 2;
|
||||
meta.value[0] = BT_AUDIO_CONTEXT_TYPE_ANY & 0xFF;
|
||||
meta.value[1] = (BT_AUDIO_CONTEXT_TYPE_ANY >> 8) & 0xFF;
|
||||
|
||||
LOG_DBG("Updating stream metadata");
|
||||
err = bt_bap_stream_metadata(&stream->stream, &meta, 1);
|
||||
err = bt_bap_stream_metadata(&stream->stream, meta, ARRAY_SIZE(meta));
|
||||
if (err != 0) {
|
||||
LOG_DBG("Failed to update stream metadata, err %d", err);
|
||||
return BTP_STATUS_FAILED;
|
||||
|
|
|
@ -27,7 +27,7 @@ CONFIG_BT_ASCS_ASE_SNK_COUNT=2
|
|||
CONFIG_BT_ASCS_ASE_SRC_COUNT=2
|
||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||
CONFIG_BT_BAP_BROADCAST_SINK=y
|
||||
CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN=128
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=196
|
||||
CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=196
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1
|
||||
|
|
|
@ -40,7 +40,7 @@ static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
|
|||
static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(streams));
|
||||
static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams));
|
||||
|
||||
static struct bt_audio_codec_data metadata[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT];
|
||||
static uint8_t metadata[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE];
|
||||
|
||||
/* Create a mask for the maximum BIS we can sync to using the number of streams
|
||||
* we have. We add an additional 1 since the bis indexes start from 1 and not
|
||||
|
|
|
@ -97,8 +97,8 @@ static struct bt_bap_stream_ops stream_ops = {
|
|||
.sent = sent_cb
|
||||
};
|
||||
|
||||
static struct bt_audio_codec_data valid_bis_codec_data =
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
static uint8_t valid_bis_codec_data[] = {BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ))};
|
||||
|
||||
static void broadcast_source_create_inval_reset_param(
|
||||
struct bt_bap_broadcast_source_create_param *param,
|
||||
|
@ -110,8 +110,8 @@ static void broadcast_source_create_inval_reset_param(
|
|||
struct bt_bap_broadcast_source_create_param create_param;
|
||||
|
||||
valid_stream_param.stream = &broadcast_source_streams[0];
|
||||
valid_stream_param.data_count = 1U;
|
||||
valid_stream_param.data = &valid_bis_codec_data;
|
||||
valid_stream_param.data_len = ARRAY_SIZE(valid_bis_codec_data);
|
||||
valid_stream_param.data = valid_bis_codec_data;
|
||||
|
||||
valid_subgroup_param.params_count = 1U;
|
||||
valid_subgroup_param.params = &valid_stream_param;
|
||||
|
@ -154,15 +154,15 @@ static void broadcast_source_create_inval_stream_param(void)
|
|||
broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param);
|
||||
|
||||
/* Initialize codec configuration data that is too large */
|
||||
stream_param.data_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT + 1;
|
||||
stream_param.data_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_create with stream_param.data_count %zu\n",
|
||||
stream_param.data_count);
|
||||
printk("Test bt_bap_broadcast_source_create with stream_param.data_len %zu\n",
|
||||
stream_param.data_len);
|
||||
err = bt_bap_broadcast_source_create(&create_param, &broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_create with stream_param data count %u "
|
||||
FAIL("bt_bap_broadcast_source_create with stream_param data len %u "
|
||||
"did not fail\n",
|
||||
stream_param.data_count);
|
||||
stream_param.data_len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -181,22 +181,22 @@ static void broadcast_source_create_inval_stream_param(void)
|
|||
|
||||
broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param);
|
||||
|
||||
if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) {
|
||||
struct bt_audio_codec_data bis_codec_data;
|
||||
if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE < 255) {
|
||||
uint8_t bis_codec_data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + 1] = {0};
|
||||
|
||||
memcpy(&bis_codec_data, &valid_bis_codec_data, sizeof(valid_bis_codec_data));
|
||||
memcpy(bis_codec_data, valid_bis_codec_data, ARRAY_SIZE(valid_bis_codec_data));
|
||||
|
||||
/* Set LTV data to invalid size */
|
||||
bis_codec_data.data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1;
|
||||
stream_param.data = &bis_codec_data;
|
||||
stream_param.data_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + 1;
|
||||
stream_param.data = bis_codec_data;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_create with CC LTV size %u\n",
|
||||
bis_codec_data.data.data_len);
|
||||
stream_param.data_len);
|
||||
err = bt_bap_broadcast_source_create(&create_param, &broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_create with CC LTV size %u in stream_param "
|
||||
"did not fail\n",
|
||||
bis_codec_data.data.data_len);
|
||||
stream_param.data_len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -215,14 +215,13 @@ static void broadcast_source_create_inval_subgroup_codec_param(void)
|
|||
subgroup_param.codec_cfg =
|
||||
memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg));
|
||||
|
||||
codec_cfg.data_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT + 1;
|
||||
codec_cfg.data_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_create with codec.data_count %u\n",
|
||||
codec_cfg.data_count);
|
||||
printk("Test bt_bap_broadcast_source_create with codec.data_len %zu\n", codec_cfg.data_len);
|
||||
err = bt_bap_broadcast_source_create(&create_param, &broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_create with codec data count %zu did not fail\n",
|
||||
codec_cfg.data_count);
|
||||
FAIL("bt_bap_broadcast_source_create with codec data len %zu did not fail\n",
|
||||
codec_cfg.data_len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -230,53 +229,52 @@ static void broadcast_source_create_inval_subgroup_codec_param(void)
|
|||
subgroup_param.codec_cfg =
|
||||
memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg));
|
||||
|
||||
codec_cfg.meta_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT + 1;
|
||||
codec_cfg.meta_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_create with codec.meta_count %u\n",
|
||||
codec_cfg.meta_count);
|
||||
printk("Test bt_bap_broadcast_source_create with codec.meta_len %zu\n", codec_cfg.meta_len);
|
||||
err = bt_bap_broadcast_source_create(&create_param, &broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_create with codec meta count %zu did not fail\n",
|
||||
codec_cfg.meta_count);
|
||||
FAIL("bt_bap_broadcast_source_create with codec meta len %zu did not fail\n",
|
||||
codec_cfg.meta_len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) {
|
||||
if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE < 255) {
|
||||
broadcast_source_create_inval_reset_param(&create_param, &subgroup_param,
|
||||
&stream_param);
|
||||
subgroup_param.codec_cfg = memcpy(&codec_cfg, &preset_16_2_1.codec_cfg,
|
||||
sizeof(preset_16_2_1.codec_cfg));
|
||||
|
||||
/* Set LTV data to invalid size */
|
||||
codec_cfg.data[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1;
|
||||
codec_cfg.data_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_create with CC LTV size %u\n",
|
||||
codec_cfg.data[0].data.data_len);
|
||||
codec_cfg.data_len);
|
||||
err = bt_bap_broadcast_source_create(&create_param, &broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_create with CC LTV size %zu in "
|
||||
"subgroup_param did not fail\n",
|
||||
codec_cfg.data[0].data.data_len);
|
||||
codec_cfg.data_len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) {
|
||||
if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE < 255) {
|
||||
broadcast_source_create_inval_reset_param(&create_param, &subgroup_param,
|
||||
&stream_param);
|
||||
subgroup_param.codec_cfg = memcpy(&codec_cfg, &preset_16_2_1.codec_cfg,
|
||||
sizeof(preset_16_2_1.codec_cfg));
|
||||
|
||||
/* Set LTV data to invalid size */
|
||||
codec_cfg.meta[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1;
|
||||
codec_cfg.meta_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_create with Meta LTV size %u\n",
|
||||
codec_cfg.meta[0].data.data_len);
|
||||
codec_cfg.meta_len);
|
||||
err = bt_bap_broadcast_source_create(&create_param, &broadcast_source);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_create with meta LTV size %zu in "
|
||||
"subgroup_param did not fail\n",
|
||||
codec_cfg.meta[0].data.data_len);
|
||||
codec_cfg.meta_len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -542,8 +540,8 @@ static void broadcast_source_create_inval(void)
|
|||
|
||||
static int setup_broadcast_source(struct bt_bap_broadcast_source **source)
|
||||
{
|
||||
struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
uint8_t bis_codec_data[] = {3, BT_AUDIO_CODEC_CONFIG_LC3_FREQ,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)};
|
||||
struct bt_bap_broadcast_source_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_bap_broadcast_source_subgroup_param
|
||||
|
@ -558,8 +556,10 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source)
|
|||
stream_params[i].stream = &broadcast_source_streams[i];
|
||||
bt_bap_stream_cb_register(stream_params[i].stream,
|
||||
&stream_ops);
|
||||
stream_params[i].data_count = 1U;
|
||||
stream_params[i].data = &bis_codec_data;
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
|
||||
stream_params[i].data_len = ARRAY_SIZE(bis_codec_data);
|
||||
stream_params[i].data = bis_codec_data;
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
|
||||
}
|
||||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(subgroup_params); i++) {
|
||||
|
@ -781,38 +781,38 @@ static void test_broadcast_source_reconfig_inval(struct bt_bap_broadcast_source
|
|||
/* Test invalid codec values */
|
||||
memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg));
|
||||
|
||||
codec_cfg.data_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT + 1;
|
||||
codec_cfg.data_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_reconfig with codec.data_count %u\n",
|
||||
codec_cfg.data_count);
|
||||
printk("Test bt_bap_broadcast_source_reconfig with codec.data_len %zu\n",
|
||||
codec_cfg.data_len);
|
||||
err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_reconfig with too high codec data count did not "
|
||||
FAIL("bt_bap_broadcast_source_reconfig with too high codec data len did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg));
|
||||
|
||||
codec_cfg.meta_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT + 1;
|
||||
codec_cfg.meta_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_reconfig with codec.meta_count %u\n",
|
||||
codec_cfg.meta_count);
|
||||
printk("Test bt_bap_broadcast_source_reconfig with codec.meta_len %zu\n",
|
||||
codec_cfg.meta_len);
|
||||
err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_reconfig with too high codec meta count did not "
|
||||
FAIL("bt_bap_broadcast_source_reconfig with too high codec meta len did not "
|
||||
"fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg));
|
||||
|
||||
if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) {
|
||||
if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE < 255) {
|
||||
/* Set LTV data to invalid size */
|
||||
codec_cfg.data[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1;
|
||||
codec_cfg.data_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_reconfig with CC LTV size %u\n",
|
||||
codec_cfg.data[0].data.data_len);
|
||||
codec_cfg.data_len);
|
||||
err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_reconfig with too large CC LTV did not "
|
||||
|
@ -823,12 +823,12 @@ static void test_broadcast_source_reconfig_inval(struct bt_bap_broadcast_source
|
|||
memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg));
|
||||
}
|
||||
|
||||
if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) {
|
||||
if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE < 255) {
|
||||
/* Set LTV data to invalid size */
|
||||
codec_cfg.meta[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1;
|
||||
codec_cfg.meta_len = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE + 1;
|
||||
|
||||
printk("Test bt_bap_broadcast_source_reconfig with meta LTV size %u\n",
|
||||
codec_cfg.meta[0].data.data_len);
|
||||
codec_cfg.meta_len);
|
||||
err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos);
|
||||
if (err == 0) {
|
||||
FAIL("bt_bap_broadcast_source_reconfig with too large meta LTV did not "
|
||||
|
@ -1101,8 +1101,7 @@ static int stop_extended_adv(struct bt_le_ext_adv *adv)
|
|||
|
||||
static void test_main(void)
|
||||
{
|
||||
struct bt_audio_codec_data new_metadata[1] =
|
||||
BT_AUDIO_CODEC_LC3_CONFIG_META(BT_AUDIO_CONTEXT_TYPE_ALERTS);
|
||||
uint8_t new_metadata[] = BT_AUDIO_CODEC_CFG_LC3_META(BT_AUDIO_CONTEXT_TYPE_ALERTS);
|
||||
struct bt_bap_broadcast_source *source;
|
||||
struct bt_le_ext_adv *adv;
|
||||
int err;
|
||||
|
|
|
@ -527,10 +527,9 @@ static int mod_source(struct sync_state *state)
|
|||
{
|
||||
const uint16_t pref_context = BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL;
|
||||
struct bt_bap_scan_delegator_mod_src_param param;
|
||||
uint8_t pref_context_metadata[4] = {
|
||||
0x03, /* length of the type and value */
|
||||
BT_AUDIO_METADATA_TYPE_PREF_CONTEXT,
|
||||
BT_BYTES_LIST_LE16(pref_context),
|
||||
const uint8_t pref_context_metadata[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT,
|
||||
BT_BYTES_LIST_LE16(pref_context)),
|
||||
};
|
||||
int err;
|
||||
|
||||
|
|
|
@ -501,23 +501,15 @@ static void enable_streams(size_t stream_cnt)
|
|||
|
||||
static int metadata_update_stream(struct bt_bap_stream *stream)
|
||||
{
|
||||
struct bt_audio_codec_data new_meta = BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_METADATA_TYPE_VENDOR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
|
||||
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
|
||||
0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c,
|
||||
0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
|
||||
0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f);
|
||||
const uint8_t new_meta[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, LONG_META),
|
||||
};
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_stream_metadata);
|
||||
|
||||
do {
|
||||
err = bt_bap_stream_metadata(stream, &new_meta, 1);
|
||||
err = bt_bap_stream_metadata(stream, new_meta, ARRAY_SIZE(new_meta));
|
||||
if (err == -EBUSY) {
|
||||
k_sleep(BAP_STREAM_RETRY_WAIT);
|
||||
} else if (err != 0) {
|
||||
|
|
|
@ -14,30 +14,33 @@ void print_hex(const uint8_t *ptr, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static void print_ltv_elem(const char *str, uint8_t type, uint8_t value_len, const uint8_t *value,
|
||||
size_t cnt)
|
||||
struct print_ltv_info {
|
||||
const char *str;
|
||||
size_t cnt;
|
||||
};
|
||||
|
||||
static bool print_ltv_elem(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("%s #%zu: type 0x%02x value_len %u\n", str, cnt, type, value_len);
|
||||
print_hex(value, value_len);
|
||||
struct print_ltv_info *ltv_info = user_data;
|
||||
|
||||
printk("%s #%zu: type 0x%02x value_len %u", ltv_info->str, ltv_info->cnt, data->type,
|
||||
data->data_len);
|
||||
print_hex(data->data, data->data_len);
|
||||
printk("\n");
|
||||
|
||||
ltv_info->cnt++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_ltv_array(const char *str, const uint8_t *ltv_data, size_t ltv_data_len)
|
||||
{
|
||||
size_t cnt = 0U;
|
||||
struct print_ltv_info ltv_info = {
|
||||
.str = str,
|
||||
.cnt = 0U,
|
||||
};
|
||||
|
||||
for (size_t i = 0U; i < ltv_data_len;) {
|
||||
const uint8_t len = ltv_data[i++];
|
||||
const uint8_t type = ltv_data[i++];
|
||||
const uint8_t *value = <v_data[i];
|
||||
const uint8_t value_len = len - sizeof(type);
|
||||
|
||||
print_ltv_elem(str, type, value_len, value, cnt++);
|
||||
/* Since we are incrementing i by the value_len, we don't need to increment it
|
||||
* further in the `for` statement
|
||||
*/
|
||||
i += value_len;
|
||||
}
|
||||
bt_audio_data_parse(ltv_data, ltv_data_len, print_ltv_elem, <v_info);
|
||||
}
|
||||
|
||||
void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
|
||||
|
@ -58,28 +61,18 @@ void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
|
|||
|
||||
void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
printk("codec_cap ID 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id,
|
||||
codec_cfg->cid, codec_cfg->vid, codec_cfg->data_count);
|
||||
printk("codec_cfg ID 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id,
|
||||
codec_cfg->cid, codec_cfg->vid, codec_cfg->data_len);
|
||||
|
||||
for (uint8_t i = 0; i < codec_cfg->data_count; i++) {
|
||||
printk("data #%u: type 0x%02x len %u\n",
|
||||
i, codec_cfg->data[i].data.type,
|
||||
codec_cfg->data[i].data.data_len);
|
||||
print_hex(codec_cfg->data[i].data.data,
|
||||
codec_cfg->data[i].data.data_len -
|
||||
sizeof(codec_cfg->data[i].data.type));
|
||||
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
|
||||
print_ltv_array("data", codec_cfg->data, codec_cfg->data_len);
|
||||
} else { /* If not LC3, we cannot assume it's LTV */
|
||||
printk("data: ");
|
||||
print_hex(codec_cfg->data, codec_cfg->data_len);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < codec_cfg->meta_count; i++) {
|
||||
printk("meta #%u: type 0x%02x len %u\n",
|
||||
i, codec_cfg->meta[i].data.type,
|
||||
codec_cfg->meta[i].data.data_len);
|
||||
print_hex(codec_cfg->meta[i].data.data,
|
||||
codec_cfg->meta[i].data.data_len -
|
||||
sizeof(codec_cfg->meta[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
print_ltv_array("meta", codec_cfg->meta, codec_cfg->meta_len);
|
||||
}
|
||||
|
||||
void print_qos(const struct bt_audio_codec_qos *qos)
|
||||
|
|
|
@ -12,6 +12,25 @@
|
|||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
|
||||
#define LONG_META 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, \
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, \
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, \
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, \
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, \
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, \
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, \
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, \
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, \
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, \
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, \
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, \
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
||||
|
||||
#define LONG_META_LEN (sizeof((uint8_t []){LONG_META}) + 1U) /* Size of data + type */
|
||||
|
||||
void print_hex(const uint8_t *ptr, size_t len);
|
||||
void print_codec_cap(const struct bt_audio_codec_cap *codec_cap);
|
||||
void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg);
|
||||
|
|
|
@ -19,25 +19,6 @@ extern enum bst_result_t bst_result;
|
|||
|
||||
#define PREF_CONTEXT (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)
|
||||
|
||||
#define LONG_META 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, \
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, \
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, \
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, \
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, \
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, \
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, \
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, \
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, \
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, \
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, \
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, \
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
||||
|
||||
#define LONG_META_LEN (sizeof((uint8_t []){LONG_META}) + 1U) /* Size of data + type */
|
||||
|
||||
static const struct bt_audio_codec_cap lc3_codec_cap = {
|
||||
.path_id = BT_ISO_DATA_PATH_HCI,
|
||||
.id = BT_AUDIO_CODEC_LC3_ID,
|
||||
|
@ -45,18 +26,20 @@ static const struct bt_audio_codec_cap lc3_codec_cap = {
|
|||
.vid = 0x0000U,
|
||||
.data_len = (3 + 1) + (2 + 1) + (2 + 1) + (5 + 1) + (2 + 1),
|
||||
.data = {
|
||||
3, BT_AUDIO_CODEC_LC3_FREQ,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_LC3_FREQ_16KHZ),
|
||||
2, BT_AUDIO_CODEC_LC3_DURATION, BT_AUDIO_CODEC_LC3_DURATION_10,
|
||||
2, BT_AUDIO_CODEC_LC3_CHAN_COUNT, CHANNEL_COUNT_1,
|
||||
5, BT_AUDIO_CODEC_LC3_FRAME_LEN, BT_BYTES_LIST_LE16(40U),
|
||||
BT_BYTES_LIST_LE16(40U),
|
||||
2, BT_AUDIO_CODEC_LC3_FRAME_COUNT, 1U,
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FREQ,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_LC3_FREQ_16KHZ)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_DURATION,
|
||||
BT_AUDIO_CODEC_LC3_DURATION_10),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_CHAN_COUNT, CHANNEL_COUNT_1),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_LEN, BT_BYTES_LIST_LE16(40U),
|
||||
BT_BYTES_LIST_LE16(40U)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_COUNT, 1U),
|
||||
},
|
||||
.meta_len = (5 + 1) + (LONG_META_LEN + 1U),
|
||||
.meta = {
|
||||
5, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, BT_BYTES_LIST_LE32(PREF_CONTEXT),
|
||||
LONG_META_LEN, BT_AUDIO_METADATA_TYPE_VENDOR, LONG_META,
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT,
|
||||
BT_BYTES_LIST_LE32(PREF_CONTEXT)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, LONG_META),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -143,10 +126,10 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Enable: stream %p meta_count %zu\n", stream, meta_count);
|
||||
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -158,24 +141,25 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
|
||||
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
|
||||
static bool data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("Metadata: stream %p meta_count %zu\n", stream, meta_count);
|
||||
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
const struct bt_audio_codec_data *data = &meta[i];
|
||||
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->data.type,
|
||||
data->data.data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->data.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
|
||||
}
|
||||
|
||||
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
||||
|
|
|
@ -62,31 +62,84 @@ static struct bt_cap_stream unicast_streams[CONFIG_BT_ASCS_ASE_SNK_COUNT +
|
|||
|
||||
CREATE_FLAG(flag_unicast_stream_configured);
|
||||
|
||||
static bool valid_subgroup_metadata(const struct bt_bap_base_subgroup *subgroup)
|
||||
static bool valid_metadata_type(uint8_t type, uint8_t len)
|
||||
{
|
||||
bool stream_context_found = false;
|
||||
|
||||
for (size_t j = 0U; j < subgroup->codec_cfg.meta_count; j++) {
|
||||
const struct bt_data *metadata = &subgroup->codec_cfg.meta[j].data;
|
||||
|
||||
if (metadata->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
|
||||
if (metadata->data_len != 2) { /* Stream context size */
|
||||
printk("Subgroup has invalid streaming context length: %u\n",
|
||||
metadata->data_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
stream_context_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stream_context_found) {
|
||||
printk("Subgroup did not have streaming context\n");
|
||||
switch (type) {
|
||||
case BT_AUDIO_METADATA_TYPE_PREF_CONTEXT:
|
||||
case BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT:
|
||||
if (len != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_STREAM_LANG:
|
||||
if (len != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_PARENTAL_RATING:
|
||||
if (len != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */
|
||||
case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */
|
||||
if (len < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_CCID_LIST:
|
||||
case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO: /* 0 - 255 octets */
|
||||
case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI: /* 0 - 255 octets */
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool subgroup_data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
bool *stream_context_found = (bool *)user_data;
|
||||
|
||||
printk("type %u len %u\n", data->type, data->data_len);
|
||||
|
||||
if (!valid_metadata_type(data->type, data->data_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
|
||||
if (data->data_len != 2) { /* Stream context size */
|
||||
return false;
|
||||
}
|
||||
|
||||
*stream_context_found = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool valid_subgroup_metadata(const struct bt_bap_base_subgroup *subgroup)
|
||||
{
|
||||
bool stream_context_found = false;
|
||||
int err;
|
||||
|
||||
printk("meta %p len %zu", subgroup->codec_cfg.meta, subgroup->codec_cfg.meta_len);
|
||||
|
||||
err = bt_audio_data_parse(subgroup->codec_cfg.meta, subgroup->codec_cfg.meta_len,
|
||||
subgroup_data_func_cb, &stream_context_found);
|
||||
if (err != 0 && err != -ECANCELED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream_context_found) {
|
||||
printk("Subgroup did not have streaming context\n");
|
||||
}
|
||||
|
||||
return stream_context_found;
|
||||
}
|
||||
|
||||
static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base)
|
||||
|
@ -347,11 +400,10 @@ static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_audi
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int unicast_server_enable(struct bt_bap_stream *stream,
|
||||
const struct bt_audio_codec_data *meta, size_t meta_count,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
static int unicast_server_enable(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len, struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Enable: stream %p meta_count %zu\n", stream, meta_count);
|
||||
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -363,25 +415,25 @@ static int unicast_server_start(struct bt_bap_stream *stream, struct bt_bap_ascs
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int unicast_server_metadata(struct bt_bap_stream *stream,
|
||||
const struct bt_audio_codec_data *meta, size_t meta_count,
|
||||
struct bt_bap_ascs_rsp *rsp)
|
||||
static bool ascs_data_func_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
printk("Metadata: stream %p meta_count %zu\n", stream, meta_count);
|
||||
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
const struct bt_audio_codec_data *data = &meta[i];
|
||||
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->data.type,
|
||||
data->data.data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
|
||||
data->data.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
|
||||
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
|
||||
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
|
||||
size_t meta_len, struct bt_bap_ascs_rsp *rsp)
|
||||
{
|
||||
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
|
||||
|
||||
return bt_audio_data_parse(meta, meta_len, ascs_data_func_cb, rsp);
|
||||
}
|
||||
|
||||
static int unicast_server_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
|
||||
|
|
|
@ -227,8 +227,8 @@ static void stop_and_delete_extended_adv(struct bt_le_ext_adv *adv)
|
|||
|
||||
static void test_broadcast_audio_create_inval(void)
|
||||
{
|
||||
struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
uint8_t bis_codec_data[] = {3, BT_AUDIO_CODEC_CONFIG_LC3_FREQ,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)};
|
||||
struct bt_cap_initiator_broadcast_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_cap_initiator_broadcast_subgroup_param subgroup_param;
|
||||
|
@ -240,8 +240,8 @@ static void test_broadcast_audio_create_inval(void)
|
|||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
stream_params[i].stream = &broadcast_source_streams[i];
|
||||
stream_params[i].data_count = 1U;
|
||||
stream_params[i].data = &bis_codec_data;
|
||||
stream_params[i].data_len = ARRAY_SIZE(bis_codec_data);
|
||||
stream_params[i].data = bis_codec_data;
|
||||
}
|
||||
|
||||
subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams);
|
||||
|
@ -285,8 +285,8 @@ static void test_broadcast_audio_create_inval(void)
|
|||
|
||||
static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadcast_source)
|
||||
{
|
||||
struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA(
|
||||
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
uint8_t bis_codec_data[] = {3, BT_AUDIO_CODEC_CONFIG_LC3_FREQ,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ)};
|
||||
struct bt_cap_initiator_broadcast_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_cap_initiator_broadcast_subgroup_param subgroup_param;
|
||||
|
@ -295,8 +295,8 @@ static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadca
|
|||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
stream_params[i].stream = &broadcast_source_streams[i];
|
||||
stream_params[i].data_count = 1U;
|
||||
stream_params[i].data = &bis_codec_data;
|
||||
stream_params[i].data_len = ARRAY_SIZE(bis_codec_data);
|
||||
stream_params[i].data = bis_codec_data;
|
||||
}
|
||||
|
||||
subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams);
|
||||
|
@ -359,17 +359,14 @@ static void test_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast
|
|||
|
||||
static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *broadcast_source)
|
||||
{
|
||||
const uint16_t mock_ccid = 0x1234;
|
||||
const struct bt_audio_codec_data new_metadata[] = {
|
||||
const uint16_t mock_ccid = 0xAB;
|
||||
const uint8_t new_metadata[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU),
|
||||
((mock_ccid >> 8) & 0xFFU)),
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, mock_ccid),
|
||||
};
|
||||
const struct bt_audio_codec_data invalid_metadata[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU),
|
||||
((mock_ccid >> 8) & 0xFFU)),
|
||||
const uint8_t invalid_metadata[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, mock_ccid),
|
||||
};
|
||||
int err;
|
||||
|
||||
|
@ -409,12 +406,11 @@ static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *br
|
|||
|
||||
static void test_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source)
|
||||
{
|
||||
const uint16_t mock_ccid = 0x1234;
|
||||
const struct bt_audio_codec_data new_metadata[] = {
|
||||
const uint16_t mock_ccid = 0xAB;
|
||||
const uint8_t new_metadata[] = {
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST,
|
||||
BT_BYTES_LIST_LE16(mock_ccid)),
|
||||
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, mock_ccid),
|
||||
};
|
||||
int err;
|
||||
|
||||
|
|
|
@ -685,7 +685,7 @@ static void unicast_audio_update_inval(void)
|
|||
|
||||
param.stream = &unicast_client_streams[0];
|
||||
param.meta = unicast_preset_16_2_1.codec_cfg.meta;
|
||||
param.meta_count = unicast_preset_16_2_1.codec_cfg.meta_count;
|
||||
param.meta_len = unicast_preset_16_2_1.codec_cfg.meta_len;
|
||||
|
||||
err = bt_cap_initiator_unicast_audio_update(NULL, 1);
|
||||
if (err == 0) {
|
||||
|
@ -718,7 +718,7 @@ static void unicast_audio_update(void)
|
|||
|
||||
param.stream = &unicast_client_streams[0];
|
||||
param.meta = unicast_preset_16_2_1.codec_cfg.meta;
|
||||
param.meta_count = unicast_preset_16_2_1.codec_cfg.meta_count;
|
||||
param.meta_len = unicast_preset_16_2_1.codec_cfg.meta_len;
|
||||
|
||||
UNSET_FLAG(flag_updated);
|
||||
|
||||
|
@ -929,36 +929,6 @@ static inline void copy_unicast_stream_preset(struct unicast_stream *stream,
|
|||
printk("named_preset %p\n", named_preset);
|
||||
memcpy(&stream->qos, &named_preset->preset.qos, sizeof(stream->qos));
|
||||
memcpy(&stream->codec_cfg, &named_preset->preset.codec_cfg, sizeof(stream->codec_cfg));
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
/* Need to update the `bt_data.data` pointer to the new value after copying the codec */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.data); i++) {
|
||||
const struct bt_audio_codec_data *preset_data =
|
||||
&named_preset->preset.codec_cfg.data[i];
|
||||
struct bt_audio_codec_data *data = &stream->codec_cfg.data[i];
|
||||
const uint8_t data_len = preset_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, preset_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 \
|
||||
*/
|
||||
|
||||
#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.meta); i++) {
|
||||
const struct bt_audio_codec_data *preset_data =
|
||||
&named_preset->preset.codec_cfg.meta[i];
|
||||
struct bt_audio_codec_data *data = &stream->codec_cfg.meta[i];
|
||||
const uint8_t data_len = preset_data->data.data_len;
|
||||
|
||||
data->data.data = data->value;
|
||||
data->data.data_len = data_len;
|
||||
memcpy(data->value, preset_data->data.data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > \
|
||||
* 0 \
|
||||
*/
|
||||
}
|
||||
|
||||
static int cap_initiator_ac_create_unicast_group(const struct cap_initiator_ac_param *param,
|
||||
|
@ -1029,20 +999,32 @@ static int cap_initiator_ac_create_unicast_group(const struct cap_initiator_ac_p
|
|||
|
||||
static int set_chan_alloc(enum bt_audio_location loc, struct bt_audio_codec_cfg *codec_cfg)
|
||||
{
|
||||
for (size_t i = 0U; i < codec_cfg->data_count; i++) {
|
||||
struct bt_audio_codec_data *data = &codec_cfg->data[i];
|
||||
for (size_t i = 0U; i < codec_cfg->data_len;) {
|
||||
const uint8_t len = codec_cfg->data[i++];
|
||||
uint8_t value_len;
|
||||
uint8_t *value;
|
||||
uint8_t type;
|
||||
|
||||
/* Overwrite the location value */
|
||||
if (data->data.type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) {
|
||||
if (len == 0 || len > codec_cfg->data_len - i) {
|
||||
/* Invalid len field */
|
||||
return false;
|
||||
}
|
||||
|
||||
type = codec_cfg->data[i++];
|
||||
value = &codec_cfg->data[i];
|
||||
value_len = len - sizeof(type);
|
||||
|
||||
if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) {
|
||||
const uint32_t loc_32 = loc;
|
||||
|
||||
sys_put_le32(loc_32, data->value);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
sys_put_le32(loc_32, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
i += value_len;
|
||||
}
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
static int cap_initiator_ac_cap_unicast_start(const struct cap_initiator_ac_param *param,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue