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/csip.h>
18 #include <zephyr/bluetooth/audio/tbs.h>
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/conn.h>
21 #include <zephyr/bluetooth/gatt.h>
22 #include <zephyr/bluetooth/iso.h>
23 #include <zephyr/logging/log.h>
24 #include <zephyr/net/buf.h>
25 #include <zephyr/sys/__assert.h>
26 #include <zephyr/sys/check.h>
27 #include <zephyr/sys/util.h>
28 #include <zephyr/sys/util_macro.h>
29
30 #include "bap_endpoint.h"
31 #include "cap_internal.h"
32 #include "ccid_internal.h"
33 #include "csip_internal.h"
34
35 LOG_MODULE_REGISTER(bt_cap_initiator, CONFIG_BT_CAP_INITIATOR_LOG_LEVEL);
36
37 #include "common/bt_str.h"
38
39 static const struct bt_cap_initiator_cb *cap_cb;
40
bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb * cb)41 int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb)
42 {
43 CHECKIF(cb == NULL) {
44 LOG_DBG("cb is NULL");
45 return -EINVAL;
46 }
47
48 CHECKIF(cap_cb != NULL) {
49 LOG_DBG("callbacks already registered");
50 return -EALREADY;
51 }
52
53 cap_cb = cb;
54
55 return 0;
56 }
57
bt_cap_initiator_unregister_cb(const struct bt_cap_initiator_cb * cb)58 int bt_cap_initiator_unregister_cb(const struct bt_cap_initiator_cb *cb)
59 {
60 CHECKIF(cb == NULL) {
61 LOG_DBG("cb is NULL");
62 return -EINVAL;
63 }
64
65 CHECKIF(cap_cb != cb) {
66 LOG_DBG("cb is not registered");
67 return -EINVAL;
68 }
69
70 cap_cb = NULL;
71
72 return 0;
73 }
74
75 struct valid_metadata_param {
76 bool stream_context_found;
77 bool valid;
78 };
79
data_func_cb(struct bt_data * data,void * user_data)80 static bool data_func_cb(struct bt_data *data, void *user_data)
81 {
82 struct valid_metadata_param *metadata_param = (struct valid_metadata_param *)user_data;
83
84 LOG_DBG("type %u len %u data %s", data->type, data->data_len,
85 bt_hex(data->data, data->data_len));
86
87 if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
88 if (data->data_len != 2) { /* Stream context size */
89 return false;
90 }
91
92 metadata_param->stream_context_found = true;
93 } else if (IS_ENABLED(CONFIG_BT_CCID) && data->type == BT_AUDIO_METADATA_TYPE_CCID_LIST) {
94 /* If the application supplies a CCID list, we verify that the CCIDs exist on our
95 * device
96 */
97 for (uint8_t i = 0U; i < data->data_len; i++) {
98 const uint8_t ccid = data->data[i];
99
100 if (bt_ccid_find_attr(ccid) == NULL) {
101 LOG_DBG("Unknown characteristic for CCID 0x%02X", ccid);
102 metadata_param->valid = false;
103
104 return false;
105 }
106 }
107 }
108
109 return true;
110 }
111
cap_initiator_valid_metadata(const uint8_t meta[],size_t meta_len)112 static bool cap_initiator_valid_metadata(const uint8_t meta[], size_t meta_len)
113 {
114 struct valid_metadata_param metadata_param = {
115 .stream_context_found = false,
116 .valid = true,
117 };
118 int err;
119
120 LOG_DBG("meta %p len %zu", meta, meta_len);
121
122 err = bt_audio_data_parse(meta, meta_len, data_func_cb, &metadata_param);
123 if (err != 0 && err != -ECANCELED) {
124 return false;
125 }
126
127 if (!metadata_param.stream_context_found) {
128 LOG_DBG("No streaming context supplied");
129 }
130
131 return metadata_param.stream_context_found && metadata_param.valid;
132 }
133
134 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
135 static struct bt_cap_broadcast_source {
136 struct bt_bap_broadcast_source *bap_broadcast;
137 } broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
138
cap_initiator_broadcast_audio_start_valid_param(const struct bt_cap_initiator_broadcast_create_param * param)139 static bool cap_initiator_broadcast_audio_start_valid_param(
140 const struct bt_cap_initiator_broadcast_create_param *param)
141 {
142
143 for (size_t i = 0U; i < param->subgroup_count; i++) {
144 const struct bt_cap_initiator_broadcast_subgroup_param *subgroup_param;
145 const struct bt_audio_codec_cfg *codec_cfg;
146 bool valid_metadata;
147
148 subgroup_param = ¶m->subgroup_params[i];
149 codec_cfg = subgroup_param->codec_cfg;
150
151 /* Streaming Audio Context shall be present in CAP */
152
153 CHECKIF(codec_cfg == NULL) {
154 LOG_DBG("subgroup[%zu]->codec_cfg is NULL", i);
155 return false;
156 }
157
158 valid_metadata =
159 cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len);
160
161 CHECKIF(!valid_metadata) {
162 LOG_DBG("Invalid metadata supplied for subgroup[%zu]", i);
163 return false;
164 }
165 }
166
167 return true;
168 }
169
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])170 static void cap_initiator_broadcast_to_bap_broadcast_param(
171 const struct bt_cap_initiator_broadcast_create_param *cap_param,
172 struct bt_bap_broadcast_source_param *bap_param,
173 struct bt_bap_broadcast_source_subgroup_param
174 bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT],
175 struct bt_bap_broadcast_source_stream_param
176 bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT])
177 {
178 size_t stream_cnt = 0U;
179
180 bap_param->params_count = cap_param->subgroup_count;
181 bap_param->params = bap_subgroup_params;
182 bap_param->qos = cap_param->qos;
183 bap_param->packing = cap_param->packing;
184 bap_param->encryption = cap_param->encryption;
185 if (bap_param->encryption) {
186 memcpy(bap_param->broadcast_code, cap_param->broadcast_code,
187 BT_AUDIO_BROADCAST_CODE_SIZE);
188 } else {
189 memset(bap_param->broadcast_code, 0, BT_AUDIO_BROADCAST_CODE_SIZE);
190 }
191
192 for (size_t i = 0U; i < bap_param->params_count; i++) {
193 const struct bt_cap_initiator_broadcast_subgroup_param *cap_subgroup_param =
194 &cap_param->subgroup_params[i];
195 struct bt_bap_broadcast_source_subgroup_param *bap_subgroup_param =
196 &bap_param->params[i];
197
198 bap_subgroup_param->codec_cfg = cap_subgroup_param->codec_cfg;
199 bap_subgroup_param->params_count = cap_subgroup_param->stream_count;
200 bap_subgroup_param->params = &bap_stream_params[stream_cnt];
201
202 for (size_t j = 0U; j < bap_subgroup_param->params_count; j++, stream_cnt++) {
203 const struct bt_cap_initiator_broadcast_stream_param *cap_stream_param =
204 &cap_subgroup_param->stream_params[j];
205 struct bt_bap_broadcast_source_stream_param *bap_stream_param =
206 &bap_subgroup_param->params[j];
207
208 bap_stream_param->stream = &cap_stream_param->stream->bap_stream;
209 #if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0
210 bap_stream_param->data_len = cap_stream_param->data_len;
211 /* We do not need to copy the data, as that is the same type of struct, so
212 * we can just point to the CAP parameter data
213 */
214 bap_stream_param->data = cap_stream_param->data;
215 #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */
216 }
217 }
218 }
219
bt_cap_initiator_broadcast_audio_create(const struct bt_cap_initiator_broadcast_create_param * param,struct bt_cap_broadcast_source ** broadcast_source)220 int bt_cap_initiator_broadcast_audio_create(
221 const struct bt_cap_initiator_broadcast_create_param *param,
222 struct bt_cap_broadcast_source **broadcast_source)
223 {
224 struct bt_bap_broadcast_source_subgroup_param
225 bap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
226 struct bt_bap_broadcast_source_stream_param
227 bap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
228 struct bt_bap_broadcast_source_param bap_create_param = {0};
229
230 CHECKIF(param == NULL) {
231 LOG_DBG("param is NULL");
232 return -EINVAL;
233 }
234
235 CHECKIF(broadcast_source == NULL) {
236 LOG_DBG("source is NULL");
237 return -EINVAL;
238 }
239
240 if (!cap_initiator_broadcast_audio_start_valid_param(param)) {
241 return -EINVAL;
242 }
243
244 for (size_t i = 0; i < ARRAY_SIZE(broadcast_sources); i++) {
245 if (broadcast_sources[i].bap_broadcast == NULL) {
246 *broadcast_source = &broadcast_sources[i];
247 break;
248 }
249 }
250
251 cap_initiator_broadcast_to_bap_broadcast_param(param, &bap_create_param,
252 bap_subgroup_params, bap_stream_params);
253
254 return bt_bap_broadcast_source_create(&bap_create_param,
255 &(*broadcast_source)->bap_broadcast);
256 }
257
bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source * broadcast_source,struct bt_le_ext_adv * adv)258 int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source,
259 struct bt_le_ext_adv *adv)
260 {
261 CHECKIF(adv == NULL) {
262 LOG_DBG("adv is NULL");
263 return -EINVAL;
264 }
265
266 CHECKIF(broadcast_source == NULL) {
267 LOG_DBG("broadcast_source is NULL");
268 return -EINVAL;
269 }
270
271 return bt_bap_broadcast_source_start(broadcast_source->bap_broadcast, adv);
272 }
273
bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source * broadcast_source,const uint8_t meta[],size_t meta_len)274 int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source,
275 const uint8_t meta[], size_t meta_len)
276 {
277 CHECKIF(broadcast_source == NULL) {
278 LOG_DBG("broadcast_source is NULL");
279 return -EINVAL;
280 }
281
282 CHECKIF(meta == NULL) {
283 LOG_DBG("meta is NULL");
284 return -EINVAL;
285 }
286
287 if (!cap_initiator_valid_metadata(meta, meta_len)) {
288 LOG_DBG("Invalid metadata");
289 return -EINVAL;
290 }
291
292 return bt_bap_broadcast_source_update_metadata(broadcast_source->bap_broadcast, meta,
293 meta_len);
294 }
295
bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source * broadcast_source)296 int bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source)
297 {
298 CHECKIF(broadcast_source == NULL) {
299 LOG_DBG("broadcast_source is NULL");
300 return -EINVAL;
301 }
302
303 return bt_bap_broadcast_source_stop(broadcast_source->bap_broadcast);
304 }
305
bt_cap_initiator_broadcast_audio_delete(struct bt_cap_broadcast_source * broadcast_source)306 int bt_cap_initiator_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source)
307 {
308 int err;
309
310 CHECKIF(broadcast_source == NULL) {
311 LOG_DBG("broadcast_source is NULL");
312 return -EINVAL;
313 }
314
315 err = bt_bap_broadcast_source_delete(broadcast_source->bap_broadcast);
316 if (err == 0) {
317 broadcast_source->bap_broadcast = NULL;
318 }
319
320 return err;
321 }
322
bt_cap_initiator_broadcast_get_id(const struct bt_cap_broadcast_source * broadcast_source,uint32_t * const broadcast_id)323 int bt_cap_initiator_broadcast_get_id(const struct bt_cap_broadcast_source *broadcast_source,
324 uint32_t *const broadcast_id)
325 {
326 CHECKIF(broadcast_source == NULL) {
327 LOG_DBG("broadcast_source is NULL");
328 return -EINVAL;
329 }
330
331 return bt_bap_broadcast_source_get_id(broadcast_source->bap_broadcast, broadcast_id);
332 }
333
bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source * broadcast_source,struct net_buf_simple * base_buf)334 int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcast_source,
335 struct net_buf_simple *base_buf)
336 {
337 CHECKIF(broadcast_source == NULL) {
338 LOG_DBG("broadcast_source is NULL");
339 return -EINVAL;
340 }
341
342 return bt_bap_broadcast_source_get_base(broadcast_source->bap_broadcast, base_buf);
343 }
344
345 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
346
347 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
348
stream_get_state(const struct bt_bap_stream * bap_stream)349 static enum bt_bap_ep_state stream_get_state(const struct bt_bap_stream *bap_stream)
350 {
351 struct bt_bap_ep_info ep_info;
352 int err;
353
354 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
355 if (err != 0) {
356 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
357
358 return BT_BAP_EP_STATE_IDLE;
359 }
360
361 return ep_info.state;
362 }
363
stream_is_in_state(const struct bt_bap_stream * bap_stream,enum bt_bap_ep_state state)364 static bool stream_is_in_state(const struct bt_bap_stream *bap_stream, enum bt_bap_ep_state state)
365 {
366 if (bap_stream->conn == NULL) {
367 return state == BT_BAP_EP_STATE_IDLE;
368 }
369
370 return stream_get_state(bap_stream) == state;
371 }
372
stream_is_dir(const struct bt_bap_stream * bap_stream,enum bt_audio_dir dir)373 static bool stream_is_dir(const struct bt_bap_stream *bap_stream, enum bt_audio_dir dir)
374 {
375 struct bt_bap_ep_info ep_info;
376 int err;
377
378 if (bap_stream->conn == NULL) {
379 return false;
380 }
381
382 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
383 if (err != 0) {
384 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
385
386 return false;
387 }
388
389 return ep_info.dir == dir;
390 }
391
iso_is_in_state(const struct bt_cap_stream * cap_stream,enum bt_iso_state state)392 static bool iso_is_in_state(const struct bt_cap_stream *cap_stream, enum bt_iso_state state)
393 {
394 const struct bt_bap_stream *bap_stream = &cap_stream->bap_stream;
395 struct bt_bap_ep_info ep_info;
396 int err;
397
398 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
399 if (err != 0) {
400 LOG_DBG("Failed to get endpoint info %p: %d", bap_stream, err);
401
402 return false;
403 }
404
405 if (ep_info.iso_chan == NULL) {
406 return state == BT_ISO_STATE_DISCONNECTED;
407 }
408
409 return state == ep_info.iso_chan->state;
410 }
411
412 /**
413 * @brief Gets the next stream for the active procedure.
414 *
415 * Returns NULL if all streams are in the right state for the current step
416 */
417 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)418 get_proc_param_by_cap_stream(struct bt_cap_common_proc *active_proc,
419 const struct bt_cap_stream *cap_stream)
420 {
421 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
422 if (active_proc->proc_param.initiator[i].stream == cap_stream) {
423 return &active_proc->proc_param.initiator[i];
424 }
425 }
426
427 return NULL;
428 }
429
update_proc_done_cnt(struct bt_cap_common_proc * active_proc)430 static void update_proc_done_cnt(struct bt_cap_common_proc *active_proc)
431 {
432 const enum bt_cap_common_subproc_type subproc_type = active_proc->subproc_type;
433 const enum bt_cap_common_proc_type proc_type = active_proc->proc_type;
434 size_t proc_done_cnt = 0U;
435
436 if (proc_type == BT_CAP_COMMON_PROC_TYPE_START) {
437 /* To support state changes by the server, we cannot rely simply on the number of
438 * BAP procedures we have initiated. For the start and stop CAP procedures we use
439 * the states to determine how far we are.
440 */
441 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
442 const struct bt_cap_initiator_proc_param *proc_param;
443 struct bt_cap_stream *cap_stream;
444 struct bt_bap_stream *bap_stream;
445 enum bt_bap_ep_state state;
446
447 proc_param = &active_proc->proc_param.initiator[i];
448 cap_stream = proc_param->stream;
449 bap_stream = &cap_stream->bap_stream;
450
451 state = stream_get_state(bap_stream);
452
453 switch (subproc_type) {
454 case BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG:
455 if (state > BT_BAP_EP_STATE_IDLE) {
456 proc_done_cnt++;
457 }
458 break;
459 case BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG:
460 if (state > BT_BAP_EP_STATE_CODEC_CONFIGURED) {
461 proc_done_cnt++;
462 } else if (state < BT_BAP_EP_STATE_CODEC_CONFIGURED) {
463 /* Unexpected state - Abort */
464 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
465 }
466 break;
467 case BT_CAP_COMMON_SUBPROC_TYPE_ENABLE:
468 if (state > BT_BAP_EP_STATE_QOS_CONFIGURED) {
469 proc_done_cnt++;
470 } else if (state < BT_BAP_EP_STATE_QOS_CONFIGURED) {
471 /* Unexpected state - Abort */
472 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
473 }
474 break;
475 case BT_CAP_COMMON_SUBPROC_TYPE_CONNECT:
476 if (state < BT_BAP_EP_STATE_ENABLING) {
477 /* Unexpected state - Abort */
478 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
479 } else if (proc_param->start.connected) {
480 proc_done_cnt++;
481 }
482 break;
483 case BT_CAP_COMMON_SUBPROC_TYPE_START:
484 if (state > BT_BAP_EP_STATE_ENABLING) {
485 proc_done_cnt++;
486 } else if (state < BT_BAP_EP_STATE_ENABLING ||
487 !iso_is_in_state(cap_stream, BT_ISO_STATE_CONNECTED)) {
488 /* Unexpected state - Abort */
489 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
490 }
491 break;
492 default:
493 __ASSERT(false, "Invalid subproc %d for %d", subproc_type,
494 proc_type);
495 }
496 }
497 } else if (proc_type == BT_CAP_COMMON_PROC_TYPE_STOP) {
498 /* To support state changes by the server, we cannot rely simply on the number of
499 * BAP procedures we have initiated. For the start and stop CAP procedures we use
500 * the states to determine how far we are.
501 */
502 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
503 const struct bt_cap_initiator_proc_param *proc_param;
504 struct bt_cap_stream *cap_stream;
505 struct bt_bap_stream *bap_stream;
506 enum bt_bap_ep_state state;
507
508 proc_param = &active_proc->proc_param.initiator[i];
509 cap_stream = proc_param->stream;
510 bap_stream = &cap_stream->bap_stream;
511
512 state = stream_get_state(bap_stream);
513
514 switch (subproc_type) {
515 case BT_CAP_COMMON_SUBPROC_TYPE_RELEASE:
516 if (state == BT_BAP_EP_STATE_IDLE ||
517 state == BT_BAP_EP_STATE_CODEC_CONFIGURED) {
518 proc_done_cnt++;
519 }
520 break;
521 default:
522 __ASSERT(false, "Invalid subproc %d for %d", subproc_type,
523 proc_type);
524 }
525 }
526 } else if (proc_type == BT_CAP_COMMON_PROC_TYPE_UPDATE) {
527 /* For metadata we cannot check the states for all streams, as it does not trigger a
528 * state change
529 */
530 const struct bt_cap_initiator_proc_param *proc_param;
531 struct bt_cap_stream *cap_stream;
532 struct bt_bap_stream *bap_stream;
533 enum bt_bap_ep_state state;
534
535 proc_param = &active_proc->proc_param.initiator[active_proc->proc_done_cnt];
536 cap_stream = proc_param->stream;
537 bap_stream = &cap_stream->bap_stream;
538
539 state = stream_get_state(bap_stream);
540
541 switch (subproc_type) {
542 case BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE:
543 if (state == BT_BAP_EP_STATE_ENABLING ||
544 state == BT_BAP_EP_STATE_STREAMING) {
545 proc_done_cnt = active_proc->proc_done_cnt + 1U;
546 } else {
547 /* Unexpected state - Abort */
548 bt_cap_common_abort_proc(bap_stream->conn, -EBADMSG);
549 }
550 break;
551 default:
552 __ASSERT(false, "Invalid subproc %d for %d", subproc_type, proc_type);
553 }
554 }
555
556 active_proc->proc_done_cnt = proc_done_cnt;
557
558 LOG_DBG("proc %d subproc %d: %zu/%zu", proc_type, subproc_type, active_proc->proc_done_cnt,
559 active_proc->proc_cnt);
560 }
561
562 /**
563 * @brief Gets the next stream for the active procedure.
564 *
565 * Returns NULL if all streams are in the right state for the current step
566 */
567 static struct bt_cap_initiator_proc_param *
get_next_proc_param(struct bt_cap_common_proc * active_proc)568 get_next_proc_param(struct bt_cap_common_proc *active_proc)
569 {
570 const enum bt_cap_common_subproc_type subproc_type = active_proc->subproc_type;
571
572 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
573 struct bt_cap_initiator_proc_param *proc_param;
574 struct bt_cap_stream *cap_stream;
575 struct bt_bap_stream *bap_stream;
576
577 proc_param = &active_proc->proc_param.initiator[i];
578 cap_stream = proc_param->stream;
579 bap_stream = &cap_stream->bap_stream;
580
581 switch (subproc_type) {
582 case BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG:
583 if (stream_is_in_state(bap_stream, BT_BAP_EP_STATE_IDLE)) {
584 return proc_param;
585 }
586 break;
587 case BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG:
588 if (stream_is_in_state(bap_stream, BT_BAP_EP_STATE_CODEC_CONFIGURED)) {
589 return proc_param;
590 }
591 break;
592 case BT_CAP_COMMON_SUBPROC_TYPE_ENABLE:
593 if (stream_is_in_state(bap_stream, BT_BAP_EP_STATE_QOS_CONFIGURED)) {
594 return proc_param;
595 }
596 break;
597 case BT_CAP_COMMON_SUBPROC_TYPE_CONNECT:
598 if (stream_is_in_state(bap_stream, BT_BAP_EP_STATE_ENABLING) &&
599 !proc_param->start.connected) {
600 return proc_param;
601 }
602 break;
603 case BT_CAP_COMMON_SUBPROC_TYPE_START:
604 if (stream_is_in_state(bap_stream, BT_BAP_EP_STATE_ENABLING)) {
605 /* TODO: Add check for connected */
606 return proc_param;
607 }
608 break;
609 case BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE:
610 if (stream_is_in_state(bap_stream, BT_BAP_EP_STATE_ENABLING) ||
611 stream_is_in_state(bap_stream, BT_BAP_EP_STATE_STREAMING)) {
612 return proc_param;
613 }
614 break;
615 case BT_CAP_COMMON_SUBPROC_TYPE_RELEASE:
616 if (!stream_is_in_state(bap_stream, BT_BAP_EP_STATE_IDLE)) {
617 return proc_param;
618 }
619 break;
620 default:
621 break;
622 }
623 }
624
625 return NULL;
626 }
627
628 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)629 bt_cap_initiator_discover_complete(struct bt_conn *conn, int err,
630 const struct bt_csip_set_coordinator_set_member *member,
631 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
632 {
633 if (cap_cb && cap_cb->unicast_discovery_complete) {
634 cap_cb->unicast_discovery_complete(conn, err, member, csis_inst);
635 }
636 }
637
bt_cap_initiator_unicast_discover(struct bt_conn * conn)638 int bt_cap_initiator_unicast_discover(struct bt_conn *conn)
639 {
640 CHECKIF(conn == NULL) {
641 LOG_DBG("NULL conn");
642 return -EINVAL;
643 }
644
645 return bt_cap_common_discover(conn, bt_cap_initiator_discover_complete);
646 }
647
valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param * param)648 static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param)
649 {
650 struct bt_bap_unicast_group *unicast_group = NULL;
651
652 CHECKIF(param == NULL) {
653 LOG_DBG("param is NULL");
654 return false;
655 }
656
657 CHECKIF(param->count == 0) {
658 LOG_DBG("Invalid param->count: %u", param->count);
659 return false;
660 }
661
662 CHECKIF(param->stream_params == NULL) {
663 LOG_DBG("param->stream_params is NULL");
664 return false;
665 }
666
667 CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
668 LOG_DBG("param->count (%zu) is larger than "
669 "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)",
670 param->count,
671 CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT);
672 return false;
673 }
674
675 for (size_t i = 0U; i < param->count; i++) {
676 const struct bt_cap_unicast_audio_start_stream_param *stream_param =
677 ¶m->stream_params[i];
678 const union bt_cap_set_member *member = &stream_param->member;
679 const struct bt_cap_stream *cap_stream = stream_param->stream;
680 const struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg;
681 const struct bt_bap_stream *bap_stream;
682 const struct bt_conn *member_conn =
683 bt_cap_common_get_member_conn(param->type, member);
684
685 if (member == NULL) {
686 LOG_DBG("param->members[%zu] is NULL", i);
687 return false;
688 }
689
690 if (member_conn == NULL) {
691 LOG_DBG("Invalid param->members[%zu]", i);
692 return false;
693 }
694
695 CHECKIF(stream_param->codec_cfg == NULL) {
696 LOG_DBG("param->stream_params[%zu].codec_cfg is NULL", i);
697 return false;
698 }
699
700 CHECKIF(!cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_len)) {
701 LOG_DBG("param->stream_params[%zu].codec_cfg is invalid", i);
702 return false;
703 }
704
705 CHECKIF(stream_param->ep == NULL) {
706 LOG_DBG("param->stream_params[%zu].ep is NULL", i);
707 return false;
708 }
709
710 CHECKIF(member == NULL) {
711 LOG_DBG("param->stream_params[%zu].member is NULL", i);
712 return false;
713 }
714
715 CHECKIF(cap_stream == NULL) {
716 LOG_DBG("param->streams[%zu] is NULL", i);
717 return false;
718 }
719
720 bap_stream = &cap_stream->bap_stream;
721
722 CHECKIF(bap_stream->ep != NULL) {
723 LOG_DBG("param->streams[%zu] is already started", i);
724 return false;
725 }
726
727 CHECKIF(bap_stream->group == NULL) {
728 LOG_DBG("param->streams[%zu] is not in a unicast group", i);
729 return false;
730 }
731
732 /* Use the group of the first stream for comparison */
733 if (unicast_group == NULL) {
734 unicast_group = bap_stream->group;
735 } else {
736 CHECKIF(bap_stream->group != unicast_group) {
737 LOG_DBG("param->streams[%zu] is not in this group %p", i,
738 unicast_group);
739 return false;
740 }
741 }
742
743 for (size_t j = 0U; j < i; j++) {
744 if (param->stream_params[j].stream == cap_stream) {
745 LOG_DBG("param->stream_params[%zu] (%p) is "
746 "duplicated by "
747 "param->stream_params[%zu] (%p)",
748 j, param->stream_params[j].stream,
749 i, cap_stream);
750 return false;
751 }
752 }
753 }
754
755 return true;
756 }
757
cap_initiator_unicast_audio_proc_complete(void)758 static void cap_initiator_unicast_audio_proc_complete(void)
759 {
760 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
761 enum bt_cap_common_proc_type proc_type;
762 struct bt_conn *failed_conn;
763 int err;
764
765 failed_conn = active_proc->failed_conn;
766 err = active_proc->err;
767 proc_type = active_proc->proc_type;
768 bt_cap_common_clear_active_proc();
769
770 if (cap_cb == NULL) {
771 return;
772 }
773
774 switch (proc_type) {
775 case BT_CAP_COMMON_PROC_TYPE_START:
776 if (cap_cb->unicast_start_complete != NULL) {
777 cap_cb->unicast_start_complete(err, failed_conn);
778 }
779 break;
780 case BT_CAP_COMMON_PROC_TYPE_UPDATE:
781 if (cap_cb->unicast_update_complete != NULL) {
782 cap_cb->unicast_update_complete(err, failed_conn);
783 }
784 break;
785 case BT_CAP_COMMON_PROC_TYPE_STOP:
786 if (cap_cb->unicast_stop_complete != NULL) {
787 cap_cb->unicast_stop_complete(err, failed_conn);
788 }
789 break;
790 case BT_CAP_COMMON_PROC_TYPE_NONE:
791 default:
792 __ASSERT(false, "Invalid proc_type: %u", proc_type);
793 }
794 }
795
cap_initiator_unicast_audio_configure(const struct bt_cap_unicast_audio_start_param * param)796 static int cap_initiator_unicast_audio_configure(
797 const struct bt_cap_unicast_audio_start_param *param)
798 {
799 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
800 struct bt_cap_initiator_proc_param *proc_param;
801 struct bt_audio_codec_cfg *codec_cfg;
802 struct bt_bap_stream *bap_stream;
803 struct bt_bap_ep *ep;
804 struct bt_conn *conn;
805 int err;
806 /** TODO: If this is a CSIP set, then the order of the procedures may
807 * not match the order in the parameters, and the CSIP ordered access
808 * procedure should be used.
809 */
810
811 for (size_t i = 0U; i < param->count; i++) {
812 struct bt_cap_unicast_audio_start_stream_param *stream_param =
813 ¶m->stream_params[i];
814 union bt_cap_set_member *member = &stream_param->member;
815 struct bt_cap_stream *cap_stream = stream_param->stream;
816
817 conn = bt_cap_common_get_member_conn(param->type, member);
818
819 /* Ensure that ops are registered before any procedures are started */
820 bt_cap_stream_ops_register_bap(cap_stream);
821
822 /* Store the necessary parameters as we cannot assume that the supplied parameters
823 * are kept valid
824 */
825 active_proc->proc_param.initiator[i].stream = cap_stream;
826 active_proc->proc_param.initiator[i].start.ep = stream_param->ep;
827 active_proc->proc_param.initiator[i].start.conn = conn;
828 active_proc->proc_param.initiator[i].start.codec_cfg = stream_param->codec_cfg;
829 }
830
831 /* Store the information about the active procedure so that we can
832 * continue the procedure after each step
833 */
834 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_START, param->count);
835 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG);
836
837 proc_param = get_next_proc_param(active_proc);
838 if (proc_param == NULL) {
839 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
840 */
841 bt_cap_initiator_codec_configured(active_proc->proc_param.initiator[0].stream);
842
843 return 0;
844 }
845
846 bap_stream = &proc_param->stream->bap_stream;
847 codec_cfg = proc_param->start.codec_cfg;
848 conn = proc_param->start.conn;
849 ep = proc_param->start.ep;
850 active_proc->proc_initiated_cnt++;
851
852 /* Since BAP operations may require a write long or a read long on the notification,
853 * we cannot assume that we can do multiple streams at once, thus do it one at a time.
854 * TODO: We should always be able to do one per ACL, so there is room for optimization.
855 */
856 err = bt_bap_stream_config(conn, bap_stream, ep, codec_cfg);
857 if (err != 0) {
858 LOG_DBG("Failed to config stream %p: %d", proc_param->stream, err);
859
860 bt_cap_common_clear_active_proc();
861 }
862
863 return err;
864 }
865
bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param * param)866 int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param)
867 {
868 if (bt_cap_common_proc_is_active()) {
869 LOG_DBG("A CAP procedure is already in progress");
870
871 return -EBUSY;
872 }
873
874 if (!valid_unicast_audio_start_param(param)) {
875 return -EINVAL;
876 }
877
878 return cap_initiator_unicast_audio_configure(param);
879 }
880
bt_cap_initiator_codec_configured(struct bt_cap_stream * cap_stream)881 void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream)
882 {
883 struct bt_conn
884 *conns[MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT)];
885 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
886 struct bt_cap_initiator_proc_param *proc_param;
887 struct bt_bap_unicast_group *unicast_group;
888
889 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
890 /* State change happened outside of a procedure; ignore */
891 return;
892 }
893
894 LOG_DBG("cap_stream %p", cap_stream);
895
896 if (bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) {
897 /* When releasing a stream, it may go into the codec configured state if
898 * the unicast server caches the configuration - We treat it as a release
899 */
900 bt_cap_initiator_released(cap_stream);
901 return;
902 } else if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG)) {
903 /* Unexpected callback - Abort */
904 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
905 } else {
906 update_proc_done_cnt(active_proc);
907
908 LOG_DBG("Stream %p configured (%zu/%zu streams done)", cap_stream,
909 active_proc->proc_done_cnt, active_proc->proc_cnt);
910 }
911
912 if (bt_cap_common_proc_is_aborted()) {
913 if (bt_cap_common_proc_all_handled()) {
914 cap_initiator_unicast_audio_proc_complete();
915 }
916
917 return;
918 }
919
920 if (!bt_cap_common_proc_is_done()) {
921 struct bt_cap_stream *next_cap_stream;
922 struct bt_bap_stream *next_bap_stream;
923 struct bt_audio_codec_cfg *codec_cfg;
924 struct bt_conn *conn;
925 struct bt_bap_ep *ep;
926 int err;
927
928 proc_param = get_next_proc_param(active_proc);
929 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
930 next_cap_stream = proc_param->stream;
931 conn = proc_param->start.conn;
932 ep = proc_param->start.ep;
933 codec_cfg = proc_param->start.codec_cfg;
934 next_bap_stream = &next_cap_stream->bap_stream;
935 active_proc->proc_initiated_cnt++;
936
937 /* Since BAP operations may require a write long or a read long on the notification,
938 * we cannot assume that we can do multiple streams at once, thus do it one at a
939 * time.
940 * TODO: We should always be able to do one per ACL, so there is room for
941 * optimization.
942 */
943 err = bt_bap_stream_config(conn, next_bap_stream, ep, codec_cfg);
944 if (err != 0) {
945 LOG_DBG("Failed to config stream %p: %d", next_cap_stream, err);
946
947 bt_cap_common_abort_proc(conn, err);
948 cap_initiator_unicast_audio_proc_complete();
949 }
950
951 return;
952 }
953
954 /* The QoS Configure procedure works on a set of connections and a
955 * unicast group, so we generate a list of unique connection pointers
956 * for the procedure
957 */
958 (void)memset(conns, 0, sizeof(conns));
959 for (size_t i = 0U; i < active_proc->proc_cnt; i++) {
960 struct bt_conn *stream_conn =
961 active_proc->proc_param.initiator[i].stream->bap_stream.conn;
962 struct bt_conn **free_conn = NULL;
963 bool already_added = false;
964
965 for (size_t j = 0U; j < ARRAY_SIZE(conns); j++) {
966 if (stream_conn == conns[j]) {
967 already_added = true;
968 break;
969 } else if (conns[j] == NULL && free_conn == NULL) {
970 free_conn = &conns[j];
971 }
972 }
973
974 if (already_added) {
975 continue;
976 }
977
978 if (free_conn != NULL) {
979 *free_conn = stream_conn;
980 } else {
981 __ASSERT_PRINT("No free conns");
982 }
983 }
984
985 /* All streams in the procedure share the same unicast group, so we just
986 * use the reference from the first stream
987 */
988 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG);
989 proc_param = get_next_proc_param(active_proc);
990 if (proc_param == NULL) {
991 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
992 */
993 bt_cap_initiator_qos_configured(active_proc->proc_param.initiator[0].stream);
994
995 return;
996 }
997
998 unicast_group = (struct bt_bap_unicast_group *)proc_param->stream->bap_stream.group;
999
1000 for (size_t i = 0U; i < ARRAY_SIZE(conns); i++) {
1001 int err;
1002
1003 /* When conns[i] is NULL, we have QoS Configured all unique connections */
1004 if (conns[i] == NULL) {
1005 break;
1006 }
1007
1008 active_proc->proc_initiated_cnt++;
1009
1010 err = bt_bap_stream_qos(conns[i], unicast_group);
1011 if (err != 0) {
1012 LOG_DBG("Failed to set stream QoS for conn %p and group %p: %d",
1013 (void *)conns[i], unicast_group, err);
1014
1015 /* End or mark procedure as aborted.
1016 * If we have sent any requests over air, we will abort
1017 * once all sent requests has completed
1018 */
1019 bt_cap_common_abort_proc(conns[i], err);
1020 if (i == 0U) {
1021 cap_initiator_unicast_audio_proc_complete();
1022 }
1023
1024 return;
1025 }
1026 }
1027 }
1028
bt_cap_initiator_qos_configured(struct bt_cap_stream * cap_stream)1029 void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream)
1030 {
1031 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1032 struct bt_cap_initiator_proc_param *proc_param;
1033 struct bt_cap_stream *next_cap_stream;
1034 struct bt_bap_stream *bap_stream;
1035 int err;
1036
1037 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1038 /* State change happened outside of a procedure; ignore */
1039 return;
1040 }
1041
1042 LOG_DBG("cap_stream %p", cap_stream);
1043
1044 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG)) {
1045 /* Unexpected callback - Abort */
1046 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1047 } else {
1048 update_proc_done_cnt(active_proc);
1049
1050 LOG_DBG("Stream %p QoS configured (%zu/%zu streams done)", cap_stream,
1051 active_proc->proc_done_cnt, active_proc->proc_cnt);
1052 }
1053
1054 if (bt_cap_common_proc_is_aborted()) {
1055 if (bt_cap_common_proc_all_handled()) {
1056 cap_initiator_unicast_audio_proc_complete();
1057 }
1058
1059 return;
1060 }
1061
1062 if (!bt_cap_common_proc_is_done()) {
1063 /* Not yet finished, wait for all */
1064 return;
1065 }
1066
1067 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE);
1068 proc_param = get_next_proc_param(active_proc);
1069 if (proc_param == NULL) {
1070 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
1071 */
1072 bt_cap_initiator_enabled(active_proc->proc_param.initiator[0].stream);
1073
1074 return;
1075 }
1076
1077 next_cap_stream = proc_param->stream;
1078 bap_stream = &next_cap_stream->bap_stream;
1079 active_proc->proc_initiated_cnt++;
1080
1081 /* Since BAP operations may require a write long or a read long on the notification, we
1082 * cannot assume that we can do multiple streams at once, thus do it one at a time.
1083 * TODO: We should always be able to do one per ACL, so there is room for optimization.
1084 */
1085 err = bt_bap_stream_enable(bap_stream, bap_stream->codec_cfg->meta,
1086 bap_stream->codec_cfg->meta_len);
1087 if (err != 0) {
1088 LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err);
1089
1090 bt_cap_common_abort_proc(bap_stream->conn, err);
1091 cap_initiator_unicast_audio_proc_complete();
1092 }
1093 }
1094
bt_cap_initiator_enabled(struct bt_cap_stream * cap_stream)1095 void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream)
1096 {
1097 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1098 struct bt_cap_initiator_proc_param *proc_param;
1099 struct bt_bap_stream *bap_stream;
1100 int err;
1101
1102 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1103 /* State change happened outside of a procedure; ignore */
1104 return;
1105 }
1106
1107 LOG_DBG("cap_stream %p", cap_stream);
1108
1109 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE)) {
1110 /* Unexpected callback - Abort */
1111 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1112 } else {
1113 update_proc_done_cnt(active_proc);
1114
1115 LOG_DBG("Stream %p enabled (%zu/%zu streams done)", cap_stream,
1116 active_proc->proc_done_cnt, active_proc->proc_cnt);
1117 }
1118
1119 if (bt_cap_common_proc_is_aborted()) {
1120 if (bt_cap_common_proc_all_handled()) {
1121 cap_initiator_unicast_audio_proc_complete();
1122 }
1123
1124 return;
1125 }
1126
1127 if (!bt_cap_common_proc_is_done()) {
1128 struct bt_cap_stream *next_cap_stream;
1129 struct bt_bap_stream *next_bap_stream;
1130
1131 proc_param = get_next_proc_param(active_proc);
1132 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1133 next_cap_stream = proc_param->stream;
1134 next_bap_stream = &next_cap_stream->bap_stream;
1135
1136 active_proc->proc_initiated_cnt++;
1137
1138 /* Since BAP operations may require a write long or a read long on the notification,
1139 * we cannot assume that we can do multiple streams at once, thus do it one at a
1140 * time.
1141 * TODO: We should always be able to do one per ACL, so there is room for
1142 * optimization.
1143 */
1144 err = bt_bap_stream_enable(next_bap_stream, next_bap_stream->codec_cfg->meta,
1145 next_bap_stream->codec_cfg->meta_len);
1146 if (err != 0) {
1147 LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err);
1148
1149 bt_cap_common_abort_proc(next_bap_stream->conn, err);
1150 cap_initiator_unicast_audio_proc_complete();
1151 }
1152
1153 return;
1154 }
1155
1156 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_CONNECT);
1157 proc_param = get_next_proc_param(active_proc);
1158 if (proc_param == NULL) {
1159 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
1160 */
1161 bt_cap_initiator_connected(active_proc->proc_param.initiator[0].stream);
1162
1163 return;
1164 }
1165
1166 bap_stream = &proc_param->stream->bap_stream;
1167
1168 err = bt_bap_stream_connect(bap_stream);
1169 if (err == -EALREADY) {
1170 /* If the stream is already connected we can just call the callback directly
1171 * NOTE: It's important that we do not do any additional functionality after
1172 * calling this
1173 */
1174 bt_cap_initiator_connected(proc_param->stream);
1175 } else if (err != 0) {
1176 LOG_DBG("Failed to connect stream %p: %d", proc_param->stream, err);
1177
1178 /* End and 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(bap_stream->conn, err);
1183 cap_initiator_unicast_audio_proc_complete();
1184 }
1185 }
1186
bt_cap_initiator_connected(struct bt_cap_stream * cap_stream)1187 void bt_cap_initiator_connected(struct bt_cap_stream *cap_stream)
1188 {
1189 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1190 struct bt_cap_initiator_proc_param *proc_param;
1191 struct bt_bap_stream *bap_stream;
1192 int err;
1193
1194 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1195 /* State change happened outside of a procedure; ignore */
1196 return;
1197 }
1198
1199 LOG_DBG("cap_stream %p", cap_stream);
1200
1201 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CONNECT)) {
1202 /* Unexpected callback - Abort */
1203 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1204 } else {
1205 proc_param = get_proc_param_by_cap_stream(active_proc, cap_stream);
1206 __ASSERT_NO_MSG(proc_param != NULL);
1207
1208 /* Sets connected before update_proc_done_cnt as that is the only way to can track
1209 * the CIS state change
1210 */
1211 proc_param->start.connected = true;
1212 update_proc_done_cnt(active_proc);
1213
1214 LOG_DBG("Stream %p connected (%zu/%zu streams done)", cap_stream,
1215 active_proc->proc_done_cnt, active_proc->proc_cnt);
1216 }
1217
1218 if (bt_cap_common_proc_is_aborted()) {
1219 if (bt_cap_common_proc_all_handled()) {
1220 cap_initiator_unicast_audio_proc_complete();
1221 }
1222
1223 return;
1224 }
1225
1226 if (!bt_cap_common_proc_is_done()) {
1227 struct bt_cap_stream *next_cap_stream;
1228 struct bt_bap_stream *next_bap_stream;
1229
1230 proc_param = get_next_proc_param(active_proc);
1231 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1232 next_cap_stream = proc_param->stream;
1233 next_bap_stream = &next_cap_stream->bap_stream;
1234
1235 active_proc->proc_initiated_cnt++;
1236
1237 err = bt_bap_stream_connect(next_bap_stream);
1238 if (err == 0 || err == -EALREADY) {
1239 /* Pending connected - wait for connected callback */
1240 } else if (err != 0) {
1241 LOG_DBG("Failed to connect stream %p: %d", next_cap_stream, err);
1242
1243 bt_cap_common_abort_proc(next_bap_stream->conn, err);
1244 cap_initiator_unicast_audio_proc_complete();
1245 }
1246
1247 return;
1248 }
1249
1250 /* All streams connected - Start sending the receiver start ready for all source
1251 * ASEs. For sink ASEs it is the responsibility of the unicast server to do the
1252 * receiver start ready operation. If there are no source ASEs then we just wait.
1253 */
1254 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_START);
1255 proc_param = get_next_proc_param(active_proc);
1256 if (proc_param == NULL) {
1257 /* If proc_param is NULL then this step is a no-op and we can skip to the next step
1258 */
1259 bt_cap_initiator_started(active_proc->proc_param.initiator[0].stream);
1260
1261 return;
1262 }
1263
1264 bap_stream = &proc_param->stream->bap_stream;
1265 if (stream_is_dir(bap_stream, BT_AUDIO_DIR_SOURCE)) {
1266 /* Since BAP operations may require a write long or a read long on the notification,
1267 * we cannot assume that we can do multiple streams at once, thus do it one at a
1268 * time.
1269 * TODO: We should always be able to do one per ACL, so there is room for
1270 * optimization.
1271 */
1272 err = bt_bap_stream_start(bap_stream);
1273 if (err != 0) {
1274 LOG_DBG("Failed to start stream %p: %d", proc_param->stream, err);
1275
1276 bt_cap_common_abort_proc(bap_stream->conn, err);
1277 cap_initiator_unicast_audio_proc_complete();
1278
1279 return;
1280 }
1281 }
1282 }
1283
bt_cap_initiator_started(struct bt_cap_stream * cap_stream)1284 void bt_cap_initiator_started(struct bt_cap_stream *cap_stream)
1285 {
1286 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1287
1288 LOG_DBG("cap_stream %p", cap_stream);
1289
1290 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1291 /* State change happened outside of a procedure; ignore */
1292 return;
1293 }
1294
1295 /* Streams may go into the streaming state while we are connecting or starting them */
1296 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_START) &&
1297 !bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CONNECT)) {
1298 /* Unexpected callback - Abort */
1299 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1300 } else {
1301 update_proc_done_cnt(active_proc);
1302
1303 LOG_DBG("Stream %p started (%zu/%zu streams done)", cap_stream,
1304 active_proc->proc_done_cnt, active_proc->proc_cnt);
1305 }
1306
1307 if (!bt_cap_common_proc_is_done()) {
1308 struct bt_cap_initiator_proc_param *proc_param;
1309 struct bt_cap_stream *next_cap_stream;
1310 struct bt_bap_stream *next_bap_stream;
1311
1312 proc_param = get_next_proc_param(active_proc);
1313 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1314 next_cap_stream = proc_param->stream;
1315 next_bap_stream = &next_cap_stream->bap_stream;
1316
1317 if (stream_is_dir(next_bap_stream, BT_AUDIO_DIR_SOURCE)) {
1318 int err;
1319
1320 /* Since BAP operations may require a write long or a read long on
1321 * the notification, we cannot assume that we can do multiple
1322 * streams at once, thus do it one at a time.
1323 * TODO: We should always be able to do one per ACL, so there is
1324 * room for optimization.
1325 */
1326 err = bt_bap_stream_start(next_bap_stream);
1327 if (err != 0) {
1328 LOG_DBG("Failed to start stream %p: %d", next_cap_stream, err);
1329
1330 /* End and mark procedure as aborted.
1331 * If we have sent any requests over air, we will abort
1332 * once all sent requests has completed
1333 */
1334 bt_cap_common_abort_proc(next_bap_stream->conn, err);
1335 cap_initiator_unicast_audio_proc_complete();
1336
1337 return;
1338 }
1339 } /* else await notifications from server */
1340
1341 /* Return to await for response from server */
1342 return;
1343 }
1344
1345 cap_initiator_unicast_audio_proc_complete();
1346 }
1347
can_update_metadata(const struct bt_bap_stream * bap_stream)1348 static bool can_update_metadata(const struct bt_bap_stream *bap_stream)
1349 {
1350 return stream_is_in_state(bap_stream, BT_BAP_EP_STATE_ENABLING) ||
1351 stream_is_in_state(bap_stream, BT_BAP_EP_STATE_STREAMING);
1352 }
1353
valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_update_param * param)1354 static bool valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_update_param *param)
1355 {
1356 struct bt_bap_unicast_group *unicast_group = NULL;
1357
1358 CHECKIF(param == NULL) {
1359 LOG_DBG("param is NULL");
1360 return false;
1361 }
1362
1363 CHECKIF(param->count == 0) {
1364 LOG_DBG("Invalid param->count: %u", param->count);
1365 return false;
1366 }
1367
1368 CHECKIF(param->stream_params == NULL) {
1369 LOG_DBG("param->stream_params is NULL");
1370 return false;
1371 }
1372
1373 CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
1374 LOG_DBG("param->count (%zu) is larger than "
1375 "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)",
1376 param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT);
1377 return false;
1378 }
1379
1380 for (size_t i = 0U; i < param->count; i++) {
1381 const struct bt_cap_unicast_audio_update_stream_param *stream_param =
1382 ¶m->stream_params[i];
1383 const struct bt_cap_stream *cap_stream = stream_param->stream;
1384 const struct bt_bap_stream *bap_stream;
1385 struct bt_conn *conn;
1386
1387 CHECKIF(cap_stream == NULL) {
1388 LOG_DBG("param->stream_params[%zu] is NULL", i);
1389 return false;
1390 }
1391
1392 bap_stream = &cap_stream->bap_stream;
1393 conn = bap_stream->conn;
1394 CHECKIF(conn == NULL) {
1395 LOG_DBG("param->stream_params[%zu].stream->bap_stream.conn is NULL", i);
1396
1397 return -EINVAL;
1398 }
1399
1400 CHECKIF(bap_stream->group == NULL) {
1401 LOG_DBG("param->stream_params[%zu] is not in a unicast group", i);
1402 return false;
1403 }
1404
1405 /* Use the group of the first stream for comparison */
1406 if (unicast_group == NULL) {
1407 unicast_group = bap_stream->group;
1408 } else {
1409 CHECKIF(bap_stream->group != unicast_group) {
1410 LOG_DBG("param->stream_params[%zu] is not in this group %p", i,
1411 unicast_group);
1412 return false;
1413 }
1414 }
1415
1416 if (!can_update_metadata(bap_stream)) {
1417 LOG_DBG("param->stream_params[%zu].stream is not in right state to be "
1418 "updated",
1419 i);
1420
1421 return false;
1422 }
1423
1424 if (!cap_initiator_valid_metadata(stream_param->meta, stream_param->meta_len)) {
1425 LOG_DBG("param->stream_params[%zu] invalid metadata", i);
1426
1427 return false;
1428 }
1429
1430 for (size_t j = 0U; j < i; j++) {
1431 if (param->stream_params[j].stream == cap_stream) {
1432 LOG_DBG("param->stream_params[%zu] (%p) is "
1433 "duplicated by "
1434 "param->stream_params[%zu] (%p)",
1435 j, param->stream_params[j].stream, i, cap_stream);
1436 return false;
1437 }
1438 }
1439 }
1440
1441 return true;
1442 }
1443
bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param * param)1444 int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param *param)
1445 {
1446 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1447 struct bt_cap_initiator_proc_param *proc_param;
1448 struct bt_bap_stream *bap_stream;
1449 const uint8_t *meta;
1450 size_t meta_len;
1451 int err;
1452
1453 if (bt_cap_common_proc_is_active()) {
1454 LOG_DBG("A CAP procedure is already in progress");
1455
1456 return -EBUSY;
1457 }
1458
1459 if (!valid_unicast_audio_update_param(param)) {
1460 return -EINVAL;
1461 }
1462
1463 for (size_t i = 0U; i < param->count; i++) {
1464 const struct bt_cap_unicast_audio_update_stream_param *stream_param =
1465 ¶m->stream_params[i];
1466 struct bt_cap_stream *cap_stream = stream_param->stream;
1467
1468 active_proc->proc_param.initiator[i].stream = cap_stream;
1469 active_proc->proc_param.initiator[i].meta_update.meta_len = stream_param->meta_len;
1470 memcpy(&active_proc->proc_param.initiator[i].meta_update.meta, stream_param->meta,
1471 stream_param->meta_len);
1472 }
1473
1474 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_UPDATE, param->count);
1475 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE);
1476
1477 proc_param = get_next_proc_param(active_proc);
1478 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1479
1480 bap_stream = &proc_param->stream->bap_stream;
1481 meta_len = proc_param->meta_update.meta_len;
1482 meta = proc_param->meta_update.meta;
1483 active_proc->proc_initiated_cnt++;
1484
1485 err = bt_bap_stream_metadata(bap_stream, meta, meta_len);
1486 if (err != 0) {
1487 LOG_DBG("Failed to update metadata for stream %p: %d", proc_param->stream, err);
1488
1489 bt_cap_common_clear_active_proc();
1490 }
1491
1492 return err;
1493 }
1494
bt_cap_initiator_unicast_audio_cancel(void)1495 int bt_cap_initiator_unicast_audio_cancel(void)
1496 {
1497 if (!bt_cap_common_proc_is_active() && !bt_cap_common_proc_is_aborted()) {
1498 LOG_DBG("No CAP procedure is in progress");
1499
1500 return -EALREADY;
1501 }
1502
1503 bt_cap_common_abort_proc(NULL, -ECANCELED);
1504 cap_initiator_unicast_audio_proc_complete();
1505
1506 return 0;
1507 }
1508
bt_cap_initiator_metadata_updated(struct bt_cap_stream * cap_stream)1509 void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream)
1510 {
1511 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1512
1513 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1514 /* State change happened outside of a procedure; ignore */
1515 return;
1516 }
1517
1518 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE)) {
1519 /* Unexpected callback - Abort */
1520 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1521 } else {
1522 update_proc_done_cnt(active_proc);
1523
1524 LOG_DBG("Stream %p QoS metadata updated (%zu/%zu streams done)", cap_stream,
1525 active_proc->proc_done_cnt, active_proc->proc_cnt);
1526 }
1527
1528 if (bt_cap_common_proc_is_aborted()) {
1529 if (bt_cap_common_proc_all_handled()) {
1530 cap_initiator_unicast_audio_proc_complete();
1531 }
1532
1533 return;
1534 }
1535
1536 if (!bt_cap_common_proc_is_done()) {
1537 const size_t proc_done_cnt = active_proc->proc_done_cnt;
1538 struct bt_cap_initiator_proc_param *proc_param;
1539 struct bt_cap_stream *next_cap_stream;
1540 struct bt_bap_stream *bap_stream;
1541 const uint8_t *meta;
1542 size_t meta_len;
1543 int err;
1544
1545 proc_param = &active_proc->proc_param.initiator[proc_done_cnt];
1546 meta_len = proc_param->meta_update.meta_len;
1547 meta = proc_param->meta_update.meta;
1548 next_cap_stream = proc_param->stream;
1549 bap_stream = &next_cap_stream->bap_stream;
1550 active_proc->proc_initiated_cnt++;
1551
1552 /* Since BAP operations may require a write long or a read long on the notification,
1553 * we cannot assume that we can do multiple streams at once, thus do it one at a
1554 * time.
1555 * TODO: We should always be able to do one per ACL, so there is room for
1556 * optimization.
1557 */
1558
1559 err = bt_bap_stream_metadata(bap_stream, meta, meta_len);
1560 if (err != 0) {
1561 LOG_DBG("Failed to update metadata for stream %p: %d", next_cap_stream,
1562 err);
1563
1564 bt_cap_common_abort_proc(bap_stream->conn, err);
1565 cap_initiator_unicast_audio_proc_complete();
1566 }
1567
1568 return;
1569 }
1570
1571 cap_initiator_unicast_audio_proc_complete();
1572 }
1573
can_release(const struct bt_bap_stream * bap_stream)1574 static bool can_release(const struct bt_bap_stream *bap_stream)
1575 {
1576 if (bap_stream->conn == NULL) {
1577 return false;
1578 }
1579
1580 return !stream_is_in_state(bap_stream, BT_BAP_EP_STATE_IDLE);
1581 }
1582
valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_stop_param * param)1583 static bool valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_stop_param *param)
1584 {
1585 struct bt_bap_unicast_group *unicast_group = NULL;
1586
1587 CHECKIF(param == NULL) {
1588 LOG_DBG("param is NULL");
1589 return false;
1590 }
1591
1592 CHECKIF(param->count == 0) {
1593 LOG_DBG("Invalid param->count: %u", param->count);
1594 return false;
1595 }
1596
1597 CHECKIF(param->streams == NULL) {
1598 LOG_DBG("param->streams is NULL");
1599 return false;
1600 }
1601
1602 CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
1603 LOG_DBG("param->count (%zu) is larger than "
1604 "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)",
1605 param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT);
1606 return false;
1607 }
1608
1609 for (size_t i = 0U; i < param->count; i++) {
1610 const struct bt_cap_stream *cap_stream = param->streams[i];
1611 const struct bt_bap_stream *bap_stream;
1612 struct bt_conn *conn;
1613
1614 CHECKIF(cap_stream == NULL) {
1615 LOG_DBG("param->streams[%zu] is NULL", i);
1616 return false;
1617 }
1618
1619 bap_stream = &cap_stream->bap_stream;
1620 conn = bap_stream->conn;
1621 CHECKIF(conn == NULL) {
1622 LOG_DBG("param->streams[%zu]->bap_stream.conn is NULL", i);
1623
1624 return -EINVAL;
1625 }
1626
1627 CHECKIF(bap_stream->group == NULL) {
1628 LOG_DBG("param->streams[%zu] is not in a unicast group", i);
1629 return false;
1630 }
1631
1632 /* Use the group of the first stream for comparison */
1633 if (unicast_group == NULL) {
1634 unicast_group = bap_stream->group;
1635 } else {
1636 CHECKIF(bap_stream->group != unicast_group) {
1637 LOG_DBG("param->streams[%zu] is not in this group %p", i,
1638 unicast_group);
1639 return false;
1640 }
1641 }
1642
1643 if (!can_release(bap_stream)) {
1644 LOG_DBG("Cannot stop param->streams[%zu]", i);
1645
1646 return false;
1647 }
1648
1649 for (size_t j = 0U; j < i; j++) {
1650 if (param->streams[j] == cap_stream) {
1651 LOG_DBG("param->stream_params[%zu] (%p) is "
1652 "duplicated by "
1653 "param->stream_params[%zu] (%p)",
1654 j, param->streams[j], i, cap_stream);
1655 return false;
1656 }
1657 }
1658 }
1659
1660 return true;
1661 }
1662
bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param * param)1663 int bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param *param)
1664 {
1665 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1666 struct bt_cap_initiator_proc_param *proc_param;
1667 struct bt_bap_stream *bap_stream;
1668 int err;
1669
1670 if (bt_cap_common_proc_is_active()) {
1671 LOG_DBG("A CAP procedure is already in progress");
1672
1673 return -EBUSY;
1674 }
1675
1676 if (!valid_unicast_audio_stop_param(param)) {
1677 return -EINVAL;
1678 }
1679
1680 for (size_t i = 0U; i < param->count; i++) {
1681 struct bt_cap_stream *cap_stream = param->streams[i];
1682
1683 active_proc->proc_param.initiator[i].stream = cap_stream;
1684 }
1685
1686 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_STOP, param->count);
1687
1688 bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE);
1689
1690 /** TODO: If this is a CSIP set, then the order of the procedures may
1691 * not match the order in the parameters, and the CSIP ordered access
1692 * procedure should be used.
1693 */
1694 proc_param = get_next_proc_param(active_proc);
1695 __ASSERT(proc_param != NULL, "proc is not done, but could not get next proc_param");
1696
1697 bap_stream = &proc_param->stream->bap_stream;
1698 active_proc->proc_initiated_cnt++;
1699
1700 err = bt_bap_stream_release(bap_stream);
1701 if (err != 0) {
1702 LOG_DBG("Failed to stop bap_stream %p: %d", proc_param->stream, err);
1703
1704 bt_cap_common_clear_active_proc();
1705 }
1706
1707 return err;
1708 }
1709
bt_cap_initiator_released(struct bt_cap_stream * cap_stream)1710 void bt_cap_initiator_released(struct bt_cap_stream *cap_stream)
1711 {
1712 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1713
1714 if (!bt_cap_common_stream_in_active_proc(cap_stream)) {
1715 /* State change happened outside of a procedure; ignore */
1716 return;
1717 }
1718
1719 if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) {
1720 /* Unexpected callback - Abort */
1721 bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG);
1722 } else {
1723 update_proc_done_cnt(active_proc);
1724
1725 LOG_DBG("Stream %p released (%zu/%zu streams done)", cap_stream,
1726 active_proc->proc_done_cnt, active_proc->proc_cnt);
1727 }
1728
1729 if (bt_cap_common_proc_is_aborted()) {
1730 if (bt_cap_common_proc_all_handled()) {
1731 cap_initiator_unicast_audio_proc_complete();
1732 }
1733
1734 return;
1735 }
1736
1737 if (!bt_cap_common_proc_is_done()) {
1738 struct bt_cap_stream *next_cap_stream =
1739 active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream;
1740 struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream;
1741 int err;
1742
1743 active_proc->proc_initiated_cnt++;
1744 /* Since BAP operations may require a write long or a read long on the
1745 * notification, we cannot assume that we can do multiple streams at once,
1746 * thus do it one at a time.
1747 * TODO: We should always be able to do one per ACL, so there is room for
1748 * optimization.
1749 */
1750 err = bt_bap_stream_release(bap_stream);
1751 if (err != 0) {
1752 LOG_DBG("Failed to release stream %p: %d", next_cap_stream, err);
1753
1754 bt_cap_common_abort_proc(bap_stream->conn, err);
1755 cap_initiator_unicast_audio_proc_complete();
1756 }
1757 } else {
1758 cap_initiator_unicast_audio_proc_complete();
1759 }
1760 }
1761
1762 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1763
1764 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)
1765
bt_cap_initiator_unicast_to_broadcast(const struct bt_cap_unicast_to_broadcast_param * param,struct bt_cap_broadcast_source ** source)1766 int bt_cap_initiator_unicast_to_broadcast(
1767 const struct bt_cap_unicast_to_broadcast_param *param,
1768 struct bt_cap_broadcast_source **source)
1769 {
1770 return -ENOSYS;
1771 }
1772
bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param * param,struct bt_bap_unicast_group ** unicast_group)1773 int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param *param,
1774 struct bt_bap_unicast_group **unicast_group)
1775 {
1776 return -ENOSYS;
1777 }
1778
1779 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE && CONFIG_BT_BAP_UNICAST_CLIENT */
1780