diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index f04c5c82814..3409e000d9c 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -346,7 +346,10 @@ int bt_cap_initiator_unregister_cb(const struct bt_cap_initiator_cb *cb); * * @param param Parameters to start the audio streams. * - * @return 0 on success or negative error value on failure. + * @retval 0 on success + * @retval -EBUSY if a CAP procedure is already in progress + * @retval -EINVAL if any parameter is invalid + * @retval -EALREADY All streams are already in the streaming state */ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param); diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index e6a16c4bf5a..552bc724e11 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "bap_endpoint.h" #include "cap_internal.h" @@ -860,6 +861,8 @@ static int cap_initiator_unicast_audio_configure( int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param) { + bool all_streaming = true; + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); @@ -870,6 +873,20 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start return -EINVAL; } + for (size_t i = 0U; i < param->count; i++) { + const struct bt_bap_stream *bap_stream = + ¶m->stream_params[i].stream->bap_stream; + + if (!stream_is_in_state(bap_stream, BT_BAP_EP_STATE_STREAMING)) { + all_streaming = false; + } + } + + if (all_streaming) { + LOG_DBG("All streams are already in the streaming state"); + return -EALREADY; + } + return cap_initiator_unicast_audio_configure(param); } diff --git a/tests/bluetooth/audio/cap_initiator/src/test_unicast_start.c b/tests/bluetooth/audio/cap_initiator/src/test_unicast_start.c index 9f73712f2f0..7ff7f2472ff 100644 --- a/tests/bluetooth/audio/cap_initiator/src/test_unicast_start.c +++ b/tests/bluetooth/audio/cap_initiator/src/test_unicast_start.c @@ -500,3 +500,40 @@ static ZTEST_F(cap_initiator_test_unicast_start, test_initiator_unicast_start_st "[%zu]: Stream %p unexpected state: %d", i, bap_stream, state); } } + +static ZTEST_F(cap_initiator_test_unicast_start, test_initiator_unicast_start_state_streaming) +{ + struct bt_cap_unicast_audio_start_stream_param + stream_params[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT] = {0}; + const struct bt_cap_unicast_audio_start_param param = { + .type = BT_CAP_SET_TYPE_AD_HOC, + .count = ARRAY_SIZE(stream_params), + .stream_params = stream_params, + }; + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) { + stream_params[i].stream = &fixture->cap_streams[i]; + stream_params[i].codec_cfg = &fixture->preset.codec_cfg; + stream_params[i].member.member = &fixture->conns[i % ARRAY_SIZE(fixture->conns)]; + stream_params[i].ep = &fixture->eps[i]; + + test_unicast_set_state(stream_params[i].stream, stream_params[i].member.member, + stream_params[i].ep, &fixture->preset, + BT_BAP_EP_STATE_STREAMING); + } + + err = bt_cap_initiator_unicast_audio_start(¶m); + zassert_equal(err, -EALREADY, "Unexpected return value %d", err); + + zexpect_call_count("bt_cap_initiator_cb.unicast_start_complete_cb", 0, + mock_cap_initiator_unicast_start_complete_cb_fake.call_count); + + for (size_t i = 0U; i < ARRAY_SIZE(stream_params); i++) { + const struct bt_bap_stream *bap_stream = &fixture->cap_streams[i].bap_stream; + const enum bt_bap_ep_state state = bap_stream->ep->status.state; + + zassert_equal(state, BT_BAP_EP_STATE_STREAMING, + "[%zu]: Stream %p unexpected state: %d", i, bap_stream, state); + } +}