1 /*
2 * Copyright (c) 2022-2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12
13 #include <zephyr/autoconf.h>
14 #include <zephyr/bluetooth/audio/audio.h>
15 #include <zephyr/bluetooth/audio/bap.h>
16 #include <zephyr/bluetooth/audio/cap.h>
17 #include <zephyr/bluetooth/audio/ccid.h>
18 #include <zephyr/bluetooth/audio/csip.h>
19 #include <zephyr/bluetooth/audio/tbs.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/gatt.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/logging/log.h>
25 #include <zephyr/net_buf.h>
26 #include <zephyr/sys/__assert.h>
27 #include <zephyr/sys/check.h>
28 #include <zephyr/sys/util.h>
29 #include <zephyr/sys/util_macro.h>
30 #include <sys/errno.h>
31
32 #include "bap_endpoint.h"
33 #include "cap_internal.h"
34 #include "csip_internal.h"
35
36 LOG_MODULE_REGISTER(bt_cap_initiator, CONFIG_BT_CAP_INITIATOR_LOG_LEVEL);
37
38 #include "common/bt_str.h"
39
40 static const struct bt_cap_initiator_cb *cap_cb;
41
bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb * cb)42 int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb)
43 {
44 CHECKIF(cb == NULL) {
45 LOG_DBG("cb is NULL");
46 return -EINVAL;
47 }
48
49 CHECKIF(cap_cb != NULL) {
50 LOG_DBG("callbacks already registered");
51 return -EALREADY;
52 }
53
54 cap_cb = cb;
55
56 return 0;
57 }
58
bt_cap_initiator_unregister_cb(const struct bt_cap_initiator_cb * cb)59 int bt_cap_initiator_unregister_cb(const struct bt_cap_initiator_cb *cb)
60 {
61 CHECKIF(cb == NULL) {
62 LOG_DBG("cb is NULL");
63 return -EINVAL;
64 }
65
66 CHECKIF(cap_cb != cb) {
67 LOG_DBG("cb is not registered");
68 return -EINVAL;
69 }
70
71 cap_cb = NULL;
72
73 return 0;
74 }
75
76 struct valid_metadata_param {
77 bool stream_context_found;
78 bool valid;
79 };
80
data_func_cb(struct bt_data * data,void * user_data)81 static bool data_func_cb(struct bt_data *data, void *user_data)
82 {
83 struct valid_metadata_param *metadata_param = (struct valid_metadata_param *)user_data;
84
85 LOG_DBG("type %u len %u data %s", data->type, data->data_len,
86 bt_hex(data->data, data->data_len));
87
88 if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
89 if (data->data_len != 2) { /* Stream context size */
90 return false;
91 }
92
93 metadata_param->stream_context_found = true;
94 } else if (IS_ENABLED(CONFIG_BT_CONN) && data->type == BT_AUDIO_METADATA_TYPE_CCID_LIST) {
95 /* If the application supplies a CCID list, we verify that the CCIDs exist on our
96 * device
97 * This is guarded by CONFIG_BT_CONN as without that we do not have a GATT DB to
98 * check.
99 */
100 for (uint8_t i = 0U; i < data->data_len; i++) {
101 const uint8_t ccid = data->data[i];
102 if (bt_ccid_find_attr(ccid) == NULL) {
103 LOG_DBG("Unknown characteristic for CCID 0x%02X", ccid);
104 metadata_param->valid = false;
105
106 return false;
107 }
108 }
109 }
110
111 return true;
112 }
113
cap_initiator_valid_metadata(const uint8_t meta[],size_t meta_len)114 static bool cap_initiator_valid_metadata(const uint8_t meta[], size_t meta_len)
115 {
116 struct valid_metadata_param metadata_param = {
117 .stream_context_found = false,
118 .valid = true,
119 };
120 int err;
121
122 LOG_DBG("meta %p len %zu", (void *)meta, meta_len);
123
124 err = bt_audio_data_parse(meta, meta_len, data_func_cb, &metadata_param);
125 if (err != 0 && err != -ECANCELED) {
126 return false;
127 }
128
129 if (!metadata_param.stream_context_found) {
130 LOG_DBG("No streaming context supplied");
131 }
132
133 return metadata_param.stream_context_found && metadata_param.valid;
134 }
135
136 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
137 static struct bt_cap_broadcast_source {
138 struct bt_bap_broadcast_source *bap_broadcast;
139 } broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
140
cap_initiator_broadcast_audio_start_valid_param(const struct bt_cap_initiator_broadcast_create_param * param)141 static bool cap_initiator_broadcast_audio_start_valid_param(
142 const struct bt_cap_initiator_broadcast_create_param *param)
143 {
144
145 for (size_t i = 0U; i < param->subgroup_count; i++) {
146 const struct bt_cap_initiator_broadcast_subgroup_param *subgroup_param;
147 const struct bt_audio_codec_cfg *codec_cfg;
148 bool valid_metadata;
149
150 subgroup_param = ¶m->subgroup_params[i];
151 codec_cfg = subgroup_param->codec_cfg;
152
153 /* Streaming Audio Context shall be present in CAP */
154
155 CHECKIF(codec_cfg == NULL) {
156 LOG_DBG("subgroup[%zu]->codec_cfg is NULL", i);
157 return false;
158 }
159
160 valid_metadata =
161 cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len);
162
163 CHECKIF(!valid_metadata) {
164 LOG_DBG("Invalid metadata supplied for subgroup[%zu]", i);
165 return false;
166 }
167 }
168
169 return true;
170 }
171
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])172 static void cap_initiator_broadcast_to_bap_broadcast_param(
173 const struct bt_cap_initiator_broadcast_create_param *cap_param,
174 struct bt_bap_broadcast_source_param *bap_param,
175 struct bt_bap_broadcast_source_subgroup_param
176 bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT],
177 struct bt_bap_broadcast_source_stream_param
178 bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT])
179 {
180 size_t stream_cnt = 0U;
181
182 bap_param->params_count = cap_param->subgroup_count;
183 bap_param->params = bap_subgroup_params;
184 bap_param->qos = cap_param->qos;
185 bap_param->packing = cap_param->packing;
186 bap_param->encryption = cap_param->encryption;
187 if (bap_param->encryption) {
188 memcpy(bap_param->broadcast_code, cap_param->broadcast_code,
189 BT_ISO_BROADCAST_CODE_SIZE);
190 } else {
191 memset(bap_param->broadcast_code, 0, BT_ISO_BROADCAST_CODE_SIZE);
192 }
193
194 for (size_t i = 0U; i < bap_param->params_count; i++) {
195 const struct bt_cap_initiator_broadcast_subgroup_param *cap_subgroup_param =
196 &cap_param->subgroup_params[i];
197 struct bt_bap_broadcast_source_subgroup_param *bap_subgroup_param =
198 &bap_param->params[i];
199
200 bap_subgroup_param->codec_cfg = cap_subgroup_param->codec_cfg;
201 bap_subgroup_param->params_count = cap_subgroup_param->stream_count;
202 bap_subgroup_param->params = &bap_stream_params[stream_cnt];
203
204 for (size_t j = 0U; j < bap_subgroup_param->params_count; j++, stream_cnt++) {
205 const struct bt_cap_initiator_broadcast_stream_param *cap_stream_param =
206 &cap_subgroup_param->stream_params[j];
207 struct bt_bap_broadcast_source_stream_param *bap_stream_param =
208 &bap_subgroup_param->params[j];
209
210 bap_stream_param->stream = &cap_stream_param->stream->bap_stream;
211 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
212 bap_stream_param->data_len = cap_stream_param->data_len;
213 /* We do not need to copy the data, as that is the same type of struct, so
214 * we can just point to the CAP parameter data
215 */
216 bap_stream_param->data = cap_stream_param->data;
217 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
218 }
219 }
220 }
221
bt_cap_initiator_broadcast_audio_create(const struct bt_cap_initiator_broadcast_create_param * param,struct bt_cap_broadcast_source ** broadcast_source)222 int bt_cap_initiator_broadcast_audio_create(
223 const struct bt_cap_initiator_broadcast_create_param *param,
224 struct bt_cap_broadcast_source **broadcast_source)
225 {
226 struct bt_bap_broadcast_source_subgroup_param
227 bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
228 struct bt_bap_broadcast_source_stream_param
229 bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
230 struct bt_bap_broadcast_source_param bap_create_param = {0};
231
232 CHECKIF(param == NULL) {
233 LOG_DBG("param is NULL");
234 return -EINVAL;
235 }
236
237 CHECKIF(broadcast_source == NULL) {
238 LOG_DBG("source is NULL");
239 return -EINVAL;
240 }
241
242 if (!cap_initiator_broadcast_audio_start_valid_param(param)) {
243 return -EINVAL;
244 }
245
246 for (size_t i = 0; i < ARRAY_SIZE(broadcast_sources); i++) {
247 if (broadcast_sources[i].bap_broadcast == NULL) {
248 *broadcast_source = &broadcast_sources[i];
249 break;
250 }
251 }
252
253 cap_initiator_broadcast_to_bap_broadcast_param(param, &bap_create_param,
254 bap_subgroup_params, bap_stream_params);
255
256 return bt_bap_broadcast_source_create(&bap_create_param,
257 &(*broadcast_source)->bap_broadcast);
258 }
259
get_cap_broadcast_source_by_bap_broadcast_source(const struct bt_bap_broadcast_source * bap_broadcast_source)260 static struct bt_cap_broadcast_source *get_cap_broadcast_source_by_bap_broadcast_source(
261 const struct bt_bap_broadcast_source *bap_broadcast_source)
262 {
263 for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources); i++) {
264 if (broadcast_sources[i].bap_broadcast == bap_broadcast_source) {
265 return &broadcast_sources[i];
266 }
267 }
268
269 return NULL;
270 }
271
broadcast_source_started_cb(struct bt_bap_broadcast_source * bap_broadcast_source)272 static void broadcast_source_started_cb(struct bt_bap_broadcast_source *bap_broadcast_source)
273 {
274 if (cap_cb && cap_cb->broadcast_started) {
275 struct bt_cap_broadcast_source *source =
276 get_cap_broadcast_source_by_bap_broadcast_source(bap_broadcast_source);
277
278 if (source == NULL) {
279 /* Not one of ours */
280 return;
281 }
282
283 cap_cb->broadcast_started(source);
284 }
285 }
286
broadcast_source_stopped_cb(struct bt_bap_broadcast_source * bap_broadcast_source,uint8_t reason)287 static void broadcast_source_stopped_cb(struct bt_bap_broadcast_source *bap_broadcast_source,
288 uint8_t reason)
289 {
290 if (cap_cb && cap_cb->broadcast_stopped) {
291 struct bt_cap_broadcast_source *source =
292 get_cap_broadcast_source_by_bap_broadcast_source(bap_broadcast_source);
293
294 if (source == NULL) {
295 /* Not one of ours */
296 return;
297 }
298
299 cap_cb->broadcast_stopped(source, reason);
300 }
301 }
302
bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source * broadcast_source,struct bt_le_ext_adv * adv)303 int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source,
304 struct bt_le_ext_adv *adv)
305 {
306 static bool broadcast_source_cbs_registered;
307
308 CHECKIF(adv == NULL) {
309 LOG_DBG("adv is NULL");
310 return -EINVAL;
311 }
312
313 CHECKIF(broadcast_source == NULL) {
314 LOG_DBG("broadcast_source is NULL");
315 return -EINVAL;
316 }
317
318 if (!broadcast_source_cbs_registered) {
319 static struct bt_bap_broadcast_source_cb broadcast_source_cb = {
320 .started = broadcast_source_started_cb,
321 .stopped = broadcast_source_stopped_cb,
322 };
323 const int err = bt_bap_broadcast_source_register_cb(&broadcast_source_cb);
324
325 if (err != 0) {
326 __ASSERT(false, "Failed to register BAP broadcast source callbacks: %d",
327 err);
328 }
329
330 broadcast_source_cbs_registered = true;
331 }
332
333 return bt_bap_broadcast_source_start(broadcast_source->bap_broadcast, adv);
334 }
335
bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source * broadcast_source,const uint8_t meta[],size_t meta_len)336 int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source,
337 const uint8_t meta[], size_t meta_len)
338 {
339 CHECKIF(broadcast_source == NULL) {
340 LOG_DBG("broadcast_source is NULL");
341 return -EINVAL;
342 }
343
344 CHECKIF(meta == NULL) {
345 LOG_DBG("meta is NULL");
346 return -EINVAL;
347 }
348
349 if (!cap_initiator_valid_metadata(meta, meta_len)) {
350 LOG_DBG("Invalid metadata");
351 return -EINVAL;
352 }
353
354 return bt_bap_broadcast_source_update_metadata(broadcast_source->bap_broadcast, meta,
355 meta_len);
356 }
357
bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source * broadcast_source)358 int bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source)
359 {
360 CHECKIF(broadcast_source == NULL) {
361 LOG_DBG("broadcast_source is NULL");
362 return -EINVAL;
363 }
364
365 return bt_bap_broadcast_source_stop(broadcast_source->bap_broadcast);
366 }
367
bt_cap_initiator_broadcast_audio_delete(struct bt_cap_broadcast_source * broadcast_source)368 int bt_cap_initiator_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source)
369 {
370 int err;
371
372 CHECKIF(broadcast_source == NULL) {
373 LOG_DBG("broadcast_source is NULL");
374 return -EINVAL;
375 }
376
377 err = bt_bap_broadcast_source_delete(broadcast_source->bap_broadcast);
378 if (err == 0) {
379 broadcast_source->bap_broadcast = NULL;
380 }
381
382 return err;
383 }
384
bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source * broadcast_source,struct net_buf_simple * base_buf)385 int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcast_source,
386 struct net_buf_simple *base_buf)
387 {
388 CHECKIF(broadcast_source == NULL) {
389 LOG_DBG("broadcast_source is NULL");
390 return -EINVAL;
391 }
392
393 return bt_bap_broadcast_source_get_base(broadcast_source->bap_broadcast, base_buf);
394 }
395
396 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
397
398 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
399
stream_get_state(const struct bt_bap_stream * bap_stream)400 static enum bt_bap_ep_state stream_get_state(const struct bt_bap_stream *bap_stream)
401 {
402 struct bt_bap_ep_info ep_info;
403 int err;
404
405 if (bap_stream->ep == NULL) {
406 return BT_BAP_EP_STATE_IDLE;
407 }
408
409 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
410 if (err != 0) {
411 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
412
413 return BT_BAP_EP_STATE_IDLE;
414 }
415
416 return ep_info.state;
417 }
418
stream_is_in_state(const struct bt_bap_stream * bap_stream,enum bt_bap_ep_state state)419 static bool stream_is_in_state(const struct bt_bap_stream *bap_stream, enum bt_bap_ep_state state)
420 {
421 if (bap_stream->conn == NULL) {
422 return state == BT_BAP_EP_STATE_IDLE;
423 }
424
425 return stream_get_state(bap_stream) == state;
426 }
427
stream_is_dir(const struct bt_bap_stream * bap_stream,enum bt_audio_dir dir)428 static bool stream_is_dir(const struct bt_bap_stream *bap_stream, enum bt_audio_dir dir)
429 {
430 struct bt_bap_ep_info ep_info;
431 int err;
432
433 if (bap_stream->conn == NULL) {
434 return false;
435 }
436
437 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
438 if (err != 0) {
439 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
440
441 return false;
442 }
443
444 return ep_info.dir == dir;
445 }
446
bap_stream_get_iso_state(const struct bt_bap_stream * bap_stream)447 static enum bt_iso_state bap_stream_get_iso_state(const struct bt_bap_stream *bap_stream)
448 {
449 struct bt_bap_ep_info ep_info;
450 int err;
451
452 if (bap_stream->ep == NULL) {
453 return BT_ISO_STATE_DISCONNECTED;
454 }
455
456 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
457 if (err != 0) {
458 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
459
460 return BT_ISO_STATE_DISCONNECTED;
461 }
462
463 if (ep_info.iso_chan == NULL) {
464 return BT_ISO_STATE_DISCONNECTED;
465 }
466
467 return ep_info.iso_chan->state;
468 }
469
iso_is_in_state(const struct bt_cap_stream * cap_stream,enum bt_iso_state state)470 static bool iso_is_in_state(const struct bt_cap_stream *cap_stream, enum bt_iso_state state)
471 {
472 const struct bt_bap_stream *bap_stream = &cap_stream->bap_stream;
473
474 return bap_stream_get_iso_state(bap_stream) == state;
475 }
476
set_cap_stream_in_progress(struct bt_cap_stream * cap_stream,bool value)477 static void set_cap_stream_in_progress(struct bt_cap_stream *cap_stream, bool value)
478 {
479 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
480
481 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
482 if (cap_stream == active_proc->proc_param.initiator[i].stream) {
483 active_proc->proc_param.initiator[i].in_progress = value;
484 return;
485 }
486 }
487
488 __ASSERT(false, "CAP stream %p not in active_proc", cap_stream);
489 }
490
491 /**
492 * @brief Gets the next stream for the active procedure.
493 *
494 * Returns NULL if all streams are in the right state for the current step
495 */
496 static struct bt_cap_initiator_proc_param *
get_proc_param_by_cap_stream(struct bt_cap_common_proc * active_proc,const struct bt_cap_stream * cap_stream)497 get_proc_param_by_cap_stream(struct bt_cap_common_proc *active_proc,
498 const struct bt_cap_stream *cap_stream)
499 {
500 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
501 if (active_proc->proc_param.initiator[i].stream == cap_stream) {
502 return &active_proc->proc_param.initiator[i];
503 }
504 }
505
506 return NULL;
507 }
508
update_proc_done_cnt(struct bt_cap_common_proc * active_proc)509 static void update_proc_done_cnt(struct bt_cap_common_proc *active_proc)
510 {
511 const enum bt_cap_common_subproc_type subproc_type = active_proc->subproc_type;
512 const enum bt_cap_common_proc_type proc_type = active_proc->proc_type;
513 size_t proc_done_cnt = 0U;
514
515 if (proc_type == BT_CAP_COMMON_PROC_TYPE_START) {
516 /* To support state changes by the server, we cannot rely simply on the number of
517 * BAP procedures we have initiated. For the start and stop CAP procedures we use
518 * the states to determine how far we are.
519 */
520 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
521 struct bt_cap_initiator_proc_param *proc_param;
522 struct bt_cap_stream *cap_stream;
523 struct bt_bap_stream *bap_stream;
524 enum bt_bap_ep_state state;
525
526 proc_param = &active_proc->proc_param.initiator[i];
527 cap_stream = proc_param->stream;
528 bap_stream = &cap_stream->bap_stream;
529
530 state = stream_get_state(bap_stream);
531
532 switch (subproc_type) {
533 case BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG:
534 if (state > BT_BAP_EP_STATE_IDLE) {
535 proc_done_cnt++;
536 }
537 break;
538 case BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG:
539 if (state > BT_BAP_EP_STATE_CODEC_CONFIGURED) {
540 proc_done_cnt++;
541 } else if (state < BT_BAP_EP_STATE_CODEC_CONFIGURED) {
542 /* Unexpected state - Abort */
543 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
544 }
545 break;
546 case BT_CAP_COMMON_SUBPROC_TYPE_ENABLE:
547 if (state > BT_BAP_EP_STATE_QOS_CONFIGURED) {
548 proc_done_cnt++;
549 } else if (state < BT_BAP_EP_STATE_QOS_CONFIGURED) {
550 /* Unexpected state - Abort */
551 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
552 }
553 break;
554 case BT_CAP_COMMON_SUBPROC_TYPE_CONNECT:
555 if (state < BT_BAP_EP_STATE_ENABLING) {
556 /* Unexpected state - Abort */
557 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
558 } else if (proc_param->start.connected) {
559 proc_done_cnt++;
560 }
561 break;
562 case BT_CAP_COMMON_SUBPROC_TYPE_START:
563 if (state > BT_BAP_EP_STATE_ENABLING) {
564 proc_done_cnt++;
565 } else if (state < BT_BAP_EP_STATE_ENABLING ||
566 !iso_is_in_state(cap_stream, BT_ISO_STATE_CONNECTED)) {
567 /* Unexpected state - Abort */
568 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
569 }
570 break;
571 default:
572 __ASSERT(false, "Invalid subproc %d for %d", subproc_type,
573 proc_type);
574 }
575 }
576 } else if (proc_type == BT_CAP_COMMON_PROC_TYPE_STOP) {
577 /* To support state changes by the server, we cannot rely simply on the number of
578 * BAP procedures we have initiated. For the start and stop CAP procedures we use
579 * the states to determine how far we are.
580 */
581 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
582 struct bt_cap_initiator_proc_param *proc_param;
583 struct bt_cap_stream *cap_stream;
584 struct bt_bap_stream *bap_stream;
585 enum bt_bap_ep_state state;
586
587 proc_param = &active_proc->proc_param.initiator[i];
588 cap_stream = proc_param->stream;
589 bap_stream = &cap_stream->bap_stream;
590
591 state = stream_get_state(bap_stream);
592
593 switch (subproc_type) {
594 case BT_CAP_COMMON_SUBPROC_TYPE_DISABLE:
595 if (state == BT_BAP_EP_STATE_QOS_CONFIGURED ||
596 state == BT_BAP_EP_STATE_DISABLING) {
597 proc_done_cnt++;
598 }
599 break;
600 case BT_CAP_COMMON_SUBPROC_TYPE_STOP:
601 if (state == BT_BAP_EP_STATE_QOS_CONFIGURED) {
602 proc_done_cnt++;
603 }
604 break;
605 case BT_CAP_COMMON_SUBPROC_TYPE_RELEASE:
606 if (state == BT_BAP_EP_STATE_IDLE ||
607 state == BT_BAP_EP_STATE_CODEC_CONFIGURED) {
608 proc_done_cnt++;
609 }
610 break;
611 default:
612 __ASSERT(false, "Invalid subproc %d for %d", subproc_type,
613 proc_type);
614 }
615 }
616 } else if (proc_type == BT_CAP_COMMON_PROC_TYPE_UPDATE) {
617 /* For metadata we cannot check the states for all streams, as it does not trigger a
618 * state change
619 */
620 struct bt_cap_initiator_proc_param *proc_param;
621 struct bt_cap_stream *cap_stream;
622 struct bt_bap_stream *bap_stream;
623 enum bt_bap_ep_state state;
624
625 proc_param = &active_proc->proc_param.initiator[active_proc->proc_done_cnt];
626 cap_stream = proc_param->stream;
627 bap_stream = &cap_stream->bap_stream;
628
629 state = stream_get_state(bap_stream);
630
631 switch (subproc_type) {
632 case BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE:
633 if (state == BT_BAP_EP_STATE_ENABLING ||
634 state == BT_BAP_EP_STATE_STREAMING) {
635 proc_done_cnt = active_proc->proc_done_cnt + 1U;
636 } else {
637 /* Unexpected state - Abort */
638 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
639 }
640 break;
641 default:
642 __ASSERT(false, "Invalid subproc %d for %d", subproc_type, proc_type);
643 }
644 }
645
646 active_proc->proc_done_cnt = proc_done_cnt;
647
648 LOG_DBG("proc %d subproc %d: %zu/%zu", proc_type, subproc_type, active_proc->proc_done_cnt,
649 active_proc->proc_cnt);
650 }
651
652 /**
653 * @brief Gets the next stream for the active procedure.
654 *
655 * Returns NULL if all streams are in the right state for the current step
656 */
657 static struct bt_cap_initiator_proc_param *
get_next_proc_param(struct bt_cap_common_proc * active_proc)658 get_next_proc_param(struct bt_cap_common_proc *active_proc)
659 {
660 const enum bt_cap_common_subproc_type subproc_type = active_proc->subproc_type;
661
662 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
663 struct bt_cap_initiator_proc_param *proc_param;
664 struct bt_cap_stream *cap_stream;
665 struct bt_bap_stream *bap_stream;
666 enum bt_bap_ep_state state;
667
668 proc_param = &active_proc->proc_param.initiator[i];
669
670 if (proc_param->in_progress) {
671 continue;
672 }
673
674 cap_stream = proc_param->stream;
675 bap_stream = &cap_stream->bap_stream;
676 state = stream_get_state(bap_stream);
677
678 switch (subproc_type) {
679 case BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG:
680 if (state == BT_BAP_EP_STATE_IDLE) {
681 return proc_param;
682 }
683 break;
684 case BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG:
685 if (state == BT_BAP_EP_STATE_CODEC_CONFIGURED) {
686 return proc_param;
687 }
688 break;
689 case BT_CAP_COMMON_SUBPROC_TYPE_ENABLE:
690 if (state == BT_BAP_EP_STATE_QOS_CONFIGURED) {
691 return proc_param;
692 }
693 break;
694 case BT_CAP_COMMON_SUBPROC_TYPE_CONNECT:
695 if (state == BT_BAP_EP_STATE_ENABLING && !proc_param->start.connected) {
696 return proc_param;
697 }
698 break;
699 case BT_CAP_COMMON_SUBPROC_TYPE_START:
700 if (state == BT_BAP_EP_STATE_ENABLING) {
701 /* TODO: Add check for connected */
702 return proc_param;
703 }
704 break;
705 case BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE:
706 if (state == BT_BAP_EP_STATE_ENABLING ||
707 state == BT_BAP_EP_STATE_STREAMING) {
708 return proc_param;
709 }
710 break;
711 case BT_CAP_COMMON_SUBPROC_TYPE_DISABLE:
712 if (state == BT_BAP_EP_STATE_ENABLING ||
713 state == BT_BAP_EP_STATE_STREAMING) {
714 return proc_param;
715 }
716 break;
717 case BT_CAP_COMMON_SUBPROC_TYPE_STOP:
718 if (state == BT_BAP_EP_STATE_DISABLING) {
719 return proc_param;
720 }
721 break;
722 case BT_CAP_COMMON_SUBPROC_TYPE_RELEASE:
723 if (proc_param->stop.release && state != BT_BAP_EP_STATE_IDLE &&
724 state != BT_BAP_EP_STATE_CODEC_CONFIGURED) {
725 return proc_param;
726 }
727 break;
728 default:
729 break;
730 }
731 }
732
733 return NULL;
734 }
735
736 static void
bt_cap_initiator_discover_complete(struct bt_conn * conn,int err,const struct bt_csip_set_coordinator_set_member * member,const struct bt_csip_set_coordinator_csis_inst * csis_inst)737 bt_cap_initiator_discover_complete(struct bt_conn *conn, int err,
738 const struct bt_csip_set_coordinator_set_member *member,
739 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
740 {
741 if (cap_cb && cap_cb->unicast_discovery_complete) {
742 cap_cb->unicast_discovery_complete(conn, err, member, csis_inst);
743 }
744 }
745
bt_cap_initiator_unicast_discover(struct bt_conn * conn)746 int bt_cap_initiator_unicast_discover(struct bt_conn *conn)
747 {
748 CHECKIF(conn == NULL) {
749 LOG_DBG("NULL conn");
750 return -EINVAL;
751 }
752
753 return bt_cap_common_discover(conn, bt_cap_initiator_discover_complete);
754 }
755
valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param * param)756 static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param)
757 {
758 struct bt_bap_unicast_group *unicast_group = NULL;
759
760 CHECKIF(param == NULL) {
761 LOG_DBG("param is NULL");
762 return false;
763 }
764
765 CHECKIF(param->count == 0) {
766 LOG_DBG("Invalid param->count: %u", param->count);
767 return false;
768 }
769
770 CHECKIF(param->stream_params == NULL) {
771 LOG_DBG("param->stream_params is NULL");
772 return false;
773 }
774
775 CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
776 LOG_DBG("param->count (%zu) is larger than "
777 "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)",
778 param->count,
779 CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT);
780 return false;
781 }
782
783 for (size_t i = 0U; i < param->count; i++) {
784 const struct bt_cap_unicast_audio_start_stream_param *stream_param =
785 ¶m->stream_params[i];
786 const union bt_cap_set_member *member = &stream_param->member;
787 const struct bt_cap_stream *cap_stream = stream_param->stream;
788 const struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg;
789 const struct bt_bap_stream *bap_stream;
790 const struct bt_conn *member_conn =
791 bt_cap_common_get_member_conn(param->type, member);
792
793 if (member == NULL) {
794 LOG_DBG("param->members[%zu] is NULL", i);
795 return false;
796 }
797
798 if (member_conn == NULL) {
799 LOG_DBG("Invalid param->members[%zu]", i);
800 return false;
801 }
802
803 CHECKIF(stream_param->codec_cfg == NULL) {
804 LOG_DBG("param->stream_params[%zu].codec_cfg is NULL", i);
805 return false;
806 }
807
808 CHECKIF(!cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len)) {
809 LOG_DBG("param->stream_params[%zu].codec_cfg is invalid", i);
810 return false;
811 }
812
813 CHECKIF(stream_param->ep == NULL) {
814 LOG_DBG("param->stream_params[%zu].ep is NULL", i);
815 return false;
816 }
817
818 CHECKIF(member == NULL) {
819 LOG_DBG("param->stream_params[%zu].member is NULL", i);
820 return false;
821 }
822
823 CHECKIF(cap_stream == NULL) {
824 LOG_DBG("param->streams[%zu] is NULL", i);
825 return false;
826 }
827
828 bap_stream = &cap_stream->bap_stream;
829
830 CHECKIF(bap_stream->group == NULL) {
831 LOG_DBG("param->streams[%zu] is not in a unicast group", i);
832 return false;
833 }
834
835 /* Use the group of the first stream for comparison */
836 if (unicast_group == NULL) {
837 unicast_group = bap_stream->group;
838 } else {
839 CHECKIF(bap_stream->group != unicast_group) {
840 LOG_DBG("param->streams[%zu] is not in this group %p", i,
841 unicast_group);
842 return false;
843 }
844 }
845
846 for (size_t j = 0U; j < i; j++) {
847 if (param->stream_params[j].stream == cap_stream) {
848 LOG_DBG("param->stream_params[%zu] (%p) is "
849 "duplicated by "
850 "param->stream_params[%zu] (%p)",
851 j, param->stream_params[j].stream,
852 i, cap_stream);
853 return false;
854 }
855 }
856 }
857
858 return true;
859 }
860
cap_initiator_unicast_audio_proc_complete(void)861 static void cap_initiator_unicast_audio_proc_complete(void)
862 {
863 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
864 enum bt_cap_common_proc_type proc_type;
865 struct bt_conn *failed_conn;
866 int err;
867
868 failed_conn = active_proc->failed_conn;
869 err = active_proc->err;
870 proc_type = active_proc->proc_type;
871 bt_cap_common_clear_active_proc();
872
873 if (cap_cb == NULL) {
874 return;
875 }
876
877 switch (proc_type) {
878 case BT_CAP_COMMON_PROC_TYPE_START:
879 if (cap_cb->unicast_start_complete != NULL) {
880 cap_cb->unicast_start_complete(err, failed_conn);
881 }
882 break;
883 case BT_CAP_COMMON_PROC_TYPE_UPDATE:
884 if (cap_cb->unicast_update_complete != NULL) {
885 cap_cb->unicast_update_complete(err, failed_conn);
886 }
887 break;
888 case BT_CAP_COMMON_PROC_TYPE_STOP:
889 if (cap_cb->unicast_stop_complete != NULL) {
890 cap_cb->unicast_stop_complete(err, failed_conn);
891 }
892 break;
893 case BT_CAP_COMMON_PROC_TYPE_NONE:
894 default:
895 __ASSERT(false, "Invalid proc_type: %u", proc_type);
896 }
897 }
898
bt_cap_initiator_cp_cb(struct bt_cap_stream * cap_stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)899 void bt_cap_initiator_cp_cb(struct bt_cap_stream *cap_stream, enum bt_bap_ascs_rsp_code rsp_code,
900 enum bt_bap_ascs_reason reason)
901 {
902 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
903 /* State change happened outside of a procedure; ignore */
904 return;
905 }
906
907 LOG_DBG("cap_stream %p", cap_stream);
908
909 set_cap_stream_in_progress(cap_stream, false);
910
911 if (rsp_code != BT_BAP_ASCS_RSP_CODE_SUCCESS) {
912 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
913
914 /* In the case that the control point write is rejected, we will not get a ASE state
915 * change notification. This is considered an error that shall abort the current
916 * procedure.
917 */
918 active_proc->proc_done_cnt++;
919
920 LOG_DBG("Control point operation on stream %p failed with %d and reason %d",
921 cap_stream, rsp_code, reason);
922
923 /* Unexpected callback - Abort */
924 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
925
926 if (bt_cap_common_proc_is_aborted()) {
927 if (bt_cap_common_proc_all_handled()) {
928 cap_initiator_unicast_audio_proc_complete();
929 }
930
931 return;
932 }
933 }
934 }
935
cap_initiator_unicast_audio_configure(const struct bt_cap_unicast_audio_start_param * param)936 static int cap_initiator_unicast_audio_configure(
937 const struct bt_cap_unicast_audio_start_param *param)
938 {
939 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
940 struct bt_cap_initiator_proc_param *proc_param;
941 struct bt_audio_codec_cfg *codec_cfg;
942 struct bt_bap_stream *bap_stream;
943 struct bt_bap_ep *ep;
944 struct bt_conn *conn;
945 int err;
946 /** TODO: If this is a CSIP set, then the order of the procedures may
947 * not match the order in the parameters, and the CSIP ordered access
948 * procedure should be used.
949 */
950
951 for (size_t i = 0U; i < param->count; i++) {
952 struct bt_cap_unicast_audio_start_stream_param *stream_param =
953 ¶m->stream_params[i];
954 union bt_cap_set_member *member = &stream_param->member;
955 struct bt_cap_stream *cap_stream = stream_param->stream;
956
957 conn = bt_cap_common_get_member_conn(param->type, member);
958
959 /* Ensure that ops are registered before any procedures are started */
960 bt_cap_stream_ops_register_bap(cap_stream);
961
962 /* Store the necessary parameters as we cannot assume that the supplied parameters
963 * are kept valid
964 */
965 active_proc->proc_param.initiator[i].stream = cap_stream;
966 active_proc->proc_param.initiator[i].start.ep = stream_param->ep;
967 active_proc->proc_param.initiator[i].start.conn = conn;
968 active_proc->proc_param.initiator[i].start.codec_cfg = stream_param->codec_cfg;
969 }
970
971 /* Store the information about the active procedure so that we can
972 * continue the procedure after each step
973 */
974 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_START, param->count);
975 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG);
976
977 proc_param = get_next_proc_param(active_proc);
978 if (proc_param == NULL) {
979 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
980 */
981 bt_cap_initiator_codec_configured(active_proc->proc_param.initiator[0].stream);
982
983 return 0;
984 }
985
986 bap_stream = &proc_param->stream->bap_stream;
987 codec_cfg = proc_param->start.codec_cfg;
988 conn = proc_param->start.conn;
989 ep = proc_param->start.ep;
990 active_proc->proc_initiated_cnt++;
991 proc_param->in_progress = true;
992
993 /* Since BAP operations may require a write long or a read long on the notification,
994 * we cannot assume that we can do multiple streams at once, thus do it one at a time.
995 * TODO: We should always be able to do one per ACL, so there is room for optimization.
996 * This applies to all BAP calls in this file.
997 */
998 err = bt_bap_stream_config(conn, bap_stream, ep, codec_cfg);
999 if (err != 0) {
1000 LOG_DBG("Failed to config stream %p: %d", proc_param->stream, err);
1001
1002 bt_cap_common_clear_active_proc();
1003 }
1004
1005 return err;
1006 }
1007
bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param * param)1008 int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param)
1009 {
1010 bool all_streaming = true;
1011
1012 if (bt_cap_common_proc_is_active()) {
1013 LOG_DBG("A CAP procedure is already in progress");
1014
1015 return -EBUSY;
1016 }
1017
1018 if (!valid_unicast_audio_start_param(param)) {
1019 return -EINVAL;
1020 }
1021
1022 for (size_t i = 0U; i < param->count; i++) {
1023 const struct bt_bap_stream *bap_stream =
1024 ¶m->stream_params[i].stream->bap_stream;
1025
1026 if (!stream_is_in_state(bap_stream, BT_BAP_EP_STATE_STREAMING)) {
1027 all_streaming = false;
1028 }
1029 }
1030
1031 if (all_streaming) {
1032 LOG_DBG("All streams are already in the streaming state");
1033 return -EALREADY;
1034 }
1035
1036 return cap_initiator_unicast_audio_configure(param);
1037 }
1038
bt_cap_initiator_codec_configured(struct bt_cap_stream * cap_stream)1039 void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream)
1040 {
1041 struct bt_conn
1042 *conns[MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT)];
1043 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1044 struct bt_cap_initiator_proc_param *proc_param;
1045 struct bt_bap_unicast_group *unicast_group;
1046
1047 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1048 /* State change happened outside of a procedure; ignore */
1049 return;
1050 }
1051
1052 LOG_DBG("cap_stream %p", cap_stream);
1053
1054 if (bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) {
1055 /* When releasing a stream, it may go into the codec configured state if
1056 * the unicast server caches the configuration - We treat it as a release
1057 */
1058 bt_cap_initiator_released(cap_stream);
1059 return;
1060 } else if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG)) {
1061 /* Unexpected callback - Abort */
1062 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1063 } else {
1064 update_proc_done_cnt(active_proc);
1065
1066 LOG_DBG("Stream %p configured (%zu/%zu streams done)", cap_stream,
1067 active_proc->proc_done_cnt, active_proc->proc_cnt);
1068 }
1069
1070 if (bt_cap_common_proc_is_aborted()) {
1071 if (bt_cap_common_proc_all_handled()) {
1072 cap_initiator_unicast_audio_proc_complete();
1073 }
1074
1075 return;
1076 }
1077
1078 if (!bt_cap_common_proc_is_done()) {
1079 struct bt_cap_stream *next_cap_stream;
1080 struct bt_bap_stream *next_bap_stream;
1081 struct bt_audio_codec_cfg *codec_cfg;
1082 struct bt_conn *conn;
1083 struct bt_bap_ep *ep;
1084 int err;
1085
1086 proc_param = get_next_proc_param(active_proc);
1087 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1088 next_cap_stream = proc_param->stream;
1089 conn = proc_param->start.conn;
1090 ep = proc_param->start.ep;
1091 codec_cfg = proc_param->start.codec_cfg;
1092 next_bap_stream = &next_cap_stream->bap_stream;
1093 active_proc->proc_initiated_cnt++;
1094 proc_param->in_progress = true;
1095
1096 err = bt_bap_stream_config(conn, next_bap_stream, ep, codec_cfg);
1097 if (err != 0) {
1098 LOG_DBG("Failed to config stream %p: %d", next_cap_stream, err);
1099
1100 bt_cap_common_abort_proc(conn, err);
1101 cap_initiator_unicast_audio_proc_complete();
1102 }
1103
1104 return;
1105 }
1106
1107 /* The QoS Configure procedure works on a set of connections and a
1108 * unicast group, so we generate a list of unique connection pointers
1109 * for the procedure
1110 */
1111 (void)memset(conns, 0, sizeof(conns));
1112 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
1113 struct bt_conn *stream_conn =
1114 active_proc->proc_param.initiator[i].stream->bap_stream.conn;
1115 struct bt_conn **free_conn = NULL;
1116 bool already_added = false;
1117
1118 for (size_t j = 0U; j < ARRAY_SIZE(conns); j++) {
1119 if (stream_conn == conns[j]) {
1120 already_added = true;
1121 break;
1122 } else if (conns[j] == NULL && free_conn == NULL) {
1123 free_conn = &conns[j];
1124 }
1125 }
1126
1127 if (already_added) {
1128 continue;
1129 }
1130
1131 if (free_conn != NULL) {
1132 *free_conn = stream_conn;
1133 } else {
1134 __ASSERT(false, "[%zu]: No free conns", i);
1135 return;
1136 }
1137 }
1138
1139 /* All streams in the procedure share the same unicast group, so we just
1140 * use the reference from the first stream
1141 */
1142 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG);
1143 proc_param = get_next_proc_param(active_proc);
1144 if (proc_param == NULL) {
1145 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
1146 */
1147 bt_cap_initiator_qos_configured(active_proc->proc_param.initiator[0].stream);
1148
1149 return;
1150 }
1151
1152 unicast_group = (struct bt_bap_unicast_group *)proc_param->stream->bap_stream.group;
1153
1154 for (size_t i = 0U; i < ARRAY_SIZE(conns); i++) {
1155 int err;
1156
1157 /* When conns[i] is NULL, we have QoS Configured all unique connections */
1158 if (conns[i] == NULL) {
1159 break;
1160 }
1161
1162 for (size_t j = 0U; j < active_proc->proc_cnt; j++) {
1163 proc_param = &active_proc->proc_param.initiator[j];
1164 if (proc_param->stream->bap_stream.conn == conns[i]) {
1165 active_proc->proc_initiated_cnt++;
1166 proc_param->in_progress = false;
1167 break;
1168 }
1169 }
1170
1171 proc_param->in_progress = true;
1172
1173 err = bt_bap_stream_qos(conns[i], unicast_group);
1174 if (err != 0) {
1175 LOG_DBG("Failed to set stream QoS for conn %p and group %p: %d",
1176 (void *)conns[i], unicast_group, err);
1177
1178 /* End or mark procedure as aborted.
1179 * If we have sent any requests over air, we will abort
1180 * once all sent requests has completed
1181 */
1182 bt_cap_common_abort_proc(conns[i], err);
1183 if (i == 0U) {
1184 cap_initiator_unicast_audio_proc_complete();
1185 }
1186
1187 return;
1188 }
1189 }
1190 }
1191
bt_cap_initiator_qos_configured(struct bt_cap_stream * cap_stream)1192 void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream)
1193 {
1194 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1195
1196 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1197 /* State change happened outside of a procedure; ignore */
1198 return;
1199 }
1200
1201 LOG_DBG("cap_stream %p", cap_stream);
1202
1203 if (!(bt_cap_common_proc_is_type(BT_CAP_COMMON_PROC_TYPE_START) &&
1204 bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG)) &&
1205 !(bt_cap_common_proc_is_type(BT_CAP_COMMON_PROC_TYPE_STOP))) {
1206 /* Unexpected callback - Abort */
1207 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1208 } else {
1209 update_proc_done_cnt(active_proc);
1210
1211 LOG_DBG("Stream %p QoS configured (%zu/%zu streams done)", cap_stream,
1212 active_proc->proc_done_cnt, active_proc->proc_cnt);
1213 }
1214
1215 if (bt_cap_common_proc_is_aborted()) {
1216 if (bt_cap_common_proc_all_handled()) {
1217 cap_initiator_unicast_audio_proc_complete();
1218 }
1219
1220 return;
1221 }
1222
1223 if (bt_cap_common_proc_is_type(BT_CAP_COMMON_PROC_TYPE_START)) {
1224 struct bt_cap_initiator_proc_param *proc_param;
1225 struct bt_cap_stream *next_cap_stream;
1226 struct bt_bap_stream *bap_stream;
1227 int err;
1228
1229 if (!bt_cap_common_proc_is_done()) {
1230 /* Not yet finished, wait for all */
1231 return;
1232 }
1233
1234 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE);
1235 proc_param = get_next_proc_param(active_proc);
1236 if (proc_param == NULL) {
1237 /* If proc_param is NULL then this step is a no-op and we can skip to the
1238 * next step
1239 */
1240 bt_cap_initiator_enabled(active_proc->proc_param.initiator[0].stream);
1241
1242 return;
1243 }
1244
1245 next_cap_stream = proc_param->stream;
1246 bap_stream = &next_cap_stream->bap_stream;
1247 active_proc->proc_initiated_cnt++;
1248 proc_param->in_progress = true;
1249
1250 err = bt_bap_stream_enable(bap_stream, bap_stream->codec_cfg->meta,
1251 bap_stream->codec_cfg->meta_len);
1252 if (err != 0) {
1253 LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err);
1254
1255 bt_cap_common_abort_proc(bap_stream->conn, err);
1256 cap_initiator_unicast_audio_proc_complete();
1257 }
1258 } else if (bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) {
1259 struct bt_cap_initiator_proc_param *proc_param;
1260 struct bt_cap_stream *next_cap_stream;
1261 struct bt_bap_stream *next_bap_stream;
1262 int err;
1263
1264 proc_param = get_next_proc_param(active_proc);
1265 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1266
1267 next_cap_stream = proc_param->stream;
1268 next_bap_stream = &next_cap_stream->bap_stream;
1269 active_proc->proc_initiated_cnt++;
1270 proc_param->in_progress = true;
1271
1272 err = bt_bap_stream_release(next_bap_stream);
1273 if (err != 0) {
1274 LOG_DBG("Failed to release stream %p: %d", next_cap_stream, err);
1275
1276 bt_cap_common_abort_proc(next_bap_stream->conn, err);
1277 cap_initiator_unicast_audio_proc_complete();
1278 }
1279 }
1280 }
1281
bt_cap_initiator_enabled(struct bt_cap_stream * cap_stream)1282 void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream)
1283 {
1284 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1285 struct bt_cap_initiator_proc_param *proc_param;
1286 struct bt_bap_stream *bap_stream;
1287 int err;
1288
1289 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1290 /* State change happened outside of a procedure; ignore */
1291 return;
1292 }
1293
1294 LOG_DBG("cap_stream %p", cap_stream);
1295
1296 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE)) {
1297 /* Unexpected callback - Abort */
1298 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1299 } else {
1300 update_proc_done_cnt(active_proc);
1301
1302 LOG_DBG("Stream %p enabled (%zu/%zu streams done)", cap_stream,
1303 active_proc->proc_done_cnt, active_proc->proc_cnt);
1304 }
1305
1306 if (bt_cap_common_proc_is_aborted()) {
1307 if (bt_cap_common_proc_all_handled()) {
1308 cap_initiator_unicast_audio_proc_complete();
1309 }
1310
1311 return;
1312 }
1313
1314 if (!bt_cap_common_proc_is_done()) {
1315 struct bt_cap_stream *next_cap_stream;
1316 struct bt_bap_stream *next_bap_stream;
1317
1318 proc_param = get_next_proc_param(active_proc);
1319 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1320 next_cap_stream = proc_param->stream;
1321 next_bap_stream = &next_cap_stream->bap_stream;
1322
1323 active_proc->proc_initiated_cnt++;
1324 proc_param->in_progress = true;
1325
1326 err = bt_bap_stream_enable(next_bap_stream, next_bap_stream->codec_cfg->meta,
1327 next_bap_stream->codec_cfg->meta_len);
1328 if (err != 0) {
1329 LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err);
1330
1331 bt_cap_common_abort_proc(next_bap_stream->conn, err);
1332 cap_initiator_unicast_audio_proc_complete();
1333 }
1334
1335 return;
1336 }
1337
1338 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_CONNECT);
1339 proc_param = get_next_proc_param(active_proc);
1340 if (proc_param == NULL) {
1341 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
1342 */
1343 bt_cap_initiator_connected(active_proc->proc_param.initiator[0].stream);
1344
1345 return;
1346 }
1347
1348 bap_stream = &proc_param->stream->bap_stream;
1349 proc_param->in_progress = true;
1350
1351 err = bt_bap_stream_connect(bap_stream);
1352 if (err == -EALREADY) {
1353 /* If the stream is already connected we can just call the callback directly
1354 * NOTE: It's important that we do not do any additional functionality after
1355 * calling this
1356 */
1357 proc_param->in_progress = false;
1358 bt_cap_initiator_connected(proc_param->stream);
1359 } else if (err != 0) {
1360 LOG_DBG("Failed to connect stream %p: %d", proc_param->stream, err);
1361
1362 /* End and mark procedure as aborted.
1363 * If we have sent any requests over air, we will abort
1364 * once all sent requests has completed
1365 */
1366 bt_cap_common_abort_proc(bap_stream->conn, err);
1367 cap_initiator_unicast_audio_proc_complete();
1368 }
1369 }
1370
bt_cap_initiator_connected(struct bt_cap_stream * cap_stream)1371 void bt_cap_initiator_connected(struct bt_cap_stream *cap_stream)
1372 {
1373 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1374 struct bt_cap_initiator_proc_param *proc_param;
1375 struct bt_bap_stream *bap_stream;
1376 int err;
1377
1378 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1379 /* State change happened outside of a procedure; ignore */
1380 return;
1381 }
1382
1383 LOG_DBG("cap_stream %p", cap_stream);
1384
1385 set_cap_stream_in_progress(cap_stream, false);
1386
1387 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CONNECT)) {
1388 /* Unexpected callback - Abort */
1389 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1390 } else {
1391 proc_param = get_proc_param_by_cap_stream(active_proc, cap_stream);
1392 __ASSERT_NO_MSG(proc_param != NULL);
1393
1394 /* Sets connected before update_proc_done_cnt as that is the only way to can track
1395 * the CIS state change
1396 */
1397 proc_param->start.connected = true;
1398 update_proc_done_cnt(active_proc);
1399
1400 LOG_DBG("Stream %p connected (%zu/%zu streams done)", cap_stream,
1401 active_proc->proc_done_cnt, active_proc->proc_cnt);
1402 }
1403
1404 if (bt_cap_common_proc_is_aborted()) {
1405 if (bt_cap_common_proc_all_handled()) {
1406 cap_initiator_unicast_audio_proc_complete();
1407 }
1408
1409 return;
1410 }
1411
1412 if (!bt_cap_common_proc_is_done()) {
1413 struct bt_cap_stream *next_cap_stream;
1414 struct bt_bap_stream *next_bap_stream;
1415
1416 proc_param = get_next_proc_param(active_proc);
1417 if (proc_param != NULL) {
1418 next_cap_stream = proc_param->stream;
1419 next_bap_stream = &next_cap_stream->bap_stream;
1420
1421 active_proc->proc_initiated_cnt++;
1422 proc_param->in_progress = true;
1423
1424 err = bt_bap_stream_connect(next_bap_stream);
1425 if (err == 0 || err == -EALREADY) {
1426 if (err == -EALREADY) {
1427 proc_param->in_progress = false;
1428 }
1429 /* Pending connected - wait for connected callback */
1430 } else if (err != 0) {
1431 LOG_DBG("Failed to connect stream %p: %d", next_cap_stream, err);
1432
1433 bt_cap_common_abort_proc(next_bap_stream->conn, err);
1434 cap_initiator_unicast_audio_proc_complete();
1435 }
1436 } /* else pending connection - wait for connected callback */
1437
1438 return;
1439 }
1440
1441 /* All streams connected - Start sending the receiver start ready for all source
1442 * ASEs. For sink ASEs it is the responsibility of the unicast server to do the
1443 * receiver start ready operation. If there are no source ASEs then we just wait.
1444 */
1445 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_START);
1446 proc_param = get_next_proc_param(active_proc);
1447 if (proc_param == NULL) {
1448 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
1449 */
1450 bt_cap_initiator_started(active_proc->proc_param.initiator[0].stream);
1451
1452 return;
1453 }
1454
1455 bap_stream = &proc_param->stream->bap_stream;
1456 if (stream_is_dir(bap_stream, BT_AUDIO_DIR_SOURCE)) {
1457 proc_param->in_progress = true;
1458
1459 err = bt_bap_stream_start(bap_stream);
1460 if (err != 0) {
1461 LOG_DBG("Failed to start stream %p: %d", proc_param->stream, err);
1462
1463 bt_cap_common_abort_proc(bap_stream->conn, err);
1464 cap_initiator_unicast_audio_proc_complete();
1465
1466 return;
1467 }
1468 }
1469 }
1470
bt_cap_initiator_started(struct bt_cap_stream * cap_stream)1471 void bt_cap_initiator_started(struct bt_cap_stream *cap_stream)
1472 {
1473 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1474
1475 LOG_DBG("cap_stream %p", cap_stream);
1476
1477 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1478 /* State change happened outside of a procedure; ignore */
1479 return;
1480 }
1481
1482 /* Streams may go into the streaming state while we are connecting or starting them */
1483 if (bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CONNECT)) {
1484 /* If we are still connecting the streams, we terminate early as to not perform any
1485 * start operations until all streams are connected
1486 */
1487 return;
1488 } else if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_START)) {
1489 /* Unexpected callback - Abort */
1490 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1491 } else {
1492 update_proc_done_cnt(active_proc);
1493
1494 LOG_DBG("Stream %p started (%zu/%zu streams done)", cap_stream,
1495 active_proc->proc_done_cnt, active_proc->proc_cnt);
1496 }
1497
1498 if (!bt_cap_common_proc_is_done()) {
1499 struct bt_cap_initiator_proc_param *proc_param;
1500 struct bt_cap_stream *next_cap_stream;
1501 struct bt_bap_stream *next_bap_stream;
1502
1503 proc_param = get_next_proc_param(active_proc);
1504 if (proc_param != NULL) {
1505 next_cap_stream = proc_param->stream;
1506 next_bap_stream = &next_cap_stream->bap_stream;
1507
1508 if (stream_is_dir(next_bap_stream, BT_AUDIO_DIR_SOURCE)) {
1509 int err;
1510
1511 proc_param->in_progress = true;
1512
1513 err = bt_bap_stream_start(next_bap_stream);
1514 if (err != 0) {
1515 LOG_DBG("Failed to start stream %p: %d", next_cap_stream,
1516 err);
1517
1518 /* End and mark procedure as aborted.
1519 * If we have sent any requests over air, we will abort
1520 * once all sent requests has completed
1521 */
1522 bt_cap_common_abort_proc(next_bap_stream->conn, err);
1523 cap_initiator_unicast_audio_proc_complete();
1524
1525 return;
1526 }
1527 }
1528 } /* else await notifications from server */
1529
1530 /* Return to await for response from server */
1531 return;
1532 }
1533
1534 cap_initiator_unicast_audio_proc_complete();
1535 }
1536
can_update_metadata(const struct bt_bap_stream * bap_stream)1537 static bool can_update_metadata(const struct bt_bap_stream *bap_stream)
1538 {
1539 return stream_is_in_state(bap_stream, BT_BAP_EP_STATE_ENABLING) ||
1540 stream_is_in_state(bap_stream, BT_BAP_EP_STATE_STREAMING);
1541 }
1542
valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_update_param * param)1543 static bool valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_update_param *param)
1544 {
1545 struct bt_bap_unicast_group *unicast_group = NULL;
1546
1547 CHECKIF(param == NULL) {
1548 LOG_DBG("param is NULL");
1549 return false;
1550 }
1551
1552 CHECKIF(param->count == 0) {
1553 LOG_DBG("Invalid param->count: %u", param->count);
1554 return false;
1555 }
1556
1557 CHECKIF(param->stream_params == NULL) {
1558 LOG_DBG("param->stream_params is NULL");
1559 return false;
1560 }
1561
1562 CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
1563 LOG_DBG("param->count (%zu) is larger than "
1564 "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)",
1565 param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT);
1566 return false;
1567 }
1568
1569 for (size_t i = 0U; i < param->count; i++) {
1570 const struct bt_cap_unicast_audio_update_stream_param *stream_param =
1571 ¶m->stream_params[i];
1572 const struct bt_cap_stream *cap_stream = stream_param->stream;
1573 const struct bt_bap_stream *bap_stream;
1574 struct bt_conn *conn;
1575
1576 CHECKIF(cap_stream == NULL) {
1577 LOG_DBG("param->stream_params[%zu] is NULL", i);
1578 return false;
1579 }
1580
1581 bap_stream = &cap_stream->bap_stream;
1582 conn = bap_stream->conn;
1583 CHECKIF(conn == NULL) {
1584 LOG_DBG("param->stream_params[%zu].stream->bap_stream.conn is NULL", i);
1585
1586 return -EINVAL;
1587 }
1588
1589 CHECKIF(bap_stream->group == NULL) {
1590 LOG_DBG("param->stream_params[%zu] is not in a unicast group", i);
1591 return false;
1592 }
1593
1594 /* Use the group of the first stream for comparison */
1595 if (unicast_group == NULL) {
1596 unicast_group = bap_stream->group;
1597 } else {
1598 CHECKIF(bap_stream->group != unicast_group) {
1599 LOG_DBG("param->stream_params[%zu] is not in this group %p", i,
1600 unicast_group);
1601 return false;
1602 }
1603 }
1604
1605 if (!can_update_metadata(bap_stream)) {
1606 LOG_DBG("param->stream_params[%zu].stream is not in right state to be "
1607 "updated",
1608 i);
1609
1610 return false;
1611 }
1612
1613 if (!cap_initiator_valid_metadata(stream_param->meta, stream_param->meta_len)) {
1614 LOG_DBG("param->stream_params[%zu] invalid metadata", i);
1615
1616 return false;
1617 }
1618
1619 for (size_t j = 0U; j < i; j++) {
1620 if (param->stream_params[j].stream == cap_stream) {
1621 LOG_DBG("param->stream_params[%zu] (%p) is "
1622 "duplicated by "
1623 "param->stream_params[%zu] (%p)",
1624 j, param->stream_params[j].stream, i, cap_stream);
1625 return false;
1626 }
1627 }
1628 }
1629
1630 return true;
1631 }
1632
bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param * param)1633 int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param *param)
1634 {
1635 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1636 struct bt_cap_initiator_proc_param *proc_param;
1637 struct bt_bap_stream *bap_stream;
1638 const uint8_t *meta;
1639 size_t meta_len;
1640 int err;
1641
1642 if (bt_cap_common_proc_is_active()) {
1643 LOG_DBG("A CAP procedure is already in progress");
1644
1645 return -EBUSY;
1646 }
1647
1648 if (!valid_unicast_audio_update_param(param)) {
1649 return -EINVAL;
1650 }
1651
1652 for (size_t i = 0U; i < param->count; i++) {
1653 const struct bt_cap_unicast_audio_update_stream_param *stream_param =
1654 ¶m->stream_params[i];
1655 struct bt_cap_stream *cap_stream = stream_param->stream;
1656
1657 /* Ensure that ops are registered before any procedures are started */
1658 bt_cap_stream_ops_register_bap(cap_stream);
1659
1660 active_proc->proc_param.initiator[i].stream = cap_stream;
1661 active_proc->proc_param.initiator[i].meta_update.meta_len = stream_param->meta_len;
1662 memcpy(&active_proc->proc_param.initiator[i].meta_update.meta, stream_param->meta,
1663 stream_param->meta_len);
1664 }
1665
1666 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_UPDATE, param->count);
1667 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE);
1668
1669 proc_param = get_next_proc_param(active_proc);
1670 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1671
1672 bap_stream = &proc_param->stream->bap_stream;
1673 meta_len = proc_param->meta_update.meta_len;
1674 meta = proc_param->meta_update.meta;
1675 active_proc->proc_initiated_cnt++;
1676 proc_param->in_progress = true;
1677
1678 err = bt_bap_stream_metadata(bap_stream, meta, meta_len);
1679 if (err != 0) {
1680 LOG_DBG("Failed to update metadata for stream %p: %d", proc_param->stream, err);
1681
1682 bt_cap_common_clear_active_proc();
1683 }
1684
1685 return err;
1686 }
1687
bt_cap_initiator_unicast_audio_cancel(void)1688 int bt_cap_initiator_unicast_audio_cancel(void)
1689 {
1690 if (!bt_cap_common_proc_is_active() && !bt_cap_common_proc_is_aborted()) {
1691 LOG_DBG("No CAP procedure is in progress");
1692
1693 return -EALREADY;
1694 }
1695
1696 bt_cap_common_abort_proc(NULL, -ECANCELED);
1697 cap_initiator_unicast_audio_proc_complete();
1698
1699 return 0;
1700 }
1701
bt_cap_initiator_metadata_updated(struct bt_cap_stream * cap_stream)1702 void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream)
1703 {
1704 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1705
1706 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1707 /* State change happened outside of a procedure; ignore */
1708 return;
1709 }
1710
1711 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE)) {
1712 /* Unexpected callback - Abort */
1713 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1714 } else {
1715 update_proc_done_cnt(active_proc);
1716
1717 LOG_DBG("Stream %p QoS metadata updated (%zu/%zu streams done)", cap_stream,
1718 active_proc->proc_done_cnt, active_proc->proc_cnt);
1719 }
1720
1721 if (bt_cap_common_proc_is_aborted()) {
1722 if (bt_cap_common_proc_all_handled()) {
1723 cap_initiator_unicast_audio_proc_complete();
1724 }
1725
1726 return;
1727 }
1728
1729 if (!bt_cap_common_proc_is_done()) {
1730 const size_t proc_done_cnt = active_proc->proc_done_cnt;
1731 struct bt_cap_initiator_proc_param *proc_param;
1732 struct bt_cap_stream *next_cap_stream;
1733 struct bt_bap_stream *bap_stream;
1734 const uint8_t *meta;
1735 size_t meta_len;
1736 int err;
1737
1738 proc_param = &active_proc->proc_param.initiator[proc_done_cnt];
1739 meta_len = proc_param->meta_update.meta_len;
1740 meta = proc_param->meta_update.meta;
1741 next_cap_stream = proc_param->stream;
1742 bap_stream = &next_cap_stream->bap_stream;
1743 active_proc->proc_initiated_cnt++;
1744 proc_param->in_progress = true;
1745
1746 err = bt_bap_stream_metadata(bap_stream, meta, meta_len);
1747 if (err != 0) {
1748 LOG_DBG("Failed to update metadata for stream %p: %d", next_cap_stream,
1749 err);
1750
1751 bt_cap_common_abort_proc(bap_stream->conn, err);
1752 cap_initiator_unicast_audio_proc_complete();
1753 }
1754
1755 return;
1756 }
1757
1758 cap_initiator_unicast_audio_proc_complete();
1759 }
1760
can_release_stream(const struct bt_bap_stream * bap_stream)1761 static bool can_release_stream(const struct bt_bap_stream *bap_stream)
1762 {
1763 enum bt_bap_ep_state state;
1764
1765 if (bap_stream->conn == NULL) {
1766 return false;
1767 }
1768
1769 state = stream_get_state(bap_stream);
1770
1771 /* We cannot release idle endpoints.
1772 * We do not know if we can release endpoints in the Codec Configured state as servers may
1773 * cache it, so treat it as idle
1774 */
1775 return state != BT_BAP_EP_STATE_IDLE && state != BT_BAP_EP_STATE_CODEC_CONFIGURED;
1776 }
1777
can_disable_stream(const struct bt_bap_stream * bap_stream)1778 static bool can_disable_stream(const struct bt_bap_stream *bap_stream)
1779 {
1780 enum bt_bap_ep_state state;
1781
1782 if (bap_stream->conn == NULL) {
1783 return false;
1784 }
1785
1786 state = stream_get_state(bap_stream);
1787
1788 return state == BT_BAP_EP_STATE_STREAMING || state == BT_BAP_EP_STATE_ENABLING;
1789 }
1790
can_stop_stream(const struct bt_bap_stream * bap_stream)1791 static bool can_stop_stream(const struct bt_bap_stream *bap_stream)
1792 {
1793 enum bt_iso_state iso_state;
1794
1795 if (bap_stream->conn == NULL) {
1796 return false;
1797 }
1798
1799 if (stream_is_dir(bap_stream, BT_AUDIO_DIR_SINK)) {
1800 return false;
1801 }
1802
1803 iso_state = bap_stream_get_iso_state(bap_stream);
1804 if (iso_state != BT_ISO_STATE_CONNECTED && iso_state != BT_ISO_STATE_CONNECTING) {
1805 return false;
1806 }
1807
1808 return stream_is_in_state(bap_stream, BT_BAP_EP_STATE_DISABLING);
1809 }
1810
valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_stop_param * param)1811 static bool valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_stop_param *param)
1812 {
1813 struct bt_bap_unicast_group *unicast_group = NULL;
1814
1815 CHECKIF(param == NULL) {
1816 LOG_DBG("param is NULL");
1817 return false;
1818 }
1819
1820 CHECKIF(param->count == 0) {
1821 LOG_DBG("Invalid param->count: %u", param->count);
1822 return false;
1823 }
1824
1825 CHECKIF(param->streams == NULL) {
1826 LOG_DBG("param->streams is NULL");
1827 return false;
1828 }
1829
1830 CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
1831 LOG_DBG("param->count (%zu) is larger than "
1832 "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)",
1833 param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT);
1834 return false;
1835 }
1836
1837 for (size_t i = 0U; i < param->count; i++) {
1838 const struct bt_cap_stream *cap_stream = param->streams[i];
1839 const struct bt_bap_stream *bap_stream;
1840 struct bt_conn *conn;
1841
1842 CHECKIF(cap_stream == NULL) {
1843 LOG_DBG("param->streams[%zu] is NULL", i);
1844 return false;
1845 }
1846
1847 bap_stream = &cap_stream->bap_stream;
1848 conn = bap_stream->conn;
1849 CHECKIF(conn == NULL) {
1850 LOG_DBG("param->streams[%zu]->bap_stream.conn is NULL", i);
1851
1852 return -EINVAL;
1853 }
1854
1855 if (param->type == BT_CAP_SET_TYPE_CSIP) {
1856 struct bt_cap_common_client *client = bt_cap_common_get_client_by_acl(conn);
1857
1858 if (client->csis_inst == NULL) {
1859 LOG_DBG("param->streams[%zu]->bap_stream.conn not part of a "
1860 "coordinated set",
1861 i);
1862
1863 return false;
1864 }
1865 }
1866
1867 CHECKIF(bap_stream->group == NULL) {
1868 LOG_DBG("param->streams[%zu] is not in a unicast group", i);
1869 return false;
1870 }
1871
1872 /* Use the group of the first stream for comparison */
1873 if (unicast_group == NULL) {
1874 unicast_group = bap_stream->group;
1875 } else {
1876 CHECKIF(bap_stream->group != unicast_group) {
1877 LOG_DBG("param->streams[%zu] is not in this group %p", i,
1878 unicast_group);
1879 return false;
1880 }
1881 }
1882
1883 for (size_t j = 0U; j < i; j++) {
1884 if (param->streams[j] == cap_stream) {
1885 LOG_DBG("param->stream_params[%zu] (%p) is "
1886 "duplicated by "
1887 "param->stream_params[%zu] (%p)",
1888 j, param->streams[j], i, cap_stream);
1889 return false;
1890 }
1891 }
1892 }
1893
1894 return true;
1895 }
1896
bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param * param)1897 int bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param *param)
1898 {
1899 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1900 bool can_release = false;
1901 bool can_disable = false;
1902 bool can_stop = false;
1903 int err;
1904
1905 if (bt_cap_common_proc_is_active()) {
1906 LOG_DBG("A CAP procedure is already in progress");
1907
1908 return -EBUSY;
1909 }
1910
1911 if (!valid_unicast_audio_stop_param(param)) {
1912 return -EINVAL;
1913 }
1914
1915 for (size_t i = 0U; i < param->count; i++) {
1916 struct bt_cap_stream *cap_stream = param->streams[i];
1917 struct bt_bap_stream *bap_stream = &cap_stream->bap_stream;
1918
1919 /* Ensure that ops are registered before any procedures are started */
1920 bt_cap_stream_ops_register_bap(cap_stream);
1921
1922 active_proc->proc_param.initiator[i].stream = cap_stream;
1923 active_proc->proc_param.initiator[i].stop.release = param->release;
1924
1925 if (!can_disable && can_disable_stream(bap_stream)) {
1926 can_disable = true;
1927 }
1928
1929 if (!can_stop && can_stop_stream(bap_stream)) {
1930 can_stop = true;
1931 }
1932
1933 if (!can_release && param->release && can_release_stream(bap_stream)) {
1934 can_release = true;
1935 }
1936 }
1937
1938 if (!can_disable && !can_stop && !can_release) {
1939 LOG_DBG("Cannot %s any streams", !can_disable ? "disable"
1940 : !can_stop ? "stop"
1941 : "release");
1942 return -EALREADY;
1943 }
1944
1945 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_STOP, param->count);
1946 /** TODO: If this is a CSIP set, then the order of the procedures may
1947 * not match the order in the parameters, and the CSIP ordered access
1948 * procedure should be used.
1949 */
1950
1951 if (can_disable) {
1952 struct bt_cap_initiator_proc_param *proc_param;
1953 struct bt_bap_stream *bap_stream;
1954
1955 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_DISABLE);
1956
1957 proc_param = get_next_proc_param(active_proc);
1958 __ASSERT(proc_param != NULL,
1959 "proc is not started, but could not get next proc_param");
1960 bap_stream = &proc_param->stream->bap_stream;
1961 active_proc->proc_initiated_cnt++;
1962 proc_param->in_progress = true;
1963
1964 err = bt_bap_stream_disable(bap_stream);
1965 if (err != 0) {
1966 LOG_DBG("Failed to disable bap_stream %p: %d", proc_param->stream, err);
1967
1968 bt_cap_common_clear_active_proc();
1969 }
1970 } else if (can_stop) {
1971 struct bt_cap_initiator_proc_param *proc_param;
1972 struct bt_bap_stream *bap_stream;
1973
1974 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_STOP);
1975
1976 proc_param = get_next_proc_param(active_proc);
1977 __ASSERT(proc_param != NULL,
1978 "proc is not started, but could not get next proc_param");
1979 bap_stream = &proc_param->stream->bap_stream;
1980 active_proc->proc_initiated_cnt++;
1981 proc_param->in_progress = true;
1982
1983 err = bt_bap_stream_stop(bap_stream);
1984 if (err != 0) {
1985 LOG_DBG("Failed to stop bap_stream %p: %d", proc_param->stream, err);
1986
1987 bt_cap_common_clear_active_proc();
1988 }
1989 } else {
1990 struct bt_cap_initiator_proc_param *proc_param;
1991 struct bt_bap_stream *bap_stream;
1992
1993 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE);
1994
1995 proc_param = get_next_proc_param(active_proc);
1996 __ASSERT(proc_param != NULL,
1997 "proc is not started, but could not get next proc_param");
1998 bap_stream = &proc_param->stream->bap_stream;
1999 active_proc->proc_initiated_cnt++;
2000 proc_param->in_progress = true;
2001
2002 err = bt_bap_stream_release(bap_stream);
2003 if (err != 0) {
2004 LOG_DBG("Failed to release bap_stream %p: %d", proc_param->stream, err);
2005
2006 bt_cap_common_clear_active_proc();
2007 }
2008 }
2009
2010 return err;
2011 }
2012
bt_cap_initiator_disabled(struct bt_cap_stream * cap_stream)2013 void bt_cap_initiator_disabled(struct bt_cap_stream *cap_stream)
2014 {
2015 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
2016
2017 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
2018 /* State change happened outside of a procedure; ignore */
2019 return;
2020 }
2021
2022 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_DISABLE)) {
2023 /* Unexpected callback - Abort */
2024 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
2025 } else {
2026 update_proc_done_cnt(active_proc);
2027
2028 LOG_DBG("Stream %p disabled (%zu/%zu streams done)", cap_stream,
2029 active_proc->proc_done_cnt, active_proc->proc_cnt);
2030 }
2031
2032 if (bt_cap_common_proc_is_aborted()) {
2033 if (bt_cap_common_proc_all_handled()) {
2034 cap_initiator_unicast_audio_proc_complete();
2035 }
2036
2037 return;
2038 }
2039
2040 if (!bt_cap_common_proc_is_done()) {
2041 struct bt_cap_initiator_proc_param *proc_param;
2042 struct bt_cap_stream *next_cap_stream;
2043 struct bt_bap_stream *next_bap_stream;
2044 int err;
2045
2046 proc_param = get_next_proc_param(active_proc);
2047 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
2048 next_cap_stream = proc_param->stream;
2049 next_bap_stream = &next_cap_stream->bap_stream;
2050 active_proc->proc_initiated_cnt++;
2051 proc_param->in_progress = true;
2052
2053 err = bt_bap_stream_disable(next_bap_stream);
2054 if (err != 0) {
2055 LOG_DBG("Failed to disable stream %p: %d", next_cap_stream, err);
2056
2057 bt_cap_common_abort_proc(next_bap_stream->conn, err);
2058 cap_initiator_unicast_audio_proc_complete();
2059 }
2060 } else {
2061 struct bt_cap_initiator_proc_param *proc_param;
2062 struct bt_cap_stream *next_cap_stream;
2063 struct bt_bap_stream *next_bap_stream;
2064 int err;
2065
2066 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_STOP);
2067
2068 proc_param = get_next_proc_param(active_proc);
2069 if (proc_param == NULL) {
2070 /* If proc_param is NULL then this step is a no-op and we can skip to the
2071 * next step
2072 */
2073 bt_cap_initiator_stopped(active_proc->proc_param.initiator[0].stream);
2074
2075 return;
2076 }
2077
2078 next_cap_stream = proc_param->stream;
2079 next_bap_stream = &next_cap_stream->bap_stream;
2080 active_proc->proc_initiated_cnt++;
2081 proc_param->in_progress = true;
2082
2083 err = bt_bap_stream_stop(next_bap_stream);
2084 if (err != 0 && err != -EALREADY) {
2085 LOG_DBG("Failed to stop stream %p: %d", next_cap_stream, err);
2086
2087 bt_cap_common_abort_proc(next_bap_stream->conn, err);
2088 cap_initiator_unicast_audio_proc_complete();
2089 } else if (err == -EALREADY) {
2090 proc_param->in_progress = false;
2091 } /* else wait for server notification*/
2092 }
2093 }
2094
bt_cap_initiator_stopped(struct bt_cap_stream * cap_stream)2095 void bt_cap_initiator_stopped(struct bt_cap_stream *cap_stream)
2096 {
2097 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
2098
2099 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
2100 /* State change happened outside of a procedure; ignore */
2101 return;
2102 }
2103
2104 if (!bt_cap_common_proc_is_type(BT_CAP_COMMON_PROC_TYPE_STOP)) {
2105 /* Unexpected callback - Abort */
2106 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
2107 } else {
2108 if (bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_STOP)) {
2109 update_proc_done_cnt(active_proc);
2110
2111 LOG_DBG("Stream %p stopped (%zu/%zu streams done)", cap_stream,
2112 active_proc->proc_done_cnt, active_proc->proc_cnt);
2113 } else {
2114 /* We are still doing disable - Wait for those to be done, as stopped may
2115 * also be called when we are disabling sink ASEs
2116 */
2117 return;
2118 }
2119 }
2120
2121 if (bt_cap_common_proc_is_aborted()) {
2122 if (bt_cap_common_proc_all_handled()) {
2123 cap_initiator_unicast_audio_proc_complete();
2124 }
2125
2126 return;
2127 }
2128
2129 if (!bt_cap_common_proc_is_done()) {
2130 struct bt_cap_initiator_proc_param *proc_param;
2131 struct bt_cap_stream *next_cap_stream;
2132 struct bt_bap_stream *next_bap_stream;
2133 int err;
2134
2135 proc_param = get_next_proc_param(active_proc);
2136 if (proc_param != NULL) {
2137 next_cap_stream = proc_param->stream;
2138 next_bap_stream = &next_cap_stream->bap_stream;
2139
2140 active_proc->proc_initiated_cnt++;
2141 proc_param->in_progress = true;
2142
2143 err = bt_bap_stream_stop(next_bap_stream);
2144 if (err != 0 && err != -EALREADY) {
2145 LOG_DBG("Failed to stop stream %p: %d", next_cap_stream, err);
2146
2147 bt_cap_common_abort_proc(next_bap_stream->conn, err);
2148 cap_initiator_unicast_audio_proc_complete();
2149 } else if (err == -EALREADY) {
2150 proc_param->in_progress = false;
2151 }
2152 } /* else await notification from server */
2153 } else {
2154 /* We are done stopping streams now - We mark the next subproc. If
2155 * get_next_proc_param returns a NULL value it means that we are complete done. If
2156 * it returns a non-NULL value, it means that we need to start releasing streams.
2157 * However, since the QoS Configured state is better suited to trigger this, we
2158 * simply wait until bt_cap_initiator_qos_configured is called.
2159 */
2160 struct bt_cap_initiator_proc_param *proc_param;
2161
2162 if (!bt_cap_common_proc_is_done()) {
2163 /* We are still disabling or stopping some */
2164 return;
2165 }
2166
2167 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE);
2168
2169 proc_param = get_next_proc_param(active_proc);
2170 if (proc_param == NULL) {
2171 /* If proc_param is NULL then this step is a no-op and we can finish the
2172 * procedure
2173 */
2174 cap_initiator_unicast_audio_proc_complete();
2175
2176 return;
2177 } /* wait for bt_cap_initiator_qos_configured */
2178 }
2179 }
2180
bt_cap_initiator_released(struct bt_cap_stream * cap_stream)2181 void bt_cap_initiator_released(struct bt_cap_stream *cap_stream)
2182 {
2183 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
2184
2185 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
2186 /* State change happened outside of a procedure; ignore */
2187 return;
2188 }
2189
2190 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) {
2191 /* Unexpected callback - Abort */
2192 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
2193 } else {
2194 update_proc_done_cnt(active_proc);
2195
2196 LOG_DBG("Stream %p released (%zu/%zu streams done)", cap_stream,
2197 active_proc->proc_done_cnt, active_proc->proc_cnt);
2198 }
2199
2200 if (bt_cap_common_proc_is_aborted()) {
2201 if (bt_cap_common_proc_all_handled()) {
2202 cap_initiator_unicast_audio_proc_complete();
2203 }
2204
2205 return;
2206 }
2207
2208 if (!bt_cap_common_proc_is_done()) {
2209 struct bt_cap_initiator_proc_param *proc_param;
2210 struct bt_cap_stream *next_cap_stream;
2211 struct bt_bap_stream *next_bap_stream;
2212 int err;
2213
2214 proc_param = get_next_proc_param(active_proc);
2215 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
2216 next_cap_stream = proc_param->stream;
2217 next_bap_stream = &next_cap_stream->bap_stream;
2218 active_proc->proc_initiated_cnt++;
2219 proc_param->in_progress = true;
2220
2221 err = bt_bap_stream_release(next_bap_stream);
2222 if (err != 0) {
2223 LOG_DBG("Failed to release stream %p: %d", next_cap_stream, err);
2224
2225 bt_cap_common_abort_proc(next_bap_stream->conn, err);
2226 cap_initiator_unicast_audio_proc_complete();
2227 }
2228 } else {
2229 cap_initiator_unicast_audio_proc_complete();
2230 }
2231 }
2232
2233 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
2234
2235 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)
2236
bt_cap_initiator_unicast_to_broadcast(const struct bt_cap_unicast_to_broadcast_param * param,struct bt_cap_broadcast_source ** source)2237 int bt_cap_initiator_unicast_to_broadcast(
2238 const struct bt_cap_unicast_to_broadcast_param *param,
2239 struct bt_cap_broadcast_source **source)
2240 {
2241 return -ENOSYS;
2242 }
2243
bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param * param,struct bt_bap_unicast_group ** unicast_group)2244 int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param *param,
2245 struct bt_bap_unicast_group **unicast_group)
2246 {
2247 return -ENOSYS;
2248 }
2249
2250 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE && CONFIG_BT_BAP_UNICAST_CLIENT */
2251