Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 1 | /* Bluetooth Audio Broadcast Source */ |
| 2 | |
| 3 | /* |
Emil Gydesen | 7fc0519 | 2023-02-20 14:33:43 +0100 | [diff] [blame] | 4 | * Copyright (c) 2021-2023 Nordic Semiconductor ASA |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 5 | * |
| 6 | * SPDX-License-Identifier: Apache-2.0 |
| 7 | */ |
| 8 | |
Gerard Marull-Paretas | 79e6b0e | 2022-08-25 09:58:46 +0200 | [diff] [blame] | 9 | #include <zephyr/kernel.h> |
Gerard Marull-Paretas | 5113c14 | 2022-05-06 11:12:04 +0200 | [diff] [blame] | 10 | #include <zephyr/sys/byteorder.h> |
| 11 | #include <zephyr/sys/check.h> |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 12 | |
Gerard Marull-Paretas | 5113c14 | 2022-05-06 11:12:04 +0200 | [diff] [blame] | 13 | #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 Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 17 | |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 18 | #include <zephyr/logging/log.h> |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 19 | LOG_MODULE_REGISTER(bt_bap_broadcast_source, CONFIG_BT_BAP_BROADCAST_SOURCE_LOG_LEVEL); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 20 | |
Emil Gydesen | 7fc0519 | 2023-02-20 14:33:43 +0100 | [diff] [blame] | 21 | #include "bap_iso.h" |
| 22 | #include "bap_endpoint.h" |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 23 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 24 | struct bt_audio_broadcast_subgroup { |
| 25 | /* The streams used to create the broadcast source */ |
| 26 | sys_slist_t streams; |
| 27 | |
| 28 | /* The codec of the subgroup */ |
| 29 | struct bt_codec *codec; |
| 30 | |
| 31 | /* List node */ |
| 32 | sys_snode_t _node; |
| 33 | }; |
| 34 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 35 | static struct bt_audio_ep broadcast_source_eps[CONFIG_BT_BAP_BROADCAST_SRC_COUNT] |
| 36 | [BROADCAST_STREAM_CNT]; |
| 37 | static struct bt_audio_broadcast_subgroup |
| 38 | broadcast_source_subgroups[CONFIG_BT_BAP_BROADCAST_SRC_COUNT] |
| 39 | [CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]; |
| 40 | static struct bt_bap_broadcast_source broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT]; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 41 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 42 | /** |
| 43 | * 2 octets UUID |
| 44 | * 3 octets presentation delay |
| 45 | * 1 octet number of subgroups |
| 46 | * |
| 47 | * Each subgroup then has |
| 48 | * 1 octet of number of BIS |
| 49 | * 5 octets of Codec_ID |
| 50 | * 1 octet codec specific configuration len |
| 51 | * 0-n octets of codec specific configuration |
| 52 | * 1 octet metadata len |
| 53 | * 0-n octets of metadata |
| 54 | * |
| 55 | * For each BIS in the subgroup there is |
| 56 | * 1 octet for the BIS index |
| 57 | * 1 octet codec specific configuration len |
| 58 | * 0-n octets of codec specific configuration |
| 59 | * |
| 60 | * For a minimal BASE with 1 subgroup and 1 BIS without and other data the |
| 61 | * total comes to 16 |
| 62 | */ |
| 63 | #define MINIMUM_BASE_SIZE 16 |
| 64 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 65 | static void broadcast_source_set_ep_state(struct bt_audio_ep *ep, uint8_t state) |
| 66 | { |
| 67 | uint8_t old_state; |
| 68 | |
| 69 | old_state = ep->status.state; |
| 70 | |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 71 | LOG_DBG("ep %p id 0x%02x %s -> %s", ep, ep->status.id, bt_audio_ep_state_str(old_state), |
| 72 | bt_audio_ep_state_str(state)); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 73 | |
| 74 | switch (old_state) { |
| 75 | case BT_AUDIO_EP_STATE_IDLE: |
| 76 | if (state != BT_AUDIO_EP_STATE_QOS_CONFIGURED) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 77 | LOG_DBG("Invalid broadcast sync endpoint state transition"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 78 | return; |
| 79 | } |
| 80 | break; |
| 81 | case BT_AUDIO_EP_STATE_QOS_CONFIGURED: |
| 82 | if (state != BT_AUDIO_EP_STATE_IDLE && |
Emil Gydesen | 05ace18 | 2022-06-03 10:48:19 +0200 | [diff] [blame] | 83 | state != BT_AUDIO_EP_STATE_ENABLING) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 84 | LOG_DBG("Invalid broadcast sync endpoint state transition"); |
Emil Gydesen | 05ace18 | 2022-06-03 10:48:19 +0200 | [diff] [blame] | 85 | return; |
| 86 | } |
| 87 | break; |
| 88 | case BT_AUDIO_EP_STATE_ENABLING: |
| 89 | if (state != BT_AUDIO_EP_STATE_STREAMING) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 90 | LOG_DBG("Invalid broadcast sync endpoint state transition"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 91 | return; |
| 92 | } |
Emil Gydesen | 2df9077 | 2022-03-18 13:53:31 +0100 | [diff] [blame] | 93 | break; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 94 | case BT_AUDIO_EP_STATE_STREAMING: |
| 95 | if (state != BT_AUDIO_EP_STATE_QOS_CONFIGURED) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 96 | LOG_DBG("Invalid broadcast sync endpoint state transition"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 97 | return; |
| 98 | } |
| 99 | break; |
| 100 | default: |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 101 | LOG_ERR("Invalid broadcast sync endpoint state: %s", |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 102 | bt_audio_ep_state_str(old_state)); |
| 103 | return; |
| 104 | } |
| 105 | |
| 106 | ep->status.state = state; |
| 107 | |
| 108 | if (state == BT_AUDIO_EP_STATE_IDLE) { |
| 109 | struct bt_audio_stream *stream = ep->stream; |
| 110 | |
| 111 | if (stream != NULL) { |
| 112 | stream->ep = NULL; |
| 113 | stream->codec = NULL; |
| 114 | ep->stream = NULL; |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |
Emil Gydesen | 4518c19 | 2022-03-07 14:18:26 +0100 | [diff] [blame] | 119 | static void broadcast_source_iso_sent(struct bt_iso_chan *chan) |
| 120 | { |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 121 | struct bt_audio_iso *iso = CONTAINER_OF(chan, struct bt_audio_iso, chan); |
| 122 | const struct bt_audio_stream_ops *ops; |
| 123 | struct bt_audio_stream *stream; |
| 124 | struct bt_audio_ep *ep = iso->tx.ep; |
| 125 | |
| 126 | if (ep == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 127 | LOG_ERR("iso %p not bound with ep", chan); |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 128 | return; |
| 129 | } |
| 130 | |
| 131 | stream = ep->stream; |
| 132 | if (stream == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 133 | LOG_ERR("No stream for ep %p", ep); |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 134 | return; |
| 135 | } |
| 136 | |
| 137 | ops = stream->ops; |
Emil Gydesen | 4518c19 | 2022-03-07 14:18:26 +0100 | [diff] [blame] | 138 | |
Emil Gydesen | 65f130b | 2022-09-26 17:15:24 +0200 | [diff] [blame] | 139 | if (IS_ENABLED(CONFIG_BT_AUDIO_DEBUG_STREAM_DATA)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 140 | LOG_DBG("stream %p ep %p", stream, stream->ep); |
Emil Gydesen | 65f130b | 2022-09-26 17:15:24 +0200 | [diff] [blame] | 141 | } |
Emil Gydesen | 4518c19 | 2022-03-07 14:18:26 +0100 | [diff] [blame] | 142 | |
| 143 | if (ops != NULL && ops->sent != NULL) { |
Emil Gydesen | 9b15426 | 2022-05-24 13:59:45 +0200 | [diff] [blame] | 144 | ops->sent(stream); |
Emil Gydesen | 4518c19 | 2022-03-07 14:18:26 +0100 | [diff] [blame] | 145 | } |
| 146 | } |
| 147 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 148 | static void broadcast_source_iso_connected(struct bt_iso_chan *chan) |
| 149 | { |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 150 | struct bt_audio_iso *iso = CONTAINER_OF(chan, struct bt_audio_iso, chan); |
Emil Gydesen | e8e1920 | 2022-02-14 14:18:03 +0100 | [diff] [blame] | 151 | const struct bt_audio_stream_ops *ops; |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 152 | struct bt_audio_stream *stream; |
| 153 | struct bt_audio_ep *ep = iso->tx.ep; |
Emil Gydesen | e8e1920 | 2022-02-14 14:18:03 +0100 | [diff] [blame] | 154 | |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 155 | if (ep == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 156 | LOG_ERR("iso %p not bound with ep", chan); |
Emil Gydesen | 9b15426 | 2022-05-24 13:59:45 +0200 | [diff] [blame] | 157 | return; |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | stream = ep->stream; |
| 161 | if (stream == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 162 | LOG_ERR("No stream for ep %p", ep); |
Emil Gydesen | e8e1920 | 2022-02-14 14:18:03 +0100 | [diff] [blame] | 163 | return; |
| 164 | } |
| 165 | |
Emil Gydesen | 9b15426 | 2022-05-24 13:59:45 +0200 | [diff] [blame] | 166 | ops = stream->ops; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 167 | |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 168 | LOG_DBG("stream %p ep %p", stream, ep); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 169 | |
| 170 | broadcast_source_set_ep_state(ep, BT_AUDIO_EP_STATE_STREAMING); |
| 171 | |
Emil Gydesen | 628b54a | 2022-02-02 17:12:30 +0100 | [diff] [blame] | 172 | if (ops != NULL && ops->started != NULL) { |
Emil Gydesen | 9b15426 | 2022-05-24 13:59:45 +0200 | [diff] [blame] | 173 | ops->started(stream); |
Emil Gydesen | 102dcca | 2022-01-20 15:03:00 +0100 | [diff] [blame] | 174 | } else { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 175 | LOG_WRN("No callback for connected set"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 176 | } |
| 177 | } |
| 178 | |
| 179 | static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) |
| 180 | { |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 181 | struct bt_audio_iso *iso = CONTAINER_OF(chan, struct bt_audio_iso, chan); |
Emil Gydesen | e8e1920 | 2022-02-14 14:18:03 +0100 | [diff] [blame] | 182 | const struct bt_audio_stream_ops *ops; |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 183 | struct bt_audio_stream *stream; |
| 184 | struct bt_audio_ep *ep = iso->tx.ep; |
Emil Gydesen | e8e1920 | 2022-02-14 14:18:03 +0100 | [diff] [blame] | 185 | |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 186 | if (ep == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 187 | LOG_ERR("iso %p not bound with ep", chan); |
Emil Gydesen | 9b15426 | 2022-05-24 13:59:45 +0200 | [diff] [blame] | 188 | return; |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | stream = ep->stream; |
| 192 | if (stream == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 193 | LOG_ERR("No stream for ep %p", ep); |
Emil Gydesen | e8e1920 | 2022-02-14 14:18:03 +0100 | [diff] [blame] | 194 | return; |
| 195 | } |
| 196 | |
Emil Gydesen | 9b15426 | 2022-05-24 13:59:45 +0200 | [diff] [blame] | 197 | ops = stream->ops; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 198 | |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 199 | LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 200 | |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 201 | broadcast_source_set_ep_state(ep, BT_AUDIO_EP_STATE_QOS_CONFIGURED); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 202 | |
Emil Gydesen | 628b54a | 2022-02-02 17:12:30 +0100 | [diff] [blame] | 203 | if (ops != NULL && ops->stopped != NULL) { |
Emil Gydesen | 59a9f8a | 2023-03-02 15:01:00 +0100 | [diff] [blame] | 204 | ops->stopped(stream, reason); |
Emil Gydesen | 102dcca | 2022-01-20 15:03:00 +0100 | [diff] [blame] | 205 | } else { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 206 | LOG_WRN("No callback for stopped set"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 207 | } |
| 208 | } |
| 209 | |
| 210 | static struct bt_iso_chan_ops broadcast_source_iso_ops = { |
Emil Gydesen | 4518c19 | 2022-03-07 14:18:26 +0100 | [diff] [blame] | 211 | .sent = broadcast_source_iso_sent, |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 212 | .connected = broadcast_source_iso_connected, |
| 213 | .disconnected = broadcast_source_iso_disconnected, |
| 214 | }; |
| 215 | |
| 216 | bool bt_audio_ep_is_broadcast_src(const struct bt_audio_ep *ep) |
| 217 | { |
| 218 | for (int i = 0; i < ARRAY_SIZE(broadcast_source_eps); i++) { |
| 219 | if (PART_OF_ARRAY(broadcast_source_eps[i], ep)) { |
| 220 | return true; |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | return false; |
| 225 | } |
| 226 | |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 227 | static void broadcast_source_ep_init(struct bt_audio_ep *ep) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 228 | { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 229 | LOG_DBG("ep %p", ep); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 230 | |
| 231 | (void)memset(ep, 0, sizeof(*ep)); |
Emil Gydesen | 6191a76 | 2022-03-29 18:20:10 +0200 | [diff] [blame] | 232 | ep->dir = BT_AUDIO_DIR_SOURCE; |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 233 | ep->iso = NULL; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 234 | } |
| 235 | |
| 236 | static struct bt_audio_ep *broadcast_source_new_ep(uint8_t index) |
| 237 | { |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 238 | for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_eps[index]); i++) { |
Emil Gydesen | e8e1920 | 2022-02-14 14:18:03 +0100 | [diff] [blame] | 239 | struct bt_audio_ep *ep = &broadcast_source_eps[index][i]; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 240 | |
| 241 | /* If ep->stream is NULL the endpoint is unallocated */ |
| 242 | if (ep->stream == NULL) { |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 243 | broadcast_source_ep_init(ep); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 244 | return ep; |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | return NULL; |
| 249 | } |
| 250 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 251 | static struct bt_audio_broadcast_subgroup *broadcast_source_new_subgroup(uint8_t index) |
| 252 | { |
| 253 | for (size_t i = 0; i < ARRAY_SIZE(broadcast_source_subgroups[index]); i++) { |
| 254 | struct bt_audio_broadcast_subgroup *subgroup = |
| 255 | &broadcast_source_subgroups[index][i]; |
| 256 | |
| 257 | if (sys_slist_is_empty(&subgroup->streams)) { |
| 258 | return subgroup; |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | return NULL; |
| 263 | } |
| 264 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 265 | static int broadcast_source_setup_stream(uint8_t index, struct bt_audio_stream *stream, |
| 266 | struct bt_codec *codec, struct bt_codec_qos *qos, |
| 267 | struct bt_bap_broadcast_source *source) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 268 | { |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 269 | struct bt_audio_iso *iso; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 270 | struct bt_audio_ep *ep; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 271 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 272 | ep = broadcast_source_new_ep(index); |
| 273 | if (ep == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 274 | LOG_DBG("Could not allocate new broadcast endpoint"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 275 | return -ENOMEM; |
| 276 | } |
| 277 | |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 278 | iso = bt_audio_iso_new(); |
| 279 | if (iso == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 280 | LOG_DBG("Could not allocate iso"); |
Mariusz Skamra | 3fa4569 | 2022-10-21 14:35:10 +0200 | [diff] [blame] | 281 | return -ENOMEM; |
| 282 | } |
| 283 | |
| 284 | bt_audio_iso_init(iso, &broadcast_source_iso_ops); |
| 285 | bt_audio_iso_bind_ep(iso, ep); |
| 286 | |
| 287 | bt_audio_codec_qos_to_iso_qos(iso->chan.qos->tx, qos); |
| 288 | bt_audio_codec_to_iso_path(iso->chan.qos->tx->path, codec); |
| 289 | |
| 290 | bt_audio_iso_unref(iso); |
| 291 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 292 | bt_audio_stream_attach(NULL, stream, ep, codec); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 293 | stream->qos = qos; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 294 | ep->broadcast_source = source; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 295 | |
| 296 | return 0; |
| 297 | } |
| 298 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 299 | static bool encode_base_subgroup(struct bt_audio_broadcast_subgroup *subgroup, |
| 300 | struct bt_audio_broadcast_stream_data *stream_data, |
| 301 | uint8_t *streams_encoded, |
| 302 | struct net_buf_simple *buf) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 303 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 304 | struct bt_audio_stream *stream; |
| 305 | const struct bt_codec *codec; |
| 306 | uint8_t stream_count; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 307 | uint8_t bis_index; |
| 308 | uint8_t *start; |
| 309 | uint8_t len; |
| 310 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 311 | stream_count = 0; |
| 312 | SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) { |
| 313 | stream_count++; |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 314 | } |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 315 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 316 | codec = subgroup->codec; |
| 317 | |
| 318 | net_buf_simple_add_u8(buf, stream_count); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 319 | net_buf_simple_add_u8(buf, codec->id); |
| 320 | net_buf_simple_add_le16(buf, codec->cid); |
| 321 | net_buf_simple_add_le16(buf, codec->vid); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 322 | |
| 323 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 324 | /* Insert codec configuration data in LTV format */ |
| 325 | start = net_buf_simple_add(buf, sizeof(len)); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 326 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 327 | for (int i = 0; i < codec->data_count; i++) { |
| 328 | const struct bt_data *codec_data = &codec->data[i].data; |
| 329 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 330 | if ((buf->size - buf->len) < (sizeof(codec_data->data_len) + |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 331 | sizeof(codec_data->type) + |
| 332 | codec_data->data_len)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 333 | LOG_DBG("No room for codec[%d] with len %u", i, codec_data->data_len); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 334 | |
| 335 | return false; |
| 336 | } |
| 337 | |
Casper Bonde | e2dad8f | 2022-05-24 15:02:30 +0200 | [diff] [blame] | 338 | net_buf_simple_add_u8(buf, codec_data->data_len + sizeof(codec_data->type)); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 339 | net_buf_simple_add_u8(buf, codec_data->type); |
Casper Bonde | e2dad8f | 2022-05-24 15:02:30 +0200 | [diff] [blame] | 340 | net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 341 | |
| 342 | } |
Nazar Kazakov | f483b1b | 2022-03-16 21:07:43 +0000 | [diff] [blame] | 343 | /* Calculate length of codec config data */ |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 344 | len = net_buf_simple_tail(buf) - start - sizeof(len); |
| 345 | /* Update the length field */ |
| 346 | *start = len; |
| 347 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 348 | if ((buf->size - buf->len) < sizeof(len)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 349 | LOG_DBG("No room for metadata length"); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 350 | |
| 351 | return false; |
| 352 | } |
| 353 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 354 | /* Insert codec metadata in LTV format*/ |
| 355 | start = net_buf_simple_add(buf, sizeof(len)); |
| 356 | for (int i = 0; i < codec->meta_count; i++) { |
| 357 | const struct bt_data *metadata = &codec->meta[i].data; |
| 358 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 359 | if ((buf->size - buf->len) < (sizeof(metadata->data_len) + |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 360 | sizeof(metadata->type) + |
| 361 | metadata->data_len)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 362 | LOG_DBG("No room for metadata[%d] with len %u", i, metadata->data_len); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 363 | |
| 364 | return false; |
| 365 | } |
| 366 | |
Casper Bonde | e2dad8f | 2022-05-24 15:02:30 +0200 | [diff] [blame] | 367 | net_buf_simple_add_u8(buf, metadata->data_len + sizeof(metadata->type)); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 368 | net_buf_simple_add_u8(buf, metadata->type); |
Casper Bonde | e2dad8f | 2022-05-24 15:02:30 +0200 | [diff] [blame] | 369 | net_buf_simple_add_mem(buf, metadata->data, metadata->data_len); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 370 | } |
Nazar Kazakov | f483b1b | 2022-03-16 21:07:43 +0000 | [diff] [blame] | 371 | /* Calculate length of codec config data */ |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 372 | len = net_buf_simple_tail(buf) - start - sizeof(len); |
| 373 | /* Update the length field */ |
| 374 | *start = len; |
| 375 | |
| 376 | /* Create BIS index bitfield */ |
| 377 | bis_index = 0; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 378 | for (int i = 0; i < stream_count; i++) { |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 379 | bis_index++; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 380 | if ((buf->size - buf->len) < (sizeof(bis_index) + sizeof(uint8_t))) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 381 | LOG_DBG("No room for BIS[%d] index", i); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 382 | |
| 383 | return false; |
| 384 | } |
| 385 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 386 | net_buf_simple_add_u8(buf, bis_index); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 387 | |
| 388 | if ((buf->size - buf->len) < sizeof(len)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 389 | LOG_DBG("No room for bis codec config length"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 390 | |
| 391 | return false; |
| 392 | } |
| 393 | |
| 394 | /* Insert codec configuration data in LTV format */ |
| 395 | start = net_buf_simple_add(buf, sizeof(len)); |
| 396 | |
| 397 | #if defined(CONFIG_BT_CODEC_MAX_DATA_COUNT) |
| 398 | for (size_t j = 0U; j < stream_data[i].data_count; j++) { |
| 399 | const struct bt_data *codec_data = &stream_data[i].data[j].data; |
| 400 | |
| 401 | if ((buf->size - buf->len) < (sizeof(codec_data->data_len) + |
| 402 | sizeof(codec_data->type) + |
| 403 | codec_data->data_len)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 404 | LOG_DBG("No room for BIS [%u] codec[%zu] with len %u", bis_index, j, |
| 405 | codec_data->data_len); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 406 | |
| 407 | return false; |
| 408 | } |
| 409 | |
| 410 | net_buf_simple_add_u8(buf, codec_data->data_len + sizeof(codec_data->type)); |
| 411 | net_buf_simple_add_u8(buf, codec_data->type); |
| 412 | net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len); |
| 413 | } |
| 414 | #endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT */ |
| 415 | |
| 416 | /* Calculate length of codec config data */ |
| 417 | len = net_buf_simple_tail(buf) - start - sizeof(len); |
| 418 | /* Update the length field */ |
| 419 | *start = len; |
| 420 | |
| 421 | streams_encoded++; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 422 | } |
| 423 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 424 | return true; |
| 425 | } |
| 426 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 427 | static bool encode_base(struct bt_bap_broadcast_source *source, struct net_buf_simple *buf) |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 428 | { |
| 429 | struct bt_audio_broadcast_subgroup *subgroup; |
| 430 | uint8_t streams_encoded; |
| 431 | uint8_t subgroup_count; |
| 432 | |
| 433 | /* 13 is the size of the fixed size values following this check */ |
| 434 | if ((buf->size - buf->len) < MINIMUM_BASE_SIZE) { |
| 435 | return false; |
| 436 | } |
| 437 | |
| 438 | subgroup_count = 0U; |
| 439 | SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { |
| 440 | subgroup_count++; |
| 441 | } |
| 442 | |
| 443 | net_buf_simple_add_le16(buf, BT_UUID_BASIC_AUDIO_VAL); |
| 444 | |
| 445 | net_buf_simple_add_le24(buf, source->qos->pd); |
| 446 | net_buf_simple_add_u8(buf, subgroup_count); |
| 447 | |
| 448 | /* Since the `stream_data` is only stored in the broadcast source, |
| 449 | * we need to provide that information when encoding each subgroup |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 450 | */ |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 451 | streams_encoded = 0; |
| 452 | SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { |
| 453 | if (!encode_base_subgroup(subgroup, |
| 454 | &source->stream_data[streams_encoded], |
| 455 | &streams_encoded, buf)) { |
| 456 | return false; |
| 457 | } |
| 458 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 459 | |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 460 | return true; |
| 461 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 462 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 463 | static int generate_broadcast_id(struct bt_bap_broadcast_source *source) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 464 | { |
| 465 | bool unique; |
| 466 | |
| 467 | do { |
| 468 | int err; |
| 469 | |
| 470 | err = bt_rand(&source->broadcast_id, |
| 471 | BT_AUDIO_BROADCAST_ID_SIZE); |
| 472 | if (err) { |
| 473 | return err; |
| 474 | } |
| 475 | |
| 476 | /* Ensure uniqueness */ |
| 477 | unique = true; |
| 478 | for (int i = 0; i < ARRAY_SIZE(broadcast_sources); i++) { |
| 479 | if (&broadcast_sources[i] == source) { |
| 480 | continue; |
| 481 | } |
| 482 | |
| 483 | if (broadcast_sources[i].broadcast_id == source->broadcast_id) { |
| 484 | unique = false; |
| 485 | break; |
| 486 | } |
| 487 | } |
| 488 | } while (!unique); |
| 489 | |
| 490 | return 0; |
| 491 | } |
| 492 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 493 | static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 494 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 495 | struct bt_audio_broadcast_subgroup *subgroup, *next_subgroup; |
Emil Gydesen | 5628b29 | 2022-03-11 16:20:31 +0100 | [diff] [blame] | 496 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 497 | SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&source->subgroups, subgroup, |
| 498 | next_subgroup, _node) { |
| 499 | struct bt_audio_stream *stream, *next_stream; |
Emil Gydesen | 468bd4d | 2022-03-11 14:58:51 +0100 | [diff] [blame] | 500 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 501 | SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&subgroup->streams, stream, |
| 502 | next_stream, _node) { |
| 503 | bt_audio_iso_unbind_ep(stream->ep->iso, stream->ep); |
| 504 | stream->ep->stream = NULL; |
| 505 | stream->ep = NULL; |
| 506 | stream->codec = NULL; |
| 507 | stream->qos = NULL; |
| 508 | stream->group = NULL; |
| 509 | |
| 510 | sys_slist_remove(&subgroup->streams, NULL, |
| 511 | &stream->_node); |
| 512 | } |
| 513 | sys_slist_remove(&source->subgroups, NULL, &subgroup->_node); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 514 | } |
| 515 | |
| 516 | (void)memset(source, 0, sizeof(*source)); |
| 517 | } |
| 518 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 519 | static bool valid_create_param(const struct bt_bap_broadcast_source_create_param *param) |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 520 | { |
| 521 | const struct bt_codec_qos *qos; |
| 522 | |
| 523 | CHECKIF(param == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 524 | LOG_DBG("param is NULL"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 525 | return false; |
| 526 | } |
| 527 | |
| 528 | CHECKIF(param->params_count == 0U) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 529 | LOG_DBG("param->params_count is 0"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 530 | return false; |
| 531 | } |
| 532 | |
Emil Gydesen | ba19497 | 2022-12-20 15:39:07 +0100 | [diff] [blame] | 533 | CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL && |
| 534 | param->packing != BT_ISO_PACKING_INTERLEAVED) { |
| 535 | LOG_DBG("param->packing %u is invalid", param->packing); |
| 536 | return false; |
| 537 | } |
| 538 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 539 | qos = param->qos; |
| 540 | CHECKIF(qos == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 541 | LOG_DBG("param->qos is NULL"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 542 | return false; |
| 543 | } |
| 544 | |
| 545 | CHECKIF(!bt_audio_valid_qos(qos)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 546 | LOG_DBG("param->qos is invalid"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 547 | return false; |
| 548 | } |
| 549 | |
| 550 | for (size_t i = 0U; i < param->params_count; i++) { |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 551 | const struct bt_bap_broadcast_source_subgroup_param *subgroup_param; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 552 | |
| 553 | subgroup_param = ¶m->params[i]; |
| 554 | |
| 555 | CHECKIF(subgroup_param->params_count == 0U) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 556 | LOG_DBG("subgroup_params[%zu].count is 0", i); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 557 | return false; |
| 558 | } |
| 559 | |
| 560 | CHECKIF(subgroup_param->codec == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 561 | LOG_DBG("subgroup_params[%zu].codec is NULL", i); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 562 | return false; |
| 563 | } |
| 564 | |
| 565 | for (size_t j = 0U; j < subgroup_param->params_count; j++) { |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 566 | const struct bt_bap_broadcast_source_stream_param *stream_param; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 567 | |
| 568 | stream_param = &subgroup_param->params[j]; |
| 569 | |
| 570 | CHECKIF(stream_param->stream == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 571 | LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is NULL", |
| 572 | i, j); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 573 | return false; |
| 574 | } |
| 575 | |
| 576 | CHECKIF(stream_param->stream->group != NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 577 | LOG_DBG("subgroup_params[%zu].stream_params[%zu]->stream is " |
| 578 | "already part of group %p", |
| 579 | i, j, stream_param->stream->group); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 580 | return false; |
| 581 | } |
| 582 | } |
| 583 | } |
| 584 | |
| 585 | return true; |
| 586 | } |
| 587 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 588 | static enum bt_audio_state broadcast_source_get_state(struct bt_bap_broadcast_source *source) |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 589 | { |
| 590 | struct bt_audio_broadcast_subgroup *subgroup; |
| 591 | struct bt_audio_stream *stream; |
| 592 | sys_snode_t *head_node; |
| 593 | |
| 594 | if (source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 595 | LOG_DBG("source is NULL"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 596 | return BT_AUDIO_EP_STATE_IDLE; |
| 597 | } |
| 598 | |
| 599 | if (sys_slist_is_empty(&source->subgroups)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 600 | LOG_DBG("Source does not have any streams"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 601 | return BT_AUDIO_EP_STATE_IDLE; |
| 602 | } |
| 603 | |
| 604 | /* Get the first stream */ |
| 605 | head_node = sys_slist_peek_head(&source->subgroups); |
| 606 | subgroup = CONTAINER_OF(head_node, struct bt_audio_broadcast_subgroup, _node); |
| 607 | |
| 608 | head_node = sys_slist_peek_head(&subgroup->streams); |
| 609 | stream = CONTAINER_OF(head_node, struct bt_audio_stream, _node); |
| 610 | |
| 611 | /* All streams in a broadcast source is in the same state, |
| 612 | * so we can just check the first stream |
| 613 | */ |
| 614 | if (stream->ep == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 615 | LOG_DBG("stream->ep is NULL"); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 616 | return BT_AUDIO_EP_STATE_IDLE; |
| 617 | } |
| 618 | |
| 619 | return stream->ep->status.state; |
| 620 | } |
| 621 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 622 | int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param *param, |
| 623 | struct bt_bap_broadcast_source **out_source) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 624 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 625 | struct bt_audio_broadcast_subgroup *subgroup; |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 626 | struct bt_bap_broadcast_source *source; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 627 | struct bt_codec_qos *qos; |
| 628 | size_t stream_count; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 629 | uint8_t index; |
| 630 | int err; |
| 631 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 632 | CHECKIF(out_source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 633 | LOG_DBG("out_source is NULL"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 634 | return -EINVAL; |
| 635 | } |
| 636 | /* Set out_source to NULL until the source has actually been created */ |
| 637 | *out_source = NULL; |
| 638 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 639 | if (!valid_create_param(param)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 640 | LOG_DBG("Invalid parameters"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 641 | return -EINVAL; |
| 642 | } |
| 643 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 644 | source = NULL; |
| 645 | for (index = 0; index < ARRAY_SIZE(broadcast_sources); index++) { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 646 | if (sys_slist_is_empty(&broadcast_sources[index].subgroups)) { /* Find free entry */ |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 647 | source = &broadcast_sources[index]; |
| 648 | break; |
| 649 | } |
| 650 | } |
| 651 | |
| 652 | if (source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 653 | LOG_DBG("Could not allocate any more broadcast sources"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 654 | return -ENOMEM; |
| 655 | } |
| 656 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 657 | stream_count = 0U; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 658 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 659 | qos = param->qos; |
| 660 | /* Go through all subgroups and streams and setup each setup with an |
| 661 | * endpoint |
| 662 | */ |
| 663 | for (size_t i = 0U; i < param->params_count; i++) { |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 664 | const struct bt_bap_broadcast_source_subgroup_param *subgroup_param; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 665 | |
| 666 | subgroup_param = ¶m->params[i]; |
| 667 | |
| 668 | subgroup = broadcast_source_new_subgroup(index); |
| 669 | if (subgroup == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 670 | LOG_DBG("Could not allocate new broadcast subgroup"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 671 | broadcast_source_cleanup(source); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 672 | return -ENOMEM; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 673 | } |
| 674 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 675 | subgroup->codec = subgroup_param->codec; |
| 676 | sys_slist_append(&source->subgroups, &subgroup->_node); |
| 677 | |
| 678 | /* Check that we are not above the maximum BIS count */ |
| 679 | if (subgroup_param->params_count + stream_count > BROADCAST_STREAM_CNT) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 680 | LOG_DBG("Cannot create broadcaster with %zu streams", stream_count); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 681 | broadcast_source_cleanup(source); |
| 682 | |
| 683 | return -ENOMEM; |
| 684 | } |
| 685 | |
| 686 | for (size_t j = 0U; j < subgroup_param->params_count; j++) { |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 687 | const struct bt_bap_broadcast_source_stream_param *stream_param; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 688 | struct bt_audio_stream *stream; |
| 689 | |
| 690 | stream_param = &subgroup_param->params[j]; |
| 691 | stream = stream_param->stream; |
| 692 | |
| 693 | err = broadcast_source_setup_stream(index, stream, |
| 694 | subgroup_param->codec, |
| 695 | qos, source); |
| 696 | if (err != 0) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 697 | LOG_DBG("Failed to setup streams[%zu]: %d", i, err); |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 698 | broadcast_source_cleanup(source); |
| 699 | return err; |
| 700 | } |
| 701 | |
| 702 | /* Store the BIS specific codec configuration data in |
| 703 | * the broadcast source. It is stored in the broadcast |
| 704 | * source, instead of the stream object, as this is |
| 705 | * only relevant for the broadcast source, and not used |
| 706 | * for unicast or broadcast sink. |
| 707 | */ |
| 708 | (void)memcpy(source->stream_data[stream_count].data, |
| 709 | stream_param->data, |
| 710 | stream_param->data_count * sizeof(*stream_param->data)); |
| 711 | source->stream_data[stream_count].data_count = stream_param->data_count; |
| 712 | |
| 713 | sys_slist_append(&subgroup->streams, &stream->_node); |
| 714 | stream_count++; |
| 715 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 716 | } |
| 717 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 718 | err = generate_broadcast_id(source); |
| 719 | if (err != 0) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 720 | LOG_DBG("Could not generate broadcast id: %d", err); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 721 | return err; |
| 722 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 723 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 724 | /* Finalize state changes and store information */ |
| 725 | SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { |
| 726 | struct bt_audio_stream *stream; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 727 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 728 | SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) { |
| 729 | broadcast_source_set_ep_state(stream->ep, |
| 730 | BT_AUDIO_EP_STATE_QOS_CONFIGURED); |
| 731 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 732 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 733 | source->qos = qos; |
Emil Gydesen | ba19497 | 2022-12-20 15:39:07 +0100 | [diff] [blame] | 734 | source->packing = param->packing; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 735 | |
Emil Gydesen | 8d86fa0 | 2022-12-13 21:03:14 +0100 | [diff] [blame] | 736 | source->encryption = param->encryption; |
| 737 | if (source->encryption) { |
| 738 | (void)memcpy(source->broadcast_code, param->broadcast_code, |
| 739 | sizeof(source->broadcast_code)); |
| 740 | } |
| 741 | |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 742 | LOG_DBG("Broadcasting with ID 0x%6X", source->broadcast_id); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 743 | |
| 744 | *out_source = source; |
| 745 | |
| 746 | return 0; |
| 747 | } |
| 748 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 749 | int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, struct bt_codec *codec, |
| 750 | struct bt_codec_qos *qos) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 751 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 752 | struct bt_audio_broadcast_subgroup *subgroup; |
| 753 | enum bt_audio_state broadcast_state; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 754 | struct bt_audio_stream *stream; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 755 | |
| 756 | CHECKIF(source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 757 | LOG_DBG("source is NULL"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 758 | return -EINVAL; |
| 759 | } |
| 760 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 761 | broadcast_state = broadcast_source_get_state(source); |
| 762 | if (broadcast_source_get_state(source) != BT_AUDIO_EP_STATE_QOS_CONFIGURED) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 763 | LOG_DBG("Broadcast source invalid state: %u", broadcast_state); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 764 | return -EBADMSG; |
| 765 | } |
| 766 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 767 | SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { |
| 768 | SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) { |
Emil Gydesen | e5890fc | 2023-01-24 14:41:17 +0100 | [diff] [blame] | 769 | struct bt_iso_chan_io_qos *iso_qos; |
| 770 | |
| 771 | iso_qos = stream->ep->iso->chan.qos->tx; |
| 772 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 773 | bt_audio_stream_attach(NULL, stream, stream->ep, codec); |
Emil Gydesen | e5890fc | 2023-01-24 14:41:17 +0100 | [diff] [blame] | 774 | |
| 775 | bt_audio_codec_qos_to_iso_qos(iso_qos, qos); |
| 776 | bt_audio_codec_to_iso_path(iso_qos->path, codec); |
| 777 | stream->qos = qos; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 778 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 779 | } |
| 780 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 781 | source->qos = qos; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 782 | |
| 783 | return 0; |
| 784 | } |
| 785 | |
Emil Gydesen | 1424df4 | 2022-06-28 20:09:13 +0200 | [diff] [blame] | 786 | static void broadcast_source_store_metadata(struct bt_codec *codec, |
| 787 | const struct bt_codec_data meta[], |
| 788 | size_t meta_count) |
| 789 | { |
| 790 | size_t old_meta_count; |
| 791 | |
| 792 | old_meta_count = codec->meta_count; |
| 793 | |
| 794 | /* Update metadata */ |
| 795 | codec->meta_count = meta_count; |
| 796 | (void)memcpy(codec->meta, meta, meta_count * sizeof(*meta)); |
| 797 | if (old_meta_count > meta_count) { |
| 798 | size_t meta_count_diff = old_meta_count - meta_count; |
| 799 | |
| 800 | /* If we previously had more metadata entries we reset the |
| 801 | * data that was not overwritten by the new metadata |
| 802 | */ |
| 803 | (void)memset(&codec->meta[meta_count], |
| 804 | 0, meta_count_diff * sizeof(*meta)); |
| 805 | } |
| 806 | } |
| 807 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 808 | int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source, |
| 809 | const struct bt_codec_data meta[], size_t meta_count) |
Emil Gydesen | 1424df4 | 2022-06-28 20:09:13 +0200 | [diff] [blame] | 810 | { |
| 811 | struct bt_audio_broadcast_subgroup *subgroup; |
| 812 | enum bt_audio_state broadcast_state; |
| 813 | |
| 814 | CHECKIF(source == NULL) { |
| 815 | LOG_DBG("source is NULL"); |
| 816 | |
| 817 | return -EINVAL; |
| 818 | } |
| 819 | |
| 820 | CHECKIF((meta == NULL && meta_count != 0) || |
| 821 | (meta != NULL && meta_count == 0)) { |
| 822 | LOG_DBG("Invalid metadata combination: %p %zu", |
| 823 | meta, meta_count); |
| 824 | |
| 825 | return -EINVAL; |
| 826 | } |
| 827 | |
| 828 | CHECKIF(meta_count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) { |
| 829 | LOG_DBG("Invalid meta_count: %zu (max %d)", |
| 830 | meta_count, CONFIG_BT_CODEC_MAX_METADATA_COUNT); |
| 831 | |
| 832 | return -EINVAL; |
| 833 | } |
| 834 | |
| 835 | for (size_t i = 0; i < meta_count; i++) { |
| 836 | CHECKIF(meta[i].data.data_len > sizeof(meta[i].value)) { |
| 837 | LOG_DBG("Invalid meta[%zu] data_len %u", |
| 838 | i, meta[i].data.data_len); |
| 839 | |
| 840 | return -EINVAL; |
| 841 | } |
| 842 | } |
| 843 | broadcast_state = broadcast_source_get_state(source); |
| 844 | if (broadcast_source_get_state(source) != BT_AUDIO_EP_STATE_STREAMING) { |
| 845 | LOG_DBG("Broadcast source invalid state: %u", broadcast_state); |
| 846 | |
| 847 | return -EBADMSG; |
| 848 | } |
| 849 | |
| 850 | /* TODO: We should probably find a way to update the metadata |
| 851 | * for each subgroup individually |
| 852 | */ |
| 853 | SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { |
| 854 | broadcast_source_store_metadata(subgroup->codec, meta, meta_count); |
| 855 | } |
| 856 | |
| 857 | return 0; |
| 858 | } |
| 859 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 860 | int bt_bap_broadcast_source_start(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv *adv) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 861 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 862 | struct bt_iso_chan *bis[BROADCAST_STREAM_CNT]; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 863 | struct bt_iso_big_create_param param = { 0 }; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 864 | struct bt_audio_broadcast_subgroup *subgroup; |
| 865 | enum bt_audio_state broadcast_state; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 866 | struct bt_audio_stream *stream; |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 867 | size_t bis_count; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 868 | int err; |
| 869 | |
| 870 | CHECKIF(source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 871 | LOG_DBG("source is NULL"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 872 | return -EINVAL; |
| 873 | } |
| 874 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 875 | broadcast_state = broadcast_source_get_state(source); |
| 876 | if (broadcast_source_get_state(source) != BT_AUDIO_EP_STATE_QOS_CONFIGURED) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 877 | LOG_DBG("Broadcast source invalid state: %u", broadcast_state); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 878 | return -EBADMSG; |
| 879 | } |
| 880 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 881 | bis_count = 0; |
| 882 | SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { |
| 883 | SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) { |
| 884 | bis[bis_count++] = bt_audio_stream_iso_chan_get(stream); |
| 885 | } |
| 886 | } |
| 887 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 888 | /* Create BIG */ |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 889 | param.num_bis = bis_count; |
| 890 | param.bis_channels = bis; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 891 | param.framing = source->qos->framing; |
Emil Gydesen | ba19497 | 2022-12-20 15:39:07 +0100 | [diff] [blame] | 892 | param.packing = source->packing; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 893 | param.interval = source->qos->interval; |
| 894 | param.latency = source->qos->latency; |
Emil Gydesen | 8d86fa0 | 2022-12-13 21:03:14 +0100 | [diff] [blame] | 895 | param.encryption = source->encryption; |
| 896 | if (param.encryption) { |
| 897 | (void)memcpy(param.bcode, source->broadcast_code, |
| 898 | sizeof(param.bcode)); |
| 899 | } |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 900 | |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 901 | err = bt_iso_big_create(adv, ¶m, &source->big); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 902 | if (err != 0) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 903 | LOG_DBG("Failed to create BIG: %d", err); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 904 | return err; |
| 905 | } |
| 906 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 907 | SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { |
| 908 | SYS_SLIST_FOR_EACH_CONTAINER(&subgroup->streams, stream, _node) { |
| 909 | struct bt_audio_ep *ep = stream->ep; |
Emil Gydesen | 05ace18 | 2022-06-03 10:48:19 +0200 | [diff] [blame] | 910 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 911 | broadcast_source_set_ep_state(ep, BT_AUDIO_EP_STATE_ENABLING); |
| 912 | } |
Emil Gydesen | 05ace18 | 2022-06-03 10:48:19 +0200 | [diff] [blame] | 913 | } |
| 914 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 915 | return 0; |
| 916 | } |
| 917 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 918 | int bt_bap_broadcast_source_stop(struct bt_bap_broadcast_source *source) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 919 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 920 | enum bt_audio_state broadcast_state; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 921 | int err; |
| 922 | |
| 923 | CHECKIF(source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 924 | LOG_DBG("source is NULL"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 925 | return -EINVAL; |
| 926 | } |
| 927 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 928 | broadcast_state = broadcast_source_get_state(source); |
| 929 | if (broadcast_state != BT_AUDIO_EP_STATE_STREAMING && |
| 930 | broadcast_state != BT_AUDIO_EP_STATE_ENABLING) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 931 | LOG_DBG("Broadcast source invalid state: %u", broadcast_state); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 932 | return -EBADMSG; |
| 933 | } |
| 934 | |
| 935 | if (source->big == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 936 | LOG_DBG("Source is not started"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 937 | return -EALREADY; |
| 938 | } |
| 939 | |
| 940 | err = bt_iso_big_terminate(source->big); |
| 941 | if (err) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 942 | LOG_DBG("Failed to terminate BIG (err %d)", err); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 943 | return err; |
| 944 | } |
| 945 | |
| 946 | source->big = NULL; |
| 947 | |
| 948 | return 0; |
| 949 | } |
| 950 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 951 | int bt_bap_broadcast_source_delete(struct bt_bap_broadcast_source *source) |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 952 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 953 | enum bt_audio_state broadcast_state; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 954 | |
| 955 | CHECKIF(source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 956 | LOG_DBG("source is NULL"); |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 957 | return -EINVAL; |
| 958 | } |
| 959 | |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 960 | broadcast_state = broadcast_source_get_state(source); |
| 961 | if (broadcast_state != BT_AUDIO_EP_STATE_QOS_CONFIGURED) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 962 | LOG_DBG("Broadcast source invalid state: %u", broadcast_state); |
Emil Gydesen | 468bd4d | 2022-03-11 14:58:51 +0100 | [diff] [blame] | 963 | return -EBADMSG; |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 964 | } |
| 965 | |
Emil Gydesen | ab87e0a | 2022-01-10 15:06:08 +0100 | [diff] [blame] | 966 | /* Reset the broadcast source */ |
| 967 | broadcast_source_cleanup(source); |
| 968 | |
| 969 | return 0; |
| 970 | } |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 971 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 972 | int bt_bap_broadcast_source_get_id(const struct bt_bap_broadcast_source *source, |
| 973 | uint32_t *const broadcast_id) |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 974 | { |
| 975 | CHECKIF(source == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 976 | LOG_DBG("source is NULL"); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 977 | return -EINVAL; |
| 978 | } |
| 979 | |
| 980 | CHECKIF(broadcast_id == NULL) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 981 | LOG_DBG("broadcast_id is NULL"); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 982 | return -EINVAL; |
| 983 | } |
| 984 | |
| 985 | *broadcast_id = source->broadcast_id; |
| 986 | |
| 987 | return 0; |
| 988 | } |
| 989 | |
Emil Gydesen | be42429 | 2023-02-25 16:47:19 +0100 | [diff] [blame^] | 990 | int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source, |
| 991 | struct net_buf_simple *base_buf) |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 992 | { |
Emil Gydesen | 40e3930 | 2022-09-05 11:29:06 +0200 | [diff] [blame] | 993 | if (!encode_base(source, base_buf)) { |
Théo Battrel | e458f5a | 2022-11-02 14:31:13 +0100 | [diff] [blame] | 994 | LOG_DBG("base_buf %p with size %u not large enough", base_buf, base_buf->size); |
Emil Gydesen | 7ab1caf | 2022-09-02 15:43:30 +0200 | [diff] [blame] | 995 | |
| 996 | return -EMSGSIZE; |
| 997 | } |
| 998 | |
| 999 | return 0; |
| 1000 | } |