1 /* Bluetooth Audio Broadcast Source */
2
3 /*
4 * Copyright (c) 2021-2025 Nordic Semiconductor ASA
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <string.h>
14
15 #include <zephyr/autoconf.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/crypto.h>
19 #include <zephyr/bluetooth/gatt.h>
20 #include <zephyr/bluetooth/audio/audio.h>
21 #include <zephyr/bluetooth/audio/bap.h>
22 #include <zephyr/bluetooth/hci_types.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/bluetooth/uuid.h>
25 #include <zephyr/kernel.h>
26 #include <zephyr/logging/log.h>
27 #include <zephyr/net_buf.h>
28 #include <zephyr/sys/__assert.h>
29 #include <zephyr/sys/byteorder.h>
30 #include <zephyr/sys/check.h>
31 #include <zephyr/sys/slist.h>
32 #include <zephyr/sys/util.h>
33 #include <zephyr/sys/util_macro.h>
34
35 LOG_MODULE_REGISTER(bt_bap_broadcast_source, CONFIG_BT_BAP_BROADCAST_SOURCE_LOG_LEVEL);
36
37 #include "audio_internal.h"
38 #include "bap_iso.h"
39 #include "bap_endpoint.h"
40 #include "bap_stream.h"
41
42 struct bt_bap_broadcast_subgroup {
43 /* The streams used to create the broadcast source */
44 sys_slist_t streams;
45
46 /* The codec of the subgroup */
47 struct bt_audio_codec_cfg *codec_cfg;
48
49 /* List node */
50 sys_snode_t _node;
51 };
52
53 static struct bt_bap_ep broadcast_source_eps[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
54 [BROADCAST_STREAM_CNT];
55 static struct bt_bap_broadcast_subgroup
56 broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
57 [CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
58 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);
60
61 /**
62 * 2 octets UUID
63 * 3 octets presentation delay
64 * 1 octet number of subgroups
65 *
66 * Each subgroup then has
67 * 1 octet of number of BIS
68 * 5 octets of Codec_ID
69 * 1 octet codec specific configuration len
70 * 0-n octets of codec specific configuration
71 * 1 octet metadata len
72 * 0-n octets of metadata
73 *
74 * For each BIS in the subgroup there is
75 * 1 octet for the BIS index
76 * 1 octet codec specific configuration len
77 * 0-n octets of codec specific configuration
78 *
79 * For a minimal BASE with 1 subgroup and 1 BIS without and other data the
80 * total comes to 16
81 */
82 #define MINIMUM_BASE_SIZE 16
83
broadcast_source_set_ep_state(struct bt_bap_ep * ep,uint8_t state)84 static void broadcast_source_set_ep_state(struct bt_bap_ep *ep, uint8_t state)
85 {
86 uint8_t old_state;
87
88 old_state = ep->status.state;
89
90 LOG_DBG("ep %p id 0x%02x %s -> %s", ep, ep->status.id, bt_bap_ep_state_str(old_state),
91 bt_bap_ep_state_str(state));
92
93 switch (old_state) {
94 case BT_BAP_EP_STATE_IDLE:
95 if (state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
96 LOG_DBG("Invalid broadcast sync endpoint state transition");
97 return;
98 }
99 break;
100 case BT_BAP_EP_STATE_QOS_CONFIGURED:
101 if (state != BT_BAP_EP_STATE_IDLE && state != BT_BAP_EP_STATE_ENABLING) {
102 LOG_DBG("Invalid broadcast sync endpoint state transition");
103 return;
104 }
105 break;
106 case BT_BAP_EP_STATE_ENABLING:
107 if (state != BT_BAP_EP_STATE_STREAMING && state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
108 LOG_DBG("Invalid broadcast sync endpoint state transition");
109 return;
110 }
111 break;
112 case BT_BAP_EP_STATE_STREAMING:
113 if (state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
114 LOG_DBG("Invalid broadcast sync endpoint state transition");
115 return;
116 }
117 break;
118 default:
119 LOG_ERR("Invalid broadcast sync endpoint state: %s",
120 bt_bap_ep_state_str(old_state));
121 return;
122 }
123
124 ep->status.state = state;
125 }
126
broadcast_source_set_state(struct bt_bap_broadcast_source * source,uint8_t state)127 static void broadcast_source_set_state(struct bt_bap_broadcast_source *source, uint8_t state)
128 {
129 struct bt_bap_broadcast_subgroup *subgroup;
130
131 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
132 struct bt_bap_stream *stream;
133
134 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
135 broadcast_source_set_ep_state(stream->ep, state);
136 }
137 }
138 }
139
broadcast_source_iso_sent(struct bt_iso_chan * chan)140 static void broadcast_source_iso_sent(struct bt_iso_chan *chan)
141 {
142 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
143 const struct bt_bap_stream_ops *ops;
144 struct bt_bap_stream *stream;
145 struct bt_bap_ep *ep = iso->tx.ep;
146
147 if (ep == NULL) {
148 LOG_ERR("iso %p not bound with ep", chan);
149 return;
150 }
151
152 stream = ep->stream;
153 if (stream == NULL) {
154 LOG_ERR("No stream for ep %p", ep);
155 return;
156 }
157
158 ops = stream->ops;
159
160 if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) {
161 LOG_DBG("stream %p ep %p", stream, stream->ep);
162 }
163
164 if (ops != NULL && ops->sent != NULL) {
165 ops->sent(stream);
166 }
167 }
168
broadcast_source_iso_connected(struct bt_iso_chan * chan)169 static void broadcast_source_iso_connected(struct bt_iso_chan *chan)
170 {
171 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
172 const struct bt_bap_stream_ops *ops;
173 struct bt_bap_stream *stream;
174 struct bt_bap_ep *ep = iso->tx.ep;
175
176 if (ep == NULL) {
177 LOG_ERR("iso %p not bound with ep", chan);
178 return;
179 }
180
181 stream = ep->stream;
182 if (stream == NULL) {
183 LOG_ERR("No stream for ep %p", ep);
184 return;
185 }
186
187 LOG_DBG("stream %p ep %p", stream, ep);
188
189 #if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM)
190 /* reset sequence number */
191 stream->_prev_seq_num = 0U;
192 #endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */
193
194 /* Setup the ISO data path */
195 bt_bap_setup_iso_data_path(stream);
196
197 ops = stream->ops;
198 if (ops != NULL && ops->connected != NULL) {
199 ops->connected(stream);
200 }
201
202 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING);
203
204 if (ops != NULL && ops->started != NULL) {
205 ops->started(stream);
206 }
207 }
208
broadcast_source_iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)209 static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
210 {
211 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
212 const struct bt_bap_stream_ops *ops;
213 struct bt_bap_stream *stream;
214 struct bt_bap_ep *ep = iso->tx.ep;
215
216 if (ep == NULL) {
217 LOG_ERR("iso %p not bound with ep", chan);
218 return;
219 }
220
221 stream = ep->stream;
222 if (stream == NULL) {
223 LOG_ERR("No stream for ep %p", ep);
224 return;
225 }
226
227 LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason);
228
229 ops = stream->ops;
230 if (ops != NULL && ops->disconnected != NULL) {
231 ops->disconnected(stream, reason);
232 }
233
234 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED);
235
236 if (ops != NULL && ops->stopped != NULL) {
237 ops->stopped(stream, reason);
238 }
239 }
240
241 static struct bt_iso_chan_ops broadcast_source_iso_ops = {
242 .sent = broadcast_source_iso_sent,
243 .connected = broadcast_source_iso_connected,
244 .disconnected = broadcast_source_iso_disconnected,
245 };
246
bt_bap_ep_is_broadcast_src(const struct bt_bap_ep * ep)247 bool bt_bap_ep_is_broadcast_src(const struct bt_bap_ep *ep)
248 {
249 for (int i = 0; i < ARRAY_SIZE(broadcast_source_eps); i++) {
250 if (PART_OF_ARRAY(broadcast_source_eps[i], ep)) {
251 return true;
252 }
253 }
254
255 return false;
256 }
257
broadcast_source_ep_init(struct bt_bap_ep * ep)258 static void broadcast_source_ep_init(struct bt_bap_ep *ep)
259 {
260 LOG_DBG("ep %p", ep);
261
262 (void)memset(ep, 0, sizeof(*ep));
263 ep->dir = BT_AUDIO_DIR_SOURCE;
264 ep->iso = NULL;
265 }
266
broadcast_source_new_ep(uint8_t index)267 static struct bt_bap_ep *broadcast_source_new_ep(uint8_t index)
268 {
269 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_eps[index]); i++) {
270 struct bt_bap_ep *ep = &broadcast_source_eps[index][i];
271
272 /* If ep->stream is NULL the endpoint is unallocated */
273 if (ep->stream == NULL) {
274 broadcast_source_ep_init(ep);
275 return ep;
276 }
277 }
278
279 return NULL;
280 }
281
broadcast_source_new_subgroup(uint8_t index)282 static struct bt_bap_broadcast_subgroup *broadcast_source_new_subgroup(uint8_t index)
283 {
284 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_subgroups[index]); i++) {
285 struct bt_bap_broadcast_subgroup *subgroup = &broadcast_source_subgroups[index][i];
286
287 if (sys_slist_is_empty(&subgroup->streams)) {
288 return subgroup;
289 }
290 }
291
292 return NULL;
293 }
294
broadcast_source_setup_stream(uint8_t index,struct bt_bap_stream * stream,struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_qos_cfg * qos,struct bt_bap_broadcast_source * source)295 static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *stream,
296 struct bt_audio_codec_cfg *codec_cfg,
297 struct bt_bap_qos_cfg *qos,
298 struct bt_bap_broadcast_source *source)
299 {
300 struct bt_bap_iso *iso;
301 struct bt_bap_ep *ep;
302
303 ep = broadcast_source_new_ep(index);
304 if (ep == NULL) {
305 LOG_DBG("Could not allocate new broadcast endpoint");
306 return -ENOMEM;
307 }
308
309 iso = bt_bap_iso_new();
310 if (iso == NULL) {
311 LOG_DBG("Could not allocate iso");
312 return -ENOMEM;
313 }
314
315 bt_bap_iso_init(iso, &broadcast_source_iso_ops);
316 bt_bap_iso_bind_ep(iso, ep);
317 stream->iso = &iso->chan;
318
319 bt_bap_qos_cfg_to_iso_qos(iso->chan.qos->tx, qos);
320
321 #if defined(CONFIG_BT_ISO_TEST_PARAMS)
322 iso->chan.qos->num_subevents = qos->num_subevents;
323 #endif /* CONFIG_BT_ISO_TEST_PARAMS */
324
325 bt_bap_iso_unref(iso);
326
327 bt_bap_stream_attach(NULL, stream, ep, codec_cfg);
328 stream->qos = qos;
329 stream->group = source;
330 ep->broadcast_source = source;
331
332 return 0;
333 }
334
encode_base_subgroup(struct bt_bap_broadcast_subgroup * subgroup,struct bt_audio_broadcast_stream_data * stream_data,uint8_t * streams_encoded,struct net_buf_simple * buf)335 static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
336 struct bt_audio_broadcast_stream_data *stream_data,
337 uint8_t *streams_encoded, struct net_buf_simple *buf)
338 {
339 struct bt_bap_stream *stream;
340 const struct bt_audio_codec_cfg *codec_cfg;
341 uint8_t stream_count;
342 uint8_t len;
343
344 stream_count = 0;
345 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
346 stream_count++;
347 }
348
349 codec_cfg = subgroup->codec_cfg;
350
351 net_buf_simple_add_u8(buf, stream_count);
352 net_buf_simple_add_u8(buf, codec_cfg->id);
353 net_buf_simple_add_le16(buf, codec_cfg->cid);
354 net_buf_simple_add_le16(buf, codec_cfg->vid);
355
356 net_buf_simple_add_u8(buf, codec_cfg->data_len);
357 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
358 if ((buf->size - buf->len) < codec_cfg->data_len) {
359 LOG_DBG("No room for config data: %zu", codec_cfg->data_len);
360
361 return false;
362 }
363 net_buf_simple_add_mem(buf, codec_cfg->data, codec_cfg->data_len);
364 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
365
366 if ((buf->size - buf->len) < sizeof(len)) {
367 LOG_DBG("No room for metadata length");
368
369 return false;
370 }
371
372 net_buf_simple_add_u8(buf, codec_cfg->meta_len);
373
374 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
375 if ((buf->size - buf->len) < codec_cfg->meta_len) {
376 LOG_DBG("No room for metadata data: %zu", codec_cfg->meta_len);
377
378 return false;
379 }
380
381 net_buf_simple_add_mem(buf, codec_cfg->meta, codec_cfg->meta_len);
382 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
383
384 /* Create BIS index bitfield */
385 for (uint8_t i = 0U; i < stream_count; i++) {
386 /* Set the bis_index to *streams_encoded plus 1 as the indexes start from 1 */
387 const uint8_t bis_index = *streams_encoded + 1;
388
389 if ((buf->size - buf->len) < (sizeof(bis_index) + sizeof(uint8_t))) {
390 LOG_DBG("No room for BIS[%d] index", i);
391
392 return false;
393 }
394
395 net_buf_simple_add_u8(buf, bis_index);
396
397 if ((buf->size - buf->len) < sizeof(len)) {
398 LOG_DBG("No room for bis codec config length");
399
400 return false;
401 }
402
403 net_buf_simple_add_u8(buf, stream_data[i].data_len);
404 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
405 if ((buf->size - buf->len) < stream_data[i].data_len) {
406 LOG_DBG("No room for BIS[%u] data: %zu", i, stream_data[i].data_len);
407
408 return false;
409 }
410
411 net_buf_simple_add_mem(buf, stream_data[i].data, stream_data[i].data_len);
412 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
413
414 (*streams_encoded)++;
415 }
416
417 return true;
418 }
419
encode_base(struct bt_bap_broadcast_source * source,struct net_buf_simple * buf)420 static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_simple *buf)
421 {
422 struct bt_bap_broadcast_subgroup *subgroup;
423 uint8_t streams_encoded;
424 uint8_t subgroup_count;
425
426 /* 13 is the size of the fixed size values following this check */
427 if ((buf->size - buf->len) < MINIMUM_BASE_SIZE) {
428 return false;
429 }
430
431 subgroup_count = 0U;
432 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
433 subgroup_count++;
434 }
435
436 net_buf_simple_add_le16(buf, BT_UUID_BASIC_AUDIO_VAL);
437
438 net_buf_simple_add_le24(buf, source->qos->pd);
439 net_buf_simple_add_u8(buf, subgroup_count);
440
441 /* Since the `stream_data` is only stored in the broadcast source,
442 * we need to provide that information when encoding each subgroup
443 */
444 streams_encoded = 0;
445 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
446 if (!encode_base_subgroup(subgroup, &source->stream_data[streams_encoded],
447 &streams_encoded, buf)) {
448 return false;
449 }
450 }
451
452 return true;
453 }
454
broadcast_source_cleanup(struct bt_bap_broadcast_source * source)455 static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
456 {
457 struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup;
458
459 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, next_subgroup, _node) {
460 struct bt_bap_stream *stream, *next_stream;
461
462 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, next_stream, _node) {
463 bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
464 stream->iso = NULL;
465 stream->ep->stream = NULL;
466 stream->ep->broadcast_source = NULL;
467 stream->ep = NULL;
468 stream->codec_cfg = NULL;
469 stream->qos = NULL;
470 stream->group = NULL;
471
472 sys_slist_remove(&subgroup->streams, NULL, &stream->_node);
473 }
474 sys_slist_remove(&source->subgroups, NULL, &subgroup->_node);
475 }
476
477 (void)memset(source, 0, sizeof(*source));
478 }
479
valid_broadcast_source_param(const struct bt_bap_broadcast_source_param * param,const struct bt_bap_broadcast_source * source)480 static bool valid_broadcast_source_param(const struct bt_bap_broadcast_source_param *param,
481 const struct bt_bap_broadcast_source *source)
482 {
483 const struct bt_bap_qos_cfg *qos;
484
485 CHECKIF(param == NULL) {
486 LOG_DBG("param is NULL");
487 return false;
488 }
489
490 CHECKIF(!IN_RANGE(param->params_count, 1U, CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT)) {
491 LOG_DBG("param->params_count %zu is invalid", param->params_count);
492 return false;
493 }
494
495 CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL &&
496 param->packing != BT_ISO_PACKING_INTERLEAVED) {
497 LOG_DBG("param->packing %u is invalid", param->packing);
498 return false;
499 }
500
501 qos = param->qos;
502 CHECKIF(qos == NULL) {
503 LOG_DBG("param->qos is NULL");
504 return false;
505 }
506
507 CHECKIF(bt_audio_verify_qos(qos) != BT_BAP_ASCS_REASON_NONE) {
508 LOG_DBG("param->qos is invalid");
509 return false;
510 }
511
512 CHECKIF(param->qos->rtn > BT_ISO_BROADCAST_RTN_MAX) {
513 LOG_DBG("param->qos->rtn %u invalid", param->qos->rtn);
514 return false;
515 }
516
517 CHECKIF(param->params == NULL) {
518 LOG_DBG("param->params is NULL");
519 return false;
520 }
521
522 CHECKIF(param->params_count == 0) {
523 LOG_DBG("param->params_count is 0");
524 return false;
525 }
526
527 for (size_t i = 0U; i < param->params_count; i++) {
528 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
529
530 subgroup_param = ¶m->params[i];
531
532 CHECKIF(subgroup_param->params == NULL) {
533 LOG_DBG("subgroup_params[%zu].params is NULL", i);
534 return false;
535 }
536
537 CHECKIF(!IN_RANGE(subgroup_param->params_count, 1U,
538 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)) {
539 LOG_DBG("subgroup_params[%zu].count (%zu) is invalid", i,
540 subgroup_param->params_count);
541 return false;
542 }
543
544 CHECKIF(!bt_audio_valid_codec_cfg(subgroup_param->codec_cfg)) {
545 LOG_DBG("subgroup_params[%zu].codec_cfg is invalid", i);
546 return false;
547 }
548
549 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
550 const struct bt_bap_broadcast_source_stream_param *stream_param;
551
552 stream_param = &subgroup_param->params[j];
553
554 CHECKIF(stream_param->stream == NULL) {
555 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is NULL",
556 i, j);
557 return false;
558 }
559
560 CHECKIF(stream_param->stream->group != NULL &&
561 stream_param->stream->group != source) {
562 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is "
563 "already part of group %p",
564 i, j, stream_param->stream->group);
565 return false;
566 }
567
568 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
569 CHECKIF(stream_param->data == NULL && stream_param->data_len != 0) {
570 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data is "
571 "NULL with len %zu",
572 i, j, stream_param->data_len);
573 return false;
574 }
575
576 CHECKIF(stream_param->data_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
577 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data_len too "
578 "large: %zu > %d",
579 i, j, stream_param->data_len,
580 CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE);
581 return false;
582 }
583
584 CHECKIF(stream_param->data != NULL &&
585 subgroup_param->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3 &&
586 !bt_audio_valid_ltv(stream_param->data, stream_param->data_len)) {
587 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data not valid "
588 "LTV",
589 i, j);
590 return false;
591 }
592 }
593 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
594 }
595
596 return true;
597 }
598
599 /** Gets the "highest" state of all BIS in the broadcast source */
broadcast_source_get_state(struct bt_bap_broadcast_source * source)600 static enum bt_bap_ep_state broadcast_source_get_state(struct bt_bap_broadcast_source *source)
601 {
602 enum bt_bap_ep_state state = BT_BAP_EP_STATE_IDLE;
603 struct bt_bap_broadcast_subgroup *subgroup;
604
605 if (source == NULL) {
606 LOG_DBG("source is NULL");
607 return state;
608 }
609
610 if (sys_slist_is_empty(&source->subgroups)) {
611 LOG_DBG("Source does not have any streams");
612 return state;
613 }
614
615 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
616 struct bt_bap_stream *stream;
617
618 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
619 if (stream->ep != NULL) {
620 state = MAX(state, stream->ep->status.state);
621 }
622 }
623 }
624
625 return state;
626 }
627
merge_bis_and_subgroup_data_cb(struct bt_data * data,void * user_data)628 static bool merge_bis_and_subgroup_data_cb(struct bt_data *data, void *user_data)
629 {
630 struct bt_audio_codec_cfg *codec_cfg = user_data;
631 int err;
632
633 err = bt_audio_codec_cfg_set_val(codec_cfg, data->type, data->data, data->data_len);
634 if (err < 0) {
635 LOG_DBG("Failed to set type %u with len %u in codec_cfg: %d", data->type,
636 data->data_len, err);
637
638 return false;
639 }
640
641 return true;
642 }
643
update_codec_cfg_data(struct bt_audio_codec_cfg * codec_cfg,const struct bt_bap_broadcast_source_stream_param * stream_param)644 static int update_codec_cfg_data(struct bt_audio_codec_cfg *codec_cfg,
645 const struct bt_bap_broadcast_source_stream_param *stream_param)
646 {
647 if (stream_param->data_len > 0) {
648 int err;
649
650 /* Merge subgroup codec configuration with the BIS configuration
651 * As per the BAP spec, if a value exist at level 2 (subgroup) and 3 (BIS), then it
652 * is the value at level 3 that shall be used
653 */
654 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
655 err = bt_audio_data_parse(stream_param->data, stream_param->data_len,
656 merge_bis_and_subgroup_data_cb, codec_cfg);
657 if (err != 0) {
658 LOG_DBG("Could not merge BIS and subgroup config in codec_cfg: %d",
659 err);
660
661 return -EINVAL;
662 }
663 } else {
664 /* If it is not LC3, then we don't know how to merge the subgroup and BIS
665 * codecs, so we just append them
666 */
667 if (codec_cfg->data_len + stream_param->data_len >
668 sizeof(codec_cfg->data)) {
669 LOG_DBG("Could not store BIS and subgroup config in codec_cfg (%u "
670 "> %u)",
671 codec_cfg->data_len + stream_param->data_len,
672 sizeof(codec_cfg->data));
673
674 return -ENOMEM;
675 }
676
677 memcpy(&codec_cfg->data[codec_cfg->data_len], stream_param->data,
678 stream_param->data_len);
679 codec_cfg->data_len += stream_param->data_len;
680 }
681 }
682
683 return 0;
684 }
685
bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param * param,struct bt_bap_broadcast_source ** out_source)686 int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
687 struct bt_bap_broadcast_source **out_source)
688 {
689 struct bt_bap_broadcast_source *source;
690 struct bt_bap_qos_cfg *qos;
691 size_t stream_count;
692 uint8_t index;
693 uint8_t bis_count;
694 int err;
695
696 CHECKIF(out_source == NULL) {
697 LOG_DBG("out_source is NULL");
698 return -EINVAL;
699 }
700
701 /* Set out_source to NULL until the source has actually been created */
702 *out_source = NULL;
703
704 if (!valid_broadcast_source_param(param, NULL)) {
705 LOG_DBG("Invalid parameters");
706 return -EINVAL;
707 }
708
709 source = NULL;
710 for (index = 0; index < ARRAY_SIZE(broadcast_sources); index++) {
711 if (sys_slist_is_empty(&broadcast_sources[index].subgroups)) { /* Find free entry */
712 source = &broadcast_sources[index];
713 break;
714 }
715 }
716
717 if (source == NULL) {
718 LOG_DBG("Could not allocate any more broadcast sources");
719 return -ENOMEM;
720 }
721
722 stream_count = 0U;
723 bis_count = 0U;
724 qos = param->qos;
725 /* Go through all subgroups and streams and setup each setup with an
726 * endpoint
727 */
728 for (size_t i = 0U; i < param->params_count; i++) {
729 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
730 struct bt_bap_broadcast_subgroup *subgroup;
731
732 subgroup_param = ¶m->params[i];
733
734 subgroup = broadcast_source_new_subgroup(index);
735 if (subgroup == NULL) {
736 LOG_DBG("Could not allocate new broadcast subgroup");
737 broadcast_source_cleanup(source);
738 return -ENOMEM;
739 }
740
741 subgroup->codec_cfg = subgroup_param->codec_cfg;
742 sys_slist_append(&source->subgroups, &subgroup->_node);
743
744 /* Check that we are not above the maximum BIS count */
745 if (subgroup_param->params_count + stream_count > BROADCAST_STREAM_CNT) {
746 LOG_DBG("Cannot create broadcaster with %zu streams", stream_count);
747 broadcast_source_cleanup(source);
748
749 return -ENOMEM;
750 }
751
752 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
753 const struct bt_bap_broadcast_source_stream_param *stream_param;
754 struct bt_bap_stream *stream;
755 struct bt_audio_codec_cfg *codec_cfg;
756
757 codec_cfg = subgroup_param->codec_cfg;
758 stream_param = &subgroup_param->params[j];
759 stream = stream_param->stream;
760
761 if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
762 if (bis_count >= BROADCAST_STREAM_CNT) {
763 LOG_DBG("Stream count %d exceeded", bis_count);
764 return -ENOMEM;
765 }
766
767 codec_cfg = &source->codec_cfg[bis_count];
768 memcpy(codec_cfg, subgroup_param->codec_cfg,
769 sizeof(struct bt_audio_codec_cfg));
770
771 err = update_codec_cfg_data(codec_cfg, stream_param);
772 if (err != 0) {
773 LOG_DBG("codec config update failed [%zu]: %d", i, err);
774 broadcast_source_cleanup(source);
775 return err;
776 }
777
778 bis_count++;
779 }
780
781 err = broadcast_source_setup_stream(index, stream, codec_cfg, qos, source);
782 if (err != 0) {
783 LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
784 broadcast_source_cleanup(source);
785 return err;
786 }
787
788 /* Store the BIS specific codec configuration data in
789 * the broadcast source. It is stored in the broadcast
790 * source, instead of the stream object, as this is
791 * only relevant for the broadcast source, and not used
792 * for unicast or broadcast sink.
793 */
794 (void)memcpy(source->stream_data[stream_count].data, stream_param->data,
795 stream_param->data_len * sizeof(*stream_param->data));
796 source->stream_data[stream_count].data_len = stream_param->data_len;
797
798 sys_slist_append(&subgroup->streams, &stream->_node);
799 stream_count++;
800 }
801 }
802
803 /* Finalize state changes and store information */
804 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
805 source->qos = qos;
806 source->packing = param->packing;
807 #if defined(CONFIG_BT_ISO_TEST_PARAMS)
808 source->irc = param->irc;
809 source->pto = param->pto;
810 source->iso_interval = param->iso_interval;
811 #endif /* CONFIG_BT_ISO_TEST_PARAMS */
812
813 source->encryption = param->encryption;
814 if (source->encryption) {
815 (void)memcpy(source->broadcast_code, param->broadcast_code,
816 sizeof(source->broadcast_code));
817 }
818
819 *out_source = source;
820
821 return 0;
822 }
823
bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source * source,struct bt_bap_broadcast_source_param * param)824 int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
825 struct bt_bap_broadcast_source_param *param)
826 {
827 struct bt_bap_broadcast_subgroup *subgroup;
828 enum bt_bap_ep_state broadcast_state;
829 struct bt_bap_qos_cfg *qos;
830 size_t subgroup_cnt;
831 uint8_t bis_count;
832
833 CHECKIF(source == NULL) {
834 LOG_DBG("source is NULL");
835 return -EINVAL;
836 }
837
838 if (!valid_broadcast_source_param(param, source)) {
839 LOG_DBG("Invalid parameters");
840 return -EINVAL;
841 }
842
843 broadcast_state = broadcast_source_get_state(source);
844 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
845 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
846 return -EBADMSG;
847 }
848
849 /* Verify that the parameter counts do not exceed existing number of subgroups and streams*/
850 subgroup_cnt = 0U;
851 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
852 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param =
853 ¶m->params[subgroup_cnt];
854 const size_t subgroup_stream_param_cnt = subgroup_param->params_count;
855 struct bt_bap_stream *stream;
856 size_t subgroup_stream_cnt = 0U;
857
858 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
859 subgroup_stream_cnt++;
860 }
861
862 /* Verify that the param stream is in the subgroup */
863 for (size_t i = 0U; i < subgroup_param->params_count; i++) {
864 struct bt_bap_stream *subgroup_stream;
865 struct bt_bap_stream *param_stream;
866 bool stream_in_subgroup = false;
867
868 param_stream = subgroup_param->params[i].stream;
869
870 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
871 if (subgroup_stream == param_stream) {
872 stream_in_subgroup = true;
873 break;
874 }
875 }
876
877 if (!stream_in_subgroup) {
878 LOG_DBG("Invalid param->params[%zu]->param[%zu].stream "
879 "not in subgroup",
880 subgroup_cnt, i);
881 return -EINVAL;
882 }
883 }
884
885 if (subgroup_stream_cnt < subgroup_stream_param_cnt) {
886 LOG_DBG("Invalid param->params[%zu]->params_count: %zu "
887 "(only %zu streams in subgroup)",
888 subgroup_cnt, subgroup_stream_param_cnt, subgroup_stream_cnt);
889 return -EINVAL;
890 }
891
892 subgroup_cnt++;
893 }
894
895 if (subgroup_cnt < param->params_count) {
896 LOG_DBG("Invalid param->params_count: %zu (only %zu subgroups in source)",
897 param->params_count, subgroup_cnt);
898 return -EINVAL;
899 }
900
901 qos = param->qos;
902 bis_count = 0U;
903 /* We update up to the first param->params_count subgroups */
904 for (size_t i = 0U; i < param->params_count; i++) {
905 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
906 struct bt_audio_codec_cfg *codec_cfg;
907 struct bt_bap_stream *stream;
908
909 if (i == 0) {
910 subgroup =
911 SYS_SLIST_PEEK_HEAD_CONTAINER(&source->subgroups, subgroup, _node);
912 } else {
913 subgroup = SYS_SLIST_PEEK_NEXT_CONTAINER(subgroup, _node);
914 }
915
916 subgroup_param = ¶m->params[i];
917 codec_cfg = subgroup_param->codec_cfg;
918 subgroup->codec_cfg = codec_cfg;
919
920 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
921 const struct bt_bap_broadcast_source_stream_param *stream_param;
922 struct bt_audio_broadcast_stream_data *stream_data;
923 struct bt_bap_stream *subgroup_stream;
924 size_t stream_idx;
925
926 stream_param = &subgroup_param->params[j];
927 stream = stream_param->stream;
928 if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
929 int err;
930
931 if (bis_count >= BROADCAST_STREAM_CNT) {
932 LOG_DBG("Stream count %d exceeded", bis_count);
933 return -ENOMEM;
934 }
935
936 codec_cfg = &source->codec_cfg[bis_count];
937 memcpy(codec_cfg, subgroup_param->codec_cfg,
938 sizeof(struct bt_audio_codec_cfg));
939
940 err = update_codec_cfg_data(codec_cfg, stream_param);
941 if (err != 0) {
942 LOG_DBG("codec config update failed [%zu]: %d", i, err);
943 return err;
944 }
945
946 bis_count++;
947 }
948
949 stream_idx = 0U;
950 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
951 if (subgroup_stream == stream) {
952 break;
953 }
954
955 stream_idx++;
956 }
957
958 /* Store the BIS specific codec configuration data in the broadcast source.
959 * It is stored in the broadcast* source, instead of the stream object,
960 * as this is only relevant for the broadcast source, and not used
961 * for unicast or broadcast sink.
962 */
963 stream_data = &source->stream_data[stream_idx];
964 (void)memcpy(stream_data->data, stream_param->data, stream_param->data_len);
965 stream_data->data_len = stream_param->data_len;
966 }
967
968 /* Apply the codec_cfg to all streams in the subgroup, and not just the ones in the
969 * params
970 */
971 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
972 bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg);
973 }
974 }
975
976 /* Finally we apply the new qos and to all streams */
977 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
978 struct bt_bap_stream *stream;
979
980 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
981 struct bt_iso_chan_io_qos *iso_qos;
982
983 iso_qos = stream->ep->iso->chan.qos->tx;
984 bt_bap_qos_cfg_to_iso_qos(iso_qos, qos);
985 stream->qos = qos;
986 }
987 }
988
989 source->qos = qos;
990
991 return 0;
992 }
993
bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source * source,const uint8_t meta[],size_t meta_len)994 int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
995 const uint8_t meta[], size_t meta_len)
996 {
997 struct bt_bap_broadcast_subgroup *subgroup;
998 enum bt_bap_ep_state broadcast_state;
999
1000 CHECKIF(source == NULL) {
1001 LOG_DBG("source is NULL");
1002
1003 return -EINVAL;
1004 }
1005
1006 CHECKIF((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) {
1007 LOG_DBG("Invalid metadata combination: %p %zu", meta, meta_len);
1008
1009 return -EINVAL;
1010 }
1011
1012 CHECKIF(meta_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
1013 LOG_DBG("Invalid meta_len: %zu (max %d)", meta_len,
1014 CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
1015
1016 return -EINVAL;
1017 }
1018
1019 broadcast_state = broadcast_source_get_state(source);
1020 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_STREAMING) {
1021 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1022
1023 return -EBADMSG;
1024 }
1025
1026 /* TODO: We should probably find a way to update the metadata
1027 * for each subgroup individually
1028 */
1029 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
1030 memset(subgroup->codec_cfg->meta, 0, sizeof(subgroup->codec_cfg->meta));
1031 memcpy(subgroup->codec_cfg->meta, meta, meta_len);
1032 subgroup->codec_cfg->meta_len = meta_len;
1033 }
1034
1035 return 0;
1036 }
1037
bt_bap_broadcast_source_start(struct bt_bap_broadcast_source * source,struct bt_le_ext_adv * adv)1038 int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv)
1039 {
1040 struct bt_iso_chan *bis[BROADCAST_STREAM_CNT];
1041 struct bt_iso_big_create_param param = {0};
1042 struct bt_bap_broadcast_subgroup *subgroup;
1043 enum bt_bap_ep_state broadcast_state;
1044 struct bt_bap_stream *stream;
1045 size_t bis_count;
1046 int err;
1047
1048 CHECKIF(source == NULL) {
1049 LOG_DBG("source is NULL");
1050 return -EINVAL;
1051 }
1052
1053 CHECKIF(adv == NULL) {
1054 LOG_DBG("adv is NULL");
1055 return -EINVAL;
1056 }
1057
1058 broadcast_state = broadcast_source_get_state(source);
1059 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
1060 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1061 return -EBADMSG;
1062 }
1063
1064 bis_count = 0;
1065 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
1066 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
1067 bis[bis_count++] = bt_bap_stream_iso_chan_get(stream);
1068 }
1069 }
1070
1071 /* Create BIG */
1072 param.num_bis = bis_count;
1073 param.bis_channels = bis;
1074 param.framing = source->qos->framing;
1075 param.packing = source->packing;
1076 param.interval = source->qos->interval;
1077 param.latency = source->qos->latency;
1078 param.encryption = source->encryption;
1079 if (param.encryption) {
1080 (void)memcpy(param.bcode, source->broadcast_code, sizeof(param.bcode));
1081 }
1082 #if defined(CONFIG_BT_ISO_TEST_PARAMS)
1083 param.irc = source->irc;
1084 param.pto = source->pto;
1085 param.iso_interval = source->iso_interval;
1086 #endif /* CONFIG_BT_ISO_TEST_PARAMS */
1087
1088 /* Set the enabling state early in case that the BIS is connected before we can manage to
1089 * set it afterwards
1090 */
1091 broadcast_source_set_state(source, BT_BAP_EP_STATE_ENABLING);
1092
1093 err = bt_iso_big_create(adv, ¶m, &source->big);
1094 if (err != 0) {
1095 LOG_DBG("Failed to create BIG: %d", err);
1096 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
1097
1098 return err;
1099 }
1100
1101 return 0;
1102 }
1103
bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source * source)1104 int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source)
1105 {
1106 enum bt_bap_ep_state broadcast_state;
1107 int err;
1108
1109 CHECKIF(source == NULL) {
1110 LOG_DBG("source is NULL");
1111 return -EINVAL;
1112 }
1113
1114 broadcast_state = broadcast_source_get_state(source);
1115 if (broadcast_state != BT_BAP_EP_STATE_STREAMING &&
1116 broadcast_state != BT_BAP_EP_STATE_ENABLING) {
1117 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1118 return -EBADMSG;
1119 }
1120
1121 if (source->big == NULL) {
1122 LOG_DBG("Source is not started");
1123 return -EALREADY;
1124 }
1125
1126 err = bt_iso_big_terminate(source->big);
1127 if (err) {
1128 LOG_DBG("Failed to terminate BIG (err %d)", err);
1129 return err;
1130 }
1131
1132 return 0;
1133 }
1134
bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source * source)1135 int bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source *source)
1136 {
1137 enum bt_bap_ep_state broadcast_state;
1138
1139 CHECKIF(source == NULL) {
1140 LOG_DBG("source is NULL");
1141 return -EINVAL;
1142 }
1143
1144 broadcast_state = broadcast_source_get_state(source);
1145 if (broadcast_state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
1146 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1147 return -EBADMSG;
1148 }
1149
1150 broadcast_source_set_state(source, BT_BAP_EP_STATE_IDLE);
1151
1152 /* Reset the broadcast source */
1153 broadcast_source_cleanup(source);
1154
1155 return 0;
1156 }
1157
bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source * source,struct net_buf_simple * base_buf)1158 int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,
1159 struct net_buf_simple *base_buf)
1160 {
1161 enum bt_bap_ep_state broadcast_state;
1162
1163 CHECKIF(source == NULL) {
1164 LOG_DBG("source is NULL");
1165 return -EINVAL;
1166 }
1167
1168 CHECKIF(base_buf == NULL) {
1169 LOG_DBG("base_buf is NULL");
1170 return -EINVAL;
1171 }
1172
1173 broadcast_state = broadcast_source_get_state(source);
1174 if (broadcast_state == BT_BAP_EP_STATE_IDLE) {
1175 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1176 return -EBADMSG;
1177 }
1178
1179 if (!encode_base(source, base_buf)) {
1180 LOG_DBG("base_buf %p with size %u not large enough", base_buf, base_buf->size);
1181
1182 return -EMSGSIZE;
1183 }
1184
1185 return 0;
1186 }
1187
get_broadcast_source_by_big(const struct bt_iso_big * big)1188 static struct bt_bap_broadcast_source *get_broadcast_source_by_big(const struct bt_iso_big *big)
1189 {
1190 for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources); i++) {
1191 if (broadcast_sources[i].big == big) {
1192 return &broadcast_sources[i];
1193 }
1194 }
1195
1196 return NULL;
1197 }
1198
big_started_cb(struct bt_iso_big * big)1199 static void big_started_cb(struct bt_iso_big *big)
1200 {
1201 struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big);
1202 struct bt_bap_broadcast_source_cb *listener;
1203
1204 if (source == NULL) {
1205 /* Not one of ours */
1206 return;
1207 }
1208
1209 SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) {
1210 if (listener->started != NULL) {
1211 listener->started(source);
1212 }
1213 }
1214 }
1215
big_stopped_cb(struct bt_iso_big * big,uint8_t reason)1216 static void big_stopped_cb(struct bt_iso_big *big, uint8_t reason)
1217 {
1218 struct bt_bap_broadcast_source *source = get_broadcast_source_by_big(big);
1219 struct bt_bap_broadcast_source_cb *listener;
1220
1221 if (source == NULL) {
1222 /* Not one of ours */
1223 return;
1224 }
1225
1226 source->big = NULL;
1227
1228 SYS_SLIST_FOR_EACH_CONTAINER(&bap_broadcast_source_cbs, listener, _node) {
1229 if (listener->stopped != NULL) {
1230 listener->stopped(source, reason);
1231 }
1232 }
1233 }
1234
bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb * cb)1235 int bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb *cb)
1236 {
1237 static bool iso_big_cb_registered;
1238
1239 CHECKIF(cb == NULL) {
1240 LOG_DBG("cb is NULL");
1241
1242 return -EINVAL;
1243 }
1244
1245 if (sys_slist_find(&bap_broadcast_source_cbs, &cb->_node, NULL)) {
1246 LOG_DBG("cb %p is already registered", cb);
1247
1248 return -EEXIST;
1249 }
1250
1251 if (!iso_big_cb_registered) {
1252 static struct bt_iso_big_cb big_cb = {
1253 .started = big_started_cb,
1254 .stopped = big_stopped_cb,
1255 };
1256 const int err = bt_iso_big_register_cb(&big_cb);
1257
1258 if (err != 0) {
1259 __ASSERT(false, "Failed to register ISO BIG callbacks: %d", err);
1260 }
1261
1262 iso_big_cb_registered = true;
1263 }
1264
1265 sys_slist_append(&bap_broadcast_source_cbs, &cb->_node);
1266
1267 return 0;
1268 }
1269
bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb * cb)1270 int bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb *cb)
1271 {
1272 CHECKIF(cb == NULL) {
1273 LOG_DBG("cb is NULL");
1274
1275 return -EINVAL;
1276 }
1277
1278 if (!sys_slist_find_and_remove(&bap_broadcast_source_cbs, &cb->_node)) {
1279 LOG_DBG("cb %p is not registered", cb);
1280
1281 return -ENOENT;
1282 }
1283
1284 return 0;
1285 }
1286
bt_bap_broadcast_source_foreach_stream(struct bt_bap_broadcast_source * source,bt_bap_broadcast_source_foreach_stream_func_t func,void * user_data)1287 int bt_bap_broadcast_source_foreach_stream(struct bt_bap_broadcast_source *source,
1288 bt_bap_broadcast_source_foreach_stream_func_t func,
1289 void *user_data)
1290 {
1291 struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup;
1292
1293 if (source == NULL) {
1294 LOG_DBG("source is NULL");
1295 return -EINVAL;
1296 }
1297
1298 if (func == NULL) {
1299 LOG_DBG("func is NULL");
1300 return -EINVAL;
1301 }
1302
1303 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, next_subgroup, _node) {
1304 struct bt_bap_stream *stream, *next_stream;
1305
1306 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, next_stream, _node) {
1307 const bool stop = func(stream, user_data);
1308
1309 if (stop) {
1310 return -ECANCELED;
1311 }
1312 }
1313 }
1314
1315 return 0;
1316 }
1317