Bluetooth: Audio: Add broadcast source metadata update function

Add API to do the BAP Broadcast Source Metadata update procedure,
which updates the metadata of a broadcast source while
it is streaming.

This is also makes all checks for the "head stream" the same.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2022-06-28 20:09:13 +02:00 committed by Carles Cufí
commit 1424df424c
4 changed files with 128 additions and 1 deletions

View file

@ -2077,7 +2077,7 @@ int bt_audio_broadcast_source_create(struct bt_audio_broadcast_source_create_par
/** @brief Reconfigure audio broadcast source.
*
* Reconfigure an audio broadcast source with a new codec and codec quality of
* service parameters.
* service parameters. This can only be done when the source is stopped.
*
* @param source Pointer to the broadcast source
* @param codec Codec configuration.
@ -2089,6 +2089,22 @@ int bt_audio_broadcast_source_reconfig(struct bt_audio_broadcast_source *source,
struct bt_codec *codec,
struct bt_codec_qos *qos);
/** @brief Modify the metadata of an audio broadcast source.
*
* Modify the metadata an audio broadcast source. This can only be done when
* the source is started. To update the metadata in the stopped state, use
* bt_audio_broadcast_source_reconfig().
*
* @param source Pointer to the broadcast source.
* @param meta Metadata entries.
* @param meta_count Number of metadata entries.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_audio_broadcast_source_update_metadata(struct bt_audio_broadcast_source *source,
const struct bt_codec_data meta[],
size_t meta_count);
/** @brief Start audio broadcast source.
*
* Start an audio broadcast source with one or more audio streams.

View file

@ -765,6 +765,81 @@ int bt_audio_broadcast_source_reconfig(struct bt_audio_broadcast_source *source,
return 0;
}
static void broadcast_source_store_metadata(struct bt_codec *codec,
const struct bt_codec_data meta[],
size_t meta_count)
{
size_t old_meta_count;
old_meta_count = codec->meta_count;
/* Update metadata */
codec->meta_count = meta_count;
(void)memcpy(codec->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->meta[meta_count],
0, meta_count_diff * sizeof(*meta));
}
}
int bt_audio_broadcast_source_update_metadata(struct bt_audio_broadcast_source *source,
const struct bt_codec_data meta[],
size_t meta_count)
{
struct bt_audio_broadcast_subgroup *subgroup;
enum bt_audio_state broadcast_state;
CHECKIF(source == NULL) {
LOG_DBG("source is NULL");
return -EINVAL;
}
CHECKIF((meta == NULL && meta_count != 0) ||
(meta != NULL && meta_count == 0)) {
LOG_DBG("Invalid metadata combination: %p %zu",
meta, meta_count);
return -EINVAL;
}
CHECKIF(meta_count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) {
LOG_DBG("Invalid meta_count: %zu (max %d)",
meta_count, CONFIG_BT_CODEC_MAX_METADATA_COUNT);
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_AUDIO_EP_STATE_STREAMING) {
LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
return -EBADMSG;
}
/* TODO: We should probably find a way to update the metadata
* for each subgroup individually
*/
SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
broadcast_source_store_metadata(subgroup->codec, meta, meta_count);
}
return 0;
}
int bt_audio_broadcast_source_start(struct bt_audio_broadcast_source *source,
struct bt_le_ext_adv *adv)
{

View file

@ -15,6 +15,7 @@ extern enum bst_result_t bst_result;
CREATE_FLAG(broadcaster_found);
CREATE_FLAG(base_received);
CREATE_FLAG(flag_base_metadata_updated);
CREATE_FLAG(pa_synced);
CREATE_FLAG(flag_syncable);
CREATE_FLAG(pa_sync_lost);
@ -30,6 +31,8 @@ static struct bt_audio_lc3_preset preset_16_2_1 =
static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(streams));
static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams));
static struct bt_codec_data metadata[CONFIG_BT_CODEC_MAX_METADATA_COUNT];
/* 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
* 0.
@ -76,6 +79,17 @@ static void base_recv_cb(struct bt_audio_broadcast_sink *sink,
uint32_t base_bis_index_bitfield = 0U;
if (TEST_FLAG(base_received)) {
if (base->subgroup_count > 0 &&
memcmp(metadata, base->subgroups[0].codec.meta,
sizeof(base->subgroups[0].codec.meta)) != 0) {
(void)memcpy(metadata, base->subgroups[0].codec.meta,
sizeof(base->subgroups[0].codec.meta));
SET_FLAG(flag_base_metadata_updated);
}
return;
}
@ -235,6 +249,10 @@ static void test_main(void)
printk("Waiting for data\n");
WAIT_FOR_FLAG(flag_received);
/* Ensure that we also see the metadata update */
printk("Waiting for metadata update\n");
WAIT_FOR_FLAG(flag_base_metadata_updated)
/* The order of PA sync lost and BIG Sync lost is irrelevant
* and depend on timeout parameters. We just wait for PA first, but
* either way will work.
@ -293,6 +311,10 @@ static void test_sink_disconnect(void)
printk("Waiting for data\n");
WAIT_FOR_FLAG(flag_received);
/* Ensure that we also see the metadata update */
printk("Waiting for metadata update\n");
WAIT_FOR_FLAG(flag_base_metadata_updated)
err = bt_audio_broadcast_sink_stop(g_sink);
if (err != 0) {
FAIL("Unable to stop sink: %d", err);

View file

@ -244,6 +244,8 @@ static int stop_extended_adv(struct bt_le_ext_adv *adv)
static void test_main(void)
{
struct bt_codec_data new_metadata[1] =
BT_CODEC_LC3_CONFIG_META(BT_AUDIO_CONTEXT_TYPE_ALERTS);
struct bt_audio_broadcast_source *source;
struct bt_le_ext_adv *adv;
int err;
@ -299,6 +301,18 @@ static void test_main(void)
/* Keeping running for a little while */
k_sleep(K_SECONDS(15));
/* Update metadata while streaming */
printk("Updating metadata\n");
err = bt_audio_broadcast_source_update_metadata(source, new_metadata,
ARRAY_SIZE(new_metadata));
if (err != 0) {
FAIL("Failed to update metadata broadcast source: %d", err);
return;
}
/* Keeping running for a little while */
k_sleep(K_SECONDS(5));
printk("Stopping broadcast source\n");
SET_FLAG(flag_stopping);
err = bt_audio_broadcast_source_stop(source);