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