From 0ae976166ff51cb5a2c86d59d3c954bc57db9546 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 5 Jul 2024 15:10:12 +0200 Subject: [PATCH] Bluetooth: CAP: 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/cap.h | 16 +++++ subsys/bluetooth/audio/cap_initiator.c | 60 ++++++++++++++++++ .../cap_initiator/include/cap_initiator.h | 3 + .../audio/cap_initiator/uut/cap_initiator.c | 7 +++ .../audio/src/cap_initiator_broadcast_test.c | 61 ++++++++++++++----- 5 files changed, 132 insertions(+), 15 deletions(-) diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 34b5b0f3e1c..b539a463c26 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -128,6 +128,22 @@ struct bt_cap_initiator_cb { */ void (*unicast_stop_complete)(int err, struct bt_conn *conn); #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ +#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) + /** + * @brief The Broadcast Source has started and all of the streams are ready for audio data + * + * @param source The started Broadcast Source + */ + void (*broadcast_started)(struct bt_cap_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 (*broadcast_stopped)(struct bt_cap_broadcast_source *source, uint8_t reason); +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ }; /** diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index d6485e5f094..b1f8bedb734 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -257,9 +257,54 @@ int bt_cap_initiator_broadcast_audio_create( &(*broadcast_source)->bap_broadcast); } +static struct bt_cap_broadcast_source *get_cap_broadcast_source_by_bap_broadcast_source( + const struct bt_bap_broadcast_source *bap_broadcast_source) +{ + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources); i++) { + if (broadcast_sources[i].bap_broadcast == bap_broadcast_source) { + return &broadcast_sources[i]; + } + } + + return NULL; +} + +static void broadcast_source_started_cb(struct bt_bap_broadcast_source *bap_broadcast_source) +{ + if (cap_cb && cap_cb->broadcast_started) { + struct bt_cap_broadcast_source *source = + get_cap_broadcast_source_by_bap_broadcast_source(bap_broadcast_source); + + if (source == NULL) { + /* Not one of ours */ + return; + } + + cap_cb->broadcast_started(source); + } +} + +static void broadcast_source_stopped_cb(struct bt_bap_broadcast_source *bap_broadcast_source, + uint8_t reason) +{ + if (cap_cb && cap_cb->broadcast_stopped) { + struct bt_cap_broadcast_source *source = + get_cap_broadcast_source_by_bap_broadcast_source(bap_broadcast_source); + + if (source == NULL) { + /* Not one of ours */ + return; + } + + cap_cb->broadcast_stopped(source, reason); + } +} + int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source, struct bt_le_ext_adv *adv) { + static bool broadcast_source_cbs_registered; + CHECKIF(adv == NULL) { LOG_DBG("adv is NULL"); return -EINVAL; @@ -270,6 +315,21 @@ int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broad return -EINVAL; } + if (!broadcast_source_cbs_registered) { + static struct bt_bap_broadcast_source_cb broadcast_source_cb = { + .started = broadcast_source_started_cb, + .stopped = broadcast_source_stopped_cb, + }; + const int err = bt_bap_broadcast_source_register_cb(&broadcast_source_cb); + + if (err != 0) { + __ASSERT(false, "Failed to register BAP broadcast source callbacks: %d", + err); + } + + broadcast_source_cbs_registered = true; + } + return bt_bap_broadcast_source_start(broadcast_source->bap_broadcast, adv); } diff --git a/tests/bluetooth/audio/cap_initiator/include/cap_initiator.h b/tests/bluetooth/audio/cap_initiator/include/cap_initiator.h index 9b69f7d837f..57104e7ef03 100644 --- a/tests/bluetooth/audio/cap_initiator/include/cap_initiator.h +++ b/tests/bluetooth/audio/cap_initiator/include/cap_initiator.h @@ -23,5 +23,8 @@ DECLARE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_discovery_complete_cb, struct DECLARE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_start_complete_cb, int, struct bt_conn *); DECLARE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_update_complete_cb, int, struct bt_conn *); DECLARE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_stop_complete_cb, int, struct bt_conn *); +DECLARE_FAKE_VOID_FUNC(mock_cap_initiator_broadcast_started_cb, struct bt_cap_broadcast_source *); +DECLARE_FAKE_VOID_FUNC(mock_cap_initiator_broadcast_stopped_cb, struct bt_cap_broadcast_source *, + uint8_t); #endif /* MOCKS_CAP_INITIATOR_H_ */ diff --git a/tests/bluetooth/audio/cap_initiator/uut/cap_initiator.c b/tests/bluetooth/audio/cap_initiator/uut/cap_initiator.c index d094cc3c5b9..78dea5f4685 100644 --- a/tests/bluetooth/audio/cap_initiator/uut/cap_initiator.c +++ b/tests/bluetooth/audio/cap_initiator/uut/cap_initiator.c @@ -25,6 +25,9 @@ DEFINE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_discovery_complete_cb, struct b DEFINE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_start_complete_cb, int, struct bt_conn *); DEFINE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_update_complete_cb, int, struct bt_conn *); DEFINE_FAKE_VOID_FUNC(mock_cap_initiator_unicast_stop_complete_cb, int, struct bt_conn *); +DEFINE_FAKE_VOID_FUNC(mock_cap_initiator_broadcast_started_cb, struct bt_cap_broadcast_source *); +DEFINE_FAKE_VOID_FUNC(mock_cap_initiator_broadcast_stopped_cb, struct bt_cap_broadcast_source *, + uint8_t); const struct bt_cap_initiator_cb mock_cap_initiator_cb = { #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) @@ -33,6 +36,10 @@ const struct bt_cap_initiator_cb mock_cap_initiator_cb = { .unicast_update_complete = mock_cap_initiator_unicast_update_complete_cb, .unicast_stop_complete = mock_cap_initiator_unicast_stop_complete_cb, #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ +#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) + .broadcast_started = mock_cap_initiator_broadcast_started_cb, + .broadcast_stopped = mock_cap_initiator_broadcast_stopped_cb, +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ }; void mock_cap_initiator_init(void) diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c index ea6eacef4fb..9fd54af563c 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -33,6 +33,8 @@ #include "common.h" #if defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE) +CREATE_FLAG(flag_source_started); + /* Zephyr Controller works best while Extended Advertising interval to be a multiple * of the ISO Interval minus 10 ms (max. advertising random delay). This is * required to place the AUX_ADV_IND PDUs in a non-overlapping interval with the @@ -75,8 +77,8 @@ static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1(LOCATION, CONTEXT); static size_t stream_count; -static K_SEM_DEFINE(sem_broadcast_started, 0U, ARRAY_SIZE(broadcast_streams)); -static K_SEM_DEFINE(sem_broadcast_stopped, 0U, ARRAY_SIZE(broadcast_streams)); +static K_SEM_DEFINE(sem_broadcast_stream_started, 0U, ARRAY_SIZE(broadcast_streams)); +static K_SEM_DEFINE(sem_broadcast_stream_stopped, 0U, ARRAY_SIZE(broadcast_streams)); static const struct named_lc3_preset lc3_broadcast_presets[] = { {"8_1_1", BT_BAP_LC3_BROADCAST_PRESET_8_1_1(LOCATION, CONTEXT)}, @@ -114,7 +116,7 @@ static const struct named_lc3_preset lc3_broadcast_presets[] = { {"48_6_2", BT_BAP_LC3_BROADCAST_PRESET_48_6_2(LOCATION, CONTEXT)}, }; -static void broadcast_started_cb(struct bt_bap_stream *stream) +static void broadcast_stream_started_cb(struct bt_bap_stream *stream) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream); @@ -122,16 +124,16 @@ static void broadcast_started_cb(struct bt_bap_stream *stream) test_stream->tx_cnt = 0U; printk("Stream %p started\n", stream); - k_sem_give(&sem_broadcast_started); + k_sem_give(&sem_broadcast_stream_started); } -static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +static void broadcast_stream_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_broadcast_stopped); + k_sem_give(&sem_broadcast_stream_stopped); } -static void broadcast_sent_cb(struct bt_bap_stream *bap_stream) +static void broadcast_stream_sent_cb(struct bt_bap_stream *bap_stream) { struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(bap_stream); struct bt_cap_stream *cap_stream = cap_stream_from_audio_test_stream(test_stream); @@ -178,13 +180,30 @@ static void broadcast_sent_cb(struct bt_bap_stream *bap_stream) } static struct bt_bap_stream_ops broadcast_stream_ops = { - .started = broadcast_started_cb, - .stopped = broadcast_stopped_cb, - .sent = broadcast_sent_cb, + .started = broadcast_stream_started_cb, + .stopped = broadcast_stream_stopped_cb, + .sent = broadcast_stream_sent_cb, }; +static void broadcast_source_started_cb(struct bt_cap_broadcast_source *broadcast_source) +{ + printk("Broadcast source %p started\n", broadcast_source); + SET_FLAG(flag_source_started); +} + +static void broadcast_source_stopped_cb(struct bt_cap_broadcast_source *broadcast_source, + uint8_t reason) +{ + printk("Broadcast source %p stopped with reason 0x%02X\n", broadcast_source, reason); + UNSET_FLAG(flag_source_started); +} + static void init(void) { + static struct bt_cap_initiator_cb broadcast_cbs = { + .broadcast_started = broadcast_source_started_cb, + .broadcast_stopped = broadcast_source_stopped_cb, + }; int err; err = bt_enable(NULL); @@ -221,6 +240,12 @@ static void init(void) printk("Registered GTBS\n"); } + + err = bt_cap_initiator_register_cb(&broadcast_cbs); + if (err != 0) { + FAIL("Failed to register broadcast callbacks: %d\n", err); + return; + } } static void setup_extended_adv(struct bt_le_ext_adv **adv) @@ -605,9 +630,11 @@ static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_ /* Wait for all to be stopped */ printk("Waiting for broadcast_streams to be stopped\n"); for (size_t i = 0U; i < stream_count; i++) { - k_sem_take(&sem_broadcast_stopped, K_FOREVER); + k_sem_take(&sem_broadcast_stream_stopped, K_FOREVER); } + WAIT_FOR_UNSET_FLAG(flag_source_started); + printk("Broadcast source stopped\n"); /* Verify that it cannot be stopped twice */ @@ -679,9 +706,11 @@ static void test_main_cap_initiator_broadcast(void) /* Wait for all to be started */ printk("Waiting for broadcast_streams to be started\n"); for (size_t i = 0U; i < stream_count; i++) { - k_sem_take(&sem_broadcast_started, K_FOREVER); + k_sem_take(&sem_broadcast_stream_started, K_FOREVER); } + WAIT_FOR_FLAG(flag_source_started); + /* Initialize sending */ for (size_t i = 0U; i < stream_count; i++) { struct audio_test_stream *test_stream = &broadcast_source_streams[i]; @@ -689,7 +718,7 @@ static void test_main_cap_initiator_broadcast(void) test_stream->tx_active = true; for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - broadcast_sent_cb(bap_stream_from_audio_test_stream(test_stream)); + broadcast_stream_sent_cb(bap_stream_from_audio_test_stream(test_stream)); } } @@ -785,9 +814,11 @@ static int test_cap_initiator_ac(const struct cap_initiator_ac_param *param) /* Wait for all to be started */ printk("Waiting for broadcast_streams to be started\n"); for (size_t i = 0U; i < stream_count; i++) { - k_sem_take(&sem_broadcast_started, K_FOREVER); + k_sem_take(&sem_broadcast_stream_started, K_FOREVER); } + WAIT_FOR_FLAG(flag_source_started); + /* Initialize sending */ for (size_t i = 0U; i < stream_count; i++) { struct audio_test_stream *test_stream = &broadcast_source_streams[i]; @@ -795,7 +826,7 @@ static int test_cap_initiator_ac(const struct cap_initiator_ac_param *param) test_stream->tx_active = true; for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { - broadcast_sent_cb(bap_stream_from_audio_test_stream(test_stream)); + broadcast_stream_sent_cb(bap_stream_from_audio_test_stream(test_stream)); } }