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