diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index d5f81764c06..324d4f0ca4d 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -1946,24 +1946,25 @@ int bt_audio_stream_release(struct bt_audio_stream *stream); int bt_audio_stream_send(struct bt_audio_stream *stream, struct net_buf *buf, uint16_t seq_num, uint32_t ts); +struct bt_audio_unicast_group_stream_param { + /** Pointer to a stream object. */ + struct bt_audio_stream *stream; + + /** The QoS settings for the stream object. */ + struct bt_codec_qos *qos; +}; + /** @brief Parameter struct for the unicast group functions * * Parameter struct for the bt_audio_unicast_group_create() and * bt_audio_unicast_group_add_streams() functions. */ -struct bt_audio_unicast_group_stream_param { - /** Pointer to a stream object. */ - struct bt_audio_stream *stream; +struct bt_audio_unicast_group_stream_pair_param { + /** Pointer to a receiving stream parameters. */ + struct bt_audio_unicast_group_stream_param *rx_param; - /** The QoS settings for the @ref bt_audio_unicast_group_stream_param.stream. */ - struct bt_codec_qos *qos; - - /** @brief The direction of the @ref bt_audio_unicast_group_stream_param.stream - * - * If two streams are being used for the same ACL connection but in - * different directions, they may use the same CIS. - */ - enum bt_audio_dir dir; + /** Pointer to a transmiting stream parameters. */ + struct bt_audio_unicast_group_stream_param *tx_param; }; struct bt_audio_unicast_group_param { @@ -1971,7 +1972,7 @@ struct bt_audio_unicast_group_param { size_t params_count; /** Array of stream parameters */ - struct bt_audio_unicast_group_stream_param *params; + struct bt_audio_unicast_group_stream_pair_param *params; /** @brief Unicast Group packing mode. * @@ -2020,7 +2021,7 @@ int bt_audio_unicast_group_create(struct bt_audio_unicast_group_param *param, * @return 0 in case of success or negative value in case of error. */ int bt_audio_unicast_group_add_streams(struct bt_audio_unicast_group *unicast_group, - struct bt_audio_unicast_group_stream_param params[], + struct bt_audio_unicast_group_stream_pair_param params[], size_t num_param); /** @brief Delete audio unicast group. diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 42acb896866..6fefc990203 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -33,8 +33,10 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_AUDIO_UNICAST_CLIENT_ASE_SNK_COUNT, static struct bt_audio_stream streams[CONFIG_BT_AUDIO_UNICAST_CLIENT_ASE_SNK_COUNT + CONFIG_BT_AUDIO_UNICAST_CLIENT_ASE_SRC_COUNT]; static size_t configured_sink_stream_count; -static size_t configured_stream_count; +static size_t configured_source_stream_count; +#define configured_stream_count (configured_sink_stream_count + \ + configured_source_stream_count) /* Select a codec configuration to apply that is mandatory to support by both client and server. * Allows this sample application to work without logic to parse the codec capabilities of the @@ -329,25 +331,6 @@ static void audio_timer_timeout(struct k_work *work) #endif - -static enum bt_audio_dir stream_dir(const struct bt_audio_stream *stream) -{ - for (size_t i = 0U; i < ARRAY_SIZE(sinks); i++) { - if (sinks[i].ep != NULL && stream->ep == sinks[i].ep) { - return BT_AUDIO_DIR_SINK; - } - } - - for (size_t i = 0U; i < ARRAY_SIZE(sources); i++) { - if (sources[i] != NULL && stream->ep == sources[i]) { - return BT_AUDIO_DIR_SOURCE; - } - } - - __ASSERT(false, "Invalid stream"); - return 0; -} - static void print_hex(const uint8_t *ptr, size_t len) { while (len-- != 0) { @@ -880,7 +863,6 @@ static int configure_streams(void) } printk("Configured sink stream[%zu]\n", i); - configured_stream_count++; configured_sink_stream_count++; } @@ -900,7 +882,7 @@ static int configure_streams(void) } printk("Configured source stream[%zu]\n", i); - configured_stream_count++; + configured_source_stream_count++; } return 0; @@ -908,18 +890,34 @@ static int configure_streams(void) static int create_group(void) { - struct bt_audio_unicast_group_stream_param stream_params[ARRAY_SIZE(streams)]; + const size_t params_count = MAX(configured_sink_stream_count, + configured_source_stream_count); + struct bt_audio_unicast_group_stream_pair_param pair_params[params_count]; + struct bt_audio_unicast_group_stream_param stream_params[configured_stream_count]; struct bt_audio_unicast_group_param param; int err; for (size_t i = 0U; i < configured_stream_count; i++) { stream_params[i].stream = &streams[i]; stream_params[i].qos = &codec_configuration.qos; - stream_params[i].dir = stream_dir(stream_params[i].stream); } - param.params = stream_params; - param.params_count = configured_stream_count; + for (size_t i = 0U; i < params_count; i++) { + if (i < configured_sink_stream_count) { + pair_params[i].tx_param = &stream_params[i]; + } else { + pair_params[i].tx_param = NULL; + } + + if (i < configured_source_stream_count) { + pair_params[i].rx_param = &stream_params[i + configured_sink_stream_count]; + } else { + pair_params[i].rx_param = NULL; + } + } + + param.params = pair_params; + param.params_count = params_count; param.packing = BT_ISO_PACKING_SEQUENTIAL; err = bt_audio_unicast_group_create(¶m, &unicast_group); @@ -969,7 +967,7 @@ static int enable_streams(void) init_lc3(); } - for (size_t i = 0; i < configured_stream_count; i++) { + for (size_t i = 0U; i < configured_stream_count; i++) { int err; err = bt_audio_stream_enable(&streams[i], @@ -992,7 +990,7 @@ static int enable_streams(void) static int start_streams(void) { - for (size_t i = 0; i < configured_stream_count; i++) { + for (size_t i = 0U; i < configured_stream_count; i++) { int err; err = bt_audio_stream_start(&streams[i]); @@ -1025,7 +1023,7 @@ static void reset_data(void) k_sem_reset(&sem_stream_started); configured_sink_stream_count = 0; - configured_stream_count = 0; + configured_source_stream_count = 0; } void main(void) diff --git a/subsys/bluetooth/audio/stream.c b/subsys/bluetooth/audio/stream.c index b22b46d3c11..ef81663d810 100644 --- a/subsys/bluetooth/audio/stream.c +++ b/subsys/bluetooth/audio/stream.c @@ -399,6 +399,10 @@ static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param, cig_param->sca = BT_GAP_SCA_UNKNOWN; } +/* FIXME: Remove `qos` parameter. Some of the QoS related CIG can be different + * between CIS'es. The implementation shall take the CIG parameters from + * unicast_group instead. + */ static int bt_audio_cig_create(struct bt_audio_unicast_group *group, const struct bt_codec_qos *qos) { @@ -730,35 +734,6 @@ int bt_audio_stream_connect(struct bt_audio_stream *stream) } } -static struct bt_audio_iso *get_new_iso(struct bt_audio_unicast_group *group, - struct bt_conn *acl, - enum bt_audio_dir dir) -{ - struct bt_audio_stream *stream; - - /* Check if there's already an ISO that can be used for this direction */ - SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) { - __ASSERT(stream->audio_iso != NULL, "stream->audio_iso is NULL"); - - /* Don't attempt to couple streams if the ACL is either NULL, - * or the connection points differ - */ - if (acl == NULL || stream->conn != acl) { - continue; - } - - if (bt_audio_iso_get_stream(stream->audio_iso, dir) == NULL) { - LOG_DBG("Returning existing audio_iso for group %p", - group); - - return bt_audio_iso_ref(stream->audio_iso); - } - } - - LOG_DBG("Returning new audio_iso for group %p", group); - return bt_unicast_client_new_audio_iso(); -} - static int unicast_group_add_iso(struct bt_audio_unicast_group *group, struct bt_audio_iso *iso) { @@ -850,33 +825,20 @@ static void unicast_client_codec_qos_to_iso_qos(struct bt_audio_iso *iso, } } -static int unicast_group_add_stream(struct bt_audio_unicast_group *group, - struct bt_audio_stream *stream, - struct bt_codec_qos *qos, - enum bt_audio_dir dir) +static void unicast_group_add_stream(struct bt_audio_unicast_group *group, + struct bt_audio_unicast_group_stream_param *param, + struct bt_audio_iso *iso, + enum bt_audio_dir dir) { - struct bt_audio_iso *iso; - int err; + struct bt_audio_stream *stream = param->stream; + struct bt_codec_qos *qos = param->qos; + + LOG_DBG("group %p stream %p qos %p iso %p dir %u", + group, stream, qos, iso, dir); - __ASSERT_NO_MSG(group != NULL); - __ASSERT_NO_MSG(stream != NULL); __ASSERT_NO_MSG(stream->ep == NULL || (stream->ep != NULL && stream->ep->iso == NULL)); - LOG_DBG("group %p stream %p dir %s", - group, stream, bt_audio_dir_str(dir)); - - iso = get_new_iso(group, stream->conn, dir); - if (iso == NULL) { - return -ENOMEM; - } - - err = unicast_group_add_iso(group, iso); - if (err < 0) { - bt_audio_iso_unref(iso); - return err; - } - stream->qos = qos; stream->dir = dir; stream->unicast_group = group; @@ -890,10 +852,39 @@ static int unicast_group_add_stream(struct bt_audio_unicast_group *group, /* Store the Codec QoS in the audio_iso */ unicast_client_codec_qos_to_iso_qos(iso, qos, dir); - bt_audio_iso_unref(iso); sys_slist_append(&group->streams, &stream->_node); +} - LOG_DBG("Added stream %p to group %p", stream, group); +static int unicast_group_add_stream_pair(struct bt_audio_unicast_group *group, + struct bt_audio_unicast_group_stream_pair_param *param) +{ + struct bt_audio_iso *iso; + int err; + + __ASSERT_NO_MSG(group != NULL); + __ASSERT_NO_MSG(param != NULL); + __ASSERT_NO_MSG(param->rx_param != NULL || param->tx_param != NULL); + + iso = bt_unicast_client_new_audio_iso(); + if (iso == NULL) { + return -ENOMEM; + } + + err = unicast_group_add_iso(group, iso); + if (err < 0) { + bt_audio_iso_unref(iso); + return err; + } + + if (param->rx_param != NULL) { + unicast_group_add_stream(group, param->rx_param, iso, BT_AUDIO_DIR_SOURCE); + } + + if (param->tx_param != NULL) { + unicast_group_add_stream(group, param->tx_param, iso, BT_AUDIO_DIR_SINK); + } + + bt_audio_iso_unref(iso); return 0; } @@ -921,6 +912,24 @@ static void unicast_group_del_stream(struct bt_audio_unicast_group *group, } } +static void unicast_group_del_stream_pair(struct bt_audio_unicast_group *group, + struct bt_audio_unicast_group_stream_pair_param *param) +{ + __ASSERT_NO_MSG(group != NULL); + __ASSERT_NO_MSG(param != NULL); + __ASSERT_NO_MSG(param->rx_param != NULL || param->tx_param != NULL); + + if (param->rx_param != NULL) { + __ASSERT_NO_MSG(param->rx_param->stream); + unicast_group_del_stream(group, param->rx_param->stream); + } + + if (param->tx_param != NULL) { + __ASSERT_NO_MSG(param->tx_param->stream); + unicast_group_del_stream(group, param->tx_param->stream); + } +} + static struct bt_audio_unicast_group *unicast_group_alloc(void) { struct bt_audio_unicast_group *group = NULL; @@ -965,6 +974,72 @@ static void unicast_group_free(struct bt_audio_unicast_group *group) group->allocated = false; } +static int stream_param_check(const struct bt_audio_unicast_group_stream_param *param) +{ + CHECKIF(param->stream == NULL) { + LOG_ERR("param->stream is NULL"); + return -EINVAL; + } + + CHECKIF(param->qos == NULL) { + LOG_ERR("param->qos is NULL"); + return -EINVAL; + } + + if (param->stream != NULL && param->stream->group != NULL) { + LOG_WRN("stream %p already part of group %p", + param->stream, param->stream->group); + return -EALREADY; + } + + CHECKIF(!bt_audio_valid_qos(param->qos)) { + LOG_ERR("Invalid QoS"); + return -EINVAL; + } + + return 0; +} + +static int stream_pair_param_check(const struct bt_audio_unicast_group_stream_pair_param *param) +{ + int err; + + CHECKIF(param->rx_param == NULL && param->tx_param == NULL) { + LOG_DBG("Invalid stream parameters"); + return -EINVAL; + } + + if (param->rx_param != NULL) { + err = stream_param_check(param->rx_param); + if (err < 0) { + return err; + } + } + + if (param->tx_param != NULL) { + err = stream_param_check(param->tx_param); + if (err < 0) { + return err; + } + } + + return 0; +} + +static int group_qos_common_set(const struct bt_codec_qos **group_qos, + const struct bt_audio_unicast_group_stream_pair_param *param) +{ + if (param->rx_param != NULL && *group_qos == NULL) { + *group_qos = param->rx_param->qos; + } + + if (param->tx_param != NULL && *group_qos == NULL) { + *group_qos = param->tx_param->qos; + } + + return 0; +} + int bt_audio_unicast_group_create(struct bt_audio_unicast_group_param *param, struct bt_audio_unicast_group **out_unicast_group) { @@ -990,34 +1065,6 @@ int bt_audio_unicast_group_create(struct bt_audio_unicast_group_param *param, return -EINVAL; } - for (size_t i = 0U; i < param->params_count; i++) { - struct bt_audio_unicast_group_stream_param *stream_param = ¶m->params[i]; - - CHECKIF(stream_param->stream == NULL || - stream_param->qos == NULL || - (stream_param->dir != BT_AUDIO_DIR_SINK && - stream_param->dir != BT_AUDIO_DIR_SOURCE)) { - LOG_DBG("Invalid params[%zu] values", i); - return -EINVAL; - } - - if (stream_param->stream->group != NULL) { - LOG_DBG("params[%zu] stream (%p) already part of group %p", - i, stream_param->stream, - stream_param->stream->group); - return -EALREADY; - } - - if (group_qos == NULL) { - group_qos = stream_param->qos; - } - - CHECKIF(!bt_audio_valid_qos(stream_param->qos)) { - LOG_DBG("Invalid QoS"); - return -EINVAL; - } - } - unicast_group = unicast_group_alloc(); if (unicast_group == NULL) { LOG_DBG("Could not allocate any more unicast groups"); @@ -1025,12 +1072,22 @@ int bt_audio_unicast_group_create(struct bt_audio_unicast_group_param *param, } for (size_t i = 0U; i < param->params_count; i++) { - struct bt_audio_unicast_group_stream_param *stream_param = ¶m->params[i]; + struct bt_audio_unicast_group_stream_pair_param *stream_param; - err = unicast_group_add_stream(unicast_group, - stream_param->stream, - stream_param->qos, - stream_param->dir); + stream_param = ¶m->params[i]; + + err = stream_pair_param_check(stream_param); + if (err < 0) { + return err; + } + + err = group_qos_common_set(&group_qos, stream_param); + if (err < 0) { + return err; + } + + err = unicast_group_add_stream_pair(unicast_group, + stream_param); if (err < 0) { LOG_DBG("unicast_group_add_stream failed: %d", err); unicast_group_free(unicast_group); @@ -1053,7 +1110,7 @@ int bt_audio_unicast_group_create(struct bt_audio_unicast_group_param *param, } int bt_audio_unicast_group_add_streams(struct bt_audio_unicast_group *unicast_group, - struct bt_audio_unicast_group_stream_param params[], + struct bt_audio_unicast_group_stream_pair_param params[], size_t num_param) { const struct bt_codec_qos *group_qos = unicast_group->qos; @@ -1078,26 +1135,6 @@ int bt_audio_unicast_group_add_streams(struct bt_audio_unicast_group *unicast_gr return -EINVAL; } - for (size_t i = 0U; i < num_param; i++) { - CHECKIF(params[i].stream == NULL || - params[i].qos == NULL || - (params[i].dir != BT_AUDIO_DIR_SINK && - params[i].dir != BT_AUDIO_DIR_SOURCE)) { - LOG_DBG("Invalid params[%zu] values", i); - return -EINVAL; - } - - if (params[i].stream->group != NULL) { - LOG_DBG("params[%zu] stream (%p) already part of group %p", i, - params[i].stream, params[i].stream->group); - return -EALREADY; - } - - if (group_qos == NULL) { - group_qos = params[i].qos; - } - } - total_stream_cnt = num_param; SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, tmp_stream, _node) { total_stream_cnt++; @@ -1120,10 +1157,22 @@ int bt_audio_unicast_group_add_streams(struct bt_audio_unicast_group *unicast_gr } for (num_added = 0U; num_added < num_param; num_added++) { - err = unicast_group_add_stream(unicast_group, - params[num_added].stream, - params[num_added].qos, - params[num_added].dir); + struct bt_audio_unicast_group_stream_pair_param *stream_param; + + stream_param = ¶ms[num_added]; + + err = stream_pair_param_check(stream_param); + if (err < 0) { + return err; + } + + err = group_qos_common_set(&group_qos, stream_param); + if (err < 0) { + return err; + } + + err = unicast_group_add_stream_pair(unicast_group, + stream_param); if (err < 0) { LOG_DBG("unicast_group_add_stream failed: %d", err); goto fail; @@ -1141,7 +1190,7 @@ int bt_audio_unicast_group_add_streams(struct bt_audio_unicast_group *unicast_gr fail: /* Restore group by removing the newly added streams */ while (num_added--) { - unicast_group_del_stream(unicast_group, params[num_added].stream); + unicast_group_del_stream_pair(unicast_group, ¶ms[num_added]); } return err; diff --git a/subsys/bluetooth/shell/audio.c b/subsys/bluetooth/shell/audio.c index ccf016d7256..edb863c65e6 100644 --- a/subsys/bluetooth/shell/audio.c +++ b/subsys/bluetooth/shell/audio.c @@ -1068,14 +1068,22 @@ static int cmd_qos(const struct shell *sh, size_t argc, char *argv[]) struct bt_audio_unicast_group_stream_param stream_param = { .stream = default_stream, .qos = &default_preset->preset.qos, - .dir = stream_dir(default_stream) }; + struct bt_audio_unicast_group_stream_pair_param pair_param; struct bt_audio_unicast_group_param param = { .packing = BT_ISO_PACKING_SEQUENTIAL, - .params = &stream_param, + .params = &pair_param, .params_count = 1, }; + if (stream_dir(default_stream) == BT_AUDIO_DIR_SOURCE) { + pair_param.rx_param = &stream_param; + pair_param.tx_param = NULL; + } else { + pair_param.rx_param = NULL; + pair_param.tx_param = &stream_param; + } + err = bt_audio_unicast_group_create(¶m, &default_unicast_group); if (err != 0) { shell_error(sh, "Unable to create default unicast group: %d", err); diff --git a/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_client_test.c b/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_client_test.c index f77093dce32..3414b4d5f65 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_client_test.c +++ b/tests/bluetooth/bsim_bt/bsim_test_audio/src/unicast_client_test.c @@ -339,16 +339,18 @@ static size_t release_streams(size_t stream_cnt) static void create_unicast_group(struct bt_audio_unicast_group **unicast_group, size_t stream_cnt) { + struct bt_audio_unicast_group_stream_pair_param pair_params[ARRAY_SIZE(g_streams)]; struct bt_audio_unicast_group_stream_param stream_params[ARRAY_SIZE(g_streams)]; struct bt_audio_unicast_group_param param; for (size_t i = 0U; i < stream_cnt; i++) { stream_params[i].stream = &g_streams[i]; stream_params[i].qos = &preset_16_2_1.qos; - stream_params[i].dir = BT_AUDIO_DIR_SINK; /* we only configure sinks */ + pair_params[i].rx_param = NULL; + pair_params[i].tx_param = &stream_params[i]; } - param.params = stream_params; + param.params = pair_params; param.params_count = stream_cnt; param.packing = BT_ISO_PACKING_SEQUENTIAL;