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