blob: bb8ec7a7b63fe8e80302c7ea8124fcab37425849 [file] [log] [blame]
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001/* Bluetooth Audio Broadcast Source */
2
3/*
Emil Gydesen7fc05192023-02-20 14:33:43 +01004 * Copyright (c) 2021-2023 Nordic Semiconductor ASA
Emil Gydesenab87e0a2022-01-10 15:06:08 +01005 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
Gerard Marull-Paretas79e6b0e2022-08-25 09:58:46 +02009#include <zephyr/kernel.h>
Gerard Marull-Paretas5113c142022-05-06 11:12:04 +020010#include <zephyr/sys/byteorder.h>
11#include <zephyr/sys/check.h>
Emil Gydesenab87e0a2022-01-10 15:06:08 +010012
Gerard Marull-Paretas5113c142022-05-06 11:12:04 +020013#include <zephyr/bluetooth/bluetooth.h>
14#include <zephyr/bluetooth/conn.h>
15#include <zephyr/bluetooth/gatt.h>
16#include <zephyr/bluetooth/audio/audio.h>
Emil Gydesenab87e0a2022-01-10 15:06:08 +010017
Théo Battrele458f5a2022-11-02 14:31:13 +010018#include <zephyr/logging/log.h>
Emil Gydesenbe424292023-02-25 16:47:19 +010019LOG_MODULE_REGISTER(bt_bap_broadcast_source, CONFIG_BT_BAP_BROADCAST_SOURCE_LOG_LEVEL);
Emil Gydesenab87e0a2022-01-10 15:06:08 +010020
Emil Gydesen7fc05192023-02-20 14:33:43 +010021#include "bap_iso.h"
22#include "bap_endpoint.h"
Emil Gydesenab87e0a2022-01-10 15:06:08 +010023
Emil Gydesen40e39302022-09-05 11:29:06 +020024struct bt_audio_broadcast_subgroup {
25 /* The streams used to create the broadcast source */
26 sys_slist_t streams;
27
28 /* The codec of the subgroup */
29 struct bt_codec *codec;
30
31 /* List node */
32 sys_snode_t _node;
33};
34
Emil Gydesenbe424292023-02-25 16:47:19 +010035static struct bt_audio_ep broadcast_source_eps[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
36 [BROADCAST_STREAM_CNT];
37static struct bt_audio_broadcast_subgroup
38 broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
39 [CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
40static struct bt_bap_broadcast_source broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
Emil Gydesenab87e0a2022-01-10 15:06:08 +010041
Emil Gydesen40e39302022-09-05 11:29:06 +020042/**
43 * 2 octets UUID
44 * 3 octets presentation delay
45 * 1 octet number of subgroups
46 *
47 * Each subgroup then has
48 * 1 octet of number of BIS
49 * 5 octets of Codec_ID
50 * 1 octet codec specific configuration len
51 * 0-n octets of codec specific configuration
52 * 1 octet metadata len
53 * 0-n octets of metadata
54 *
55 * For each BIS in the subgroup there is
56 * 1 octet for the BIS index
57 * 1 octet codec specific configuration len
58 * 0-n octets of codec specific configuration
59 *
60 * For a minimal BASE with 1 subgroup and 1 BIS without and other data the
61 * total comes to 16
62 */
63#define MINIMUM_BASE_SIZE 16
64
Emil Gydesenab87e0a2022-01-10 15:06:08 +010065static void broadcast_source_set_ep_state(struct bt_audio_ep *ep, uint8_t state)
66{
67 uint8_t old_state;
68
69 old_state = ep->status.state;
70
Théo Battrele458f5a2022-11-02 14:31:13 +010071 LOG_DBG("ep %p id 0x%02x %s -> %s", ep, ep->status.id, bt_audio_ep_state_str(old_state),
72 bt_audio_ep_state_str(state));
Emil Gydesenab87e0a2022-01-10 15:06:08 +010073
74 switch (old_state) {
75 case BT_AUDIO_EP_STATE_IDLE:
76 if (state != BT_AUDIO_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +010077 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesenab87e0a2022-01-10 15:06:08 +010078 return;
79 }
80 break;
81 case BT_AUDIO_EP_STATE_QOS_CONFIGURED:
82 if (state != BT_AUDIO_EP_STATE_IDLE &&
Emil Gydesen05ace182022-06-03 10:48:19 +020083 state != BT_AUDIO_EP_STATE_ENABLING) {
Théo Battrele458f5a2022-11-02 14:31:13 +010084 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesen05ace182022-06-03 10:48:19 +020085 return;
86 }
87 break;
88 case BT_AUDIO_EP_STATE_ENABLING:
89 if (state != BT_AUDIO_EP_STATE_STREAMING) {
Théo Battrele458f5a2022-11-02 14:31:13 +010090 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesenab87e0a2022-01-10 15:06:08 +010091 return;
92 }
Emil Gydesen2df90772022-03-18 13:53:31 +010093 break;
Emil Gydesenab87e0a2022-01-10 15:06:08 +010094 case BT_AUDIO_EP_STATE_STREAMING:
95 if (state != BT_AUDIO_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +010096 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesenab87e0a2022-01-10 15:06:08 +010097 return;
98 }
99 break;
100 default:
Théo Battrele458f5a2022-11-02 14:31:13 +0100101 LOG_ERR("Invalid broadcast sync endpoint state: %s",
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100102 bt_audio_ep_state_str(old_state));
103 return;
104 }
105
106 ep->status.state = state;
107
108 if (state == BT_AUDIO_EP_STATE_IDLE) {
109 struct bt_audio_stream *stream = ep->stream;
110
111 if (stream != NULL) {
112 stream->ep = NULL;
113 stream->codec = NULL;
114 ep->stream = NULL;
115 }
116 }
117}
118
Emil Gydesen4518c192022-03-07 14:18:26 +0100119static void broadcast_source_iso_sent(struct bt_iso_chan *chan)
120{
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200121 struct bt_audio_iso *iso = CONTAINER_OF(chan, struct bt_audio_iso, chan);
122 const struct bt_audio_stream_ops *ops;
123 struct bt_audio_stream *stream;
124 struct bt_audio_ep *ep = iso->tx.ep;
125
126 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100127 LOG_ERR("iso %p not bound with ep", chan);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200128 return;
129 }
130
131 stream = ep->stream;
132 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100133 LOG_ERR("No stream for ep %p", ep);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200134 return;
135 }
136
137 ops = stream->ops;
Emil Gydesen4518c192022-03-07 14:18:26 +0100138
Emil Gydesen65f130b2022-09-26 17:15:24 +0200139 if (IS_ENABLED(CONFIG_BT_AUDIO_DEBUG_STREAM_DATA)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100140 LOG_DBG("stream %p ep %p", stream, stream->ep);
Emil Gydesen65f130b2022-09-26 17:15:24 +0200141 }
Emil Gydesen4518c192022-03-07 14:18:26 +0100142
143 if (ops != NULL && ops->sent != NULL) {
Emil Gydesen9b154262022-05-24 13:59:45 +0200144 ops->sent(stream);
Emil Gydesen4518c192022-03-07 14:18:26 +0100145 }
146}
147
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100148static void broadcast_source_iso_connected(struct bt_iso_chan *chan)
149{
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200150 struct bt_audio_iso *iso = CONTAINER_OF(chan, struct bt_audio_iso, chan);
Emil Gydesene8e19202022-02-14 14:18:03 +0100151 const struct bt_audio_stream_ops *ops;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200152 struct bt_audio_stream *stream;
153 struct bt_audio_ep *ep = iso->tx.ep;
Emil Gydesene8e19202022-02-14 14:18:03 +0100154
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200155 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100156 LOG_ERR("iso %p not bound with ep", chan);
Emil Gydesen9b154262022-05-24 13:59:45 +0200157 return;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200158 }
159
160 stream = ep->stream;
161 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100162 LOG_ERR("No stream for ep %p", ep);
Emil Gydesene8e19202022-02-14 14:18:03 +0100163 return;
164 }
165
Emil Gydesen9b154262022-05-24 13:59:45 +0200166 ops = stream->ops;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100167
Théo Battrele458f5a2022-11-02 14:31:13 +0100168 LOG_DBG("stream %p ep %p", stream, ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100169
170 broadcast_source_set_ep_state(ep, BT_AUDIO_EP_STATE_STREAMING);
171
Emil Gydesen628b54a2022-02-02 17:12:30 +0100172 if (ops != NULL && ops->started != NULL) {
Emil Gydesen9b154262022-05-24 13:59:45 +0200173 ops->started(stream);
Emil Gydesen102dcca2022-01-20 15:03:00 +0100174 } else {
Théo Battrele458f5a2022-11-02 14:31:13 +0100175 LOG_WRN("No callback for connected set");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100176 }
177}
178
179static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
180{
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200181 struct bt_audio_iso *iso = CONTAINER_OF(chan, struct bt_audio_iso, chan);
Emil Gydesene8e19202022-02-14 14:18:03 +0100182 const struct bt_audio_stream_ops *ops;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200183 struct bt_audio_stream *stream;
184 struct bt_audio_ep *ep = iso->tx.ep;
Emil Gydesene8e19202022-02-14 14:18:03 +0100185
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200186 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100187 LOG_ERR("iso %p not bound with ep", chan);
Emil Gydesen9b154262022-05-24 13:59:45 +0200188 return;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200189 }
190
191 stream = ep->stream;
192 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100193 LOG_ERR("No stream for ep %p", ep);
Emil Gydesene8e19202022-02-14 14:18:03 +0100194 return;
195 }
196
Emil Gydesen9b154262022-05-24 13:59:45 +0200197 ops = stream->ops;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100198
Théo Battrele458f5a2022-11-02 14:31:13 +0100199 LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100200
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200201 broadcast_source_set_ep_state(ep, BT_AUDIO_EP_STATE_QOS_CONFIGURED);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100202
Emil Gydesen628b54a2022-02-02 17:12:30 +0100203 if (ops != NULL && ops->stopped != NULL) {
Emil Gydesen59a9f8a2023-03-02 15:01:00 +0100204 ops->stopped(stream, reason);
Emil Gydesen102dcca2022-01-20 15:03:00 +0100205 } else {
Théo Battrele458f5a2022-11-02 14:31:13 +0100206 LOG_WRN("No callback for stopped set");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100207 }
208}
209
210static struct bt_iso_chan_ops broadcast_source_iso_ops = {
Emil Gydesen4518c192022-03-07 14:18:26 +0100211 .sent = broadcast_source_iso_sent,
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100212 .connected = broadcast_source_iso_connected,
213 .disconnected = broadcast_source_iso_disconnected,
214};
215
216bool bt_audio_ep_is_broadcast_src(const struct bt_audio_ep *ep)
217{
218 for (int i = 0; i < ARRAY_SIZE(broadcast_source_eps); i++) {
219 if (PART_OF_ARRAY(broadcast_source_eps[i], ep)) {
220 return true;
221 }
222 }
223
224 return false;
225}
226
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200227static void broadcast_source_ep_init(struct bt_audio_ep *ep)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100228{
Théo Battrele458f5a2022-11-02 14:31:13 +0100229 LOG_DBG("ep %p", ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100230
231 (void)memset(ep, 0, sizeof(*ep));
Emil Gydesen6191a762022-03-29 18:20:10 +0200232 ep->dir = BT_AUDIO_DIR_SOURCE;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200233 ep->iso = NULL;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100234}
235
236static struct bt_audio_ep *broadcast_source_new_ep(uint8_t index)
237{
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100238 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_eps[index]); i++) {
Emil Gydesene8e19202022-02-14 14:18:03 +0100239 struct bt_audio_ep *ep = &broadcast_source_eps[index][i];
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100240
241 /* If ep->stream is NULL the endpoint is unallocated */
242 if (ep->stream == NULL) {
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200243 broadcast_source_ep_init(ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100244 return ep;
245 }
246 }
247
248 return NULL;
249}
250
Emil Gydesen40e39302022-09-05 11:29:06 +0200251static struct bt_audio_broadcast_subgroup *broadcast_source_new_subgroup(uint8_t index)
252{
253 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_subgroups[index]); i++) {
254 struct bt_audio_broadcast_subgroup *subgroup =
255 &broadcast_source_subgroups[index][i];
256
257 if (sys_slist_is_empty(&subgroup->streams)) {
258 return subgroup;
259 }
260 }
261
262 return NULL;
263}
264
Emil Gydesenbe424292023-02-25 16:47:19 +0100265static int broadcast_source_setup_stream(uint8_t index, struct bt_audio_stream *stream,
266 struct bt_codec *codec, struct bt_codec_qos *qos,
267 struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100268{
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200269 struct bt_audio_iso *iso;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100270 struct bt_audio_ep *ep;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100271
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100272 ep = broadcast_source_new_ep(index);
273 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100274 LOG_DBG("Could not allocate new broadcast endpoint");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100275 return -ENOMEM;
276 }
277
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200278 iso = bt_audio_iso_new();
279 if (iso == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100280 LOG_DBG("Could not allocate iso");
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200281 return -ENOMEM;
282 }
283
284 bt_audio_iso_init(iso, &broadcast_source_iso_ops);
285 bt_audio_iso_bind_ep(iso, ep);
286
287 bt_audio_codec_qos_to_iso_qos(iso->chan.qos->tx, qos);
288 bt_audio_codec_to_iso_path(iso->chan.qos->tx->path, codec);
289
290 bt_audio_iso_unref(iso);
291
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100292 bt_audio_stream_attach(NULL, stream, ep, codec);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100293 stream->qos = qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200294 ep->broadcast_source = source;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100295
296 return 0;
297}
298
Emil Gydesen40e39302022-09-05 11:29:06 +0200299static bool encode_base_subgroup(struct bt_audio_broadcast_subgroup *subgroup,
300 struct bt_audio_broadcast_stream_data *stream_data,
301 uint8_t *streams_encoded,
302 struct net_buf_simple *buf)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100303{
Emil Gydesen40e39302022-09-05 11:29:06 +0200304 struct bt_audio_stream *stream;
305 const struct bt_codec *codec;
306 uint8_t stream_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100307 uint8_t bis_index;
308 uint8_t *start;
309 uint8_t len;
310
Emil Gydesen40e39302022-09-05 11:29:06 +0200311 stream_count = 0;
312 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
313 stream_count++;
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200314 }
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200315
Emil Gydesen40e39302022-09-05 11:29:06 +0200316 codec = subgroup->codec;
317
318 net_buf_simple_add_u8(buf, stream_count);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100319 net_buf_simple_add_u8(buf, codec->id);
320 net_buf_simple_add_le16(buf, codec->cid);
321 net_buf_simple_add_le16(buf, codec->vid);
Emil Gydesen40e39302022-09-05 11:29:06 +0200322
323
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100324 /* Insert codec configuration data in LTV format */
325 start = net_buf_simple_add(buf, sizeof(len));
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200326
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100327 for (int i = 0; i < codec->data_count; i++) {
328 const struct bt_data *codec_data = &codec->data[i].data;
329
Emil Gydesen40e39302022-09-05 11:29:06 +0200330 if ((buf->size - buf->len) < (sizeof(codec_data->data_len) +
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200331 sizeof(codec_data->type) +
332 codec_data->data_len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100333 LOG_DBG("No room for codec[%d] with len %u", i, codec_data->data_len);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200334
335 return false;
336 }
337
Casper Bondee2dad8f2022-05-24 15:02:30 +0200338 net_buf_simple_add_u8(buf, codec_data->data_len + sizeof(codec_data->type));
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100339 net_buf_simple_add_u8(buf, codec_data->type);
Casper Bondee2dad8f2022-05-24 15:02:30 +0200340 net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100341
342 }
Nazar Kazakovf483b1b2022-03-16 21:07:43 +0000343 /* Calculate length of codec config data */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100344 len = net_buf_simple_tail(buf) - start - sizeof(len);
345 /* Update the length field */
346 *start = len;
347
Emil Gydesen40e39302022-09-05 11:29:06 +0200348 if ((buf->size - buf->len) < sizeof(len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100349 LOG_DBG("No room for metadata length");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200350
351 return false;
352 }
353
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100354 /* Insert codec metadata in LTV format*/
355 start = net_buf_simple_add(buf, sizeof(len));
356 for (int i = 0; i < codec->meta_count; i++) {
357 const struct bt_data *metadata = &codec->meta[i].data;
358
Emil Gydesen40e39302022-09-05 11:29:06 +0200359 if ((buf->size - buf->len) < (sizeof(metadata->data_len) +
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200360 sizeof(metadata->type) +
361 metadata->data_len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100362 LOG_DBG("No room for metadata[%d] with len %u", i, metadata->data_len);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200363
364 return false;
365 }
366
Casper Bondee2dad8f2022-05-24 15:02:30 +0200367 net_buf_simple_add_u8(buf, metadata->data_len + sizeof(metadata->type));
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100368 net_buf_simple_add_u8(buf, metadata->type);
Casper Bondee2dad8f2022-05-24 15:02:30 +0200369 net_buf_simple_add_mem(buf, metadata->data, metadata->data_len);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100370 }
Nazar Kazakovf483b1b2022-03-16 21:07:43 +0000371 /* Calculate length of codec config data */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100372 len = net_buf_simple_tail(buf) - start - sizeof(len);
373 /* Update the length field */
374 *start = len;
375
376 /* Create BIS index bitfield */
377 bis_index = 0;
Emil Gydesen40e39302022-09-05 11:29:06 +0200378 for (int i = 0; i < stream_count; i++) {
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100379 bis_index++;
Emil Gydesen40e39302022-09-05 11:29:06 +0200380 if ((buf->size - buf->len) < (sizeof(bis_index) + sizeof(uint8_t))) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100381 LOG_DBG("No room for BIS[%d] index", i);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200382
383 return false;
384 }
385
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100386 net_buf_simple_add_u8(buf, bis_index);
Emil Gydesen40e39302022-09-05 11:29:06 +0200387
388 if ((buf->size - buf->len) < sizeof(len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100389 LOG_DBG("No room for bis codec config length");
Emil Gydesen40e39302022-09-05 11:29:06 +0200390
391 return false;
392 }
393
394 /* Insert codec configuration data in LTV format */
395 start = net_buf_simple_add(buf, sizeof(len));
396
397#if defined(CONFIG_BT_CODEC_MAX_DATA_COUNT)
398 for (size_t j = 0U; j < stream_data[i].data_count; j++) {
399 const struct bt_data *codec_data = &stream_data[i].data[j].data;
400
401 if ((buf->size - buf->len) < (sizeof(codec_data->data_len) +
402 sizeof(codec_data->type) +
403 codec_data->data_len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100404 LOG_DBG("No room for BIS [%u] codec[%zu] with len %u", bis_index, j,
405 codec_data->data_len);
Emil Gydesen40e39302022-09-05 11:29:06 +0200406
407 return false;
408 }
409
410 net_buf_simple_add_u8(buf, codec_data->data_len + sizeof(codec_data->type));
411 net_buf_simple_add_u8(buf, codec_data->type);
412 net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len);
413 }
414#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT */
415
416 /* Calculate length of codec config data */
417 len = net_buf_simple_tail(buf) - start - sizeof(len);
418 /* Update the length field */
419 *start = len;
420
421 streams_encoded++;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100422 }
423
Emil Gydesen40e39302022-09-05 11:29:06 +0200424 return true;
425}
426
Emil Gydesenbe424292023-02-25 16:47:19 +0100427static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_simple *buf)
Emil Gydesen40e39302022-09-05 11:29:06 +0200428{
429 struct bt_audio_broadcast_subgroup *subgroup;
430 uint8_t streams_encoded;
431 uint8_t subgroup_count;
432
433 /* 13 is the size of the fixed size values following this check */
434 if ((buf->size - buf->len) < MINIMUM_BASE_SIZE) {
435 return false;
436 }
437
438 subgroup_count = 0U;
439 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
440 subgroup_count++;
441 }
442
443 net_buf_simple_add_le16(buf, BT_UUID_BASIC_AUDIO_VAL);
444
445 net_buf_simple_add_le24(buf, source->qos->pd);
446 net_buf_simple_add_u8(buf, subgroup_count);
447
448 /* Since the `stream_data` is only stored in the broadcast source,
449 * we need to provide that information when encoding each subgroup
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100450 */
Emil Gydesen40e39302022-09-05 11:29:06 +0200451 streams_encoded = 0;
452 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
453 if (!encode_base_subgroup(subgroup,
454 &source->stream_data[streams_encoded],
455 &streams_encoded, buf)) {
456 return false;
457 }
458 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100459
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200460 return true;
461}
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100462
Emil Gydesenbe424292023-02-25 16:47:19 +0100463static int generate_broadcast_id(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100464{
465 bool unique;
466
467 do {
468 int err;
469
470 err = bt_rand(&source->broadcast_id,
471 BT_AUDIO_BROADCAST_ID_SIZE);
472 if (err) {
473 return err;
474 }
475
476 /* Ensure uniqueness */
477 unique = true;
478 for (int i = 0; i < ARRAY_SIZE(broadcast_sources); i++) {
479 if (&broadcast_sources[i] == source) {
480 continue;
481 }
482
483 if (broadcast_sources[i].broadcast_id == source->broadcast_id) {
484 unique = false;
485 break;
486 }
487 }
488 } while (!unique);
489
490 return 0;
491}
492
Emil Gydesenbe424292023-02-25 16:47:19 +0100493static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100494{
Emil Gydesen40e39302022-09-05 11:29:06 +0200495 struct bt_audio_broadcast_subgroup *subgroup, *next_subgroup;
Emil Gydesen5628b292022-03-11 16:20:31 +0100496
Emil Gydesen40e39302022-09-05 11:29:06 +0200497 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup,
498 next_subgroup, _node) {
499 struct bt_audio_stream *stream, *next_stream;
Emil Gydesen468bd4d2022-03-11 14:58:51 +0100500
Emil Gydesen40e39302022-09-05 11:29:06 +0200501 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream,
502 next_stream, _node) {
503 bt_audio_iso_unbind_ep(stream->ep->iso, stream->ep);
504 stream->ep->stream = NULL;
505 stream->ep = NULL;
506 stream->codec = NULL;
507 stream->qos = NULL;
508 stream->group = NULL;
509
510 sys_slist_remove(&subgroup->streams, NULL,
511 &stream->_node);
512 }
513 sys_slist_remove(&source->subgroups, NULL, &subgroup->_node);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100514 }
515
516 (void)memset(source, 0, sizeof(*source));
517}
518
Emil Gydesenbe424292023-02-25 16:47:19 +0100519static bool valid_create_param(const struct bt_bap_broadcast_source_create_param *param)
Emil Gydesen40e39302022-09-05 11:29:06 +0200520{
521 const struct bt_codec_qos *qos;
522
523 CHECKIF(param == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100524 LOG_DBG("param is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200525 return false;
526 }
527
528 CHECKIF(param->params_count == 0U) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100529 LOG_DBG("param->params_count is 0");
Emil Gydesen40e39302022-09-05 11:29:06 +0200530 return false;
531 }
532
Emil Gydesenba194972022-12-20 15:39:07 +0100533 CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL &&
534 param->packing != BT_ISO_PACKING_INTERLEAVED) {
535 LOG_DBG("param->packing %u is invalid", param->packing);
536 return false;
537 }
538
Emil Gydesen40e39302022-09-05 11:29:06 +0200539 qos = param->qos;
540 CHECKIF(qos == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100541 LOG_DBG("param->qos is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200542 return false;
543 }
544
545 CHECKIF(!bt_audio_valid_qos(qos)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100546 LOG_DBG("param->qos is invalid");
Emil Gydesen40e39302022-09-05 11:29:06 +0200547 return false;
548 }
549
550 for (size_t i = 0U; i < param->params_count; i++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100551 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200552
553 subgroup_param = &param->params[i];
554
555 CHECKIF(subgroup_param->params_count == 0U) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100556 LOG_DBG("subgroup_params[%zu].count is 0", i);
Emil Gydesen40e39302022-09-05 11:29:06 +0200557 return false;
558 }
559
560 CHECKIF(subgroup_param->codec == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100561 LOG_DBG("subgroup_params[%zu].codec is NULL", i);
Emil Gydesen40e39302022-09-05 11:29:06 +0200562 return false;
563 }
564
565 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100566 const struct bt_bap_broadcast_source_stream_param *stream_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200567
568 stream_param = &subgroup_param->params[j];
569
570 CHECKIF(stream_param->stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100571 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is NULL",
572 i, j);
Emil Gydesen40e39302022-09-05 11:29:06 +0200573 return false;
574 }
575
576 CHECKIF(stream_param->stream->group != NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100577 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is "
578 "already part of group %p",
579 i, j, stream_param->stream->group);
Emil Gydesen40e39302022-09-05 11:29:06 +0200580 return false;
581 }
582 }
583 }
584
585 return true;
586}
587
Emil Gydesenbe424292023-02-25 16:47:19 +0100588static enum bt_audio_state broadcast_source_get_state(struct bt_bap_broadcast_source *source)
Emil Gydesen40e39302022-09-05 11:29:06 +0200589{
590 struct bt_audio_broadcast_subgroup *subgroup;
591 struct bt_audio_stream *stream;
592 sys_snode_t *head_node;
593
594 if (source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100595 LOG_DBG("source is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200596 return BT_AUDIO_EP_STATE_IDLE;
597 }
598
599 if (sys_slist_is_empty(&source->subgroups)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100600 LOG_DBG("Source does not have any streams");
Emil Gydesen40e39302022-09-05 11:29:06 +0200601 return BT_AUDIO_EP_STATE_IDLE;
602 }
603
604 /* Get the first stream */
605 head_node = sys_slist_peek_head(&source->subgroups);
606 subgroup = CONTAINER_OF(head_node, struct bt_audio_broadcast_subgroup, _node);
607
608 head_node = sys_slist_peek_head(&subgroup->streams);
609 stream = CONTAINER_OF(head_node, struct bt_audio_stream, _node);
610
611 /* All streams in a broadcast source is in the same state,
612 * so we can just check the first stream
613 */
614 if (stream->ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100615 LOG_DBG("stream->ep is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200616 return BT_AUDIO_EP_STATE_IDLE;
617 }
618
619 return stream->ep->status.state;
620}
621
Emil Gydesenbe424292023-02-25 16:47:19 +0100622int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *param,
623 struct bt_bap_broadcast_source **out_source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100624{
Emil Gydesen40e39302022-09-05 11:29:06 +0200625 struct bt_audio_broadcast_subgroup *subgroup;
Emil Gydesenbe424292023-02-25 16:47:19 +0100626 struct bt_bap_broadcast_source *source;
Emil Gydesen40e39302022-09-05 11:29:06 +0200627 struct bt_codec_qos *qos;
628 size_t stream_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100629 uint8_t index;
630 int err;
631
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100632 CHECKIF(out_source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100633 LOG_DBG("out_source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100634 return -EINVAL;
635 }
636 /* Set out_source to NULL until the source has actually been created */
637 *out_source = NULL;
638
Emil Gydesen40e39302022-09-05 11:29:06 +0200639 if (!valid_create_param(param)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100640 LOG_DBG("Invalid parameters");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100641 return -EINVAL;
642 }
643
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100644 source = NULL;
645 for (index = 0; index < ARRAY_SIZE(broadcast_sources); index++) {
Emil Gydesen40e39302022-09-05 11:29:06 +0200646 if (sys_slist_is_empty(&broadcast_sources[index].subgroups)) { /* Find free entry */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100647 source = &broadcast_sources[index];
648 break;
649 }
650 }
651
652 if (source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100653 LOG_DBG("Could not allocate any more broadcast sources");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100654 return -ENOMEM;
655 }
656
Emil Gydesen40e39302022-09-05 11:29:06 +0200657 stream_count = 0U;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100658
Emil Gydesen40e39302022-09-05 11:29:06 +0200659 qos = param->qos;
660 /* Go through all subgroups and streams and setup each setup with an
661 * endpoint
662 */
663 for (size_t i = 0U; i < param->params_count; i++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100664 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200665
666 subgroup_param = &param->params[i];
667
668 subgroup = broadcast_source_new_subgroup(index);
669 if (subgroup == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100670 LOG_DBG("Could not allocate new broadcast subgroup");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100671 broadcast_source_cleanup(source);
Emil Gydesen40e39302022-09-05 11:29:06 +0200672 return -ENOMEM;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100673 }
674
Emil Gydesen40e39302022-09-05 11:29:06 +0200675 subgroup->codec = subgroup_param->codec;
676 sys_slist_append(&source->subgroups, &subgroup->_node);
677
678 /* Check that we are not above the maximum BIS count */
679 if (subgroup_param->params_count + stream_count > BROADCAST_STREAM_CNT) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100680 LOG_DBG("Cannot create broadcaster with %zu streams", stream_count);
Emil Gydesen40e39302022-09-05 11:29:06 +0200681 broadcast_source_cleanup(source);
682
683 return -ENOMEM;
684 }
685
686 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100687 const struct bt_bap_broadcast_source_stream_param *stream_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200688 struct bt_audio_stream *stream;
689
690 stream_param = &subgroup_param->params[j];
691 stream = stream_param->stream;
692
693 err = broadcast_source_setup_stream(index, stream,
694 subgroup_param->codec,
695 qos, source);
696 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100697 LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
Emil Gydesen40e39302022-09-05 11:29:06 +0200698 broadcast_source_cleanup(source);
699 return err;
700 }
701
702 /* Store the BIS specific codec configuration data in
703 * the broadcast source. It is stored in the broadcast
704 * source, instead of the stream object, as this is
705 * only relevant for the broadcast source, and not used
706 * for unicast or broadcast sink.
707 */
708 (void)memcpy(source->stream_data[stream_count].data,
709 stream_param->data,
710 stream_param->data_count * sizeof(*stream_param->data));
711 source->stream_data[stream_count].data_count = stream_param->data_count;
712
713 sys_slist_append(&subgroup->streams, &stream->_node);
714 stream_count++;
715 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100716 }
717
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100718 err = generate_broadcast_id(source);
719 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100720 LOG_DBG("Could not generate broadcast id: %d", err);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100721 return err;
722 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100723
Emil Gydesen40e39302022-09-05 11:29:06 +0200724 /* Finalize state changes and store information */
725 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
726 struct bt_audio_stream *stream;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100727
Emil Gydesen40e39302022-09-05 11:29:06 +0200728 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
729 broadcast_source_set_ep_state(stream->ep,
730 BT_AUDIO_EP_STATE_QOS_CONFIGURED);
731 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100732 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100733 source->qos = qos;
Emil Gydesenba194972022-12-20 15:39:07 +0100734 source->packing = param->packing;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100735
Emil Gydesen8d86fa02022-12-13 21:03:14 +0100736 source->encryption = param->encryption;
737 if (source->encryption) {
738 (void)memcpy(source->broadcast_code, param->broadcast_code,
739 sizeof(source->broadcast_code));
740 }
741
Théo Battrele458f5a2022-11-02 14:31:13 +0100742 LOG_DBG("Broadcasting with ID 0x%6X", source->broadcast_id);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100743
744 *out_source = source;
745
746 return 0;
747}
748
Emil Gydesenbe424292023-02-25 16:47:19 +0100749int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, struct bt_codec *codec,
750 struct bt_codec_qos *qos)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100751{
Emil Gydesen40e39302022-09-05 11:29:06 +0200752 struct bt_audio_broadcast_subgroup *subgroup;
753 enum bt_audio_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100754 struct bt_audio_stream *stream;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100755
756 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100757 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100758 return -EINVAL;
759 }
760
Emil Gydesen40e39302022-09-05 11:29:06 +0200761 broadcast_state = broadcast_source_get_state(source);
762 if (broadcast_source_get_state(source) != BT_AUDIO_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100763 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100764 return -EBADMSG;
765 }
766
Emil Gydesen40e39302022-09-05 11:29:06 +0200767 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
768 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
Emil Gydesene5890fc2023-01-24 14:41:17 +0100769 struct bt_iso_chan_io_qos *iso_qos;
770
771 iso_qos = stream->ep->iso->chan.qos->tx;
772
Emil Gydesen40e39302022-09-05 11:29:06 +0200773 bt_audio_stream_attach(NULL, stream, stream->ep, codec);
Emil Gydesene5890fc2023-01-24 14:41:17 +0100774
775 bt_audio_codec_qos_to_iso_qos(iso_qos, qos);
776 bt_audio_codec_to_iso_path(iso_qos->path, codec);
777 stream->qos = qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200778 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100779 }
780
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100781 source->qos = qos;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100782
783 return 0;
784}
785
Emil Gydesen1424df42022-06-28 20:09:13 +0200786static void broadcast_source_store_metadata(struct bt_codec *codec,
787 const struct bt_codec_data meta[],
788 size_t meta_count)
789{
790 size_t old_meta_count;
791
792 old_meta_count = codec->meta_count;
793
794 /* Update metadata */
795 codec->meta_count = meta_count;
796 (void)memcpy(codec->meta, meta, meta_count * sizeof(*meta));
797 if (old_meta_count > meta_count) {
798 size_t meta_count_diff = old_meta_count - meta_count;
799
800 /* If we previously had more metadata entries we reset the
801 * data that was not overwritten by the new metadata
802 */
803 (void)memset(&codec->meta[meta_count],
804 0, meta_count_diff * sizeof(*meta));
805 }
806}
807
Emil Gydesenbe424292023-02-25 16:47:19 +0100808int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
809 const struct bt_codec_data meta[], size_t meta_count)
Emil Gydesen1424df42022-06-28 20:09:13 +0200810{
811 struct bt_audio_broadcast_subgroup *subgroup;
812 enum bt_audio_state broadcast_state;
813
814 CHECKIF(source == NULL) {
815 LOG_DBG("source is NULL");
816
817 return -EINVAL;
818 }
819
820 CHECKIF((meta == NULL && meta_count != 0) ||
821 (meta != NULL && meta_count == 0)) {
822 LOG_DBG("Invalid metadata combination: %p %zu",
823 meta, meta_count);
824
825 return -EINVAL;
826 }
827
828 CHECKIF(meta_count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) {
829 LOG_DBG("Invalid meta_count: %zu (max %d)",
830 meta_count, CONFIG_BT_CODEC_MAX_METADATA_COUNT);
831
832 return -EINVAL;
833 }
834
835 for (size_t i = 0; i < meta_count; i++) {
836 CHECKIF(meta[i].data.data_len > sizeof(meta[i].value)) {
837 LOG_DBG("Invalid meta[%zu] data_len %u",
838 i, meta[i].data.data_len);
839
840 return -EINVAL;
841 }
842 }
843 broadcast_state = broadcast_source_get_state(source);
844 if (broadcast_source_get_state(source) != BT_AUDIO_EP_STATE_STREAMING) {
845 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
846
847 return -EBADMSG;
848 }
849
850 /* TODO: We should probably find a way to update the metadata
851 * for each subgroup individually
852 */
853 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
854 broadcast_source_store_metadata(subgroup->codec, meta, meta_count);
855 }
856
857 return 0;
858}
859
Emil Gydesenbe424292023-02-25 16:47:19 +0100860int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100861{
Emil Gydesen40e39302022-09-05 11:29:06 +0200862 struct bt_iso_chan *bis[BROADCAST_STREAM_CNT];
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100863 struct bt_iso_big_create_param param = { 0 };
Emil Gydesen40e39302022-09-05 11:29:06 +0200864 struct bt_audio_broadcast_subgroup *subgroup;
865 enum bt_audio_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100866 struct bt_audio_stream *stream;
Emil Gydesen40e39302022-09-05 11:29:06 +0200867 size_t bis_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100868 int err;
869
870 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100871 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100872 return -EINVAL;
873 }
874
Emil Gydesen40e39302022-09-05 11:29:06 +0200875 broadcast_state = broadcast_source_get_state(source);
876 if (broadcast_source_get_state(source) != BT_AUDIO_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100877 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100878 return -EBADMSG;
879 }
880
Emil Gydesen40e39302022-09-05 11:29:06 +0200881 bis_count = 0;
882 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
883 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
884 bis[bis_count++] = bt_audio_stream_iso_chan_get(stream);
885 }
886 }
887
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100888 /* Create BIG */
Emil Gydesen40e39302022-09-05 11:29:06 +0200889 param.num_bis = bis_count;
890 param.bis_channels = bis;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100891 param.framing = source->qos->framing;
Emil Gydesenba194972022-12-20 15:39:07 +0100892 param.packing = source->packing;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100893 param.interval = source->qos->interval;
894 param.latency = source->qos->latency;
Emil Gydesen8d86fa02022-12-13 21:03:14 +0100895 param.encryption = source->encryption;
896 if (param.encryption) {
897 (void)memcpy(param.bcode, source->broadcast_code,
898 sizeof(param.bcode));
899 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100900
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200901 err = bt_iso_big_create(adv, &param, &source->big);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100902 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100903 LOG_DBG("Failed to create BIG: %d", err);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100904 return err;
905 }
906
Emil Gydesen40e39302022-09-05 11:29:06 +0200907 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
908 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
909 struct bt_audio_ep *ep = stream->ep;
Emil Gydesen05ace182022-06-03 10:48:19 +0200910
Emil Gydesen40e39302022-09-05 11:29:06 +0200911 broadcast_source_set_ep_state(ep, BT_AUDIO_EP_STATE_ENABLING);
912 }
Emil Gydesen05ace182022-06-03 10:48:19 +0200913 }
914
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100915 return 0;
916}
917
Emil Gydesenbe424292023-02-25 16:47:19 +0100918int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100919{
Emil Gydesen40e39302022-09-05 11:29:06 +0200920 enum bt_audio_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100921 int err;
922
923 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100924 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100925 return -EINVAL;
926 }
927
Emil Gydesen40e39302022-09-05 11:29:06 +0200928 broadcast_state = broadcast_source_get_state(source);
929 if (broadcast_state != BT_AUDIO_EP_STATE_STREAMING &&
930 broadcast_state != BT_AUDIO_EP_STATE_ENABLING) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100931 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100932 return -EBADMSG;
933 }
934
935 if (source->big == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100936 LOG_DBG("Source is not started");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100937 return -EALREADY;
938 }
939
940 err = bt_iso_big_terminate(source->big);
941 if (err) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100942 LOG_DBG("Failed to terminate BIG (err %d)", err);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100943 return err;
944 }
945
946 source->big = NULL;
947
948 return 0;
949}
950
Emil Gydesenbe424292023-02-25 16:47:19 +0100951int bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100952{
Emil Gydesen40e39302022-09-05 11:29:06 +0200953 enum bt_audio_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100954
955 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100956 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100957 return -EINVAL;
958 }
959
Emil Gydesen40e39302022-09-05 11:29:06 +0200960 broadcast_state = broadcast_source_get_state(source);
961 if (broadcast_state != BT_AUDIO_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100962 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesen468bd4d2022-03-11 14:58:51 +0100963 return -EBADMSG;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100964 }
965
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100966 /* Reset the broadcast source */
967 broadcast_source_cleanup(source);
968
969 return 0;
970}
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200971
Emil Gydesenbe424292023-02-25 16:47:19 +0100972int bt_bap_broadcast_source_get_id(const struct bt_bap_broadcast_source *source,
973 uint32_t *const broadcast_id)
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200974{
975 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100976 LOG_DBG("source is NULL");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200977 return -EINVAL;
978 }
979
980 CHECKIF(broadcast_id == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100981 LOG_DBG("broadcast_id is NULL");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200982 return -EINVAL;
983 }
984
985 *broadcast_id = source->broadcast_id;
986
987 return 0;
988}
989
Emil Gydesenbe424292023-02-25 16:47:19 +0100990int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,
991 struct net_buf_simple *base_buf)
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200992{
Emil Gydesen40e39302022-09-05 11:29:06 +0200993 if (!encode_base(source, base_buf)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100994 LOG_DBG("base_buf %p with size %u not large enough", base_buf, base_buf->size);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200995
996 return -EMSGSIZE;
997 }
998
999 return 0;
1000}