1 /* Bluetooth Audio Broadcast Source */
2
3 /*
4 * Copyright (c) 2021-2024 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 ops = stream->ops;
195 if (ops != NULL && ops->connected != NULL) {
196 ops->connected(stream);
197 }
198
199 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING);
200
201 if (ops != NULL && ops->started != NULL) {
202 ops->started(stream);
203 } else {
204 LOG_WRN("No callback for started set");
205 }
206 }
207
broadcast_source_iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)208 static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
209 {
210 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
211 const struct bt_bap_stream_ops *ops;
212 struct bt_bap_stream *stream;
213 struct bt_bap_ep *ep = iso->tx.ep;
214
215 if (ep == NULL) {
216 LOG_ERR("iso %p not bound with ep", chan);
217 return;
218 }
219
220 stream = ep->stream;
221 if (stream == NULL) {
222 LOG_ERR("No stream for ep %p", ep);
223 return;
224 }
225
226 LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason);
227
228 ops = stream->ops;
229 if (ops != NULL && ops->disconnected != NULL) {
230 ops->disconnected(stream, reason);
231 }
232
233 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED);
234
235 if (ops != NULL && ops->stopped != NULL) {
236 ops->stopped(stream, reason);
237 } else {
238 LOG_WRN("No callback for stopped set");
239 }
240 }
241
242 static struct bt_iso_chan_ops broadcast_source_iso_ops = {
243 .sent = broadcast_source_iso_sent,
244 .connected = broadcast_source_iso_connected,
245 .disconnected = broadcast_source_iso_disconnected,
246 };
247
bt_bap_ep_is_broadcast_src(const struct bt_bap_ep * ep)248 bool bt_bap_ep_is_broadcast_src(const struct bt_bap_ep *ep)
249 {
250 for (int i = 0; i < ARRAY_SIZE(broadcast_source_eps); i++) {
251 if (PART_OF_ARRAY(broadcast_source_eps[i], ep)) {
252 return true;
253 }
254 }
255
256 return false;
257 }
258
broadcast_source_ep_init(struct bt_bap_ep * ep)259 static void broadcast_source_ep_init(struct bt_bap_ep *ep)
260 {
261 LOG_DBG("ep %p", ep);
262
263 (void)memset(ep, 0, sizeof(*ep));
264 ep->dir = BT_AUDIO_DIR_SOURCE;
265 ep->iso = NULL;
266 }
267
broadcast_source_new_ep(uint8_t index)268 static struct bt_bap_ep *broadcast_source_new_ep(uint8_t index)
269 {
270 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_eps[index]); i++) {
271 struct bt_bap_ep *ep = &broadcast_source_eps[index][i];
272
273 /* If ep->stream is NULL the endpoint is unallocated */
274 if (ep->stream == NULL) {
275 broadcast_source_ep_init(ep);
276 return ep;
277 }
278 }
279
280 return NULL;
281 }
282
broadcast_source_new_subgroup(uint8_t index)283 static struct bt_bap_broadcast_subgroup *broadcast_source_new_subgroup(uint8_t index)
284 {
285 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_subgroups[index]); i++) {
286 struct bt_bap_broadcast_subgroup *subgroup = &broadcast_source_subgroups[index][i];
287
288 if (sys_slist_is_empty(&subgroup->streams)) {
289 return subgroup;
290 }
291 }
292
293 return NULL;
294 }
295
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)296 static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *stream,
297 struct bt_audio_codec_cfg *codec_cfg,
298 struct bt_bap_qos_cfg *qos,
299 struct bt_bap_broadcast_source *source)
300 {
301 struct bt_bap_iso *iso;
302 struct bt_bap_ep *ep;
303
304 ep = broadcast_source_new_ep(index);
305 if (ep == NULL) {
306 LOG_DBG("Could not allocate new broadcast endpoint");
307 return -ENOMEM;
308 }
309
310 iso = bt_bap_iso_new();
311 if (iso == NULL) {
312 LOG_DBG("Could not allocate iso");
313 return -ENOMEM;
314 }
315
316 bt_bap_iso_init(iso, &broadcast_source_iso_ops);
317 bt_bap_iso_bind_ep(iso, ep);
318
319 bt_bap_qos_cfg_to_iso_qos(iso->chan.qos->tx, qos);
320 bt_bap_iso_configure_data_path(ep, codec_cfg);
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 ep->broadcast_source = source;
330
331 return 0;
332 }
333
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)334 static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
335 struct bt_audio_broadcast_stream_data *stream_data,
336 uint8_t *streams_encoded, struct net_buf_simple *buf)
337 {
338 struct bt_bap_stream *stream;
339 const struct bt_audio_codec_cfg *codec_cfg;
340 uint8_t stream_count;
341 uint8_t len;
342
343 stream_count = 0;
344 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
345 stream_count++;
346 }
347
348 codec_cfg = subgroup->codec_cfg;
349
350 net_buf_simple_add_u8(buf, stream_count);
351 net_buf_simple_add_u8(buf, codec_cfg->id);
352 net_buf_simple_add_le16(buf, codec_cfg->cid);
353 net_buf_simple_add_le16(buf, codec_cfg->vid);
354
355 net_buf_simple_add_u8(buf, codec_cfg->data_len);
356 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
357 if ((buf->size - buf->len) < codec_cfg->data_len) {
358 LOG_DBG("No room for config data: %zu", codec_cfg->data_len);
359
360 return false;
361 }
362 net_buf_simple_add_mem(buf, codec_cfg->data, codec_cfg->data_len);
363 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
364
365 if ((buf->size - buf->len) < sizeof(len)) {
366 LOG_DBG("No room for metadata length");
367
368 return false;
369 }
370
371 net_buf_simple_add_u8(buf, codec_cfg->meta_len);
372
373 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
374 if ((buf->size - buf->len) < codec_cfg->meta_len) {
375 LOG_DBG("No room for metadata data: %zu", codec_cfg->meta_len);
376
377 return false;
378 }
379
380 net_buf_simple_add_mem(buf, codec_cfg->meta, codec_cfg->meta_len);
381 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
382
383 /* Create BIS index bitfield */
384 for (uint8_t i = 0U; i < stream_count; i++) {
385 /* Set the bis_index to *streams_encoded plus 1 as the indexes start from 1 */
386 const uint8_t bis_index = *streams_encoded + 1;
387
388 if ((buf->size - buf->len) < (sizeof(bis_index) + sizeof(uint8_t))) {
389 LOG_DBG("No room for BIS[%d] index", i);
390
391 return false;
392 }
393
394 net_buf_simple_add_u8(buf, bis_index);
395
396 if ((buf->size - buf->len) < sizeof(len)) {
397 LOG_DBG("No room for bis codec config length");
398
399 return false;
400 }
401
402 net_buf_simple_add_u8(buf, stream_data[i].data_len);
403 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
404 if ((buf->size - buf->len) < stream_data[i].data_len) {
405 LOG_DBG("No room for BIS[%u] data: %zu", i, stream_data[i].data_len);
406
407 return false;
408 }
409
410 net_buf_simple_add_mem(buf, stream_data[i].data, stream_data[i].data_len);
411 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
412
413 (*streams_encoded)++;
414 }
415
416 return true;
417 }
418
encode_base(struct bt_bap_broadcast_source * source,struct net_buf_simple * buf)419 static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_simple *buf)
420 {
421 struct bt_bap_broadcast_subgroup *subgroup;
422 uint8_t streams_encoded;
423 uint8_t subgroup_count;
424
425 /* 13 is the size of the fixed size values following this check */
426 if ((buf->size - buf->len) < MINIMUM_BASE_SIZE) {
427 return false;
428 }
429
430 subgroup_count = 0U;
431 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
432 subgroup_count++;
433 }
434
435 net_buf_simple_add_le16(buf, BT_UUID_BASIC_AUDIO_VAL);
436
437 net_buf_simple_add_le24(buf, source->qos->pd);
438 net_buf_simple_add_u8(buf, subgroup_count);
439
440 /* Since the `stream_data` is only stored in the broadcast source,
441 * we need to provide that information when encoding each subgroup
442 */
443 streams_encoded = 0;
444 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
445 if (!encode_base_subgroup(subgroup, &source->stream_data[streams_encoded],
446 &streams_encoded, buf)) {
447 return false;
448 }
449 }
450
451 return true;
452 }
453
broadcast_source_cleanup(struct bt_bap_broadcast_source * source)454 static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
455 {
456 struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup;
457
458 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, next_subgroup, _node) {
459 struct bt_bap_stream *stream, *next_stream;
460
461 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, next_stream, _node) {
462 bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
463 stream->ep->stream = NULL;
464 stream->ep = NULL;
465 stream->codec_cfg = NULL;
466 stream->qos = NULL;
467 stream->group = NULL;
468
469 sys_slist_remove(&subgroup->streams, NULL, &stream->_node);
470 }
471 sys_slist_remove(&source->subgroups, NULL, &subgroup->_node);
472 }
473
474 (void)memset(source, 0, sizeof(*source));
475 }
476
valid_broadcast_source_param(const struct bt_bap_broadcast_source_param * param,const struct bt_bap_broadcast_source * source)477 static bool valid_broadcast_source_param(const struct bt_bap_broadcast_source_param *param,
478 const struct bt_bap_broadcast_source *source)
479 {
480 const struct bt_bap_qos_cfg *qos;
481
482 CHECKIF(param == NULL) {
483 LOG_DBG("param is NULL");
484 return false;
485 }
486
487 CHECKIF(!IN_RANGE(param->params_count, 1U, CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT)) {
488 LOG_DBG("param->params_count %zu is invalid", param->params_count);
489 return false;
490 }
491
492 CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL &&
493 param->packing != BT_ISO_PACKING_INTERLEAVED) {
494 LOG_DBG("param->packing %u is invalid", param->packing);
495 return false;
496 }
497
498 qos = param->qos;
499 CHECKIF(qos == NULL) {
500 LOG_DBG("param->qos is NULL");
501 return false;
502 }
503
504 CHECKIF(bt_audio_verify_qos(qos) != BT_BAP_ASCS_REASON_NONE) {
505 LOG_DBG("param->qos is invalid");
506 return false;
507 }
508
509 CHECKIF(param->qos->rtn > BT_ISO_BROADCAST_RTN_MAX) {
510 LOG_DBG("param->qos->rtn %u invalid", param->qos->rtn);
511 return false;
512 }
513
514 CHECKIF(param->params == NULL) {
515 LOG_DBG("param->params is NULL");
516 return false;
517 }
518
519 CHECKIF(param->params_count == 0) {
520 LOG_DBG("param->params_count is 0");
521 return false;
522 }
523
524 for (size_t i = 0U; i < param->params_count; i++) {
525 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
526
527 subgroup_param = ¶m->params[i];
528
529 CHECKIF(subgroup_param->params == NULL) {
530 LOG_DBG("subgroup_params[%zu].params is NULL", i);
531 return false;
532 }
533
534 CHECKIF(!IN_RANGE(subgroup_param->params_count, 1U,
535 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)) {
536 LOG_DBG("subgroup_params[%zu].count (%zu) is invalid", i,
537 subgroup_param->params_count);
538 return false;
539 }
540
541 CHECKIF(!bt_audio_valid_codec_cfg(subgroup_param->codec_cfg)) {
542 LOG_DBG("subgroup_params[%zu].codec_cfg is invalid", i);
543 return false;
544 }
545
546 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
547 const struct bt_bap_broadcast_source_stream_param *stream_param;
548
549 stream_param = &subgroup_param->params[j];
550
551 CHECKIF(stream_param->stream == NULL) {
552 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is NULL",
553 i, j);
554 return false;
555 }
556
557 CHECKIF(stream_param->stream->group != NULL &&
558 stream_param->stream->group != source) {
559 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is "
560 "already part of group %p",
561 i, j, stream_param->stream->group);
562 return false;
563 }
564
565 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
566 CHECKIF(stream_param->data == NULL && stream_param->data_len != 0) {
567 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data is "
568 "NULL with len %zu",
569 i, j, stream_param->data_len);
570 return false;
571 }
572
573 CHECKIF(stream_param->data_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
574 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data_len too "
575 "large: %zu > %d",
576 i, j, stream_param->data_len,
577 CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE);
578 return false;
579 }
580
581 CHECKIF(stream_param->data != NULL &&
582 subgroup_param->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3 &&
583 !bt_audio_valid_ltv(stream_param->data, stream_param->data_len)) {
584 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data not valid "
585 "LTV",
586 i, j);
587 return false;
588 }
589 }
590 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
591 }
592
593 return true;
594 }
595
596 /** Gets the "highest" state of all BIS in the broadcast source */
broadcast_source_get_state(struct bt_bap_broadcast_source * source)597 static enum bt_bap_ep_state broadcast_source_get_state(struct bt_bap_broadcast_source *source)
598 {
599 enum bt_bap_ep_state state = BT_BAP_EP_STATE_IDLE;
600 struct bt_bap_broadcast_subgroup *subgroup;
601
602 if (source == NULL) {
603 LOG_DBG("source is NULL");
604 return state;
605 }
606
607 if (sys_slist_is_empty(&source->subgroups)) {
608 LOG_DBG("Source does not have any streams");
609 return state;
610 }
611
612 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
613 struct bt_bap_stream *stream;
614
615 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
616 if (stream->ep != NULL) {
617 state = MAX(state, stream->ep->status.state);
618 }
619 }
620 }
621
622 return state;
623 }
624
merge_bis_and_subgroup_data_cb(struct bt_data * data,void * user_data)625 static bool merge_bis_and_subgroup_data_cb(struct bt_data *data, void *user_data)
626 {
627 struct bt_audio_codec_cfg *codec_cfg = user_data;
628 int err;
629
630 err = bt_audio_codec_cfg_set_val(codec_cfg, data->type, data->data, data->data_len);
631 if (err < 0) {
632 LOG_DBG("Failed to set type %u with len %u in codec_cfg: %d", data->type,
633 data->data_len, err);
634
635 return false;
636 }
637
638 return true;
639 }
640
update_codec_cfg_data(struct bt_audio_codec_cfg * codec_cfg,const struct bt_bap_broadcast_source_stream_param * stream_param)641 static int update_codec_cfg_data(struct bt_audio_codec_cfg *codec_cfg,
642 const struct bt_bap_broadcast_source_stream_param *stream_param)
643 {
644 if (stream_param->data_len > 0) {
645 int err;
646
647 /* Merge subgroup codec configuration with the BIS configuration
648 * As per the BAP spec, if a value exist at level 2 (subgroup) and 3 (BIS), then it
649 * is the value at level 3 that shall be used
650 */
651 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
652 err = bt_audio_data_parse(stream_param->data, stream_param->data_len,
653 merge_bis_and_subgroup_data_cb, codec_cfg);
654 if (err != 0) {
655 LOG_DBG("Could not merge BIS and subgroup config in codec_cfg: %d",
656 err);
657
658 return -EINVAL;
659 }
660 } else {
661 /* If it is not LC3, then we don't know how to merge the subgroup and BIS
662 * codecs, so we just append them
663 */
664 if (codec_cfg->data_len + stream_param->data_len >
665 sizeof(codec_cfg->data)) {
666 LOG_DBG("Could not store BIS and subgroup config in codec_cfg (%u "
667 "> %u)",
668 codec_cfg->data_len + stream_param->data_len,
669 sizeof(codec_cfg->data));
670
671 return -ENOMEM;
672 }
673
674 memcpy(&codec_cfg->data[codec_cfg->data_len], stream_param->data,
675 stream_param->data_len);
676 codec_cfg->data_len += stream_param->data_len;
677 }
678 }
679
680 return 0;
681 }
682
bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param * param,struct bt_bap_broadcast_source ** out_source)683 int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
684 struct bt_bap_broadcast_source **out_source)
685 {
686 struct bt_bap_broadcast_source *source;
687 struct bt_bap_qos_cfg *qos;
688 size_t stream_count;
689 uint8_t index;
690 uint8_t bis_count;
691 int err;
692
693 CHECKIF(out_source == NULL) {
694 LOG_DBG("out_source is NULL");
695 return -EINVAL;
696 }
697
698 /* Set out_source to NULL until the source has actually been created */
699 *out_source = NULL;
700
701 if (!valid_broadcast_source_param(param, NULL)) {
702 LOG_DBG("Invalid parameters");
703 return -EINVAL;
704 }
705
706 source = NULL;
707 for (index = 0; index < ARRAY_SIZE(broadcast_sources); index++) {
708 if (sys_slist_is_empty(&broadcast_sources[index].subgroups)) { /* Find free entry */
709 source = &broadcast_sources[index];
710 break;
711 }
712 }
713
714 if (source == NULL) {
715 LOG_DBG("Could not allocate any more broadcast sources");
716 return -ENOMEM;
717 }
718
719 stream_count = 0U;
720 bis_count = 0U;
721 qos = param->qos;
722 /* Go through all subgroups and streams and setup each setup with an
723 * endpoint
724 */
725 for (size_t i = 0U; i < param->params_count; i++) {
726 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
727 struct bt_bap_broadcast_subgroup *subgroup;
728
729 subgroup_param = ¶m->params[i];
730
731 subgroup = broadcast_source_new_subgroup(index);
732 if (subgroup == NULL) {
733 LOG_DBG("Could not allocate new broadcast subgroup");
734 broadcast_source_cleanup(source);
735 return -ENOMEM;
736 }
737
738 subgroup->codec_cfg = subgroup_param->codec_cfg;
739 sys_slist_append(&source->subgroups, &subgroup->_node);
740
741 /* Check that we are not above the maximum BIS count */
742 if (subgroup_param->params_count + stream_count > BROADCAST_STREAM_CNT) {
743 LOG_DBG("Cannot create broadcaster with %zu streams", stream_count);
744 broadcast_source_cleanup(source);
745
746 return -ENOMEM;
747 }
748
749 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
750 const struct bt_bap_broadcast_source_stream_param *stream_param;
751 struct bt_bap_stream *stream;
752 struct bt_audio_codec_cfg *codec_cfg;
753
754 codec_cfg = subgroup_param->codec_cfg;
755 stream_param = &subgroup_param->params[j];
756 stream = stream_param->stream;
757
758 if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
759 if (bis_count >= BROADCAST_STREAM_CNT) {
760 LOG_DBG("Stream count %d exceeded", bis_count);
761 return -ENOMEM;
762 }
763
764 codec_cfg = &source->codec_cfg[bis_count];
765 memcpy(codec_cfg, subgroup_param->codec_cfg,
766 sizeof(struct bt_audio_codec_cfg));
767
768 err = update_codec_cfg_data(codec_cfg, stream_param);
769 if (err != 0) {
770 LOG_DBG("codec config update failed [%zu]: %d", i, err);
771 broadcast_source_cleanup(source);
772 return err;
773 }
774
775 bis_count++;
776 }
777
778 err = broadcast_source_setup_stream(index, stream, codec_cfg, qos, source);
779 if (err != 0) {
780 LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
781 broadcast_source_cleanup(source);
782 return err;
783 }
784
785 /* Store the BIS specific codec configuration data in
786 * the broadcast source. It is stored in the broadcast
787 * source, instead of the stream object, as this is
788 * only relevant for the broadcast source, and not used
789 * for unicast or broadcast sink.
790 */
791 (void)memcpy(source->stream_data[stream_count].data, stream_param->data,
792 stream_param->data_len * sizeof(*stream_param->data));
793 source->stream_data[stream_count].data_len = stream_param->data_len;
794
795 sys_slist_append(&subgroup->streams, &stream->_node);
796 stream_count++;
797 }
798 }
799
800 /* Finalize state changes and store information */
801 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
802 source->qos = qos;
803 source->packing = param->packing;
804 #if defined(CONFIG_BT_ISO_TEST_PARAMS)
805 source->irc = param->irc;
806 source->pto = param->pto;
807 source->iso_interval = param->iso_interval;
808 #endif /* CONFIG_BT_ISO_TEST_PARAMS */
809
810 source->encryption = param->encryption;
811 if (source->encryption) {
812 (void)memcpy(source->broadcast_code, param->broadcast_code,
813 sizeof(source->broadcast_code));
814 }
815
816 *out_source = source;
817
818 return 0;
819 }
820
bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source * source,struct bt_bap_broadcast_source_param * param)821 int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
822 struct bt_bap_broadcast_source_param *param)
823 {
824 struct bt_bap_broadcast_subgroup *subgroup;
825 enum bt_bap_ep_state broadcast_state;
826 struct bt_bap_qos_cfg *qos;
827 size_t subgroup_cnt;
828 uint8_t bis_count;
829
830 CHECKIF(source == NULL) {
831 LOG_DBG("source is NULL");
832 return -EINVAL;
833 }
834
835 if (!valid_broadcast_source_param(param, source)) {
836 LOG_DBG("Invalid parameters");
837 return -EINVAL;
838 }
839
840 broadcast_state = broadcast_source_get_state(source);
841 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
842 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
843 return -EBADMSG;
844 }
845
846 /* Verify that the parameter counts do not exceed existing number of subgroups and streams*/
847 subgroup_cnt = 0U;
848 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
849 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param =
850 ¶m->params[subgroup_cnt];
851 const size_t subgroup_stream_param_cnt = subgroup_param->params_count;
852 struct bt_bap_stream *stream;
853 size_t subgroup_stream_cnt = 0U;
854
855 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
856 subgroup_stream_cnt++;
857 }
858
859 /* Verify that the param stream is in the subgroup */
860 for (size_t i = 0U; i < subgroup_param->params_count; i++) {
861 struct bt_bap_stream *subgroup_stream;
862 struct bt_bap_stream *param_stream;
863 bool stream_in_subgroup = false;
864
865 param_stream = subgroup_param->params[i].stream;
866
867 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
868 if (subgroup_stream == param_stream) {
869 stream_in_subgroup = true;
870 break;
871 }
872 }
873
874 if (!stream_in_subgroup) {
875 LOG_DBG("Invalid param->params[%zu]->param[%zu].stream "
876 "not in subgroup",
877 subgroup_cnt, i);
878 return -EINVAL;
879 }
880 }
881
882 if (subgroup_stream_cnt < subgroup_stream_param_cnt) {
883 LOG_DBG("Invalid param->params[%zu]->params_count: %zu "
884 "(only %zu streams in subgroup)",
885 subgroup_cnt, subgroup_stream_param_cnt, subgroup_stream_cnt);
886 return -EINVAL;
887 }
888
889 subgroup_cnt++;
890 }
891
892 if (subgroup_cnt < param->params_count) {
893 LOG_DBG("Invalid param->params_count: %zu (only %zu subgroups in source)",
894 param->params_count, subgroup_cnt);
895 return -EINVAL;
896 }
897
898 qos = param->qos;
899 bis_count = 0U;
900 /* We update up to the first param->params_count subgroups */
901 for (size_t i = 0U; i < param->params_count; i++) {
902 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
903 struct bt_audio_codec_cfg *codec_cfg;
904 struct bt_bap_stream *stream;
905
906 if (i == 0) {
907 subgroup =
908 SYS_SLIST_PEEK_HEAD_CONTAINER(&source->subgroups, subgroup, _node);
909 } else {
910 subgroup = SYS_SLIST_PEEK_NEXT_CONTAINER(subgroup, _node);
911 }
912
913 subgroup_param = ¶m->params[i];
914 codec_cfg = subgroup_param->codec_cfg;
915 subgroup->codec_cfg = codec_cfg;
916
917 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
918 const struct bt_bap_broadcast_source_stream_param *stream_param;
919 struct bt_audio_broadcast_stream_data *stream_data;
920 struct bt_bap_stream *subgroup_stream;
921 size_t stream_idx;
922
923 stream_param = &subgroup_param->params[j];
924 stream = stream_param->stream;
925 if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
926 int err;
927
928 if (bis_count >= BROADCAST_STREAM_CNT) {
929 LOG_DBG("Stream count %d exceeded", bis_count);
930 return -ENOMEM;
931 }
932
933 codec_cfg = &source->codec_cfg[bis_count];
934 memcpy(codec_cfg, subgroup_param->codec_cfg,
935 sizeof(struct bt_audio_codec_cfg));
936
937 err = update_codec_cfg_data(codec_cfg, stream_param);
938 if (err != 0) {
939 LOG_DBG("codec config update failed [%zu]: %d", i, err);
940 return err;
941 }
942
943 bis_count++;
944 }
945
946 stream_idx = 0U;
947 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
948 if (subgroup_stream == stream) {
949 break;
950 }
951
952 stream_idx++;
953 }
954
955 /* Store the BIS specific codec configuration data in the broadcast source.
956 * It is stored in the broadcast* source, instead of the stream object,
957 * as this is only relevant for the broadcast source, and not used
958 * for unicast or broadcast sink.
959 */
960 stream_data = &source->stream_data[stream_idx];
961 (void)memcpy(stream_data->data, stream_param->data, stream_param->data_len);
962 stream_data->data_len = stream_param->data_len;
963 }
964
965 /* Apply the codec_cfg to all streams in the subgroup, and not just the ones in the
966 * params
967 */
968 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
969 bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg);
970 bt_bap_iso_configure_data_path(stream->ep, codec_cfg);
971 }
972 }
973
974 /* Finally we apply the new qos and to all streams */
975 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
976 struct bt_bap_stream *stream;
977
978 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
979 struct bt_iso_chan_io_qos *iso_qos;
980
981 iso_qos = stream->ep->iso->chan.qos->tx;
982 bt_bap_qos_cfg_to_iso_qos(iso_qos, qos);
983 stream->qos = qos;
984 }
985 }
986
987 source->qos = qos;
988
989 return 0;
990 }
991
bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source * source,const uint8_t meta[],size_t meta_len)992 int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
993 const uint8_t meta[], size_t meta_len)
994 {
995 struct bt_bap_broadcast_subgroup *subgroup;
996 enum bt_bap_ep_state broadcast_state;
997
998 CHECKIF(source == NULL) {
999 LOG_DBG("source is NULL");
1000
1001 return -EINVAL;
1002 }
1003
1004 CHECKIF((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) {
1005 LOG_DBG("Invalid metadata combination: %p %zu", meta, meta_len);
1006
1007 return -EINVAL;
1008 }
1009
1010 CHECKIF(meta_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
1011 LOG_DBG("Invalid meta_len: %zu (max %d)", meta_len,
1012 CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
1013
1014 return -EINVAL;
1015 }
1016
1017 broadcast_state = broadcast_source_get_state(source);
1018 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_STREAMING) {
1019 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1020
1021 return -EBADMSG;
1022 }
1023
1024 /* TODO: We should probably find a way to update the metadata
1025 * for each subgroup individually
1026 */
1027 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
1028 memset(subgroup->codec_cfg->meta, 0, sizeof(subgroup->codec_cfg->meta));
1029 memcpy(subgroup->codec_cfg->meta, meta, meta_len);
1030 subgroup->codec_cfg->meta_len = meta_len;
1031 }
1032
1033 return 0;
1034 }
1035
bt_bap_broadcast_source_start(struct bt_bap_broadcast_source * source,struct bt_le_ext_adv * adv)1036 int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv)
1037 {
1038 struct bt_iso_chan *bis[BROADCAST_STREAM_CNT];
1039 struct bt_iso_big_create_param param = {0};
1040 struct bt_bap_broadcast_subgroup *subgroup;
1041 enum bt_bap_ep_state broadcast_state;
1042 struct bt_bap_stream *stream;
1043 size_t bis_count;
1044 int err;
1045
1046 CHECKIF(source == NULL) {
1047 LOG_DBG("source is NULL");
1048 return -EINVAL;
1049 }
1050
1051 CHECKIF(adv == NULL) {
1052 LOG_DBG("adv is NULL");
1053 return -EINVAL;
1054 }
1055
1056 broadcast_state = broadcast_source_get_state(source);
1057 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
1058 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1059 return -EBADMSG;
1060 }
1061
1062 bis_count = 0;
1063 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
1064 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
1065 bis[bis_count++] = bt_bap_stream_iso_chan_get(stream);
1066 }
1067 }
1068
1069 /* Create BIG */
1070 param.num_bis = bis_count;
1071 param.bis_channels = bis;
1072 param.framing = source->qos->framing;
1073 param.packing = source->packing;
1074 param.interval = source->qos->interval;
1075 param.latency = source->qos->latency;
1076 param.encryption = source->encryption;
1077 if (param.encryption) {
1078 (void)memcpy(param.bcode, source->broadcast_code, sizeof(param.bcode));
1079 }
1080 #if defined(CONFIG_BT_ISO_TEST_PARAMS)
1081 param.irc = source->irc;
1082 param.pto = source->pto;
1083 param.iso_interval = source->iso_interval;
1084 #endif /* CONFIG_BT_ISO_TEST_PARAMS */
1085
1086 /* Set the enabling state early in case that the BIS is connected before we can manage to
1087 * set it afterwards
1088 */
1089 broadcast_source_set_state(source, BT_BAP_EP_STATE_ENABLING);
1090
1091 err = bt_iso_big_create(adv, ¶m, &source->big);
1092 if (err != 0) {
1093 LOG_DBG("Failed to create BIG: %d", err);
1094 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
1095
1096 return err;
1097 }
1098
1099 return 0;
1100 }
1101
bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source * source)1102 int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source)
1103 {
1104 enum bt_bap_ep_state broadcast_state;
1105 int err;
1106
1107 CHECKIF(source == NULL) {
1108 LOG_DBG("source is NULL");
1109 return -EINVAL;
1110 }
1111
1112 broadcast_state = broadcast_source_get_state(source);
1113 if (broadcast_state != BT_BAP_EP_STATE_STREAMING &&
1114 broadcast_state != BT_BAP_EP_STATE_ENABLING) {
1115 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1116 return -EBADMSG;
1117 }
1118
1119 if (source->big == NULL) {
1120 LOG_DBG("Source is not started");
1121 return -EALREADY;
1122 }
1123
1124 err = bt_iso_big_terminate(source->big);
1125 if (err) {
1126 LOG_DBG("Failed to terminate BIG (err %d)", err);
1127 return err;
1128 }
1129
1130 return 0;
1131 }
1132
bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source * source)1133 int bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source *source)
1134 {
1135 enum bt_bap_ep_state broadcast_state;
1136
1137 CHECKIF(source == NULL) {
1138 LOG_DBG("source is NULL");
1139 return -EINVAL;
1140 }
1141
1142 broadcast_state = broadcast_source_get_state(source);
1143 if (broadcast_state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
1144 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1145 return -EBADMSG;
1146 }
1147
1148 broadcast_source_set_state(source, BT_BAP_EP_STATE_IDLE);
1149
1150 /* Reset the broadcast source */
1151 broadcast_source_cleanup(source);
1152
1153 return 0;
1154 }
1155
bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source * source,struct net_buf_simple * base_buf)1156 int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,
1157 struct net_buf_simple *base_buf)
1158 {
1159 enum bt_bap_ep_state broadcast_state;
1160
1161 CHECKIF(source == NULL) {
1162 LOG_DBG("source is NULL");
1163 return -EINVAL;
1164 }
1165
1166 CHECKIF(base_buf == NULL) {
1167 LOG_DBG("base_buf is NULL");
1168 return -EINVAL;
1169 }
1170
1171 broadcast_state = broadcast_source_get_state(source);
1172 if (broadcast_state == BT_BAP_EP_STATE_IDLE) {
1173 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1174 return -EBADMSG;
1175 }
1176
1177 if (!encode_base(source, base_buf)) {
1178 LOG_DBG("base_buf %p with size %u not large enough", base_buf, base_buf->size);
1179
1180 return -EMSGSIZE;
1181 }
1182
1183 return 0;
1184 }
1185
get_broadcast_source_by_big(const struct bt_iso_big * big)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
big_started_cb(struct bt_iso_big * big)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
big_stopped_cb(struct bt_iso_big * big,uint8_t reason)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
bt_bap_broadcast_source_register_cb(struct bt_bap_broadcast_source_cb * cb)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
bt_bap_broadcast_source_unregister_cb(struct bt_bap_broadcast_source_cb * cb)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 }
1284