blob: 26b79b0466624e2de5d596e67866ef9335b9a7c9 [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 Gydesen77853f42023-02-27 15:32:52 +010017#include <zephyr/bluetooth/audio/bap.h>
Emil Gydesenab87e0a2022-01-10 15:06:08 +010018
Théo Battrele458f5a2022-11-02 14:31:13 +010019#include <zephyr/logging/log.h>
Emil Gydesenbe424292023-02-25 16:47:19 +010020LOG_MODULE_REGISTER(bt_bap_broadcast_source, CONFIG_BT_BAP_BROADCAST_SOURCE_LOG_LEVEL);
Emil Gydesenab87e0a2022-01-10 15:06:08 +010021
Emil Gydesen7fc05192023-02-20 14:33:43 +010022#include "bap_iso.h"
23#include "bap_endpoint.h"
Emil Gydesenab87e0a2022-01-10 15:06:08 +010024
Emil Gydesen099c1382023-03-01 11:57:11 +010025struct bt_bap_broadcast_subgroup {
Emil Gydesen40e39302022-09-05 11:29:06 +020026 /* The streams used to create the broadcast source */
27 sys_slist_t streams;
28
29 /* The codec of the subgroup */
Emil Gydesen69f7fd92023-05-16 14:16:14 +020030 struct bt_audio_codec_cfg *codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +020031
32 /* List node */
33 sys_snode_t _node;
34};
35
Emil Gydesen33268632023-03-01 11:18:25 +010036static struct bt_bap_ep broadcast_source_eps[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
37 [BROADCAST_STREAM_CNT];
Emil Gydesen099c1382023-03-01 11:57:11 +010038static struct bt_bap_broadcast_subgroup
Emil Gydesenbe424292023-02-25 16:47:19 +010039 broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
40 [CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
41static struct bt_bap_broadcast_source broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
Emil Gydesenab87e0a2022-01-10 15:06:08 +010042
Emil Gydesen40e39302022-09-05 11:29:06 +020043/**
44 * 2 octets UUID
45 * 3 octets presentation delay
46 * 1 octet number of subgroups
47 *
48 * Each subgroup then has
49 * 1 octet of number of BIS
50 * 5 octets of Codec_ID
51 * 1 octet codec specific configuration len
52 * 0-n octets of codec specific configuration
53 * 1 octet metadata len
54 * 0-n octets of metadata
55 *
56 * For each BIS in the subgroup there is
57 * 1 octet for the BIS index
58 * 1 octet codec specific configuration len
59 * 0-n octets of codec specific configuration
60 *
61 * For a minimal BASE with 1 subgroup and 1 BIS without and other data the
62 * total comes to 16
63 */
64#define MINIMUM_BASE_SIZE 16
65
Emil Gydesen33268632023-03-01 11:18:25 +010066static void broadcast_source_set_ep_state(struct bt_bap_ep *ep, uint8_t state)
Emil Gydesenab87e0a2022-01-10 15:06:08 +010067{
68 uint8_t old_state;
69
70 old_state = ep->status.state;
71
Emil Gydesen33268632023-03-01 11:18:25 +010072 LOG_DBG("ep %p id 0x%02x %s -> %s", ep, ep->status.id, bt_bap_ep_state_str(old_state),
73 bt_bap_ep_state_str(state));
Emil Gydesenab87e0a2022-01-10 15:06:08 +010074
75 switch (old_state) {
Emil Gydesen33268632023-03-01 11:18:25 +010076 case BT_BAP_EP_STATE_IDLE:
77 if (state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +010078 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesenab87e0a2022-01-10 15:06:08 +010079 return;
80 }
81 break;
Emil Gydesen33268632023-03-01 11:18:25 +010082 case BT_BAP_EP_STATE_QOS_CONFIGURED:
83 if (state != BT_BAP_EP_STATE_IDLE && state != BT_BAP_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;
Emil Gydesen33268632023-03-01 11:18:25 +010088 case BT_BAP_EP_STATE_ENABLING:
89 if (state != BT_BAP_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 Gydesen33268632023-03-01 11:18:25 +010094 case BT_BAP_EP_STATE_STREAMING:
95 if (state != BT_BAP_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 Gydesen33268632023-03-01 11:18:25 +0100102 bt_bap_ep_state_str(old_state));
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100103 return;
104 }
105
106 ep->status.state = state;
Emil Gydesenc66f2102023-05-09 13:51:02 +0200107}
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100108
Emil Gydesenc66f2102023-05-09 13:51:02 +0200109static void broadcast_source_set_state(struct bt_bap_broadcast_source *source, uint8_t state)
110{
111 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100112
Emil Gydesenc66f2102023-05-09 13:51:02 +0200113 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
114 struct bt_bap_stream *stream;
115
116 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
117 broadcast_source_set_ep_state(stream->ep, state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100118 }
119 }
120}
121
Emil Gydesen4518c192022-03-07 14:18:26 +0100122static void broadcast_source_iso_sent(struct bt_iso_chan *chan)
123{
Emil Gydesene2765d72023-03-01 11:52:29 +0100124 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
Emil Gydesen77853f42023-02-27 15:32:52 +0100125 const struct bt_bap_stream_ops *ops;
126 struct bt_bap_stream *stream;
Emil Gydesen33268632023-03-01 11:18:25 +0100127 struct bt_bap_ep *ep = iso->tx.ep;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200128
129 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100130 LOG_ERR("iso %p not bound with ep", chan);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200131 return;
132 }
133
134 stream = ep->stream;
135 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100136 LOG_ERR("No stream for ep %p", ep);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200137 return;
138 }
139
140 ops = stream->ops;
Emil Gydesen4518c192022-03-07 14:18:26 +0100141
Emil Gydesen77853f42023-02-27 15:32:52 +0100142 if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100143 LOG_DBG("stream %p ep %p", stream, stream->ep);
Emil Gydesen65f130b2022-09-26 17:15:24 +0200144 }
Emil Gydesen4518c192022-03-07 14:18:26 +0100145
146 if (ops != NULL && ops->sent != NULL) {
Emil Gydesen9b154262022-05-24 13:59:45 +0200147 ops->sent(stream);
Emil Gydesen4518c192022-03-07 14:18:26 +0100148 }
149}
150
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100151static void broadcast_source_iso_connected(struct bt_iso_chan *chan)
152{
Emil Gydesene2765d72023-03-01 11:52:29 +0100153 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
Emil Gydesen77853f42023-02-27 15:32:52 +0100154 const struct bt_bap_stream_ops *ops;
155 struct bt_bap_stream *stream;
Emil Gydesen33268632023-03-01 11:18:25 +0100156 struct bt_bap_ep *ep = iso->tx.ep;
Emil Gydesene8e19202022-02-14 14:18:03 +0100157
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200158 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100159 LOG_ERR("iso %p not bound with ep", chan);
Emil Gydesen9b154262022-05-24 13:59:45 +0200160 return;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200161 }
162
163 stream = ep->stream;
164 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100165 LOG_ERR("No stream for ep %p", ep);
Emil Gydesene8e19202022-02-14 14:18:03 +0100166 return;
167 }
168
Emil Gydesen9b154262022-05-24 13:59:45 +0200169 ops = stream->ops;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100170
Théo Battrele458f5a2022-11-02 14:31:13 +0100171 LOG_DBG("stream %p ep %p", stream, ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100172
Emil Gydesen33268632023-03-01 11:18:25 +0100173 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100174
Emil Gydesen628b54a2022-02-02 17:12:30 +0100175 if (ops != NULL && ops->started != NULL) {
Emil Gydesen9b154262022-05-24 13:59:45 +0200176 ops->started(stream);
Emil Gydesen102dcca2022-01-20 15:03:00 +0100177 } else {
Emil Gydesen68a4d0f2023-08-31 15:30:31 +0200178 LOG_WRN("No callback for started set");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100179 }
180}
181
182static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
183{
Emil Gydesene2765d72023-03-01 11:52:29 +0100184 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
Emil Gydesen77853f42023-02-27 15:32:52 +0100185 const struct bt_bap_stream_ops *ops;
186 struct bt_bap_stream *stream;
Emil Gydesen33268632023-03-01 11:18:25 +0100187 struct bt_bap_ep *ep = iso->tx.ep;
Emil Gydesene8e19202022-02-14 14:18:03 +0100188
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200189 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100190 LOG_ERR("iso %p not bound with ep", chan);
Emil Gydesen9b154262022-05-24 13:59:45 +0200191 return;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200192 }
193
194 stream = ep->stream;
195 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100196 LOG_ERR("No stream for ep %p", ep);
Emil Gydesene8e19202022-02-14 14:18:03 +0100197 return;
198 }
199
Emil Gydesen9b154262022-05-24 13:59:45 +0200200 ops = stream->ops;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100201
Théo Battrele458f5a2022-11-02 14:31:13 +0100202 LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100203
Emil Gydesen33268632023-03-01 11:18:25 +0100204 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100205
Emil Gydesen628b54a2022-02-02 17:12:30 +0100206 if (ops != NULL && ops->stopped != NULL) {
Emil Gydesen59a9f8a2023-03-02 15:01:00 +0100207 ops->stopped(stream, reason);
Emil Gydesen102dcca2022-01-20 15:03:00 +0100208 } else {
Théo Battrele458f5a2022-11-02 14:31:13 +0100209 LOG_WRN("No callback for stopped set");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100210 }
211}
212
213static struct bt_iso_chan_ops broadcast_source_iso_ops = {
Emil Gydesen4518c192022-03-07 14:18:26 +0100214 .sent = broadcast_source_iso_sent,
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100215 .connected = broadcast_source_iso_connected,
216 .disconnected = broadcast_source_iso_disconnected,
217};
218
Emil Gydesen33268632023-03-01 11:18:25 +0100219bool bt_bap_ep_is_broadcast_src(const struct bt_bap_ep *ep)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100220{
221 for (int i = 0; i < ARRAY_SIZE(broadcast_source_eps); i++) {
222 if (PART_OF_ARRAY(broadcast_source_eps[i], ep)) {
223 return true;
224 }
225 }
226
227 return false;
228}
229
Emil Gydesen33268632023-03-01 11:18:25 +0100230static void broadcast_source_ep_init(struct bt_bap_ep *ep)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100231{
Théo Battrele458f5a2022-11-02 14:31:13 +0100232 LOG_DBG("ep %p", ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100233
234 (void)memset(ep, 0, sizeof(*ep));
Emil Gydesen6191a762022-03-29 18:20:10 +0200235 ep->dir = BT_AUDIO_DIR_SOURCE;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200236 ep->iso = NULL;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100237}
238
Emil Gydesen33268632023-03-01 11:18:25 +0100239static struct bt_bap_ep *broadcast_source_new_ep(uint8_t index)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100240{
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100241 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_eps[index]); i++) {
Emil Gydesen33268632023-03-01 11:18:25 +0100242 struct bt_bap_ep *ep = &broadcast_source_eps[index][i];
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100243
244 /* If ep->stream is NULL the endpoint is unallocated */
245 if (ep->stream == NULL) {
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200246 broadcast_source_ep_init(ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100247 return ep;
248 }
249 }
250
251 return NULL;
252}
253
Emil Gydesen099c1382023-03-01 11:57:11 +0100254static struct bt_bap_broadcast_subgroup *broadcast_source_new_subgroup(uint8_t index)
Emil Gydesen40e39302022-09-05 11:29:06 +0200255{
256 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_subgroups[index]); i++) {
Emil Gydesen099c1382023-03-01 11:57:11 +0100257 struct bt_bap_broadcast_subgroup *subgroup = &broadcast_source_subgroups[index][i];
Emil Gydesen40e39302022-09-05 11:29:06 +0200258
259 if (sys_slist_is_empty(&subgroup->streams)) {
260 return subgroup;
261 }
262 }
263
264 return NULL;
265}
266
Emil Gydesen77853f42023-02-27 15:32:52 +0100267static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *stream,
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200268 struct bt_audio_codec_cfg *codec_cfg,
269 struct bt_audio_codec_qos *qos,
Emil Gydesenbe424292023-02-25 16:47:19 +0100270 struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100271{
Emil Gydesene2765d72023-03-01 11:52:29 +0100272 struct bt_bap_iso *iso;
Emil Gydesen33268632023-03-01 11:18:25 +0100273 struct bt_bap_ep *ep;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100274
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100275 ep = broadcast_source_new_ep(index);
276 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100277 LOG_DBG("Could not allocate new broadcast endpoint");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100278 return -ENOMEM;
279 }
280
Emil Gydesene2765d72023-03-01 11:52:29 +0100281 iso = bt_bap_iso_new();
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200282 if (iso == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100283 LOG_DBG("Could not allocate iso");
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200284 return -ENOMEM;
285 }
286
Emil Gydesene2765d72023-03-01 11:52:29 +0100287 bt_bap_iso_init(iso, &broadcast_source_iso_ops);
288 bt_bap_iso_bind_ep(iso, ep);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200289
290 bt_audio_codec_qos_to_iso_qos(iso->chan.qos->tx, qos);
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200291 bt_audio_codec_cfg_to_iso_path(iso->chan.qos->tx->path, codec_cfg);
Emil Gydesen84c01bb2023-01-23 14:33:54 +0100292#if defined(CONFIG_BT_ISO_TEST_PARAMS)
293 iso->chan.qos->num_subevents = qos->num_subevents;
294#endif /* CONFIG_BT_ISO_TEST_PARAMS */
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200295
Emil Gydesene2765d72023-03-01 11:52:29 +0100296 bt_bap_iso_unref(iso);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200297
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200298 bt_bap_stream_attach(NULL, stream, ep, codec_cfg);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100299 stream->qos = qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200300 ep->broadcast_source = source;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100301
302 return 0;
303}
304
Emil Gydesen099c1382023-03-01 11:57:11 +0100305static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
306 struct bt_audio_broadcast_stream_data *stream_data,
307 uint8_t *streams_encoded, struct net_buf_simple *buf)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100308{
Emil Gydesen77853f42023-02-27 15:32:52 +0100309 struct bt_bap_stream *stream;
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200310 const struct bt_audio_codec_cfg *codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200311 uint8_t stream_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100312 uint8_t len;
313
Emil Gydesen40e39302022-09-05 11:29:06 +0200314 stream_count = 0;
315 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
316 stream_count++;
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200317 }
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200318
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200319 codec_cfg = subgroup->codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200320
321 net_buf_simple_add_u8(buf, stream_count);
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200322 net_buf_simple_add_u8(buf, codec_cfg->id);
323 net_buf_simple_add_le16(buf, codec_cfg->cid);
324 net_buf_simple_add_le16(buf, codec_cfg->vid);
Emil Gydesen40e39302022-09-05 11:29:06 +0200325
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200326 net_buf_simple_add_u8(buf, codec_cfg->data_len);
327#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
328 if ((buf->size - buf->len) < codec_cfg->data_len) {
329 LOG_DBG("No room for config data: %zu", codec_cfg->data_len);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200330
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200331 return false;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100332 }
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200333 net_buf_simple_add_mem(buf, codec_cfg->data, codec_cfg->data_len);
334#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100335
Emil Gydesen40e39302022-09-05 11:29:06 +0200336 if ((buf->size - buf->len) < sizeof(len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100337 LOG_DBG("No room for metadata length");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200338
339 return false;
340 }
341
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200342 net_buf_simple_add_u8(buf, codec_cfg->meta_len);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100343
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200344#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
345 if ((buf->size - buf->len) < codec_cfg->meta_len) {
346 LOG_DBG("No room for metadata data: %zu", codec_cfg->meta_len);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200347
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200348 return false;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100349 }
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200350
351 net_buf_simple_add_mem(buf, codec_cfg->meta, codec_cfg->meta_len);
352#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100353
354 /* Create BIS index bitfield */
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200355 for (uint8_t i = 0U; i < stream_count; i++) {
Emil Gydesenaf953a12023-10-04 23:31:28 +0200356 /* Set the bis_index to *streams_encoded plus 1 as the indexes start from 1 */
357 const uint8_t bis_index = *streams_encoded + 1;
358
Emil Gydesen40e39302022-09-05 11:29:06 +0200359 if ((buf->size - buf->len) < (sizeof(bis_index) + sizeof(uint8_t))) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100360 LOG_DBG("No room for BIS[%d] index", i);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200361
362 return false;
363 }
364
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100365 net_buf_simple_add_u8(buf, bis_index);
Emil Gydesen40e39302022-09-05 11:29:06 +0200366
367 if ((buf->size - buf->len) < sizeof(len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100368 LOG_DBG("No room for bis codec config length");
Emil Gydesen40e39302022-09-05 11:29:06 +0200369
370 return false;
371 }
372
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200373 net_buf_simple_add_u8(buf, stream_data[i].data_len);
374#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
375 if ((buf->size - buf->len) < stream_data[i].data_len) {
376 LOG_DBG("No room for BIS[%u] data: %zu", i, stream_data[i].data_len);
Emil Gydesen40e39302022-09-05 11:29:06 +0200377
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200378 return false;
Emil Gydesen40e39302022-09-05 11:29:06 +0200379 }
Emil Gydesen40e39302022-09-05 11:29:06 +0200380
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200381 net_buf_simple_add_mem(buf, stream_data[i].data, stream_data[i].data_len);
382#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
Emil Gydesen40e39302022-09-05 11:29:06 +0200383
Emil Gydesenaf953a12023-10-04 23:31:28 +0200384 (*streams_encoded)++;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100385 }
386
Emil Gydesen40e39302022-09-05 11:29:06 +0200387 return true;
388}
389
Emil Gydesenbe424292023-02-25 16:47:19 +0100390static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_simple *buf)
Emil Gydesen40e39302022-09-05 11:29:06 +0200391{
Emil Gydesen099c1382023-03-01 11:57:11 +0100392 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen40e39302022-09-05 11:29:06 +0200393 uint8_t streams_encoded;
394 uint8_t subgroup_count;
395
396 /* 13 is the size of the fixed size values following this check */
397 if ((buf->size - buf->len) < MINIMUM_BASE_SIZE) {
398 return false;
399 }
400
401 subgroup_count = 0U;
402 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
403 subgroup_count++;
404 }
405
406 net_buf_simple_add_le16(buf, BT_UUID_BASIC_AUDIO_VAL);
407
408 net_buf_simple_add_le24(buf, source->qos->pd);
409 net_buf_simple_add_u8(buf, subgroup_count);
410
411 /* Since the `stream_data` is only stored in the broadcast source,
412 * we need to provide that information when encoding each subgroup
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100413 */
Emil Gydesen40e39302022-09-05 11:29:06 +0200414 streams_encoded = 0;
415 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
416 if (!encode_base_subgroup(subgroup,
417 &source->stream_data[streams_encoded],
418 &streams_encoded, buf)) {
419 return false;
420 }
421 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100422
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200423 return true;
424}
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100425
Emil Gydesenbe424292023-02-25 16:47:19 +0100426static int generate_broadcast_id(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100427{
428 bool unique;
429
430 do {
431 int err;
432
433 err = bt_rand(&source->broadcast_id,
434 BT_AUDIO_BROADCAST_ID_SIZE);
435 if (err) {
436 return err;
437 }
438
439 /* Ensure uniqueness */
440 unique = true;
441 for (int i = 0; i < ARRAY_SIZE(broadcast_sources); i++) {
442 if (&broadcast_sources[i] == source) {
443 continue;
444 }
445
446 if (broadcast_sources[i].broadcast_id == source->broadcast_id) {
447 unique = false;
448 break;
449 }
450 }
451 } while (!unique);
452
453 return 0;
454}
455
Emil Gydesenbe424292023-02-25 16:47:19 +0100456static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100457{
Emil Gydesen099c1382023-03-01 11:57:11 +0100458 struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup;
Emil Gydesen5628b292022-03-11 16:20:31 +0100459
Emil Gydesen40e39302022-09-05 11:29:06 +0200460 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup,
461 next_subgroup, _node) {
Emil Gydesen77853f42023-02-27 15:32:52 +0100462 struct bt_bap_stream *stream, *next_stream;
Emil Gydesen468bd4d2022-03-11 14:58:51 +0100463
Emil Gydesen40e39302022-09-05 11:29:06 +0200464 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream,
465 next_stream, _node) {
Emil Gydesene2765d72023-03-01 11:52:29 +0100466 bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
Emil Gydesen40e39302022-09-05 11:29:06 +0200467 stream->ep->stream = NULL;
468 stream->ep = NULL;
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200469 stream->codec_cfg = NULL;
Emil Gydesen40e39302022-09-05 11:29:06 +0200470 stream->qos = NULL;
471 stream->group = NULL;
472
473 sys_slist_remove(&subgroup->streams, NULL,
474 &stream->_node);
475 }
476 sys_slist_remove(&source->subgroups, NULL, &subgroup->_node);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100477 }
478
479 (void)memset(source, 0, sizeof(*source));
480}
481
Emil Gydesend327b162023-08-17 13:15:12 +0200482static bool valid_broadcast_source_param(const struct bt_bap_broadcast_source_param *param,
483 const struct bt_bap_broadcast_source *source)
Emil Gydesen40e39302022-09-05 11:29:06 +0200484{
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200485 const struct bt_audio_codec_qos *qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200486
487 CHECKIF(param == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100488 LOG_DBG("param is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200489 return false;
490 }
491
Emil Gydesen117f6292023-05-09 14:05:36 +0200492 CHECKIF(!IN_RANGE(param->params_count, 1U, CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT)) {
493 LOG_DBG("param->params_count %zu is invalid", param->params_count);
Emil Gydesen40e39302022-09-05 11:29:06 +0200494 return false;
495 }
496
Emil Gydesenba194972022-12-20 15:39:07 +0100497 CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL &&
498 param->packing != BT_ISO_PACKING_INTERLEAVED) {
499 LOG_DBG("param->packing %u is invalid", param->packing);
500 return false;
501 }
502
Emil Gydesen40e39302022-09-05 11:29:06 +0200503 qos = param->qos;
504 CHECKIF(qos == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100505 LOG_DBG("param->qos is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200506 return false;
507 }
508
Magdalena Kasenberg57784df2023-02-15 11:22:04 +0100509 CHECKIF(bt_audio_verify_qos(qos) != BT_BAP_ASCS_REASON_NONE) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100510 LOG_DBG("param->qos is invalid");
Emil Gydesen40e39302022-09-05 11:29:06 +0200511 return false;
512 }
513
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200514 CHECKIF(param->qos->rtn > BT_ISO_BROADCAST_RTN_MAX) {
515 LOG_DBG("param->qos->rtn %u invalid", param->qos->rtn);
516 return false;
517 }
518
519 CHECKIF(param->params == NULL) {
520 LOG_DBG("param->params is NULL");
521 return false;
522 }
523
524 CHECKIF(param->params_count == 0) {
525 LOG_DBG("param->params_count is 0");
526 return false;
527 }
528
Emil Gydesen40e39302022-09-05 11:29:06 +0200529 for (size_t i = 0U; i < param->params_count; i++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100530 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200531
532 subgroup_param = &param->params[i];
533
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200534 CHECKIF(subgroup_param->params == NULL) {
535 LOG_DBG("subgroup_params[%zu].params is NULL", i);
Emil Gydesen40e39302022-09-05 11:29:06 +0200536 return false;
537 }
538
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200539 CHECKIF(!IN_RANGE(subgroup_param->params_count, 1U,
540 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)) {
541 LOG_DBG("subgroup_params[%zu].count (%zu) is invalid", i,
542 subgroup_param->params_count);
543 return false;
544 }
545
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200546 CHECKIF(!bt_audio_valid_codec_cfg(subgroup_param->codec_cfg)) {
547 LOG_DBG("subgroup_params[%zu].codec_cfg is invalid", i);
Emil Gydesen40e39302022-09-05 11:29:06 +0200548 return false;
549 }
550
551 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100552 const struct bt_bap_broadcast_source_stream_param *stream_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200553
554 stream_param = &subgroup_param->params[j];
555
556 CHECKIF(stream_param->stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100557 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is NULL",
558 i, j);
Emil Gydesen40e39302022-09-05 11:29:06 +0200559 return false;
560 }
561
Emil Gydesend327b162023-08-17 13:15:12 +0200562 CHECKIF(stream_param->stream->group != NULL &&
563 stream_param->stream->group != source) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100564 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is "
565 "already part of group %p",
566 i, j, stream_param->stream->group);
Emil Gydesen40e39302022-09-05 11:29:06 +0200567 return false;
568 }
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200569
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200570 CHECKIF(stream_param->data == NULL && stream_param->data_len != 0) {
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200571 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data is "
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200572 "NULL with len %zu",
573 i, j, stream_param->data_len);
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200574 return false;
575 }
576
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200577#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
578 CHECKIF(stream_param->data_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
579 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data_len too "
580 "large: %zu > %d",
581 i, j, stream_param->data_len,
582 CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE);
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200583 return false;
584 }
Emil Gydesen40e39302022-09-05 11:29:06 +0200585 }
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200586#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
Emil Gydesen40e39302022-09-05 11:29:06 +0200587 }
588
589 return true;
590}
591
Emil Gydesen33268632023-03-01 11:18:25 +0100592static enum bt_bap_ep_state broadcast_source_get_state(struct bt_bap_broadcast_source *source)
Emil Gydesen40e39302022-09-05 11:29:06 +0200593{
Emil Gydesen099c1382023-03-01 11:57:11 +0100594 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen77853f42023-02-27 15:32:52 +0100595 struct bt_bap_stream *stream;
Emil Gydesen40e39302022-09-05 11:29:06 +0200596 sys_snode_t *head_node;
597
598 if (source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100599 LOG_DBG("source is NULL");
Emil Gydesen33268632023-03-01 11:18:25 +0100600 return BT_BAP_EP_STATE_IDLE;
Emil Gydesen40e39302022-09-05 11:29:06 +0200601 }
602
603 if (sys_slist_is_empty(&source->subgroups)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100604 LOG_DBG("Source does not have any streams");
Emil Gydesen33268632023-03-01 11:18:25 +0100605 return BT_BAP_EP_STATE_IDLE;
Emil Gydesen40e39302022-09-05 11:29:06 +0200606 }
607
608 /* Get the first stream */
609 head_node = sys_slist_peek_head(&source->subgroups);
Emil Gydesen099c1382023-03-01 11:57:11 +0100610 subgroup = CONTAINER_OF(head_node, struct bt_bap_broadcast_subgroup, _node);
Emil Gydesen40e39302022-09-05 11:29:06 +0200611
612 head_node = sys_slist_peek_head(&subgroup->streams);
Emil Gydesen77853f42023-02-27 15:32:52 +0100613 stream = CONTAINER_OF(head_node, struct bt_bap_stream, _node);
Emil Gydesen40e39302022-09-05 11:29:06 +0200614
615 /* All streams in a broadcast source is in the same state,
616 * so we can just check the first stream
617 */
618 if (stream->ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100619 LOG_DBG("stream->ep is NULL");
Emil Gydesen33268632023-03-01 11:18:25 +0100620 return BT_BAP_EP_STATE_IDLE;
Emil Gydesen40e39302022-09-05 11:29:06 +0200621 }
622
623 return stream->ep->status.state;
624}
625
Emil Gydesend327b162023-08-17 13:15:12 +0200626int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
Emil Gydesenbe424292023-02-25 16:47:19 +0100627 struct bt_bap_broadcast_source **out_source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100628{
Emil Gydesenbe424292023-02-25 16:47:19 +0100629 struct bt_bap_broadcast_source *source;
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200630 struct bt_audio_codec_qos *qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200631 size_t stream_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100632 uint8_t index;
633 int err;
634
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100635 CHECKIF(out_source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100636 LOG_DBG("out_source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100637 return -EINVAL;
638 }
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200639
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100640 /* Set out_source to NULL until the source has actually been created */
641 *out_source = NULL;
642
Emil Gydesend327b162023-08-17 13:15:12 +0200643 if (!valid_broadcast_source_param(param, NULL)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100644 LOG_DBG("Invalid parameters");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100645 return -EINVAL;
646 }
647
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100648 source = NULL;
649 for (index = 0; index < ARRAY_SIZE(broadcast_sources); index++) {
Emil Gydesen40e39302022-09-05 11:29:06 +0200650 if (sys_slist_is_empty(&broadcast_sources[index].subgroups)) { /* Find free entry */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100651 source = &broadcast_sources[index];
652 break;
653 }
654 }
655
656 if (source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100657 LOG_DBG("Could not allocate any more broadcast sources");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100658 return -ENOMEM;
659 }
660
Emil Gydesen40e39302022-09-05 11:29:06 +0200661 stream_count = 0U;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100662
Emil Gydesen40e39302022-09-05 11:29:06 +0200663 qos = param->qos;
664 /* Go through all subgroups and streams and setup each setup with an
665 * endpoint
666 */
667 for (size_t i = 0U; i < param->params_count; i++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100668 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
Emil Gydesenc66f2102023-05-09 13:51:02 +0200669 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen40e39302022-09-05 11:29:06 +0200670
671 subgroup_param = &param->params[i];
672
673 subgroup = broadcast_source_new_subgroup(index);
674 if (subgroup == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100675 LOG_DBG("Could not allocate new broadcast subgroup");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100676 broadcast_source_cleanup(source);
Emil Gydesen40e39302022-09-05 11:29:06 +0200677 return -ENOMEM;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100678 }
679
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200680 subgroup->codec_cfg = subgroup_param->codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200681 sys_slist_append(&source->subgroups, &subgroup->_node);
682
683 /* Check that we are not above the maximum BIS count */
684 if (subgroup_param->params_count + stream_count > BROADCAST_STREAM_CNT) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100685 LOG_DBG("Cannot create broadcaster with %zu streams", stream_count);
Emil Gydesen40e39302022-09-05 11:29:06 +0200686 broadcast_source_cleanup(source);
687
688 return -ENOMEM;
689 }
690
691 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100692 const struct bt_bap_broadcast_source_stream_param *stream_param;
Emil Gydesen77853f42023-02-27 15:32:52 +0100693 struct bt_bap_stream *stream;
Emil Gydesen40e39302022-09-05 11:29:06 +0200694
695 stream_param = &subgroup_param->params[j];
696 stream = stream_param->stream;
697
698 err = broadcast_source_setup_stream(index, stream,
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200699 subgroup_param->codec_cfg, qos, source);
Emil Gydesen40e39302022-09-05 11:29:06 +0200700 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100701 LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
Emil Gydesen40e39302022-09-05 11:29:06 +0200702 broadcast_source_cleanup(source);
703 return err;
704 }
705
706 /* Store the BIS specific codec configuration data in
707 * the broadcast source. It is stored in the broadcast
708 * source, instead of the stream object, as this is
709 * only relevant for the broadcast source, and not used
710 * for unicast or broadcast sink.
711 */
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200712 (void)memcpy(source->stream_data[stream_count].data, stream_param->data,
713 stream_param->data_len * sizeof(*stream_param->data));
714 source->stream_data[stream_count].data_len = stream_param->data_len;
Emil Gydesen40e39302022-09-05 11:29:06 +0200715
716 sys_slist_append(&subgroup->streams, &stream->_node);
717 stream_count++;
718 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100719 }
720
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100721 err = generate_broadcast_id(source);
722 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100723 LOG_DBG("Could not generate broadcast id: %d", err);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100724 return err;
725 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100726
Emil Gydesen40e39302022-09-05 11:29:06 +0200727 /* Finalize state changes and store information */
Emil Gydesenc66f2102023-05-09 13:51:02 +0200728 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100729 source->qos = qos;
Emil Gydesenba194972022-12-20 15:39:07 +0100730 source->packing = param->packing;
Emil Gydesen84c01bb2023-01-23 14:33:54 +0100731#if defined(CONFIG_BT_ISO_TEST_PARAMS)
732 source->irc = param->irc;
733 source->pto = param->pto;
734 source->iso_interval = param->iso_interval;
735#endif /* CONFIG_BT_ISO_TEST_PARAMS */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100736
Emil Gydesen8d86fa02022-12-13 21:03:14 +0100737 source->encryption = param->encryption;
738 if (source->encryption) {
739 (void)memcpy(source->broadcast_code, param->broadcast_code,
740 sizeof(source->broadcast_code));
741 }
742
Théo Battrele458f5a2022-11-02 14:31:13 +0100743 LOG_DBG("Broadcasting with ID 0x%6X", source->broadcast_id);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100744
745 *out_source = source;
746
747 return 0;
748}
749
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200750int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
Emil Gydesend327b162023-08-17 13:15:12 +0200751 struct bt_bap_broadcast_source_param *param)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100752{
Emil Gydesen099c1382023-03-01 11:57:11 +0100753 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen33268632023-03-01 11:18:25 +0100754 enum bt_bap_ep_state broadcast_state;
Emil Gydesend327b162023-08-17 13:15:12 +0200755 struct bt_audio_codec_qos *qos;
756 size_t subgroup_cnt;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100757
758 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100759 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100760 return -EINVAL;
761 }
762
Emil Gydesend327b162023-08-17 13:15:12 +0200763 if (!valid_broadcast_source_param(param, source)) {
764 LOG_DBG("Invalid parameters");
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200765 return -EINVAL;
766 }
767
Emil Gydesen40e39302022-09-05 11:29:06 +0200768 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +0100769 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100770 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100771 return -EBADMSG;
772 }
773
Emil Gydesend327b162023-08-17 13:15:12 +0200774 /* Verify that the parameter counts do not exceed existing number of subgroups and streams*/
775 subgroup_cnt = 0U;
Emil Gydesen40e39302022-09-05 11:29:06 +0200776 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
Emil Gydesend327b162023-08-17 13:15:12 +0200777 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param =
778 &param->params[subgroup_cnt];
779 const size_t subgroup_stream_param_cnt = subgroup_param->params_count;
780 struct bt_bap_stream *stream;
Emil Gydesene962fda2023-10-04 17:29:33 +0200781 size_t subgroup_stream_cnt = 0U;
Emil Gydesend327b162023-08-17 13:15:12 +0200782
Emil Gydesen40e39302022-09-05 11:29:06 +0200783 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
Emil Gydesene962fda2023-10-04 17:29:33 +0200784 subgroup_stream_cnt++;
Emil Gydesend327b162023-08-17 13:15:12 +0200785 }
786
787 /* Verify that the param stream is in the subgroup */
788 for (size_t i = 0U; i < subgroup_param->params_count; i++) {
789 struct bt_bap_stream *subgroup_stream;
790 struct bt_bap_stream *param_stream;
791 bool stream_in_subgroup;
792
793 param_stream = subgroup_param->params[i].stream;
794
795 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
796 if (subgroup_stream == param_stream) {
797 stream_in_subgroup = true;
798 break;
799 }
800 }
801
802 if (!stream_in_subgroup) {
803 LOG_DBG("Invalid param->params[%zu]->param[%zu].stream "
804 "not in subgroup",
805 subgroup_cnt, i);
806 return -EINVAL;
807 }
808 }
809
Emil Gydesene962fda2023-10-04 17:29:33 +0200810 if (subgroup_stream_cnt < subgroup_stream_param_cnt) {
Emil Gydesend327b162023-08-17 13:15:12 +0200811 LOG_DBG("Invalid param->params[%zu]->params_count: %zu "
812 "(only %zu streams in subgroup)",
Emil Gydesene962fda2023-10-04 17:29:33 +0200813 subgroup_cnt, subgroup_stream_param_cnt, subgroup_stream_cnt);
Emil Gydesend327b162023-08-17 13:15:12 +0200814 return -EINVAL;
815 }
816
817 subgroup_cnt++;
818 }
819
820 if (subgroup_cnt < param->params_count) {
821 LOG_DBG("Invalid param->params_count: %zu (only %zu subgroups in source)",
822 param->params_count, subgroup_cnt);
823 return -EINVAL;
824 }
825
826 qos = param->qos;
827
828 /* We update up to the first param->params_count subgroups */
829 for (size_t i = 0U; i < param->params_count; i++) {
830 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
831 struct bt_audio_codec_cfg *codec_cfg;
Emil Gydesende67ec92023-10-05 14:14:04 +0200832 struct bt_bap_stream *stream;
Emil Gydesend327b162023-08-17 13:15:12 +0200833
834 if (i == 0) {
835 subgroup =
836 SYS_SLIST_PEEK_HEAD_CONTAINER(&source->subgroups, subgroup, _node);
837 } else {
838 subgroup = SYS_SLIST_PEEK_NEXT_CONTAINER(subgroup, _node);
839 }
840
841 subgroup_param = &param->params[i];
842 codec_cfg = subgroup_param->codec_cfg;
843 subgroup->codec_cfg = codec_cfg;
844
845 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
846 const struct bt_bap_broadcast_source_stream_param *stream_param;
847 struct bt_audio_broadcast_stream_data *stream_data;
848 struct bt_bap_stream *subgroup_stream;
Emil Gydesend327b162023-08-17 13:15:12 +0200849 size_t stream_idx;
850
851 stream_param = &subgroup_param->params[j];
852 stream = stream_param->stream;
853
854 stream_idx = 0U;
855 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
856 if (subgroup_stream == stream) {
Emil Gydesend327b162023-08-17 13:15:12 +0200857 break;
858 }
859
860 stream_idx++;
861 }
Emil Gydesene5890fc2023-01-24 14:41:17 +0100862
Emil Gydesend327b162023-08-17 13:15:12 +0200863 /* Store the BIS specific codec configuration data in the broadcast source.
864 * It is stored in the broadcast* source, instead of the stream object,
865 * as this is only relevant for the broadcast source, and not used
866 * for unicast or broadcast sink.
867 */
868 stream_data = &source->stream_data[stream_idx];
869 (void)memcpy(stream_data->data, stream_param->data, stream_param->data_len);
870 stream_data->data_len = stream_param->data_len;
Emil Gydesen40e39302022-09-05 11:29:06 +0200871 }
Emil Gydesende67ec92023-10-05 14:14:04 +0200872
873 /* Apply the codec_cfg to all streams in the subgroup, and not just the ones in the
874 * params
875 */
876 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
877 struct bt_iso_chan_io_qos *iso_qos;
878
879 iso_qos = stream->ep->iso->chan.qos->tx;
880 bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg);
881 bt_audio_codec_cfg_to_iso_path(iso_qos->path, codec_cfg);
882 }
883 }
884
885 /* Finally we apply the new qos and to all streams */
886 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
887 struct bt_bap_stream *stream;
888
889 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
890 struct bt_iso_chan_io_qos *iso_qos;
891
892 iso_qos = stream->ep->iso->chan.qos->tx;
893 bt_audio_codec_qos_to_iso_qos(iso_qos, qos);
894 stream->qos = qos;
895 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100896 }
897
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100898 source->qos = qos;
899
900 return 0;
901}
902
Emil Gydesenbe424292023-02-25 16:47:19 +0100903int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200904 const uint8_t meta[], size_t meta_len)
Emil Gydesen1424df42022-06-28 20:09:13 +0200905{
Emil Gydesen099c1382023-03-01 11:57:11 +0100906 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen33268632023-03-01 11:18:25 +0100907 enum bt_bap_ep_state broadcast_state;
Emil Gydesen1424df42022-06-28 20:09:13 +0200908
909 CHECKIF(source == NULL) {
910 LOG_DBG("source is NULL");
911
912 return -EINVAL;
913 }
914
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200915 CHECKIF((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) {
916 LOG_DBG("Invalid metadata combination: %p %zu", meta, meta_len);
Emil Gydesen1424df42022-06-28 20:09:13 +0200917
918 return -EINVAL;
919 }
920
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200921 CHECKIF(meta_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
922 LOG_DBG("Invalid meta_len: %zu (max %d)", meta_len,
923 CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
Emil Gydesen1424df42022-06-28 20:09:13 +0200924
925 return -EINVAL;
926 }
927
Emil Gydesen1424df42022-06-28 20:09:13 +0200928 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +0100929 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_STREAMING) {
Emil Gydesen1424df42022-06-28 20:09:13 +0200930 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
931
932 return -EBADMSG;
933 }
934
935 /* TODO: We should probably find a way to update the metadata
936 * for each subgroup individually
937 */
938 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200939 memset(subgroup->codec_cfg->meta, 0, sizeof(subgroup->codec_cfg->meta));
940 memcpy(subgroup->codec_cfg->meta, meta, meta_len);
Magdalena Kasenberge05d9642023-12-20 16:47:34 +0100941 subgroup->codec_cfg->meta_len = meta_len;
Emil Gydesen1424df42022-06-28 20:09:13 +0200942 }
943
944 return 0;
945}
946
Emil Gydesenbe424292023-02-25 16:47:19 +0100947int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100948{
Emil Gydesen40e39302022-09-05 11:29:06 +0200949 struct bt_iso_chan *bis[BROADCAST_STREAM_CNT];
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100950 struct bt_iso_big_create_param param = { 0 };
Emil Gydesen099c1382023-03-01 11:57:11 +0100951 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen33268632023-03-01 11:18:25 +0100952 enum bt_bap_ep_state broadcast_state;
Emil Gydesen77853f42023-02-27 15:32:52 +0100953 struct bt_bap_stream *stream;
Emil Gydesen40e39302022-09-05 11:29:06 +0200954 size_t bis_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100955 int err;
956
957 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100958 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100959 return -EINVAL;
960 }
961
Emil Gydesenafd41612023-05-09 15:13:45 +0200962 CHECKIF(adv == NULL) {
963 LOG_DBG("adv is NULL");
964 return -EINVAL;
965 }
966
Emil Gydesen40e39302022-09-05 11:29:06 +0200967 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +0100968 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100969 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100970 return -EBADMSG;
971 }
972
Emil Gydesen40e39302022-09-05 11:29:06 +0200973 bis_count = 0;
974 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
975 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
Emil Gydesen77853f42023-02-27 15:32:52 +0100976 bis[bis_count++] = bt_bap_stream_iso_chan_get(stream);
Emil Gydesen40e39302022-09-05 11:29:06 +0200977 }
978 }
979
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100980 /* Create BIG */
Emil Gydesen40e39302022-09-05 11:29:06 +0200981 param.num_bis = bis_count;
982 param.bis_channels = bis;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100983 param.framing = source->qos->framing;
Emil Gydesenba194972022-12-20 15:39:07 +0100984 param.packing = source->packing;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100985 param.interval = source->qos->interval;
986 param.latency = source->qos->latency;
Emil Gydesen8d86fa02022-12-13 21:03:14 +0100987 param.encryption = source->encryption;
988 if (param.encryption) {
989 (void)memcpy(param.bcode, source->broadcast_code,
990 sizeof(param.bcode));
991 }
Emil Gydesen84c01bb2023-01-23 14:33:54 +0100992#if defined(CONFIG_BT_ISO_TEST_PARAMS)
993 param.irc = source->irc;
994 param.pto = source->pto;
995 param.iso_interval = source->iso_interval;
996#endif /* CONFIG_BT_ISO_TEST_PARAMS */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100997
Emil Gydesen68a4d0f2023-08-31 15:30:31 +0200998 /* Set the enabling state early in case that the BIS is connected before we can manage to
999 * set it afterwards
1000 */
1001 broadcast_source_set_state(source, BT_BAP_EP_STATE_ENABLING);
1002
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001003 err = bt_iso_big_create(adv, &param, &source->big);
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001004 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001005 LOG_DBG("Failed to create BIG: %d", err);
Emil Gydesen68a4d0f2023-08-31 15:30:31 +02001006 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
1007
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001008 return err;
1009 }
1010
1011 return 0;
1012}
1013
Emil Gydesenbe424292023-02-25 16:47:19 +01001014int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001015{
Emil Gydesen33268632023-03-01 11:18:25 +01001016 enum bt_bap_ep_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001017 int err;
1018
1019 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001020 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001021 return -EINVAL;
1022 }
1023
Emil Gydesen40e39302022-09-05 11:29:06 +02001024 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +01001025 if (broadcast_state != BT_BAP_EP_STATE_STREAMING &&
1026 broadcast_state != BT_BAP_EP_STATE_ENABLING) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001027 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001028 return -EBADMSG;
1029 }
1030
1031 if (source->big == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001032 LOG_DBG("Source is not started");
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001033 return -EALREADY;
1034 }
1035
1036 err = bt_iso_big_terminate(source->big);
1037 if (err) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001038 LOG_DBG("Failed to terminate BIG (err %d)", err);
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001039 return err;
1040 }
1041
1042 source->big = NULL;
1043
1044 return 0;
1045}
1046
Emil Gydesenbe424292023-02-25 16:47:19 +01001047int bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001048{
Emil Gydesen33268632023-03-01 11:18:25 +01001049 enum bt_bap_ep_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001050
1051 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001052 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001053 return -EINVAL;
1054 }
1055
Emil Gydesen40e39302022-09-05 11:29:06 +02001056 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +01001057 if (broadcast_state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001058 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesen468bd4d2022-03-11 14:58:51 +01001059 return -EBADMSG;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001060 }
1061
Emil Gydesenc66f2102023-05-09 13:51:02 +02001062 broadcast_source_set_state(source, BT_BAP_EP_STATE_IDLE);
1063
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001064 /* Reset the broadcast source */
1065 broadcast_source_cleanup(source);
1066
1067 return 0;
1068}
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001069
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001070int bt_bap_broadcast_source_get_id(struct bt_bap_broadcast_source *source,
Emil Gydesenbe424292023-02-25 16:47:19 +01001071 uint32_t *const broadcast_id)
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001072{
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001073 enum bt_bap_ep_state broadcast_state;
1074
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001075 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001076 LOG_DBG("source is NULL");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001077 return -EINVAL;
1078 }
1079
1080 CHECKIF(broadcast_id == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001081 LOG_DBG("broadcast_id is NULL");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001082 return -EINVAL;
1083 }
1084
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001085 broadcast_state = broadcast_source_get_state(source);
1086 if (broadcast_state == BT_BAP_EP_STATE_IDLE) {
1087 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1088 return -EBADMSG;
1089 }
1090
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001091 *broadcast_id = source->broadcast_id;
1092
1093 return 0;
1094}
1095
Emil Gydesenbe424292023-02-25 16:47:19 +01001096int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,
1097 struct net_buf_simple *base_buf)
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001098{
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001099 enum bt_bap_ep_state broadcast_state;
1100
Emil Gydesenfa95a7a2023-04-12 16:29:29 +02001101 CHECKIF(source == NULL) {
1102 LOG_DBG("source is NULL");
1103 return -EINVAL;
1104 }
1105
1106 CHECKIF(base_buf == NULL) {
1107 LOG_DBG("base_buf is NULL");
1108 return -EINVAL;
1109 }
1110
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001111 broadcast_state = broadcast_source_get_state(source);
1112 if (broadcast_state == BT_BAP_EP_STATE_IDLE) {
1113 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1114 return -EBADMSG;
1115 }
1116
Emil Gydesen40e39302022-09-05 11:29:06 +02001117 if (!encode_base(source, base_buf)) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001118 LOG_DBG("base_buf %p with size %u not large enough", base_buf, base_buf->size);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001119
1120 return -EMSGSIZE;
1121 }
1122
1123 return 0;
1124}