Skip to content

Commit ab9ee08

Browse files
Thalleykartben
authored andcommitted
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 <[email protected]>
1 parent e8bcb29 commit ab9ee08

File tree

10 files changed

+416
-45
lines changed

10 files changed

+416
-45
lines changed

include/zephyr/bluetooth/audio/bap.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,53 @@ int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgrou
20012001
* @{
20022002
*/
20032003

2004+
/**
2005+
* @brief Struct to hold the Broadcast Source callbacks
2006+
*
2007+
* These can be registered for usage with bt_bap_broadcast_source_register_cb().
2008+
*/
2009+
struct bt_bap_broadcast_source_cb {
2010+
/**
2011+
* @brief The Broadcast Source has started and all of the streams are ready for audio data
2012+
*
2013+
* @param source The started Broadcast Source
2014+
*/
2015+
void (*started)(struct bt_bap_broadcast_source *source);
2016+
2017+
/**
2018+
* @brief The Broadcast Source has stopped and none of the streams are ready for audio data
2019+
*
2020+
* @param source The stopped Broadcast Source
2021+
* @param reason The reason why the Broadcast Source stopped (see the BT_HCI_ERR_* values)
2022+
*/
2023+
void (*stopped)(struct bt_bap_broadcast_source *source, uint8_t reason);
2024+
2025+
/** @internal Internally used field for list handling */
2026+
sys_snode_t _node;
2027+
};
2028+
2029+
/**
2030+
* @brief Registers callbacks for Broadcast Sources
2031+
*
2032+
* @param cb Pointer to the callback structure.
2033+
*
2034+
* @retval 0 on success
2035+
* @retval -EINVAL if @p cb is NULL
2036+
* @retval -EEXIST if @p cb is already registered
2037+
*/
2038+
int bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb *cb);
2039+
2040+
/**
2041+
* @brief Unregisters callbacks for Broadcast Sources
2042+
*
2043+
* @param cb Pointer to the callback structure.
2044+
*
2045+
* @retval 0 on success
2046+
* @retval -EINVAL if @p cb is NULL
2047+
* @retval -ENOENT if @p cb is not registered
2048+
*/
2049+
int bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb *cb);
2050+
20042051
/** Broadcast Source stream parameters */
20052052
struct bt_bap_broadcast_source_stream_param {
20062053
/** Audio stream */

subsys/bluetooth/audio/bap_broadcast_source.c

Lines changed: 113 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* Bluetooth Audio Broadcast Source */
22

33
/*
4-
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
4+
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
55
*
66
* SPDX-License-Identifier: Apache-2.0
77
*/
@@ -25,6 +25,7 @@
2525
#include <zephyr/kernel.h>
2626
#include <zephyr/logging/log.h>
2727
#include <zephyr/net_buf.h>
28+
#include <zephyr/sys/__assert.h>
2829
#include <zephyr/sys/byteorder.h>
2930
#include <zephyr/sys/check.h>
3031
#include <zephyr/sys/slist.h>
@@ -55,6 +56,7 @@ static struct bt_bap_broadcast_subgroup
5556
broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
5657
[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
5758
static struct bt_bap_broadcast_source broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
59+
static sys_slist_t bap_broadcast_source_cbs = SYS_SLIST_STATIC_INIT(&bap_broadcast_source_cbs);
5860

5961
/**
6062
* 2 octets UUID
@@ -238,9 +240,9 @@ static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t
238240
}
239241

240242
static struct bt_iso_chan_ops broadcast_source_iso_ops = {
241-
.sent = broadcast_source_iso_sent,
242-
.connected = broadcast_source_iso_connected,
243-
.disconnected = broadcast_source_iso_disconnected,
243+
.sent = broadcast_source_iso_sent,
244+
.connected = broadcast_source_iso_connected,
245+
.disconnected = broadcast_source_iso_disconnected,
244246
};
245247

246248
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
440442
*/
441443
streams_encoded = 0;
442444
SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
443-
if (!encode_base_subgroup(subgroup,
444-
&source->stream_data[streams_encoded],
445+
if (!encode_base_subgroup(subgroup, &source->stream_data[streams_encoded],
445446
&streams_encoded, buf)) {
446447
return false;
447448
}
@@ -454,21 +455,18 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
454455
{
455456
struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup;
456457

457-
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup,
458-
next_subgroup, _node) {
458+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, next_subgroup, _node) {
459459
struct bt_bap_stream *stream, *next_stream;
460460

461-
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream,
462-
next_stream, _node) {
461+
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, next_stream, _node) {
463462
bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
464463
stream->ep->stream = NULL;
465464
stream->ep = NULL;
466465
stream->codec_cfg = NULL;
467466
stream->qos = NULL;
468467
stream->group = NULL;
469468

470-
sys_slist_remove(&subgroup->streams, NULL,
471-
&stream->_node);
469+
sys_slist_remove(&subgroup->streams, NULL, &stream->_node);
472470
}
473471
sys_slist_remove(&source->subgroups, NULL, &subgroup->_node);
474472
}
@@ -777,8 +775,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
777775
bis_count++;
778776
}
779777

780-
err = broadcast_source_setup_stream(index, stream,
781-
codec_cfg, qos, source);
778+
err = broadcast_source_setup_stream(index, stream, codec_cfg, qos, source);
782779
if (err != 0) {
783780
LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
784781
broadcast_source_cleanup(source);
@@ -1039,7 +1036,7 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour
10391036
int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv)
10401037
{
10411038
struct bt_iso_chan *bis[BROADCAST_STREAM_CNT];
1042-
struct bt_iso_big_create_param param = { 0 };
1039+
struct bt_iso_big_create_param param = {0};
10431040
struct bt_bap_broadcast_subgroup *subgroup;
10441041
enum bt_bap_ep_state broadcast_state;
10451042
struct bt_bap_stream *stream;
@@ -1078,8 +1075,7 @@ int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct
10781075
param.latency = source->qos->latency;
10791076
param.encryption = source->encryption;
10801077
if (param.encryption) {
1081-
(void)memcpy(param.bcode, source->broadcast_code,
1082-
sizeof(param.bcode));
1078+
(void)memcpy(param.bcode, source->broadcast_code, sizeof(param.bcode));
10831079
}
10841080
#if defined(CONFIG_BT_ISO_TEST_PARAMS)
10851081
param.irc = source->irc;
@@ -1125,14 +1121,12 @@ int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source)
11251121
return -EALREADY;
11261122
}
11271123

1128-
err = bt_iso_big_terminate(source->big);
1124+
err = bt_iso_big_terminate(source->big);
11291125
if (err) {
11301126
LOG_DBG("Failed to terminate BIG (err %d)", err);
11311127
return err;
11321128
}
11331129

1134-
source->big = NULL;
1135-
11361130
return 0;
11371131
}
11381132

@@ -1188,3 +1182,102 @@ int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,
11881182

11891183
return 0;
11901184
}
1185+
1186+
static struct bt_bap_broadcast_source *get_broadcast_source_by_big(const struct bt_iso_big *big)
1187+
{
1188+
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources); i++) {
1189+
if (broadcast_sources[i].big == big) {
1190+
return &broadcast_sources[i];
1191+
}
1192+
}
1193+
1194+
return NULL;
1195+
}
1196+
1197+
static void big_started_cb(struct bt_iso_big *big)
1198+
{
1199+
struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big);
1200+
struct bt_bap_broadcast_source_cb *listener;
1201+
1202+
if (source == NULL) {
1203+
/* Not one of ours */
1204+
return;
1205+
}
1206+
1207+
SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) {
1208+
if (listener->started != NULL) {
1209+
listener->started(source);
1210+
}
1211+
}
1212+
}
1213+
1214+
static void big_stopped_cb(struct bt_iso_big *big, uint8_t reason)
1215+
{
1216+
struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big);
1217+
struct bt_bap_broadcast_source_cb *listener;
1218+
1219+
if (source == NULL) {
1220+
/* Not one of ours */
1221+
return;
1222+
}
1223+
1224+
source->big = NULL;
1225+
1226+
SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) {
1227+
if (listener->stopped != NULL) {
1228+
listener->stopped(source, reason);
1229+
}
1230+
}
1231+
}
1232+
1233+
int bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb *cb)
1234+
{
1235+
static bool iso_big_cb_registered;
1236+
1237+
CHECKIF(cb == NULL) {
1238+
LOG_DBG("cb is NULL");
1239+
1240+
return -EINVAL;
1241+
}
1242+
1243+
if (sys_slist_find(&bap_broadcast_source_cbs, &cb->_node, NULL)) {
1244+
LOG_DBG("cb %p is already registered", cb);
1245+
1246+
return -EEXIST;
1247+
}
1248+
1249+
if (!iso_big_cb_registered) {
1250+
static struct bt_iso_big_cb big_cb = {
1251+
.started = big_started_cb,
1252+
.stopped = big_stopped_cb,
1253+
};
1254+
const int err = bt_iso_big_register_cb(&big_cb);
1255+
1256+
if (err != 0) {
1257+
__ASSERT(false, "Failed to register ISO BIG callbacks: %d", err);
1258+
}
1259+
1260+
iso_big_cb_registered = true;
1261+
}
1262+
1263+
sys_slist_append(&bap_broadcast_source_cbs, &cb->_node);
1264+
1265+
return 0;
1266+
}
1267+
1268+
int bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb *cb)
1269+
{
1270+
CHECKIF(cb == NULL) {
1271+
LOG_DBG("cb is NULL");
1272+
1273+
return -EINVAL;
1274+
}
1275+
1276+
if (!sys_slist_find_and_remove(&bap_broadcast_source_cbs, &cb->_node)) {
1277+
LOG_DBG("cb %p is not registered", cb);
1278+
1279+
return -ENOENT;
1280+
}
1281+
1282+
return 0;
1283+
}

tests/bluetooth/audio/bap_broadcast_source/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ target_include_directories(testbinary PRIVATE include)
1515
target_sources(testbinary
1616
PRIVATE
1717
src/main.c
18+
src/test_callback_register.c
1819
)

tests/bluetooth/audio/bap_broadcast_source/src/main.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,41 @@
11
/* main.c - Application main entry point */
22

33
/*
4-
* Copyright (c) 2023 Nordic Semiconductor ASA
4+
* Copyright (c) 2023-2024 Nordic Semiconductor ASA
55
*
66
* SPDX-License-Identifier: Apache-2.0
77
*/
88

9+
#include <errno.h>
10+
#include <stdint.h>
911
#include <stdlib.h>
1012
#include <string.h>
1113

1214
#include <zephyr/bluetooth/audio/audio.h>
1315
#include <zephyr/bluetooth/audio/bap.h>
16+
#include <zephyr/bluetooth/audio/lc3.h>
17+
#include <zephyr/bluetooth/byteorder.h>
18+
#include <zephyr/bluetooth/hci_types.h>
1419
#include <zephyr/bluetooth/iso.h>
1520
#include <zephyr/fff.h>
1621
#include <zephyr/kernel.h>
22+
#include <zephyr/net/buf.h>
23+
#include <zephyr/sys/printk.h>
1724
#include <zephyr/sys/util_macro.h>
1825

19-
#include "bluetooth.h"
26+
#include "bap_broadcast_source.h"
27+
#include "bap_stream.h"
2028
#include "bap_stream_expects.h"
29+
#include "bluetooth.h"
30+
#include "expects_util.h"
31+
#include "ztest_assert.h"
32+
#include "ztest_test.h"
2133

2234
DEFINE_FFF_GLOBALS;
2335

2436
static void mock_init_rule_before(const struct ztest_unit_test *test, void *fixture)
2537
{
38+
mock_bap_broadcast_source_init();
2639
mock_bap_stream_init();
2740
}
2841

@@ -136,8 +149,13 @@ static void *bap_broadcast_source_test_suite_setup(void)
136149

137150
static void bap_broadcast_source_test_suite_before(void *f)
138151
{
152+
int err;
153+
139154
memset(f, 0, sizeof(struct bap_broadcast_source_test_suite_fixture));
140155
bap_broadcast_source_test_suite_fixture_init(f);
156+
157+
err = bt_bap_broadcast_source_register_cb(&mock_bap_broadcast_source_cb);
158+
zassert_equal(0, err, "Unexpected return value %d", err);
141159
}
142160

143161
static void bap_broadcast_source_test_suite_after(void *f)
@@ -164,6 +182,8 @@ static void bap_broadcast_source_test_suite_after(void *f)
164182
free(param->params);
165183
free(param->qos);
166184
free(param);
185+
186+
bt_bap_broadcast_source_unregister_cb(&mock_bap_broadcast_source_cb);
167187
}
168188

169189
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
224244
mock_bap_stream_connected_cb_fake.call_count);
225245
zexpect_call_count("bt_bap_stream_ops.started", fixture->stream_cnt,
226246
mock_bap_stream_started_cb_fake.call_count);
247+
zexpect_call_count("bt_bap_broadcast_source_cb.started", 1,
248+
mock_bap_broadcast_source_started_cb_fake.call_count);
227249

228250
for (size_t i = 0U; i < create_param->params_count; i++) {
229251
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
260282
mock_bap_stream_disconnected_cb_fake.call_count);
261283
zexpect_call_count("bt_bap_stream_ops.stopped", fixture->stream_cnt,
262284
mock_bap_stream_stopped_cb_fake.call_count);
285+
zexpect_call_count("bt_bap_broadcast_source_cb.stopped", 1,
286+
mock_bap_broadcast_source_stopped_cb_fake.call_count);
263287

264288
err = bt_bap_broadcast_source_delete(fixture->source);
265289
zassert_equal(0, err, "Unable to delete broadcast source: err %d", err);

0 commit comments

Comments
 (0)