blob: 26a1f6bb5d02ab9074c1ad63d79406ed333d69e9 [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
Emil Gydesenebadb112024-05-20 19:40:04 +02009#include <errno.h>
10#include <stdbool.h>
11#include <stddef.h>
12#include <stdint.h>
13#include <string.h>
Emil Gydesenab87e0a2022-01-10 15:06:08 +010014
Emil Gydesenebadb112024-05-20 19:40:04 +020015#include <zephyr/autoconf.h>
Gerard Marull-Paretas5113c142022-05-06 11:12:04 +020016#include <zephyr/bluetooth/bluetooth.h>
17#include <zephyr/bluetooth/conn.h>
Emil Gydesenebadb112024-05-20 19:40:04 +020018#include <zephyr/bluetooth/crypto.h>
Gerard Marull-Paretas5113c142022-05-06 11:12:04 +020019#include <zephyr/bluetooth/gatt.h>
20#include <zephyr/bluetooth/audio/audio.h>
Emil Gydesen77853f42023-02-27 15:32:52 +010021#include <zephyr/bluetooth/audio/bap.h>
Emil Gydesenebadb112024-05-20 19:40:04 +020022#include <zephyr/bluetooth/hci_types.h>
23#include <zephyr/bluetooth/iso.h>
24#include <zephyr/bluetooth/uuid.h>
25#include <zephyr/kernel.h>
Théo Battrele458f5a2022-11-02 14:31:13 +010026#include <zephyr/logging/log.h>
Henrik Brix Andersen159f7db2024-09-04 16:00:21 +000027#include <zephyr/net_buf.h>
Emil Gydesenebadb112024-05-20 19:40:04 +020028#include <zephyr/sys/byteorder.h>
29#include <zephyr/sys/check.h>
30#include <zephyr/sys/slist.h>
31#include <zephyr/sys/util.h>
32#include <zephyr/sys/util_macro.h>
33
Emil Gydesenbe424292023-02-25 16:47:19 +010034LOG_MODULE_REGISTER(bt_bap_broadcast_source, CONFIG_BT_BAP_BROADCAST_SOURCE_LOG_LEVEL);
Emil Gydesenab87e0a2022-01-10 15:06:08 +010035
Emil Gydesenf500f7c2024-08-22 13:52:32 +020036#include "audio_internal.h"
Emil Gydesen7fc05192023-02-20 14:33:43 +010037#include "bap_iso.h"
38#include "bap_endpoint.h"
Emil Gydesenebadb112024-05-20 19:40:04 +020039#include "bap_stream.h"
Emil Gydesenab87e0a2022-01-10 15:06:08 +010040
Emil Gydesen099c1382023-03-01 11:57:11 +010041struct bt_bap_broadcast_subgroup {
Emil Gydesen40e39302022-09-05 11:29:06 +020042 /* The streams used to create the broadcast source */
43 sys_slist_t streams;
44
45 /* The codec of the subgroup */
Emil Gydesen69f7fd92023-05-16 14:16:14 +020046 struct bt_audio_codec_cfg *codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +020047
48 /* List node */
49 sys_snode_t _node;
50};
51
Emil Gydesen33268632023-03-01 11:18:25 +010052static struct bt_bap_ep broadcast_source_eps[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
53 [BROADCAST_STREAM_CNT];
Emil Gydesen099c1382023-03-01 11:57:11 +010054static struct bt_bap_broadcast_subgroup
Emil Gydesenbe424292023-02-25 16:47:19 +010055 broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]
56 [CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
57static struct bt_bap_broadcast_source broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
Emil Gydesenab87e0a2022-01-10 15:06:08 +010058
Emil Gydesen40e39302022-09-05 11:29:06 +020059/**
60 * 2 octets UUID
61 * 3 octets presentation delay
62 * 1 octet number of subgroups
63 *
64 * Each subgroup then has
65 * 1 octet of number of BIS
66 * 5 octets of Codec_ID
67 * 1 octet codec specific configuration len
68 * 0-n octets of codec specific configuration
69 * 1 octet metadata len
70 * 0-n octets of metadata
71 *
72 * For each BIS in the subgroup there is
73 * 1 octet for the BIS index
74 * 1 octet codec specific configuration len
75 * 0-n octets of codec specific configuration
76 *
77 * For a minimal BASE with 1 subgroup and 1 BIS without and other data the
78 * total comes to 16
79 */
80#define MINIMUM_BASE_SIZE 16
81
Emil Gydesen33268632023-03-01 11:18:25 +010082static void broadcast_source_set_ep_state(struct bt_bap_ep *ep, uint8_t state)
Emil Gydesenab87e0a2022-01-10 15:06:08 +010083{
84 uint8_t old_state;
85
86 old_state = ep->status.state;
87
Emil Gydesen33268632023-03-01 11:18:25 +010088 LOG_DBG("ep %p id 0x%02x %s -> %s", ep, ep->status.id, bt_bap_ep_state_str(old_state),
89 bt_bap_ep_state_str(state));
Emil Gydesenab87e0a2022-01-10 15:06:08 +010090
91 switch (old_state) {
Emil Gydesen33268632023-03-01 11:18:25 +010092 case BT_BAP_EP_STATE_IDLE:
93 if (state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +010094 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesenab87e0a2022-01-10 15:06:08 +010095 return;
96 }
97 break;
Emil Gydesen33268632023-03-01 11:18:25 +010098 case BT_BAP_EP_STATE_QOS_CONFIGURED:
99 if (state != BT_BAP_EP_STATE_IDLE && state != BT_BAP_EP_STATE_ENABLING) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100100 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesen05ace182022-06-03 10:48:19 +0200101 return;
102 }
103 break;
Emil Gydesen33268632023-03-01 11:18:25 +0100104 case BT_BAP_EP_STATE_ENABLING:
Emil Gydesen590d3e12024-02-05 15:46:22 +0100105 if (state != BT_BAP_EP_STATE_STREAMING && state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100106 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100107 return;
108 }
Emil Gydesen2df90772022-03-18 13:53:31 +0100109 break;
Emil Gydesen33268632023-03-01 11:18:25 +0100110 case BT_BAP_EP_STATE_STREAMING:
111 if (state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100112 LOG_DBG("Invalid broadcast sync endpoint state transition");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100113 return;
114 }
115 break;
116 default:
Théo Battrele458f5a2022-11-02 14:31:13 +0100117 LOG_ERR("Invalid broadcast sync endpoint state: %s",
Emil Gydesen33268632023-03-01 11:18:25 +0100118 bt_bap_ep_state_str(old_state));
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100119 return;
120 }
121
122 ep->status.state = state;
Emil Gydesenc66f2102023-05-09 13:51:02 +0200123}
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100124
Emil Gydesenc66f2102023-05-09 13:51:02 +0200125static void broadcast_source_set_state(struct bt_bap_broadcast_source *source, uint8_t state)
126{
127 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100128
Emil Gydesenc66f2102023-05-09 13:51:02 +0200129 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
130 struct bt_bap_stream *stream;
131
132 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
133 broadcast_source_set_ep_state(stream->ep, state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100134 }
135 }
136}
137
Emil Gydesen4518c192022-03-07 14:18:26 +0100138static void broadcast_source_iso_sent(struct bt_iso_chan *chan)
139{
Emil Gydesene2765d72023-03-01 11:52:29 +0100140 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
Emil Gydesen77853f42023-02-27 15:32:52 +0100141 const struct bt_bap_stream_ops *ops;
142 struct bt_bap_stream *stream;
Emil Gydesen33268632023-03-01 11:18:25 +0100143 struct bt_bap_ep *ep = iso->tx.ep;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200144
145 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100146 LOG_ERR("iso %p not bound with ep", chan);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200147 return;
148 }
149
150 stream = ep->stream;
151 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100152 LOG_ERR("No stream for ep %p", ep);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200153 return;
154 }
155
156 ops = stream->ops;
Emil Gydesen4518c192022-03-07 14:18:26 +0100157
Emil Gydesen77853f42023-02-27 15:32:52 +0100158 if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100159 LOG_DBG("stream %p ep %p", stream, stream->ep);
Emil Gydesen65f130b2022-09-26 17:15:24 +0200160 }
Emil Gydesen4518c192022-03-07 14:18:26 +0100161
162 if (ops != NULL && ops->sent != NULL) {
Emil Gydesen9b154262022-05-24 13:59:45 +0200163 ops->sent(stream);
Emil Gydesen4518c192022-03-07 14:18:26 +0100164 }
165}
166
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100167static void broadcast_source_iso_connected(struct bt_iso_chan *chan)
168{
Emil Gydesene2765d72023-03-01 11:52:29 +0100169 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
Emil Gydesen77853f42023-02-27 15:32:52 +0100170 const struct bt_bap_stream_ops *ops;
171 struct bt_bap_stream *stream;
Emil Gydesen33268632023-03-01 11:18:25 +0100172 struct bt_bap_ep *ep = iso->tx.ep;
Emil Gydesene8e19202022-02-14 14:18:03 +0100173
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200174 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100175 LOG_ERR("iso %p not bound with ep", chan);
Emil Gydesen9b154262022-05-24 13:59:45 +0200176 return;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200177 }
178
179 stream = ep->stream;
180 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100181 LOG_ERR("No stream for ep %p", ep);
Emil Gydesene8e19202022-02-14 14:18:03 +0100182 return;
183 }
184
Théo Battrele458f5a2022-11-02 14:31:13 +0100185 LOG_DBG("stream %p ep %p", stream, ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100186
Emil Gydesen7cfc8b32024-02-08 13:39:33 +0100187#if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM)
188 /* reset sequence number */
189 stream->_prev_seq_num = 0U;
190#endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */
191
Emil Gydesenb857ef72023-12-28 13:50:56 +0100192 ops = stream->ops;
193 if (ops != NULL && ops->connected != NULL) {
194 ops->connected(stream);
195 }
196
Emil Gydesen33268632023-03-01 11:18:25 +0100197 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100198
Emil Gydesen628b54a2022-02-02 17:12:30 +0100199 if (ops != NULL && ops->started != NULL) {
Emil Gydesen9b154262022-05-24 13:59:45 +0200200 ops->started(stream);
Emil Gydesen102dcca2022-01-20 15:03:00 +0100201 } else {
Emil Gydesen68a4d0f2023-08-31 15:30:31 +0200202 LOG_WRN("No callback for started set");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100203 }
204}
205
206static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
207{
Emil Gydesene2765d72023-03-01 11:52:29 +0100208 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
Emil Gydesen77853f42023-02-27 15:32:52 +0100209 const struct bt_bap_stream_ops *ops;
210 struct bt_bap_stream *stream;
Emil Gydesen33268632023-03-01 11:18:25 +0100211 struct bt_bap_ep *ep = iso->tx.ep;
Emil Gydesene8e19202022-02-14 14:18:03 +0100212
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200213 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100214 LOG_ERR("iso %p not bound with ep", chan);
Emil Gydesen9b154262022-05-24 13:59:45 +0200215 return;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200216 }
217
218 stream = ep->stream;
219 if (stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100220 LOG_ERR("No stream for ep %p", ep);
Emil Gydesene8e19202022-02-14 14:18:03 +0100221 return;
222 }
223
Théo Battrele458f5a2022-11-02 14:31:13 +0100224 LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100225
Emil Gydesenb857ef72023-12-28 13:50:56 +0100226 ops = stream->ops;
227 if (ops != NULL && ops->disconnected != NULL) {
228 ops->disconnected(stream, reason);
229 }
230
Emil Gydesen33268632023-03-01 11:18:25 +0100231 broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100232
Emil Gydesen628b54a2022-02-02 17:12:30 +0100233 if (ops != NULL && ops->stopped != NULL) {
Emil Gydesen59a9f8a2023-03-02 15:01:00 +0100234 ops->stopped(stream, reason);
Emil Gydesen102dcca2022-01-20 15:03:00 +0100235 } else {
Théo Battrele458f5a2022-11-02 14:31:13 +0100236 LOG_WRN("No callback for stopped set");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100237 }
238}
239
240static struct bt_iso_chan_ops broadcast_source_iso_ops = {
Emil Gydesen4518c192022-03-07 14:18:26 +0100241 .sent = broadcast_source_iso_sent,
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100242 .connected = broadcast_source_iso_connected,
243 .disconnected = broadcast_source_iso_disconnected,
244};
245
Emil Gydesen33268632023-03-01 11:18:25 +0100246bool bt_bap_ep_is_broadcast_src(const struct bt_bap_ep *ep)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100247{
248 for (int i = 0; i < ARRAY_SIZE(broadcast_source_eps); i++) {
249 if (PART_OF_ARRAY(broadcast_source_eps[i], ep)) {
250 return true;
251 }
252 }
253
254 return false;
255}
256
Emil Gydesen33268632023-03-01 11:18:25 +0100257static void broadcast_source_ep_init(struct bt_bap_ep *ep)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100258{
Théo Battrele458f5a2022-11-02 14:31:13 +0100259 LOG_DBG("ep %p", ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100260
261 (void)memset(ep, 0, sizeof(*ep));
Emil Gydesen6191a762022-03-29 18:20:10 +0200262 ep->dir = BT_AUDIO_DIR_SOURCE;
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200263 ep->iso = NULL;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100264}
265
Emil Gydesen33268632023-03-01 11:18:25 +0100266static struct bt_bap_ep *broadcast_source_new_ep(uint8_t index)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100267{
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100268 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_eps[index]); i++) {
Emil Gydesen33268632023-03-01 11:18:25 +0100269 struct bt_bap_ep *ep = &broadcast_source_eps[index][i];
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100270
271 /* If ep->stream is NULL the endpoint is unallocated */
272 if (ep->stream == NULL) {
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200273 broadcast_source_ep_init(ep);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100274 return ep;
275 }
276 }
277
278 return NULL;
279}
280
Emil Gydesen099c1382023-03-01 11:57:11 +0100281static struct bt_bap_broadcast_subgroup *broadcast_source_new_subgroup(uint8_t index)
Emil Gydesen40e39302022-09-05 11:29:06 +0200282{
283 for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_subgroups[index]); i++) {
Emil Gydesen099c1382023-03-01 11:57:11 +0100284 struct bt_bap_broadcast_subgroup *subgroup = &broadcast_source_subgroups[index][i];
Emil Gydesen40e39302022-09-05 11:29:06 +0200285
286 if (sys_slist_is_empty(&subgroup->streams)) {
287 return subgroup;
288 }
289 }
290
291 return NULL;
292}
293
Emil Gydesen77853f42023-02-27 15:32:52 +0100294static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *stream,
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200295 struct bt_audio_codec_cfg *codec_cfg,
Emil Gydesendc97bbd2024-08-02 11:23:33 +0200296 struct bt_bap_qos_cfg *qos,
Emil Gydesenbe424292023-02-25 16:47:19 +0100297 struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100298{
Emil Gydesene2765d72023-03-01 11:52:29 +0100299 struct bt_bap_iso *iso;
Emil Gydesen33268632023-03-01 11:18:25 +0100300 struct bt_bap_ep *ep;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100301
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100302 ep = broadcast_source_new_ep(index);
303 if (ep == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100304 LOG_DBG("Could not allocate new broadcast endpoint");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100305 return -ENOMEM;
306 }
307
Emil Gydesene2765d72023-03-01 11:52:29 +0100308 iso = bt_bap_iso_new();
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200309 if (iso == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100310 LOG_DBG("Could not allocate iso");
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200311 return -ENOMEM;
312 }
313
Emil Gydesene2765d72023-03-01 11:52:29 +0100314 bt_bap_iso_init(iso, &broadcast_source_iso_ops);
315 bt_bap_iso_bind_ep(iso, ep);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200316
Emil Gydesendc97bbd2024-08-02 11:23:33 +0200317 bt_bap_qos_cfg_to_iso_qos(iso->chan.qos->tx, qos);
Emil Gydesenaef39f62024-01-19 13:13:08 +0100318 bt_bap_iso_configure_data_path(ep, codec_cfg);
Emil Gydesen84c01bb2023-01-23 14:33:54 +0100319#if defined(CONFIG_BT_ISO_TEST_PARAMS)
320 iso->chan.qos->num_subevents = qos->num_subevents;
321#endif /* CONFIG_BT_ISO_TEST_PARAMS */
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200322
Emil Gydesene2765d72023-03-01 11:52:29 +0100323 bt_bap_iso_unref(iso);
Mariusz Skamra3fa45692022-10-21 14:35:10 +0200324
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200325 bt_bap_stream_attach(NULL, stream, ep, codec_cfg);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100326 stream->qos = qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200327 ep->broadcast_source = source;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100328
329 return 0;
330}
331
Emil Gydesen099c1382023-03-01 11:57:11 +0100332static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup,
333 struct bt_audio_broadcast_stream_data *stream_data,
334 uint8_t *streams_encoded, struct net_buf_simple *buf)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100335{
Emil Gydesen77853f42023-02-27 15:32:52 +0100336 struct bt_bap_stream *stream;
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200337 const struct bt_audio_codec_cfg *codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200338 uint8_t stream_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100339 uint8_t len;
340
Emil Gydesen40e39302022-09-05 11:29:06 +0200341 stream_count = 0;
342 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
343 stream_count++;
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200344 }
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200345
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200346 codec_cfg = subgroup->codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200347
348 net_buf_simple_add_u8(buf, stream_count);
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200349 net_buf_simple_add_u8(buf, codec_cfg->id);
350 net_buf_simple_add_le16(buf, codec_cfg->cid);
351 net_buf_simple_add_le16(buf, codec_cfg->vid);
Emil Gydesen40e39302022-09-05 11:29:06 +0200352
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200353 net_buf_simple_add_u8(buf, codec_cfg->data_len);
354#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
355 if ((buf->size - buf->len) < codec_cfg->data_len) {
356 LOG_DBG("No room for config data: %zu", codec_cfg->data_len);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200357
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200358 return false;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100359 }
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200360 net_buf_simple_add_mem(buf, codec_cfg->data, codec_cfg->data_len);
361#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100362
Emil Gydesen40e39302022-09-05 11:29:06 +0200363 if ((buf->size - buf->len) < sizeof(len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100364 LOG_DBG("No room for metadata length");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200365
366 return false;
367 }
368
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200369 net_buf_simple_add_u8(buf, codec_cfg->meta_len);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100370
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200371#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
372 if ((buf->size - buf->len) < codec_cfg->meta_len) {
373 LOG_DBG("No room for metadata data: %zu", codec_cfg->meta_len);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200374
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200375 return false;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100376 }
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200377
378 net_buf_simple_add_mem(buf, codec_cfg->meta, codec_cfg->meta_len);
379#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100380
381 /* Create BIS index bitfield */
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200382 for (uint8_t i = 0U; i < stream_count; i++) {
Emil Gydesenaf953a12023-10-04 23:31:28 +0200383 /* Set the bis_index to *streams_encoded plus 1 as the indexes start from 1 */
384 const uint8_t bis_index = *streams_encoded + 1;
385
Emil Gydesen40e39302022-09-05 11:29:06 +0200386 if ((buf->size - buf->len) < (sizeof(bis_index) + sizeof(uint8_t))) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100387 LOG_DBG("No room for BIS[%d] index", i);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200388
389 return false;
390 }
391
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100392 net_buf_simple_add_u8(buf, bis_index);
Emil Gydesen40e39302022-09-05 11:29:06 +0200393
394 if ((buf->size - buf->len) < sizeof(len)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100395 LOG_DBG("No room for bis codec config length");
Emil Gydesen40e39302022-09-05 11:29:06 +0200396
397 return false;
398 }
399
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200400 net_buf_simple_add_u8(buf, stream_data[i].data_len);
401#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
402 if ((buf->size - buf->len) < stream_data[i].data_len) {
403 LOG_DBG("No room for BIS[%u] data: %zu", i, stream_data[i].data_len);
Emil Gydesen40e39302022-09-05 11:29:06 +0200404
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200405 return false;
Emil Gydesen40e39302022-09-05 11:29:06 +0200406 }
Emil Gydesen40e39302022-09-05 11:29:06 +0200407
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200408 net_buf_simple_add_mem(buf, stream_data[i].data, stream_data[i].data_len);
409#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
Emil Gydesen40e39302022-09-05 11:29:06 +0200410
Emil Gydesenaf953a12023-10-04 23:31:28 +0200411 (*streams_encoded)++;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100412 }
413
Emil Gydesen40e39302022-09-05 11:29:06 +0200414 return true;
415}
416
Emil Gydesenbe424292023-02-25 16:47:19 +0100417static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_simple *buf)
Emil Gydesen40e39302022-09-05 11:29:06 +0200418{
Emil Gydesen099c1382023-03-01 11:57:11 +0100419 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen40e39302022-09-05 11:29:06 +0200420 uint8_t streams_encoded;
421 uint8_t subgroup_count;
422
423 /* 13 is the size of the fixed size values following this check */
424 if ((buf->size - buf->len) < MINIMUM_BASE_SIZE) {
425 return false;
426 }
427
428 subgroup_count = 0U;
429 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
430 subgroup_count++;
431 }
432
433 net_buf_simple_add_le16(buf, BT_UUID_BASIC_AUDIO_VAL);
434
435 net_buf_simple_add_le24(buf, source->qos->pd);
436 net_buf_simple_add_u8(buf, subgroup_count);
437
438 /* Since the `stream_data` is only stored in the broadcast source,
439 * we need to provide that information when encoding each subgroup
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100440 */
Emil Gydesen40e39302022-09-05 11:29:06 +0200441 streams_encoded = 0;
442 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
443 if (!encode_base_subgroup(subgroup,
444 &source->stream_data[streams_encoded],
445 &streams_encoded, buf)) {
446 return false;
447 }
448 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100449
Emil Gydesen7ab1caf2022-09-02 15:43:30 +0200450 return true;
451}
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100452
Emil Gydesenbe424292023-02-25 16:47:19 +0100453static int generate_broadcast_id(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100454{
455 bool unique;
456
457 do {
458 int err;
459
460 err = bt_rand(&source->broadcast_id,
461 BT_AUDIO_BROADCAST_ID_SIZE);
462 if (err) {
463 return err;
464 }
465
466 /* Ensure uniqueness */
467 unique = true;
468 for (int i = 0; i < ARRAY_SIZE(broadcast_sources); i++) {
469 if (&broadcast_sources[i] == source) {
470 continue;
471 }
472
473 if (broadcast_sources[i].broadcast_id == source->broadcast_id) {
474 unique = false;
475 break;
476 }
477 }
478 } while (!unique);
479
480 return 0;
481}
482
Emil Gydesenbe424292023-02-25 16:47:19 +0100483static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100484{
Emil Gydesen099c1382023-03-01 11:57:11 +0100485 struct bt_bap_broadcast_subgroup *subgroup, *next_subgroup;
Emil Gydesen5628b292022-03-11 16:20:31 +0100486
Emil Gydesen40e39302022-09-05 11:29:06 +0200487 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup,
488 next_subgroup, _node) {
Emil Gydesen77853f42023-02-27 15:32:52 +0100489 struct bt_bap_stream *stream, *next_stream;
Emil Gydesen468bd4d2022-03-11 14:58:51 +0100490
Emil Gydesen40e39302022-09-05 11:29:06 +0200491 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream,
492 next_stream, _node) {
Emil Gydesene2765d72023-03-01 11:52:29 +0100493 bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
Emil Gydesen40e39302022-09-05 11:29:06 +0200494 stream->ep->stream = NULL;
495 stream->ep = NULL;
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200496 stream->codec_cfg = NULL;
Emil Gydesen40e39302022-09-05 11:29:06 +0200497 stream->qos = NULL;
498 stream->group = NULL;
499
500 sys_slist_remove(&subgroup->streams, NULL,
501 &stream->_node);
502 }
503 sys_slist_remove(&source->subgroups, NULL, &subgroup->_node);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100504 }
505
506 (void)memset(source, 0, sizeof(*source));
507}
508
Emil Gydesend327b162023-08-17 13:15:12 +0200509static bool valid_broadcast_source_param(const struct bt_bap_broadcast_source_param *param,
510 const struct bt_bap_broadcast_source *source)
Emil Gydesen40e39302022-09-05 11:29:06 +0200511{
Emil Gydesendc97bbd2024-08-02 11:23:33 +0200512 const struct bt_bap_qos_cfg *qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200513
514 CHECKIF(param == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100515 LOG_DBG("param is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200516 return false;
517 }
518
Emil Gydesen117f6292023-05-09 14:05:36 +0200519 CHECKIF(!IN_RANGE(param->params_count, 1U, CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT)) {
520 LOG_DBG("param->params_count %zu is invalid", param->params_count);
Emil Gydesen40e39302022-09-05 11:29:06 +0200521 return false;
522 }
523
Emil Gydesenba194972022-12-20 15:39:07 +0100524 CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL &&
525 param->packing != BT_ISO_PACKING_INTERLEAVED) {
526 LOG_DBG("param->packing %u is invalid", param->packing);
527 return false;
528 }
529
Emil Gydesen40e39302022-09-05 11:29:06 +0200530 qos = param->qos;
531 CHECKIF(qos == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100532 LOG_DBG("param->qos is NULL");
Emil Gydesen40e39302022-09-05 11:29:06 +0200533 return false;
534 }
535
Magdalena Kasenberg57784df2023-02-15 11:22:04 +0100536 CHECKIF(bt_audio_verify_qos(qos) != BT_BAP_ASCS_REASON_NONE) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100537 LOG_DBG("param->qos is invalid");
Emil Gydesen40e39302022-09-05 11:29:06 +0200538 return false;
539 }
540
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200541 CHECKIF(param->qos->rtn > BT_ISO_BROADCAST_RTN_MAX) {
542 LOG_DBG("param->qos->rtn %u invalid", param->qos->rtn);
543 return false;
544 }
545
546 CHECKIF(param->params == NULL) {
547 LOG_DBG("param->params is NULL");
548 return false;
549 }
550
551 CHECKIF(param->params_count == 0) {
552 LOG_DBG("param->params_count is 0");
553 return false;
554 }
555
Emil Gydesen40e39302022-09-05 11:29:06 +0200556 for (size_t i = 0U; i < param->params_count; i++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100557 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200558
559 subgroup_param = &param->params[i];
560
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200561 CHECKIF(subgroup_param->params == NULL) {
562 LOG_DBG("subgroup_params[%zu].params is NULL", i);
Emil Gydesen40e39302022-09-05 11:29:06 +0200563 return false;
564 }
565
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200566 CHECKIF(!IN_RANGE(subgroup_param->params_count, 1U,
567 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)) {
568 LOG_DBG("subgroup_params[%zu].count (%zu) is invalid", i,
569 subgroup_param->params_count);
570 return false;
571 }
572
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200573 CHECKIF(!bt_audio_valid_codec_cfg(subgroup_param->codec_cfg)) {
574 LOG_DBG("subgroup_params[%zu].codec_cfg is invalid", i);
Emil Gydesen40e39302022-09-05 11:29:06 +0200575 return false;
576 }
577
578 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100579 const struct bt_bap_broadcast_source_stream_param *stream_param;
Emil Gydesen40e39302022-09-05 11:29:06 +0200580
581 stream_param = &subgroup_param->params[j];
582
583 CHECKIF(stream_param->stream == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100584 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is NULL",
585 i, j);
Emil Gydesen40e39302022-09-05 11:29:06 +0200586 return false;
587 }
588
Emil Gydesend327b162023-08-17 13:15:12 +0200589 CHECKIF(stream_param->stream->group != NULL &&
590 stream_param->stream->group != source) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100591 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is "
592 "already part of group %p",
593 i, j, stream_param->stream->group);
Emil Gydesen40e39302022-09-05 11:29:06 +0200594 return false;
595 }
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200596
Emil Gydesen8a6c1d92024-02-23 15:02:41 +0100597#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200598 CHECKIF(stream_param->data == NULL && stream_param->data_len != 0) {
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200599 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data is "
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200600 "NULL with len %zu",
601 i, j, stream_param->data_len);
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200602 return false;
603 }
604
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200605 CHECKIF(stream_param->data_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
606 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data_len too "
607 "large: %zu > %d",
608 i, j, stream_param->data_len,
609 CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE);
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200610 return false;
611 }
Emil Gydesen8a6c1d92024-02-23 15:02:41 +0100612
Magdalena Kasenbergdba205a2024-03-12 14:09:06 +0100613 CHECKIF(stream_param->data != NULL &&
614 subgroup_param->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3 &&
Emil Gydesen8a6c1d92024-02-23 15:02:41 +0100615 !bt_audio_valid_ltv(stream_param->data, stream_param->data_len)) {
616 LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data not valid "
617 "LTV",
618 i, j);
619 return false;
620 }
Emil Gydesen40e39302022-09-05 11:29:06 +0200621 }
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200622#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
Emil Gydesen40e39302022-09-05 11:29:06 +0200623 }
624
625 return true;
626}
627
Emil Gydesenb413b502024-07-01 10:53:58 +0200628/** Gets the "highest" state of all BIS in the broadcast source */
Emil Gydesen33268632023-03-01 11:18:25 +0100629static enum bt_bap_ep_state broadcast_source_get_state(struct bt_bap_broadcast_source *source)
Emil Gydesen40e39302022-09-05 11:29:06 +0200630{
Emil Gydesenb413b502024-07-01 10:53:58 +0200631 enum bt_bap_ep_state state = BT_BAP_EP_STATE_IDLE;
Emil Gydesen099c1382023-03-01 11:57:11 +0100632 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen40e39302022-09-05 11:29:06 +0200633
634 if (source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100635 LOG_DBG("source is NULL");
Emil Gydesenb413b502024-07-01 10:53:58 +0200636 return state;
Emil Gydesen40e39302022-09-05 11:29:06 +0200637 }
638
639 if (sys_slist_is_empty(&source->subgroups)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100640 LOG_DBG("Source does not have any streams");
Emil Gydesenb413b502024-07-01 10:53:58 +0200641 return state;
Emil Gydesen40e39302022-09-05 11:29:06 +0200642 }
643
Emil Gydesenb413b502024-07-01 10:53:58 +0200644 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
645 struct bt_bap_stream *stream;
Emil Gydesen40e39302022-09-05 11:29:06 +0200646
Emil Gydesenb413b502024-07-01 10:53:58 +0200647 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
648 if (stream->ep != NULL) {
649 state = MAX(state, stream->ep->status.state);
650 }
651 }
Emil Gydesen40e39302022-09-05 11:29:06 +0200652 }
653
Emil Gydesenb413b502024-07-01 10:53:58 +0200654 return state;
Emil Gydesen40e39302022-09-05 11:29:06 +0200655}
656
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200657static bool merge_bis_and_subgroup_data_cb(struct bt_data *data, void *user_data)
658{
659 struct bt_audio_codec_cfg *codec_cfg = user_data;
660 int err;
661
662 err = bt_audio_codec_cfg_set_val(codec_cfg, data->type, data->data, data->data_len);
663 if (err < 0) {
664 LOG_DBG("Failed to set type %u with len %u in codec_cfg: %d", data->type,
665 data->data_len, err);
666
667 return false;
668 }
669
670 return true;
671}
672
673static int update_codec_cfg_data(struct bt_audio_codec_cfg *codec_cfg,
674 const struct bt_bap_broadcast_source_stream_param *stream_param)
675{
Emil Gydesen35fa7002024-06-14 11:05:50 +0200676 if (stream_param->data_len > 0) {
677 int err;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200678
Emil Gydesen35fa7002024-06-14 11:05:50 +0200679 /* Merge subgroup codec configuration with the BIS configuration
680 * As per the BAP spec, if a value exist at level 2 (subgroup) and 3 (BIS), then it
681 * is the value at level 3 that shall be used
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200682 */
Emil Gydesen35fa7002024-06-14 11:05:50 +0200683 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
684 err = bt_audio_data_parse(stream_param->data, stream_param->data_len,
685 merge_bis_and_subgroup_data_cb, codec_cfg);
686 if (err != 0) {
687 LOG_DBG("Could not merge BIS and subgroup config in codec_cfg: %d",
688 err);
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200689
Emil Gydesen35fa7002024-06-14 11:05:50 +0200690 return -EINVAL;
691 }
692 } else {
693 /* If it is not LC3, then we don't know how to merge the subgroup and BIS
694 * codecs, so we just append them
695 */
696 if (codec_cfg->data_len + stream_param->data_len >
697 sizeof(codec_cfg->data)) {
698 LOG_DBG("Could not store BIS and subgroup config in codec_cfg (%u "
699 "> %u)",
700 codec_cfg->data_len + stream_param->data_len,
701 sizeof(codec_cfg->data));
702
703 return -ENOMEM;
704 }
705
706 memcpy(&codec_cfg->data[codec_cfg->data_len], stream_param->data,
707 stream_param->data_len);
708 codec_cfg->data_len += stream_param->data_len;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200709 }
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200710 }
711
712 return 0;
713}
714
Emil Gydesend327b162023-08-17 13:15:12 +0200715int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_param *param,
Emil Gydesenbe424292023-02-25 16:47:19 +0100716 struct bt_bap_broadcast_source **out_source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100717{
Emil Gydesenbe424292023-02-25 16:47:19 +0100718 struct bt_bap_broadcast_source *source;
Emil Gydesendc97bbd2024-08-02 11:23:33 +0200719 struct bt_bap_qos_cfg *qos;
Emil Gydesen40e39302022-09-05 11:29:06 +0200720 size_t stream_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100721 uint8_t index;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200722 uint8_t bis_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100723 int err;
724
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100725 CHECKIF(out_source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100726 LOG_DBG("out_source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100727 return -EINVAL;
728 }
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200729
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100730 /* Set out_source to NULL until the source has actually been created */
731 *out_source = NULL;
732
Emil Gydesend327b162023-08-17 13:15:12 +0200733 if (!valid_broadcast_source_param(param, NULL)) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100734 LOG_DBG("Invalid parameters");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100735 return -EINVAL;
736 }
737
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100738 source = NULL;
739 for (index = 0; index < ARRAY_SIZE(broadcast_sources); index++) {
Emil Gydesen40e39302022-09-05 11:29:06 +0200740 if (sys_slist_is_empty(&broadcast_sources[index].subgroups)) { /* Find free entry */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100741 source = &broadcast_sources[index];
742 break;
743 }
744 }
745
746 if (source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100747 LOG_DBG("Could not allocate any more broadcast sources");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100748 return -ENOMEM;
749 }
750
Emil Gydesen40e39302022-09-05 11:29:06 +0200751 stream_count = 0U;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200752 bis_count = 0U;
Emil Gydesen40e39302022-09-05 11:29:06 +0200753 qos = param->qos;
754 /* Go through all subgroups and streams and setup each setup with an
755 * endpoint
756 */
757 for (size_t i = 0U; i < param->params_count; i++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100758 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
Emil Gydesenc66f2102023-05-09 13:51:02 +0200759 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen40e39302022-09-05 11:29:06 +0200760
761 subgroup_param = &param->params[i];
762
763 subgroup = broadcast_source_new_subgroup(index);
764 if (subgroup == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100765 LOG_DBG("Could not allocate new broadcast subgroup");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100766 broadcast_source_cleanup(source);
Emil Gydesen40e39302022-09-05 11:29:06 +0200767 return -ENOMEM;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100768 }
769
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200770 subgroup->codec_cfg = subgroup_param->codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200771 sys_slist_append(&source->subgroups, &subgroup->_node);
772
773 /* Check that we are not above the maximum BIS count */
774 if (subgroup_param->params_count + stream_count > BROADCAST_STREAM_CNT) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100775 LOG_DBG("Cannot create broadcaster with %zu streams", stream_count);
Emil Gydesen40e39302022-09-05 11:29:06 +0200776 broadcast_source_cleanup(source);
777
778 return -ENOMEM;
779 }
780
781 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
Emil Gydesenbe424292023-02-25 16:47:19 +0100782 const struct bt_bap_broadcast_source_stream_param *stream_param;
Emil Gydesen77853f42023-02-27 15:32:52 +0100783 struct bt_bap_stream *stream;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200784 struct bt_audio_codec_cfg *codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200785
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200786 codec_cfg = subgroup_param->codec_cfg;
Emil Gydesen40e39302022-09-05 11:29:06 +0200787 stream_param = &subgroup_param->params[j];
788 stream = stream_param->stream;
789
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200790 if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
791 if (bis_count >= BROADCAST_STREAM_CNT) {
792 LOG_DBG("Stream count %d exceeded", bis_count);
793 return -ENOMEM;
794 }
795
796 codec_cfg = &source->codec_cfg[bis_count];
797 memcpy(codec_cfg, subgroup_param->codec_cfg,
798 sizeof(struct bt_audio_codec_cfg));
Emil Gydesen35fa7002024-06-14 11:05:50 +0200799
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200800 err = update_codec_cfg_data(codec_cfg, stream_param);
801 if (err != 0) {
802 LOG_DBG("codec config update failed [%zu]: %d", i, err);
803 broadcast_source_cleanup(source);
804 return err;
805 }
806
807 bis_count++;
808 }
809
Emil Gydesen40e39302022-09-05 11:29:06 +0200810 err = broadcast_source_setup_stream(index, stream,
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200811 codec_cfg, qos, source);
Emil Gydesen40e39302022-09-05 11:29:06 +0200812 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100813 LOG_DBG("Failed to setup streams[%zu]: %d", i, err);
Emil Gydesen40e39302022-09-05 11:29:06 +0200814 broadcast_source_cleanup(source);
815 return err;
816 }
817
818 /* Store the BIS specific codec configuration data in
819 * the broadcast source. It is stored in the broadcast
820 * source, instead of the stream object, as this is
821 * only relevant for the broadcast source, and not used
822 * for unicast or broadcast sink.
823 */
Emil Gydesen6ccd1122023-05-22 15:08:57 +0200824 (void)memcpy(source->stream_data[stream_count].data, stream_param->data,
825 stream_param->data_len * sizeof(*stream_param->data));
826 source->stream_data[stream_count].data_len = stream_param->data_len;
Emil Gydesen40e39302022-09-05 11:29:06 +0200827
828 sys_slist_append(&subgroup->streams, &stream->_node);
829 stream_count++;
830 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100831 }
832
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100833 err = generate_broadcast_id(source);
834 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100835 LOG_DBG("Could not generate broadcast id: %d", err);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100836 return err;
837 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100838
Emil Gydesen40e39302022-09-05 11:29:06 +0200839 /* Finalize state changes and store information */
Emil Gydesenc66f2102023-05-09 13:51:02 +0200840 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100841 source->qos = qos;
Emil Gydesenba194972022-12-20 15:39:07 +0100842 source->packing = param->packing;
Emil Gydesen84c01bb2023-01-23 14:33:54 +0100843#if defined(CONFIG_BT_ISO_TEST_PARAMS)
844 source->irc = param->irc;
845 source->pto = param->pto;
846 source->iso_interval = param->iso_interval;
847#endif /* CONFIG_BT_ISO_TEST_PARAMS */
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100848
Emil Gydesen8d86fa02022-12-13 21:03:14 +0100849 source->encryption = param->encryption;
850 if (source->encryption) {
851 (void)memcpy(source->broadcast_code, param->broadcast_code,
852 sizeof(source->broadcast_code));
853 }
854
Théo Battrele458f5a2022-11-02 14:31:13 +0100855 LOG_DBG("Broadcasting with ID 0x%6X", source->broadcast_id);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100856
857 *out_source = source;
858
859 return 0;
860}
861
Emil Gydesen69f7fd92023-05-16 14:16:14 +0200862int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source,
Emil Gydesend327b162023-08-17 13:15:12 +0200863 struct bt_bap_broadcast_source_param *param)
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100864{
Emil Gydesen099c1382023-03-01 11:57:11 +0100865 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen33268632023-03-01 11:18:25 +0100866 enum bt_bap_ep_state broadcast_state;
Emil Gydesendc97bbd2024-08-02 11:23:33 +0200867 struct bt_bap_qos_cfg *qos;
Emil Gydesend327b162023-08-17 13:15:12 +0200868 size_t subgroup_cnt;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200869 uint8_t bis_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100870
871 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100872 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100873 return -EINVAL;
874 }
875
Emil Gydesend327b162023-08-17 13:15:12 +0200876 if (!valid_broadcast_source_param(param, source)) {
877 LOG_DBG("Invalid parameters");
Emil Gydesenfa95a7a2023-04-12 16:29:29 +0200878 return -EINVAL;
879 }
880
Emil Gydesen40e39302022-09-05 11:29:06 +0200881 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +0100882 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +0100883 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +0100884 return -EBADMSG;
885 }
886
Emil Gydesend327b162023-08-17 13:15:12 +0200887 /* Verify that the parameter counts do not exceed existing number of subgroups and streams*/
888 subgroup_cnt = 0U;
Emil Gydesen40e39302022-09-05 11:29:06 +0200889 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
Emil Gydesend327b162023-08-17 13:15:12 +0200890 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param =
891 &param->params[subgroup_cnt];
892 const size_t subgroup_stream_param_cnt = subgroup_param->params_count;
893 struct bt_bap_stream *stream;
Emil Gydesene962fda2023-10-04 17:29:33 +0200894 size_t subgroup_stream_cnt = 0U;
Emil Gydesend327b162023-08-17 13:15:12 +0200895
Emil Gydesen40e39302022-09-05 11:29:06 +0200896 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
Emil Gydesene962fda2023-10-04 17:29:33 +0200897 subgroup_stream_cnt++;
Emil Gydesend327b162023-08-17 13:15:12 +0200898 }
899
900 /* Verify that the param stream is in the subgroup */
901 for (size_t i = 0U; i < subgroup_param->params_count; i++) {
902 struct bt_bap_stream *subgroup_stream;
903 struct bt_bap_stream *param_stream;
Emil Gydesenf4cbf402024-01-03 09:58:07 +0100904 bool stream_in_subgroup = false;
Emil Gydesend327b162023-08-17 13:15:12 +0200905
906 param_stream = subgroup_param->params[i].stream;
907
908 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
909 if (subgroup_stream == param_stream) {
910 stream_in_subgroup = true;
911 break;
912 }
913 }
914
915 if (!stream_in_subgroup) {
916 LOG_DBG("Invalid param->params[%zu]->param[%zu].stream "
917 "not in subgroup",
918 subgroup_cnt, i);
919 return -EINVAL;
920 }
921 }
922
Emil Gydesene962fda2023-10-04 17:29:33 +0200923 if (subgroup_stream_cnt < subgroup_stream_param_cnt) {
Emil Gydesend327b162023-08-17 13:15:12 +0200924 LOG_DBG("Invalid param->params[%zu]->params_count: %zu "
925 "(only %zu streams in subgroup)",
Emil Gydesene962fda2023-10-04 17:29:33 +0200926 subgroup_cnt, subgroup_stream_param_cnt, subgroup_stream_cnt);
Emil Gydesend327b162023-08-17 13:15:12 +0200927 return -EINVAL;
928 }
929
930 subgroup_cnt++;
931 }
932
933 if (subgroup_cnt < param->params_count) {
934 LOG_DBG("Invalid param->params_count: %zu (only %zu subgroups in source)",
935 param->params_count, subgroup_cnt);
936 return -EINVAL;
937 }
938
939 qos = param->qos;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200940 bis_count = 0U;
Emil Gydesend327b162023-08-17 13:15:12 +0200941 /* We update up to the first param->params_count subgroups */
942 for (size_t i = 0U; i < param->params_count; i++) {
943 const struct bt_bap_broadcast_source_subgroup_param *subgroup_param;
944 struct bt_audio_codec_cfg *codec_cfg;
Emil Gydesende67ec92023-10-05 14:14:04 +0200945 struct bt_bap_stream *stream;
Emil Gydesend327b162023-08-17 13:15:12 +0200946
947 if (i == 0) {
948 subgroup =
949 SYS_SLIST_PEEK_HEAD_CONTAINER(&source->subgroups, subgroup, _node);
950 } else {
951 subgroup = SYS_SLIST_PEEK_NEXT_CONTAINER(subgroup, _node);
952 }
953
954 subgroup_param = &param->params[i];
955 codec_cfg = subgroup_param->codec_cfg;
956 subgroup->codec_cfg = codec_cfg;
957
958 for (size_t j = 0U; j < subgroup_param->params_count; j++) {
959 const struct bt_bap_broadcast_source_stream_param *stream_param;
960 struct bt_audio_broadcast_stream_data *stream_data;
961 struct bt_bap_stream *subgroup_stream;
Emil Gydesend327b162023-08-17 13:15:12 +0200962 size_t stream_idx;
963
964 stream_param = &subgroup_param->params[j];
965 stream = stream_param->stream;
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200966 if (CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0) {
967 int err;
968
969 if (bis_count >= BROADCAST_STREAM_CNT) {
970 LOG_DBG("Stream count %d exceeded", bis_count);
971 return -ENOMEM;
972 }
973
974 codec_cfg = &source->codec_cfg[bis_count];
975 memcpy(codec_cfg, subgroup_param->codec_cfg,
976 sizeof(struct bt_audio_codec_cfg));
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200977
Emil Gydesen35fa7002024-06-14 11:05:50 +0200978 err = update_codec_cfg_data(codec_cfg, stream_param);
Nithin Ramesh Myliattildf458582024-05-17 06:08:29 +0200979 if (err != 0) {
980 LOG_DBG("codec config update failed [%zu]: %d", i, err);
981 return err;
982 }
983
984 bis_count++;
985 }
Emil Gydesend327b162023-08-17 13:15:12 +0200986
987 stream_idx = 0U;
988 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, subgroup_stream, _node) {
989 if (subgroup_stream == stream) {
Emil Gydesend327b162023-08-17 13:15:12 +0200990 break;
991 }
992
993 stream_idx++;
994 }
Emil Gydesene5890fc2023-01-24 14:41:17 +0100995
Emil Gydesend327b162023-08-17 13:15:12 +0200996 /* Store the BIS specific codec configuration data in the broadcast source.
997 * It is stored in the broadcast* source, instead of the stream object,
998 * as this is only relevant for the broadcast source, and not used
999 * for unicast or broadcast sink.
1000 */
1001 stream_data = &source->stream_data[stream_idx];
1002 (void)memcpy(stream_data->data, stream_param->data, stream_param->data_len);
1003 stream_data->data_len = stream_param->data_len;
Emil Gydesen40e39302022-09-05 11:29:06 +02001004 }
Emil Gydesende67ec92023-10-05 14:14:04 +02001005
1006 /* Apply the codec_cfg to all streams in the subgroup, and not just the ones in the
1007 * params
1008 */
1009 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
Emil Gydesende67ec92023-10-05 14:14:04 +02001010 bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg);
Emil Gydesenaef39f62024-01-19 13:13:08 +01001011 bt_bap_iso_configure_data_path(stream->ep, codec_cfg);
Emil Gydesende67ec92023-10-05 14:14:04 +02001012 }
1013 }
1014
1015 /* Finally we apply the new qos and to all streams */
1016 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
1017 struct bt_bap_stream *stream;
1018
1019 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
1020 struct bt_iso_chan_io_qos *iso_qos;
1021
1022 iso_qos = stream->ep->iso->chan.qos->tx;
Emil Gydesendc97bbd2024-08-02 11:23:33 +02001023 bt_bap_qos_cfg_to_iso_qos(iso_qos, qos);
Emil Gydesende67ec92023-10-05 14:14:04 +02001024 stream->qos = qos;
1025 }
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001026 }
1027
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001028 source->qos = qos;
1029
1030 return 0;
1031}
1032
Emil Gydesenbe424292023-02-25 16:47:19 +01001033int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source,
Emil Gydesen6ccd1122023-05-22 15:08:57 +02001034 const uint8_t meta[], size_t meta_len)
Emil Gydesen1424df42022-06-28 20:09:13 +02001035{
Emil Gydesen099c1382023-03-01 11:57:11 +01001036 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen33268632023-03-01 11:18:25 +01001037 enum bt_bap_ep_state broadcast_state;
Emil Gydesen1424df42022-06-28 20:09:13 +02001038
1039 CHECKIF(source == NULL) {
1040 LOG_DBG("source is NULL");
1041
1042 return -EINVAL;
1043 }
1044
Emil Gydesen6ccd1122023-05-22 15:08:57 +02001045 CHECKIF((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) {
1046 LOG_DBG("Invalid metadata combination: %p %zu", meta, meta_len);
Emil Gydesen1424df42022-06-28 20:09:13 +02001047
1048 return -EINVAL;
1049 }
1050
Emil Gydesen6ccd1122023-05-22 15:08:57 +02001051 CHECKIF(meta_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
1052 LOG_DBG("Invalid meta_len: %zu (max %d)", meta_len,
1053 CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
Emil Gydesen1424df42022-06-28 20:09:13 +02001054
1055 return -EINVAL;
1056 }
1057
Emil Gydesen1424df42022-06-28 20:09:13 +02001058 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +01001059 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_STREAMING) {
Emil Gydesen1424df42022-06-28 20:09:13 +02001060 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1061
1062 return -EBADMSG;
1063 }
1064
1065 /* TODO: We should probably find a way to update the metadata
1066 * for each subgroup individually
1067 */
1068 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
Emil Gydesen6ccd1122023-05-22 15:08:57 +02001069 memset(subgroup->codec_cfg->meta, 0, sizeof(subgroup->codec_cfg->meta));
1070 memcpy(subgroup->codec_cfg->meta, meta, meta_len);
Magdalena Kasenberge05d9642023-12-20 16:47:34 +01001071 subgroup->codec_cfg->meta_len = meta_len;
Emil Gydesen1424df42022-06-28 20:09:13 +02001072 }
1073
1074 return 0;
1075}
1076
Emil Gydesenbe424292023-02-25 16:47:19 +01001077int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv)
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001078{
Emil Gydesen40e39302022-09-05 11:29:06 +02001079 struct bt_iso_chan *bis[BROADCAST_STREAM_CNT];
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001080 struct bt_iso_big_create_param param = { 0 };
Emil Gydesen099c1382023-03-01 11:57:11 +01001081 struct bt_bap_broadcast_subgroup *subgroup;
Emil Gydesen33268632023-03-01 11:18:25 +01001082 enum bt_bap_ep_state broadcast_state;
Emil Gydesen77853f42023-02-27 15:32:52 +01001083 struct bt_bap_stream *stream;
Emil Gydesen40e39302022-09-05 11:29:06 +02001084 size_t bis_count;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001085 int err;
1086
1087 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001088 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001089 return -EINVAL;
1090 }
1091
Emil Gydesenafd41612023-05-09 15:13:45 +02001092 CHECKIF(adv == NULL) {
1093 LOG_DBG("adv is NULL");
1094 return -EINVAL;
1095 }
1096
Emil Gydesen40e39302022-09-05 11:29:06 +02001097 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +01001098 if (broadcast_source_get_state(source) != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001099 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001100 return -EBADMSG;
1101 }
1102
Emil Gydesen40e39302022-09-05 11:29:06 +02001103 bis_count = 0;
1104 SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) {
1105 SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) {
Emil Gydesen77853f42023-02-27 15:32:52 +01001106 bis[bis_count++] = bt_bap_stream_iso_chan_get(stream);
Emil Gydesen40e39302022-09-05 11:29:06 +02001107 }
1108 }
1109
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001110 /* Create BIG */
Emil Gydesen40e39302022-09-05 11:29:06 +02001111 param.num_bis = bis_count;
1112 param.bis_channels = bis;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001113 param.framing = source->qos->framing;
Emil Gydesenba194972022-12-20 15:39:07 +01001114 param.packing = source->packing;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001115 param.interval = source->qos->interval;
1116 param.latency = source->qos->latency;
Emil Gydesen8d86fa02022-12-13 21:03:14 +01001117 param.encryption = source->encryption;
1118 if (param.encryption) {
1119 (void)memcpy(param.bcode, source->broadcast_code,
1120 sizeof(param.bcode));
1121 }
Emil Gydesen84c01bb2023-01-23 14:33:54 +01001122#if defined(CONFIG_BT_ISO_TEST_PARAMS)
1123 param.irc = source->irc;
1124 param.pto = source->pto;
1125 param.iso_interval = source->iso_interval;
1126#endif /* CONFIG_BT_ISO_TEST_PARAMS */
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001127
Emil Gydesen68a4d0f2023-08-31 15:30:31 +02001128 /* Set the enabling state early in case that the BIS is connected before we can manage to
1129 * set it afterwards
1130 */
1131 broadcast_source_set_state(source, BT_BAP_EP_STATE_ENABLING);
1132
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001133 err = bt_iso_big_create(adv, &param, &source->big);
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001134 if (err != 0) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001135 LOG_DBG("Failed to create BIG: %d", err);
Emil Gydesen68a4d0f2023-08-31 15:30:31 +02001136 broadcast_source_set_state(source, BT_BAP_EP_STATE_QOS_CONFIGURED);
1137
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001138 return err;
1139 }
1140
1141 return 0;
1142}
1143
Emil Gydesenbe424292023-02-25 16:47:19 +01001144int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001145{
Emil Gydesen33268632023-03-01 11:18:25 +01001146 enum bt_bap_ep_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001147 int err;
1148
1149 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001150 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001151 return -EINVAL;
1152 }
1153
Emil Gydesen40e39302022-09-05 11:29:06 +02001154 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +01001155 if (broadcast_state != BT_BAP_EP_STATE_STREAMING &&
1156 broadcast_state != BT_BAP_EP_STATE_ENABLING) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001157 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001158 return -EBADMSG;
1159 }
1160
1161 if (source->big == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001162 LOG_DBG("Source is not started");
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001163 return -EALREADY;
1164 }
1165
1166 err = bt_iso_big_terminate(source->big);
1167 if (err) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001168 LOG_DBG("Failed to terminate BIG (err %d)", err);
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001169 return err;
1170 }
1171
1172 source->big = NULL;
1173
1174 return 0;
1175}
1176
Emil Gydesenbe424292023-02-25 16:47:19 +01001177int bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source *source)
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001178{
Emil Gydesen33268632023-03-01 11:18:25 +01001179 enum bt_bap_ep_state broadcast_state;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001180
1181 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001182 LOG_DBG("source is NULL");
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001183 return -EINVAL;
1184 }
1185
Emil Gydesen40e39302022-09-05 11:29:06 +02001186 broadcast_state = broadcast_source_get_state(source);
Emil Gydesen33268632023-03-01 11:18:25 +01001187 if (broadcast_state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001188 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
Emil Gydesen468bd4d2022-03-11 14:58:51 +01001189 return -EBADMSG;
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001190 }
1191
Emil Gydesenc66f2102023-05-09 13:51:02 +02001192 broadcast_source_set_state(source, BT_BAP_EP_STATE_IDLE);
1193
Emil Gydesenab87e0a2022-01-10 15:06:08 +01001194 /* Reset the broadcast source */
1195 broadcast_source_cleanup(source);
1196
1197 return 0;
1198}
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001199
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001200int bt_bap_broadcast_source_get_id(struct bt_bap_broadcast_source *source,
Emil Gydesenbe424292023-02-25 16:47:19 +01001201 uint32_t *const broadcast_id)
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001202{
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001203 enum bt_bap_ep_state broadcast_state;
1204
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001205 CHECKIF(source == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001206 LOG_DBG("source is NULL");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001207 return -EINVAL;
1208 }
1209
1210 CHECKIF(broadcast_id == NULL) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001211 LOG_DBG("broadcast_id is NULL");
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001212 return -EINVAL;
1213 }
1214
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001215 broadcast_state = broadcast_source_get_state(source);
1216 if (broadcast_state == BT_BAP_EP_STATE_IDLE) {
1217 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1218 return -EBADMSG;
1219 }
1220
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001221 *broadcast_id = source->broadcast_id;
1222
1223 return 0;
1224}
1225
Emil Gydesenbe424292023-02-25 16:47:19 +01001226int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,
1227 struct net_buf_simple *base_buf)
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001228{
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001229 enum bt_bap_ep_state broadcast_state;
1230
Emil Gydesenfa95a7a2023-04-12 16:29:29 +02001231 CHECKIF(source == NULL) {
1232 LOG_DBG("source is NULL");
1233 return -EINVAL;
1234 }
1235
1236 CHECKIF(base_buf == NULL) {
1237 LOG_DBG("base_buf is NULL");
1238 return -EINVAL;
1239 }
1240
Emil Gydesen9d62bef2023-09-08 11:29:44 +02001241 broadcast_state = broadcast_source_get_state(source);
1242 if (broadcast_state == BT_BAP_EP_STATE_IDLE) {
1243 LOG_DBG("Broadcast source invalid state: %u", broadcast_state);
1244 return -EBADMSG;
1245 }
1246
Emil Gydesen40e39302022-09-05 11:29:06 +02001247 if (!encode_base(source, base_buf)) {
Théo Battrele458f5a2022-11-02 14:31:13 +01001248 LOG_DBG("base_buf %p with size %u not large enough", base_buf, base_buf->size);
Emil Gydesen7ab1caf2022-09-02 15:43:30 +02001249
1250 return -EMSGSIZE;
1251 }
1252
1253 return 0;
1254}