From ab9ee0817d1398a7b204a0951d1a75193245d41c Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 5 Jul 2024 10:21:40 +0200 Subject: [PATCH] Bluetooth: BAP: Add broadcast source callback structs These callbacks are trigger for changes that affect the entire broadcast source, such as the BIG started and terminated events. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/bap.h | 47 +++++++ subsys/bluetooth/audio/bap_broadcast_source.c | 133 +++++++++++++++--- .../audio/bap_broadcast_source/CMakeLists.txt | 1 + .../audio/bap_broadcast_source/src/main.c | 28 +++- .../src/test_callback_register.c | 98 +++++++++++++ .../bap_broadcast_source/uut/CMakeLists.txt | 1 + .../uut/bap_broadcast_source.c | 31 ++++ .../mocks/include/bap_broadcast_source.h | 23 +++ tests/bluetooth/audio/mocks/src/iso.c | 24 ++++ .../audio/src/bap_broadcast_source_test.c | 75 +++++++--- 10 files changed, 416 insertions(+), 45 deletions(-) create mode 100644 tests/bluetooth/audio/bap_broadcast_source/src/test_callback_register.c create mode 100644 tests/bluetooth/audio/bap_broadcast_source/uut/bap_broadcast_source.c create mode 100644 tests/bluetooth/audio/mocks/include/bap_broadcast_source.h diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 38356a17527..33ba8ca3cff 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -2001,6 +2001,53 @@ int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgrou * @{ */ +/** + * @brief Struct to hold the Broadcast Source callbacks + * + * These can be registered for usage with bt_bap_broadcast_source_register_cb(). + */ +struct bt_bap_broadcast_source_cb { + /** + * @brief The Broadcast Source has started and all of the streams are ready for audio data + * + * @param source The started Broadcast Source + */ + void (*started)(struct bt_bap_broadcast_source *source); + + /** + * @brief The Broadcast Source has stopped and none of the streams are ready for audio data + * + * @param source The stopped Broadcast Source + * @param reason The reason why the Broadcast Source stopped (see the BT_HCI_ERR_* values) + */ + void (*stopped)(struct bt_bap_broadcast_source *source, uint8_t reason); + + /** @internal Internally used field for list handling */ + sys_snode_t _node; +}; + +/** + * @brief Registers callbacks for Broadcast Sources + * + * @param cb Pointer to the callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EEXIST if @p cb is already registered + */ +int bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb *cb); + +/** + * @brief Unregisters callbacks for Broadcast Sources + * + * @param cb Pointer to the callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -ENOENT if @p cb is not registered + */ +int bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb *cb); + /** Broadcast Source stream parameters */ struct bt_bap_broadcast_source_stream_param { /** Audio stream */ diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 93186af67f0..132dca5580a 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -1,7 +1,7 @@ /* Bluetooth Audio Broadcast Source */ /* - * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ static struct bt_bap_broadcast_subgroup broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT] [CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; static struct bt_bap_broadcast_source broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]; +static sys_slist_t bap_broadcast_source_cbs = SYS_SLIST_STATIC_INIT(&bap_broadcast_source_cbs); /** * 2 octets UUID @@ -238,9 +240,9 @@ static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t } static struct bt_iso_chan_ops broadcast_source_iso_ops = { - .sent = broadcast_source_iso_sent, - .connected = broadcast_source_iso_connected, - .disconnected = broadcast_source_iso_disconnected, + .sent = broadcast_source_iso_sent, + .connected = broadcast_source_iso_connected, + .disconnected = broadcast_source_iso_disconnected, }; bool bt_bap_ep_is_broadcast_src(const struct bt_bap_ep *ep) @@ -440,8 +442,7 @@ static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_s */ streams_encoded = 0; SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { - if (!encode_base_subgroup(subgroup, - &source->stream_data[streams_encoded], + if (!encode_base_subgroup(subgroup, &source->stream_data[streams_encoded], &streams_encoded, buf)) { return false; } @@ -454,12 +455,10 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source) { struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup; - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, - next_subgroup, _node) { + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, next_subgroup, _node) { struct bt_bap_stream *stream, *next_stream; - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, - next_stream, _node) { + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, next_stream, _node) { bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep); stream->ep->stream = NULL; stream->ep = NULL; @@ -467,8 +466,7 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source) stream->qos = NULL; stream->group = NULL; - sys_slist_remove(&subgroup->streams, NULL, - &stream->_node); + sys_slist_remove(&subgroup->streams, NULL, &stream->_node); } sys_slist_remove(&source->subgroups, NULL, &subgroup->_node); } @@ -777,8 +775,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param, bis_count++; } - err = broadcast_source_setup_stream(index, stream, - codec_cfg, qos, source); + err = broadcast_source_setup_stream(index, stream, codec_cfg, qos, source); if (err != 0) { LOG_DBG("Failed to setup streams[%zu]: %d", i, err); broadcast_source_cleanup(source); @@ -1039,7 +1036,7 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv) { struct bt_iso_chan *bis[BROADCAST_STREAM_CNT]; - struct bt_iso_big_create_param param = { 0 }; + struct bt_iso_big_create_param param = {0}; struct bt_bap_broadcast_subgroup *subgroup; enum bt_bap_ep_state broadcast_state; struct bt_bap_stream *stream; @@ -1078,8 +1075,7 @@ int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct param.latency = source->qos->latency; param.encryption = source->encryption; if (param.encryption) { - (void)memcpy(param.bcode, source->broadcast_code, - sizeof(param.bcode)); + (void)memcpy(param.bcode, source->broadcast_code, sizeof(param.bcode)); } #if defined(CONFIG_BT_ISO_TEST_PARAMS) param.irc = source->irc; @@ -1125,14 +1121,12 @@ int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source) return -EALREADY; } - err = bt_iso_big_terminate(source->big); + err = bt_iso_big_terminate(source->big); if (err) { LOG_DBG("Failed to terminate BIG (err %d)", err); return err; } - source->big = NULL; - return 0; } @@ -1188,3 +1182,102 @@ int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source, return 0; } + +static struct bt_bap_broadcast_source *get_broadcast_source_by_big(const struct bt_iso_big *big) +{ + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources); i++) { + if (broadcast_sources[i].big == big) { + return &broadcast_sources[i]; + } + } + + return NULL; +} + +static void big_started_cb(struct bt_iso_big *big) +{ + struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big); + struct bt_bap_broadcast_source_cb *listener; + + if (source == NULL) { + /* Not one of ours */ + return; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) { + if (listener->started != NULL) { + listener->started(source); + } + } +} + +static void big_stopped_cb(struct bt_iso_big *big, uint8_t reason) +{ + struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big); + struct bt_bap_broadcast_source_cb *listener; + + if (source == NULL) { + /* Not one of ours */ + return; + } + + source->big = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) { + if (listener->stopped != NULL) { + listener->stopped(source, reason); + } + } +} + +int bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb *cb) +{ + static bool iso_big_cb_registered; + + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + + return -EINVAL; + } + + if (sys_slist_find(&bap_broadcast_source_cbs, &cb->_node, NULL)) { + LOG_DBG("cb %p is already registered", cb); + + return -EEXIST; + } + + if (!iso_big_cb_registered) { + static struct bt_iso_big_cb big_cb = { + .started = big_started_cb, + .stopped = big_stopped_cb, + }; + const int err = bt_iso_big_register_cb(&big_cb); + + if (err != 0) { + __ASSERT(false, "Failed to register ISO BIG callbacks: %d", err); + } + + iso_big_cb_registered = true; + } + + sys_slist_append(&bap_broadcast_source_cbs, &cb->_node); + + return 0; +} + +int bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb *cb) +{ + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + + return -EINVAL; + } + + if (!sys_slist_find_and_remove(&bap_broadcast_source_cbs, &cb->_node)) { + LOG_DBG("cb %p is not registered", cb); + + return -ENOENT; + } + + return 0; +} diff --git a/tests/bluetooth/audio/bap_broadcast_source/CMakeLists.txt b/tests/bluetooth/audio/bap_broadcast_source/CMakeLists.txt index ef097b64e7a..d79b0f147a6 100644 --- a/tests/bluetooth/audio/bap_broadcast_source/CMakeLists.txt +++ b/tests/bluetooth/audio/bap_broadcast_source/CMakeLists.txt @@ -15,4 +15,5 @@ target_include_directories(testbinary PRIVATE include) target_sources(testbinary PRIVATE src/main.c + src/test_callback_register.c ) diff --git a/tests/bluetooth/audio/bap_broadcast_source/src/main.c b/tests/bluetooth/audio/bap_broadcast_source/src/main.c index 82e6406919f..38a2b0a6e50 100644 --- a/tests/bluetooth/audio/bap_broadcast_source/src/main.c +++ b/tests/bluetooth/audio/bap_broadcast_source/src/main.c @@ -1,28 +1,41 @@ /* main.c - Application main entry point */ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include #include #include #include +#include +#include +#include #include #include #include +#include +#include #include -#include "bluetooth.h" +#include "bap_broadcast_source.h" +#include "bap_stream.h" #include "bap_stream_expects.h" +#include "bluetooth.h" +#include "expects_util.h" +#include "ztest_assert.h" +#include "ztest_test.h" DEFINE_FFF_GLOBALS; static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixture) { + mock_bap_broadcast_source_init(); mock_bap_stream_init(); } @@ -136,8 +149,13 @@ static void *bap_broadcast_source_test_suite_setup(void) static void bap_broadcast_source_test_suite_before(void *f) { + int err; + memset(f, 0, sizeof(struct bap_broadcast_source_test_suite_fixture)); bap_broadcast_source_test_suite_fixture_init(f); + + err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb); + zassert_equal(0, err, "Unexpected return value %d", err); } static void bap_broadcast_source_test_suite_after(void *f) @@ -164,6 +182,8 @@ static void bap_broadcast_source_test_suite_after(void *f) free(param->params); free(param->qos); free(param); + + bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb); } static void bap_broadcast_source_test_suite_teardown(void *f) @@ -224,6 +244,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send mock_bap_stream_connected_cb_fake.call_count); zexpect_call_count("bt_bap_stream_ops.started", fixture->stream_cnt, mock_bap_stream_started_cb_fake.call_count); + zexpect_call_count("bt_bap_broadcast_source_cb.started", 1, + mock_bap_broadcast_source_started_cb_fake.call_count); for (size_t i = 0U; i < create_param->params_count; i++) { for (size_t j = 0U; j < create_param->params[i].params_count; j++) { @@ -260,6 +282,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send mock_bap_stream_disconnected_cb_fake.call_count); zexpect_call_count("bt_bap_stream_ops.stopped", fixture->stream_cnt, mock_bap_stream_stopped_cb_fake.call_count); + zexpect_call_count("bt_bap_broadcast_source_cb.stopped", 1, + mock_bap_broadcast_source_stopped_cb_fake.call_count); err = bt_bap_broadcast_source_delete(fixture->source); zassert_equal(0, err, "Unable to delete broadcast source: err %d", err); diff --git a/tests/bluetooth/audio/bap_broadcast_source/src/test_callback_register.c b/tests/bluetooth/audio/bap_broadcast_source/src/test_callback_register.c new file mode 100644 index 00000000000..0e221a68551 --- /dev/null +++ b/tests/bluetooth/audio/bap_broadcast_source/src/test_callback_register.c @@ -0,0 +1,98 @@ +/* test_callback_register.c - Test bt_bap_broadcast_source_register and unregister */ + +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#include "bap_broadcast_source.h" +#include "ztest_assert.h" +#include "ztest_test.h" + +#define FFF_GLOBALS + +static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixture) +{ + mock_bap_broadcast_source_init(); +} + +ZTEST_RULE(mock_rule, mock_init_rule_before, NULL); + +static void bap_broadcast_source_test_cb_register_suite_after(void *f) +{ + bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb); +} + +ZTEST_SUITE(bap_broadcast_source_test_cb_register_suite, NULL, NULL, NULL, + bap_broadcast_source_test_cb_register_suite_after, NULL); + +static ZTEST(bap_broadcast_source_test_cb_register_suite, test_broadcast_source_register_cb) +{ + int err; + + err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb); + zassert_equal(0, err, "Unexpected return value %d", err); +} + +static ZTEST(bap_broadcast_source_test_cb_register_suite, + test_broadcast_source_register_cb_inval_param_null) +{ + int err; + + err = bt_bap_broadcast_source_register_cb(NULL); + zassert_equal(err, -EINVAL, "Unexpected return value %d", err); +} + +static ZTEST(bap_broadcast_source_test_cb_register_suite, + test_broadcast_source_register_cb_inval_double_register) +{ + int err; + + err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb); + zassert_equal(err, 0, "Unexpected return value %d", err); + + err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb); + zassert_equal(err, -EEXIST, "Unexpected return value %d", err); +} + +static ZTEST(bap_broadcast_source_test_cb_register_suite, test_broadcast_source_unregister_cb) +{ + int err; + + err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb); + zassert_equal(err, 0, "Unexpected return value %d", err); + + err = bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb); + zassert_equal(err, 0, "Unexpected return value %d", err); +} + +static ZTEST(bap_broadcast_source_test_cb_register_suite, + test_broadcast_source_unregister_cb_inval_param_null) +{ + int err; + + err = bt_bap_broadcast_source_unregister_cb(NULL); + zassert_equal(err, -EINVAL, "Unexpected return value %d", err); +} + +static ZTEST(bap_broadcast_source_test_cb_register_suite, + test_broadcast_source_unregister_cb_inval_double_unregister) +{ + int err; + + err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb); + zassert_equal(err, 0, "Unexpected return value %d", err); + + err = bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb); + zassert_equal(err, 0, "Unexpected return value %d", err); + + err = bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb); + zassert_equal(err, -ENOENT, "Unexpected return value %d", err); +} diff --git a/tests/bluetooth/audio/bap_broadcast_source/uut/CMakeLists.txt b/tests/bluetooth/audio/bap_broadcast_source/uut/CMakeLists.txt index 879a50720b3..76dd64501cf 100644 --- a/tests/bluetooth/audio/bap_broadcast_source/uut/CMakeLists.txt +++ b/tests/bluetooth/audio/bap_broadcast_source/uut/CMakeLists.txt @@ -14,6 +14,7 @@ add_library(uut STATIC ${ZEPHYR_BASE}/subsys/bluetooth/audio/codec.c ${ZEPHYR_BASE}/subsys/logging/log_minimal.c ${ZEPHYR_BASE}/lib/net_buf/buf_simple.c + bap_broadcast_source.c ) add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/mocks mocks) diff --git a/tests/bluetooth/audio/bap_broadcast_source/uut/bap_broadcast_source.c b/tests/bluetooth/audio/bap_broadcast_source/uut/bap_broadcast_source.c new file mode 100644 index 00000000000..e0e2944836b --- /dev/null +++ b/tests/bluetooth/audio/bap_broadcast_source/uut/bap_broadcast_source.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include + +#include "bap_broadcast_source.h" +#include "zephyr/fff.h" + +/* List of fakes used by this unit tester */ +#define FFF_FAKES_LIST(FAKE) \ + FAKE(mock_bap_broadcast_source_started_cb) \ + FAKE(mock_bap_broadcast_source_stopped_cb) + +DEFINE_FAKE_VOID_FUNC(mock_bap_broadcast_source_started_cb, struct bt_bap_broadcast_source *); + +DEFINE_FAKE_VOID_FUNC(mock_bap_broadcast_source_stopped_cb, struct bt_bap_broadcast_source *, + uint8_t); + +struct bt_bap_broadcast_source_cb mock_bap_broadcast_source_cb = { + .started = mock_bap_broadcast_source_started_cb, + .stopped = mock_bap_broadcast_source_stopped_cb, +}; + +void mock_bap_broadcast_source_init(void) +{ + FFF_FAKES_LIST(RESET_FAKE); +} diff --git a/tests/bluetooth/audio/mocks/include/bap_broadcast_source.h b/tests/bluetooth/audio/mocks/include/bap_broadcast_source.h new file mode 100644 index 00000000000..d6b75e7c51a --- /dev/null +++ b/tests/bluetooth/audio/mocks/include/bap_broadcast_source.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef MOCKS_BAP_BROADCAST_SOURCE_H_ +#define MOCKS_BAP_BROADCAST_SOURCE_H_ + +#include + +#include +#include + +extern struct bt_bap_broadcast_source_cb mock_bap_broadcast_source_cb; + +void mock_bap_broadcast_source_init(void); + +DECLARE_FAKE_VOID_FUNC(mock_bap_broadcast_source_started_cb, struct bt_bap_broadcast_source *); +DECLARE_FAKE_VOID_FUNC(mock_bap_broadcast_source_stopped_cb, struct bt_bap_broadcast_source *, + uint8_t); + +#endif /* MOCKS_BAP_BROADCAST_SOURCE_H_ */ diff --git a/tests/bluetooth/audio/mocks/src/iso.c b/tests/bluetooth/audio/mocks/src/iso.c index 7271a66242e..bb344f81a77 100644 --- a/tests/bluetooth/audio/mocks/src/iso.c +++ b/tests/bluetooth/audio/mocks/src/iso.c @@ -1,10 +1,13 @@ /* * Copyright (c) 2023 Codecoup + * Copyright (c) 2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ +#include #include + #include #include "conn.h" @@ -123,6 +126,19 @@ int mock_bt_iso_disconnected(struct bt_iso_chan *chan, uint8_t err) } #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) +static struct bt_iso_big_cb *iso_cb; + +int bt_iso_big_register_cb(struct bt_iso_big_cb *cb) +{ + if (cb == NULL) { + return -EINVAL; + } + + iso_cb = cb; + + return 0; +} + int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param, struct bt_iso_big **out_big) { @@ -153,6 +169,10 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *out_big = big; + if (iso_cb != NULL && iso_cb->started != NULL) { + iso_cb->started(big); + } + return 0; } @@ -169,6 +189,10 @@ int bt_iso_big_terminate(struct bt_iso_big *big) mock_bt_iso_disconnected(bis, BT_HCI_ERR_LOCALHOST_TERM_CONN); } + if (iso_cb != NULL && iso_cb->stopped != NULL) { + iso_cb->stopped(big, BT_HCI_ERR_LOCALHOST_TERM_CONN); + } + free(big); return 0; diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c index de0d7764779..0006c54508b 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,6 +35,8 @@ #define SUPPORTED_MAX_FRAMES_PER_SDU 1 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) +CREATE_FLAG(flag_source_started); + /* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that * the controller is never idle */ @@ -62,8 +64,8 @@ static uint8_t bis_codec_data[] = { BT_BYTES_LIST_LE32(BT_AUDIO_LOCATION_FRONT_CENTER)), }; -static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(broadcast_source_streams)); -static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(broadcast_source_streams)); +static K_SEM_DEFINE(sem_stream_started, 0U, ARRAY_SIZE(broadcast_source_streams)); +static K_SEM_DEFINE(sem_stream_stopped, 0U, ARRAY_SIZE(broadcast_source_streams)); static void validate_stream_codec_cfg(const struct bt_bap_stream *stream) { @@ -174,7 +176,7 @@ static void validate_stream_codec_cfg(const struct bt_bap_stream *stream) } } -static void started_cb(struct bt_bap_stream *stream) +static void stream_started_cb(struct bt_bap_stream *stream) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); struct bt_bap_ep_info info; @@ -216,13 +218,13 @@ static void started_cb(struct bt_bap_stream *stream) printk("Stream %p started\n", stream); validate_stream_codec_cfg(stream); - k_sem_give(&sem_started); + k_sem_give(&sem_stream_started); } -static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +static void steam_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) { printk("Stream %p stopped with reason 0x%02X\n", stream, reason); - k_sem_give(&sem_stopped); + k_sem_give(&sem_stream_stopped); } static void stream_sent_cb(struct bt_bap_stream *stream) @@ -265,11 +267,23 @@ static void stream_sent_cb(struct bt_bap_stream *stream) } static struct bt_bap_stream_ops stream_ops = { - .started = started_cb, - .stopped = stopped_cb, + .started = stream_started_cb, + .stopped = steam_stopped_cb, .sent = stream_sent_cb, }; +static void source_started_cb(struct bt_bap_broadcast_source *source) +{ + printk("Broadcast source %p started\n", source); + SET_FLAG(flag_source_started); +} + +static void source_stopped_cb(struct bt_bap_broadcast_source *source, uint8_t reason) +{ + printk("Broadcast source %p stopped with reason 0x%02X\n", source, reason); + UNSET_FLAG(flag_source_started); +} + static int setup_broadcast_source(struct bt_bap_broadcast_source **source, bool encryption) { struct bt_bap_broadcast_source_stream_param @@ -467,10 +481,12 @@ static void test_broadcast_source_start(struct bt_bap_broadcast_source *source, } /* Wait for all to be started */ - printk("Waiting for streams to be started\n"); + printk("Waiting for %zu streams to be started\n", ARRAY_SIZE(broadcast_source_streams)); for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - k_sem_take(&sem_started, K_FOREVER); + k_sem_take(&sem_stream_started, K_FOREVER); } + + WAIT_FOR_FLAG(flag_source_started); } static void test_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source, @@ -520,10 +536,12 @@ static void test_broadcast_source_stop(struct bt_bap_broadcast_source *source) } /* Wait for all to be stopped */ - printk("Waiting for streams to be stopped\n"); + printk("Waiting for %zu streams to be stopped\n", ARRAY_SIZE(broadcast_source_streams)); for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { - k_sem_take(&sem_stopped, K_FOREVER); + k_sem_take(&sem_stream_stopped, K_FOREVER); } + + WAIT_FOR_UNSET_FLAG(flag_source_started); } static void test_broadcast_source_delete(struct bt_bap_broadcast_source *source) @@ -564,10 +582,12 @@ static int stop_extended_adv(struct bt_le_ext_adv *adv) return 0; } -static void test_main(void) +static void init(void) { - struct bt_bap_broadcast_source *source; - struct bt_le_ext_adv *adv; + static struct bt_bap_broadcast_source_cb broadcast_source_cb = { + .started = source_started_cb, + .stopped = source_stopped_cb, + }; int err; err = bt_enable(NULL); @@ -578,6 +598,21 @@ static void test_main(void) printk("Bluetooth initialized\n"); + err = bt_bap_broadcast_source_register_cb(&broadcast_source_cb); + if (err != 0) { + FAIL("Failed to register broadcast source callbacks (err %d)\n", err); + return; + } +} + +static void test_main(void) +{ + struct bt_bap_broadcast_source *source; + struct bt_le_ext_adv *adv; + int err; + + init(); + err = setup_broadcast_source(&source, false); if (err != 0) { FAIL("Unable to setup broadcast source: %d\n", err); @@ -650,13 +685,7 @@ static void test_main_encrypted(void) struct bt_le_ext_adv *adv; int err; - err = bt_enable(NULL); - if (err) { - FAIL("Bluetooth init failed (err %d)\n", err); - return; - } - - printk("Bluetooth initialized\n"); + init(); err = setup_broadcast_source(&source, true); if (err != 0) {