Bluetooth: BAP: Broadcast source reconfig with subgroups

Modify the bt_bap_broadcast_source_reconfig to use the same
parameter struct as bt_bap_broadcast_source_create so that
the two are more similar, since they both set the same values.

This allow for full control of which subgroups and stream
are updated.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-08-17 13:15:12 +02:00 committed by Fabio Baltieri
commit d327b1625c
6 changed files with 125 additions and 35 deletions

View file

@ -1400,7 +1400,7 @@ struct bt_bap_broadcast_source_subgroup_param {
};
/** Broadcast Source create parameters */
struct bt_bap_broadcast_source_create_param {
struct bt_bap_broadcast_source_param {
/** The number of parameters in @p subgroup_params */
size_t params_count;
@ -1451,7 +1451,7 @@ struct bt_bap_broadcast_source_create_param {
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *param,
int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
struct bt_bap_broadcast_source **source);
/**
@ -1460,15 +1460,21 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *
* Reconfigure an audio broadcast source with a new codec and codec quality of
* service parameters. This can only be done when the source is stopped.
*
* Since this may modify the Broadcast Audio Source Endpoint (BASE),
* bt_bap_broadcast_source_get_base() should be called after this to get the new BASE information.
*
* If the @p param.params_count is smaller than the number of subgroups that have been created in
* the Broadcast Source, only the first @p param.params_count subgroups are updated. If a stream
* exist in a subgroup not part of @p param, then that stream is left as is (i.e. it is not removed;
* the only way to remove a stream from a Broadcast Source is to recreate the Broadcast Source).
*
* @param source Pointer to the broadcast source
* @param codec_cfg Codec configuration.
* @param qos Quality of Service configuration
* @param param Pointer to parameters used to reconfigure the broadcast source.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
struct bt_audio_codec_cfg *codec_cfg,
struct bt_audio_codec_qos *qos);
struct bt_bap_broadcast_source_param *param);
/**
* @brief Modify the metadata of an audio broadcast source.

View file

@ -93,7 +93,7 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source)
stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
struct bt_bap_broadcast_source_subgroup_param
subgroup_param[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
struct bt_bap_broadcast_source_create_param create_param;
struct bt_bap_broadcast_source_param create_param;
const size_t streams_per_subgroup = ARRAY_SIZE(stream_params) / ARRAY_SIZE(subgroup_param);
int err;

View file

@ -476,7 +476,8 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
(void)memset(source, 0, sizeof(*source));
}
static bool valid_create_param(const struct bt_bap_broadcast_source_create_param *param)
static bool valid_broadcast_source_param(const struct bt_bap_broadcast_source_param *param,
const struct bt_bap_broadcast_source *source)
{
const struct bt_audio_codec_qos *qos;
@ -555,7 +556,8 @@ static bool valid_create_param(const struct bt_bap_broadcast_source_create_param
return false;
}
CHECKIF(stream_param->stream->group != NULL) {
CHECKIF(stream_param->stream->group != NULL &&
stream_param->stream->group != source) {
LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is "
"already part of group %p",
i, j, stream_param->stream->group);
@ -618,7 +620,7 @@ static enum bt_bap_ep_state broadcast_source_get_state(struct bt_bap_broadcast_s
return stream->ep->status.state;
}
int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *param,
int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
struct bt_bap_broadcast_source **out_source)
{
struct bt_bap_broadcast_source *source;
@ -635,7 +637,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *
/* Set out_source to NULL until the source has actually been created */
*out_source = NULL;
if (!valid_create_param(param)) {
if (!valid_broadcast_source_param(param, NULL)) {
LOG_DBG("Invalid parameters");
return -EINVAL;
}
@ -738,35 +740,20 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *
}
int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
struct bt_audio_codec_cfg *codec_cfg,
struct bt_audio_codec_qos *qos)
struct bt_bap_broadcast_source_param *param)
{
struct bt_bap_broadcast_subgroup *subgroup;
enum bt_bap_ep_state broadcast_state;
struct bt_bap_stream *stream;
struct bt_audio_codec_qos *qos;
size_t subgroup_cnt;
CHECKIF(source == NULL) {
LOG_DBG("source is NULL");
return -EINVAL;
}
CHECKIF(!bt_audio_valid_codec_cfg(codec_cfg)) {
LOG_DBG("codec_cfg is invalid");
return -EINVAL;
}
CHECKIF(qos == NULL) {
LOG_DBG("qos is NULL");
return -EINVAL;
}
CHECKIF(bt_audio_verify_qos(qos) != BT_BAP_ASCS_REASON_NONE) {
LOG_DBG("qos is invalid");
return -EINVAL;
}
CHECKIF(qos->rtn > BT_ISO_BROADCAST_RTN_MAX) {
LOG_DBG("qos->rtn %u invalid", qos->rtn);
if (!valid_broadcast_source_param(param, source)) {
LOG_DBG("Invalid parameters");
return -EINVAL;
}
@ -776,9 +763,97 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
return -EBADMSG;
}
/* Verify that the parameter counts do not exceed existing number of subgroups and streams*/
subgroup_cnt = 0U;
SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
const struct bt_bap_broadcast_source_subgroup_param *subgroup_param =
&param->params[subgroup_cnt];
const size_t subgroup_stream_param_cnt = subgroup_param->params_count;
struct bt_bap_stream *stream;
size_t stream_cnt = 0U;
SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
stream_cnt++;
}
/* Verify that the param stream is in the subgroup */
for (size_t i = 0U; i < subgroup_param->params_count; i++) {
struct bt_bap_stream *subgroup_stream;
struct bt_bap_stream *param_stream;
bool stream_in_subgroup;
param_stream = subgroup_param->params[i].stream;
SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
if (subgroup_stream == param_stream) {
stream_in_subgroup = true;
break;
}
}
if (!stream_in_subgroup) {
LOG_DBG("Invalid param->params[%zu]->param[%zu].stream "
"not in subgroup",
subgroup_cnt, i);
return -EINVAL;
}
}
if (subgroup_stream_param_cnt < stream_cnt) {
LOG_DBG("Invalid param->params[%zu]->params_count: %zu "
"(only %zu streams in subgroup)",
subgroup_cnt, subgroup_stream_param_cnt, stream_cnt);
return -EINVAL;
}
subgroup_cnt++;
}
if (subgroup_cnt < param->params_count) {
LOG_DBG("Invalid param->params_count: %zu (only %zu subgroups in source)",
param->params_count, subgroup_cnt);
return -EINVAL;
}
qos = param->qos;
/* We update up to the first param->params_count subgroups */
for (size_t i = 0U; i < param->params_count; i++) {
const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
struct bt_audio_codec_cfg *codec_cfg;
if (i == 0) {
subgroup =
SYS_SLIST_PEEK_HEAD_CONTAINER(&source->subgroups, subgroup, _node);
} else {
subgroup = SYS_SLIST_PEEK_NEXT_CONTAINER(subgroup, _node);
}
subgroup_param = &param->params[i];
codec_cfg = subgroup_param->codec_cfg;
subgroup->codec_cfg = codec_cfg;
for (size_t j = 0U; j < subgroup_param->params_count; j++) {
const struct bt_bap_broadcast_source_stream_param *stream_param;
struct bt_audio_broadcast_stream_data *stream_data;
struct bt_bap_stream *subgroup_stream;
struct bt_iso_chan_io_qos *iso_qos;
struct bt_bap_stream *stream;
bool stream_in_subgroup;
size_t stream_idx;
stream_param = &subgroup_param->params[j];
stream = stream_param->stream;
stream_idx = 0U;
SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
if (subgroup_stream == stream) {
stream_in_subgroup = true;
break;
}
stream_idx++;
}
iso_qos = stream->ep->iso->chan.qos->tx;
@ -787,6 +862,15 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
bt_audio_codec_qos_to_iso_qos(iso_qos, qos);
bt_audio_codec_cfg_to_iso_path(iso_qos->path, codec_cfg);
stream->qos = qos;
/* Store the BIS specific codec configuration data in the broadcast source.
* It is stored in the broadcast* source, instead of the stream object,
* as this is only relevant for the broadcast source, and not used
* for unicast or broadcast sink.
*/
stream_data = &source->stream_data[stream_idx];
(void)memcpy(stream_data->data, stream_param->data, stream_param->data_len);
stream_data->data_len = stream_param->data_len;
}
}

View file

@ -114,7 +114,7 @@ static bool cap_initiator_broadcast_audio_start_valid_param(
static void cap_initiator_broadcast_to_bap_broadcast_param(
const struct bt_cap_initiator_broadcast_create_param *cap_param,
struct bt_bap_broadcast_source_create_param *bap_param,
struct bt_bap_broadcast_source_param *bap_param,
struct bt_bap_broadcast_source_subgroup_param
bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT],
struct bt_bap_broadcast_source_stream_param
@ -170,7 +170,7 @@ int bt_cap_initiator_broadcast_audio_create(
bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
struct bt_bap_broadcast_source_stream_param
bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
struct bt_bap_broadcast_source_create_param bap_create_param;
struct bt_bap_broadcast_source_param bap_create_param;
CHECKIF(param == NULL) {
LOG_DBG("param is NULL");

View file

@ -2052,7 +2052,7 @@ static int cmd_create_broadcast(const struct shell *sh, size_t argc,
struct bt_bap_broadcast_source_stream_param
stream_params[ARRAY_SIZE(broadcast_source_streams)];
struct bt_bap_broadcast_source_subgroup_param subgroup_param;
struct bt_bap_broadcast_source_create_param create_param = {0};
struct bt_bap_broadcast_source_param create_param = {0};
const struct named_lc3_preset *named_preset;
int err;

View file

@ -1043,7 +1043,7 @@ static int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv,
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};
struct bt_bap_broadcast_source_param create_param = {0};
const struct named_lc3_preset *named_preset;
struct bt_le_ext_adv *adv;
int err;