1 /* Bluetooth Audio Stream */
2
3 /*
4 * Copyright (c) 2020 Intel Corporation
5 * Copyright (c) 2021-2024 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <errno.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <string.h>
15
16 #include <zephyr/autoconf.h>
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/gap.h>
20 #include <zephyr/bluetooth/gatt.h>
21 #include <zephyr/bluetooth/hci.h>
22 #include <zephyr/bluetooth/hci_types.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/bluetooth/audio/audio.h>
25 #include <zephyr/bluetooth/audio/bap.h>
26 #include <zephyr/kernel.h>
27 #include <zephyr/logging/log.h>
28 #include <zephyr/net_buf.h>
29 #include <zephyr/sys/__assert.h>
30 #include <zephyr/sys/byteorder.h>
31 #include <zephyr/sys/check.h>
32 #include <zephyr/sys/slist.h>
33 #include <zephyr/sys/util.h>
34 #include <zephyr/sys/util_macro.h>
35
36 #include "../host/iso_internal.h"
37
38 #include "audio_internal.h"
39 #include "bap_iso.h"
40 #include "bap_endpoint.h"
41 #include "bap_unicast_client_internal.h"
42 #include "bap_unicast_server.h"
43
44 LOG_MODULE_REGISTER(bt_bap_stream, CONFIG_BT_BAP_STREAM_LOG_LEVEL);
45
46 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \
47 defined(CONFIG_BT_BAP_BROADCAST_SINK)
bt_bap_qos_cfg_to_iso_qos(struct bt_iso_chan_io_qos * io,const struct bt_bap_qos_cfg * qos_cfg)48 void bt_bap_qos_cfg_to_iso_qos(struct bt_iso_chan_io_qos *io, const struct bt_bap_qos_cfg *qos_cfg)
49 {
50 io->sdu = qos_cfg->sdu;
51 io->phy = qos_cfg->phy;
52 io->rtn = qos_cfg->rtn;
53 #if defined(CONFIG_BT_ISO_TEST_PARAMS)
54 io->burst_number = qos_cfg->burst_number;
55 io->max_pdu = qos_cfg->max_pdu;
56 #endif /* CONFIG_BT_ISO_TEST_PARAMS */
57 }
58 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT || \
59 * CONFIG_BT_BAP_BROADCAST_SOURCE || \
60 * CONFIG_BT_BAP_BROADCAST_SINK \
61 */
62
bt_bap_stream_init(struct bt_bap_stream * stream)63 void bt_bap_stream_init(struct bt_bap_stream *stream)
64 {
65 struct bt_bap_stream_ops *ops;
66 void *user_data;
67
68 /* Save the stream->ops and stream->user_data owned by API user */
69 ops = stream->ops;
70 user_data = stream->user_data;
71
72 memset(stream, 0, sizeof(*stream));
73
74 /* Restore */
75 stream->ops = ops;
76 stream->user_data = user_data;
77 }
78
bt_bap_stream_attach(struct bt_conn * conn,struct bt_bap_stream * stream,struct bt_bap_ep * ep,struct bt_audio_codec_cfg * codec_cfg)79 void bt_bap_stream_attach(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep,
80 struct bt_audio_codec_cfg *codec_cfg)
81 {
82 LOG_DBG("conn %p stream %p ep %p codec_cfg %p", (void *)conn, stream, ep, codec_cfg);
83
84 if (conn != NULL) {
85 __ASSERT(stream->conn == NULL || stream->conn == conn,
86 "stream->conn %p already attached", (void *)stream->conn);
87 if (stream->conn == NULL) {
88 stream->conn = bt_conn_ref(conn);
89 }
90 }
91 stream->codec_cfg = codec_cfg;
92 stream->ep = ep;
93 ep->stream = stream;
94 }
95
bt_bap_stream_iso_chan_get(struct bt_bap_stream * stream)96 struct bt_iso_chan *bt_bap_stream_iso_chan_get(struct bt_bap_stream *stream)
97 {
98 if (stream != NULL && stream->ep != NULL && stream->ep->iso != NULL) {
99 return &stream->ep->iso->chan;
100 }
101
102 return NULL;
103 }
104
bt_bap_stream_cb_register(struct bt_bap_stream * stream,struct bt_bap_stream_ops * ops)105 void bt_bap_stream_cb_register(struct bt_bap_stream *stream,
106 struct bt_bap_stream_ops *ops)
107 {
108 stream->ops = ops;
109 }
110
bt_bap_ep_get_info(const struct bt_bap_ep * ep,struct bt_bap_ep_info * info)111 int bt_bap_ep_get_info(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info)
112 {
113 enum bt_audio_dir dir;
114
115 CHECKIF(ep == NULL) {
116 LOG_DBG("ep is NULL");
117
118 return -EINVAL;
119 }
120
121 CHECKIF(info == NULL) {
122 LOG_DBG("info is NULL");
123
124 return -EINVAL;
125 }
126
127 dir = ep->dir;
128
129 info->id = ep->status.id;
130 info->state = ep->status.state;
131 info->dir = dir;
132 info->qos_pref = &ep->qos_pref;
133
134 if (ep->iso == NULL) {
135 info->paired_ep = NULL;
136 info->iso_chan = NULL;
137 } else {
138 info->paired_ep = bt_bap_iso_get_paired_ep(ep);
139 info->iso_chan = &ep->iso->chan;
140 }
141
142 info->can_send = false;
143 info->can_recv = false;
144 if (IS_ENABLED(CONFIG_BT_AUDIO_TX) && ep->stream != NULL) {
145 if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) && bt_bap_ep_is_broadcast_src(ep)) {
146 info->can_send = true;
147 } else if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK) &&
148 bt_bap_ep_is_broadcast_snk(ep)) {
149 info->can_recv = true;
150 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
151 bt_bap_ep_is_unicast_client(ep)) {
152 /* dir is not initialized before the connection is set */
153 if (ep->stream->conn != NULL) {
154 info->can_send = dir == BT_AUDIO_DIR_SINK;
155 info->can_recv = dir == BT_AUDIO_DIR_SOURCE;
156 }
157 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER)) {
158 /* dir is not initialized before the connection is set */
159 if (ep->stream->conn != NULL) {
160 info->can_send = dir == BT_AUDIO_DIR_SOURCE;
161 info->can_recv = dir == BT_AUDIO_DIR_SINK;
162 }
163 }
164 }
165
166 return 0;
167 }
168
bt_audio_verify_qos(const struct bt_bap_qos_cfg * qos)169 enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_bap_qos_cfg *qos)
170 {
171 if (qos->interval < BT_ISO_SDU_INTERVAL_MIN ||
172 qos->interval > BT_ISO_SDU_INTERVAL_MAX) {
173 LOG_DBG("Interval not within allowed range: %u (%u-%u)", qos->interval,
174 BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX);
175 return BT_BAP_ASCS_REASON_INTERVAL;
176 }
177
178 if (qos->framing > BT_BAP_QOS_CFG_FRAMING_FRAMED) {
179 LOG_DBG("Invalid Framing 0x%02x", qos->framing);
180 return BT_BAP_ASCS_REASON_FRAMING;
181 }
182
183 if (qos->phy != BT_BAP_QOS_CFG_1M && qos->phy != BT_BAP_QOS_CFG_2M &&
184 qos->phy != BT_BAP_QOS_CFG_CODED) {
185 LOG_DBG("Invalid PHY 0x%02x", qos->phy);
186 return BT_BAP_ASCS_REASON_PHY;
187 }
188
189 if (qos->sdu > BT_ISO_MAX_SDU) {
190 LOG_DBG("Invalid SDU %u", qos->sdu);
191 return BT_BAP_ASCS_REASON_SDU;
192 }
193
194 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_UNICAST)
195 if (qos->latency < BT_ISO_LATENCY_MIN ||
196 qos->latency > BT_ISO_LATENCY_MAX) {
197 LOG_DBG("Invalid Latency %u", qos->latency);
198 return BT_BAP_ASCS_REASON_LATENCY;
199 }
200 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE || CONFIG_BT_BAP_UNICAST */
201
202 if (qos->pd > BT_AUDIO_PD_MAX) {
203 LOG_DBG("Invalid presentation delay %u", qos->pd);
204 return BT_BAP_ASCS_REASON_PD;
205 }
206
207 return BT_BAP_ASCS_REASON_NONE;
208 }
209
bt_audio_valid_codec_cfg(const struct bt_audio_codec_cfg * codec_cfg)210 bool bt_audio_valid_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
211 {
212 if (codec_cfg == NULL) {
213 LOG_DBG("codec is NULL");
214 return false;
215 }
216
217 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
218 if (codec_cfg->cid != 0U) {
219 LOG_DBG("codec_cfg->cid (%u) is invalid", codec_cfg->cid);
220 return false;
221 }
222
223 if (codec_cfg->vid != 0U) {
224 LOG_DBG("codec_cfg->vid (%u) is invalid", codec_cfg->vid);
225 return false;
226 }
227 }
228
229 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
230 /* Verify that codec configuration length is 0 when using
231 * BT_HCI_CODING_FORMAT_TRANSPARENT as per the core spec, 5.4, Vol 4, Part E, 7.8.109
232 */
233 if (codec_cfg->id == BT_HCI_CODING_FORMAT_TRANSPARENT && codec_cfg->data_len != 0) {
234 LOG_DBG("Invalid data_len %zu for codec_id %u", codec_cfg->data_len, codec_cfg->id);
235 return false;
236 }
237
238 if (codec_cfg->data_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE) {
239 LOG_DBG("codec_cfg->data_len (%zu) is invalid", codec_cfg->data_len);
240 return false;
241 }
242
243 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3 &&
244 !bt_audio_valid_ltv(codec_cfg->data, codec_cfg->data_len)) {
245 LOG_DBG("codec_cfg->data not valid LTV");
246 return false;
247 }
248 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
249
250 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0
251 if (codec_cfg->meta_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
252 LOG_DBG("codec_cfg->meta_len (%zu) is invalid", codec_cfg->meta_len);
253 return false;
254 }
255
256 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3 &&
257 !bt_audio_valid_ltv(codec_cfg->data, codec_cfg->data_len)) {
258 LOG_DBG("codec_cfg->meta not valid LTV");
259 return false;
260 }
261 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */
262
263 return true;
264 }
265
bt_bap_valid_qos_pref(const struct bt_bap_qos_cfg_pref * qos_pref)266 bool bt_bap_valid_qos_pref(const struct bt_bap_qos_cfg_pref *qos_pref)
267 {
268 const uint8_t phy_mask = BT_GAP_LE_PHY_1M | BT_GAP_LE_PHY_2M | BT_GAP_LE_PHY_CODED;
269
270 if ((qos_pref->phy & (~phy_mask)) != 0U) {
271 LOG_DBG("Invalid phy: %u", qos_pref->phy);
272
273 return false;
274 }
275
276 if (!IN_RANGE(qos_pref->latency, BT_ISO_LATENCY_MIN, BT_ISO_LATENCY_MAX)) {
277 LOG_DBG("Invalid latency: %u", qos_pref->latency);
278
279 return false;
280 }
281
282 if (qos_pref->pd_min > BT_AUDIO_PD_MAX) {
283 LOG_DBG("Invalid pd_min: %u", qos_pref->pd_min);
284
285 return false;
286 }
287
288 if (qos_pref->pd_max > BT_AUDIO_PD_MAX) {
289 LOG_DBG("Invalid pd_min: %u", qos_pref->pd_min);
290
291 return false;
292 }
293
294 if (qos_pref->pd_max < qos_pref->pd_min) {
295 LOG_DBG("Invalid combination of pd_min %u and pd_max: %u", qos_pref->pd_min,
296 qos_pref->pd_max);
297
298 return false;
299 }
300
301 if (qos_pref->pref_pd_min != BT_AUDIO_PD_PREF_NONE) {
302 /* If pref_pd_min != BT_AUDIO_PD_PREF_NONE then pd_min <= pref_pd_min <= pd_max */
303 if (!IN_RANGE(qos_pref->pref_pd_min, qos_pref->pd_min, qos_pref->pd_max)) {
304 LOG_DBG("Invalid combination of pref_pd_min %u, pd_min %u and pd_max: %u",
305 qos_pref->pref_pd_min, qos_pref->pd_min, qos_pref->pd_max);
306
307 return false;
308 }
309 }
310
311 if (qos_pref->pref_pd_max != BT_AUDIO_PD_PREF_NONE) {
312 /* If pref_pd_min == BT_AUDIO_PD_PREF_NONE then pd_min <= pref_pd_max <= pd_max
313 *
314 * If pref_pd_min != BT_AUDIO_PD_PREF_NONE then
315 * pd_min <= pref_pd_min <= pref_pd_max <= pd_max
316 */
317 if (qos_pref->pref_pd_min == BT_AUDIO_PD_PREF_NONE) {
318 if (!IN_RANGE(qos_pref->pref_pd_max, qos_pref->pd_min, qos_pref->pd_max)) {
319 LOG_DBG("Invalid combination of pref_pd_max %u, pd_min %u and "
320 "pd_max: %u",
321 qos_pref->pref_pd_max, qos_pref->pd_min, qos_pref->pd_max);
322
323 return false;
324 }
325 } else {
326 if (!IN_RANGE(qos_pref->pref_pd_max, qos_pref->pref_pd_min,
327 qos_pref->pd_max)) {
328 LOG_DBG("Invalid combination of pref_pd_max %u, pref_pd_min %u and "
329 "pd_max: %u",
330 qos_pref->pref_pd_max, qos_pref->pd_min, qos_pref->pd_max);
331
332 return false;
333 }
334 }
335 }
336
337 return true;
338 }
339
340 #if defined(CONFIG_BT_AUDIO_TX)
bt_bap_stream_can_send(const struct bt_bap_stream * stream)341 static bool bt_bap_stream_can_send(const struct bt_bap_stream *stream)
342 {
343 struct bt_bap_ep_info info;
344 int err;
345
346 if (stream == NULL || stream->ep == NULL) {
347 return false;
348 }
349
350 err = bt_bap_ep_get_info(stream->ep, &info);
351 if (err != 0) {
352 return false;
353 }
354
355 return info.can_send;
356 }
357
bap_stream_send(struct bt_bap_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts,bool has_ts)358 static int bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, uint16_t seq_num,
359 uint32_t ts, bool has_ts)
360 {
361 struct bt_iso_chan *iso_chan;
362 struct bt_bap_ep *ep;
363 int ret;
364
365 if (stream == NULL) {
366 LOG_DBG("stream is NULL");
367 return -EINVAL;
368 }
369
370 if (stream->ep == NULL) {
371 LOG_DBG("stream->ep %p is NULL", stream);
372 return -EINVAL;
373 }
374
375 if (!bt_bap_stream_can_send(stream)) {
376 LOG_DBG("Stream is not configured for TX");
377
378 return -EINVAL;
379 }
380
381 ep = stream->ep;
382
383 if (ep->status.state != BT_BAP_EP_STATE_STREAMING) {
384 LOG_DBG("Channel %p not ready for streaming (state: %s)", stream,
385 bt_bap_ep_state_str(ep->status.state));
386 return -EBADMSG;
387 }
388
389 iso_chan = bt_bap_stream_iso_chan_get(stream);
390
391 if (has_ts) {
392 ret = bt_iso_chan_send_ts(iso_chan, buf, seq_num, ts);
393 } else {
394 ret = bt_iso_chan_send(iso_chan, buf, seq_num);
395 }
396
397 if (ret < 0) {
398 return ret;
399 }
400
401 #if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM)
402 if (stream->_prev_seq_num != 0U && seq_num != 0U &&
403 (stream->_prev_seq_num + 1U) != seq_num) {
404 LOG_WRN("Unexpected seq_num diff between %u and %u for %p", stream->_prev_seq_num,
405 seq_num, stream);
406 }
407
408 stream->_prev_seq_num = seq_num;
409 #endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */
410
411 return ret;
412 }
413
bt_bap_stream_send(struct bt_bap_stream * stream,struct net_buf * buf,uint16_t seq_num)414 int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, uint16_t seq_num)
415 {
416 return bap_stream_send(stream, buf, seq_num, 0, false);
417 }
418
bt_bap_stream_send_ts(struct bt_bap_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts)419 int bt_bap_stream_send_ts(struct bt_bap_stream *stream, struct net_buf *buf, uint16_t seq_num,
420 uint32_t ts)
421 {
422 return bap_stream_send(stream, buf, seq_num, ts, true);
423 }
424
bt_bap_stream_get_tx_sync(struct bt_bap_stream * stream,struct bt_iso_tx_info * info)425 int bt_bap_stream_get_tx_sync(struct bt_bap_stream *stream, struct bt_iso_tx_info *info)
426 {
427 struct bt_iso_chan *iso_chan;
428
429 CHECKIF(stream == NULL) {
430 LOG_DBG("stream is null");
431
432 return -EINVAL;
433 }
434
435 CHECKIF(info == NULL) {
436 LOG_DBG("info is null");
437
438 return -EINVAL;
439 }
440
441 if (!bt_bap_stream_can_send(stream)) {
442 LOG_DBG("Stream is not configured for TX");
443
444 return -EINVAL;
445 }
446
447 iso_chan = bt_bap_stream_iso_chan_get(stream);
448 if (iso_chan == NULL) {
449 LOG_DBG("Could not get iso channel from stream %p", stream);
450 return -EINVAL;
451 }
452
453 return bt_iso_chan_get_tx_sync(iso_chan, info);
454 }
455 #endif /* CONFIG_BT_AUDIO_TX */
456
457 #if defined(CONFIG_BT_BAP_UNICAST)
458
459 /** Checks if the stream can terminate the CIS
460 *
461 * If the CIS is used for another stream, or if the CIS is not in the connected
462 * state it will return false.
463 */
bt_bap_stream_can_disconnect(const struct bt_bap_stream * stream)464 bool bt_bap_stream_can_disconnect(const struct bt_bap_stream *stream)
465 {
466 const struct bt_bap_ep *stream_ep;
467 enum bt_iso_state iso_state;
468
469 if (stream == NULL) {
470 return false;
471 }
472
473 stream_ep = stream->ep;
474
475 if (stream_ep == NULL || stream_ep->iso == NULL) {
476 return false;
477 }
478
479 iso_state = stream_ep->iso->chan.state;
480
481 if (iso_state == BT_ISO_STATE_CONNECTED || iso_state == BT_ISO_STATE_CONNECTING) {
482 const struct bt_bap_ep *pair_ep;
483
484 pair_ep = bt_bap_iso_get_paired_ep(stream_ep);
485
486 /* If there are no paired endpoint, or the paired endpoint is in the QoS Configured
487 * or Codec Configured state, we can disconnect the CIS
488 */
489 if (pair_ep == NULL || pair_ep->status.state == BT_BAP_EP_STATE_QOS_CONFIGURED ||
490 pair_ep->status.state == BT_BAP_EP_STATE_CODEC_CONFIGURED) {
491 return true;
492 }
493 }
494
495 return false;
496 }
497
bt_bap_stream_is_broadcast(const struct bt_bap_stream * stream)498 static bool bt_bap_stream_is_broadcast(const struct bt_bap_stream *stream)
499 {
500 return (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) &&
501 bt_bap_ep_is_broadcast_src(stream->ep)) ||
502 (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK) && bt_bap_ep_is_broadcast_snk(stream->ep));
503 }
504
bt_bap_stream_verify_qos(const struct bt_bap_stream * stream,const struct bt_bap_qos_cfg * qos)505 enum bt_bap_ascs_reason bt_bap_stream_verify_qos(const struct bt_bap_stream *stream,
506 const struct bt_bap_qos_cfg *qos)
507 {
508 const struct bt_bap_qos_cfg_pref *qos_pref = &stream->ep->qos_pref;
509
510 if (qos_pref->latency < qos->latency) {
511 /* Latency is a preferred value. Print debug info but do not fail. */
512 LOG_DBG("Latency %u higher than preferred max %u", qos->latency, qos_pref->latency);
513 }
514
515 if (!IN_RANGE(qos->pd, qos_pref->pd_min, qos_pref->pd_max)) {
516 LOG_DBG("Presentation Delay not within range: min %u max %u pd %u",
517 qos_pref->pd_min, qos_pref->pd_max, qos->pd);
518 return BT_BAP_ASCS_REASON_PD;
519 }
520
521 return BT_BAP_ASCS_REASON_NONE;
522 }
523
bt_bap_stream_detach(struct bt_bap_stream * stream)524 void bt_bap_stream_detach(struct bt_bap_stream *stream)
525 {
526 const bool is_broadcast = bt_bap_stream_is_broadcast(stream);
527
528 LOG_DBG("stream %p conn %p ep %p", stream, (void *)stream->conn, (void *)stream->ep);
529
530 if (stream->conn != NULL) {
531 bt_conn_unref(stream->conn);
532 stream->conn = NULL;
533 }
534 stream->codec_cfg = NULL;
535 stream->ep->stream = NULL;
536 stream->ep = NULL;
537
538 if (!is_broadcast) {
539 const int err = bt_bap_stream_disconnect(stream);
540
541 if (err != 0) {
542 LOG_DBG("Failed to disconnect stream %p: %d", stream, err);
543 }
544 }
545 }
546
bt_bap_stream_disconnect(struct bt_bap_stream * stream)547 int bt_bap_stream_disconnect(struct bt_bap_stream *stream)
548 {
549 struct bt_iso_chan *iso_chan;
550
551 LOG_DBG("stream %p", stream);
552
553 if (stream == NULL) {
554 return -EINVAL;
555 }
556
557 iso_chan = bt_bap_stream_iso_chan_get(stream);
558 if (iso_chan == NULL || iso_chan->iso == NULL) {
559 LOG_DBG("Not connected");
560
561 return -ENOTCONN;
562 }
563
564 return bt_iso_chan_disconnect(iso_chan);
565 }
566
bt_bap_stream_reset(struct bt_bap_stream * stream)567 void bt_bap_stream_reset(struct bt_bap_stream *stream)
568 {
569 LOG_DBG("stream %p", stream);
570
571 if (stream == NULL) {
572 return;
573 }
574
575 if (stream->ep != NULL && stream->ep->iso != NULL) {
576 bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
577 }
578
579 bt_bap_stream_detach(stream);
580 }
581
conn_get_role(const struct bt_conn * conn)582 static uint8_t conn_get_role(const struct bt_conn *conn)
583 {
584 struct bt_conn_info info;
585 int err;
586
587 err = bt_conn_get_info(conn, &info);
588 __ASSERT(err == 0, "Failed to get conn info");
589
590 return info.role;
591 }
592
593 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
594
bt_bap_stream_config(struct bt_conn * conn,struct bt_bap_stream * stream,struct bt_bap_ep * ep,struct bt_audio_codec_cfg * codec_cfg)595 int bt_bap_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep,
596 struct bt_audio_codec_cfg *codec_cfg)
597 {
598 uint8_t role;
599 int err;
600
601 LOG_DBG("conn %p stream %p, ep %p codec_cfg %p codec id 0x%02x "
602 "codec cid 0x%04x codec vid 0x%04x", (void *)conn, stream, ep,
603 codec_cfg, codec_cfg ? codec_cfg->id : 0, codec_cfg ? codec_cfg->cid : 0,
604 codec_cfg ? codec_cfg->vid : 0);
605
606 CHECKIF(conn == NULL || stream == NULL || codec_cfg == NULL || ep == NULL) {
607 LOG_DBG("NULL value(s) supplied)");
608 return -EINVAL;
609 }
610
611 if (stream->conn != NULL) {
612 LOG_DBG("Stream already configured for conn %p", (void *)stream->conn);
613 return -EALREADY;
614 }
615
616 role = conn_get_role(conn);
617 if (role != BT_HCI_ROLE_CENTRAL) {
618 LOG_DBG("Invalid conn role: %u, shall be central", role);
619 return -EINVAL;
620 }
621
622 switch (ep->status.state) {
623 /* Valid only if ASE_State field = 0x00 (Idle) */
624 case BT_BAP_EP_STATE_IDLE:
625 /* or 0x01 (Codec Configured) */
626 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
627 /* or 0x02 (QoS Configured) */
628 case BT_BAP_EP_STATE_QOS_CONFIGURED:
629 break;
630 default:
631 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
632 return -EBADMSG;
633 }
634
635 bt_bap_stream_attach(conn, stream, ep, codec_cfg);
636
637 err = bt_bap_unicast_client_config(stream, codec_cfg);
638 if (err != 0) {
639 LOG_DBG("Failed to configure stream: %d", err);
640 return err;
641 }
642
643 return 0;
644 }
645
bt_bap_stream_qos(struct bt_conn * conn,struct bt_bap_unicast_group * group)646 int bt_bap_stream_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group)
647 {
648 uint8_t role;
649 int err;
650
651 LOG_DBG("conn %p group %p", (void *)conn, group);
652
653 CHECKIF(conn == NULL) {
654 LOG_DBG("conn is NULL");
655 return -EINVAL;
656 }
657
658 CHECKIF(group == NULL) {
659 LOG_DBG("group is NULL");
660 return -EINVAL;
661 }
662
663 if (sys_slist_is_empty(&group->streams)) {
664 LOG_DBG("group stream list is empty");
665 return -ENOEXEC;
666 }
667
668 role = conn_get_role(conn);
669 if (role != BT_HCI_ROLE_CENTRAL) {
670 LOG_DBG("Invalid conn role: %u, shall be central", role);
671 return -EINVAL;
672 }
673
674 err = bt_bap_unicast_client_qos(conn, group);
675 if (err != 0) {
676 LOG_DBG("Failed to configure stream: %d", err);
677 return err;
678 }
679
680 return 0;
681 }
682
bt_bap_stream_enable(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len)683 int bt_bap_stream_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len)
684 {
685 uint8_t role;
686 int err;
687
688 LOG_DBG("stream %p", stream);
689
690 if (stream == NULL || stream->ep == NULL || stream->conn == NULL) {
691 LOG_DBG("Invalid stream");
692 return -EINVAL;
693 }
694
695 role = conn_get_role(stream->conn);
696 if (role != BT_HCI_ROLE_CENTRAL) {
697 LOG_DBG("Invalid conn role: %u, shall be central", role);
698 return -EINVAL;
699 }
700
701 /* Valid for an ASE only if ASE_State field = 0x02 (QoS Configured) */
702 if (stream->ep->status.state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
703 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(stream->ep->status.state));
704 return -EBADMSG;
705 }
706
707 err = bt_bap_unicast_client_enable(stream, meta, meta_len);
708 if (err != 0) {
709 LOG_DBG("Failed to enable stream: %d", err);
710 return err;
711 }
712
713 return 0;
714 }
715
bt_bap_stream_stop(struct bt_bap_stream * stream)716 int bt_bap_stream_stop(struct bt_bap_stream *stream)
717 {
718 struct bt_bap_ep *ep;
719 uint8_t role;
720 int err;
721
722 if (stream == NULL || stream->ep == NULL || stream->conn == NULL) {
723 LOG_DBG("Invalid stream");
724 return -EINVAL;
725 }
726
727 role = conn_get_role(stream->conn);
728 if (role != BT_HCI_ROLE_CENTRAL) {
729 LOG_DBG("Invalid conn role: %u, shall be central", role);
730 return -EINVAL;
731 }
732
733 ep = stream->ep;
734
735 switch (ep->status.state) {
736 /* Valid only if ASE_State field = 0x03 (Disabling) */
737 case BT_BAP_EP_STATE_DISABLING:
738 break;
739 default:
740 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
741 return -EBADMSG;
742 }
743
744 err = bt_bap_unicast_client_stop(stream);
745 if (err != 0) {
746 LOG_DBG("Stopping stream failed: %d", err);
747 return err;
748 }
749
750 return 0;
751 }
752 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
753
bt_bap_stream_reconfig(struct bt_bap_stream * stream,struct bt_audio_codec_cfg * codec_cfg)754 int bt_bap_stream_reconfig(struct bt_bap_stream *stream,
755 struct bt_audio_codec_cfg *codec_cfg)
756 {
757 uint8_t state;
758 uint8_t role;
759 int err;
760
761 LOG_DBG("stream %p codec_cfg %p", stream, codec_cfg);
762
763 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
764 LOG_DBG("Invalid stream");
765 return -EINVAL;
766 }
767
768 CHECKIF(codec_cfg == NULL) {
769 LOG_DBG("codec_cfg is NULL");
770 return -EINVAL;
771 }
772
773 state = stream->ep->status.state;
774 switch (state) {
775 /* Valid only if ASE_State field = 0x00 (Idle) */
776 case BT_BAP_EP_STATE_IDLE:
777 /* or 0x01 (Codec Configured) */
778 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
779 /* or 0x02 (QoS Configured) */
780 case BT_BAP_EP_STATE_QOS_CONFIGURED:
781 break;
782 default:
783 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
784 return -EBADMSG;
785 }
786
787 role = conn_get_role(stream->conn);
788 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
789 err = bt_bap_unicast_client_config(stream, codec_cfg);
790 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
791 err = bt_bap_unicast_server_reconfig(stream, codec_cfg);
792 } else {
793 err = -EOPNOTSUPP;
794 }
795
796 if (err != 0) {
797 LOG_DBG("reconfiguring stream failed: %d", err);
798 } else {
799 stream->codec_cfg = codec_cfg;
800 }
801
802 return 0;
803 }
804
805 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
bt_bap_stream_connect(struct bt_bap_stream * stream)806 int bt_bap_stream_connect(struct bt_bap_stream *stream)
807 {
808 uint8_t state;
809
810 LOG_DBG("stream %p ep %p", stream, stream == NULL ? NULL : stream->ep);
811
812 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
813 LOG_DBG("Invalid stream");
814 return -EINVAL;
815 }
816
817 /* Valid only after the CIS ID has been assigned in QoS configured state and while we are
818 * not streaming
819 */
820 state = stream->ep->status.state;
821 switch (state) {
822 case BT_BAP_EP_STATE_QOS_CONFIGURED:
823 case BT_BAP_EP_STATE_ENABLING:
824 break;
825 default:
826 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
827 return -EBADMSG;
828 }
829
830 /* Only a unicast client can connect a stream */
831 if (conn_get_role(stream->conn) == BT_HCI_ROLE_CENTRAL) {
832 return bt_bap_unicast_client_connect(stream);
833 } else {
834 return -EOPNOTSUPP;
835 }
836 }
837 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
838
bt_bap_stream_start(struct bt_bap_stream * stream)839 int bt_bap_stream_start(struct bt_bap_stream *stream)
840 {
841 uint8_t state;
842 uint8_t role;
843 int err;
844
845 LOG_DBG("stream %p ep %p", stream, stream == NULL ? NULL : stream->ep);
846
847 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
848 LOG_DBG("Invalid stream");
849 return -EINVAL;
850 }
851
852 state = stream->ep->status.state;
853 switch (state) {
854 /* Valid only if ASE_State field = 0x03 (Enabling) */
855 case BT_BAP_EP_STATE_ENABLING:
856 break;
857 default:
858 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
859 return -EBADMSG;
860 }
861
862 role = conn_get_role(stream->conn);
863 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
864 err = bt_bap_unicast_client_start(stream);
865 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
866 err = bt_bap_unicast_server_start(stream);
867 } else {
868 err = -EOPNOTSUPP;
869 }
870
871 if (err != 0) {
872 LOG_DBG("Starting stream failed: %d", err);
873 return err;
874 }
875
876 return 0;
877 }
878
bt_bap_stream_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len)879 int bt_bap_stream_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len)
880 {
881 uint8_t state;
882 uint8_t role;
883 int err;
884
885 LOG_DBG("stream %p meta_len %zu", stream, meta_len);
886
887 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
888 LOG_DBG("Invalid stream");
889 return -EINVAL;
890 }
891
892 CHECKIF((meta == NULL && meta_len != 0U) || (meta != NULL && meta_len == 0U)) {
893 LOG_DBG("Invalid meta (%p) or len (%zu)", meta, meta_len);
894 return -EINVAL;
895 }
896
897 state = stream->ep->status.state;
898 switch (state) {
899 /* Valid for an ASE only if ASE_State field = 0x03 (Enabling) */
900 case BT_BAP_EP_STATE_ENABLING:
901 /* or 0x04 (Streaming) */
902 case BT_BAP_EP_STATE_STREAMING:
903 break;
904 default:
905 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
906 return -EBADMSG;
907 }
908
909 role = conn_get_role(stream->conn);
910 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
911 err = bt_bap_unicast_client_metadata(stream, meta, meta_len);
912 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
913 err = bt_bap_unicast_server_metadata(stream, meta, meta_len);
914 } else {
915 err = -EOPNOTSUPP;
916 }
917
918 if (err != 0) {
919 LOG_DBG("Updating metadata failed: %d", err);
920 return err;
921 }
922
923 return 0;
924 }
925
bt_bap_stream_disable(struct bt_bap_stream * stream)926 int bt_bap_stream_disable(struct bt_bap_stream *stream)
927 {
928 uint8_t state;
929 uint8_t role;
930 int err;
931
932 LOG_DBG("stream %p", stream);
933
934 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
935 LOG_DBG("Invalid stream");
936 return -EINVAL;
937 }
938
939 state = stream->ep->status.state;
940 switch (state) {
941 /* Valid only if ASE_State field = 0x03 (Enabling) */
942 case BT_BAP_EP_STATE_ENABLING:
943 /* or 0x04 (Streaming) */
944 case BT_BAP_EP_STATE_STREAMING:
945 break;
946 default:
947 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
948 return -EBADMSG;
949 }
950
951 role = conn_get_role(stream->conn);
952 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
953 err = bt_bap_unicast_client_disable(stream);
954 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
955 err = bt_bap_unicast_server_disable(stream);
956 } else {
957 err = -EOPNOTSUPP;
958 }
959
960 if (err != 0) {
961 LOG_DBG("Disabling stream failed: %d", err);
962 return err;
963 }
964
965 return 0;
966 }
967
bt_bap_stream_release(struct bt_bap_stream * stream)968 int bt_bap_stream_release(struct bt_bap_stream *stream)
969 {
970 uint8_t state;
971 uint8_t role;
972 int err;
973
974 LOG_DBG("stream %p", stream);
975
976 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
977 LOG_DBG("Invalid stream (ep %p, conn %p)", stream->ep, (void *)stream->conn);
978 return -EINVAL;
979 }
980
981 state = stream->ep->status.state;
982 switch (state) {
983 /* Valid only if ASE_State field = 0x01 (Codec Configured) */
984 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
985 /* or 0x02 (QoS Configured) */
986 case BT_BAP_EP_STATE_QOS_CONFIGURED:
987 /* or 0x03 (Enabling) */
988 case BT_BAP_EP_STATE_ENABLING:
989 /* or 0x04 (Streaming) */
990 case BT_BAP_EP_STATE_STREAMING:
991 /* or 0x04 (Disabling) */
992 case BT_BAP_EP_STATE_DISABLING:
993 break;
994 default:
995 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
996 return -EBADMSG;
997 }
998
999 role = conn_get_role(stream->conn);
1000 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
1001 err = bt_bap_unicast_client_release(stream);
1002 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
1003 err = bt_bap_unicast_server_release(stream);
1004 } else {
1005 err = -EOPNOTSUPP;
1006 }
1007
1008 if (err != 0) {
1009 LOG_DBG("Releasing stream failed: %d", err);
1010 return err;
1011 }
1012
1013 return 0;
1014 }
1015 #endif /* CONFIG_BT_BAP_UNICAST */
1016