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