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