1 /* @file
2 * @brief Bluetooth Unicast Client
3 */
4
5 /*
6 * Copyright (c) 2020 Intel Corporation
7 * Copyright (c) 2022-2023 Nordic Semiconductor ASA
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <errno.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <string.h>
17
18 #include <zephyr/autoconf.h>
19 #include <zephyr/bluetooth/att.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/gap.h>
23 #include <zephyr/bluetooth/gatt.h>
24 #include <zephyr/bluetooth/hci.h>
25 #include <zephyr/bluetooth/audio/audio.h>
26 #include <zephyr/bluetooth/audio/bap.h>
27 #include <zephyr/bluetooth/hci_types.h>
28 #include <zephyr/bluetooth/iso.h>
29 #include <zephyr/bluetooth/uuid.h>
30 #include <zephyr/kernel.h>
31 #include <zephyr/logging/log.h>
32 #include <zephyr/net_buf.h>
33 #include <zephyr/sys/__assert.h>
34 #include <zephyr/sys/atomic.h>
35 #include <zephyr/sys/byteorder.h>
36 #include <zephyr/sys/check.h>
37 #include <zephyr/sys/slist.h>
38 #include <zephyr/sys/util.h>
39 #include <zephyr/sys/util_macro.h>
40 #include <zephyr/toolchain.h>
41
42 #include "../host/hci_core.h"
43 #include "../host/conn_internal.h"
44 #include "../host/iso_internal.h"
45
46 #include "ascs_internal.h"
47 #include "audio_internal.h"
48 #include "bap_iso.h"
49 #include "bap_endpoint.h"
50 #include "bap_unicast_client_internal.h"
51 #include "pacs_internal.h"
52
53 BUILD_ASSERT(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 ||
54 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0,
55 "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT or "
56 "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT shall be non-zero");
57
58 BUILD_ASSERT(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT == 0 ||
59 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1,
60 "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT shall be either 0 or > 1");
61
62 BUILD_ASSERT(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0 ||
63 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1,
64 "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT shall be either 0 or > 1");
65
66 LOG_MODULE_REGISTER(bt_bap_unicast_client, CONFIG_BT_BAP_UNICAST_CLIENT_LOG_LEVEL);
67
68 #define PAC_DIR_UNUSED(dir) ((dir) != BT_AUDIO_DIR_SINK && (dir) != BT_AUDIO_DIR_SOURCE)
69 #define BAP_HANDLE_UNUSED 0x0000U
70 struct bt_bap_unicast_client_ep {
71 uint16_t handle;
72 uint16_t cp_handle;
73 struct bt_gatt_subscribe_params subscribe;
74 struct bt_gatt_discover_params discover;
75 struct bt_bap_ep ep;
76 struct k_work_delayable ase_read_work;
77
78 /* Bool to help handle different order of CP and ASE notification when releasing */
79 bool release_requested;
80 bool cp_ntf_pending;
81 };
82
83 static const struct bt_uuid *snk_uuid = BT_UUID_PACS_SNK;
84 static const struct bt_uuid *src_uuid = BT_UUID_PACS_SRC;
85 static const struct bt_uuid *pacs_context_uuid = BT_UUID_PACS_SUPPORTED_CONTEXT;
86 static const struct bt_uuid *pacs_snk_loc_uuid = BT_UUID_PACS_SNK_LOC;
87 static const struct bt_uuid *pacs_src_loc_uuid = BT_UUID_PACS_SRC_LOC;
88 static const struct bt_uuid *pacs_avail_ctx_uuid = BT_UUID_PACS_AVAILABLE_CONTEXT;
89 static const struct bt_uuid *ase_snk_uuid = BT_UUID_ASCS_ASE_SNK;
90 static const struct bt_uuid *ase_src_uuid = BT_UUID_ASCS_ASE_SRC;
91 static const struct bt_uuid *cp_uuid = BT_UUID_ASCS_ASE_CP;
92
93 static struct bt_bap_unicast_group unicast_groups[UNICAST_GROUP_CNT];
94
95 enum unicast_client_flag {
96 UNICAST_CLIENT_FLAG_BUSY,
97
98 UNICAST_CLIENT_FLAG_NUM_FLAGS, /* keep as last */
99 };
100
101 static struct unicast_client {
102 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
103 struct bt_bap_unicast_client_ep snks[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
104 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
105 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
106 struct bt_bap_unicast_client_ep srcs[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT];
107 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
108
109 struct bt_gatt_subscribe_params cp_subscribe;
110 struct bt_gatt_subscribe_params snk_loc_subscribe;
111 struct bt_gatt_subscribe_params src_loc_subscribe;
112 struct bt_gatt_subscribe_params avail_ctx_subscribe;
113
114 /* TODO: We should be able to reduce the number of discover params for
115 * CCCD discovery, but requires additional work if it is to support an
116 * arbitrary number of EATT bearers, as control point and location CCCD
117 * discovery needs to be done in serial to avoid using the same discover
118 * parameters twice
119 */
120 struct bt_gatt_discover_params loc_cc_disc;
121 struct bt_gatt_discover_params avail_ctx_cc_disc;
122
123 /* Discovery parameters */
124 enum bt_audio_dir dir;
125 union {
126 struct bt_gatt_read_params read_params;
127 struct bt_gatt_discover_params disc_params;
128 struct bt_gatt_write_params write_params;
129 };
130
131 /* The att_buf needs to use the maximum ATT attribute size as a single
132 * PAC record may use the full size
133 */
134 uint8_t att_buf[BT_ATT_MAX_ATTRIBUTE_LEN];
135 struct net_buf_simple net_buf;
136
137 ATOMIC_DEFINE(flags, UNICAST_CLIENT_FLAG_NUM_FLAGS);
138 } uni_cli_insts[CONFIG_BT_MAX_CONN];
139
140 static sys_slist_t unicast_client_cbs = SYS_SLIST_STATIC_INIT(&unicast_client_cbs);
141
142 /* TODO: Move the functions to avoid these prototypes */
143 static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint8_t len,
144 struct bt_audio_codec_cfg *codec_cfg);
145
146 static int unicast_client_ep_set_codec_cfg(struct bt_bap_ep *ep, uint8_t id, uint16_t cid,
147 uint16_t vid, void *data, uint8_t len,
148 struct bt_audio_codec_cfg *codec_cfg);
149 static int unicast_client_ep_start(struct bt_bap_ep *ep,
150 struct net_buf_simple *buf);
151
152 static int unicast_client_ase_discover(struct bt_conn *conn, uint16_t start_handle);
153
154 static void unicast_client_reset(struct bt_bap_ep *ep, uint8_t reason);
155
156 static void delayed_ase_read_handler(struct k_work *work);
157 static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_simple *buf);
158
unicast_client_send_start(struct bt_bap_ep * ep)159 static int unicast_client_send_start(struct bt_bap_ep *ep)
160 {
161 if (ep->receiver_ready != true || ep->dir != BT_AUDIO_DIR_SOURCE) {
162 LOG_DBG("Invalid ep %p %u %s",
163 ep, ep->receiver_ready, bt_audio_dir_str(ep->dir));
164
165 return -EINVAL;
166 }
167
168 struct bt_ascs_start_op *req;
169 struct net_buf_simple *buf;
170 int err;
171
172 buf = bt_bap_unicast_client_ep_create_pdu(ep->stream->conn, BT_ASCS_START_OP);
173 if (buf == NULL) {
174 LOG_DBG("Could not create PDU");
175 return -EBUSY;
176 }
177
178 req = net_buf_simple_add(buf, sizeof(*req));
179 req->num_ases = 1U;
180
181 err = unicast_client_ep_start(ep, buf);
182 if (err != 0) {
183 LOG_DBG("unicast_client_ep_start failed: %d",
184 err);
185
186 return err;
187 }
188
189 err = bt_bap_unicast_client_ep_send(ep->stream->conn, ep, buf);
190 if (err != 0) {
191 LOG_DBG("bt_bap_unicast_client_ep_send failed: %d", err);
192
193 return err;
194 }
195
196 return 0;
197 }
198
199 static void unicast_client_ep_idle_state(struct bt_bap_ep *ep);
200
audio_stream_by_ep_id(const struct bt_conn * conn,uint8_t id)201 static struct bt_bap_stream *audio_stream_by_ep_id(const struct bt_conn *conn,
202 uint8_t id)
203 {
204 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 || CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
205 const uint8_t conn_index = bt_conn_index(conn);
206 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 || \
207 * CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 \
208 */
209
210 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
211 for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts[conn_index].snks); i++) {
212 const struct bt_bap_unicast_client_ep *client_ep =
213 &uni_cli_insts[conn_index].snks[i];
214
215 if (client_ep->ep.status.id == id) {
216 return client_ep->ep.stream;
217 }
218 }
219 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
220
221 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
222 for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts[conn_index].srcs); i++) {
223 const struct bt_bap_unicast_client_ep *client_ep =
224 &uni_cli_insts[conn_index].srcs[i];
225
226 if (client_ep->ep.status.id == id) {
227 return client_ep->ep.stream;
228 }
229 }
230 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
231
232 return NULL;
233 }
234
reset_att_buf(struct unicast_client * client)235 static void reset_att_buf(struct unicast_client *client)
236 {
237 net_buf_simple_init_with_data(&client->net_buf, &client->att_buf, sizeof(client->att_buf));
238 net_buf_simple_reset(&client->net_buf);
239 }
240
241 #if defined(CONFIG_BT_AUDIO_RX)
unicast_client_ep_iso_recv(struct bt_iso_chan * chan,const struct bt_iso_recv_info * info,struct net_buf * buf)242 static void unicast_client_ep_iso_recv(struct bt_iso_chan *chan,
243 const struct bt_iso_recv_info *info, struct net_buf *buf)
244 {
245 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
246 const struct bt_bap_stream_ops *ops;
247 struct bt_bap_stream *stream;
248 struct bt_bap_ep *ep = iso->rx.ep;
249
250 if (ep == NULL) {
251 /* In the case that the CIS has been setup as bidirectional, and
252 * only one of the directions have an ASE configured yet,
253 * we should only care about valid ISO packets when doing this
254 * check. The reason is that some controllers send HCI ISO data
255 * packets to the host, even if no SDU was sent on the remote
256 * side. This basically means that empty PDUs are sent to the
257 * host as HCI ISO data packets, which we should just ignore
258 */
259 if ((info->flags & BT_ISO_FLAGS_VALID) != 0) {
260 LOG_DBG("Valid ISO packet of len %zu received for iso %p not bound with ep",
261 net_buf_frags_len(buf), chan);
262 }
263
264 return;
265 }
266
267 if (ep->status.state != BT_BAP_EP_STATE_STREAMING) {
268 if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) {
269 LOG_DBG("ep %p is not in the streaming state: %s", ep,
270 bt_bap_ep_state_str(ep->status.state));
271 }
272
273 return;
274 }
275
276 stream = ep->stream;
277 if (stream == NULL) {
278 LOG_ERR("No stream for ep %p", ep);
279 return;
280 }
281
282 ops = stream->ops;
283
284 if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) {
285 LOG_DBG("stream %p ep %p len %zu", stream, ep, net_buf_frags_len(buf));
286 }
287
288 if (ops != NULL && ops->recv != NULL) {
289 ops->recv(stream, info, buf);
290 } else {
291 LOG_WRN("No callback for recv set");
292 }
293 }
294 #endif /* CONFIG_BT_AUDIO_RX */
295
296 #if defined(CONFIG_BT_AUDIO_TX)
unicast_client_ep_iso_sent(struct bt_iso_chan * chan)297 static void unicast_client_ep_iso_sent(struct bt_iso_chan *chan)
298 {
299 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
300 struct bt_bap_stream *stream;
301 struct bt_bap_ep *ep = iso->tx.ep;
302
303 if (ep == NULL) {
304 LOG_ERR("iso %p not bound with ep", chan);
305 return;
306 }
307
308 stream = ep->stream;
309 if (stream == NULL) {
310 LOG_ERR("No stream for ep %p", ep);
311 return;
312 }
313
314 if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) {
315 LOG_DBG("stream %p ep %p", stream, ep);
316 }
317
318 if (stream->ops != NULL && stream->ops->sent != NULL) {
319 stream->ops->sent(stream);
320 }
321 }
322 #endif /* CONFIG_BT_AUDIO_TX */
323
unicast_client_ep_iso_connected(struct bt_bap_ep * ep)324 static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep)
325 {
326 const struct bt_bap_stream_ops *stream_ops;
327 struct bt_bap_stream *stream;
328
329 if (ep->unicast_group != NULL) {
330 ep->unicast_group->has_been_connected = true;
331 }
332
333 if (ep->status.state != BT_BAP_EP_STATE_ENABLING) {
334 LOG_DBG("endpoint not in enabling state: %s",
335 bt_bap_ep_state_str(ep->status.state));
336 return;
337 }
338
339 stream = ep->stream;
340 if (stream == NULL) {
341 LOG_ERR("No stream for ep %p", ep);
342 return;
343 }
344
345 LOG_DBG("stream %p ep %p dir %s receiver_ready %u",
346 stream, ep, bt_audio_dir_str(ep->dir), ep->receiver_ready);
347
348 #if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM)
349 /* reset sequence number */
350 stream->_prev_seq_num = 0U;
351 #endif /* CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM */
352
353 stream_ops = stream->ops;
354 if (stream_ops != NULL && stream_ops->connected != NULL) {
355 stream_ops->connected(stream);
356 }
357 }
358
unicast_client_iso_connected(struct bt_iso_chan * chan)359 static void unicast_client_iso_connected(struct bt_iso_chan *chan)
360 {
361 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
362
363 if (iso->rx.ep == NULL && iso->tx.ep == NULL) {
364 LOG_ERR("iso %p not bound with ep", chan);
365 return;
366 }
367
368 if (iso->rx.ep != NULL) {
369 unicast_client_ep_iso_connected(iso->rx.ep);
370 }
371
372 if (iso->tx.ep != NULL) {
373 unicast_client_ep_iso_connected(iso->tx.ep);
374 }
375 }
376
unicast_client_ep_iso_disconnected(struct bt_bap_ep * ep,uint8_t reason)377 static void unicast_client_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason)
378 {
379 const struct bt_bap_stream_ops *stream_ops;
380 struct bt_bap_stream *stream;
381
382 stream = ep->stream;
383 if (stream == NULL) {
384 LOG_ERR("Stream not associated with an ep");
385 return;
386 }
387
388 LOG_DBG("stream %p ep %p reason 0x%02x", stream, ep, reason);
389 ep->reason = reason;
390
391 stream_ops = stream->ops;
392 if (stream_ops != NULL && stream_ops->disconnected != NULL) {
393 stream_ops->disconnected(stream, reason);
394 }
395
396 /* If we were in the idle state when we started the ISO disconnection
397 * then we need to call unicast_client_ep_idle_state again when
398 * the ISO has finalized the disconnection
399 */
400 if (ep->status.state == BT_BAP_EP_STATE_IDLE) {
401
402 unicast_client_ep_idle_state(ep);
403
404 if (stream->conn != NULL) {
405 struct bt_conn_info conn_info;
406 int err;
407
408 err = bt_conn_get_info(stream->conn, &conn_info);
409 if (err != 0 || conn_info.state == BT_CONN_STATE_DISCONNECTED) {
410 /* Retrigger the reset of the EP if the ACL is disconnected before
411 * the ISO is disconnected
412 */
413 unicast_client_reset(ep, reason);
414 }
415 }
416 }
417 }
418
unicast_client_iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)419 static void unicast_client_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
420 {
421 struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan);
422
423 if (iso->rx.ep == NULL && iso->tx.ep == NULL) {
424 LOG_ERR("iso %p not bound with ep", chan);
425 return;
426 }
427
428 if (iso->rx.ep != NULL) {
429 unicast_client_ep_iso_disconnected(iso->rx.ep, reason);
430 }
431
432 if (iso->tx.ep != NULL) {
433 unicast_client_ep_iso_disconnected(iso->tx.ep, reason);
434 }
435 }
436
437 static struct bt_iso_chan_ops unicast_client_iso_ops = {
438 #if defined(CONFIG_BT_AUDIO_RX)
439 .recv = unicast_client_ep_iso_recv,
440 #endif /* CONFIG_BT_AUDIO_RX */
441 #if defined(CONFIG_BT_AUDIO_TX)
442 .sent = unicast_client_ep_iso_sent,
443 #endif /* CONFIG_BT_AUDIO_TX */
444 .connected = unicast_client_iso_connected,
445 .disconnected = unicast_client_iso_disconnected,
446 };
447
bt_bap_ep_is_unicast_client(const struct bt_bap_ep * ep)448 bool bt_bap_ep_is_unicast_client(const struct bt_bap_ep *ep)
449 {
450 for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts); i++) {
451 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
452 if (PART_OF_ARRAY(uni_cli_insts[i].snks, ep)) {
453 return true;
454 }
455 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
456
457 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
458 if (PART_OF_ARRAY(uni_cli_insts[i].srcs, ep)) {
459 return true;
460 }
461 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
462 }
463
464 return false;
465 }
466
unicast_client_ep_init(struct bt_bap_ep * ep,uint16_t handle,uint8_t dir)467 static void unicast_client_ep_init(struct bt_bap_ep *ep, uint16_t handle, uint8_t dir)
468 {
469 struct bt_bap_unicast_client_ep *client_ep;
470
471 LOG_DBG("ep %p dir %s handle 0x%04x", ep, bt_audio_dir_str(dir), handle);
472
473 client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
474
475 (void)memset(ep, 0, sizeof(*ep));
476 client_ep->handle = handle;
477 ep->status.id = 0U;
478 ep->dir = dir;
479 ep->reason = BT_HCI_ERR_SUCCESS;
480 k_work_init_delayable(&client_ep->ase_read_work, delayed_ase_read_handler);
481 }
482
unicast_client_ep_find(struct bt_conn * conn,uint16_t handle)483 static struct bt_bap_ep *unicast_client_ep_find(struct bt_conn *conn, uint16_t handle)
484 {
485 uint8_t index;
486
487 index = bt_conn_index(conn);
488
489 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
490 for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts[index].snks); i++) {
491 struct bt_bap_unicast_client_ep *client_ep = &uni_cli_insts[index].snks[i];
492
493 if ((handle && client_ep->handle == handle) || (!handle && client_ep->handle)) {
494 return &client_ep->ep;
495 }
496 }
497 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
498
499 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
500 for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts[index].srcs); i++) {
501 struct bt_bap_unicast_client_ep *client_ep = &uni_cli_insts[index].srcs[i];
502
503 if ((handle && client_ep->handle == handle) || (!handle && client_ep->handle)) {
504 return &client_ep->ep;
505 }
506 }
507 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
508
509 return NULL;
510 }
511
bt_bap_unicast_client_new_audio_iso(void)512 struct bt_bap_iso *bt_bap_unicast_client_new_audio_iso(void)
513 {
514 struct bt_bap_iso *bap_iso;
515
516 bap_iso = bt_bap_iso_new();
517 if (bap_iso == NULL) {
518 return NULL;
519 }
520
521 bt_bap_iso_init(bap_iso, &unicast_client_iso_ops);
522
523 LOG_DBG("New bap_iso %p", bap_iso);
524
525 return bap_iso;
526 }
527
unicast_client_ep_new(struct bt_conn * conn,enum bt_audio_dir dir,uint16_t handle)528 static struct bt_bap_ep *unicast_client_ep_new(struct bt_conn *conn, enum bt_audio_dir dir,
529 uint16_t handle)
530 {
531 size_t i, size;
532 uint8_t index;
533 struct bt_bap_unicast_client_ep *cache;
534
535 index = bt_conn_index(conn);
536
537 switch (dir) {
538 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
539 case BT_AUDIO_DIR_SINK:
540 cache = uni_cli_insts[index].snks;
541 size = ARRAY_SIZE(uni_cli_insts[index].snks);
542 break;
543 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
544 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
545 case BT_AUDIO_DIR_SOURCE:
546 cache = uni_cli_insts[index].srcs;
547 size = ARRAY_SIZE(uni_cli_insts[index].srcs);
548 break;
549 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
550 default:
551 return NULL;
552 }
553
554 for (i = 0; i < size; i++) {
555 struct bt_bap_unicast_client_ep *client_ep = &cache[i];
556
557 if (!client_ep->handle) {
558 unicast_client_ep_init(&client_ep->ep, handle, dir);
559 return &client_ep->ep;
560 }
561 }
562
563 return NULL;
564 }
565
unicast_client_ep_get(struct bt_conn * conn,enum bt_audio_dir dir,uint16_t handle)566 static struct bt_bap_ep *unicast_client_ep_get(struct bt_conn *conn, enum bt_audio_dir dir,
567 uint16_t handle)
568 {
569 struct bt_bap_ep *ep;
570
571 ep = unicast_client_ep_find(conn, handle);
572 if (ep || !handle) {
573 return ep;
574 }
575
576 return unicast_client_ep_new(conn, dir, handle);
577 }
578
unicast_client_ep_set_local_idle_state(struct bt_bap_ep * ep)579 static void unicast_client_ep_set_local_idle_state(struct bt_bap_ep *ep)
580 {
581 struct bt_ascs_ase_status status = {
582 .id = ep->status.id,
583 .state = BT_BAP_EP_STATE_IDLE,
584 };
585 struct net_buf_simple buf;
586
587 net_buf_simple_init_with_data(&buf, &status, sizeof(status));
588
589 unicast_client_ep_set_status(ep, &buf);
590 }
591
unicast_client_notify_location(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_location loc)592 static void unicast_client_notify_location(struct bt_conn *conn, enum bt_audio_dir dir,
593 enum bt_audio_location loc)
594 {
595 struct bt_bap_unicast_client_cb *listener, *next;
596
597 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
598 if (listener->location != NULL) {
599 listener->location(conn, dir, loc);
600 }
601 }
602 }
603
unicast_client_notify_available_contexts(struct bt_conn * conn,enum bt_audio_context snk_ctx,enum bt_audio_context src_ctx)604 static void unicast_client_notify_available_contexts(struct bt_conn *conn,
605 enum bt_audio_context snk_ctx,
606 enum bt_audio_context src_ctx)
607 {
608 struct bt_bap_unicast_client_cb *listener, *next;
609
610 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
611 if (listener->available_contexts != NULL) {
612 listener->available_contexts(conn, snk_ctx, src_ctx);
613 }
614 }
615 }
616
unicast_client_notify_pac_record(struct bt_conn * conn,const struct bt_audio_codec_cap * codec_cap)617 static void unicast_client_notify_pac_record(struct bt_conn *conn,
618 const struct bt_audio_codec_cap *codec_cap)
619 {
620 const struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
621 struct bt_bap_unicast_client_cb *listener, *next;
622 const enum bt_audio_dir dir = client->dir;
623
624 /* TBD: Since the PAC records are optionally notifiable we may want to supply the
625 * index and total count of records in the callback, so that it easier for the
626 * upper layers to determine when a new set of PAC records is being reported.
627 */
628
629 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
630 if (listener->pac_record != NULL) {
631 listener->pac_record(conn, dir, codec_cap);
632 }
633 }
634 }
635
unicast_client_notify_endpoint(struct bt_conn * conn,struct bt_bap_ep * ep)636 static void unicast_client_notify_endpoint(struct bt_conn *conn, struct bt_bap_ep *ep)
637 {
638 const struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
639 struct bt_bap_unicast_client_cb *listener, *next;
640 const enum bt_audio_dir dir = client->dir;
641
642 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
643 if (listener->endpoint != NULL) {
644 listener->endpoint(conn, dir, ep);
645 }
646 }
647 }
648
unicast_client_discover_complete(struct bt_conn * conn,int err)649 static void unicast_client_discover_complete(struct bt_conn *conn, int err)
650 {
651 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
652 struct bt_bap_unicast_client_cb *listener, *next;
653 const enum bt_audio_dir dir = client->dir;
654
655 /* Discover complete - Reset discovery values */
656 client->dir = 0U;
657 reset_att_buf(client);
658 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
659
660 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
661 if (listener->discover != NULL) {
662 listener->discover(conn, err, dir);
663 }
664 }
665 }
666
unicast_client_notify_ep_config(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)667 static void unicast_client_notify_ep_config(struct bt_bap_stream *stream,
668 enum bt_bap_ascs_rsp_code rsp_code,
669 enum bt_bap_ascs_reason reason)
670 {
671 struct bt_bap_unicast_client_cb *listener, *next;
672
673 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
674 if (listener->config != NULL) {
675 listener->config(stream, rsp_code, reason);
676 }
677 }
678 }
679
unicast_client_notify_ep_qos(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)680 static void unicast_client_notify_ep_qos(struct bt_bap_stream *stream,
681 enum bt_bap_ascs_rsp_code rsp_code,
682 enum bt_bap_ascs_reason reason)
683 {
684 struct bt_bap_unicast_client_cb *listener, *next;
685
686 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
687 if (listener->qos != NULL) {
688 listener->qos(stream, rsp_code, reason);
689 }
690 }
691 }
692
unicast_client_notify_ep_enable(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)693 static void unicast_client_notify_ep_enable(struct bt_bap_stream *stream,
694 enum bt_bap_ascs_rsp_code rsp_code,
695 enum bt_bap_ascs_reason reason)
696 {
697 struct bt_bap_unicast_client_cb *listener, *next;
698
699 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
700 if (listener->enable != NULL) {
701 listener->enable(stream, rsp_code, reason);
702 }
703 }
704 }
705
unicast_client_notify_ep_start(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)706 static void unicast_client_notify_ep_start(struct bt_bap_stream *stream,
707 enum bt_bap_ascs_rsp_code rsp_code,
708 enum bt_bap_ascs_reason reason)
709 {
710 struct bt_bap_unicast_client_cb *listener, *next;
711
712 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
713 if (listener->start != NULL) {
714 listener->start(stream, rsp_code, reason);
715 }
716 }
717 }
718
unicast_client_notify_ep_stop(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)719 static void unicast_client_notify_ep_stop(struct bt_bap_stream *stream,
720 enum bt_bap_ascs_rsp_code rsp_code,
721 enum bt_bap_ascs_reason reason)
722 {
723 struct bt_bap_unicast_client_cb *listener, *next;
724
725 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
726 if (listener->stop != NULL) {
727 listener->stop(stream, rsp_code, reason);
728 }
729 }
730 }
731
unicast_client_notify_ep_disable(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)732 static void unicast_client_notify_ep_disable(struct bt_bap_stream *stream,
733 enum bt_bap_ascs_rsp_code rsp_code,
734 enum bt_bap_ascs_reason reason)
735 {
736 struct bt_bap_unicast_client_cb *listener, *next;
737
738 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
739 if (listener->disable != NULL) {
740 listener->disable(stream, rsp_code, reason);
741 }
742 }
743 }
744
unicast_client_notify_ep_metadata(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)745 static void unicast_client_notify_ep_metadata(struct bt_bap_stream *stream,
746 enum bt_bap_ascs_rsp_code rsp_code,
747 enum bt_bap_ascs_reason reason)
748 {
749 struct bt_bap_unicast_client_cb *listener, *next;
750
751 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
752 if (listener->metadata != NULL) {
753 listener->metadata(stream, rsp_code, reason);
754 }
755 }
756 }
757
unicast_client_notify_ep_released(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)758 static void unicast_client_notify_ep_released(struct bt_bap_stream *stream,
759 enum bt_bap_ascs_rsp_code rsp_code,
760 enum bt_bap_ascs_reason reason)
761 {
762 struct bt_bap_unicast_client_cb *listener, *next;
763
764 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&unicast_client_cbs, listener, next, _node) {
765 if (listener->release != NULL) {
766 listener->release(stream, rsp_code, reason);
767 }
768 }
769 }
770
unicast_client_ep_idle_state(struct bt_bap_ep * ep)771 static void unicast_client_ep_idle_state(struct bt_bap_ep *ep)
772 {
773 struct bt_bap_unicast_client_ep *client_ep =
774 CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
775 struct bt_bap_stream *stream = ep->stream;
776 const struct bt_bap_stream_ops *ops;
777
778 ep->receiver_ready = false;
779
780 if (stream == NULL) {
781 return;
782 }
783
784 /* If CIS is connected, disconnect and wait for CIS disconnection */
785 if (bt_bap_stream_can_disconnect(stream)) {
786 int err;
787
788 LOG_DBG("Disconnecting stream");
789 err = bt_bap_stream_disconnect(stream);
790
791 if (err != 0) {
792 LOG_ERR("Failed to disconnect stream: %d", err);
793 }
794
795 return;
796 } else if (ep->iso != NULL && ep->iso->chan.state == BT_ISO_STATE_DISCONNECTING) {
797 /* Wait for disconnection */
798 return;
799 }
800
801 bt_bap_stream_reset(stream);
802
803 /* Notify upper layer */
804 if (client_ep->release_requested) {
805 client_ep->release_requested = false;
806
807 if (client_ep->cp_ntf_pending) {
808 /* In case that we get the idle state notification before the CP
809 * notification we trigger the CP callback now, as after this we won't be
810 * able to find the stream by the ASE ID
811 */
812 client_ep->cp_ntf_pending = false;
813
814 unicast_client_notify_ep_released(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS,
815 BT_BAP_ASCS_REASON_NONE);
816 }
817 }
818
819 ops = stream->ops;
820 if (ops != NULL && ops->released != NULL) {
821 ops->released(stream);
822 } else {
823 LOG_WRN("No callback for released set");
824 }
825 }
826
unicast_client_ep_qos_update(struct bt_bap_ep * ep,const struct bt_ascs_ase_status_qos * qos)827 static void unicast_client_ep_qos_update(struct bt_bap_ep *ep,
828 const struct bt_ascs_ase_status_qos *qos)
829 {
830 struct bt_iso_chan_io_qos *iso_io_qos;
831
832 LOG_DBG("ep %p dir %s bap_iso %p", ep, bt_audio_dir_str(ep->dir), ep->iso);
833
834 if (ep->dir == BT_AUDIO_DIR_SOURCE) {
835 /* If the endpoint is a source, then we need to
836 * reset our RX parameters
837 */
838 iso_io_qos = &ep->iso->rx.qos;
839 } else if (ep->dir == BT_AUDIO_DIR_SINK) {
840 /* If the endpoint is a sink, then we need to
841 * reset our TX parameters
842 */
843 iso_io_qos = &ep->iso->tx.qos;
844 } else {
845 __ASSERT(false, "Invalid ep->dir: %u", ep->dir);
846 return;
847 }
848
849 iso_io_qos->phy = qos->phy;
850 iso_io_qos->sdu = sys_le16_to_cpu(qos->sdu);
851 iso_io_qos->rtn = qos->rtn;
852 }
853
unicast_client_ep_config_state(struct bt_bap_ep * ep,struct net_buf_simple * buf)854 static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_simple *buf)
855 {
856 struct bt_bap_unicast_client_ep *client_ep =
857 CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
858 struct bt_ascs_ase_status_config *cfg;
859 struct bt_bap_qos_cfg_pref *pref;
860 struct bt_bap_stream *stream;
861 void *cc;
862
863 ep->receiver_ready = false;
864
865 if (client_ep->release_requested) {
866 LOG_DBG("Released was requested, change local state to idle");
867 ep->reason = BT_HCI_ERR_LOCALHOST_TERM_CONN;
868 unicast_client_ep_set_local_idle_state(ep);
869 return;
870 }
871
872 if (buf->len < sizeof(*cfg)) {
873 LOG_ERR("Config status too short");
874 return;
875 }
876
877 stream = ep->stream;
878 if (stream == NULL) {
879 LOG_WRN("No stream active for endpoint");
880 return;
881 }
882
883 cfg = net_buf_simple_pull_mem(buf, sizeof(*cfg));
884
885 if (stream->codec_cfg == NULL) {
886 LOG_ERR("Stream %p does not have a codec configured", stream);
887 return;
888 } else if (stream->codec_cfg->id != cfg->codec.id) {
889 LOG_ERR("Codec configuration mismatched: %u, %u", stream->codec_cfg->id,
890 cfg->codec.id);
891 /* TODO: Release the stream? */
892 return;
893 }
894
895 if (buf->len < cfg->cc_len) {
896 LOG_ERR("Malformed ASE Config status: buf->len %u < %u cc_len", buf->len,
897 cfg->cc_len);
898 return;
899 }
900
901 cc = net_buf_simple_pull_mem(buf, cfg->cc_len);
902
903 pref = &stream->ep->qos_pref;
904
905 /* Convert to interval representation so they can be matched by QoS */
906 pref->unframed_supported = cfg->framing == BT_ASCS_QOS_FRAMING_UNFRAMED;
907 pref->phy = cfg->phy;
908 pref->rtn = cfg->rtn;
909 pref->latency = sys_le16_to_cpu(cfg->latency);
910 pref->pd_min = sys_get_le24(cfg->pd_min);
911 pref->pd_max = sys_get_le24(cfg->pd_max);
912 pref->pref_pd_min = sys_get_le24(cfg->prefer_pd_min);
913 pref->pref_pd_max = sys_get_le24(cfg->prefer_pd_max);
914
915 LOG_DBG("dir %s unframed_supported 0x%02x phy 0x%02x rtn %u "
916 "latency %u pd_min %u pd_max %u pref_pd_min %u pref_pd_max %u codec 0x%02x ",
917 bt_audio_dir_str(ep->dir), pref->unframed_supported, pref->phy, pref->rtn,
918 pref->latency, pref->pd_min, pref->pd_max, pref->pref_pd_min, pref->pref_pd_max,
919 stream->codec_cfg->id);
920
921 if (!bt_bap_valid_qos_pref(pref)) {
922 LOG_DBG("Invalid QoS preferences");
923 memset(pref, 0, sizeof(*pref));
924
925 /* If the sever provide an invalid QoS preferences we treat it as an error and do
926 * nothing
927 */
928 return;
929 }
930
931 unicast_client_ep_set_codec_cfg(ep, cfg->codec.id, sys_le16_to_cpu(cfg->codec.cid),
932 sys_le16_to_cpu(cfg->codec.vid), cc, cfg->cc_len, NULL);
933
934 /* Notify upper layer */
935 if (stream->ops != NULL && stream->ops->configured != NULL) {
936 stream->ops->configured(stream, pref);
937 } else {
938 LOG_WRN("No callback for configured set");
939 }
940 }
941
unicast_client_ep_qos_state(struct bt_bap_ep * ep,struct net_buf_simple * buf,uint8_t old_state)942 static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_simple *buf,
943 uint8_t old_state)
944 {
945 const struct bt_bap_stream_ops *ops;
946 struct bt_ascs_ase_status_qos *qos;
947 struct bt_bap_stream *stream;
948
949 ep->receiver_ready = false;
950
951 if (buf->len < sizeof(*qos)) {
952 LOG_ERR("QoS status too short");
953 return;
954 }
955
956 stream = ep->stream;
957 if (stream == NULL) {
958 LOG_ERR("No stream active for endpoint");
959 return;
960 }
961 ops = stream->ops;
962
963 if (ops != NULL) {
964 if (ep->dir == BT_AUDIO_DIR_SINK && ops->disabled != NULL) {
965 /* If the old state was enabling or streaming, then the sink
966 * ASE has been disabled. Since the sink ASE does not have a
967 * disabling state, we can check if by comparing the old_state
968 */
969 const bool disabled = old_state == BT_BAP_EP_STATE_ENABLING ||
970 old_state == BT_BAP_EP_STATE_STREAMING;
971
972 if (disabled) {
973 ops->disabled(stream);
974 }
975 } else if (ep->dir == BT_AUDIO_DIR_SOURCE &&
976 old_state == BT_BAP_EP_STATE_DISABLING && ops->stopped != NULL) {
977 /* We left the disabling state, let the upper layers know that the stream is
978 * stopped
979 */
980 uint8_t reason = ep->reason;
981
982 if (reason == BT_HCI_ERR_SUCCESS) {
983 /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */
984 reason = BT_HCI_ERR_UNSPECIFIED;
985 } else {
986 /* Reset reason */
987 ep->reason = BT_HCI_ERR_SUCCESS;
988 }
989
990 ops->stopped(stream, reason);
991 }
992 }
993
994 qos = net_buf_simple_pull_mem(buf, sizeof(*qos));
995
996 /* Update existing QoS configuration */
997 unicast_client_ep_qos_update(ep, qos);
998
999 ep->cig_id = qos->cig_id;
1000 ep->cis_id = qos->cis_id;
1001 (void)memcpy(&stream->qos->interval, sys_le24_to_cpu(qos->interval), sizeof(qos->interval));
1002 stream->qos->framing = qos->framing;
1003 stream->qos->phy = qos->phy;
1004 stream->qos->sdu = sys_le16_to_cpu(qos->sdu);
1005 stream->qos->rtn = qos->rtn;
1006 stream->qos->latency = sys_le16_to_cpu(qos->latency);
1007 (void)memcpy(&stream->qos->pd, sys_le24_to_cpu(qos->pd), sizeof(qos->pd));
1008
1009 LOG_DBG("dir %s cig 0x%02x cis 0x%02x codec 0x%02x interval %u "
1010 "framing 0x%02x phy 0x%02x rtn %u latency %u pd %u",
1011 bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id, stream->codec_cfg->id,
1012 stream->qos->interval, stream->qos->framing, stream->qos->phy, stream->qos->rtn,
1013 stream->qos->latency, stream->qos->pd);
1014
1015 /* Disconnect ISO if connected */
1016 if (bt_bap_stream_can_disconnect(stream)) {
1017 const int err = bt_bap_stream_disconnect(stream);
1018
1019 if (err != 0) {
1020 LOG_ERR("Failed to disconnect stream: %d", err);
1021 }
1022 } else {
1023 /* We setup the data path here, as this is the earliest where
1024 * we have the ISO <-> EP coupling completed (due to setting
1025 * the CIS ID in the QoS procedure).
1026 */
1027
1028 bt_bap_iso_configure_data_path(ep, stream->codec_cfg);
1029 }
1030
1031 /* Notify upper layer */
1032 if (stream->ops != NULL && stream->ops->qos_set != NULL) {
1033 stream->ops->qos_set(stream);
1034 } else {
1035 LOG_WRN("No callback for qos_set set");
1036 }
1037 }
1038
unicast_client_ep_enabling_state(struct bt_bap_ep * ep,struct net_buf_simple * buf,bool state_changed)1039 static void unicast_client_ep_enabling_state(struct bt_bap_ep *ep, struct net_buf_simple *buf,
1040 bool state_changed)
1041 {
1042 struct bt_ascs_ase_status_enable *enable;
1043 struct bt_bap_stream *stream;
1044 void *metadata;
1045
1046 if (buf->len < sizeof(*enable)) {
1047 LOG_ERR("Enabling status too short");
1048 return;
1049 }
1050
1051 stream = ep->stream;
1052 if (stream == NULL) {
1053 LOG_ERR("No stream active for endpoint");
1054 return;
1055 }
1056
1057 enable = net_buf_simple_pull_mem(buf, sizeof(*enable));
1058
1059 if (buf->len < enable->metadata_len) {
1060 LOG_ERR("Malformed PDU: remaining len %u expected %u", buf->len,
1061 enable->metadata_len);
1062 return;
1063 }
1064
1065 metadata = net_buf_simple_pull_mem(buf, enable->metadata_len);
1066
1067 LOG_DBG("dir %s cig 0x%02x cis 0x%02x", bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id);
1068
1069 unicast_client_ep_set_metadata(ep, metadata, enable->metadata_len, NULL);
1070
1071 /* Notify upper layer
1072 *
1073 * If the state did not change then only the metadata was changed
1074 */
1075 if (state_changed) {
1076 if (stream->ops != NULL && stream->ops->enabled != NULL) {
1077 stream->ops->enabled(stream);
1078 } else {
1079 LOG_WRN("No callback for enabled set");
1080 }
1081 } else {
1082 if (stream->ops != NULL && stream->ops->metadata_updated != NULL) {
1083 stream->ops->metadata_updated(stream);
1084 } else {
1085 LOG_WRN("No callback for metadata_updated set");
1086 }
1087 }
1088 }
1089
unicast_client_ep_streaming_state(struct bt_bap_ep * ep,struct net_buf_simple * buf,bool state_changed)1090 static void unicast_client_ep_streaming_state(struct bt_bap_ep *ep, struct net_buf_simple *buf,
1091 bool state_changed)
1092 {
1093 struct bt_ascs_ase_status_stream *stream_status;
1094 struct bt_bap_stream *stream;
1095
1096 if (buf->len < sizeof(*stream_status)) {
1097 LOG_ERR("Streaming status too short");
1098 return;
1099 }
1100
1101 stream = ep->stream;
1102 if (stream == NULL) {
1103 LOG_ERR("No stream active for endpoint");
1104 return;
1105 }
1106
1107 stream_status = net_buf_simple_pull_mem(buf, sizeof(*stream_status));
1108
1109 LOG_DBG("dir %s cig 0x%02x cis 0x%02x", bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id);
1110
1111 /* Notify upper layer
1112 *
1113 * If the state did not change then only the metadata was changed
1114 */
1115 if (state_changed) {
1116 if (stream->ops != NULL && stream->ops->started != NULL) {
1117 stream->ops->started(stream);
1118 } else {
1119 LOG_WRN("No callback for started set");
1120 }
1121 } else {
1122 if (stream->ops != NULL && stream->ops->metadata_updated != NULL) {
1123 stream->ops->metadata_updated(stream);
1124 } else {
1125 LOG_WRN("No callback for metadata_updated set");
1126 }
1127 }
1128 }
1129
unicast_client_ep_disabling_state(struct bt_bap_ep * ep,struct net_buf_simple * buf)1130 static void unicast_client_ep_disabling_state(struct bt_bap_ep *ep, struct net_buf_simple *buf)
1131 {
1132 struct bt_ascs_ase_status_disable *disable;
1133 struct bt_bap_stream *stream;
1134
1135 ep->receiver_ready = false;
1136
1137 if (buf->len < sizeof(*disable)) {
1138 LOG_ERR("Disabling status too short");
1139 return;
1140 }
1141
1142 stream = ep->stream;
1143 if (stream == NULL) {
1144 LOG_ERR("No stream active for endpoint");
1145 return;
1146 }
1147
1148 disable = net_buf_simple_pull_mem(buf, sizeof(*disable));
1149
1150 LOG_DBG("dir %s cig 0x%02x cis 0x%02x", bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id);
1151
1152 /* Notify upper layer */
1153 if (stream->ops != NULL && stream->ops->disabled != NULL) {
1154 stream->ops->disabled(stream);
1155 } else {
1156 LOG_WRN("No callback for disabled set");
1157 }
1158 }
1159
unicast_client_ep_releasing_state(struct bt_bap_ep * ep,struct net_buf_simple * buf)1160 static void unicast_client_ep_releasing_state(struct bt_bap_ep *ep, struct net_buf_simple *buf)
1161 {
1162 struct bt_bap_stream *stream;
1163
1164 ep->receiver_ready = false;
1165
1166 stream = ep->stream;
1167 if (stream == NULL) {
1168 LOG_ERR("No stream active for endpoint");
1169 return;
1170 }
1171
1172 LOG_DBG("dir %s", bt_audio_dir_str(ep->dir));
1173
1174 if (bt_bap_stream_can_disconnect(stream)) {
1175 /* The Unicast Client shall terminate any CIS established for
1176 * that ASE by following the Connected Isochronous Stream
1177 * Terminate procedure defined in Volume 3, Part C,
1178 * Section 9.3.15 in when the Unicast Client has determined
1179 * that the ASE is in the Releasing state.
1180 */
1181 const int err = bt_bap_stream_disconnect(stream);
1182
1183 if (err != 0) {
1184 LOG_ERR("Failed to disconnect stream: %d", err);
1185 }
1186 }
1187 }
1188
unicast_client_ep_set_status(struct bt_bap_ep * ep,struct net_buf_simple * buf)1189 static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_simple *buf)
1190 {
1191 struct bt_ascs_ase_status *status;
1192 struct bt_bap_unicast_client_ep *client_ep;
1193 bool state_changed;
1194 uint8_t old_state;
1195
1196 if (!ep) {
1197 return;
1198 }
1199
1200 client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
1201
1202 status = net_buf_simple_pull_mem(buf, sizeof(*status));
1203
1204 old_state = ep->status.state;
1205 ep->status = *status;
1206 state_changed = old_state != ep->status.state;
1207
1208 if (state_changed && old_state == BT_BAP_EP_STATE_STREAMING) {
1209 /* We left the streaming state, let the upper layers know that the stream is stopped
1210 */
1211 struct bt_bap_stream *stream = ep->stream;
1212
1213 if (stream != NULL) {
1214 struct bt_bap_stream_ops *ops = stream->ops;
1215 uint8_t reason = ep->reason;
1216
1217 if (reason == BT_HCI_ERR_SUCCESS) {
1218 /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */
1219 reason = BT_HCI_ERR_UNSPECIFIED;
1220 } else {
1221 /* Reset reason */
1222 ep->reason = BT_HCI_ERR_SUCCESS;
1223 }
1224
1225 if (ops != NULL && ops->stopped != NULL) {
1226 ops->stopped(stream, reason);
1227 } else {
1228 LOG_WRN("No callback for stopped set");
1229 }
1230 }
1231 }
1232
1233 LOG_DBG("ep %p handle 0x%04x id 0x%02x dir %s state %s -> %s", ep, client_ep->handle,
1234 status->id, bt_audio_dir_str(ep->dir), bt_bap_ep_state_str(old_state),
1235 bt_bap_ep_state_str(status->state));
1236
1237 switch (status->state) {
1238 case BT_BAP_EP_STATE_IDLE:
1239 unicast_client_ep_idle_state(ep);
1240 break;
1241 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
1242 switch (old_state) {
1243 /* Valid only if ASE_State field = 0x00 (Idle) */
1244 case BT_BAP_EP_STATE_IDLE:
1245 /* or 0x01 (Codec Configured) */
1246 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
1247 /* or 0x02 (QoS Configured) */
1248 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1249 /* or 0x06 (Releasing) */
1250 case BT_BAP_EP_STATE_RELEASING:
1251 break;
1252 default:
1253 LOG_WRN("Invalid state transition: %s -> %s",
1254 bt_bap_ep_state_str(old_state),
1255 bt_bap_ep_state_str(ep->status.state));
1256 return;
1257 }
1258
1259 unicast_client_ep_config_state(ep, buf);
1260 break;
1261 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1262 /* QoS configured have different allowed states depending on the endpoint type */
1263 if (ep->dir == BT_AUDIO_DIR_SOURCE) {
1264 switch (old_state) {
1265 /* Valid only if ASE_State field = 0x01 (Codec Configured) */
1266 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
1267 /* or 0x02 (QoS Configured) */
1268 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1269 /* or 0x04 (Streaming) if there is a disconnect */
1270 case BT_BAP_EP_STATE_STREAMING:
1271 /* or 0x05 (Disabling) */
1272 case BT_BAP_EP_STATE_DISABLING:
1273 break;
1274 default:
1275 LOG_WRN("Invalid state transition: %s -> %s",
1276 bt_bap_ep_state_str(old_state),
1277 bt_bap_ep_state_str(ep->status.state));
1278 return;
1279 }
1280 } else {
1281 switch (old_state) {
1282 /* Valid only if ASE_State field = 0x01 (Codec Configured) */
1283 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
1284 /* or 0x02 (QoS Configured) */
1285 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1286 /* or 0x03 (Enabling) */
1287 case BT_BAP_EP_STATE_ENABLING:
1288 /* or 0x04 (Streaming)*/
1289 case BT_BAP_EP_STATE_STREAMING:
1290 break;
1291 default:
1292 LOG_WRN("Invalid state transition: %s -> %s",
1293 bt_bap_ep_state_str(old_state),
1294 bt_bap_ep_state_str(ep->status.state));
1295 return;
1296 }
1297 }
1298
1299 unicast_client_ep_qos_state(ep, buf, old_state);
1300 break;
1301 case BT_BAP_EP_STATE_ENABLING:
1302 switch (old_state) {
1303 /* Valid only if ASE_State field = 0x02 (QoS Configured) */
1304 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1305 /* or 0x03 (Enabling) */
1306 case BT_BAP_EP_STATE_ENABLING:
1307 break;
1308 default:
1309 LOG_WRN("Invalid state transition: %s -> %s",
1310 bt_bap_ep_state_str(old_state),
1311 bt_bap_ep_state_str(ep->status.state));
1312 return;
1313 }
1314
1315 unicast_client_ep_enabling_state(ep, buf, state_changed);
1316 break;
1317 case BT_BAP_EP_STATE_STREAMING:
1318 switch (old_state) {
1319 /* Valid only if ASE_State field = 0x03 (Enabling)*/
1320 case BT_BAP_EP_STATE_ENABLING:
1321 /* or 0x04 (Streaming)*/
1322 case BT_BAP_EP_STATE_STREAMING:
1323 break;
1324 default:
1325 LOG_WRN("Invalid state transition: %s -> %s",
1326 bt_bap_ep_state_str(old_state),
1327 bt_bap_ep_state_str(ep->status.state));
1328 return;
1329 }
1330
1331 unicast_client_ep_streaming_state(ep, buf, state_changed);
1332 break;
1333 case BT_BAP_EP_STATE_DISABLING:
1334 if (ep->dir == BT_AUDIO_DIR_SOURCE) {
1335 switch (old_state) {
1336 /* Valid only if ASE_State field = 0x03 (Enabling) */
1337 case BT_BAP_EP_STATE_ENABLING:
1338 /* or 0x04 (Streaming) */
1339 case BT_BAP_EP_STATE_STREAMING:
1340 break;
1341 default:
1342 LOG_WRN("Invalid state transition: %s -> %s",
1343 bt_bap_ep_state_str(old_state),
1344 bt_bap_ep_state_str(ep->status.state));
1345 return;
1346 }
1347 } else {
1348 /* Sinks cannot go into the disabling state */
1349 LOG_WRN("Invalid state transition: %s -> %s",
1350 bt_bap_ep_state_str(old_state),
1351 bt_bap_ep_state_str(ep->status.state));
1352 return;
1353 }
1354
1355 unicast_client_ep_disabling_state(ep, buf);
1356 break;
1357 case BT_BAP_EP_STATE_RELEASING:
1358 switch (old_state) {
1359 /* Valid only if ASE_State field = 0x01 (Codec Configured) */
1360 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
1361 /* or 0x02 (QoS Configured) */
1362 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1363 /* or 0x03 (Enabling) */
1364 case BT_BAP_EP_STATE_ENABLING:
1365 /* or 0x04 (Streaming) */
1366 case BT_BAP_EP_STATE_STREAMING:
1367 break;
1368 /* or 0x04 (Disabling) */
1369 case BT_BAP_EP_STATE_DISABLING:
1370 if (ep->dir == BT_AUDIO_DIR_SOURCE) {
1371 break;
1372 } /* else fall through for sink */
1373
1374 /* fall through */
1375 default:
1376 LOG_WRN("Invalid state transition: %s -> %s",
1377 bt_bap_ep_state_str(old_state),
1378 bt_bap_ep_state_str(ep->status.state));
1379 return;
1380 }
1381
1382 unicast_client_ep_releasing_state(ep, buf);
1383 break;
1384 }
1385 }
1386
valid_ltv_cb(struct bt_data * data,void * user_data)1387 static bool valid_ltv_cb(struct bt_data *data, void *user_data)
1388 {
1389 /* just return true to continue parsing as bt_data_parse will validate for us */
1390 return true;
1391 }
1392
unicast_client_ep_set_codec_cfg(struct bt_bap_ep * ep,uint8_t id,uint16_t cid,uint16_t vid,void * data,uint8_t len,struct bt_audio_codec_cfg * codec_cfg)1393 static int unicast_client_ep_set_codec_cfg(struct bt_bap_ep *ep, uint8_t id, uint16_t cid,
1394 uint16_t vid, void *data, uint8_t len,
1395 struct bt_audio_codec_cfg *codec_cfg)
1396 {
1397 if (!ep && !codec_cfg) {
1398 return -EINVAL;
1399 }
1400
1401 LOG_DBG("ep %p codec id 0x%02x cid 0x%04x vid 0x%04x len %u", ep, id, cid, vid, len);
1402
1403 if (!codec_cfg) {
1404 codec_cfg = &ep->codec_cfg;
1405 }
1406
1407 if (len > sizeof(codec_cfg->data)) {
1408 LOG_DBG("Cannot store %u octets of codec data", len);
1409
1410 return -ENOMEM;
1411 }
1412
1413 codec_cfg->id = id;
1414 codec_cfg->cid = cid;
1415 codec_cfg->vid = vid;
1416
1417 codec_cfg->data_len = len;
1418 memcpy(codec_cfg->data, data, len);
1419
1420 return 0;
1421 }
1422
unicast_client_set_codec_cap(uint8_t id,uint16_t cid,uint16_t vid,void * data,uint8_t data_len,void * meta,uint8_t meta_len,struct bt_audio_codec_cap * codec_cap)1423 static int unicast_client_set_codec_cap(uint8_t id, uint16_t cid, uint16_t vid, void *data,
1424 uint8_t data_len, void *meta, uint8_t meta_len,
1425 struct bt_audio_codec_cap *codec_cap)
1426 {
1427 struct net_buf_simple buf;
1428
1429 if (!codec_cap) {
1430 return -EINVAL;
1431 }
1432
1433 LOG_DBG("codec id 0x%02x cid 0x%04x vid 0x%04x data_len %u meta_len %u", id, cid, vid,
1434 data_len, meta_len);
1435
1436 /* Reset current data */
1437 (void)memset(codec_cap, 0, sizeof(*codec_cap));
1438
1439 codec_cap->id = id;
1440 codec_cap->cid = cid;
1441 codec_cap->vid = vid;
1442
1443 if (data_len > 0U) {
1444 if (data_len > sizeof(codec_cap->data)) {
1445 return -ENOMEM;
1446 }
1447
1448 net_buf_simple_init_with_data(&buf, data, data_len);
1449
1450 /* If codec is LC3, then it shall be LTV encoded - We verify this before storing the
1451 * data For any non-LC3 codecs, we cannot verify anything
1452 */
1453 if (id == BT_HCI_CODING_FORMAT_LC3) {
1454 bt_data_parse(&buf, valid_ltv_cb, NULL);
1455
1456 /* Check if all entries could be parsed */
1457 if (buf.len) {
1458 LOG_ERR("Unable to parse Codec capabilities: len %u", buf.len);
1459 return -EINVAL;
1460 }
1461 }
1462 memcpy(codec_cap->data, data, data_len);
1463 codec_cap->data_len = data_len;
1464 }
1465
1466 if (meta_len > 0U) {
1467 if (meta_len > sizeof(codec_cap->meta)) {
1468 return -ENOMEM;
1469 }
1470
1471 net_buf_simple_init_with_data(&buf, meta, meta_len);
1472
1473 bt_data_parse(&buf, valid_ltv_cb, NULL);
1474
1475 /* Check if all entries could be parsed */
1476 if (buf.len) {
1477 LOG_ERR("Unable to parse Codec metadata: len %u", buf.len);
1478 return -EINVAL;
1479 }
1480
1481 memcpy(codec_cap->meta, meta, meta_len);
1482 codec_cap->meta_len = meta_len;
1483 }
1484
1485 return 0;
1486 }
1487
unicast_client_ep_set_metadata(struct bt_bap_ep * ep,void * data,uint8_t len,struct bt_audio_codec_cfg * codec_cfg)1488 static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint8_t len,
1489 struct bt_audio_codec_cfg *codec_cfg)
1490 {
1491 if (!ep && !codec_cfg) {
1492 return -EINVAL;
1493 }
1494
1495 LOG_DBG("ep %p len %u codec_cfg %p", ep, len, codec_cfg);
1496
1497 if (!codec_cfg) {
1498 codec_cfg = &ep->codec_cfg;
1499 }
1500
1501 if (len > sizeof(codec_cfg->meta)) {
1502 LOG_DBG("Cannot store %u octets of metadata", len);
1503
1504 return -ENOMEM;
1505 }
1506
1507 /* Reset current metadata */
1508 codec_cfg->meta_len = len;
1509 (void)memcpy(codec_cfg->meta, data, len);
1510
1511 return 0;
1512 }
1513
unicast_client_cp_notify(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)1514 static uint8_t unicast_client_cp_notify(struct bt_conn *conn,
1515 struct bt_gatt_subscribe_params *params, const void *data,
1516 uint16_t length)
1517 {
1518 struct bt_ascs_cp_rsp *rsp;
1519 struct net_buf_simple buf;
1520
1521 LOG_DBG("conn %p len %u", conn, length);
1522
1523 if (!data) {
1524 LOG_DBG("Unsubscribed");
1525 params->value_handle = BAP_HANDLE_UNUSED;
1526 return BT_GATT_ITER_STOP;
1527 }
1528
1529 net_buf_simple_init_with_data(&buf, (void *)data, length);
1530
1531 if (buf.len < sizeof(*rsp)) {
1532 LOG_ERR("Control Point Notification too small");
1533 return BT_GATT_ITER_STOP;
1534 }
1535
1536 rsp = net_buf_simple_pull_mem(&buf, sizeof(*rsp));
1537
1538 if (rsp->num_ase == BT_ASCS_UNSUPP_OR_LENGTH_ERR_NUM_ASE) {
1539 /* This is a special case where num_ase == BT_ASCS_UNSUPP_OR_LENGTH_ERR_NUM_ASE
1540 * but really there is only one ASE response
1541 */
1542 rsp->num_ase = 1U;
1543 }
1544
1545 for (uint8_t i = 0U; i < rsp->num_ase; i++) {
1546 struct bt_bap_unicast_client_ep *client_ep = NULL;
1547 struct bt_ascs_cp_ase_rsp *ase_rsp;
1548 struct bt_bap_stream *stream;
1549
1550 if (buf.len < sizeof(*ase_rsp)) {
1551 LOG_ERR("Control Point Notification too small: %u", buf.len);
1552 return BT_GATT_ITER_STOP;
1553 }
1554
1555 ase_rsp = net_buf_simple_pull_mem(&buf, sizeof(*ase_rsp));
1556
1557 LOG_DBG("op %s (0x%02x) id 0x%02x code %s (0x%02x) "
1558 "reason %s (0x%02x)", bt_ascs_op_str(rsp->op), rsp->op,
1559 ase_rsp->id, bt_ascs_rsp_str(ase_rsp->code),
1560 ase_rsp->code, bt_ascs_reason_str(ase_rsp->reason),
1561 ase_rsp->reason);
1562
1563 stream = audio_stream_by_ep_id(conn, ase_rsp->id);
1564 if (stream == NULL) {
1565 LOG_DBG("Could not find stream by id %u", ase_rsp->id);
1566 } else {
1567 client_ep = CONTAINER_OF(stream->ep, struct bt_bap_unicast_client_ep, ep);
1568 client_ep->cp_ntf_pending = false;
1569 }
1570
1571 switch (rsp->op) {
1572 case BT_ASCS_CONFIG_OP:
1573 unicast_client_notify_ep_config(stream, ase_rsp->code, ase_rsp->reason);
1574 break;
1575 case BT_ASCS_QOS_OP:
1576 unicast_client_notify_ep_qos(stream, ase_rsp->code, ase_rsp->reason);
1577 break;
1578 case BT_ASCS_ENABLE_OP:
1579 unicast_client_notify_ep_enable(stream, ase_rsp->code, ase_rsp->reason);
1580 break;
1581 case BT_ASCS_START_OP:
1582 unicast_client_notify_ep_start(stream, ase_rsp->code, ase_rsp->reason);
1583 break;
1584 case BT_ASCS_DISABLE_OP:
1585 unicast_client_notify_ep_disable(stream, ase_rsp->code, ase_rsp->reason);
1586 break;
1587 case BT_ASCS_STOP_OP:
1588 unicast_client_notify_ep_stop(stream, ase_rsp->code, ase_rsp->reason);
1589 break;
1590 case BT_ASCS_METADATA_OP:
1591 unicast_client_notify_ep_metadata(stream, ase_rsp->code, ase_rsp->reason);
1592 break;
1593 case BT_ASCS_RELEASE_OP:
1594 /* client_ep->release_requested is set to false if handled by the
1595 * endpoint notification handler
1596 */
1597 if (client_ep != NULL && client_ep->release_requested) {
1598 /* If request was reject, do not expect endpoint notifications */
1599 if (ase_rsp->code != BT_BAP_ASCS_RSP_CODE_SUCCESS) {
1600 client_ep->cp_ntf_pending = false;
1601 client_ep->release_requested = false;
1602 }
1603
1604 unicast_client_notify_ep_released(stream, ase_rsp->code,
1605 ase_rsp->reason);
1606 }
1607 break;
1608 default:
1609 break;
1610 }
1611 }
1612
1613 return BT_GATT_ITER_CONTINUE;
1614 }
1615
unicast_client_ase_ntf_read_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * read,const void * data,uint16_t length)1616 static uint8_t unicast_client_ase_ntf_read_func(struct bt_conn *conn, uint8_t err,
1617 struct bt_gatt_read_params *read, const void *data,
1618 uint16_t length)
1619 {
1620 uint16_t handle = read->single.handle;
1621 struct net_buf_simple buf_clone;
1622 struct unicast_client *client;
1623 struct net_buf_simple *buf;
1624 struct bt_bap_ep *ep;
1625
1626 LOG_DBG("conn %p err 0x%02x len %u", conn, err, length);
1627
1628 if (err) {
1629 LOG_DBG("Failed to read ASE: %u", err);
1630
1631 return BT_GATT_ITER_STOP;
1632 }
1633
1634 LOG_DBG("handle 0x%04x", handle);
1635
1636 client = &uni_cli_insts[bt_conn_index(conn)];
1637 buf = &client->net_buf;
1638
1639 if (data != NULL) {
1640 if (net_buf_simple_tailroom(buf) < length) {
1641 LOG_DBG("Buffer full, invalid server response of size %u",
1642 length + client->net_buf.len);
1643 reset_att_buf(client);
1644 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
1645
1646 return BT_GATT_ITER_STOP;
1647 }
1648
1649 /* store data*/
1650 net_buf_simple_add_mem(buf, data, length);
1651
1652 return BT_GATT_ITER_CONTINUE;
1653 }
1654
1655 memset(read, 0, sizeof(*read));
1656
1657 if (buf->len < sizeof(struct bt_ascs_ase_status)) {
1658 LOG_DBG("Read response too small (%u)", buf->len);
1659 reset_att_buf(client);
1660 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
1661
1662 return BT_GATT_ITER_STOP;
1663 }
1664
1665 /* Clone the buffer so that we can reset it while still providing the data to the upper
1666 * layers
1667 */
1668 net_buf_simple_clone(buf, &buf_clone);
1669 reset_att_buf(client);
1670 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
1671
1672 ep = unicast_client_ep_get(conn, client->dir, handle);
1673 if (!ep) {
1674 LOG_DBG("Unknown %s ep for handle 0x%04X", bt_audio_dir_str(client->dir), handle);
1675 } else {
1676 /* Set reason in case this exits the streaming state, unless already set */
1677 if (ep->reason == BT_HCI_ERR_SUCCESS) {
1678 ep->reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN;
1679 }
1680
1681 unicast_client_ep_set_status(ep, &buf_clone);
1682 }
1683
1684 return BT_GATT_ITER_STOP;
1685 }
1686
long_ase_read(struct bt_bap_unicast_client_ep * client_ep)1687 static void long_ase_read(struct bt_bap_unicast_client_ep *client_ep)
1688 {
1689 /* Perform long read if notification is maximum size */
1690 struct bt_conn *conn = client_ep->ep.stream->conn;
1691 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
1692 struct net_buf_simple *long_read_buf = &client->net_buf;
1693 int err;
1694
1695 LOG_DBG("conn %p ep %p 0x%04X", conn, &client_ep->ep, client_ep->handle);
1696
1697 if (atomic_test_and_set_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY)) {
1698 /* If the client is busy reading or writing something else, reschedule the
1699 * long read.
1700 */
1701 struct bt_conn_info conn_info;
1702
1703 err = bt_conn_get_info(conn, &conn_info);
1704 if (err != 0) {
1705 LOG_DBG("Failed to get conn info, use default interval");
1706
1707 conn_info.le.interval = BT_GAP_INIT_CONN_INT_MIN;
1708 }
1709
1710 /* Wait a connection interval to retry */
1711 err = k_work_reschedule(&client_ep->ase_read_work,
1712 K_USEC(BT_CONN_INTERVAL_TO_US(conn_info.le.interval)));
1713 if (err < 0) {
1714 LOG_DBG("Failed to reschedule ASE long read work: %d", err);
1715 }
1716
1717 return;
1718 }
1719
1720 client->read_params.func = unicast_client_ase_ntf_read_func;
1721 client->read_params.handle_count = 1U;
1722 client->read_params.single.handle = client_ep->handle;
1723 client->read_params.single.offset = long_read_buf->len;
1724
1725 err = bt_gatt_read(conn, &client->read_params);
1726 if (err != 0) {
1727 LOG_DBG("Failed to read ASE: %d", err);
1728 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
1729 }
1730 }
1731
delayed_ase_read_handler(struct k_work * work)1732 static void delayed_ase_read_handler(struct k_work *work)
1733 {
1734 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
1735 struct bt_bap_unicast_client_ep *client_ep =
1736 CONTAINER_OF(dwork, struct bt_bap_unicast_client_ep, ase_read_work);
1737
1738 LOG_DBG("ep %p 0x%04X", &client_ep->ep, client_ep->handle);
1739
1740 /* Try reading again */
1741 long_ase_read(client_ep);
1742 }
1743
unicast_client_ep_notify(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)1744 static uint8_t unicast_client_ep_notify(struct bt_conn *conn,
1745 struct bt_gatt_subscribe_params *params, const void *data,
1746 uint16_t length)
1747 {
1748 struct net_buf_simple buf;
1749 struct bt_bap_unicast_client_ep *client_ep;
1750 uint16_t max_ntf_size;
1751 struct bt_bap_ep *ep;
1752
1753 client_ep = CONTAINER_OF(params, struct bt_bap_unicast_client_ep, subscribe);
1754 ep = &client_ep->ep;
1755
1756 LOG_DBG("conn %p ep %p len %u", conn, ep, length);
1757
1758 /* Cancel any pending long reads for the endpoint */
1759 (void)k_work_cancel_delayable(&client_ep->ase_read_work);
1760
1761 if (!data) {
1762 LOG_DBG("Unsubscribed");
1763 params->value_handle = BAP_HANDLE_UNUSED;
1764 return BT_GATT_ITER_STOP;
1765 }
1766
1767 max_ntf_size = bt_audio_get_max_ntf_size(conn);
1768
1769 if (length == max_ntf_size) {
1770 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
1771
1772 if (!atomic_test_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY)) {
1773 struct net_buf_simple *long_read_buf = &client->net_buf;
1774
1775 /* store data*/
1776 net_buf_simple_add_mem(long_read_buf, data, length);
1777 }
1778
1779 long_ase_read(client_ep);
1780
1781 return BT_GATT_ITER_CONTINUE;
1782 }
1783
1784 net_buf_simple_init_with_data(&buf, (void *)data, length);
1785
1786 if (buf.len < sizeof(struct bt_ascs_ase_status)) {
1787 LOG_ERR("Notification too small");
1788 return BT_GATT_ITER_STOP;
1789 }
1790
1791 /* Set reason in case this exits the streaming state, unless already set */
1792 if (ep->reason == BT_HCI_ERR_SUCCESS) {
1793 ep->reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN;
1794 }
1795
1796 unicast_client_ep_set_status(ep, &buf);
1797
1798 return BT_GATT_ITER_CONTINUE;
1799 }
1800
unicast_client_ep_subscribe(struct bt_conn * conn,struct bt_bap_ep * ep)1801 static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *ep)
1802 {
1803 struct bt_bap_unicast_client_ep *client_ep;
1804 int err;
1805
1806 client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
1807
1808 LOG_DBG("ep %p handle 0x%02x", ep, client_ep->handle);
1809
1810 if (client_ep->subscribe.value_handle) {
1811 return 0;
1812 }
1813
1814 client_ep->subscribe.value_handle = client_ep->handle;
1815 client_ep->subscribe.ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
1816 client_ep->subscribe.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
1817 client_ep->subscribe.disc_params = &client_ep->discover;
1818 client_ep->subscribe.notify = unicast_client_ep_notify;
1819 client_ep->subscribe.value = BT_GATT_CCC_NOTIFY;
1820 atomic_set_bit(client_ep->subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
1821
1822 err = bt_gatt_subscribe(conn, &client_ep->subscribe);
1823 if (err != 0 && err != -EALREADY) {
1824 return err;
1825 }
1826
1827 return 0;
1828 }
1829
unicast_client_cp_sub_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_subscribe_params * sub_params)1830 static void unicast_client_cp_sub_cb(struct bt_conn *conn, uint8_t err,
1831 struct bt_gatt_subscribe_params *sub_params)
1832 {
1833
1834 LOG_DBG("conn %p err %u", conn, err);
1835
1836 unicast_client_discover_complete(conn, err);
1837 }
1838
unicast_client_ep_set_cp(struct bt_conn * conn,uint16_t handle)1839 static void unicast_client_ep_set_cp(struct bt_conn *conn, uint16_t handle)
1840 {
1841 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
1842
1843 LOG_DBG("conn %p 0x%04x", conn, handle);
1844
1845 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
1846 for (size_t i = 0U; i < ARRAY_SIZE(client->snks); i++) {
1847 struct bt_bap_unicast_client_ep *client_ep = &client->snks[i];
1848
1849 if (client_ep->handle) {
1850 client_ep->cp_handle = handle;
1851 }
1852 }
1853 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
1854
1855 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
1856 for (size_t i = 0U; i < ARRAY_SIZE(client->srcs); i++) {
1857 struct bt_bap_unicast_client_ep *client_ep = &client->srcs[i];
1858
1859 if (client_ep->handle) {
1860 client_ep->cp_handle = handle;
1861 }
1862 }
1863 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
1864
1865 if (!client->cp_subscribe.value_handle) {
1866 int err;
1867
1868 client->cp_subscribe.value_handle = handle;
1869 client->cp_subscribe.ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
1870 client->cp_subscribe.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
1871 client->cp_subscribe.disc_params = &client->disc_params;
1872 client->cp_subscribe.notify = unicast_client_cp_notify;
1873 client->cp_subscribe.value = BT_GATT_CCC_NOTIFY;
1874 client->cp_subscribe.subscribe = unicast_client_cp_sub_cb;
1875 atomic_set_bit(client->cp_subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
1876
1877 err = bt_gatt_subscribe(conn, &client->cp_subscribe);
1878 if (err != 0 && err != -EALREADY) {
1879 LOG_DBG("Failed to subscribe: %d", err);
1880
1881 unicast_client_discover_complete(conn, err);
1882
1883 return;
1884 }
1885 } else { /* already subscribed */
1886 unicast_client_discover_complete(conn, 0);
1887 }
1888 }
1889
bt_bap_unicast_client_ep_create_pdu(struct bt_conn * conn,uint8_t op)1890 struct net_buf_simple *bt_bap_unicast_client_ep_create_pdu(struct bt_conn *conn, uint8_t op)
1891 {
1892 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
1893 struct bt_ascs_ase_cp *hdr;
1894
1895 if (atomic_test_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY)) {
1896 return NULL;
1897 }
1898
1899 hdr = net_buf_simple_add(&client->net_buf, sizeof(*hdr));
1900 hdr->op = op;
1901
1902 return &client->net_buf;
1903 }
1904
unicast_client_ep_config(struct bt_bap_ep * ep,struct net_buf_simple * buf,const struct bt_audio_codec_cfg * codec_cfg)1905 static int unicast_client_ep_config(struct bt_bap_ep *ep, struct net_buf_simple *buf,
1906 const struct bt_audio_codec_cfg *codec_cfg)
1907 {
1908 struct bt_ascs_config *req;
1909
1910 LOG_DBG("ep %p buf %p codec %p", ep, buf, codec_cfg);
1911
1912 if (!ep) {
1913 return -EINVAL;
1914 }
1915
1916 switch (ep->status.state) {
1917 /* Valid only if ASE_State field = 0x00 (Idle) */
1918 case BT_BAP_EP_STATE_IDLE:
1919 /* or 0x01 (Codec Configured) */
1920 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
1921 /* or 0x02 (QoS Configured) */
1922 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1923 break;
1924 default:
1925 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
1926 return -EINVAL;
1927 }
1928
1929 LOG_DBG("id 0x%02x dir %s codec 0x%02x", ep->status.id, bt_audio_dir_str(ep->dir),
1930 codec_cfg->id);
1931
1932 req = net_buf_simple_add(buf, sizeof(*req));
1933 req->ase = ep->status.id;
1934 req->latency = 0x02; /* TODO: Select target latency based on additional input? */
1935 req->phy = 0x02; /* TODO: Select target PHY based on additional input? */
1936 req->codec.id = codec_cfg->id;
1937 req->codec.cid = codec_cfg->cid;
1938 req->codec.vid = codec_cfg->vid;
1939
1940 req->cc_len = codec_cfg->data_len;
1941 net_buf_simple_add_mem(buf, codec_cfg->data, codec_cfg->data_len);
1942
1943 return 0;
1944 }
1945
bt_bap_unicast_client_ep_qos(struct bt_bap_ep * ep,struct net_buf_simple * buf,struct bt_bap_qos_cfg * qos)1946 int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *buf,
1947 struct bt_bap_qos_cfg *qos)
1948 {
1949 struct bt_ascs_qos *req;
1950 struct bt_conn_iso *conn_iso;
1951
1952 LOG_DBG("ep %p buf %p qos %p", ep, buf, qos);
1953
1954 if (!ep) {
1955 return -EINVAL;
1956 }
1957
1958 switch (ep->status.state) {
1959 /* Valid only if ASE_State field = 0x01 (Codec Configured) */
1960 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
1961 /* or 0x02 (QoS Configured) */
1962 case BT_BAP_EP_STATE_QOS_CONFIGURED:
1963 break;
1964 default:
1965 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
1966 return -EINVAL;
1967 }
1968
1969 conn_iso = &ep->iso->chan.iso->iso;
1970
1971 LOG_DBG("id 0x%02x cig 0x%02x cis 0x%02x interval %u framing 0x%02x "
1972 "phy 0x%02x sdu %u rtn %u latency %u pd %u",
1973 ep->status.id, conn_iso->cig_id, conn_iso->cis_id, qos->interval, qos->framing,
1974 qos->phy, qos->sdu, qos->rtn, qos->latency, qos->pd);
1975
1976 req = net_buf_simple_add(buf, sizeof(*req));
1977 req->ase = ep->status.id;
1978 /* TODO: don't hardcode CIG and CIS, they should come from ISO */
1979 req->cig = conn_iso->cig_id;
1980 req->cis = conn_iso->cis_id;
1981 sys_put_le24(qos->interval, req->interval);
1982 req->framing = qos->framing;
1983 req->phy = qos->phy;
1984 req->sdu = qos->sdu;
1985 req->rtn = qos->rtn;
1986 req->latency = sys_cpu_to_le16(qos->latency);
1987 sys_put_le24(qos->pd, req->pd);
1988
1989 return 0;
1990 }
1991
unicast_client_ep_enable(struct bt_bap_ep * ep,struct net_buf_simple * buf,const uint8_t meta[],size_t meta_len)1992 static int unicast_client_ep_enable(struct bt_bap_ep *ep, struct net_buf_simple *buf,
1993 const uint8_t meta[], size_t meta_len)
1994 {
1995 struct bt_ascs_metadata *req;
1996
1997 LOG_DBG("ep %p buf %p meta_len %zu", ep, buf, meta_len);
1998
1999 if (!ep) {
2000 return -EINVAL;
2001 }
2002
2003 if (ep->status.state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
2004 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
2005 return -EINVAL;
2006 }
2007
2008 LOG_DBG("id 0x%02x", ep->status.id);
2009
2010 req = net_buf_simple_add(buf, sizeof(*req));
2011 req->ase = ep->status.id;
2012
2013 req->len = meta_len;
2014 net_buf_simple_add_mem(buf, meta, meta_len);
2015
2016 return 0;
2017 }
2018
unicast_client_ep_metadata(struct bt_bap_ep * ep,struct net_buf_simple * buf,const uint8_t meta[],size_t meta_len)2019 static int unicast_client_ep_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf,
2020 const uint8_t meta[], size_t meta_len)
2021 {
2022 struct bt_ascs_metadata *req;
2023
2024 LOG_DBG("ep %p buf %p meta_len %zu", ep, buf, meta_len);
2025
2026 if (!ep) {
2027 return -EINVAL;
2028 }
2029
2030 switch (ep->status.state) {
2031 /* Valid for an ASE only if ASE_State field = 0x03 (Enabling) */
2032 case BT_BAP_EP_STATE_ENABLING:
2033 /* or 0x04 (Streaming) */
2034 case BT_BAP_EP_STATE_STREAMING:
2035 break;
2036 default:
2037 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
2038 return -EINVAL;
2039 }
2040
2041 LOG_DBG("id 0x%02x", ep->status.id);
2042
2043 req = net_buf_simple_add(buf, sizeof(*req));
2044 req->ase = ep->status.id;
2045
2046 req->len = meta_len;
2047 net_buf_simple_add_mem(buf, meta, meta_len);
2048
2049 return 0;
2050 }
2051
unicast_client_ep_start(struct bt_bap_ep * ep,struct net_buf_simple * buf)2052 static int unicast_client_ep_start(struct bt_bap_ep *ep, struct net_buf_simple *buf)
2053 {
2054 LOG_DBG("ep %p buf %p", ep, buf);
2055
2056 if (!ep) {
2057 return -EINVAL;
2058 }
2059
2060 if (ep->status.state != BT_BAP_EP_STATE_ENABLING &&
2061 ep->status.state != BT_BAP_EP_STATE_DISABLING) {
2062 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
2063 return -EINVAL;
2064 }
2065
2066 LOG_DBG("id 0x%02x", ep->status.id);
2067
2068 net_buf_simple_add_u8(buf, ep->status.id);
2069
2070 return 0;
2071 }
2072
unicast_client_ep_disable(struct bt_bap_ep * ep,struct net_buf_simple * buf)2073 static int unicast_client_ep_disable(struct bt_bap_ep *ep, struct net_buf_simple *buf)
2074 {
2075 LOG_DBG("ep %p buf %p", ep, buf);
2076
2077 if (!ep) {
2078 return -EINVAL;
2079 }
2080
2081 switch (ep->status.state) {
2082 /* Valid only if ASE_State field = 0x03 (Enabling) */
2083 case BT_BAP_EP_STATE_ENABLING:
2084 /* or 0x04 (Streaming) */
2085 case BT_BAP_EP_STATE_STREAMING:
2086 break;
2087 default:
2088 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
2089 return -EINVAL;
2090 }
2091
2092 LOG_DBG("id 0x%02x", ep->status.id);
2093
2094 net_buf_simple_add_u8(buf, ep->status.id);
2095
2096 return 0;
2097 }
2098
unicast_client_ep_stop(struct bt_bap_ep * ep,struct net_buf_simple * buf)2099 static int unicast_client_ep_stop(struct bt_bap_ep *ep, struct net_buf_simple *buf)
2100 {
2101 LOG_DBG("ep %p buf %p", ep, buf);
2102
2103 if (!ep) {
2104 return -EINVAL;
2105 }
2106
2107 /* Valid only if ASE_State field value = 0x05 (Disabling). */
2108 if (ep->status.state != BT_BAP_EP_STATE_DISABLING) {
2109 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
2110 return -EINVAL;
2111 }
2112
2113 LOG_DBG("id 0x%02x", ep->status.id);
2114
2115 net_buf_simple_add_u8(buf, ep->status.id);
2116
2117 return 0;
2118 }
2119
unicast_client_ep_release(struct bt_bap_ep * ep,struct net_buf_simple * buf)2120 static int unicast_client_ep_release(struct bt_bap_ep *ep, struct net_buf_simple *buf)
2121 {
2122 LOG_DBG("ep %p buf %p", ep, buf);
2123
2124 if (!ep) {
2125 return -EINVAL;
2126 }
2127
2128 switch (ep->status.state) {
2129 /* Valid only if ASE_State field = 0x01 (Codec Configured) */
2130 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
2131 /* or 0x02 (QoS Configured) */
2132 case BT_BAP_EP_STATE_QOS_CONFIGURED:
2133 /* or 0x03 (Enabling) */
2134 case BT_BAP_EP_STATE_ENABLING:
2135 /* or 0x04 (Streaming) */
2136 case BT_BAP_EP_STATE_STREAMING:
2137 /* or 0x05 (Disabling) */
2138 case BT_BAP_EP_STATE_DISABLING:
2139 break;
2140 default:
2141 LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state));
2142 return -EINVAL;
2143 }
2144
2145 LOG_DBG("id 0x%02x", ep->status.id);
2146
2147 net_buf_simple_add_u8(buf, ep->status.id);
2148
2149 return 0;
2150 }
2151
gatt_write_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)2152 static void gatt_write_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params)
2153 {
2154 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
2155
2156 LOG_DBG("conn %p err %u", conn, err);
2157
2158 memset(params, 0, sizeof(*params));
2159 reset_att_buf(client);
2160 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
2161
2162 /* TBD: Should we do anything in case of error here? */
2163 }
2164
bt_bap_unicast_client_ep_send(struct bt_conn * conn,struct bt_bap_ep * ep,struct net_buf_simple * buf)2165 int bt_bap_unicast_client_ep_send(struct bt_conn *conn, struct bt_bap_ep *ep,
2166 struct net_buf_simple *buf)
2167 {
2168 const uint16_t max_write_size = bt_audio_get_max_ntf_size(conn);
2169 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
2170 struct bt_bap_unicast_client_ep *client_ep =
2171 CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
2172 int err;
2173
2174 LOG_DBG("conn %p ep %p buf %p len %u", conn, ep, buf, buf->len);
2175
2176 if (buf->len > max_write_size) {
2177 if (atomic_test_and_set_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY)) {
2178 LOG_DBG("Client connection is busy");
2179 return -EBUSY;
2180 }
2181
2182 client->write_params.func = gatt_write_cb;
2183 client->write_params.handle = client_ep->cp_handle;
2184 client->write_params.offset = 0U;
2185 client->write_params.data = buf->data;
2186 client->write_params.length = buf->len;
2187 #if defined(CONFIG_BT_EATT)
2188 client->write_params.chan_opt = BT_ATT_CHAN_OPT_NONE;
2189 #endif /* CONFIG_BT_EATT */
2190
2191 err = bt_gatt_write(conn, &client->write_params);
2192 if (err != 0) {
2193 LOG_DBG("bt_gatt_write failed: %d", err);
2194 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
2195 }
2196 } else {
2197 err = bt_gatt_write_without_response(conn, client_ep->cp_handle, buf->data,
2198 buf->len, false);
2199 if (err != 0) {
2200 LOG_DBG("bt_gatt_write_without_response failed: %d", err);
2201 }
2202
2203 /* No callback for writing without response, so reset the buffer here */
2204 reset_att_buf(client);
2205 }
2206
2207 if (err == 0) {
2208 client_ep->cp_ntf_pending = true;
2209 }
2210
2211 return err;
2212 }
2213
unicast_client_reset(struct bt_bap_ep * ep,uint8_t reason)2214 static void unicast_client_reset(struct bt_bap_ep *ep, uint8_t reason)
2215 {
2216 struct bt_bap_unicast_client_ep *client_ep =
2217 CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
2218
2219 LOG_DBG("ep %p", ep);
2220 ep->reason = reason;
2221
2222 /* Pretend we received an idle state notification from the server to trigger all cleanup */
2223 unicast_client_ep_set_local_idle_state(ep);
2224
2225 if (ep->iso != NULL && ep->iso->chan.state == BT_ISO_STATE_DISCONNECTING) {
2226 /* Wait for ISO disconnected event */
2227 return;
2228 }
2229
2230 (void)k_work_cancel_delayable(&client_ep->ase_read_work);
2231 (void)memset(ep, 0, sizeof(*ep));
2232
2233 client_ep->cp_handle = BAP_HANDLE_UNUSED;
2234 client_ep->handle = BAP_HANDLE_UNUSED;
2235 (void)memset(&client_ep->discover, 0, sizeof(client_ep->discover));
2236 client_ep->release_requested = false;
2237 client_ep->cp_ntf_pending = false;
2238 /* Need to keep the subscribe params intact for the callback */
2239 }
2240
unicast_client_ep_reset(struct bt_conn * conn,uint8_t reason)2241 static void unicast_client_ep_reset(struct bt_conn *conn, uint8_t reason)
2242 {
2243 struct unicast_client *client;
2244 uint8_t index;
2245
2246 LOG_DBG("conn %p", conn);
2247
2248 index = bt_conn_index(conn);
2249
2250 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
2251 for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts[index].snks); i++) {
2252 struct bt_bap_ep *ep = &uni_cli_insts[index].snks[i].ep;
2253
2254 unicast_client_reset(ep, reason);
2255 }
2256 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
2257
2258 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
2259 for (size_t i = 0U; i < ARRAY_SIZE(uni_cli_insts[index].srcs); i++) {
2260 struct bt_bap_ep *ep = &uni_cli_insts[index].srcs[i].ep;
2261
2262 unicast_client_reset(ep, reason);
2263 }
2264 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
2265
2266 client = &uni_cli_insts[index];
2267 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
2268 client->dir = 0U;
2269 reset_att_buf(client);
2270 }
2271
bt_bap_qos_cfg_to_cig_param(struct bt_iso_cig_param * cig_param,const struct bt_bap_unicast_group * group)2272 static void bt_bap_qos_cfg_to_cig_param(struct bt_iso_cig_param *cig_param,
2273 const struct bt_bap_unicast_group *group)
2274 {
2275 cig_param->framing = group->cig_param.framing;
2276 cig_param->c_to_p_interval = group->cig_param.c_to_p_interval;
2277 cig_param->p_to_c_interval = group->cig_param.p_to_c_interval;
2278 cig_param->c_to_p_latency = group->cig_param.c_to_p_latency;
2279 cig_param->p_to_c_latency = group->cig_param.p_to_c_latency;
2280 cig_param->packing = group->cig_param.packing;
2281 cig_param->sca = BT_GAP_SCA_UNKNOWN;
2282
2283 IF_ENABLED(CONFIG_BT_ISO_TEST_PARAMS, ({
2284 cig_param->c_to_p_ft = group->cig_param.c_to_p_ft;
2285 cig_param->p_to_c_ft = group->cig_param.p_to_c_ft;
2286 cig_param->iso_interval = group->cig_param.iso_interval;
2287 }));
2288
2289 /* In the case that we only setup a single direction, we still need
2290 * (as per section 7.8.97 LE Set CIG Parameters command) to set the interval and latency on
2291 * both sides. The value shall be ignored, but the value may not always be ignored correctly
2292 * by all controllers, so we always set it here.
2293 * If it is at this point unset, then we set the opposing direction to the same value.
2294 */
2295 if (cig_param->c_to_p_interval == 0U) {
2296 cig_param->c_to_p_interval = cig_param->p_to_c_interval;
2297 } else if (cig_param->p_to_c_interval == 0U) {
2298 cig_param->p_to_c_interval = cig_param->c_to_p_interval;
2299 }
2300
2301 if (cig_param->c_to_p_latency == 0U) {
2302 cig_param->c_to_p_latency = cig_param->p_to_c_latency;
2303 } else if (cig_param->p_to_c_latency == 0U) {
2304 cig_param->p_to_c_latency = cig_param->c_to_p_latency;
2305 }
2306 }
2307
unicast_group_get_cis_count(const struct bt_bap_unicast_group * unicast_group)2308 static uint8_t unicast_group_get_cis_count(const struct bt_bap_unicast_group *unicast_group)
2309 {
2310 uint8_t cis_count = 0U;
2311
2312 for (size_t i = 0U; i < ARRAY_SIZE(unicast_group->cis); i++) {
2313 if (unicast_group->cis[i] == NULL) {
2314 /* A NULL CIS acts as a NULL terminator */
2315 break;
2316 }
2317
2318 cis_count++;
2319 }
2320
2321 return cis_count;
2322 }
2323
bt_audio_cig_create(struct bt_bap_unicast_group * group)2324 static int bt_audio_cig_create(struct bt_bap_unicast_group *group)
2325 {
2326 struct bt_iso_cig_param param = {0};
2327 int err;
2328
2329 LOG_DBG("group %p", group);
2330
2331 param.num_cis = unicast_group_get_cis_count(group);
2332 param.cis_channels = group->cis;
2333 bt_bap_qos_cfg_to_cig_param(¶m, group);
2334
2335 err = bt_iso_cig_create(¶m, &group->cig);
2336 if (err != 0) {
2337 LOG_ERR("bt_iso_cig_create failed: %d", err);
2338 return err;
2339 }
2340
2341 return 0;
2342 }
2343
bt_audio_cig_reconfigure(struct bt_bap_unicast_group * group)2344 static int bt_audio_cig_reconfigure(struct bt_bap_unicast_group *group)
2345 {
2346 struct bt_iso_cig_param param;
2347 uint8_t cis_count;
2348 int err;
2349
2350 LOG_DBG("group %p ", group);
2351
2352 cis_count = 0U;
2353 for (size_t i = 0U; i < ARRAY_SIZE(group->cis); i++) {
2354 if (group->cis[i] == NULL) {
2355 /* A NULL CIS acts as a NULL terminator */
2356 break;
2357 }
2358
2359 cis_count++;
2360 }
2361
2362 param.num_cis = cis_count;
2363 param.cis_channels = group->cis;
2364 bt_bap_qos_cfg_to_cig_param(¶m, group);
2365
2366 err = bt_iso_cig_reconfigure(group->cig, ¶m);
2367 if (err != 0) {
2368 LOG_ERR("bt_iso_cig_create failed: %d", err);
2369 return err;
2370 }
2371
2372 return 0;
2373 }
2374
audio_stream_qos_cleanup(const struct bt_conn * conn,struct bt_bap_unicast_group * group)2375 static void audio_stream_qos_cleanup(const struct bt_conn *conn,
2376 struct bt_bap_unicast_group *group)
2377 {
2378 struct bt_bap_stream *stream;
2379
2380 SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) {
2381 if (stream->conn != conn) {
2382 /* Channel not part of this ACL, skip */
2383 continue;
2384 }
2385
2386 if (stream->ep == NULL) {
2387 /* Stream did not have a endpoint configured yet */
2388 continue;
2389 }
2390
2391 bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep);
2392 }
2393 }
2394
unicast_client_cig_terminate(struct bt_bap_unicast_group * group)2395 static int unicast_client_cig_terminate(struct bt_bap_unicast_group *group)
2396 {
2397 LOG_DBG("group %p", group);
2398
2399 return bt_iso_cig_terminate(group->cig);
2400 }
2401
unicast_group_add_iso(struct bt_bap_unicast_group * group,struct bt_bap_iso * iso)2402 static int unicast_group_add_iso(struct bt_bap_unicast_group *group, struct bt_bap_iso *iso)
2403 {
2404 struct bt_iso_chan **chan_slot = NULL;
2405
2406 __ASSERT_NO_MSG(group != NULL);
2407 __ASSERT_NO_MSG(iso != NULL);
2408
2409 /* Append iso channel to the group->cis array */
2410 for (size_t i = 0U; i < ARRAY_SIZE(group->cis); i++) {
2411 /* Return if already there */
2412 if (group->cis[i] == &iso->chan) {
2413 return 0;
2414 }
2415
2416 if (chan_slot == NULL && group->cis[i] == NULL) {
2417 chan_slot = &group->cis[i];
2418 }
2419 }
2420
2421 if (chan_slot == NULL) {
2422 return -ENOMEM;
2423 }
2424
2425 *chan_slot = &iso->chan;
2426
2427 return 0;
2428 }
2429
unicast_group_del_iso(struct bt_bap_unicast_group * group,struct bt_bap_iso * iso)2430 static void unicast_group_del_iso(struct bt_bap_unicast_group *group, struct bt_bap_iso *iso)
2431 {
2432 struct bt_bap_stream *stream;
2433
2434 __ASSERT_NO_MSG(group != NULL);
2435 __ASSERT_NO_MSG(iso != NULL);
2436
2437 SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) {
2438 if (stream->ep->iso == iso) {
2439 /* still in use by some other stream */
2440 return;
2441 }
2442 }
2443
2444 for (size_t i = 0U; i < ARRAY_SIZE(group->cis); i++) {
2445 if (group->cis[i] == &iso->chan) {
2446 group->cis[i] = NULL;
2447 return;
2448 }
2449 }
2450 }
2451
unicast_client_qos_cfg_to_iso_qos(struct bt_bap_iso * iso,const struct bt_bap_qos_cfg * qos,enum bt_audio_dir dir)2452 static void unicast_client_qos_cfg_to_iso_qos(struct bt_bap_iso *iso,
2453 const struct bt_bap_qos_cfg *qos,
2454 enum bt_audio_dir dir)
2455 {
2456 struct bt_iso_chan_io_qos *io_qos;
2457 struct bt_iso_chan_io_qos *other_io_qos;
2458
2459 if (dir == BT_AUDIO_DIR_SINK) {
2460 /* If the endpoint is a sink, then we need to
2461 * configure our TX parameters
2462 */
2463 io_qos = iso->chan.qos->tx;
2464 if (bt_bap_iso_get_ep(true, iso, BT_AUDIO_DIR_SOURCE) == NULL) {
2465 other_io_qos = iso->chan.qos->rx;
2466 } else {
2467 other_io_qos = NULL;
2468 }
2469 } else {
2470 /* If the endpoint is a source, then we need to
2471 * configure our RX parameters
2472 */
2473 io_qos = iso->chan.qos->rx;
2474 if (bt_bap_iso_get_ep(true, iso, BT_AUDIO_DIR_SINK) == NULL) {
2475 other_io_qos = iso->chan.qos->tx;
2476 } else {
2477 other_io_qos = NULL;
2478 }
2479 }
2480
2481 bt_bap_qos_cfg_to_iso_qos(io_qos, qos);
2482 #if defined(CONFIG_BT_ISO_TEST_PARAMS)
2483 iso->chan.qos->num_subevents = qos->num_subevents;
2484 #endif /* CONFIG_BT_ISO_TEST_PARAMS */
2485
2486 if (other_io_qos != NULL) {
2487 /* If the opposing ASE of the CIS is not yet configured, we
2488 * still need to set the PHY value when creating the CIG.
2489 */
2490 other_io_qos->phy = io_qos->phy;
2491 }
2492 }
2493
unicast_group_set_iso_stream_param(struct bt_bap_unicast_group * group,struct bt_bap_iso * iso,struct bt_bap_qos_cfg * qos,enum bt_audio_dir dir)2494 static void unicast_group_set_iso_stream_param(struct bt_bap_unicast_group *group,
2495 struct bt_bap_iso *iso,
2496 struct bt_bap_qos_cfg *qos,
2497 enum bt_audio_dir dir)
2498 {
2499 /* Store the stream Codec QoS in the bap_iso */
2500 unicast_client_qos_cfg_to_iso_qos(iso, qos, dir);
2501
2502 /* Store the group Codec QoS in the group - This assume thats the parameters have been
2503 * verified first
2504 */
2505 group->cig_param.framing = qos->framing;
2506 if (dir == BT_AUDIO_DIR_SOURCE) {
2507 group->cig_param.p_to_c_interval = qos->interval;
2508 group->cig_param.p_to_c_latency = qos->latency;
2509 } else {
2510 group->cig_param.c_to_p_interval = qos->interval;
2511 group->cig_param.c_to_p_latency = qos->latency;
2512 }
2513 }
2514
unicast_group_add_stream(struct bt_bap_unicast_group * group,struct bt_bap_unicast_group_stream_param * param,struct bt_bap_iso * iso,enum bt_audio_dir dir)2515 static void unicast_group_add_stream(struct bt_bap_unicast_group *group,
2516 struct bt_bap_unicast_group_stream_param *param,
2517 struct bt_bap_iso *iso, enum bt_audio_dir dir)
2518 {
2519 struct bt_bap_stream *stream = param->stream;
2520 struct bt_bap_qos_cfg *qos = param->qos;
2521
2522 LOG_DBG("group %p stream %p qos %p iso %p dir %u", group, stream, qos, iso, dir);
2523
2524 __ASSERT_NO_MSG(stream->ep == NULL || (stream->ep != NULL && stream->ep->iso == NULL));
2525
2526 stream->qos = qos;
2527 stream->group = group;
2528
2529 /* iso initialized already */
2530 bt_bap_iso_bind_stream(iso, stream, dir);
2531 if (stream->ep != NULL) {
2532 bt_bap_iso_bind_ep(iso, stream->ep);
2533 }
2534
2535 unicast_group_set_iso_stream_param(group, iso, qos, dir);
2536
2537 sys_slist_append(&group->streams, &stream->_node);
2538 }
2539
unicast_group_add_stream_pair(struct bt_bap_unicast_group * group,struct bt_bap_unicast_group_stream_pair_param * param)2540 static int unicast_group_add_stream_pair(struct bt_bap_unicast_group *group,
2541 struct bt_bap_unicast_group_stream_pair_param *param)
2542 {
2543 struct bt_bap_iso *iso;
2544 int err;
2545
2546 __ASSERT_NO_MSG(group != NULL);
2547 __ASSERT_NO_MSG(param != NULL);
2548 __ASSERT_NO_MSG(param->rx_param != NULL || param->tx_param != NULL);
2549
2550 iso = bt_bap_unicast_client_new_audio_iso();
2551 if (iso == NULL) {
2552 return -ENOMEM;
2553 }
2554
2555 err = unicast_group_add_iso(group, iso);
2556 if (err < 0) {
2557 bt_bap_iso_unref(iso);
2558 return err;
2559 }
2560
2561 if (param->rx_param != NULL) {
2562 unicast_group_add_stream(group, param->rx_param, iso, BT_AUDIO_DIR_SOURCE);
2563 }
2564
2565 if (param->tx_param != NULL) {
2566 unicast_group_add_stream(group, param->tx_param, iso, BT_AUDIO_DIR_SINK);
2567 }
2568
2569 bt_bap_iso_unref(iso);
2570
2571 return 0;
2572 }
2573
unicast_group_del_stream(struct bt_bap_unicast_group * group,struct bt_bap_stream * stream,enum bt_audio_dir dir)2574 static void unicast_group_del_stream(struct bt_bap_unicast_group *group,
2575 struct bt_bap_stream *stream, enum bt_audio_dir dir)
2576 {
2577 __ASSERT_NO_MSG(group != NULL);
2578 __ASSERT_NO_MSG(stream != NULL);
2579
2580 if (sys_slist_find_and_remove(&group->streams, &stream->_node)) {
2581 struct bt_bap_ep *ep = stream->ep;
2582
2583 if (stream->bap_iso != NULL) {
2584 bt_bap_iso_unbind_stream(stream->bap_iso, stream, dir);
2585 }
2586
2587 if (ep != NULL && ep->iso != NULL) {
2588 unicast_group_del_iso(group, ep->iso);
2589
2590 bt_bap_iso_unbind_ep(ep->iso, ep);
2591 }
2592
2593 stream->group = NULL;
2594 }
2595 }
2596
unicast_group_del_stream_pair(struct bt_bap_unicast_group * group,struct bt_bap_unicast_group_stream_pair_param * param)2597 static void unicast_group_del_stream_pair(struct bt_bap_unicast_group *group,
2598 struct bt_bap_unicast_group_stream_pair_param *param)
2599 {
2600 __ASSERT_NO_MSG(group != NULL);
2601 __ASSERT_NO_MSG(param != NULL);
2602 __ASSERT_NO_MSG(param->rx_param != NULL || param->tx_param != NULL);
2603
2604 if (param->rx_param != NULL) {
2605 __ASSERT_NO_MSG(param->rx_param->stream);
2606 unicast_group_del_stream(group, param->rx_param->stream, BT_AUDIO_DIR_SOURCE);
2607 }
2608
2609 if (param->tx_param != NULL) {
2610 __ASSERT_NO_MSG(param->tx_param->stream);
2611 unicast_group_del_stream(group, param->tx_param->stream, BT_AUDIO_DIR_SINK);
2612 }
2613 }
2614
unicast_group_alloc(void)2615 static struct bt_bap_unicast_group *unicast_group_alloc(void)
2616 {
2617 struct bt_bap_unicast_group *group = NULL;
2618
2619 for (size_t i = 0U; i < ARRAY_SIZE(unicast_groups); i++) {
2620 if (!unicast_groups[i].allocated) {
2621 group = &unicast_groups[i];
2622
2623 (void)memset(group, 0, sizeof(*group));
2624
2625 group->allocated = true;
2626 group->index = i;
2627
2628 break;
2629 }
2630 }
2631
2632 return group;
2633 }
2634
unicast_group_free(struct bt_bap_unicast_group * group)2635 static void unicast_group_free(struct bt_bap_unicast_group *group)
2636 {
2637 struct bt_bap_stream *stream, *next;
2638
2639 __ASSERT_NO_MSG(group != NULL);
2640
2641 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&group->streams, stream, next, _node) {
2642 struct bt_bap_iso *bap_iso = stream->bap_iso;
2643 struct bt_bap_ep *ep = stream->ep;
2644
2645 stream->group = NULL;
2646 if (bap_iso != NULL) {
2647 if (bap_iso->rx.stream == stream) {
2648 bt_bap_iso_unbind_stream(stream->bap_iso, stream,
2649 BT_AUDIO_DIR_SOURCE);
2650 } else if (bap_iso->tx.stream == stream) {
2651 bt_bap_iso_unbind_stream(stream->bap_iso, stream,
2652 BT_AUDIO_DIR_SINK);
2653 } else {
2654 __ASSERT_PRINT("stream %p has invalid bap_iso %p", stream, bap_iso);
2655 }
2656 }
2657
2658 if (ep != NULL && ep->iso != NULL) {
2659 bt_bap_iso_unbind_ep(ep->iso, ep);
2660 }
2661
2662 sys_slist_remove(&group->streams, NULL, &stream->_node);
2663 }
2664
2665 group->allocated = false;
2666 }
2667
stream_param_check(const struct bt_bap_unicast_group_stream_param * param)2668 static int stream_param_check(const struct bt_bap_unicast_group_stream_param *param)
2669 {
2670 CHECKIF(param->stream == NULL)
2671 {
2672 LOG_DBG("param->stream is NULL");
2673 return -EINVAL;
2674 }
2675
2676 CHECKIF(param->qos == NULL)
2677 {
2678 LOG_DBG("param->qos is NULL");
2679 return -EINVAL;
2680 }
2681
2682 if (param->stream != NULL && param->stream->group != NULL) {
2683 LOG_DBG("stream %p already part of group %p", param->stream, param->stream->group);
2684 return -EALREADY;
2685 }
2686
2687 CHECKIF(bt_audio_verify_qos(param->qos) != BT_BAP_ASCS_REASON_NONE)
2688 {
2689 LOG_DBG("Invalid QoS");
2690 return -EINVAL;
2691 }
2692
2693 return 0;
2694 }
2695
stream_pair_param_check(const struct bt_bap_unicast_group_stream_pair_param * param)2696 static int stream_pair_param_check(const struct bt_bap_unicast_group_stream_pair_param *param)
2697 {
2698 int err;
2699
2700 CHECKIF(param->rx_param == NULL && param->tx_param == NULL)
2701 {
2702 LOG_DBG("Invalid stream parameters");
2703 return -EINVAL;
2704 }
2705
2706 if (param->rx_param != NULL) {
2707 err = stream_param_check(param->rx_param);
2708 if (err < 0) {
2709 return err;
2710 }
2711 }
2712
2713 if (param->tx_param != NULL) {
2714 err = stream_param_check(param->tx_param);
2715 if (err < 0) {
2716 return err;
2717 }
2718 }
2719
2720 return 0;
2721 }
2722
2723 /** Validates that the stream parameter does not contain invalid values */
valid_unicast_group_stream_param(const struct bt_bap_unicast_group * unicast_group,const struct bt_bap_unicast_group_stream_param * param,struct bt_bap_unicast_group_cig_param * cig_param,enum bt_audio_dir dir)2724 static bool valid_unicast_group_stream_param(const struct bt_bap_unicast_group *unicast_group,
2725 const struct bt_bap_unicast_group_stream_param *param,
2726 struct bt_bap_unicast_group_cig_param *cig_param,
2727 enum bt_audio_dir dir)
2728 {
2729 const struct bt_bap_qos_cfg *qos;
2730
2731 CHECKIF(param->stream == NULL) {
2732 LOG_DBG("param->stream is NULL");
2733 return -EINVAL;
2734 }
2735
2736 CHECKIF(param->qos == NULL) {
2737 LOG_DBG("param->qos is NULL");
2738 return -EINVAL;
2739 }
2740
2741 if (param->stream != NULL && param->stream->group != NULL) {
2742 if (unicast_group != NULL && param->stream->group != unicast_group) {
2743 LOG_DBG("stream %p not part of group %p (%p)", param->stream, unicast_group,
2744 param->stream->group);
2745 } else {
2746 LOG_DBG("stream %p already part of group %p", param->stream,
2747 param->stream->group);
2748 }
2749 return -EALREADY;
2750 }
2751
2752 CHECKIF(bt_audio_verify_qos(param->qos) != BT_BAP_ASCS_REASON_NONE) {
2753 LOG_DBG("Invalid QoS");
2754 return -EINVAL;
2755 }
2756
2757 qos = param->qos;
2758
2759 /* If unset we set the interval else we verify that all streams use the same interval and
2760 * latency in the same direction, as that is required when creating a CIG
2761 */
2762 if (dir == BT_AUDIO_DIR_SINK) {
2763 if (cig_param->c_to_p_interval == 0) {
2764 cig_param->c_to_p_interval = qos->interval;
2765 } else if (cig_param->c_to_p_interval != qos->interval) {
2766 return false;
2767 }
2768
2769 if (cig_param->c_to_p_latency == 0) {
2770 cig_param->c_to_p_latency = qos->latency;
2771 } else if (cig_param->c_to_p_latency != qos->latency) {
2772 return false;
2773 }
2774 } else {
2775 if (cig_param->p_to_c_interval == 0) {
2776 cig_param->p_to_c_interval = qos->interval;
2777 } else if (cig_param->p_to_c_interval != qos->interval) {
2778 return false;
2779 }
2780
2781 if (cig_param->p_to_c_latency == 0) {
2782 cig_param->p_to_c_latency = qos->latency;
2783 } else if (cig_param->p_to_c_latency != qos->latency) {
2784 return false;
2785 }
2786 }
2787
2788 if (cig_param->framing == 0) {
2789 if (qos->framing == BT_BAP_QOS_CFG_FRAMING_UNFRAMED) {
2790 cig_param->framing = BT_ISO_FRAMING_UNFRAMED;
2791 } else if (qos->framing == BT_BAP_QOS_CFG_FRAMING_FRAMED) {
2792 cig_param->framing = BT_ISO_FRAMING_FRAMED;
2793 }
2794 } else if ((qos->framing == BT_BAP_QOS_CFG_FRAMING_UNFRAMED &&
2795 cig_param->framing != BT_ISO_FRAMING_UNFRAMED) ||
2796 (qos->framing == BT_BAP_QOS_CFG_FRAMING_FRAMED &&
2797 cig_param->framing != BT_ISO_FRAMING_FRAMED)) {
2798 return false;
2799 }
2800
2801 return true;
2802 }
2803
2804 static bool
valid_group_stream_pair_param(const struct bt_bap_unicast_group * unicast_group,const struct bt_bap_unicast_group_stream_pair_param * pair_param)2805 valid_group_stream_pair_param(const struct bt_bap_unicast_group *unicast_group,
2806 const struct bt_bap_unicast_group_stream_pair_param *pair_param)
2807 {
2808 struct bt_bap_unicast_group_cig_param cig_param = {0};
2809
2810 CHECKIF(pair_param == NULL) {
2811 LOG_DBG("pair_param is NULL");
2812 return false;
2813 }
2814
2815 if (pair_param->rx_param != NULL) {
2816 if (!valid_unicast_group_stream_param(unicast_group, pair_param->rx_param,
2817 &cig_param, BT_AUDIO_DIR_SOURCE)) {
2818 return false;
2819 }
2820 }
2821
2822 if (pair_param->tx_param != NULL) {
2823 if (!valid_unicast_group_stream_param(unicast_group, pair_param->tx_param,
2824 &cig_param, BT_AUDIO_DIR_SINK)) {
2825 return false;
2826 }
2827 }
2828
2829 return true;
2830 }
2831
valid_unicast_group_param(struct bt_bap_unicast_group * unicast_group,const struct bt_bap_unicast_group_param * param)2832 static bool valid_unicast_group_param(struct bt_bap_unicast_group *unicast_group,
2833 const struct bt_bap_unicast_group_param *param)
2834 {
2835 CHECKIF(param == NULL) {
2836 LOG_DBG("streams is NULL");
2837 return false;
2838 }
2839
2840 CHECKIF(param->params_count > UNICAST_GROUP_STREAM_CNT) {
2841 LOG_DBG("Too many streams provided: %u/%u", param->params_count,
2842 UNICAST_GROUP_STREAM_CNT);
2843 return false;
2844 }
2845
2846 if (unicast_group != NULL) {
2847 const size_t group_cis_cnt = unicast_group_get_cis_count(unicast_group);
2848
2849 if (param->params_count != group_cis_cnt) {
2850 LOG_DBG("Mismatch between group CIS count (%zu) and params_count (%zu)",
2851 group_cis_cnt, param->params_count);
2852
2853 return false;
2854 }
2855 }
2856
2857 for (size_t i = 0U; i < param->params_count; i++) {
2858 if (!valid_group_stream_pair_param(unicast_group, ¶m->params[i])) {
2859 return false;
2860 }
2861 }
2862
2863 return true;
2864 }
2865
bt_bap_unicast_group_create(struct bt_bap_unicast_group_param * param,struct bt_bap_unicast_group ** out_unicast_group)2866 int bt_bap_unicast_group_create(struct bt_bap_unicast_group_param *param,
2867 struct bt_bap_unicast_group **out_unicast_group)
2868 {
2869 struct bt_bap_unicast_group *unicast_group;
2870 int err;
2871
2872 CHECKIF(out_unicast_group == NULL)
2873 {
2874 LOG_DBG("out_unicast_group is NULL");
2875 return -EINVAL;
2876 }
2877 /* Set out_unicast_group to NULL until the source has actually been created */
2878 *out_unicast_group = NULL;
2879
2880 unicast_group = unicast_group_alloc();
2881 if (unicast_group == NULL) {
2882 LOG_DBG("Could not allocate any more unicast groups");
2883 return -ENOMEM;
2884 }
2885
2886 if (!valid_unicast_group_param(NULL, param)) {
2887 unicast_group_free(unicast_group);
2888
2889 return -EINVAL;
2890 }
2891
2892 for (size_t i = 0U; i < param->params_count; i++) {
2893 struct bt_bap_unicast_group_stream_pair_param *stream_param;
2894
2895 stream_param = ¶m->params[i];
2896
2897 unicast_group->cig_param.packing = param->packing;
2898 IF_ENABLED(CONFIG_BT_ISO_TEST_PARAMS, ({
2899 unicast_group->cig_param.c_to_p_ft = param->c_to_p_ft;
2900 unicast_group->cig_param.p_to_c_ft = param->p_to_c_ft;
2901 unicast_group->cig_param.iso_interval = param->iso_interval;
2902 }));
2903
2904 err = unicast_group_add_stream_pair(unicast_group, stream_param);
2905 if (err < 0) {
2906 LOG_DBG("unicast_group_add_stream failed: %d", err);
2907 unicast_group_free(unicast_group);
2908
2909 return err;
2910 }
2911 }
2912
2913 err = bt_audio_cig_create(unicast_group);
2914 if (err != 0) {
2915 LOG_DBG("bt_audio_cig_create failed: %d", err);
2916 unicast_group_free(unicast_group);
2917
2918 return err;
2919 }
2920
2921 *out_unicast_group = unicast_group;
2922
2923 return 0;
2924 }
2925
bt_bap_unicast_group_reconfig(struct bt_bap_unicast_group * unicast_group,const struct bt_bap_unicast_group_param * param)2926 int bt_bap_unicast_group_reconfig(struct bt_bap_unicast_group *unicast_group,
2927 const struct bt_bap_unicast_group_param *param)
2928 {
2929 struct bt_iso_chan_io_qos rx_io_qos_backup[UNICAST_GROUP_STREAM_CNT];
2930 struct bt_iso_chan_io_qos tx_io_qos_backup[UNICAST_GROUP_STREAM_CNT];
2931 struct bt_bap_unicast_group_cig_param cig_param_backup;
2932 struct bt_bap_stream *tmp_stream;
2933 size_t idx;
2934 int err;
2935
2936 IF_ENABLED(CONFIG_BT_ISO_TEST_PARAMS,
2937 (uint8_t num_subevents_backup[UNICAST_GROUP_STREAM_CNT]));
2938
2939 CHECKIF(unicast_group == NULL) {
2940 LOG_DBG("unicast_group is NULL");
2941 return -EINVAL;
2942 }
2943
2944 if (unicast_group->has_been_connected) {
2945 LOG_DBG("Cannot modify a unicast_group where a CIS has been connected");
2946 return -EINVAL;
2947 }
2948
2949 if (!valid_unicast_group_param(unicast_group, param)) {
2950 return -EINVAL;
2951 }
2952
2953 /* Make backups of the values in case that the reconfigure request is rejected by e.g. the
2954 * controller
2955 */
2956 idx = 0U;
2957 SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, tmp_stream, _node) {
2958 memcpy(&rx_io_qos_backup[idx], tmp_stream->bap_iso->chan.qos->rx,
2959 sizeof(rx_io_qos_backup[idx]));
2960 memcpy(&tx_io_qos_backup[idx], tmp_stream->bap_iso->chan.qos->tx,
2961 sizeof(tx_io_qos_backup[idx]));
2962 IF_ENABLED(
2963 CONFIG_BT_ISO_TEST_PARAMS,
2964 (num_subevents_backup[idx] = tmp_stream->bap_iso->chan.qos->num_subevents));
2965 idx++;
2966 }
2967 memcpy(&cig_param_backup, &unicast_group->cig_param, sizeof(cig_param_backup));
2968
2969 /* Update the stream and group parameters */
2970 for (size_t i = 0U; i < param->params_count; i++) {
2971 struct bt_bap_unicast_group_stream_pair_param *stream_param = ¶m->params[i];
2972 struct bt_bap_unicast_group_stream_param *rx_param = stream_param->rx_param;
2973 struct bt_bap_unicast_group_stream_param *tx_param = stream_param->tx_param;
2974
2975 if (rx_param != NULL) {
2976 unicast_group_set_iso_stream_param(unicast_group, rx_param->stream->bap_iso,
2977 rx_param->qos, BT_AUDIO_DIR_SOURCE);
2978 }
2979
2980 if (tx_param != NULL) {
2981 unicast_group_set_iso_stream_param(unicast_group, tx_param->stream->bap_iso,
2982 tx_param->qos, BT_AUDIO_DIR_SOURCE);
2983 }
2984 }
2985
2986 /* Reconfigure the CIG based on the above new values */
2987 err = bt_audio_cig_reconfigure(unicast_group);
2988 if (err != 0) {
2989 LOG_DBG("bt_audio_cig_reconfigure failed: %d", err);
2990
2991 /* Revert any changes above */
2992 memcpy(&unicast_group->cig_param, &cig_param_backup, sizeof(cig_param_backup));
2993 idx = 0U;
2994 SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, tmp_stream, _node) {
2995 memcpy(tmp_stream->bap_iso->chan.qos->rx, &rx_io_qos_backup[idx],
2996 sizeof(rx_io_qos_backup[idx]));
2997 memcpy(tmp_stream->bap_iso->chan.qos->tx, &tx_io_qos_backup[idx],
2998 sizeof(tx_io_qos_backup[idx]));
2999 IF_ENABLED(CONFIG_BT_ISO_TEST_PARAMS,
3000 (tmp_stream->bap_iso->chan.qos->num_subevents =
3001 num_subevents_backup[idx]));
3002 idx++;
3003 }
3004
3005 return err;
3006 }
3007
3008 return 0;
3009 }
3010
bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group * unicast_group,struct bt_bap_unicast_group_stream_pair_param params[],size_t num_param)3011 int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group,
3012 struct bt_bap_unicast_group_stream_pair_param params[],
3013 size_t num_param)
3014 {
3015 struct bt_bap_stream *tmp_stream;
3016 size_t total_stream_cnt;
3017 struct bt_iso_cig *cig;
3018 size_t num_added;
3019 int err;
3020
3021 CHECKIF(unicast_group == NULL)
3022 {
3023 LOG_DBG("unicast_group is NULL");
3024 return -EINVAL;
3025 }
3026
3027 if (unicast_group->has_been_connected) {
3028 LOG_DBG("Cannot modify a unicast_group where a CIS has been connected");
3029 return -EINVAL;
3030 }
3031
3032 CHECKIF(params == NULL)
3033 {
3034 LOG_DBG("params is NULL");
3035 return -EINVAL;
3036 }
3037
3038 CHECKIF(num_param == 0)
3039 {
3040 LOG_DBG("num_param is 0");
3041 return -EINVAL;
3042 }
3043
3044 total_stream_cnt = num_param;
3045 SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, tmp_stream, _node) {
3046 total_stream_cnt++;
3047 }
3048
3049 if (total_stream_cnt > UNICAST_GROUP_STREAM_CNT) {
3050 LOG_DBG("Too many streams provided: %u/%u", total_stream_cnt,
3051 UNICAST_GROUP_STREAM_CNT);
3052 return -EINVAL;
3053 }
3054
3055 for (size_t i = 0U; i < num_param; i++) {
3056 if (!valid_group_stream_pair_param(unicast_group, ¶ms[i])) {
3057 return -EINVAL;
3058 }
3059 }
3060
3061 /* We can just check the CIG state to see if any streams have started as
3062 * that would start the ISO connection procedure
3063 */
3064 cig = unicast_group->cig;
3065 if (cig != NULL && cig->state != BT_ISO_CIG_STATE_CONFIGURED) {
3066 LOG_DBG("At least one unicast group stream is started");
3067 return -EBADMSG;
3068 }
3069
3070 for (num_added = 0U; num_added < num_param; num_added++) {
3071 struct bt_bap_unicast_group_stream_pair_param *stream_param;
3072
3073 stream_param = ¶ms[num_added];
3074
3075 err = stream_pair_param_check(stream_param);
3076 if (err < 0) {
3077 return err;
3078 }
3079
3080 err = unicast_group_add_stream_pair(unicast_group, stream_param);
3081 if (err < 0) {
3082 LOG_DBG("unicast_group_add_stream failed: %d", err);
3083 goto fail;
3084 }
3085 }
3086
3087 err = bt_audio_cig_reconfigure(unicast_group);
3088 if (err != 0) {
3089 LOG_DBG("bt_audio_cig_reconfigure failed: %d", err);
3090 goto fail;
3091 }
3092
3093 return 0;
3094
3095 fail:
3096 /* Restore group by removing the newly added streams */
3097 while (num_added--) {
3098 unicast_group_del_stream_pair(unicast_group, ¶ms[num_added]);
3099 }
3100
3101 return err;
3102 }
3103
bt_bap_unicast_group_delete(struct bt_bap_unicast_group * unicast_group)3104 int bt_bap_unicast_group_delete(struct bt_bap_unicast_group *unicast_group)
3105 {
3106 struct bt_bap_stream *stream;
3107
3108 CHECKIF(unicast_group == NULL)
3109 {
3110 LOG_DBG("unicast_group is NULL");
3111 return -EINVAL;
3112 }
3113
3114 SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, stream, _node) {
3115 /* If a stream has an endpoint, it is not ready to be removed
3116 * from a group, as it is not in an idle state
3117 */
3118 if (stream->ep != NULL) {
3119 LOG_DBG("stream %p is not released", stream);
3120 return -EINVAL;
3121 }
3122 }
3123
3124 if (unicast_group->cig != NULL) {
3125 const int err = unicast_client_cig_terminate(unicast_group);
3126
3127 if (err != 0) {
3128 LOG_DBG("unicast_client_cig_terminate failed with err %d", err);
3129
3130 return err;
3131 }
3132 }
3133
3134 unicast_group_free(unicast_group);
3135
3136 return 0;
3137 }
3138
bt_bap_unicast_client_config(struct bt_bap_stream * stream,const struct bt_audio_codec_cfg * codec_cfg)3139 int bt_bap_unicast_client_config(struct bt_bap_stream *stream,
3140 const struct bt_audio_codec_cfg *codec_cfg)
3141 {
3142 struct bt_bap_ep *ep = stream->ep;
3143 struct bt_ascs_config_op *op;
3144 struct net_buf_simple *buf;
3145 int err;
3146
3147 LOG_DBG("stream %p", stream);
3148
3149 if (stream->conn == NULL) {
3150 LOG_DBG("Stream %p does not have a connection", stream);
3151
3152 return -ENOTCONN;
3153 }
3154
3155 buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_CONFIG_OP);
3156 if (buf == NULL) {
3157 LOG_DBG("Could not create PDU");
3158 return -EBUSY;
3159 }
3160
3161 op = net_buf_simple_add(buf, sizeof(*op));
3162 op->num_ases = 0x01;
3163
3164 err = unicast_client_ep_config(ep, buf, codec_cfg);
3165 if (err != 0) {
3166 return err;
3167 }
3168
3169 err = bt_bap_unicast_client_ep_send(stream->conn, ep, buf);
3170 if (err != 0) {
3171 return err;
3172 }
3173
3174 return 0;
3175 }
3176
bt_bap_unicast_client_qos(struct bt_conn * conn,struct bt_bap_unicast_group * group)3177 int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group)
3178 {
3179 struct bt_bap_stream *stream;
3180 struct bt_ascs_config_op *op;
3181 struct net_buf_simple *buf;
3182 struct bt_bap_ep *ep;
3183 bool conn_stream_found;
3184 int err;
3185
3186 if (conn == NULL) {
3187 LOG_DBG("conn is NULL");
3188
3189 return -ENOTCONN;
3190 }
3191
3192 /* Used to determine if a stream for the supplied connection pointer
3193 * was actually found
3194 */
3195 conn_stream_found = false;
3196
3197 /* Validate streams before starting the QoS execution */
3198 SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) {
3199 if (stream->conn != conn) {
3200 /* Channel not part of this ACL, skip */
3201 continue;
3202 }
3203 conn_stream_found = true;
3204
3205 ep = stream->ep;
3206 if (ep == NULL) {
3207 LOG_DBG("stream->ep is NULL");
3208 return -EINVAL;
3209 }
3210
3211 /* Can only be done if all the streams are in the codec
3212 * configured state or the QoS configured state
3213 */
3214 switch (ep->status.state) {
3215 case BT_BAP_EP_STATE_CODEC_CONFIGURED:
3216 case BT_BAP_EP_STATE_QOS_CONFIGURED:
3217 break;
3218 default:
3219 LOG_DBG("Invalid state: %s", bt_bap_ep_state_str(stream->ep->status.state));
3220 return -EINVAL;
3221 }
3222
3223 if (bt_bap_stream_verify_qos(stream, stream->qos) != BT_BAP_ASCS_REASON_NONE) {
3224 return -EINVAL;
3225 }
3226
3227 /* Verify ep->dir */
3228 switch (ep->dir) {
3229 case BT_AUDIO_DIR_SINK:
3230 case BT_AUDIO_DIR_SOURCE:
3231 break;
3232 default:
3233 __ASSERT(false, "invalid endpoint dir: %u", ep->dir);
3234 return -EINVAL;
3235 }
3236
3237 if (stream->bap_iso == NULL) {
3238 /* This can only happen if the stream was somehow added
3239 * to a group without the bap_iso being bound to it
3240 */
3241 LOG_ERR("Could not find bap_iso for stream %p", stream);
3242 return -EINVAL;
3243 }
3244 }
3245
3246 if (!conn_stream_found) {
3247 LOG_DBG("No streams in the group %p for conn %p", group, conn);
3248 return -EINVAL;
3249 }
3250
3251 /* Generate the control point write */
3252 buf = bt_bap_unicast_client_ep_create_pdu(conn, BT_ASCS_QOS_OP);
3253 if (buf == NULL) {
3254 LOG_DBG("Could not create PDU");
3255 return -EBUSY;
3256 }
3257
3258 op = net_buf_simple_add(buf, sizeof(*op));
3259
3260 (void)memset(op, 0, sizeof(*op));
3261 ep = NULL; /* Needed to find the control point handle */
3262 SYS_SLIST_FOR_EACH_CONTAINER(&group->streams, stream, _node) {
3263 if (stream->conn != conn) {
3264 /* Channel not part of this ACL, skip */
3265 continue;
3266 }
3267
3268 op->num_ases++;
3269
3270 if (stream->ep->iso == NULL) {
3271 /* Not yet bound with the bap_iso */
3272 bt_bap_iso_bind_ep(stream->bap_iso, stream->ep);
3273 }
3274
3275 err = bt_bap_unicast_client_ep_qos(stream->ep, buf, stream->qos);
3276 if (err != 0) {
3277 audio_stream_qos_cleanup(conn, group);
3278
3279 return err;
3280 }
3281
3282 if (ep == NULL) {
3283 ep = stream->ep;
3284 }
3285 }
3286
3287 err = bt_bap_unicast_client_ep_send(conn, ep, buf);
3288 if (err != 0) {
3289 LOG_DBG("Could not send config QoS: %d", err);
3290 audio_stream_qos_cleanup(conn, group);
3291
3292 return err;
3293 }
3294
3295 return 0;
3296 }
3297
bt_bap_unicast_client_enable(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len)3298 int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, const uint8_t meta[],
3299 size_t meta_len)
3300 {
3301 struct bt_bap_ep *ep = stream->ep;
3302 struct net_buf_simple *buf;
3303 struct bt_ascs_enable_op *req;
3304 int err;
3305
3306 LOG_DBG("stream %p", stream);
3307
3308 if (stream->conn == NULL) {
3309 LOG_DBG("Stream %p does not have a connection", stream);
3310
3311 return -ENOTCONN;
3312 }
3313
3314 buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_ENABLE_OP);
3315 if (buf == NULL) {
3316 LOG_DBG("Could not create PDU");
3317 return -EBUSY;
3318 }
3319
3320 req = net_buf_simple_add(buf, sizeof(*req));
3321 req->num_ases = 0x01;
3322
3323 err = unicast_client_ep_enable(ep, buf, meta, meta_len);
3324 if (err) {
3325 return err;
3326 }
3327
3328 return bt_bap_unicast_client_ep_send(stream->conn, ep, buf);
3329 }
3330
bt_bap_unicast_client_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len)3331 int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
3332 size_t meta_len)
3333 {
3334 struct bt_bap_ep *ep = stream->ep;
3335 struct net_buf_simple *buf;
3336 struct bt_ascs_enable_op *req;
3337 int err;
3338
3339 LOG_DBG("stream %p", stream);
3340
3341 if (stream->conn == NULL) {
3342 LOG_DBG("Stream %p does not have a connection", stream);
3343
3344 return -ENOTCONN;
3345 }
3346
3347 buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_METADATA_OP);
3348 if (buf == NULL) {
3349 LOG_DBG("Could not create PDU");
3350 return -EBUSY;
3351 }
3352
3353 req = net_buf_simple_add(buf, sizeof(*req));
3354 req->num_ases = 0x01;
3355
3356 err = unicast_client_ep_metadata(ep, buf, meta, meta_len);
3357 if (err) {
3358 return err;
3359 }
3360
3361 return bt_bap_unicast_client_ep_send(stream->conn, ep, buf);
3362 }
3363
bt_bap_unicast_client_connect(struct bt_bap_stream * stream)3364 int bt_bap_unicast_client_connect(struct bt_bap_stream *stream)
3365 {
3366 struct bt_iso_connect_param param;
3367 struct bt_iso_chan *iso_chan;
3368 enum bt_iso_state iso_state;
3369
3370 LOG_DBG("stream %p", stream);
3371
3372 if (stream == NULL) {
3373 LOG_DBG("stream is NULL");
3374
3375 return -EINVAL;
3376 }
3377
3378 iso_chan = bt_bap_stream_iso_chan_get(stream);
3379 if (iso_chan == NULL) {
3380 LOG_DBG("iso_chan is NULL");
3381
3382 return -EINVAL;
3383 }
3384
3385 LOG_DBG("stream %p iso %p", stream, iso_chan);
3386
3387 param.acl = stream->conn;
3388 param.iso_chan = iso_chan;
3389
3390 iso_state = iso_chan->state;
3391 if (iso_state == BT_ISO_STATE_DISCONNECTED) {
3392 const int err = bt_iso_chan_connect(¶m, 1);
3393
3394 if (err == 0 || err == -EBUSY) { /* Expected / known return values */
3395 return err;
3396 }
3397
3398 /* unknown return value*/
3399 LOG_DBG("Unexpected err %d from bt_iso_chan_connect", err);
3400
3401 return -ENOEXEC;
3402 } else if (iso_state == BT_ISO_STATE_CONNECTING || iso_state == BT_ISO_STATE_CONNECTED) {
3403 LOG_DBG("iso_chan %p already connecting or connected (%u)", iso_chan, iso_state);
3404
3405 return -EALREADY;
3406 }
3407
3408 LOG_DBG("iso_chan %p in invalid state state (%u), cannot connect", iso_chan, iso_state);
3409
3410 return -EBADMSG;
3411 }
3412
bt_bap_unicast_client_start(struct bt_bap_stream * stream)3413 int bt_bap_unicast_client_start(struct bt_bap_stream *stream)
3414 {
3415 struct bt_bap_ep *ep = stream->ep;
3416 int err;
3417
3418 LOG_DBG("stream %p", stream);
3419
3420 if (stream->conn == NULL) {
3421 LOG_DBG("Stream %p does not have a connection", stream);
3422
3423 return -ENOTCONN;
3424 }
3425
3426 /* As per the ASCS spec, only source streams can be started by the client */
3427 if (ep->dir == BT_AUDIO_DIR_SINK) {
3428 LOG_DBG("Stream %p is not a source stream", stream);
3429
3430 return -EINVAL;
3431 }
3432
3433 ep->receiver_ready = true;
3434
3435 err = unicast_client_send_start(ep);
3436 if (err != 0) {
3437 LOG_DBG("Failed to send start: %d", err);
3438
3439 /* TBD: Should we release the stream then? */
3440 ep->receiver_ready = false;
3441
3442 return err;
3443 }
3444
3445 return 0;
3446 }
3447
bt_bap_unicast_client_disable(struct bt_bap_stream * stream)3448 int bt_bap_unicast_client_disable(struct bt_bap_stream *stream)
3449 {
3450 struct bt_bap_ep *ep = stream->ep;
3451 struct net_buf_simple *buf;
3452 struct bt_ascs_disable_op *req;
3453 int err;
3454
3455 LOG_DBG("stream %p", stream);
3456
3457 if (stream->conn == NULL) {
3458 LOG_DBG("Stream %p does not have a connection", stream);
3459
3460 return -ENOTCONN;
3461 }
3462
3463 buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_DISABLE_OP);
3464 if (buf == NULL) {
3465 LOG_DBG("Could not create PDU");
3466 return -EBUSY;
3467 }
3468
3469 req = net_buf_simple_add(buf, sizeof(*req));
3470 req->num_ases = 0x01;
3471
3472 err = unicast_client_ep_disable(ep, buf);
3473 if (err) {
3474 return err;
3475 }
3476
3477 return bt_bap_unicast_client_ep_send(stream->conn, ep, buf);
3478 }
3479
bt_bap_unicast_client_stop(struct bt_bap_stream * stream)3480 int bt_bap_unicast_client_stop(struct bt_bap_stream *stream)
3481 {
3482 struct bt_bap_ep *ep = stream->ep;
3483 enum bt_iso_state iso_state;
3484 struct net_buf_simple *buf;
3485 struct bt_ascs_start_op *req;
3486 int err;
3487
3488 LOG_DBG("stream %p", stream);
3489
3490 if (stream->conn == NULL) {
3491 LOG_DBG("Stream %p does not have a connection", stream);
3492
3493 return -ENOTCONN;
3494 }
3495
3496 /* ASCS_v1.0 3.2 ASE state machine transitions
3497 *
3498 * If the server detects link loss of a CIS for an ASE in the Streaming state or the
3499 * Disabling state, the server shall immediately transition that ASE to the QoS Configured
3500 * state.
3501 *
3502 * This effectively means that if an ASE no longer has a connected CIS, the server shall
3503 * bring it to the QoS Configured state. That means that we, as a unicast client, should not
3504 * attempt to stop it
3505 */
3506 if (ep->iso == NULL) {
3507 LOG_DBG("Stream endpoint does not have a CIS, server will stop the ASE");
3508 return -EALREADY;
3509 }
3510
3511 iso_state = ep->iso->chan.state;
3512 if (iso_state != BT_ISO_STATE_CONNECTED && iso_state != BT_ISO_STATE_CONNECTING) {
3513 LOG_DBG("Stream endpoint CIS is not connected, server will stop the ASE");
3514 return -EALREADY;
3515 }
3516
3517 buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_STOP_OP);
3518 if (buf == NULL) {
3519 LOG_DBG("Could not create PDU");
3520 return -EBUSY;
3521 }
3522
3523 req = net_buf_simple_add(buf, sizeof(*req));
3524 req->num_ases = 0x00;
3525
3526 /* When initiated by the client, valid only if Direction field
3527 * parameter value = 0x02 (Server is Audio Source)
3528 */
3529 if (ep->dir == BT_AUDIO_DIR_SOURCE) {
3530 err = unicast_client_ep_stop(ep, buf);
3531 if (err) {
3532 return err;
3533 }
3534 req->num_ases++;
3535
3536 err = bt_bap_unicast_client_ep_send(stream->conn, ep, buf);
3537 if (err != 0) {
3538 /* Return expected error directly */
3539 if (err == -ENOTCONN || err == -ENOMEM) {
3540 return err;
3541 }
3542
3543 LOG_DBG("bt_bap_unicast_client_ep_send failed with unexpected error %d",
3544 err);
3545
3546 return -ENOEXEC;
3547 }
3548 }
3549
3550 return 0;
3551 }
3552
bt_bap_unicast_client_release(struct bt_bap_stream * stream)3553 int bt_bap_unicast_client_release(struct bt_bap_stream *stream)
3554 {
3555 struct bt_bap_unicast_client_ep *client_ep;
3556 struct bt_bap_ep *ep = stream->ep;
3557 struct net_buf_simple *buf;
3558 struct bt_ascs_disable_op *req;
3559 int err, len;
3560
3561 LOG_DBG("stream %p", stream);
3562
3563 if (stream->conn == NULL) {
3564 LOG_DBG("Stream %p does not have a connection", stream);
3565
3566 return -ENOTCONN;
3567 }
3568
3569 buf = bt_bap_unicast_client_ep_create_pdu(stream->conn, BT_ASCS_RELEASE_OP);
3570 if (buf == NULL) {
3571 LOG_DBG("Could not create PDU");
3572 return -EBUSY;
3573 }
3574
3575 req = net_buf_simple_add(buf, sizeof(*req));
3576 req->num_ases = 0x01;
3577 len = buf->len;
3578
3579 /* Only attempt to release if not IDLE already */
3580 if (stream->ep->status.state == BT_BAP_EP_STATE_IDLE) {
3581 bt_bap_stream_reset(stream);
3582 } else {
3583 err = unicast_client_ep_release(ep, buf);
3584 if (err) {
3585 return err;
3586 }
3587 }
3588
3589 /* Check if anything needs to be send */
3590 if (len == buf->len) {
3591 return 0;
3592 }
3593
3594 err = bt_bap_unicast_client_ep_send(stream->conn, ep, buf);
3595 if (err != 0) {
3596 return err;
3597 }
3598
3599 client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep);
3600 client_ep->release_requested = true;
3601
3602 return 0;
3603 }
3604
unicast_client_cp_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * discover)3605 static uint8_t unicast_client_cp_discover_func(struct bt_conn *conn,
3606 const struct bt_gatt_attr *attr,
3607 struct bt_gatt_discover_params *discover)
3608 {
3609 struct bt_gatt_chrc *chrc;
3610 uint16_t value_handle;
3611
3612 if (!attr) {
3613 LOG_ERR("Unable to find ASE Control Point");
3614
3615 unicast_client_discover_complete(conn, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND);
3616 return BT_GATT_ITER_STOP;
3617 }
3618
3619 chrc = attr->user_data;
3620 value_handle = chrc->value_handle;
3621 memset(discover, 0, sizeof(*discover));
3622
3623 LOG_DBG("conn %p attr %p handle 0x%04x", conn, attr, value_handle);
3624
3625 unicast_client_ep_set_cp(conn, value_handle);
3626
3627 return BT_GATT_ITER_STOP;
3628 }
3629
unicast_client_ase_cp_discover(struct bt_conn * conn)3630 static int unicast_client_ase_cp_discover(struct bt_conn *conn)
3631 {
3632 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
3633
3634 LOG_DBG("conn %p", conn);
3635
3636 client->disc_params.uuid = cp_uuid;
3637 client->disc_params.func = unicast_client_cp_discover_func;
3638 client->disc_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
3639 client->disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
3640 client->disc_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
3641
3642 return bt_gatt_discover(conn, &client->disc_params);
3643 }
3644
unicast_client_ase_read_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * read,const void * data,uint16_t length)3645 static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err,
3646 struct bt_gatt_read_params *read, const void *data,
3647 uint16_t length)
3648 {
3649 uint16_t handle = read->single.handle;
3650 struct unicast_client *client;
3651 struct net_buf_simple *buf;
3652 struct bt_bap_ep *ep;
3653 int cb_err;
3654
3655 LOG_DBG("conn %p err 0x%02x len %u", conn, err, length);
3656
3657 if (err) {
3658 cb_err = err;
3659 goto fail;
3660 }
3661
3662 LOG_DBG("handle 0x%04x", handle);
3663
3664 client = &uni_cli_insts[bt_conn_index(conn)];
3665 buf = &client->net_buf;
3666
3667 if (data != NULL) {
3668 if (net_buf_simple_tailroom(buf) < length) {
3669 LOG_DBG("Buffer full, invalid server response of size %u",
3670 length + client->net_buf.len);
3671
3672 cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
3673
3674 goto fail;
3675 }
3676
3677 /* store data*/
3678 net_buf_simple_add_mem(buf, data, length);
3679
3680 return BT_GATT_ITER_CONTINUE;
3681 }
3682
3683 memset(read, 0, sizeof(*read));
3684
3685 if (buf->len < sizeof(struct bt_ascs_ase_status)) {
3686 LOG_DBG("Read response too small (%u)", buf->len);
3687
3688 cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
3689
3690 goto fail;
3691 }
3692
3693 ep = unicast_client_ep_get(conn, client->dir, handle);
3694 if (!ep) {
3695 /* The BAP spec declares that the unicast client shall subscribe to all ASEs.
3696 * In case that we cannot support this due to memory restrictions, we should
3697 * consider the discovery procedure as failing.
3698 */
3699 LOG_WRN("No space left to parse ASE");
3700 cb_err = -ENOMEM;
3701
3702 goto fail;
3703 }
3704
3705 unicast_client_ep_set_status(ep, buf);
3706 cb_err = unicast_client_ep_subscribe(conn, ep);
3707 if (cb_err != 0) {
3708 LOG_DBG("Failed to subscribe to ep %p: %d", ep, cb_err);
3709 goto fail;
3710 }
3711
3712 reset_att_buf(client);
3713
3714 unicast_client_notify_endpoint(conn, ep);
3715
3716 cb_err = unicast_client_ase_discover(conn, handle);
3717 if (cb_err != 0) {
3718 LOG_DBG("Failed to read ASE: %d", cb_err);
3719 goto fail;
3720 }
3721
3722 return BT_GATT_ITER_STOP;
3723
3724 fail:
3725 unicast_client_discover_complete(conn, cb_err);
3726 return BT_GATT_ITER_STOP;
3727 }
3728
any_ases_found(const struct unicast_client * client)3729 static bool any_ases_found(const struct unicast_client *client)
3730 {
3731 /* We always allocate ases from 0 to X, so to verify if any sink or source ASEs have been
3732 * found we can just check the first index
3733 */
3734 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
3735 if (client->dir == BT_AUDIO_DIR_SINK && client->snks[0].handle == BAP_HANDLE_UNUSED) {
3736 LOG_DBG("No sink ASEs found");
3737 return false;
3738 }
3739 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
3740 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
3741 if (client->dir == BT_AUDIO_DIR_SOURCE && client->srcs[0].handle == BAP_HANDLE_UNUSED) {
3742 LOG_DBG("No source ASEs found");
3743 return false;
3744 }
3745 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
3746
3747 return true;
3748 }
3749
unicast_client_ase_discover_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * discover)3750 static uint8_t unicast_client_ase_discover_cb(struct bt_conn *conn,
3751 const struct bt_gatt_attr *attr,
3752 struct bt_gatt_discover_params *discover)
3753 {
3754 struct unicast_client *client;
3755 struct bt_gatt_chrc *chrc;
3756 uint16_t value_handle;
3757 int err;
3758
3759 client = &uni_cli_insts[bt_conn_index(conn)];
3760
3761 if (attr == NULL) {
3762 if (!any_ases_found(client)) {
3763 unicast_client_discover_complete(conn, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND);
3764 } else {
3765 err = unicast_client_ase_cp_discover(conn);
3766 if (err != 0) {
3767 LOG_ERR("Unable to discover ASE Control Point");
3768
3769 unicast_client_discover_complete(conn, err);
3770 }
3771 }
3772
3773 return BT_GATT_ITER_STOP;
3774 }
3775
3776 chrc = attr->user_data;
3777 value_handle = chrc->value_handle;
3778 memset(discover, 0, sizeof(*discover));
3779
3780 LOG_DBG("conn %p attr %p handle 0x%04x dir %s", conn, attr, value_handle,
3781 bt_audio_dir_str(client->dir));
3782
3783 client->read_params.func = unicast_client_ase_read_func;
3784 client->read_params.handle_count = 1U;
3785 client->read_params.single.handle = value_handle;
3786 client->read_params.single.offset = 0U;
3787
3788 err = bt_gatt_read(conn, &client->read_params);
3789 if (err != 0) {
3790 LOG_DBG("Failed to read PAC records: %d", err);
3791
3792 unicast_client_discover_complete(conn, err);
3793 }
3794
3795 return BT_GATT_ITER_STOP;
3796 }
3797
unicast_client_ase_discover(struct bt_conn * conn,uint16_t start_handle)3798 static int unicast_client_ase_discover(struct bt_conn *conn, uint16_t start_handle)
3799 {
3800 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
3801
3802 LOG_DBG("conn %p ", conn);
3803
3804 if (client->dir == BT_AUDIO_DIR_SINK) {
3805 client->disc_params.uuid = ase_snk_uuid;
3806 } else if (client->dir == BT_AUDIO_DIR_SOURCE) {
3807 client->disc_params.uuid = ase_src_uuid;
3808 } else {
3809 return -EINVAL;
3810 }
3811
3812 client->disc_params.func = unicast_client_ase_discover_cb;
3813 client->disc_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
3814 client->disc_params.start_handle = start_handle;
3815 client->disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
3816
3817 return bt_gatt_discover(conn, &client->disc_params);
3818 }
3819
unicast_client_pacs_avail_ctx_read_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * read,const void * data,uint16_t length)3820 static uint8_t unicast_client_pacs_avail_ctx_read_func(struct bt_conn *conn, uint8_t err,
3821 struct bt_gatt_read_params *read,
3822 const void *data, uint16_t length)
3823 {
3824 struct bt_pacs_context context;
3825 struct net_buf_simple buf;
3826 int cb_err;
3827
3828 memset(read, 0, sizeof(*read));
3829
3830 LOG_DBG("conn %p err 0x%02x len %u", conn, err, length);
3831
3832 if (err || data == NULL || length != sizeof(context)) {
3833 LOG_DBG("Could not read available context: %d, %p, %u", err, data, length);
3834
3835 if (err == BT_ATT_ERR_SUCCESS) {
3836 err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
3837 }
3838
3839 unicast_client_discover_complete(conn, err);
3840
3841 return BT_GATT_ITER_STOP;
3842 }
3843
3844 net_buf_simple_init_with_data(&buf, (void *)data, length);
3845 context.snk = net_buf_simple_pull_le16(&buf);
3846 context.src = net_buf_simple_pull_le16(&buf);
3847
3848 LOG_DBG("sink context %u, source context %u", context.snk, context.src);
3849
3850 unicast_client_notify_available_contexts(conn, context.snk, context.src);
3851
3852 /* Read ASE instances */
3853 cb_err = unicast_client_ase_discover(conn, BT_ATT_FIRST_ATTRIBUTE_HANDLE);
3854 if (cb_err != 0) {
3855 LOG_ERR("Unable to read ASE: %d", cb_err);
3856
3857 unicast_client_discover_complete(conn, cb_err);
3858 }
3859
3860 return BT_GATT_ITER_STOP;
3861 }
3862
unicast_client_pacs_avail_ctx_notify_cb(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)3863 static uint8_t unicast_client_pacs_avail_ctx_notify_cb(struct bt_conn *conn,
3864 struct bt_gatt_subscribe_params *params,
3865 const void *data, uint16_t length)
3866 {
3867 struct bt_pacs_context context;
3868 struct net_buf_simple buf;
3869
3870 LOG_DBG("conn %p len %u", conn, length);
3871
3872 if (!data) {
3873 LOG_DBG("Unsubscribed");
3874 params->value_handle = BAP_HANDLE_UNUSED;
3875 return BT_GATT_ITER_STOP;
3876 }
3877
3878 net_buf_simple_init_with_data(&buf, (void *)data, length);
3879
3880 if (buf.len != sizeof(context)) {
3881 LOG_ERR("Avail_ctx notification incorrect size: %u", length);
3882 return BT_GATT_ITER_STOP;
3883 }
3884
3885 net_buf_simple_init_with_data(&buf, (void *)data, length);
3886 context.snk = net_buf_simple_pull_le16(&buf);
3887 context.src = net_buf_simple_pull_le16(&buf);
3888
3889 LOG_DBG("sink context %u, source context %u", context.snk, context.src);
3890
3891 unicast_client_notify_available_contexts(conn, context.snk, context.src);
3892
3893 return BT_GATT_ITER_CONTINUE;
3894 }
3895
unicast_client_pacs_avail_ctx_read(struct bt_conn * conn,uint16_t handle)3896 static int unicast_client_pacs_avail_ctx_read(struct bt_conn *conn, uint16_t handle)
3897 {
3898 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
3899
3900 LOG_DBG("conn %p", conn);
3901
3902 client->read_params.func = unicast_client_pacs_avail_ctx_read_func;
3903 client->read_params.handle_count = 1U;
3904 client->read_params.single.handle = handle;
3905 client->read_params.single.offset = 0U;
3906
3907 return bt_gatt_read(conn, &client->read_params);
3908 }
3909
unicast_client_pacs_avail_ctx_discover_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * discover)3910 static uint8_t unicast_client_pacs_avail_ctx_discover_cb(struct bt_conn *conn,
3911 const struct bt_gatt_attr *attr,
3912 struct bt_gatt_discover_params *discover)
3913 {
3914 uint8_t index = bt_conn_index(conn);
3915 const struct bt_gatt_chrc *chrc;
3916 uint8_t chrc_properties;
3917 uint16_t value_handle;
3918 int err;
3919
3920 if (!attr) {
3921 /* If available_ctx is not found, we terminate the discovery as
3922 * the characteristic is mandatory
3923 */
3924
3925 unicast_client_discover_complete(conn, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND);
3926
3927 return BT_GATT_ITER_STOP;
3928 }
3929
3930 chrc = attr->user_data;
3931 chrc_properties = chrc->properties;
3932 value_handle = chrc->value_handle;
3933 memset(discover, 0, sizeof(*discover));
3934
3935 LOG_DBG("conn %p attr %p handle 0x%04x", conn, attr, value_handle);
3936
3937 if (chrc_properties & BT_GATT_CHRC_NOTIFY) {
3938 struct bt_gatt_subscribe_params *sub_params;
3939
3940 sub_params = &uni_cli_insts[index].avail_ctx_subscribe;
3941
3942 if (sub_params->value_handle == 0) {
3943 LOG_DBG("Subscribing to handle %u", value_handle);
3944 sub_params->value_handle = value_handle;
3945 sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
3946 sub_params->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
3947 sub_params->disc_params = &uni_cli_insts[index].avail_ctx_cc_disc;
3948 sub_params->notify = unicast_client_pacs_avail_ctx_notify_cb;
3949 sub_params->value = BT_GATT_CCC_NOTIFY;
3950 atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
3951
3952 err = bt_gatt_subscribe(conn, sub_params);
3953 if (err != 0 && err != -EALREADY) {
3954 LOG_ERR("Failed to subscribe to avail_ctx: %d", err);
3955 }
3956 } /* else already subscribed */
3957 } else {
3958 LOG_DBG("Invalid chrc->properties: %u", chrc_properties);
3959 /* If the characteristic is not subscribable we terminate the
3960 * discovery as BT_GATT_CHRC_NOTIFY is mandatory
3961 */
3962 unicast_client_discover_complete(conn, BT_ATT_ERR_NOT_SUPPORTED);
3963
3964 return BT_GATT_ITER_STOP;
3965 }
3966
3967 err = unicast_client_pacs_avail_ctx_read(conn, value_handle);
3968 if (err != 0) {
3969 LOG_DBG("Failed to read PACS avail_ctx: %d", err);
3970
3971 unicast_client_discover_complete(conn, err);
3972 }
3973
3974 return BT_GATT_ITER_STOP;
3975 }
3976
unicast_client_pacs_avail_ctx_discover(struct bt_conn * conn)3977 static int unicast_client_pacs_avail_ctx_discover(struct bt_conn *conn)
3978 {
3979 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
3980
3981 LOG_DBG("conn %p", conn);
3982
3983 client->disc_params.uuid = pacs_avail_ctx_uuid;
3984 client->disc_params.func = unicast_client_pacs_avail_ctx_discover_cb;
3985 client->disc_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
3986 client->disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
3987 client->disc_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
3988
3989 return bt_gatt_discover(conn, &client->disc_params);
3990 }
3991
unicast_client_pacs_location_read_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * read,const void * data,uint16_t length)3992 static uint8_t unicast_client_pacs_location_read_func(struct bt_conn *conn, uint8_t err,
3993 struct bt_gatt_read_params *read,
3994 const void *data, uint16_t length)
3995 {
3996 struct unicast_client *client;
3997 struct net_buf_simple buf;
3998 uint32_t location;
3999 int cb_err;
4000
4001 memset(read, 0, sizeof(*read));
4002
4003 client = &uni_cli_insts[bt_conn_index(conn)];
4004
4005 LOG_DBG("conn %p err 0x%02x len %u", conn, err, length);
4006
4007 if (err || data == NULL || length != sizeof(location)) {
4008 LOG_DBG("Unable to read PACS location for dir %s: %u, %p, %u",
4009 bt_audio_dir_str(client->dir), err, data, length);
4010
4011 if (err == BT_ATT_ERR_SUCCESS) {
4012 err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
4013 }
4014
4015 unicast_client_discover_complete(conn, err);
4016
4017 return BT_GATT_ITER_STOP;
4018 }
4019
4020 net_buf_simple_init_with_data(&buf, (void *)data, length);
4021 location = net_buf_simple_pull_le32(&buf);
4022
4023 LOG_DBG("dir %s loc %X", bt_audio_dir_str(client->dir), location);
4024
4025 unicast_client_notify_location(conn, client->dir, (enum bt_audio_location)location);
4026
4027 /* Read available contexts */
4028 cb_err = unicast_client_pacs_avail_ctx_discover(conn);
4029 if (cb_err != 0) {
4030 LOG_ERR("Unable to read available contexts: %d", cb_err);
4031
4032 unicast_client_discover_complete(conn, cb_err);
4033 }
4034
4035 return BT_GATT_ITER_STOP;
4036 }
4037
unicast_client_pacs_location_notify_cb(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)4038 static uint8_t unicast_client_pacs_location_notify_cb(struct bt_conn *conn,
4039 struct bt_gatt_subscribe_params *params,
4040 const void *data, uint16_t length)
4041 {
4042 struct net_buf_simple buf;
4043 enum bt_audio_dir dir;
4044 uint32_t location;
4045
4046 LOG_DBG("conn %p len %u", conn, length);
4047
4048 if (!data) {
4049 LOG_DBG("Unsubscribed");
4050 params->value_handle = BAP_HANDLE_UNUSED;
4051 return BT_GATT_ITER_STOP;
4052 }
4053
4054 net_buf_simple_init_with_data(&buf, (void *)data, length);
4055
4056 if (buf.len != sizeof(location)) {
4057 LOG_ERR("Location notification incorrect size: %u", length);
4058 return BT_GATT_ITER_STOP;
4059 }
4060
4061 if (params == &uni_cli_insts[bt_conn_index(conn)].snk_loc_subscribe) {
4062 dir = BT_AUDIO_DIR_SINK;
4063 } else if (params == &uni_cli_insts[bt_conn_index(conn)].src_loc_subscribe) {
4064 dir = BT_AUDIO_DIR_SOURCE;
4065 } else {
4066 LOG_ERR("Invalid notification");
4067
4068 return BT_GATT_ITER_CONTINUE;
4069 }
4070
4071 net_buf_simple_init_with_data(&buf, (void *)data, length);
4072 location = net_buf_simple_pull_le32(&buf);
4073
4074 LOG_DBG("dir %s loc %X", bt_audio_dir_str(dir), location);
4075
4076 unicast_client_notify_location(conn, dir, (enum bt_audio_location)location);
4077
4078 return BT_GATT_ITER_CONTINUE;
4079 }
4080
unicast_client_pacs_location_read(struct bt_conn * conn,uint16_t handle)4081 static int unicast_client_pacs_location_read(struct bt_conn *conn, uint16_t handle)
4082 {
4083 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
4084
4085 LOG_DBG("conn %p", conn);
4086
4087 client->read_params.func = unicast_client_pacs_location_read_func;
4088 client->read_params.handle_count = 1U;
4089 client->read_params.single.handle = handle;
4090 client->read_params.single.offset = 0U;
4091
4092 return bt_gatt_read(conn, &client->read_params);
4093 }
4094
unicast_client_pacs_location_discover_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * discover)4095 static uint8_t unicast_client_pacs_location_discover_cb(struct bt_conn *conn,
4096 const struct bt_gatt_attr *attr,
4097 struct bt_gatt_discover_params *discover)
4098 {
4099 uint8_t index = bt_conn_index(conn);
4100 const struct bt_gatt_chrc *chrc;
4101 uint16_t value_handle;
4102 int err;
4103
4104 if (!attr) {
4105 /* If location is not found, we just continue reading the
4106 * available contexts, as location is optional.
4107 */
4108 err = unicast_client_pacs_avail_ctx_discover(conn);
4109 if (err != 0) {
4110 LOG_ERR("Unable to read available contexts: %d", err);
4111
4112 unicast_client_discover_complete(conn, err);
4113 }
4114
4115 return BT_GATT_ITER_STOP;
4116 }
4117
4118 chrc = attr->user_data;
4119 value_handle = chrc->value_handle;
4120 memset(discover, 0, sizeof(*discover));
4121
4122 LOG_DBG("conn %p attr %p handle 0x%04x", conn, attr, value_handle);
4123
4124 if (chrc->properties & BT_GATT_CHRC_NOTIFY) {
4125 const struct unicast_client *client = &uni_cli_insts[index];
4126 struct bt_gatt_subscribe_params *sub_params;
4127
4128 if (client->dir == BT_AUDIO_DIR_SINK) {
4129 sub_params = &uni_cli_insts[index].snk_loc_subscribe;
4130 } else {
4131 sub_params = &uni_cli_insts[index].src_loc_subscribe;
4132 }
4133
4134 sub_params->value_handle = value_handle;
4135 sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
4136 sub_params->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
4137 sub_params->disc_params = &uni_cli_insts[index].loc_cc_disc;
4138 sub_params->notify = unicast_client_pacs_location_notify_cb;
4139 sub_params->value = BT_GATT_CCC_NOTIFY;
4140 atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
4141
4142 err = bt_gatt_subscribe(conn, sub_params);
4143 if (err != 0 && err != -EALREADY) {
4144 LOG_ERR("Failed to subscribe to location: %d", err);
4145 }
4146 }
4147
4148 err = unicast_client_pacs_location_read(conn, value_handle);
4149 if (err != 0) {
4150 LOG_DBG("Failed to read PACS location: %d", err);
4151
4152 unicast_client_discover_complete(conn, err);
4153 }
4154
4155 return BT_GATT_ITER_STOP;
4156 }
4157
unicast_client_pacs_location_discover(struct bt_conn * conn)4158 static int unicast_client_pacs_location_discover(struct bt_conn *conn)
4159 {
4160 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
4161
4162 LOG_DBG("conn %p dir %s", conn, bt_audio_dir_str(client->dir));
4163
4164 if (client->dir == BT_AUDIO_DIR_SINK) {
4165 client->disc_params.uuid = pacs_snk_loc_uuid;
4166 } else if (client->dir == BT_AUDIO_DIR_SOURCE) {
4167 client->disc_params.uuid = pacs_src_loc_uuid;
4168 } else {
4169 return -EINVAL;
4170 }
4171
4172 client->disc_params.func = unicast_client_pacs_location_discover_cb;
4173 client->disc_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
4174 client->disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
4175 client->disc_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
4176
4177 return bt_gatt_discover(conn, &client->disc_params);
4178 }
4179
unicast_client_pacs_context_read_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * read,const void * data,uint16_t length)4180 static uint8_t unicast_client_pacs_context_read_func(struct bt_conn *conn, uint8_t err,
4181 struct bt_gatt_read_params *read,
4182 const void *data, uint16_t length)
4183 {
4184 struct net_buf_simple buf;
4185 struct bt_pacs_context *context;
4186 int cb_err;
4187
4188 memset(read, 0, sizeof(*read));
4189
4190 LOG_DBG("conn %p err 0x%02x len %u", conn, err, length);
4191
4192 if (err || length < sizeof(uint16_t) * 2) {
4193 goto discover_loc;
4194 }
4195
4196 net_buf_simple_init_with_data(&buf, (void *)data, length);
4197 context = net_buf_simple_pull_mem(&buf, sizeof(*context));
4198
4199 discover_loc:
4200 /* Read ASE instances */
4201 cb_err = unicast_client_pacs_location_discover(conn);
4202 if (cb_err != 0) {
4203 LOG_ERR("Unable to read PACS location: %d", cb_err);
4204
4205 unicast_client_discover_complete(conn, cb_err);
4206 }
4207
4208 return BT_GATT_ITER_STOP;
4209 }
4210
unicast_client_pacs_context_discover_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * discover)4211 static uint8_t unicast_client_pacs_context_discover_cb(struct bt_conn *conn,
4212 const struct bt_gatt_attr *attr,
4213 struct bt_gatt_discover_params *discover)
4214 {
4215 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
4216 struct bt_gatt_chrc *chrc;
4217 uint16_t value_handle;
4218 int err;
4219
4220 if (attr == NULL) {
4221 LOG_ERR("Unable to find %s PAC context", bt_audio_dir_str(client->dir));
4222
4223 unicast_client_discover_complete(conn, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND);
4224
4225 return BT_GATT_ITER_STOP;
4226 }
4227
4228 chrc = attr->user_data;
4229 value_handle = chrc->value_handle;
4230 memset(discover, 0, sizeof(*discover));
4231
4232 LOG_DBG("conn %p attr %p handle 0x%04x dir %s", conn, attr, value_handle,
4233 bt_audio_dir_str(client->dir));
4234
4235 /* TODO: Subscribe to PAC context */
4236
4237 client->read_params.func = unicast_client_pacs_context_read_func;
4238 client->read_params.handle_count = 1U;
4239 client->read_params.single.handle = value_handle;
4240 client->read_params.single.offset = 0U;
4241
4242 err = bt_gatt_read(conn, &client->read_params);
4243 if (err != 0) {
4244 LOG_DBG("Failed to read PAC records: %d", err);
4245
4246 unicast_client_discover_complete(conn, err);
4247 }
4248
4249 return BT_GATT_ITER_STOP;
4250 }
4251
unicast_client_pacs_context_discover(struct bt_conn * conn)4252 static int unicast_client_pacs_context_discover(struct bt_conn *conn)
4253 {
4254 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
4255
4256 LOG_DBG("conn %p", conn);
4257
4258 client->disc_params.uuid = pacs_context_uuid;
4259 client->disc_params.func = unicast_client_pacs_context_discover_cb;
4260 client->disc_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
4261 client->disc_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
4262 client->disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
4263
4264 return bt_gatt_discover(conn, &client->disc_params);
4265 }
4266
unicast_client_read_func(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * read,const void * data,uint16_t length)4267 static uint8_t unicast_client_read_func(struct bt_conn *conn, uint8_t err,
4268 struct bt_gatt_read_params *read, const void *data,
4269 uint16_t length)
4270 {
4271 uint16_t handle = read->single.handle;
4272 struct unicast_client *client;
4273 struct bt_pacs_read_rsp *rsp;
4274 struct net_buf_simple *buf;
4275 int cb_err = err;
4276 uint8_t i;
4277
4278 LOG_DBG("conn %p err 0x%02x len %u", conn, err, length);
4279
4280 if (cb_err != BT_ATT_ERR_SUCCESS) {
4281 goto fail;
4282 }
4283
4284 LOG_DBG("handle 0x%04x", handle);
4285
4286 client = &uni_cli_insts[bt_conn_index(conn)];
4287 buf = &client->net_buf;
4288
4289 if (data != NULL) {
4290 if (net_buf_simple_tailroom(buf) < length) {
4291 LOG_DBG("Buffer full, invalid server response of size %u",
4292 length + client->net_buf.len);
4293
4294 cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
4295
4296 goto fail;
4297 }
4298
4299 /* store data*/
4300 net_buf_simple_add_mem(buf, data, length);
4301
4302 return BT_GATT_ITER_CONTINUE;
4303 }
4304
4305 memset(read, 0, sizeof(*read));
4306
4307 if (buf->len < sizeof(*rsp)) {
4308 LOG_DBG("Read response too small (%u)", buf->len);
4309
4310 cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
4311
4312 goto fail;
4313 }
4314
4315 rsp = net_buf_simple_pull_mem(buf, sizeof(*rsp));
4316
4317 /* If no PAC was found don't bother discovering ASE and ASE CP */
4318 if (!rsp->num_pac) {
4319 goto fail;
4320 }
4321
4322 for (i = 0U; i < rsp->num_pac; i++) {
4323 struct bt_audio_codec_cap codec_cap;
4324 struct bt_pac_codec *pac_codec;
4325 struct bt_pac_ltv_data *meta, *cc;
4326 void *cc_ltv, *meta_ltv;
4327
4328 LOG_DBG("pac #%u/%u", i + 1, rsp->num_pac);
4329
4330 if (buf->len < sizeof(*pac_codec)) {
4331 LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4332 buf->len, sizeof(*pac_codec));
4333 break;
4334 }
4335
4336 pac_codec = net_buf_simple_pull_mem(buf, sizeof(*pac_codec));
4337
4338 if (buf->len < sizeof(*cc)) {
4339 LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4340 buf->len, sizeof(*cc));
4341 break;
4342 }
4343
4344 cc = net_buf_simple_pull_mem(buf, sizeof(*cc));
4345 if (buf->len < cc->len) {
4346 LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4347 buf->len, cc->len);
4348 break;
4349 }
4350
4351 cc_ltv = net_buf_simple_pull_mem(buf, cc->len);
4352
4353 if (buf->len < sizeof(*meta)) {
4354 LOG_ERR("Malformed PAC: remaining len %u expected %zu",
4355 buf->len, sizeof(*meta));
4356 break;
4357 }
4358
4359 meta = net_buf_simple_pull_mem(buf, sizeof(*meta));
4360 if (buf->len < meta->len) {
4361 LOG_ERR("Malformed PAC: remaining len %u expected %u",
4362 buf->len, meta->len);
4363 break;
4364 }
4365
4366 meta_ltv = net_buf_simple_pull_mem(buf, meta->len);
4367
4368 if (unicast_client_set_codec_cap(pac_codec->id, sys_le16_to_cpu(pac_codec->cid),
4369 sys_le16_to_cpu(pac_codec->vid), cc_ltv, cc->len,
4370 meta_ltv, meta->len, &codec_cap)) {
4371 LOG_ERR("Unable to parse Codec");
4372 break;
4373 }
4374
4375 LOG_DBG("codec 0x%02x capabilities len %u meta len %u ", codec_cap.id,
4376 codec_cap.data_len, codec_cap.meta_len);
4377
4378 unicast_client_notify_pac_record(conn, &codec_cap);
4379 }
4380
4381 reset_att_buf(client);
4382
4383 if (i != rsp->num_pac) {
4384 LOG_DBG("Failed to process all PAC records (%u/%u)", i, rsp->num_pac);
4385 cb_err = BT_ATT_ERR_INVALID_PDU;
4386 goto fail;
4387 }
4388
4389 /* Read PACS contexts */
4390 cb_err = unicast_client_pacs_context_discover(conn);
4391 if (cb_err != 0) {
4392 LOG_ERR("Unable to read PACS context: %d", cb_err);
4393 goto fail;
4394 }
4395
4396 return BT_GATT_ITER_STOP;
4397
4398 fail:
4399 unicast_client_discover_complete(conn, cb_err);
4400 return BT_GATT_ITER_STOP;
4401 }
4402
unicast_client_pac_discover_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * discover)4403 static uint8_t unicast_client_pac_discover_cb(struct bt_conn *conn,
4404 const struct bt_gatt_attr *attr,
4405 struct bt_gatt_discover_params *discover)
4406 {
4407 struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)];
4408 struct bt_gatt_chrc *chrc;
4409 uint16_t value_handle;
4410 int err;
4411
4412 if (attr == NULL) {
4413 LOG_DBG("Unable to find %s PAC", bt_audio_dir_str(client->dir));
4414
4415 unicast_client_discover_complete(conn, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND);
4416
4417 return BT_GATT_ITER_STOP;
4418 }
4419
4420 chrc = attr->user_data;
4421 value_handle = chrc->value_handle;
4422 memset(discover, 0, sizeof(*discover));
4423
4424 LOG_DBG("conn %p attr %p handle 0x%04x dir %s", conn, attr, value_handle,
4425 bt_audio_dir_str(client->dir));
4426
4427 /* TODO: Subscribe to PAC */
4428
4429 /* Reset to use for long read */
4430 reset_att_buf(client);
4431
4432 client->read_params.func = unicast_client_read_func;
4433 client->read_params.handle_count = 1U;
4434 client->read_params.single.handle = value_handle;
4435 client->read_params.single.offset = 0U;
4436
4437 err = bt_gatt_read(conn, &client->read_params);
4438 if (err != 0) {
4439 LOG_DBG("Failed to read PAC records: %d", err);
4440
4441 unicast_client_discover_complete(conn, err);
4442 }
4443
4444 return BT_GATT_ITER_STOP;
4445 }
4446
unicast_client_disconnected(struct bt_conn * conn,uint8_t reason)4447 static void unicast_client_disconnected(struct bt_conn *conn, uint8_t reason)
4448 {
4449 LOG_DBG("conn %p reason 0x%02x", conn, reason);
4450
4451 unicast_client_ep_reset(conn, reason);
4452 }
4453
4454 static struct bt_conn_cb conn_cbs = {
4455 .disconnected = unicast_client_disconnected,
4456 };
4457
bt_bap_unicast_client_discover(struct bt_conn * conn,enum bt_audio_dir dir)4458 int bt_bap_unicast_client_discover(struct bt_conn *conn, enum bt_audio_dir dir)
4459 {
4460 struct unicast_client *client;
4461 static bool conn_cb_registered;
4462 uint8_t role;
4463 int err;
4464
4465 if (!conn || conn->state != BT_CONN_CONNECTED) {
4466 return -ENOTCONN;
4467 }
4468
4469 role = conn->role;
4470 if (role != BT_HCI_ROLE_CENTRAL) {
4471 LOG_DBG("Invalid conn role: %u, shall be central", role);
4472 return -EINVAL;
4473 }
4474
4475 client = &uni_cli_insts[bt_conn_index(conn)];
4476 if (atomic_test_and_set_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY)) {
4477 LOG_DBG("Client connection is busy");
4478 return -EBUSY;
4479 }
4480
4481 if (dir == BT_AUDIO_DIR_SINK) {
4482 client->disc_params.uuid = snk_uuid;
4483 } else if (dir == BT_AUDIO_DIR_SOURCE) {
4484 client->disc_params.uuid = src_uuid;
4485 } else {
4486 return -EINVAL;
4487 }
4488
4489 client->disc_params.func = unicast_client_pac_discover_cb;
4490 client->disc_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
4491 client->disc_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
4492 client->disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
4493
4494 if (!conn_cb_registered) {
4495 bt_conn_cb_register(&conn_cbs);
4496 conn_cb_registered = true;
4497 }
4498
4499 err = bt_gatt_discover(conn, &client->disc_params);
4500 if (err != 0) {
4501 atomic_clear_bit(client->flags, UNICAST_CLIENT_FLAG_BUSY);
4502 return err;
4503 }
4504
4505 client->dir = dir;
4506
4507 return 0;
4508 }
4509
bt_bap_unicast_client_register_cb(struct bt_bap_unicast_client_cb * cb)4510 int bt_bap_unicast_client_register_cb(struct bt_bap_unicast_client_cb *cb)
4511 {
4512 CHECKIF(cb == NULL) {
4513 LOG_DBG("cb is NULL");
4514 return -EINVAL;
4515 }
4516
4517 if (sys_slist_find(&unicast_client_cbs, &cb->_node, NULL)) {
4518 return -EEXIST;
4519 }
4520
4521 sys_slist_append(&unicast_client_cbs, &cb->_node);
4522
4523 return 0;
4524 }
4525