Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions include/zephyr/bluetooth/audio/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -1294,7 +1294,7 @@ struct bt_audio_stream {
/** Endpoint reference */
struct bt_audio_ep *ep;
/** Codec Configuration */
const struct bt_codec *codec;
struct bt_codec *codec;
/** QoS Configuration */
struct bt_codec_qos *qos;
/** Audio stream operations */
Expand Down Expand Up @@ -1804,7 +1804,7 @@ int bt_audio_stream_config(struct bt_conn *conn,
* @return 0 in case of success or negative value in case of error.
*/
int bt_audio_stream_reconfig(struct bt_audio_stream *stream,
const struct bt_codec *codec);
struct bt_codec *codec);

/** @brief Configure Audio Stream QoS
*
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down
75 changes: 75 additions & 0 deletions subsys/bluetooth/audio/broadcast_source.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion subsys/bluetooth/audio/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ int bt_audio_unicast_group_delete(struct bt_audio_unicast_group *unicast_group)
#endif /* CONFIG_BT_AUDIO_UNICAST_CLIENT */

int bt_audio_stream_reconfig(struct bt_audio_stream *stream,
const struct bt_codec *codec)
struct bt_codec *codec)
{
uint8_t state;
uint8_t role;
Expand Down
67 changes: 27 additions & 40 deletions tests/bluetooth/bsim_bt/bsim_test_audio/src/broadcast_sink_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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.
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -191,7 +205,7 @@ static int init(void)
return 0;
}

static void test_main(void)
static void test_common(void)
{
int err;

Expand Down Expand Up @@ -235,6 +249,16 @@ 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)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant new line

}

static void test_main(void)
{
test_common();

/* 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.
Expand All @@ -254,44 +278,7 @@ static void test_sink_disconnect(void)
{
int err;

err = init();
if (err) {
FAIL("Init failed (err %d)\n", err);
return;
}

printk("Scanning for broadcast sources\n");
err = bt_audio_broadcast_sink_scan_start(BT_LE_SCAN_ACTIVE);
if (err != 0) {
FAIL("Unable to start scan for broadcast sources: %d", err);
return;
}
WAIT_FOR_FLAG(broadcaster_found);
printk("Broadcast source found, waiting for PA sync\n");
WAIT_FOR_FLAG(pa_synced);
printk("Broadcast source PA synced, waiting for BASE\n");
WAIT_FOR_FLAG(base_received);
printk("BASE received\n");

printk("Waiting for BIG syncable\n");
WAIT_FOR_FLAG(flag_syncable);

printk("Syncing the sink\n");
/* TODO: Sync to max streams instead of just BIT(1) */
err = bt_audio_broadcast_sink_sync(g_sink, BIT(1), streams, NULL);
if (err != 0) {
FAIL("Unable to sync the sink: %d\n", err);
return;
}

/* Wait for all to be started */
printk("Waiting for streams to be started\n");
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
k_sem_take(&sem_started, K_FOREVER);
}

printk("Waiting for data\n");
WAIT_FOR_FLAG(flag_received);
test_common();

err = bt_audio_broadcast_sink_stop(g_sink);
if (err != 0) {
Expand All @@ -312,7 +299,7 @@ static void test_sink_disconnect(void)
/* No "sync lost" event is generated when we initialized the disconnect */
g_sink = NULL;

PASS("Broadcast sink passed\n");
PASS("Broadcast sink disconnect passed\n");
}

static const struct bst_test_instance test_broadcast_sink[] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down