1 /* Bluetooth Audio Stream */
2
3 /*
4 * Copyright (c) 2020 Intel Corporation
5 * Copyright (c) 2021-2023 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/sys/check.h>
13
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/conn.h>
16 #include <zephyr/bluetooth/gatt.h>
17 #include <zephyr/bluetooth/hci.h>
18 #include <zephyr/bluetooth/iso.h>
19 #include <zephyr/bluetooth/audio/audio.h>
20 #include <zephyr/bluetooth/audio/bap.h>
21
22 #include "../host/iso_internal.h"
23
24 #include "bap_iso.h"
25 #include "audio_internal.h"
26 #include "bap_endpoint.h"
27 #include "bap_unicast_client_internal.h"
28 #include "bap_unicast_server.h"
29
30 #include <zephyr/logging/log.h>
31
32 LOG_MODULE_REGISTER(bt_bap_stream, CONFIG_BT_BAP_STREAM_LOG_LEVEL);
33
pack_bt_codec_cc(const struct bt_codec * codec,uint8_t cc[])34 static uint8_t pack_bt_codec_cc(const struct bt_codec *codec, uint8_t cc[])
35 {
36 uint8_t len;
37
38 len = 0U;
39 for (size_t i = 0U; i < codec->data_count; i++) {
40 const struct bt_data *data = &codec->data[i].data;
41
42 /* We assume that data_len and data has previously been verified
43 * and that based on the Kconfigs we can assume that the length
44 * will always fit in `cc`
45 */
46 cc[len++] = data->data_len + 1;
47 cc[len++] = data->type;
48 (void)memcpy(cc + len, data->data, data->data_len);
49 len += data->data_len;
50 }
51
52 return len;
53 }
54
bt_audio_codec_to_iso_path(struct bt_iso_chan_path * path,const struct bt_codec * codec)55 void bt_audio_codec_to_iso_path(struct bt_iso_chan_path *path,
56 const struct bt_codec *codec)
57 {
58 path->pid = codec->path_id;
59 path->format = codec->id;
60 path->cid = codec->cid;
61 path->vid = codec->vid;
62 path->delay = 0; /* TODO: Add to bt_codec? Use presentation delay? */
63 path->cc_len = pack_bt_codec_cc(codec, path->cc);
64 }
65
66 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || \
67 defined(CONFIG_BT_BAP_BROADCAST_SINK)
bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos * io,const struct bt_codec_qos * codec_qos)68 void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io,
69 const struct bt_codec_qos *codec_qos)
70 {
71 io->sdu = codec_qos->sdu;
72 io->phy = codec_qos->phy;
73 io->rtn = codec_qos->rtn;
74 }
75 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT || \
76 * CONFIG_BT_BAP_BROADCAST_SOURCE || \
77 * CONFIG_BT_BAP_BROADCAST_SINK \
78 */
79
bt_bap_stream_init(struct bt_bap_stream * stream)80 void bt_bap_stream_init(struct bt_bap_stream *stream)
81 {
82 struct bt_bap_stream_ops *ops;
83 void *user_data;
84
85 /* Save the stream->ops and stream->user_data owned by API user */
86 ops = stream->ops;
87 user_data = stream->user_data;
88
89 memset(stream, 0, sizeof(*stream));
90
91 /* Restore */
92 stream->ops = ops;
93 stream->user_data = user_data;
94 }
95
bt_bap_stream_attach(struct bt_conn * conn,struct bt_bap_stream * stream,struct bt_bap_ep * ep,struct bt_codec * codec)96 void bt_bap_stream_attach(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep,
97 struct bt_codec *codec)
98 {
99 LOG_DBG("conn %p stream %p ep %p codec %p", (void *)conn, stream, ep, codec);
100
101 if (conn != NULL) {
102 __ASSERT(stream->conn == NULL || stream->conn == conn,
103 "stream->conn %p already attached", (void *)stream->conn);
104 if (stream->conn == NULL) {
105 stream->conn = bt_conn_ref(conn);
106 }
107 }
108 stream->codec = codec;
109 stream->ep = ep;
110 ep->stream = stream;
111 }
112
bt_bap_stream_iso_chan_get(struct bt_bap_stream * stream)113 struct bt_iso_chan *bt_bap_stream_iso_chan_get(struct bt_bap_stream *stream)
114 {
115 if (stream != NULL && stream->ep != NULL && stream->ep->iso != NULL) {
116 return &stream->ep->iso->chan;
117 }
118
119 return NULL;
120 }
121
bt_bap_stream_cb_register(struct bt_bap_stream * stream,struct bt_bap_stream_ops * ops)122 void bt_bap_stream_cb_register(struct bt_bap_stream *stream,
123 struct bt_bap_stream_ops *ops)
124 {
125 stream->ops = ops;
126 }
127
bt_bap_ep_get_info(const struct bt_bap_ep * ep,struct bt_bap_ep_info * info)128 int bt_bap_ep_get_info(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info)
129 {
130 info->id = ep->status.id;
131 info->state = ep->status.state;
132 info->dir = ep->dir;
133
134 if (ep->iso == NULL) {
135 info->paired_ep = NULL;
136 } else {
137 info->paired_ep = bt_bap_iso_get_paired_ep(ep);
138 }
139
140 return 0;
141 }
142
bt_audio_verify_qos(const struct bt_codec_qos * qos)143 enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos)
144 {
145 if (qos->interval < BT_ISO_SDU_INTERVAL_MIN ||
146 qos->interval > BT_ISO_SDU_INTERVAL_MAX) {
147 LOG_DBG("Interval not within allowed range: %u (%u-%u)", qos->interval,
148 BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX);
149 return BT_BAP_ASCS_REASON_INTERVAL;
150 }
151
152 if (qos->framing > BT_CODEC_QOS_FRAMED) {
153 LOG_DBG("Invalid Framing 0x%02x", qos->framing);
154 return BT_BAP_ASCS_REASON_FRAMING;
155 }
156
157 if (qos->phy != BT_CODEC_QOS_1M &&
158 qos->phy != BT_CODEC_QOS_2M &&
159 qos->phy != BT_CODEC_QOS_CODED) {
160 LOG_DBG("Invalid PHY 0x%02x", qos->phy);
161 return BT_BAP_ASCS_REASON_PHY;
162 }
163
164 if (qos->sdu > BT_ISO_MAX_SDU) {
165 LOG_DBG("Invalid SDU %u", qos->sdu);
166 return BT_BAP_ASCS_REASON_SDU;
167 }
168
169 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_UNICAST)
170 if (qos->latency < BT_ISO_LATENCY_MIN ||
171 qos->latency > BT_ISO_LATENCY_MAX) {
172 LOG_DBG("Invalid Latency %u", qos->latency);
173 return BT_BAP_ASCS_REASON_LATENCY;
174 }
175 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE || CONFIG_BT_BAP_UNICAST */
176
177 if (qos->pd > BT_AUDIO_PD_MAX) {
178 LOG_DBG("Invalid presentation delay %u", qos->pd);
179 return BT_BAP_ASCS_REASON_PD;
180 }
181
182 return BT_BAP_ASCS_REASON_NONE;
183 }
184
bt_audio_valid_codec_data(const struct bt_codec_data * data)185 bool bt_audio_valid_codec_data(const struct bt_codec_data *data)
186 {
187 if (data->data.data_len > ARRAY_SIZE(data->value)) {
188 LOG_DBG("data invalid length: %zu/%zu", data->data.data_len,
189 ARRAY_SIZE(data->value));
190 return false;
191 }
192
193 return true;
194 }
195
bt_audio_valid_codec(const struct bt_codec * codec)196 bool bt_audio_valid_codec(const struct bt_codec *codec)
197 {
198 if (codec == NULL) {
199 LOG_DBG("codec is NULL");
200 return false;
201 }
202
203 #if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0
204 if (codec->data_count > CONFIG_BT_CODEC_MAX_DATA_COUNT) {
205 LOG_DBG("codec->data_count (%zu) is invalid", codec->data_count);
206 return false;
207 }
208
209 for (size_t i = 0U; i < codec->data_count; i++) {
210 if (!bt_audio_valid_codec_data(&codec->data[i])) {
211 LOG_DBG("codec->data[%zu] invalid", i);
212 return false;
213 }
214 }
215 #endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */
216
217 #if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0
218 if (codec->meta_count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) {
219 LOG_DBG("codec->meta_count (%zu) is invalid", codec->meta_count);
220 return false;
221 }
222
223 for (size_t i = 0U; i < codec->meta_count; i++) {
224 if (!bt_audio_valid_codec_data(&codec->meta[i])) {
225 LOG_DBG("codec->meta[%zu] invalid", i);
226 return false;
227 }
228 }
229 #endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */
230
231 return true;
232 }
233
234 #if defined(CONFIG_BT_AUDIO_TX)
bt_bap_stream_send(struct bt_bap_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts)235 int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf,
236 uint16_t seq_num, uint32_t ts)
237 {
238 struct bt_bap_ep *ep;
239
240 if (stream == NULL || stream->ep == NULL) {
241 return -EINVAL;
242 }
243
244 ep = stream->ep;
245
246 if (ep->status.state != BT_BAP_EP_STATE_STREAMING) {
247 LOG_DBG("Channel %p not ready for streaming (state: %s)", stream,
248 bt_bap_ep_state_str(ep->status.state));
249 return -EBADMSG;
250 }
251
252 /* TODO: Add checks for broadcast sink */
253
254 return bt_iso_chan_send(bt_bap_stream_iso_chan_get(stream),
255 buf, seq_num, ts);
256 }
257 #endif /* CONFIG_BT_AUDIO_TX */
258
259 #if defined(CONFIG_BT_BAP_UNICAST)
260
261 /** Checks if the stream can terminate the CIS
262 *
263 * If the CIS is used for another stream, or if the CIS is not in the connected
264 * state it will return false.
265 */
bt_bap_stream_can_disconnect(const struct bt_bap_stream * stream)266 bool bt_bap_stream_can_disconnect(const struct bt_bap_stream *stream)
267 {
268 const struct bt_bap_ep *stream_ep;
269 enum bt_iso_state iso_state;
270
271 if (stream == NULL) {
272 return false;
273 }
274
275 stream_ep = stream->ep;
276
277 if (stream_ep == NULL || stream_ep->iso == NULL) {
278 return false;
279 }
280
281 iso_state = stream_ep->iso->chan.state;
282
283 if (iso_state == BT_ISO_STATE_CONNECTED || iso_state == BT_ISO_STATE_CONNECTING) {
284 const struct bt_bap_ep *pair_ep;
285
286 pair_ep = bt_bap_iso_get_paired_ep(stream_ep);
287
288 /* If there are no paired endpoint, or the paired endpoint is
289 * not in the streaming state, we can disconnect the CIS
290 */
291 if (pair_ep == NULL || pair_ep->status.state != BT_BAP_EP_STATE_STREAMING) {
292 return true;
293 }
294 }
295
296 return false;
297 }
298
bt_bap_stream_is_broadcast(const struct bt_bap_stream * stream)299 static bool bt_bap_stream_is_broadcast(const struct bt_bap_stream *stream)
300 {
301 return (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) &&
302 bt_bap_ep_is_broadcast_src(stream->ep)) ||
303 (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK) && bt_bap_ep_is_broadcast_snk(stream->ep));
304 }
305
bt_bap_stream_verify_qos(const struct bt_bap_stream * stream,const struct bt_codec_qos * qos)306 enum bt_bap_ascs_reason bt_bap_stream_verify_qos(const struct bt_bap_stream *stream,
307 const struct bt_codec_qos *qos)
308 {
309 const struct bt_codec_qos_pref *qos_pref = &stream->ep->qos_pref;
310
311 if (qos_pref->latency < qos->latency) {
312 /* Latency is a preferred value. Print debug info but do not fail. */
313 LOG_DBG("Latency %u higher than preferred max %u", qos->latency, qos_pref->latency);
314 }
315
316 if (!IN_RANGE(qos->pd, qos_pref->pd_min, qos_pref->pd_max)) {
317 LOG_DBG("Presentation Delay not within range: min %u max %u pd %u",
318 qos_pref->pd_min, qos_pref->pd_max, qos->pd);
319 return BT_BAP_ASCS_REASON_PD;
320 }
321
322 return BT_BAP_ASCS_REASON_NONE;
323 }
324
bt_bap_stream_detach(struct bt_bap_stream * stream)325 void bt_bap_stream_detach(struct bt_bap_stream *stream)
326 {
327 const bool is_broadcast = bt_bap_stream_is_broadcast(stream);
328
329 LOG_DBG("stream %p", stream);
330
331 if (stream->conn != NULL) {
332 bt_conn_unref(stream->conn);
333 stream->conn = NULL;
334 }
335 stream->codec = NULL;
336 stream->ep->stream = NULL;
337 stream->ep = NULL;
338
339 if (!is_broadcast) {
340 bt_bap_stream_disconnect(stream);
341 }
342 }
343
bt_bap_stream_disconnect(struct bt_bap_stream * stream)344 int bt_bap_stream_disconnect(struct bt_bap_stream *stream)
345 {
346 struct bt_iso_chan *iso_chan = bt_bap_stream_iso_chan_get(stream);
347
348 LOG_DBG("stream %p iso %p", stream, iso_chan);
349
350 if (stream == NULL) {
351 return -EINVAL;
352 }
353
354 if (iso_chan == NULL || iso_chan->iso == NULL) {
355 return -ENOTCONN;
356 }
357
358 return bt_iso_chan_disconnect(iso_chan);
359 }
360
bt_bap_stream_reset(struct bt_bap_stream * stream)361 void bt_bap_stream_reset(struct bt_bap_stream *stream)
362 {
363 LOG_DBG("stream %p", stream);
364
365 if (stream == NULL) {
366 return;
367 }
368
369 if (stream->ep != NULL && stream->ep->iso != NULL) {
370 bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
371 }
372
373 bt_bap_stream_detach(stream);
374 }
375
conn_get_role(const struct bt_conn * conn)376 static uint8_t conn_get_role(const struct bt_conn *conn)
377 {
378 struct bt_conn_info info;
379 int err;
380
381 err = bt_conn_get_info(conn, &info);
382 __ASSERT(err == 0, "Failed to get conn info");
383
384 return info.role;
385 }
386
387 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
388
bt_bap_stream_config(struct bt_conn * conn,struct bt_bap_stream * stream,struct bt_bap_ep * ep,struct bt_codec * codec)389 int bt_bap_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep,
390 struct bt_codec *codec)
391 {
392 uint8_t role;
393 int err;
394
395 LOG_DBG("conn %p stream %p, ep %p codec %p codec id 0x%02x "
396 "codec cid 0x%04x codec vid 0x%04x", (void *)conn, stream, ep,
397 codec, codec ? codec->id : 0, codec ? codec->cid : 0,
398 codec ? codec->vid : 0);
399
400 CHECKIF(conn == NULL || stream == NULL || codec == NULL) {
401 LOG_DBG("NULL value(s) supplied)");
402 return -EINVAL;
403 }
404
405 if (stream->conn != NULL) {
406 LOG_DBG("Stream already configured for conn %p", (void *)stream->conn);
407 return -EALREADY;
408 }
409
410 role = conn_get_role(conn);
411 if (role != BT_HCI_ROLE_CENTRAL) {
412 LOG_DBG("Invalid conn role: %u, shall be central", role);
413 return -EINVAL;
414 }
415
416 switch (ep->status.state) {
417 /* Valid only if ASE_State field = 0x00 (Idle) */
418 case BT_BAP_EP_STATE_IDLE:
419 /* or 0x01 (Codec Configured) */
420 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
421 /* or 0x02 (QoS Configured) */
422 case BT_BAP_EP_STATE_QOS_CONFIGURED:
423 break;
424 default:
425 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
426 return -EBADMSG;
427 }
428
429 bt_bap_stream_attach(conn, stream, ep, codec);
430
431 err = bt_bap_unicast_client_config(stream, codec);
432 if (err != 0) {
433 LOG_DBG("Failed to configure stream: %d", err);
434 return err;
435 }
436
437 return 0;
438 }
439
bt_bap_stream_qos(struct bt_conn * conn,struct bt_bap_unicast_group * group)440 int bt_bap_stream_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group)
441 {
442 uint8_t role;
443 int err;
444
445 LOG_DBG("conn %p group %p", (void *)conn, group);
446
447 CHECKIF(conn == NULL) {
448 LOG_DBG("conn is NULL");
449 return -EINVAL;
450 }
451
452 CHECKIF(group == NULL) {
453 LOG_DBG("group is NULL");
454 return -EINVAL;
455 }
456
457 if (sys_slist_is_empty(&group->streams)) {
458 LOG_DBG("group stream list is empty");
459 return -ENOEXEC;
460 }
461
462 role = conn_get_role(conn);
463 if (role != BT_HCI_ROLE_CENTRAL) {
464 LOG_DBG("Invalid conn role: %u, shall be central", role);
465 return -EINVAL;
466 }
467
468 err = bt_bap_unicast_client_qos(conn, group);
469 if (err != 0) {
470 LOG_DBG("Failed to configure stream: %d", err);
471 return err;
472 }
473
474 return 0;
475 }
476
bt_bap_stream_enable(struct bt_bap_stream * stream,struct bt_codec_data * meta,size_t meta_count)477 int bt_bap_stream_enable(struct bt_bap_stream *stream,
478 struct bt_codec_data *meta,
479 size_t meta_count)
480 {
481 uint8_t role;
482 int err;
483
484 LOG_DBG("stream %p", stream);
485
486 if (stream == NULL || stream->ep == NULL || stream->conn == NULL) {
487 LOG_DBG("Invalid stream");
488 return -EINVAL;
489 }
490
491 role = conn_get_role(stream->conn);
492 if (role != BT_HCI_ROLE_CENTRAL) {
493 LOG_DBG("Invalid conn role: %u, shall be central", role);
494 return -EINVAL;
495 }
496
497 /* Valid for an ASE only if ASE_State field = 0x02 (QoS Configured) */
498 if (stream->ep->status.state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
499 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(stream->ep->status.state));
500 return -EBADMSG;
501 }
502
503 err = bt_bap_unicast_client_enable(stream, meta, meta_count);
504 if (err != 0) {
505 LOG_DBG("Failed to enable stream: %d", err);
506 return err;
507 }
508
509 return 0;
510 }
511
bt_bap_stream_stop(struct bt_bap_stream * stream)512 int bt_bap_stream_stop(struct bt_bap_stream *stream)
513 {
514 struct bt_bap_ep *ep;
515 uint8_t role;
516 int err;
517
518 if (stream == NULL || stream->ep == NULL || stream->conn == NULL) {
519 LOG_DBG("Invalid stream");
520 return -EINVAL;
521 }
522
523 role = conn_get_role(stream->conn);
524 if (role != BT_HCI_ROLE_CENTRAL) {
525 LOG_DBG("Invalid conn role: %u, shall be central", role);
526 return -EINVAL;
527 }
528
529 ep = stream->ep;
530
531 switch (ep->status.state) {
532 /* Valid only if ASE_State field = 0x03 (Disabling) */
533 case BT_BAP_EP_STATE_DISABLING:
534 break;
535 default:
536 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
537 return -EBADMSG;
538 }
539
540 err = bt_bap_unicast_client_stop(stream);
541 if (err != 0) {
542 LOG_DBG("Stopping stream failed: %d", err);
543 return err;
544 }
545
546 return 0;
547 }
548 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
549
bt_bap_stream_reconfig(struct bt_bap_stream * stream,struct bt_codec * codec)550 int bt_bap_stream_reconfig(struct bt_bap_stream *stream,
551 struct bt_codec *codec)
552 {
553 uint8_t state;
554 uint8_t role;
555 int err;
556
557 LOG_DBG("stream %p codec %p", stream, codec);
558
559 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
560 LOG_DBG("Invalid stream");
561 return -EINVAL;
562 }
563
564 CHECKIF(codec == NULL) {
565 LOG_DBG("codec is NULL");
566 return -EINVAL;
567 }
568
569 state = stream->ep->status.state;
570 switch (state) {
571 /* Valid only if ASE_State field = 0x00 (Idle) */
572 case BT_BAP_EP_STATE_IDLE:
573 /* or 0x01 (Codec Configured) */
574 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
575 /* or 0x02 (QoS Configured) */
576 case BT_BAP_EP_STATE_QOS_CONFIGURED:
577 break;
578 default:
579 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
580 return -EBADMSG;
581 }
582
583 role = conn_get_role(stream->conn);
584 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
585 err = bt_bap_unicast_client_config(stream, codec);
586 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
587 err = bt_bap_unicast_server_reconfig(stream, codec);
588 } else {
589 err = -EOPNOTSUPP;
590 }
591
592 if (err != 0) {
593 LOG_DBG("reconfiguring stream failed: %d", err);
594 } else {
595 stream->codec = codec;
596 }
597
598 return 0;
599 }
600
bt_bap_stream_start(struct bt_bap_stream * stream)601 int bt_bap_stream_start(struct bt_bap_stream *stream)
602 {
603 uint8_t state;
604 uint8_t role;
605 int err;
606
607 LOG_DBG("stream %p ep %p", stream, stream == NULL ? NULL : stream->ep);
608
609 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
610 LOG_DBG("Invalid stream");
611 return -EINVAL;
612 }
613
614 state = stream->ep->status.state;
615 switch (state) {
616 /* Valid only if ASE_State field = 0x03 (Enabling) */
617 case BT_BAP_EP_STATE_ENABLING:
618 break;
619 default:
620 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
621 return -EBADMSG;
622 }
623
624 role = conn_get_role(stream->conn);
625 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
626 err = bt_bap_unicast_client_start(stream);
627 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
628 err = bt_bap_unicast_server_start(stream);
629 } else {
630 err = -EOPNOTSUPP;
631 }
632
633 if (err != 0) {
634 LOG_DBG("Starting stream failed: %d", err);
635 return err;
636 }
637
638 return 0;
639 }
640
bt_bap_stream_metadata(struct bt_bap_stream * stream,struct bt_codec_data * meta,size_t meta_count)641 int bt_bap_stream_metadata(struct bt_bap_stream *stream,
642 struct bt_codec_data *meta,
643 size_t meta_count)
644 {
645 uint8_t state;
646 uint8_t role;
647 int err;
648
649 LOG_DBG("stream %p metadata count %u", stream, meta_count);
650
651 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
652 LOG_DBG("Invalid stream");
653 return -EINVAL;
654 }
655
656 CHECKIF((meta == NULL && meta_count != 0U) ||
657 (meta != NULL && meta_count == 0U)) {
658 LOG_DBG("Invalid meta (%p) or count (%zu)", meta, meta_count);
659 return -EINVAL;
660 }
661
662 state = stream->ep->status.state;
663 switch (state) {
664 /* Valid for an ASE only if ASE_State field = 0x03 (Enabling) */
665 case BT_BAP_EP_STATE_ENABLING:
666 /* or 0x04 (Streaming) */
667 case BT_BAP_EP_STATE_STREAMING:
668 break;
669 default:
670 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
671 return -EBADMSG;
672 }
673
674 role = conn_get_role(stream->conn);
675 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
676 err = bt_bap_unicast_client_metadata(stream, meta, meta_count);
677 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
678 err = bt_bap_unicast_server_metadata(stream, meta, meta_count);
679 } else {
680 err = -EOPNOTSUPP;
681 }
682
683 if (err != 0) {
684 LOG_DBG("Updating metadata failed: %d", err);
685 return err;
686 }
687
688 return 0;
689 }
690
bt_bap_stream_disable(struct bt_bap_stream * stream)691 int bt_bap_stream_disable(struct bt_bap_stream *stream)
692 {
693 uint8_t state;
694 uint8_t role;
695 int err;
696
697 LOG_DBG("stream %p", stream);
698
699 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
700 LOG_DBG("Invalid stream");
701 return -EINVAL;
702 }
703
704 state = stream->ep->status.state;
705 switch (state) {
706 /* Valid only if ASE_State field = 0x03 (Enabling) */
707 case BT_BAP_EP_STATE_ENABLING:
708 /* or 0x04 (Streaming) */
709 case BT_BAP_EP_STATE_STREAMING:
710 break;
711 default:
712 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
713 return -EBADMSG;
714 }
715
716 role = conn_get_role(stream->conn);
717 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
718 err = bt_bap_unicast_client_disable(stream);
719 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
720 err = bt_bap_unicast_server_disable(stream);
721 } else {
722 err = -EOPNOTSUPP;
723 }
724
725 if (err != 0) {
726 LOG_DBG("Disabling stream failed: %d", err);
727 return err;
728 }
729
730 return 0;
731 }
732
bt_bap_stream_release(struct bt_bap_stream * stream)733 int bt_bap_stream_release(struct bt_bap_stream *stream)
734 {
735 uint8_t state;
736 uint8_t role;
737 int err;
738
739 LOG_DBG("stream %p", stream);
740
741 CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) {
742 LOG_DBG("Invalid stream");
743 return -EINVAL;
744 }
745
746 state = stream->ep->status.state;
747 switch (state) {
748 /* Valid only if ASE_State field = 0x01 (Codec Configured) */
749 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
750 /* or 0x02 (QoS Configured) */
751 case BT_BAP_EP_STATE_QOS_CONFIGURED:
752 /* or 0x03 (Enabling) */
753 case BT_BAP_EP_STATE_ENABLING:
754 /* or 0x04 (Streaming) */
755 case BT_BAP_EP_STATE_STREAMING:
756 /* or 0x04 (Disabling) */
757 case BT_BAP_EP_STATE_DISABLING:
758 break;
759 default:
760 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(state));
761 return -EBADMSG;
762 }
763
764 role = conn_get_role(stream->conn);
765 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) {
766 err = bt_bap_unicast_client_release(stream);
767 } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) {
768 err = bt_bap_unicast_server_release(stream);
769 } else {
770 err = -EOPNOTSUPP;
771 }
772
773 if (err != 0) {
774 LOG_DBG("Releasing stream failed: %d", err);
775 return err;
776 }
777
778 return 0;
779 }
780 #endif /* CONFIG_BT_BAP_UNICAST */
781