1 /*
2 * Copyright (c) 2022-2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/sys/check.h>
8 #include <zephyr/bluetooth/gatt.h>
9 #include <zephyr/bluetooth/audio/audio.h>
10 #include <zephyr/bluetooth/audio/cap.h>
11 #include <zephyr/bluetooth/audio/tbs.h>
12 #include "cap_internal.h"
13 #include "csip_internal.h"
14 #include "bap_endpoint.h"
15
16 #include <zephyr/logging/log.h>
17
18 LOG_MODULE_REGISTER(bt_cap_initiator, CONFIG_BT_CAP_INITIATOR_LOG_LEVEL);
19
20 #include "common/bt_str.h"
21
22 static const struct bt_cap_initiator_cb *cap_cb;
23
bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb * cb)24 int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb)
25 {
26 CHECKIF(cb == NULL) {
27 LOG_DBG("cb is NULL");
28 return -EINVAL;
29 }
30
31 CHECKIF(cap_cb != NULL) {
32 LOG_DBG("callbacks already registered");
33 return -EALREADY;
34 }
35
36 cap_cb = cb;
37
38 return 0;
39 }
40
data_func_cb(struct bt_data * data,void * user_data)41 static bool data_func_cb(struct bt_data *data, void *user_data)
42 {
43 bool *stream_context_found = (bool *)user_data;
44
45 LOG_DBG("type %u len %u data %s", data->type, data->data_len,
46 bt_hex(data->data, data->data_len));
47
48 if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
49 if (data->data_len != 2) { /* Stream context size */
50 return false;
51 }
52
53 *stream_context_found = true;
54 return false;
55 }
56
57 return true;
58 }
59
cap_initiator_valid_metadata(const uint8_t meta[],size_t meta_len)60 static bool cap_initiator_valid_metadata(const uint8_t meta[], size_t meta_len)
61 {
62 bool stream_context_found = false;
63 int err;
64
65 LOG_DBG("meta %p len %zu", meta, meta_len);
66
67 err = bt_audio_data_parse(meta, meta_len, data_func_cb, &stream_context_found);
68 if (err != 0 && err != -ECANCELED) {
69 return false;
70 }
71
72 if (!stream_context_found) {
73 LOG_DBG("No streaming context supplied");
74 }
75
76 return stream_context_found;
77 }
78
79 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
80 static struct bt_cap_broadcast_source {
81 struct bt_bap_broadcast_source *bap_broadcast;
82 } broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
83
cap_initiator_broadcast_audio_start_valid_param(const struct bt_cap_initiator_broadcast_create_param * param)84 static bool cap_initiator_broadcast_audio_start_valid_param(
85 const struct bt_cap_initiator_broadcast_create_param *param)
86 {
87
88 for (size_t i = 0U; i < param->subgroup_count; i++) {
89 const struct bt_cap_initiator_broadcast_subgroup_param *subgroup_param;
90 const struct bt_audio_codec_cfg *codec_cfg;
91 bool valid_metadata;
92
93 subgroup_param = ¶m->subgroup_params[i];
94 codec_cfg = subgroup_param->codec_cfg;
95
96 /* Streaming Audio Context shall be present in CAP */
97
98 CHECKIF(codec_cfg == NULL) {
99 LOG_DBG("subgroup[%zu]->codec_cfg is NULL", i);
100 return false;
101 }
102
103 valid_metadata =
104 cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len);
105
106 CHECKIF(!valid_metadata) {
107 LOG_DBG("Invalid metadata supplied for subgroup[%zu]", i);
108 return false;
109 }
110 }
111
112 return true;
113 }
114
cap_initiator_broadcast_to_bap_broadcast_param(const struct bt_cap_initiator_broadcast_create_param * cap_param,struct bt_bap_broadcast_source_param * bap_param,struct bt_bap_broadcast_source_subgroup_param bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT],struct bt_bap_broadcast_source_stream_param bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT])115 static void cap_initiator_broadcast_to_bap_broadcast_param(
116 const struct bt_cap_initiator_broadcast_create_param *cap_param,
117 struct bt_bap_broadcast_source_param *bap_param,
118 struct bt_bap_broadcast_source_subgroup_param
119 bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT],
120 struct bt_bap_broadcast_source_stream_param
121 bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT])
122 {
123 size_t stream_cnt = 0U;
124
125 bap_param->params_count = cap_param->subgroup_count;
126 bap_param->params = bap_subgroup_params;
127 bap_param->qos = cap_param->qos;
128 bap_param->packing = cap_param->packing;
129 bap_param->encryption = cap_param->encryption;
130 if (bap_param->encryption) {
131 memcpy(bap_param->broadcast_code, cap_param->broadcast_code,
132 BT_AUDIO_BROADCAST_CODE_SIZE);
133 } else {
134 memset(bap_param->broadcast_code, 0, BT_AUDIO_BROADCAST_CODE_SIZE);
135 }
136
137 for (size_t i = 0U; i < bap_param->params_count; i++) {
138 const struct bt_cap_initiator_broadcast_subgroup_param *cap_subgroup_param =
139 &cap_param->subgroup_params[i];
140 struct bt_bap_broadcast_source_subgroup_param *bap_subgroup_param =
141 &bap_param->params[i];
142
143 bap_subgroup_param->codec_cfg = cap_subgroup_param->codec_cfg;
144 bap_subgroup_param->params_count = cap_subgroup_param->stream_count;
145 bap_subgroup_param->params = &bap_stream_params[stream_cnt];
146
147 for (size_t j = 0U; j < bap_subgroup_param->params_count; j++, stream_cnt++) {
148 const struct bt_cap_initiator_broadcast_stream_param *cap_stream_param =
149 &cap_subgroup_param->stream_params[j];
150 struct bt_bap_broadcast_source_stream_param *bap_stream_param =
151 &bap_subgroup_param->params[j];
152
153 bap_stream_param->stream = &cap_stream_param->stream->bap_stream;
154 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
155 bap_stream_param->data_len = cap_stream_param->data_len;
156 /* We do not need to copy the data, as that is the same type of struct, so
157 * we can just point to the CAP parameter data
158 */
159 bap_stream_param->data = cap_stream_param->data;
160 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
161 }
162 }
163 }
164
bt_cap_initiator_broadcast_audio_create(const struct bt_cap_initiator_broadcast_create_param * param,struct bt_cap_broadcast_source ** broadcast_source)165 int bt_cap_initiator_broadcast_audio_create(
166 const struct bt_cap_initiator_broadcast_create_param *param,
167 struct bt_cap_broadcast_source **broadcast_source)
168 {
169 struct bt_bap_broadcast_source_subgroup_param
170 bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
171 struct bt_bap_broadcast_source_stream_param
172 bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
173 struct bt_bap_broadcast_source_param bap_create_param;
174
175 CHECKIF(param == NULL) {
176 LOG_DBG("param is NULL");
177 return -EINVAL;
178 }
179
180 CHECKIF(broadcast_source == NULL) {
181 LOG_DBG("source is NULL");
182 return -EINVAL;
183 }
184
185 if (!cap_initiator_broadcast_audio_start_valid_param(param)) {
186 return -EINVAL;
187 }
188
189 for (size_t i = 0; i < ARRAY_SIZE(broadcast_sources); i++) {
190 if (broadcast_sources[i].bap_broadcast == NULL) {
191 *broadcast_source = &broadcast_sources[i];
192 break;
193 }
194 }
195
196 cap_initiator_broadcast_to_bap_broadcast_param(param, &bap_create_param,
197 bap_subgroup_params, bap_stream_params);
198
199 return bt_bap_broadcast_source_create(&bap_create_param,
200 &(*broadcast_source)->bap_broadcast);
201 }
202
bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source * broadcast_source,struct bt_le_ext_adv * adv)203 int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source,
204 struct bt_le_ext_adv *adv)
205 {
206 CHECKIF(adv == NULL) {
207 LOG_DBG("adv is NULL");
208 return -EINVAL;
209 }
210
211 CHECKIF(broadcast_source == NULL) {
212 LOG_DBG("broadcast_source is NULL");
213 return -EINVAL;
214 }
215
216 return bt_bap_broadcast_source_start(broadcast_source->bap_broadcast, adv);
217 }
218
bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source * broadcast_source,const uint8_t meta[],size_t meta_len)219 int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source,
220 const uint8_t meta[], size_t meta_len)
221 {
222 CHECKIF(broadcast_source == NULL) {
223 LOG_DBG("broadcast_source is NULL");
224 return -EINVAL;
225 }
226
227 CHECKIF(meta == NULL) {
228 LOG_DBG("meta is NULL");
229 return -EINVAL;
230 }
231
232 if (!cap_initiator_valid_metadata(meta, meta_len)) {
233 LOG_DBG("Invalid metadata");
234 return -EINVAL;
235 }
236
237 return bt_bap_broadcast_source_update_metadata(broadcast_source->bap_broadcast, meta,
238 meta_len);
239 }
240
bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source * broadcast_source)241 int bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source)
242 {
243 CHECKIF(broadcast_source == NULL) {
244 LOG_DBG("broadcast_source is NULL");
245 return -EINVAL;
246 }
247
248 return bt_bap_broadcast_source_stop(broadcast_source->bap_broadcast);
249 }
250
bt_cap_initiator_broadcast_audio_delete(struct bt_cap_broadcast_source * broadcast_source)251 int bt_cap_initiator_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source)
252 {
253 int err;
254
255 CHECKIF(broadcast_source == NULL) {
256 LOG_DBG("broadcast_source is NULL");
257 return -EINVAL;
258 }
259
260 err = bt_bap_broadcast_source_delete(broadcast_source->bap_broadcast);
261 if (err == 0) {
262 broadcast_source->bap_broadcast = NULL;
263 }
264
265 return err;
266 }
267
bt_cap_initiator_broadcast_get_id(const struct bt_cap_broadcast_source * broadcast_source,uint32_t * const broadcast_id)268 int bt_cap_initiator_broadcast_get_id(const struct bt_cap_broadcast_source *broadcast_source,
269 uint32_t *const broadcast_id)
270 {
271 CHECKIF(broadcast_source == NULL) {
272 LOG_DBG("broadcast_source is NULL");
273 return -EINVAL;
274 }
275
276 return bt_bap_broadcast_source_get_id(broadcast_source->bap_broadcast, broadcast_id);
277 }
278
bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source * broadcast_source,struct net_buf_simple * base_buf)279 int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcast_source,
280 struct net_buf_simple *base_buf)
281 {
282 CHECKIF(broadcast_source == NULL) {
283 LOG_DBG("broadcast_source is NULL");
284 return -EINVAL;
285 }
286
287 return bt_bap_broadcast_source_get_base(broadcast_source->bap_broadcast, base_buf);
288 }
289
290 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
291
292 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
293 enum {
294 CAP_UNICAST_PROC_STATE_ACTIVE,
295 CAP_UNICAST_PROC_STATE_ABORTED,
296
297 CAP_UNICAST_PROC_STATE_FLAG_NUM,
298 } cap_unicast_proc_state;
299
300 enum cap_unicast_proc_type {
301 CAP_UNICAST_PROC_TYPE_NONE,
302 CAP_UNICAST_PROC_TYPE_START,
303 CAP_UNICAST_PROC_TYPE_UPDATE,
304 CAP_UNICAST_PROC_TYPE_STOP,
305 };
306
307 enum cap_unicast_subproc_type {
308 CAP_UNICAST_SUBPROC_TYPE_NONE,
309 CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG,
310 CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG,
311 CAP_UNICAST_SUBPROC_TYPE_ENABLE,
312 CAP_UNICAST_SUBPROC_TYPE_START,
313 CAP_UNICAST_SUBPROC_TYPE_META_UPDATE,
314 CAP_UNICAST_SUBPROC_TYPE_RELEASE,
315 };
316
317 struct cap_unicast_proc_param {
318 struct bt_cap_stream *stream;
319 union {
320 struct {
321 struct bt_conn *conn;
322 struct bt_bap_ep *ep;
323 struct bt_audio_codec_cfg codec_cfg;
324 } start;
325 struct {
326 /** Codec Specific Capabilities Metadata count */
327 size_t meta_len;
328 /** Codec Specific Capabilities Metadata */
329 uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE];
330 } meta_update;
331 };
332 };
333
334 struct cap_unicast_proc {
335 ATOMIC_DEFINE(proc_state_flags, CAP_UNICAST_PROC_STATE_FLAG_NUM);
336 /* Total number of streams in the procedure*/
337 size_t stream_cnt;
338 /* Number of streams where a subprocedure have been started */
339 size_t stream_initiated_cnt;
340 /* Number of streams done with the procedure */
341 size_t stream_done_cnt;
342 enum cap_unicast_proc_type proc_type;
343 enum cap_unicast_subproc_type subproc_type;
344 int err;
345 struct bt_conn *failed_conn;
346 struct cap_unicast_proc_param proc_param[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT];
347 struct bt_bap_unicast_group *unicast_group;
348 };
349
350 struct cap_unicast_client {
351 struct bt_conn *conn;
352 struct bt_gatt_discover_params param;
353 uint16_t csis_start_handle;
354 const struct bt_csip_set_coordinator_csis_inst *csis_inst;
355 bool cas_found;
356 };
357
358 static struct cap_unicast_client bt_cap_unicast_clients[CONFIG_BT_MAX_CONN];
359 static const struct bt_uuid *cas_uuid = BT_UUID_CAS;
360 static struct cap_unicast_proc active_proc;
361
cap_set_subproc(enum cap_unicast_subproc_type subproc_type)362 static void cap_set_subproc(enum cap_unicast_subproc_type subproc_type)
363 {
364 active_proc.stream_done_cnt = 0U;
365 active_proc.stream_initiated_cnt = 0U;
366 active_proc.subproc_type = subproc_type;
367 }
368
cap_proc_is_active(void)369 static bool cap_proc_is_active(void)
370 {
371 return atomic_test_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE);
372 }
373
cap_proc_is_aborted(void)374 static bool cap_proc_is_aborted(void)
375 {
376 return atomic_test_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ABORTED);
377 }
378
cap_proc_all_streams_handled(void)379 static bool cap_proc_all_streams_handled(void)
380 {
381 return active_proc.stream_done_cnt == active_proc.stream_initiated_cnt;
382 }
383
cap_proc_is_done(void)384 static bool cap_proc_is_done(void)
385 {
386 return active_proc.stream_done_cnt == active_proc.stream_cnt;
387 }
388
cap_abort_proc(struct bt_conn * conn,int err)389 static void cap_abort_proc(struct bt_conn *conn, int err)
390 {
391 if (cap_proc_is_aborted()) {
392 /* no-op */
393 return;
394 }
395
396 active_proc.err = err;
397 active_proc.failed_conn = conn;
398 atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ABORTED);
399 }
400
cap_conn_in_active_proc(const struct bt_conn * conn)401 static bool cap_conn_in_active_proc(const struct bt_conn *conn)
402 {
403 if (!cap_proc_is_active()) {
404 return false;
405 }
406
407 for (size_t i = 0U; i < active_proc.stream_initiated_cnt; i++) {
408 if (active_proc.proc_param[i].stream->bap_stream.conn == conn) {
409 return true;
410 }
411 }
412
413 return false;
414 }
415
cap_initiator_disconnected(struct bt_conn * conn,uint8_t reason)416 static void cap_initiator_disconnected(struct bt_conn *conn, uint8_t reason)
417 {
418 struct cap_unicast_client *client;
419
420 client = &bt_cap_unicast_clients[bt_conn_index(conn)];
421
422 if (client->conn != NULL) {
423 bt_conn_unref(client->conn);
424 }
425 (void)memset(client, 0, sizeof(*client));
426
427 if (cap_conn_in_active_proc(conn)) {
428 cap_abort_proc(conn, -ENOTCONN);
429 }
430 }
431
432 BT_CONN_CB_DEFINE(conn_callbacks) = {
433 .disconnected = cap_initiator_disconnected,
434 };
435
lookup_unicast_client_by_csis(const struct bt_csip_set_coordinator_csis_inst * csis_inst)436 static struct cap_unicast_client *lookup_unicast_client_by_csis(
437 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
438 {
439 if (csis_inst == NULL) {
440 return NULL;
441 }
442
443 for (size_t i = 0U; i < ARRAY_SIZE(bt_cap_unicast_clients); i++) {
444 struct cap_unicast_client *client = &bt_cap_unicast_clients[i];
445
446 if (client->csis_inst == csis_inst) {
447 return client;
448 }
449 }
450
451 return NULL;
452 }
453
csis_client_discover_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_set_member * member,int err,size_t set_count)454 static void csis_client_discover_cb(struct bt_conn *conn,
455 const struct bt_csip_set_coordinator_set_member *member,
456 int err, size_t set_count)
457 {
458 struct cap_unicast_client *client;
459
460 if (err != 0) {
461 LOG_DBG("CSIS client discover failed: %d", err);
462
463 if (cap_cb && cap_cb->unicast_discovery_complete) {
464 cap_cb->unicast_discovery_complete(conn, err, NULL);
465 }
466
467 return;
468 }
469
470 client = &bt_cap_unicast_clients[bt_conn_index(conn)];
471 client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle(
472 conn, client->csis_start_handle);
473
474 if (member == NULL || set_count == 0 || client->csis_inst == NULL) {
475 LOG_ERR("Unable to find CSIS for CAS");
476
477 if (cap_cb && cap_cb->unicast_discovery_complete) {
478 cap_cb->unicast_discovery_complete(conn, -ENODATA,
479 NULL);
480 }
481 } else {
482 LOG_DBG("Found CAS with CSIS");
483 if (cap_cb && cap_cb->unicast_discovery_complete) {
484 cap_cb->unicast_discovery_complete(conn, 0,
485 client->csis_inst);
486 }
487 }
488 }
489
cap_unicast_discover_included_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)490 static uint8_t cap_unicast_discover_included_cb(struct bt_conn *conn,
491 const struct bt_gatt_attr *attr,
492 struct bt_gatt_discover_params *params)
493 {
494 params->func = NULL;
495
496 if (attr == NULL) {
497 LOG_DBG("CAS CSIS include not found");
498
499 if (cap_cb && cap_cb->unicast_discovery_complete) {
500 cap_cb->unicast_discovery_complete(conn, 0, NULL);
501 }
502 } else {
503 const struct bt_gatt_include *included_service = attr->user_data;
504 struct cap_unicast_client *client = CONTAINER_OF(params,
505 struct cap_unicast_client,
506 param);
507
508 /* If the remote CAS includes CSIS, we first check if we
509 * have already discovered it, and if so we can just retrieve it
510 * and forward it to the application. If not, then we start
511 * CSIS discovery
512 */
513 client->csis_start_handle = included_service->start_handle;
514 client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle(
515 conn, client->csis_start_handle);
516
517 if (client->csis_inst == NULL) {
518 static struct bt_csip_set_coordinator_cb csis_client_cb = {
519 .discover = csis_client_discover_cb
520 };
521 static bool csis_cbs_registered;
522 int err;
523
524 LOG_DBG("CAS CSIS not known, discovering");
525
526 if (!csis_cbs_registered) {
527 bt_csip_set_coordinator_register_cb(&csis_client_cb);
528 csis_cbs_registered = true;
529 }
530
531 err = bt_csip_set_coordinator_discover(conn);
532 if (err != 0) {
533 LOG_DBG("Discover failed (err %d)", err);
534 if (cap_cb && cap_cb->unicast_discovery_complete) {
535 cap_cb->unicast_discovery_complete(conn,
536 err,
537 NULL);
538 }
539 }
540 } else if (cap_cb && cap_cb->unicast_discovery_complete) {
541 LOG_DBG("Found CAS with CSIS");
542 cap_cb->unicast_discovery_complete(conn, 0,
543 client->csis_inst);
544 }
545 }
546
547 return BT_GATT_ITER_STOP;
548 }
549
cap_unicast_discover_cas_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)550 static uint8_t cap_unicast_discover_cas_cb(struct bt_conn *conn,
551 const struct bt_gatt_attr *attr,
552 struct bt_gatt_discover_params *params)
553 {
554 params->func = NULL;
555
556 if (attr == NULL) {
557 if (cap_cb && cap_cb->unicast_discovery_complete) {
558 cap_cb->unicast_discovery_complete(conn, -ENODATA,
559 NULL);
560 }
561 } else {
562 const struct bt_gatt_service_val *prim_service = attr->user_data;
563 struct cap_unicast_client *client = CONTAINER_OF(params,
564 struct cap_unicast_client,
565 param);
566 int err;
567
568 client->cas_found = true;
569 client->conn = bt_conn_ref(conn);
570
571 if (attr->handle == prim_service->end_handle) {
572 LOG_DBG("Found CAS without CSIS");
573 cap_cb->unicast_discovery_complete(conn, 0, NULL);
574
575 return BT_GATT_ITER_STOP;
576 }
577
578 LOG_DBG("Found CAS, discovering included CSIS");
579
580 params->uuid = NULL;
581 params->start_handle = attr->handle + 1;
582 params->end_handle = prim_service->end_handle;
583 params->type = BT_GATT_DISCOVER_INCLUDE;
584 params->func = cap_unicast_discover_included_cb;
585
586 err = bt_gatt_discover(conn, params);
587 if (err != 0) {
588 LOG_DBG("Discover failed (err %d)", err);
589
590 params->func = NULL;
591 if (cap_cb && cap_cb->unicast_discovery_complete) {
592 cap_cb->unicast_discovery_complete(conn, err,
593 NULL);
594 }
595 }
596 }
597
598 return BT_GATT_ITER_STOP;
599 }
600
bt_cap_initiator_unicast_discover(struct bt_conn * conn)601 int bt_cap_initiator_unicast_discover(struct bt_conn *conn)
602 {
603 struct bt_gatt_discover_params *param;
604 int err;
605
606 CHECKIF(conn == NULL) {
607 LOG_DBG("NULL conn");
608 return -EINVAL;
609 }
610
611 param = &bt_cap_unicast_clients[bt_conn_index(conn)].param;
612
613 /* use param->func to tell if a client is "busy" */
614 if (param->func != NULL) {
615 return -EBUSY;
616 }
617
618 param->func = cap_unicast_discover_cas_cb;
619 param->uuid = cas_uuid;
620 param->type = BT_GATT_DISCOVER_PRIMARY;
621 param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
622 param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
623
624 err = bt_gatt_discover(conn, param);
625 if (err != 0) {
626 param->func = NULL;
627 }
628
629 return err;
630 }
631
cap_stream_in_active_proc(const struct bt_cap_stream * cap_stream)632 static bool cap_stream_in_active_proc(const struct bt_cap_stream *cap_stream)
633 {
634 if (!cap_proc_is_active()) {
635 return false;
636 }
637
638 for (size_t i = 0U; i < active_proc.stream_cnt; i++) {
639 if (active_proc.proc_param[i].stream == cap_stream) {
640 return true;
641 }
642 }
643
644 return false;
645 }
646
valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param * param,struct bt_bap_unicast_group * unicast_group)647 static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param,
648 struct bt_bap_unicast_group *unicast_group)
649 {
650 CHECKIF(param == NULL) {
651 LOG_DBG("param is NULL");
652 return false;
653 }
654
655 CHECKIF(param->count == 0) {
656 LOG_DBG("Invalid param->count: %u", param->count);
657 return false;
658 }
659
660 CHECKIF(param->stream_params == NULL) {
661 LOG_DBG("param->stream_params is NULL");
662 return false;
663 }
664
665 CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
666 LOG_DBG("param->count (%zu) is larger than "
667 "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)",
668 param->count,
669 CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT);
670 return false;
671 }
672
673 for (size_t i = 0U; i < param->count; i++) {
674 const struct bt_cap_unicast_audio_start_stream_param *stream_param =
675 ¶m->stream_params[i];
676 const union bt_cap_set_member *member = &stream_param->member;
677 const struct bt_cap_stream *cap_stream = stream_param->stream;
678 const struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg;
679 const struct bt_bap_stream *bap_stream;
680
681 CHECKIF(stream_param->codec_cfg == NULL) {
682 LOG_DBG("param->stream_params[%zu].codec_cfg is NULL", i);
683 return false;
684 }
685
686 CHECKIF(!cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len)) {
687 LOG_DBG("param->stream_params[%zu].codec_cfg is invalid", i);
688 return false;
689 }
690
691 CHECKIF(stream_param->ep == NULL) {
692 LOG_DBG("param->stream_params[%zu].ep is NULL", i);
693 return false;
694 }
695
696 CHECKIF(member == NULL) {
697 LOG_DBG("param->stream_params[%zu].member is NULL", i);
698 return false;
699 }
700
701 if (param->type == BT_CAP_SET_TYPE_AD_HOC) {
702 struct cap_unicast_client *client;
703
704 CHECKIF(member->member == NULL) {
705 LOG_DBG("param->members[%zu] is NULL", i);
706 return false;
707 }
708
709 client = &bt_cap_unicast_clients[bt_conn_index(member->member)];
710
711 if (!client->cas_found) {
712 LOG_DBG("CAS was not found for param->members[%zu]", i);
713 return false;
714 }
715 }
716
717 if (param->type == BT_CAP_SET_TYPE_CSIP) {
718 struct cap_unicast_client *client;
719
720 CHECKIF(member->csip == NULL) {
721 LOG_DBG("param->csip.set[%zu] is NULL", i);
722 return false;
723 }
724
725 client = lookup_unicast_client_by_csis(member->csip);
726 if (client == NULL) {
727 LOG_DBG("CSIS was not found for param->members[%zu]", i);
728 return false;
729 }
730 }
731
732 CHECKIF(cap_stream == NULL) {
733 LOG_DBG("param->streams[%zu] is NULL", i);
734 return false;
735 }
736
737 bap_stream = &cap_stream->bap_stream;
738
739 CHECKIF(bap_stream->ep != NULL) {
740 LOG_DBG("param->streams[%zu] is already started", i);
741 return false;
742 }
743
744 CHECKIF(bap_stream->group == NULL) {
745 LOG_DBG("param->streams[%zu] is not in a unicast group", i);
746 return false;
747 }
748
749 CHECKIF(bap_stream->group != unicast_group) {
750 LOG_DBG("param->streams[%zu] is not in this group %p", i, unicast_group);
751 return false;
752 }
753
754 for (size_t j = 0U; j < i; j++) {
755 if (param->stream_params[j].stream == cap_stream) {
756 LOG_DBG("param->stream_params[%zu] (%p) is "
757 "duplicated by "
758 "param->stream_params[%zu] (%p)",
759 j, param->stream_params[j].stream,
760 i, cap_stream);
761 return false;
762 }
763 }
764 }
765
766 return true;
767 }
768
cap_initiator_unicast_audio_proc_complete(void)769 static void cap_initiator_unicast_audio_proc_complete(void)
770 {
771 struct bt_bap_unicast_group *unicast_group;
772 enum cap_unicast_proc_type proc_type;
773 struct bt_conn *failed_conn;
774 int err;
775
776 unicast_group = active_proc.unicast_group;
777 failed_conn = active_proc.failed_conn;
778 err = active_proc.err;
779 proc_type = active_proc.proc_type;
780 (void)memset(&active_proc, 0, sizeof(active_proc));
781
782 if (cap_cb == NULL) {
783 return;
784 }
785
786 switch (proc_type) {
787 case CAP_UNICAST_PROC_TYPE_START:
788 if (cap_cb->unicast_start_complete != NULL) {
789 cap_cb->unicast_start_complete(unicast_group, err, failed_conn);
790 }
791 break;
792 case CAP_UNICAST_PROC_TYPE_UPDATE:
793 if (cap_cb->unicast_update_complete != NULL) {
794 cap_cb->unicast_update_complete(err, failed_conn);
795 }
796 break;
797 case CAP_UNICAST_PROC_TYPE_STOP:
798 if (cap_cb->unicast_stop_complete != NULL) {
799 cap_cb->unicast_stop_complete(unicast_group, err, failed_conn);
800 }
801 break;
802 case CAP_UNICAST_PROC_TYPE_NONE:
803 default:
804 __ASSERT(false, "Invalid proc_type: %u", proc_type);
805 }
806 }
807
cap_initiator_unicast_audio_configure(const struct bt_cap_unicast_audio_start_param * param)808 static int cap_initiator_unicast_audio_configure(
809 const struct bt_cap_unicast_audio_start_param *param)
810 {
811 struct cap_unicast_proc_param *proc_param;
812 struct bt_audio_codec_cfg *codec_cfg;
813 struct bt_bap_stream *bap_stream;
814 struct bt_bap_ep *ep;
815 struct bt_conn *conn;
816 int err;
817 /** TODO: If this is a CSIP set, then the order of the procedures may
818 * not match the order in the parameters, and the CSIP ordered access
819 * procedure should be used.
820 */
821
822 for (size_t i = 0U; i < param->count; i++) {
823 struct bt_cap_unicast_audio_start_stream_param *stream_param =
824 ¶m->stream_params[i];
825 union bt_cap_set_member *member = &stream_param->member;
826 struct bt_cap_stream *cap_stream = stream_param->stream;
827
828 if (param->type == BT_CAP_SET_TYPE_AD_HOC) {
829 conn = member->member;
830 } else {
831 struct cap_unicast_client *client;
832
833 /* We have verified that `client` wont be NULL in
834 * `valid_unicast_audio_start_param`.
835 */
836 client = lookup_unicast_client_by_csis(member->csip);
837 __ASSERT(client != NULL, "client is NULL");
838 conn = client->conn;
839 }
840
841 /* Ensure that ops are registered before any procedures are started */
842 bt_cap_stream_ops_register_bap(cap_stream);
843
844 /* Store the necessary parameters as we cannot assume that the supplied parameters
845 * are kept valid
846 */
847 active_proc.proc_param[i].stream = cap_stream;
848 active_proc.proc_param[i].start.ep = stream_param->ep;
849 active_proc.proc_param[i].start.conn = conn;
850 memcpy(&active_proc.proc_param[i].start.codec_cfg, stream_param->codec_cfg,
851 sizeof(*stream_param->codec_cfg));
852 }
853
854 /* Store the information about the active procedure so that we can
855 * continue the procedure after each step
856 */
857 atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE);
858 active_proc.stream_cnt = param->count;
859
860 cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG);
861
862 proc_param = &active_proc.proc_param[0];
863 bap_stream = &proc_param->stream->bap_stream;
864 codec_cfg = &proc_param->start.codec_cfg;
865 conn = proc_param->start.conn;
866 ep = proc_param->start.ep;
867
868 /* Since BAP operations may require a write long or a read long on the notification,
869 * we cannot assume that we can do multiple streams at once, thus do it one at a time.
870 * TODO: We should always be able to do one per ACL, so there is room for optimization.
871 */
872 err = bt_bap_stream_config(conn, bap_stream, ep, codec_cfg);
873 if (err != 0) {
874 LOG_DBG("Failed to config stream %p: %d", proc_param->stream, err);
875
876 (void)memset(&active_proc, 0, sizeof(active_proc));
877 } else {
878 active_proc.stream_initiated_cnt++;
879 }
880
881 return err;
882 }
883
bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param * param,struct bt_bap_unicast_group * unicast_group)884 int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param,
885 struct bt_bap_unicast_group *unicast_group)
886 {
887 if (cap_proc_is_active()) {
888 LOG_DBG("A CAP procedure is already in progress");
889
890 return -EBUSY;
891 }
892
893 CHECKIF(unicast_group == NULL) {
894 LOG_DBG("unicast_group is NULL");
895 return -EINVAL;
896 }
897
898 if (!valid_unicast_audio_start_param(param, unicast_group)) {
899 return -EINVAL;
900 }
901
902 active_proc.unicast_group = unicast_group;
903 active_proc.proc_type = CAP_UNICAST_PROC_TYPE_START;
904
905 return cap_initiator_unicast_audio_configure(param);
906 }
907
bt_cap_initiator_codec_configured(struct bt_cap_stream * cap_stream)908 void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream)
909 {
910 struct bt_conn
911 *conns[MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT)];
912 struct cap_unicast_proc_param *proc_param;
913 struct bt_bap_unicast_group *unicast_group;
914
915 if (!cap_stream_in_active_proc(cap_stream)) {
916 /* State change happened outside of a procedure; ignore */
917 return;
918 }
919
920 if (active_proc.subproc_type == CAP_UNICAST_SUBPROC_TYPE_RELEASE) {
921 /* When releasing a stream, it may go into the codec configured state if
922 * the unicast server caches the configuration - We treat it as a release
923 */
924 bt_cap_initiator_released(cap_stream);
925 return;
926 } else if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG) {
927 /* Unexpected callback - Abort */
928 cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
929 } else {
930 active_proc.stream_done_cnt++;
931
932 LOG_DBG("Stream %p configured (%zu/%zu streams done)", cap_stream,
933 active_proc.stream_done_cnt, active_proc.stream_cnt);
934 }
935
936 if (cap_proc_is_aborted()) {
937 if (cap_proc_all_streams_handled()) {
938 cap_initiator_unicast_audio_proc_complete();
939 }
940
941 return;
942 }
943
944 if (!cap_proc_is_done()) {
945 struct bt_cap_stream *next_cap_stream =
946 active_proc.proc_param[active_proc.stream_done_cnt].stream;
947 struct bt_conn *conn =
948 active_proc.proc_param[active_proc.stream_done_cnt].start.conn;
949 struct bt_bap_ep *ep = active_proc.proc_param[active_proc.stream_done_cnt].start.ep;
950 struct bt_audio_codec_cfg *codec_cfg =
951 &active_proc.proc_param[active_proc.stream_done_cnt].start.codec_cfg;
952 struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream;
953 int err;
954
955 /* Since BAP operations may require a write long or a read long on the notification,
956 * we cannot assume that we can do multiple streams at once, thus do it one at a
957 * time.
958 * TODO: We should always be able to do one per ACL, so there is room for
959 * optimization.
960 */
961 err = bt_bap_stream_config(conn, bap_stream, ep, codec_cfg);
962 if (err != 0) {
963 LOG_DBG("Failed to config stream %p: %d", next_cap_stream, err);
964
965 cap_abort_proc(conn, err);
966 cap_initiator_unicast_audio_proc_complete();
967 } else {
968 active_proc.stream_initiated_cnt++;
969 }
970
971 return;
972 }
973
974 /* The QoS Configure procedure works on a set of connections and a
975 * unicast group, so we generate a list of unique connection pointers
976 * for the procedure
977 */
978 (void)memset(conns, 0, sizeof(conns));
979 for (size_t i = 0U; i < active_proc.stream_cnt; i++) {
980 struct bt_conn *stream_conn = active_proc.proc_param[i].stream->bap_stream.conn;
981 struct bt_conn **free_conn = NULL;
982 bool already_added = false;
983
984 for (size_t j = 0U; j < ARRAY_SIZE(conns); j++) {
985 if (stream_conn == conns[j]) {
986 already_added = true;
987 break;
988 } else if (conns[j] == NULL && free_conn == NULL) {
989 free_conn = &conns[j];
990 }
991 }
992
993 if (already_added) {
994 continue;
995 }
996
997 if (free_conn != NULL) {
998 *free_conn = stream_conn;
999 } else {
1000 __ASSERT_PRINT("No free conns");
1001 }
1002 }
1003
1004 /* All streams in the procedure share the same unicast group, so we just
1005 * use the reference from the first stream
1006 */
1007 proc_param = &active_proc.proc_param[0];
1008 unicast_group = (struct bt_bap_unicast_group *)proc_param->stream->bap_stream.group;
1009 cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG);
1010
1011 for (size_t i = 0U; i < ARRAY_SIZE(conns); i++) {
1012 int err;
1013
1014 /* When conns[i] is NULL, we have QoS Configured all unique connections */
1015 if (conns[i] == NULL) {
1016 break;
1017 }
1018
1019 err = bt_bap_stream_qos(conns[i], unicast_group);
1020 if (err != 0) {
1021 LOG_DBG("Failed to set stream QoS for conn %p and group %p: %d",
1022 (void *)conns[i], unicast_group, err);
1023
1024 /* End or mark procedure as aborted.
1025 * If we have sent any requests over air, we will abort
1026 * once all sent requests has completed
1027 */
1028 cap_abort_proc(conns[i], err);
1029 if (i == 0U) {
1030 cap_initiator_unicast_audio_proc_complete();
1031 }
1032
1033 return;
1034 }
1035
1036 active_proc.stream_initiated_cnt++;
1037 }
1038 }
1039
bt_cap_initiator_qos_configured(struct bt_cap_stream * cap_stream)1040 void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream)
1041 {
1042 struct cap_unicast_proc_param *proc_param;
1043 struct bt_cap_stream *next_cap_stream;
1044 struct bt_bap_stream *bap_stream;
1045 int err;
1046
1047 if (!cap_stream_in_active_proc(cap_stream)) {
1048 /* State change happened outside of a procedure; ignore */
1049 return;
1050 }
1051
1052 if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG) {
1053 /* Unexpected callback - Abort */
1054 cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1055 } else {
1056 active_proc.stream_done_cnt++;
1057
1058 LOG_DBG("Stream %p QoS configured (%zu/%zu streams done)", cap_stream,
1059 active_proc.stream_done_cnt, active_proc.stream_cnt);
1060 }
1061
1062 if (cap_proc_is_aborted()) {
1063 if (cap_proc_all_streams_handled()) {
1064 cap_initiator_unicast_audio_proc_complete();
1065 }
1066
1067 return;
1068 }
1069
1070 if (!cap_proc_is_done()) {
1071 /* Not yet finished, wait for all */
1072 return;
1073 }
1074
1075 cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_ENABLE);
1076 proc_param = &active_proc.proc_param[0];
1077 next_cap_stream = proc_param->stream;
1078 bap_stream = &next_cap_stream->bap_stream;
1079
1080 /* Since BAP operations may require a write long or a read long on the notification, we
1081 * cannot assume that we can do multiple streams at once, thus do it one at a time.
1082 * TODO: We should always be able to do one per ACL, so there is room for optimization.
1083 */
1084 err = bt_bap_stream_enable(bap_stream, bap_stream->codec_cfg->meta,
1085 bap_stream->codec_cfg->meta_len);
1086 if (err != 0) {
1087 LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err);
1088
1089 cap_abort_proc(bap_stream->conn, err);
1090 cap_initiator_unicast_audio_proc_complete();
1091 } else {
1092 active_proc.stream_initiated_cnt++;
1093 }
1094 }
1095
bt_cap_initiator_enabled(struct bt_cap_stream * cap_stream)1096 void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream)
1097 {
1098 struct cap_unicast_proc_param *proc_param;
1099 struct bt_bap_stream *bap_stream;
1100 int err;
1101
1102 if (!cap_stream_in_active_proc(cap_stream)) {
1103 /* State change happened outside of a procedure; ignore */
1104 return;
1105 }
1106
1107 if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_ENABLE) {
1108 /* Unexpected callback - Abort */
1109 cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1110 } else {
1111 active_proc.stream_done_cnt++;
1112
1113 LOG_DBG("Stream %p enabled (%zu/%zu streams done)", cap_stream,
1114 active_proc.stream_done_cnt, active_proc.stream_cnt);
1115 }
1116
1117 if (cap_proc_is_aborted()) {
1118 if (cap_proc_all_streams_handled()) {
1119 cap_initiator_unicast_audio_proc_complete();
1120 }
1121
1122 return;
1123 }
1124
1125 if (!cap_proc_is_done()) {
1126 struct bt_cap_stream *next_cap_stream =
1127 active_proc.proc_param[active_proc.stream_done_cnt].stream;
1128 struct bt_bap_stream *next_bap_stream = &next_cap_stream->bap_stream;
1129
1130 /* Since BAP operations may require a write long or a read long on the notification,
1131 * we cannot assume that we can do multiple streams at once, thus do it one at a
1132 * time.
1133 * TODO: We should always be able to do one per ACL, so there is room for
1134 * optimization.
1135 */
1136 err = bt_bap_stream_enable(next_bap_stream, next_bap_stream->codec_cfg->meta,
1137 next_bap_stream->codec_cfg->meta_len);
1138 if (err != 0) {
1139 LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err);
1140
1141 cap_abort_proc(next_bap_stream->conn, err);
1142 cap_initiator_unicast_audio_proc_complete();
1143 } else {
1144 active_proc.stream_initiated_cnt++;
1145 }
1146
1147 return;
1148 }
1149
1150 cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_START);
1151 proc_param = &active_proc.proc_param[0];
1152 bap_stream = &proc_param->stream->bap_stream;
1153
1154 /* Since BAP operations may require a write long or a read long on the notification, we
1155 * cannot assume that we can do multiple streams at once, thus do it one at a time.
1156 * TODO: We should always be able to do one per ACL, so there is room for optimization.
1157 */
1158 err = bt_bap_stream_start(bap_stream);
1159 if (err != 0) {
1160 LOG_DBG("Failed to start stream %p: %d", proc_param->stream, err);
1161
1162 /* End and mark procedure as aborted.
1163 * If we have sent any requests over air, we will abort
1164 * once all sent requests has completed
1165 */
1166 cap_abort_proc(bap_stream->conn, err);
1167 cap_initiator_unicast_audio_proc_complete();
1168
1169 return;
1170 }
1171 }
1172
bt_cap_initiator_started(struct bt_cap_stream * cap_stream)1173 void bt_cap_initiator_started(struct bt_cap_stream *cap_stream)
1174 {
1175 if (!cap_stream_in_active_proc(cap_stream)) {
1176 /* State change happened outside of a procedure; ignore */
1177 return;
1178 }
1179
1180 if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_START) {
1181 /* Unexpected callback - Abort */
1182 cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1183 } else {
1184 active_proc.stream_done_cnt++;
1185
1186 LOG_DBG("Stream %p started (%zu/%zu streams done)",
1187 cap_stream, active_proc.stream_done_cnt,
1188 active_proc.stream_cnt);
1189 }
1190
1191 /* Since bt_bap_stream_start connects the ISO, we can, at this point,
1192 * only do this one by one due to a restriction in the ISO layer
1193 * (maximum 1 outstanding ISO connection request at any one time).
1194 */
1195 if (!cap_proc_is_done()) {
1196 struct bt_cap_stream *next_cap_stream =
1197 active_proc.proc_param[active_proc.stream_done_cnt].stream;
1198 struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream;
1199 int err;
1200
1201 /* Not yet finished, start next */
1202 err = bt_bap_stream_start(bap_stream);
1203 if (err != 0) {
1204 LOG_DBG("Failed to start stream %p: %d", next_cap_stream, err);
1205
1206 /* End and mark procedure as aborted.
1207 * If we have sent any requests over air, we will abort
1208 * once all sent requests has completed
1209 */
1210 cap_abort_proc(bap_stream->conn, err);
1211 cap_initiator_unicast_audio_proc_complete();
1212 }
1213 } else {
1214 cap_initiator_unicast_audio_proc_complete();
1215 }
1216 }
1217
can_update_metadata(const struct bt_bap_stream * bap_stream)1218 static bool can_update_metadata(const struct bt_bap_stream *bap_stream)
1219 {
1220 struct bt_bap_ep_info ep_info;
1221 int err;
1222
1223 if (bap_stream->conn == NULL) {
1224 return false;
1225 }
1226
1227 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
1228 if (err != 0) {
1229 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
1230
1231 return false;
1232 }
1233
1234 return ep_info.state == BT_BAP_EP_STATE_ENABLING ||
1235 ep_info.state == BT_BAP_EP_STATE_STREAMING;
1236 }
1237
bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[],size_t count)1238 int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[],
1239 size_t count)
1240 {
1241 struct cap_unicast_proc_param *proc_param;
1242 struct bt_bap_stream *bap_stream;
1243 const uint8_t *meta;
1244 size_t meta_len;
1245 int err;
1246
1247 CHECKIF(params == NULL) {
1248 LOG_DBG("params is NULL");
1249
1250 return -EINVAL;
1251 }
1252
1253 CHECKIF(count == 0) {
1254 LOG_DBG("count is 0");
1255
1256 return -EINVAL;
1257 }
1258
1259 if (cap_proc_is_active()) {
1260 LOG_DBG("A CAP procedure is already in progress");
1261
1262 return -EBUSY;
1263 }
1264
1265 for (size_t i = 0U; i < count; i++) {
1266 struct bt_cap_stream *cap_stream = params[i].stream;
1267
1268 CHECKIF(cap_stream == NULL) {
1269 LOG_DBG("params[%zu].stream is NULL", i);
1270
1271 return -EINVAL;
1272 }
1273
1274 CHECKIF(cap_stream->bap_stream.conn == NULL) {
1275 LOG_DBG("params[%zu].stream->bap_stream.conn is NULL", i);
1276
1277 return -EINVAL;
1278 }
1279
1280 CHECKIF(!cap_initiator_valid_metadata(params[i].meta,
1281 params[i].meta_len)) {
1282 LOG_DBG("params[%zu].meta is invalid", i);
1283
1284 return -EINVAL;
1285 }
1286
1287 for (size_t j = 0U; j < i; j++) {
1288 if (params[j].stream == cap_stream) {
1289 LOG_DBG("param.streams[%zu] is duplicated by param.streams[%zu]",
1290 j, i);
1291 return -EINVAL;
1292 }
1293 }
1294
1295 if (!can_update_metadata(&cap_stream->bap_stream)) {
1296 LOG_DBG("params[%zu].stream is not in right state to be updated", i);
1297
1298 return -EINVAL;
1299 }
1300
1301 active_proc.proc_param[i].stream = cap_stream;
1302 active_proc.proc_param[i].meta_update.meta_len = params[i].meta_len;
1303 memcpy(&active_proc.proc_param[i].meta_update.meta, params[i].meta,
1304 params[i].meta_len);
1305 }
1306
1307 atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE);
1308 active_proc.stream_cnt = count;
1309
1310 active_proc.proc_type = CAP_UNICAST_PROC_TYPE_UPDATE;
1311 cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_META_UPDATE);
1312
1313 proc_param = &active_proc.proc_param[0];
1314 bap_stream = &proc_param->stream->bap_stream;
1315 meta_len = proc_param->meta_update.meta_len;
1316 meta = proc_param->meta_update.meta;
1317
1318 err = bt_bap_stream_metadata(bap_stream, meta, meta_len);
1319 if (err != 0) {
1320 LOG_DBG("Failed to update metadata for stream %p: %d", proc_param->stream, err);
1321
1322 (void)memset(&active_proc, 0, sizeof(active_proc));
1323 } else {
1324 active_proc.stream_initiated_cnt++;
1325 }
1326
1327 return err;
1328 }
1329
bt_cap_initiator_unicast_audio_cancel(void)1330 int bt_cap_initiator_unicast_audio_cancel(void)
1331 {
1332 if (!cap_proc_is_active() && !cap_proc_is_aborted()) {
1333 LOG_DBG("No CAP procedure is in progress");
1334
1335 return -EALREADY;
1336 }
1337
1338 cap_abort_proc(NULL, -ECANCELED);
1339 cap_initiator_unicast_audio_proc_complete();
1340
1341 return 0;
1342 }
1343
bt_cap_initiator_metadata_updated(struct bt_cap_stream * cap_stream)1344 void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream)
1345 {
1346 if (!cap_stream_in_active_proc(cap_stream)) {
1347 /* State change happened outside of a procedure; ignore */
1348 return;
1349 }
1350
1351 if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_META_UPDATE) {
1352 /* Unexpected callback - Abort */
1353 cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1354 } else {
1355 active_proc.stream_done_cnt++;
1356
1357 LOG_DBG("Stream %p QoS metadata updated (%zu/%zu streams done)",
1358 cap_stream, active_proc.stream_done_cnt,
1359 active_proc.stream_cnt);
1360 }
1361
1362 if (cap_proc_is_aborted()) {
1363 if (cap_proc_all_streams_handled()) {
1364 cap_initiator_unicast_audio_proc_complete();
1365 }
1366
1367 return;
1368 }
1369
1370 if (!cap_proc_is_done()) {
1371 const size_t meta_len =
1372 active_proc.proc_param[active_proc.stream_done_cnt].meta_update.meta_len;
1373 const uint8_t *meta =
1374 active_proc.proc_param[active_proc.stream_done_cnt].meta_update.meta;
1375 struct bt_cap_stream *next_cap_stream =
1376 active_proc.proc_param[active_proc.stream_done_cnt].stream;
1377 struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream;
1378 int err;
1379
1380 /* Since BAP operations may require a write long or a read long on the notification,
1381 * we cannot assume that we can do multiple streams at once, thus do it one at a
1382 * time.
1383 * TODO: We should always be able to do one per ACL, so there is room for
1384 * optimization.
1385 */
1386
1387 err = bt_bap_stream_metadata(bap_stream, meta, meta_len);
1388 if (err != 0) {
1389 LOG_DBG("Failed to update metadata for stream %p: %d", next_cap_stream,
1390 err);
1391
1392 cap_abort_proc(bap_stream->conn, err);
1393 cap_initiator_unicast_audio_proc_complete();
1394 } else {
1395 active_proc.stream_initiated_cnt++;
1396 }
1397
1398 return;
1399 }
1400
1401 cap_initiator_unicast_audio_proc_complete();
1402 }
1403
can_release(const struct bt_bap_stream * bap_stream)1404 static bool can_release(const struct bt_bap_stream *bap_stream)
1405 {
1406 struct bt_bap_ep_info ep_info;
1407 int err;
1408
1409 if (bap_stream->conn == NULL) {
1410 return false;
1411 }
1412
1413 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
1414 if (err != 0) {
1415 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
1416
1417 return false;
1418 }
1419
1420 return ep_info.state != BT_BAP_EP_STATE_IDLE;
1421 }
1422
bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group * unicast_group)1423 int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group)
1424 {
1425 struct cap_unicast_proc_param *proc_param;
1426 struct bt_bap_stream *bap_stream;
1427 size_t stream_cnt;
1428 int err;
1429
1430 if (cap_proc_is_active()) {
1431 LOG_DBG("A CAP procedure is already in progress");
1432
1433 return -EBUSY;
1434 }
1435
1436 CHECKIF(unicast_group == NULL) {
1437 LOG_DBG("unicast_group is NULL");
1438 return -EINVAL;
1439 }
1440
1441 stream_cnt = 0U;
1442 SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, bap_stream, _node) {
1443 if (can_release(bap_stream)) {
1444 struct bt_cap_stream *cap_stream =
1445 CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
1446 active_proc.proc_param[stream_cnt].stream = cap_stream;
1447 stream_cnt++;
1448 }
1449 }
1450
1451 if (stream_cnt == 0U) {
1452 LOG_DBG("All streams are already stopped");
1453
1454 return -EALREADY;
1455 }
1456
1457 atomic_set_bit(active_proc.proc_state_flags,
1458 CAP_UNICAST_PROC_STATE_ACTIVE);
1459 active_proc.stream_cnt = stream_cnt;
1460 active_proc.unicast_group = unicast_group;
1461 active_proc.proc_type = CAP_UNICAST_PROC_TYPE_STOP;
1462
1463 cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_RELEASE);
1464
1465 /** TODO: If this is a CSIP set, then the order of the procedures may
1466 * not match the order in the parameters, and the CSIP ordered access
1467 * procedure should be used.
1468 */
1469 proc_param = &active_proc.proc_param[0];
1470 bap_stream = &proc_param->stream->bap_stream;
1471
1472 err = bt_bap_stream_release(bap_stream);
1473 if (err != 0) {
1474 LOG_DBG("Failed to stop bap_stream %p: %d", proc_param->stream, err);
1475
1476 (void)memset(&active_proc, 0, sizeof(active_proc));
1477 } else {
1478 active_proc.stream_initiated_cnt++;
1479 }
1480
1481 return err;
1482 }
1483
bt_cap_initiator_released(struct bt_cap_stream * cap_stream)1484 void bt_cap_initiator_released(struct bt_cap_stream *cap_stream)
1485 {
1486 if (!cap_stream_in_active_proc(cap_stream)) {
1487 /* State change happened outside of a procedure; ignore */
1488 return;
1489 }
1490
1491 if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_RELEASE) {
1492 /* Unexpected callback - Abort */
1493 cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1494 } else {
1495 active_proc.stream_done_cnt++;
1496
1497 LOG_DBG("Stream %p released (%zu/%zu streams done)",
1498 cap_stream, active_proc.stream_done_cnt,
1499 active_proc.stream_cnt);
1500 }
1501
1502 if (cap_proc_is_aborted()) {
1503 if (cap_proc_all_streams_handled()) {
1504 cap_initiator_unicast_audio_proc_complete();
1505 }
1506
1507 return;
1508 }
1509
1510 if (!cap_proc_is_done()) {
1511 struct bt_cap_stream *next_cap_stream =
1512 active_proc.proc_param[active_proc.stream_done_cnt].stream;
1513 struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream;
1514 int err;
1515
1516 /* Since BAP operations may require a write long or a read long on the notification,
1517 * we cannot assume that we can do multiple streams at once, thus do it one at a
1518 * time.
1519 * TODO: We should always be able to do one per ACL, so there is room for
1520 * optimization.
1521 */
1522 err = bt_bap_stream_release(bap_stream);
1523 if (err != 0) {
1524 LOG_DBG("Failed to release stream %p: %d", next_cap_stream, err);
1525
1526 cap_abort_proc(bap_stream->conn, err);
1527 cap_initiator_unicast_audio_proc_complete();
1528 } else {
1529 active_proc.stream_initiated_cnt++;
1530 }
1531 } else {
1532 cap_initiator_unicast_audio_proc_complete();
1533 }
1534 }
1535
1536 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1537
1538 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)
1539
bt_cap_initiator_unicast_to_broadcast(const struct bt_cap_unicast_to_broadcast_param * param,struct bt_cap_broadcast_source ** source)1540 int bt_cap_initiator_unicast_to_broadcast(
1541 const struct bt_cap_unicast_to_broadcast_param *param,
1542 struct bt_cap_broadcast_source **source)
1543 {
1544 return -ENOSYS;
1545 }
1546
bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param * param,struct bt_bap_unicast_group ** unicast_group)1547 int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param *param,
1548 struct bt_bap_unicast_group **unicast_group)
1549 {
1550 return -ENOSYS;
1551 }
1552
1553 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE && CONFIG_BT_BAP_UNICAST_CLIENT */
1554