1 /*
2 * Copyright (c) 2022-2023 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/aics.h>
15 #include <zephyr/bluetooth/audio/audio.h>
16 #include <zephyr/bluetooth/audio/bap.h>
17 #include <zephyr/bluetooth/audio/cap.h>
18 #include <zephyr/bluetooth/audio/csip.h>
19 #include <zephyr/bluetooth/audio/micp.h>
20 #include <zephyr/bluetooth/audio/vcp.h>
21 #include <zephyr/bluetooth/audio/vocs.h>
22 #include <zephyr/bluetooth/addr.h>
23 #include <zephyr/bluetooth/conn.h>
24 #include <zephyr/bluetooth/gap.h>
25 #include <zephyr/bluetooth/gatt.h>
26 #include <zephyr/logging/log.h>
27 #include <zephyr/sys/__assert.h>
28 #include <zephyr/sys/check.h>
29 #include <zephyr/sys/util.h>
30
31 #include "audio_internal.h"
32 #include "bap_endpoint.h"
33 #include "bap_internal.h"
34 #include "cap_internal.h"
35 #include "csip_internal.h"
36
37 LOG_MODULE_REGISTER(bt_cap_commander, CONFIG_BT_CAP_COMMANDER_LOG_LEVEL);
38
39 #include "common/bt_str.h"
40
41 static void cap_commander_proc_complete(void);
42
43 static const struct bt_cap_commander_cb *cap_cb;
44
bt_cap_commander_register_cb(const struct bt_cap_commander_cb * cb)45 int bt_cap_commander_register_cb(const struct bt_cap_commander_cb *cb)
46 {
47 CHECKIF(cb == NULL) {
48 LOG_DBG("cb is NULL");
49
50 return -EINVAL;
51 }
52
53 CHECKIF(cap_cb != NULL) {
54 LOG_DBG("callbacks already registered");
55
56 return -EALREADY;
57 }
58
59 cap_cb = cb;
60
61 return 0;
62 }
63
bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb * cb)64 int bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb *cb)
65 {
66 CHECKIF(cb == NULL) {
67 LOG_DBG("cb is NULL");
68 return -EINVAL;
69 }
70
71 CHECKIF(cap_cb != cb) {
72 LOG_DBG("cb is not registered");
73 return -EINVAL;
74 }
75
76 cap_cb = NULL;
77
78 return 0;
79 }
80
81 static void
cap_commander_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)82 cap_commander_discover_complete(struct bt_conn *conn, int err,
83 const struct bt_csip_set_coordinator_set_member *member,
84 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
85 {
86 if (cap_cb && cap_cb->discovery_complete) {
87 cap_cb->discovery_complete(conn, err, member, csis_inst);
88 }
89 }
90
bt_cap_commander_discover(struct bt_conn * conn)91 int bt_cap_commander_discover(struct bt_conn *conn)
92 {
93 CHECKIF(conn == NULL) {
94 LOG_DBG("NULL conn");
95 return -EINVAL;
96 }
97
98 return bt_cap_common_discover(conn, cap_commander_discover_complete);
99 }
100
101 #if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
102 static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cb;
103 static bool broadcast_assistant_cb_registered;
104
105 static void
copy_broadcast_reception_start_param(struct bt_bap_broadcast_assistant_add_src_param * add_src_param,struct cap_broadcast_reception_start * start_param)106 copy_broadcast_reception_start_param(struct bt_bap_broadcast_assistant_add_src_param *add_src_param,
107 struct cap_broadcast_reception_start *start_param)
108 {
109 bt_addr_le_copy(&add_src_param->addr, &start_param->addr);
110 add_src_param->adv_sid = start_param->adv_sid;
111 add_src_param->broadcast_id = start_param->broadcast_id;
112 add_src_param->pa_sync = true;
113 add_src_param->pa_interval = start_param->pa_interval;
114 add_src_param->num_subgroups = start_param->num_subgroups;
115 add_src_param->subgroups = start_param->subgroups;
116 }
117
cap_commander_broadcast_assistant_add_src_cb(struct bt_conn * conn,int err)118 static void cap_commander_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err)
119 {
120 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
121 struct bt_bap_broadcast_assistant_add_src_param add_src_param = {0};
122
123 LOG_DBG("conn %p", (void *)conn);
124
125 if (!bt_cap_common_conn_in_active_proc(conn)) {
126
127 /* State change happened outside of a procedure; ignore */
128 return;
129 }
130
131 if (err != 0) {
132 LOG_DBG("Failed to add source: %d", err);
133 LOG_DBG("Aborting the proc %d %d", active_proc->proc_done_cnt,
134 active_proc->proc_initiated_cnt);
135
136 bt_cap_common_abort_proc(conn, err);
137 } else {
138 active_proc->proc_done_cnt++;
139
140 LOG_DBG("Conn %p broadcast source added (%zu/%zu streams done)", (void *)conn,
141 active_proc->proc_done_cnt, active_proc->proc_cnt);
142 }
143
144 if (bt_cap_common_proc_is_aborted()) {
145 if (bt_cap_common_proc_all_handled()) {
146 cap_commander_proc_complete();
147 }
148
149 return;
150 }
151
152 if (!bt_cap_common_proc_is_done()) {
153 struct bt_cap_commander_proc_param *proc_param;
154
155 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
156 conn = proc_param->conn;
157 copy_broadcast_reception_start_param(&add_src_param,
158 &proc_param->broadcast_reception_start);
159
160 active_proc->proc_initiated_cnt++;
161 err = bt_bap_broadcast_assistant_add_src(conn, &add_src_param);
162 if (err != 0) {
163 LOG_DBG("Failed to perform broadcast reception start for conn %p: %d",
164 (void *)conn, err);
165 bt_cap_common_abort_proc(conn, err);
166 cap_commander_proc_complete();
167 }
168 } else {
169 cap_commander_proc_complete();
170 }
171 }
172
cap_commander_register_broadcast_assistant_cb(void)173 static int cap_commander_register_broadcast_assistant_cb(void)
174 {
175 int err;
176
177 err = bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cb);
178 if (err != 0) {
179 LOG_DBG("Failed to register broadcast assistant callbacks: %d", err);
180
181 return -ENOEXEC;
182 }
183
184 broadcast_assistant_cb_registered = true;
185
186 return 0;
187 }
188
valid_broadcast_reception_start_param(const struct bt_cap_commander_broadcast_reception_start_param * param)189 static bool valid_broadcast_reception_start_param(
190 const struct bt_cap_commander_broadcast_reception_start_param *param)
191 {
192 uint32_t total_bis_sync = 0U;
193
194 CHECKIF(param == NULL) {
195 LOG_DBG("param is NULL");
196 return false;
197 }
198
199 CHECKIF(param->count == 0) {
200 LOG_DBG("Invalid param->count: %zu", param->count);
201 return false;
202 }
203
204 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
205 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
206 CONFIG_BT_MAX_CONN);
207 return false;
208 }
209
210 CHECKIF(param->param == NULL) {
211 LOG_DBG("param->param is NULL");
212 return false;
213 }
214
215 for (size_t i = 0; i < param->count; i++) {
216 const struct bt_cap_commander_broadcast_reception_start_member_param *start_param =
217 ¶m->param[i];
218 const union bt_cap_set_member *member = ¶m->param[i].member;
219 const struct bt_conn *member_conn =
220 bt_cap_common_get_member_conn(param->type, member);
221
222 if (member == NULL) {
223 LOG_DBG("param->param[%zu].member is NULL", i);
224 return false;
225 }
226
227 if (member_conn == NULL) {
228 LOG_DBG("Invalid param->param[%zu].member", i);
229 return false;
230 }
231
232 CHECKIF(start_param->addr.type > BT_ADDR_LE_RANDOM) {
233 LOG_DBG("Invalid address type %u", start_param->addr.type);
234 return false;
235 }
236
237 CHECKIF(start_param->adv_sid > BT_GAP_SID_MAX) {
238 LOG_DBG("param->param[%zu]->adv_sid is larger than %d", i, BT_GAP_SID_MAX);
239 return false;
240 }
241
242 CHECKIF(!IN_RANGE(start_param->pa_interval, BT_GAP_PER_ADV_MIN_INTERVAL,
243 BT_GAP_PER_ADV_MAX_INTERVAL)) {
244 LOG_DBG("param->param[%zu]->pa_interval is out of range", i);
245 return false;
246 }
247
248 CHECKIF(start_param->broadcast_id > BT_AUDIO_BROADCAST_ID_MAX) {
249 LOG_DBG("param->param[%zu]->broadcast_id is larger than %u", i,
250 BT_AUDIO_BROADCAST_ID_MAX);
251 return false;
252 }
253
254 CHECKIF(start_param->num_subgroups == 0) {
255 LOG_DBG("param->param[%zu]->num_subgroups is 0", i);
256 return false;
257 }
258
259 CHECKIF(start_param->num_subgroups > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) {
260 LOG_DBG("Too many subgroups %u/%u", start_param->num_subgroups,
261 CONFIG_BT_BAP_BASS_MAX_SUBGROUPS);
262
263 return false;
264 }
265
266 CHECKIF(start_param->subgroups == NULL) {
267 LOG_DBG("param->param[%zu]->subgroup is NULL", i);
268 return false;
269 }
270
271 total_bis_sync = 0U;
272 for (size_t j = 0U; j < start_param->num_subgroups; j++) {
273 const struct bt_bap_bass_subgroup *param_subgroups =
274 &start_param->subgroups[j];
275
276 CHECKIF(!valid_bis_syncs(param_subgroups->bis_sync)) {
277 LOG_DBG("param->param[%zu].subgroup[%zu].bis_sync is invalid %u", i,
278 j, param_subgroups->bis_sync);
279
280 return false;
281 }
282
283 CHECKIF((total_bis_sync & param_subgroups->bis_sync) != 0) {
284 LOG_DBG("param->param[%zu].subgroup[%zu].bis_sync 0x%08X has "
285 "duplicate bits (0x%08X) ",
286 i, j, param_subgroups->bis_sync, total_bis_sync);
287
288 return false;
289 }
290
291 total_bis_sync |= param_subgroups->bis_sync;
292
293 CHECKIF(param_subgroups->metadata_len >
294 CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
295 LOG_DBG("param->param[%zu].subgroup[%zu].metadata_len too long "
296 "%u/%u",
297 i, j, param_subgroups->metadata_len,
298 CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
299
300 return false;
301 }
302 #if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE)
303 CHECKIF(param_subgroups->metadata_len > 0 &&
304 !bt_audio_valid_ltv(param_subgroups->metadata,
305 param_subgroups->metadata_len)) {
306 LOG_DBG("param->param[%zu].subgroup[%zu].metadata not valid LTV", i,
307 j);
308 }
309 #endif
310 }
311
312 for (size_t j = 0U; j < i; j++) {
313 const union bt_cap_set_member *other = ¶m->param[j].member;
314
315 if (other == member) {
316 LOG_DBG("param->members[%zu] (%p) is duplicated by "
317 "param->members[%zu] (%p)",
318 j, other, i, member);
319 return false;
320 }
321 }
322 }
323
324 return true;
325 }
326
bt_cap_commander_broadcast_reception_start(const struct bt_cap_commander_broadcast_reception_start_param * param)327 int bt_cap_commander_broadcast_reception_start(
328 const struct bt_cap_commander_broadcast_reception_start_param *param)
329 {
330 struct bt_bap_broadcast_assistant_add_src_param add_src_param = {0};
331 struct bt_cap_commander_proc_param *proc_param;
332 struct bt_cap_common_proc *active_proc;
333 struct bt_conn *conn;
334 int err;
335
336 if (bt_cap_common_proc_is_active()) {
337 LOG_DBG("A CAP procedure is already in progress");
338
339 return -EBUSY;
340 }
341
342 if (!valid_broadcast_reception_start_param(param)) {
343 return -EINVAL;
344 }
345
346 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START, param->count);
347
348 broadcast_assistant_cb.add_src = cap_commander_broadcast_assistant_add_src_cb;
349 if (!broadcast_assistant_cb_registered &&
350 cap_commander_register_broadcast_assistant_cb() != 0) {
351 LOG_DBG("Failed to register broadcast assistant callbacks");
352
353 return -ENOEXEC;
354 }
355
356 active_proc = bt_cap_common_get_active_proc();
357
358 for (size_t i = 0U; i < param->count; i++) {
359 const struct bt_cap_commander_broadcast_reception_start_member_param *member_param =
360 ¶m->param[i];
361 struct bt_cap_commander_proc_param *stored_param;
362 struct bt_conn *member_conn =
363 bt_cap_common_get_member_conn(param->type, &member_param->member);
364
365 if (member_conn == NULL) {
366 LOG_DBG("Invalid param->members[%zu]", i);
367
368 return -EINVAL;
369 }
370
371 /* Store the necessary parameters as we cannot assume that the supplied parameters
372 * are kept valid
373 * TODO: consider putting this into a function
374 */
375 stored_param = &active_proc->proc_param.commander[i];
376 stored_param->conn = member_conn;
377 bt_addr_le_copy(&stored_param->broadcast_reception_start.addr, &member_param->addr);
378 stored_param->broadcast_reception_start.adv_sid = member_param->adv_sid;
379 stored_param->broadcast_reception_start.broadcast_id = member_param->broadcast_id;
380 stored_param->broadcast_reception_start.pa_interval = member_param->pa_interval;
381 stored_param->broadcast_reception_start.num_subgroups = member_param->num_subgroups;
382 memcpy(stored_param->broadcast_reception_start.subgroups, member_param->subgroups,
383 sizeof(struct bt_bap_bass_subgroup) * member_param->num_subgroups);
384 }
385
386 active_proc->proc_initiated_cnt++;
387
388 proc_param = &active_proc->proc_param.commander[0];
389
390 conn = proc_param->conn;
391 copy_broadcast_reception_start_param(&add_src_param,
392 &proc_param->broadcast_reception_start);
393
394 /* TODO: what to do if we are adding a source that has already been added? */
395 err = bt_bap_broadcast_assistant_add_src(conn, &add_src_param);
396 if (err != 0) {
397 LOG_DBG("Failed to start broadcast reception for conn %p: %d", (void *)conn, err);
398
399 return -ENOEXEC;
400 }
401
402 return 0;
403 }
404
405 static void
copy_broadcast_reception_stop_param(struct bt_bap_broadcast_assistant_mod_src_param * mod_src_param,struct cap_broadcast_reception_stop * stop_param)406 copy_broadcast_reception_stop_param(struct bt_bap_broadcast_assistant_mod_src_param *mod_src_param,
407 struct cap_broadcast_reception_stop *stop_param)
408 {
409 mod_src_param->src_id = stop_param->src_id;
410 mod_src_param->pa_sync = false;
411 mod_src_param->pa_interval = BT_BAP_PA_INTERVAL_UNKNOWN;
412 mod_src_param->num_subgroups = stop_param->num_subgroups;
413
414 mod_src_param->subgroups = stop_param->subgroups;
415 }
416
cap_commander_broadcast_assistant_recv_state_cb(struct bt_conn * conn,int err,const struct bt_bap_scan_delegator_recv_state * state)417 static void cap_commander_broadcast_assistant_recv_state_cb(
418 struct bt_conn *conn, int err, const struct bt_bap_scan_delegator_recv_state *state)
419 {
420 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
421
422 if (state == NULL) {
423 /* Empty receive state, indicating that the source has been removed
424 */
425 return;
426 }
427
428 if (bt_cap_common_conn_in_active_proc(conn) &&
429 active_proc->proc_type == BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP) {
430
431 LOG_DBG("BASS recv state: conn %p, src_id %u", (void *)conn, state->src_id);
432
433 for (uint8_t i = 0; i < state->num_subgroups; i++) {
434 const struct bt_bap_bass_subgroup *subgroup = &state->subgroups[i];
435
436 /* if bis_sync not equals 0 we can not remove the source (yet)
437 * and we need to wait for another notification
438 */
439 if (subgroup->bis_sync != 0) {
440 return;
441 }
442 }
443
444 LOG_DBG("Removing source for conn %p", (void *)conn);
445 err = bt_bap_broadcast_assistant_rem_src(conn, state->src_id);
446 if (err != 0) {
447 LOG_DBG("Failed to rem_src for conn %p: %d", (void *)conn, err);
448 bt_cap_common_abort_proc(conn, err);
449 cap_commander_proc_complete();
450 }
451 }
452 }
453
cap_commander_broadcast_assistant_rem_src_cb(struct bt_conn * conn,int err)454 static void cap_commander_broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err)
455 {
456 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
457 struct bt_bap_broadcast_assistant_mod_src_param mod_src_param = {0};
458
459 if (!bt_cap_common_conn_in_active_proc(conn)) {
460 /* State change happened outside of a procedure; ignore */
461 return;
462 }
463
464 if (err != 0) {
465 LOG_DBG("Failed removing source: %d", err);
466 LOG_DBG("Aborting the proc %d %d", active_proc->proc_done_cnt,
467 active_proc->proc_initiated_cnt);
468
469 bt_cap_common_abort_proc(conn, err);
470 } else {
471 active_proc->proc_done_cnt++;
472
473 LOG_DBG("Conn %p broadcast source removed (%zu/%zu streams done)", (void *)conn,
474 active_proc->proc_done_cnt, active_proc->proc_cnt);
475 }
476
477 if (bt_cap_common_proc_is_aborted()) {
478 if (bt_cap_common_proc_all_handled()) {
479 cap_commander_proc_complete();
480 }
481
482 return;
483 }
484
485 if (!bt_cap_common_proc_is_done()) {
486 struct bt_cap_commander_proc_param *proc_param;
487
488 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
489 conn = proc_param->conn;
490 copy_broadcast_reception_stop_param(&mod_src_param,
491 &proc_param->broadcast_reception_stop);
492 active_proc->proc_initiated_cnt++;
493 err = bt_bap_broadcast_assistant_mod_src(conn, &mod_src_param);
494 if (err != 0) {
495 LOG_DBG("Failed to mod_src for conn %p: %d", (void *)conn, err);
496 bt_cap_common_abort_proc(conn, err);
497 cap_commander_proc_complete();
498 }
499 } else {
500 cap_commander_proc_complete();
501 }
502 }
503
cap_commander_broadcast_assistant_mod_src_cb(struct bt_conn * conn,int err)504 static void cap_commander_broadcast_assistant_mod_src_cb(struct bt_conn *conn, int err)
505 {
506 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
507
508 if (!bt_cap_common_conn_in_active_proc(conn)) {
509 /* State change happened outside of a procedure; ignore */
510 return;
511 }
512
513 if (err != 0) {
514 LOG_DBG("Failed modifying source: %d", err);
515 LOG_DBG("Aborting the proc %d %d", active_proc->proc_done_cnt,
516 active_proc->proc_initiated_cnt);
517
518 bt_cap_common_abort_proc(conn, err);
519 } else {
520 LOG_DBG("Conn %p broadcast source modifified (%zu/%zu streams done)", (void *)conn,
521 active_proc->proc_done_cnt, active_proc->proc_cnt);
522 }
523
524 if (bt_cap_common_proc_is_aborted()) {
525 if (bt_cap_common_proc_all_handled()) {
526 cap_commander_proc_complete();
527 }
528 }
529 }
530
valid_broadcast_reception_stop_param(const struct bt_cap_commander_broadcast_reception_stop_param * param)531 static bool valid_broadcast_reception_stop_param(
532 const struct bt_cap_commander_broadcast_reception_stop_param *param)
533 {
534 CHECKIF(param == NULL) {
535 LOG_DBG("param is NULL");
536 return false;
537 }
538
539 CHECKIF(param->count == 0) {
540 LOG_DBG("Invalid param->count: %zu", param->count);
541 return false;
542 }
543
544 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
545 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
546 CONFIG_BT_MAX_CONN);
547 return false;
548 }
549
550 CHECKIF(param->param == NULL) {
551 LOG_DBG("param->param is NULL");
552 return false;
553 }
554
555 for (size_t i = 0; i < param->count; i++) {
556 const struct bt_cap_commander_broadcast_reception_stop_member_param *stop_param =
557 ¶m->param[i];
558 const union bt_cap_set_member *member = ¶m->param[i].member;
559 const struct bt_conn *member_conn =
560 bt_cap_common_get_member_conn(param->type, member);
561
562 if (member == NULL) {
563 LOG_DBG("param->param[%zu].member is NULL", i);
564 return false;
565 }
566
567 if (member_conn == NULL) {
568 LOG_DBG("Invalid param->param[%zu].member", i);
569 return false;
570 }
571
572 CHECKIF(stop_param->num_subgroups == 0) {
573 LOG_DBG("param->param[%zu]->num_subgroups is 0", i);
574 return false;
575 }
576
577 CHECKIF(stop_param->num_subgroups > CONFIG_BT_BAP_BASS_MAX_SUBGROUPS) {
578 LOG_DBG("Too many subgroups %u/%u", stop_param->num_subgroups,
579 CONFIG_BT_BAP_BASS_MAX_SUBGROUPS);
580 return false;
581 }
582
583 for (size_t j = 0U; j < i; j++) {
584 const union bt_cap_set_member *other = ¶m->param[j].member;
585 uint8_t other_src_id = param->param[j].src_id;
586
587 if (other == member && stop_param->src_id == other_src_id) {
588 LOG_DBG("param->members[%zu], src_id %d (%p) is duplicated by "
589 "param->members[%zu], src_id %d (%p)",
590 j, other_src_id, other, i, stop_param->src_id, member);
591 return false;
592 }
593 }
594 }
595
596 return true;
597 }
598
bt_cap_commander_broadcast_reception_stop(const struct bt_cap_commander_broadcast_reception_stop_param * param)599 int bt_cap_commander_broadcast_reception_stop(
600 const struct bt_cap_commander_broadcast_reception_stop_param *param)
601 {
602 struct bt_bap_broadcast_assistant_mod_src_param mod_src_param = {0};
603 struct bt_cap_commander_proc_param *proc_param;
604 struct bt_cap_common_proc *active_proc;
605 struct bt_conn *conn;
606 int err;
607
608 if (bt_cap_common_proc_is_active()) {
609 LOG_DBG("A CAP procedure is already in progress");
610
611 return -EBUSY;
612 }
613
614 if (!valid_broadcast_reception_stop_param(param)) {
615 return -EINVAL;
616 }
617
618 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP, param->count);
619
620 broadcast_assistant_cb.mod_src = cap_commander_broadcast_assistant_mod_src_cb;
621 broadcast_assistant_cb.rem_src = cap_commander_broadcast_assistant_rem_src_cb;
622 broadcast_assistant_cb.recv_state = cap_commander_broadcast_assistant_recv_state_cb;
623 if (!broadcast_assistant_cb_registered &&
624 cap_commander_register_broadcast_assistant_cb() != 0) {
625 LOG_DBG("Failed to register broadcast assistant callbacks");
626
627 return -ENOEXEC;
628 }
629
630 active_proc = bt_cap_common_get_active_proc();
631
632 for (size_t i = 0U; i < param->count; i++) {
633 const struct bt_cap_commander_broadcast_reception_stop_member_param *member_param =
634 ¶m->param[i];
635 struct bt_cap_commander_proc_param *stored_param;
636 struct bt_conn *member_conn =
637 bt_cap_common_get_member_conn(param->type, &member_param->member);
638
639 if (member_conn == NULL) {
640 LOG_DBG("Invalid param->member[%zu]", i);
641
642 return -EINVAL;
643 }
644 /* Store the necessary parameters as we cannot assume that the supplied
645 * parameters are kept valid
646 */
647 stored_param = &active_proc->proc_param.commander[i];
648 stored_param->conn = member_conn;
649 stored_param->broadcast_reception_stop.src_id = member_param->src_id;
650 stored_param->broadcast_reception_stop.num_subgroups = member_param->num_subgroups;
651 for (size_t j = 0U; j < CONFIG_BT_BAP_BASS_MAX_SUBGROUPS; j++) {
652 stored_param->broadcast_reception_stop.subgroups[j].bis_sync = 0;
653 stored_param->broadcast_reception_stop.subgroups[j].metadata_len = 0;
654 }
655 }
656
657 proc_param = &active_proc->proc_param.commander[0];
658
659 conn = proc_param->conn;
660 copy_broadcast_reception_stop_param(&mod_src_param, &proc_param->broadcast_reception_stop);
661
662 active_proc->proc_initiated_cnt++;
663
664 err = bt_bap_broadcast_assistant_mod_src(conn, &mod_src_param);
665 if (err != 0) {
666 LOG_DBG("Failed to stop broadcast reception for conn %p: %d", (void *)conn, err);
667
668 return -ENOEXEC;
669 }
670
671 return 0;
672 }
673
cap_commander_broadcast_assistant_set_broadcast_code_cb(struct bt_conn * conn,int err)674 static void cap_commander_broadcast_assistant_set_broadcast_code_cb(struct bt_conn *conn, int err)
675 {
676 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
677
678 LOG_DBG("conn %p", (void *)conn);
679
680 if (!bt_cap_common_conn_in_active_proc(conn)) {
681 /* State change happened outside of a procedure; ignore */
682 return;
683 }
684
685 if (err != 0) {
686 LOG_DBG("Failed to distribute broadcast code: %d", err);
687
688 bt_cap_common_abort_proc(conn, err);
689 } else {
690 active_proc->proc_done_cnt++;
691
692 LOG_DBG("Conn %p broadcast code set (%zu/%zu done)", (void *)conn,
693 active_proc->proc_done_cnt, active_proc->proc_cnt);
694 }
695
696 if (bt_cap_common_proc_is_aborted()) {
697 if (bt_cap_common_proc_all_handled()) {
698 cap_commander_proc_complete();
699 }
700
701 return;
702 }
703
704 if (!bt_cap_common_proc_is_done()) {
705 struct bt_cap_commander_proc_param *proc_param;
706
707 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
708 conn = proc_param->conn;
709
710 active_proc->proc_initiated_cnt++;
711 err = bt_bap_broadcast_assistant_set_broadcast_code(
712 conn, proc_param->distribute_broadcast_code.src_id,
713 proc_param->distribute_broadcast_code.broadcast_code);
714 if (err != 0) {
715 LOG_DBG("Failed to perform set broadcast code for conn %p: %d",
716 (void *)conn, err);
717 bt_cap_common_abort_proc(conn, err);
718 cap_commander_proc_complete();
719 }
720 } else {
721 cap_commander_proc_complete();
722 }
723 }
724
valid_distribute_broadcast_code_param(const struct bt_cap_commander_distribute_broadcast_code_param * param)725 static bool valid_distribute_broadcast_code_param(
726 const struct bt_cap_commander_distribute_broadcast_code_param *param)
727 {
728 CHECKIF(param == NULL) {
729 LOG_DBG("param is NULL");
730 return false;
731 }
732
733 CHECKIF(param->count == 0) {
734 LOG_DBG("Invalid param->count: %zu", param->count);
735 return false;
736 }
737
738 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
739 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
740 CONFIG_BT_MAX_CONN);
741 return false;
742 }
743
744 CHECKIF(param->param == NULL) {
745 LOG_DBG("param->param is NULL");
746 return false;
747 }
748
749 for (size_t i = 0; i < param->count; i++) {
750 const union bt_cap_set_member *member = ¶m->param[i].member;
751 const struct bt_conn *member_conn =
752 bt_cap_common_get_member_conn(param->type, member);
753
754 if (member == NULL) {
755 LOG_DBG("param->param[%zu].member is NULL", i);
756 return false;
757 }
758
759 if (member_conn == NULL) {
760 LOG_DBG("Invalid param->param[%zu].member", i);
761 return false;
762 }
763
764 for (size_t j = 0U; j < i; j++) {
765 const union bt_cap_set_member *other = ¶m->param[j].member;
766 const struct bt_conn *other_conn =
767 bt_cap_common_get_member_conn(param->type, other);
768
769 if (other_conn == member_conn) {
770 LOG_DBG("param->param[%zu].member.member (%p) is duplicated by "
771 "param->member[%zu].member.member (%p)",
772 j, (void *)other_conn, i, (void *)member_conn);
773 return false;
774 }
775 }
776 }
777
778 return true;
779 }
780
bt_cap_commander_distribute_broadcast_code(const struct bt_cap_commander_distribute_broadcast_code_param * param)781 int bt_cap_commander_distribute_broadcast_code(
782 const struct bt_cap_commander_distribute_broadcast_code_param *param)
783 {
784 struct bt_cap_commander_proc_param *proc_param;
785 struct bt_cap_common_proc *active_proc;
786 struct bt_conn *conn;
787 int err;
788
789 if (bt_cap_common_proc_is_active()) {
790 LOG_DBG("A CAP procedure is already in progress");
791
792 return -EBUSY;
793 }
794
795 if (!valid_distribute_broadcast_code_param(param)) {
796 return -EINVAL;
797 }
798
799 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE, param->count);
800
801 broadcast_assistant_cb.broadcast_code =
802 cap_commander_broadcast_assistant_set_broadcast_code_cb;
803 if (!broadcast_assistant_cb_registered &&
804 cap_commander_register_broadcast_assistant_cb() != 0) {
805 LOG_DBG("Failed to register broadcast assistant callbacks");
806
807 return -ENOEXEC;
808 }
809
810 active_proc = bt_cap_common_get_active_proc();
811
812 for (size_t i = 0U; i < param->count; i++) {
813 const struct bt_cap_commander_distribute_broadcast_code_member_param *member_param =
814 ¶m->param[i];
815 struct bt_cap_commander_proc_param *stored_param;
816 struct bt_conn *member_conn =
817 bt_cap_common_get_member_conn(param->type, &member_param->member);
818
819 if (member_conn == NULL) {
820 LOG_DBG("Invalid param->member[%zu]", i);
821
822 return -EINVAL;
823 }
824
825 /* Store the necessary parameters as we cannot assume that the
826 * supplied parameters are kept valid
827 */
828 stored_param = &active_proc->proc_param.commander[i];
829 stored_param->conn = member_conn;
830 stored_param->distribute_broadcast_code.src_id = member_param->src_id;
831 memcpy(stored_param->distribute_broadcast_code.broadcast_code,
832 param->broadcast_code, BT_ISO_BROADCAST_CODE_SIZE);
833 }
834
835 active_proc->proc_initiated_cnt++;
836
837 proc_param = &active_proc->proc_param.commander[0];
838
839 conn = proc_param->conn;
840
841 err = bt_bap_broadcast_assistant_set_broadcast_code(
842 conn, proc_param->distribute_broadcast_code.src_id,
843 proc_param->distribute_broadcast_code.broadcast_code);
844
845 if (err != 0) {
846 LOG_DBG("Failed to start distribute broadcast code for conn %p: %d", (void *)conn,
847 err);
848
849 return -ENOEXEC;
850 }
851
852 return 0;
853 }
854
855 #endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
856
cap_commander_proc_complete(void)857 static void cap_commander_proc_complete(void)
858 {
859 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
860 enum bt_cap_common_proc_type proc_type;
861 struct bt_conn *failed_conn;
862 int err;
863
864 failed_conn = active_proc->failed_conn;
865 err = active_proc->err;
866 proc_type = active_proc->proc_type;
867 bt_cap_common_clear_active_proc();
868
869 if (cap_cb == NULL) {
870 return;
871 }
872
873 switch (proc_type) {
874 #if defined(CONFIG_BT_VCP_VOL_CTLR)
875 case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE:
876 if (cap_cb->volume_changed != NULL) {
877 cap_cb->volume_changed(failed_conn, err);
878 }
879 break;
880 case BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE:
881 if (cap_cb->volume_mute_changed != NULL) {
882 cap_cb->volume_mute_changed(failed_conn, err);
883 }
884 break;
885 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
886 case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE:
887 if (cap_cb->volume_offset_changed != NULL) {
888 cap_cb->volume_offset_changed(failed_conn, err);
889 }
890 break;
891 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
892 #endif /* CONFIG_BT_VCP_VOL_CTLR */
893 #if defined(CONFIG_BT_MICP_MIC_CTLR)
894 case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_MUTE_CHANGE:
895 if (cap_cb->microphone_mute_changed != NULL) {
896 cap_cb->microphone_mute_changed(failed_conn, err);
897 }
898 break;
899 #if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
900 case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_GAIN_CHANGE:
901 if (cap_cb->microphone_gain_changed != NULL) {
902 cap_cb->microphone_gain_changed(failed_conn, err);
903 }
904 break;
905 #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
906 #endif /* CONFIG_BT_MICP_MIC_CTLR */
907 #if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
908 case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START:
909 if (cap_cb->broadcast_reception_start != NULL) {
910 cap_cb->broadcast_reception_start(failed_conn, err);
911 }
912 break;
913 case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP:
914 if (cap_cb->broadcast_reception_stop != NULL) {
915 cap_cb->broadcast_reception_stop(failed_conn, err);
916 }
917 break;
918 case BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE:
919 if (cap_cb->distribute_broadcast_code != NULL) {
920 cap_cb->distribute_broadcast_code(failed_conn, err);
921 }
922 break;
923 #endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
924 case BT_CAP_COMMON_PROC_TYPE_NONE:
925 default:
926 __ASSERT(false, "Invalid proc_type: %u", proc_type);
927 }
928 }
929
bt_cap_commander_cancel(void)930 int bt_cap_commander_cancel(void)
931 {
932 if (!bt_cap_common_proc_is_active() && !bt_cap_common_proc_is_aborted()) {
933 LOG_DBG("No CAP procedure is in progress");
934
935 return -EALREADY;
936 }
937
938 bt_cap_common_abort_proc(NULL, -ECANCELED);
939 cap_commander_proc_complete();
940
941 return 0;
942 }
943
944 #if defined(CONFIG_BT_VCP_VOL_CTLR)
945 static struct bt_vcp_vol_ctlr_cb vol_ctlr_cb;
946 static bool vcp_cb_registered;
947
cap_commander_register_vcp_cb(void)948 static int cap_commander_register_vcp_cb(void)
949 {
950 int err;
951
952 err = bt_vcp_vol_ctlr_cb_register(&vol_ctlr_cb);
953 if (err != 0) {
954 LOG_DBG("Failed to register VCP callbacks: %d", err);
955
956 return -ENOEXEC;
957 }
958
959 vcp_cb_registered = true;
960
961 return 0;
962 }
963
valid_change_volume_param(const struct bt_cap_commander_change_volume_param * param)964 static bool valid_change_volume_param(const struct bt_cap_commander_change_volume_param *param)
965 {
966 CHECKIF(param == NULL) {
967 LOG_DBG("param is NULL");
968 return false;
969 }
970
971 CHECKIF(param->count == 0) {
972 LOG_DBG("Invalid param->count: %u", param->count);
973 return false;
974 }
975
976 CHECKIF(param->members == NULL) {
977 LOG_DBG("param->members is NULL");
978 return false;
979 }
980
981 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
982 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
983 CONFIG_BT_MAX_CONN);
984 return false;
985 }
986
987 for (size_t i = 0U; i < param->count; i++) {
988 const union bt_cap_set_member *member = ¶m->members[i];
989 const struct bt_conn *member_conn =
990 bt_cap_common_get_member_conn(param->type, member);
991
992 if (member == NULL) {
993 LOG_DBG("param->members[%zu] is NULL", i);
994 return false;
995 }
996
997 if (member_conn == NULL) {
998 LOG_DBG("Invalid param->members[%zu]", i);
999 return false;
1000 }
1001
1002 if (bt_vcp_vol_ctlr_get_by_conn(member_conn) == NULL) {
1003 LOG_DBG("Volume control not available for param->members[%zu]", i);
1004 return false;
1005 }
1006
1007 for (size_t j = 0U; j < i; j++) {
1008 const union bt_cap_set_member *other = ¶m->members[j];
1009
1010 if (other == member) {
1011 LOG_DBG("param->members[%zu] (%p) is duplicated by "
1012 "param->members[%zu] (%p)",
1013 j, other, i, member);
1014 return false;
1015 }
1016 }
1017 }
1018
1019 return true;
1020 }
1021
cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)1022 static void cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
1023 {
1024 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1025 struct bt_conn *conn;
1026 int vcp_err;
1027
1028 LOG_DBG("vol_ctlr %p", (void *)vol_ctlr);
1029
1030 vcp_err = bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
1031 if (vcp_err != 0) {
1032 LOG_ERR("Failed to get conn by vol_ctrl: %d", vcp_err);
1033 return;
1034 }
1035
1036 LOG_DBG("conn %p", (void *)conn);
1037 if (!bt_cap_common_conn_in_active_proc(conn)) {
1038 /* State change happened outside of a procedure; ignore */
1039 return;
1040 }
1041
1042 if (err != 0) {
1043 LOG_DBG("Failed to set volume: %d", err);
1044 bt_cap_common_abort_proc(conn, err);
1045 } else {
1046 active_proc->proc_done_cnt++;
1047
1048 LOG_DBG("Conn %p volume updated (%zu/%zu streams done)", (void *)conn,
1049 active_proc->proc_done_cnt, active_proc->proc_cnt);
1050 }
1051
1052 if (bt_cap_common_proc_is_aborted()) {
1053 LOG_DBG("Proc is aborted");
1054 if (bt_cap_common_proc_all_handled()) {
1055 LOG_DBG("All handled");
1056 cap_commander_proc_complete();
1057 }
1058
1059 return;
1060 }
1061
1062 if (!bt_cap_common_proc_is_done()) {
1063 const struct bt_cap_commander_proc_param *proc_param;
1064
1065 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
1066 conn = proc_param->conn;
1067 active_proc->proc_initiated_cnt++;
1068 err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn),
1069 proc_param->change_volume.volume);
1070 if (err != 0) {
1071 LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err);
1072 bt_cap_common_abort_proc(conn, err);
1073 cap_commander_proc_complete();
1074 }
1075 } else {
1076 cap_commander_proc_complete();
1077 }
1078 }
1079
bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_param * param)1080 int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_param *param)
1081 {
1082 const struct bt_cap_commander_proc_param *proc_param;
1083 struct bt_cap_common_proc *active_proc;
1084 struct bt_conn *conn;
1085 int err;
1086
1087 if (bt_cap_common_proc_is_active()) {
1088 LOG_DBG("A CAP procedure is already in progress");
1089
1090 return -EBUSY;
1091 }
1092
1093 if (!valid_change_volume_param(param)) {
1094 return -EINVAL;
1095 }
1096
1097 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, param->count);
1098
1099 vol_ctlr_cb.vol_set = cap_commander_vcp_vol_set_cb;
1100 if (!vcp_cb_registered && cap_commander_register_vcp_cb() != 0) {
1101 LOG_DBG("Failed to register VCP callbacks");
1102
1103 return -ENOEXEC;
1104 }
1105
1106 active_proc = bt_cap_common_get_active_proc();
1107
1108 for (size_t i = 0U; i < param->count; i++) {
1109 struct bt_conn *member_conn =
1110 bt_cap_common_get_member_conn(param->type, ¶m->members[i]);
1111
1112 if (member_conn == NULL) {
1113 LOG_DBG("Invalid param->members[%zu]", i);
1114 return -EINVAL;
1115 }
1116
1117 /* Store the necessary parameters as we cannot assume that the supplied parameters
1118 * are kept valid
1119 */
1120 active_proc->proc_param.commander[i].conn = member_conn;
1121 active_proc->proc_param.commander[i].change_volume.volume = param->volume;
1122 }
1123
1124 proc_param = &active_proc->proc_param.commander[0];
1125 conn = proc_param->conn;
1126 active_proc->proc_initiated_cnt++;
1127 err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn),
1128 proc_param->change_volume.volume);
1129 if (err != 0) {
1130 LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err);
1131 return -ENOEXEC;
1132 }
1133
1134 return 0;
1135 }
1136
valid_change_volume_mute_state_param(const struct bt_cap_commander_change_volume_mute_state_param * param)1137 static bool valid_change_volume_mute_state_param(
1138 const struct bt_cap_commander_change_volume_mute_state_param *param)
1139 {
1140 CHECKIF(param == NULL) {
1141 LOG_DBG("param is NULL");
1142 return false;
1143 }
1144
1145 CHECKIF(param->count == 0) {
1146 LOG_DBG("Invalid param->count: %u", param->count);
1147 return false;
1148 }
1149
1150 CHECKIF(param->members == NULL) {
1151 LOG_DBG("param->members is NULL");
1152 return false;
1153 }
1154
1155 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
1156 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
1157 CONFIG_BT_MAX_CONN);
1158 return false;
1159 }
1160
1161 for (size_t i = 0U; i < param->count; i++) {
1162 const union bt_cap_set_member *member = ¶m->members[i];
1163 const struct bt_conn *member_conn =
1164 bt_cap_common_get_member_conn(param->type, member);
1165
1166 if (member == NULL) {
1167 LOG_DBG("param->members[%zu] is NULL", i);
1168 return false;
1169 }
1170
1171 if (member_conn == NULL) {
1172 LOG_DBG("Invalid param->members[%zu]", i);
1173 return false;
1174 }
1175
1176 CHECKIF(bt_vcp_vol_ctlr_get_by_conn(member_conn) == NULL) {
1177 LOG_DBG("Volume control not available for param->members[%zu]", i);
1178 return false;
1179 }
1180
1181 for (size_t j = 0U; j < i; j++) {
1182 const union bt_cap_set_member *other = ¶m->members[j];
1183
1184 CHECKIF(other == member) {
1185 LOG_DBG("param->members[%zu] (%p) is duplicated by "
1186 "param->members[%zu] (%p)",
1187 j, other, i, member);
1188 return false;
1189 }
1190 }
1191 }
1192
1193 return true;
1194 }
1195
cap_commander_vcp_vol_mute_cb(struct bt_vcp_vol_ctlr * vol_ctlr,int err)1196 static void cap_commander_vcp_vol_mute_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err)
1197 {
1198 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1199 struct bt_conn *conn;
1200 int vcp_err;
1201
1202 LOG_DBG("vol_ctlr %p", (void *)vol_ctlr);
1203
1204 vcp_err = bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn);
1205 if (vcp_err != 0) {
1206 LOG_ERR("Failed to get conn by vol_ctrl: %d", vcp_err);
1207 return;
1208 }
1209
1210 LOG_DBG("conn %p", (void *)conn);
1211 if (!bt_cap_common_conn_in_active_proc(conn)) {
1212 /* State change happened outside of a procedure; ignore */
1213 return;
1214 }
1215
1216 if (err != 0) {
1217 LOG_DBG("Failed to set volume: %d", err);
1218 bt_cap_common_abort_proc(conn, err);
1219 } else {
1220 active_proc->proc_done_cnt++;
1221
1222 LOG_DBG("Conn %p volume updated (%zu/%zu streams done)", (void *)conn,
1223 active_proc->proc_done_cnt, active_proc->proc_cnt);
1224 }
1225
1226 if (bt_cap_common_proc_is_aborted()) {
1227 LOG_DBG("Proc is aborted");
1228 if (bt_cap_common_proc_all_handled()) {
1229 LOG_DBG("All handled");
1230 cap_commander_proc_complete();
1231 }
1232
1233 return;
1234 }
1235
1236 if (!bt_cap_common_proc_is_done()) {
1237 const struct bt_cap_commander_proc_param *proc_param;
1238
1239 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
1240 conn = proc_param->conn;
1241 active_proc->proc_initiated_cnt++;
1242 if (proc_param->change_vol_mute.mute) {
1243 err = bt_vcp_vol_ctlr_mute(bt_vcp_vol_ctlr_get_by_conn(conn));
1244 } else {
1245 err = bt_vcp_vol_ctlr_unmute(bt_vcp_vol_ctlr_get_by_conn(conn));
1246 }
1247
1248 if (err != 0) {
1249 LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err);
1250 bt_cap_common_abort_proc(conn, err);
1251 cap_commander_proc_complete();
1252 }
1253 } else {
1254 cap_commander_proc_complete();
1255 }
1256 }
1257
bt_cap_commander_change_volume_mute_state(const struct bt_cap_commander_change_volume_mute_state_param * param)1258 int bt_cap_commander_change_volume_mute_state(
1259 const struct bt_cap_commander_change_volume_mute_state_param *param)
1260 {
1261 const struct bt_cap_commander_proc_param *proc_param;
1262 struct bt_cap_common_proc *active_proc;
1263 struct bt_conn *conn;
1264 int err;
1265
1266 if (bt_cap_common_proc_is_active()) {
1267 LOG_DBG("A CAP procedure is already in progress");
1268
1269 return -EBUSY;
1270 }
1271
1272 if (!valid_change_volume_mute_state_param(param)) {
1273 return -EINVAL;
1274 }
1275
1276 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE, param->count);
1277
1278 vol_ctlr_cb.mute = cap_commander_vcp_vol_mute_cb;
1279 vol_ctlr_cb.unmute = cap_commander_vcp_vol_mute_cb;
1280 if (!vcp_cb_registered && cap_commander_register_vcp_cb() != 0) {
1281 LOG_DBG("Failed to register VCP callbacks");
1282
1283 return -ENOEXEC;
1284 }
1285
1286 active_proc = bt_cap_common_get_active_proc();
1287
1288 for (size_t i = 0U; i < param->count; i++) {
1289 struct bt_conn *member_conn =
1290 bt_cap_common_get_member_conn(param->type, ¶m->members[i]);
1291
1292 CHECKIF(member_conn == NULL) {
1293 LOG_DBG("Invalid param->members[%zu]", i);
1294 return -EINVAL;
1295 }
1296
1297 /* Store the necessary parameters as we cannot assume that the supplied parameters
1298 * are kept valid
1299 */
1300 active_proc->proc_param.commander[i].conn = member_conn;
1301 active_proc->proc_param.commander[i].change_vol_mute.mute = param->mute;
1302 }
1303
1304 proc_param = &active_proc->proc_param.commander[0];
1305 conn = proc_param->conn;
1306 active_proc->proc_initiated_cnt++;
1307
1308 if (proc_param->change_vol_mute.mute) {
1309 err = bt_vcp_vol_ctlr_mute(bt_vcp_vol_ctlr_get_by_conn(conn));
1310 } else {
1311 err = bt_vcp_vol_ctlr_unmute(bt_vcp_vol_ctlr_get_by_conn(conn));
1312 }
1313
1314 if (err != 0) {
1315 LOG_DBG("Failed to set volume mute state for conn %p: %d", (void *)conn, err);
1316 return -ENOEXEC;
1317 }
1318
1319 return 0;
1320 }
1321
1322 #if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
1323 static bool
valid_change_offset_param(const struct bt_cap_commander_change_volume_offset_param * param)1324 valid_change_offset_param(const struct bt_cap_commander_change_volume_offset_param *param)
1325 {
1326 CHECKIF(param == NULL) {
1327 LOG_DBG("param is NULL");
1328 return false;
1329 }
1330
1331 CHECKIF(param->count == 0) {
1332 LOG_DBG("Invalid param->count: %u", param->count);
1333 return false;
1334 }
1335
1336 CHECKIF(param->param == NULL) {
1337 LOG_DBG("param->param is NULL");
1338 return false;
1339 }
1340
1341 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
1342 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
1343 CONFIG_BT_MAX_CONN);
1344 return false;
1345 }
1346
1347 for (size_t i = 0U; i < param->count; i++) {
1348 const struct bt_cap_commander_change_volume_offset_member_param *member_param =
1349 ¶m->param[i];
1350 const union bt_cap_set_member *member = &member_param->member;
1351 const struct bt_conn *member_conn =
1352 bt_cap_common_get_member_conn(param->type, member);
1353 struct bt_vcp_vol_ctlr *vol_ctlr;
1354 struct bt_vcp_included included;
1355 int err;
1356
1357 if (member == NULL) {
1358 LOG_DBG("param->param[%zu].member is NULL", i);
1359 return false;
1360 }
1361
1362 if (member_conn == NULL) {
1363 LOG_DBG("Invalid param->param[%zu].member", i);
1364 return false;
1365 }
1366
1367 vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(member_conn);
1368 if (vol_ctlr == NULL) {
1369 LOG_DBG("Volume control not available for param->param[%zu].member", i);
1370 return false;
1371 }
1372
1373 err = bt_vcp_vol_ctlr_included_get(vol_ctlr, &included);
1374 if (err != 0 || included.vocs_cnt == 0) {
1375 LOG_DBG("Volume offset control not available for param->param[%zu].member",
1376 i);
1377 return -ENOEXEC;
1378 }
1379
1380 if (!IN_RANGE(member_param->offset, BT_VOCS_MIN_OFFSET, BT_VOCS_MAX_OFFSET)) {
1381 LOG_DBG("Invalid offset %d for param->param[%zu].offset",
1382 member_param->offset, i);
1383 return false;
1384 }
1385
1386 for (size_t j = 0U; j < i; j++) {
1387 const union bt_cap_set_member *other = ¶m->param[j].member;
1388
1389 if (other == member) {
1390 LOG_DBG("param->param[%zu].member (%p) is duplicated by "
1391 "param->param[%zu].member (%p)",
1392 j, other, i, member);
1393 return false;
1394 }
1395 }
1396 }
1397
1398 return true;
1399 }
1400
cap_commander_vcp_set_offset_cb(struct bt_vocs * inst,int err)1401 static void cap_commander_vcp_set_offset_cb(struct bt_vocs *inst, int err)
1402 {
1403 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1404 struct bt_conn *conn;
1405 int vocs_err;
1406
1407 LOG_DBG("bt_vocs %p", (void *)inst);
1408
1409 vocs_err = bt_vocs_client_conn_get(inst, &conn);
1410 if (vocs_err != 0) {
1411 LOG_ERR("Failed to get conn by inst: %d", vocs_err);
1412 return;
1413 }
1414
1415 LOG_DBG("conn %p", (void *)conn);
1416 if (!bt_cap_common_conn_in_active_proc(conn)) {
1417 /* State change happened outside of a procedure; ignore */
1418 return;
1419 }
1420
1421 if (err != 0) {
1422 LOG_DBG("Failed to set offset: %d", err);
1423 bt_cap_common_abort_proc(conn, err);
1424 } else {
1425 active_proc->proc_done_cnt++;
1426
1427 LOG_DBG("Conn %p offset updated (%zu/%zu streams done)", (void *)conn,
1428 active_proc->proc_done_cnt, active_proc->proc_cnt);
1429 }
1430
1431 if (bt_cap_common_proc_is_aborted()) {
1432 LOG_DBG("Proc is aborted");
1433 if (bt_cap_common_proc_all_handled()) {
1434 LOG_DBG("All handled");
1435 cap_commander_proc_complete();
1436 }
1437
1438 return;
1439 }
1440
1441 if (!bt_cap_common_proc_is_done()) {
1442 const struct bt_cap_commander_proc_param *proc_param;
1443
1444 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
1445 conn = proc_param->conn;
1446 active_proc->proc_initiated_cnt++;
1447
1448 err = bt_vocs_state_set(proc_param->change_offset.vocs,
1449 proc_param->change_offset.offset);
1450 if (err != 0) {
1451 LOG_DBG("Failed to set offset for conn %p: %d", (void *)conn, err);
1452 bt_cap_common_abort_proc(conn, err);
1453 cap_commander_proc_complete();
1454 }
1455 } else {
1456 cap_commander_proc_complete();
1457 }
1458 }
1459
bt_cap_commander_change_volume_offset(const struct bt_cap_commander_change_volume_offset_param * param)1460 int bt_cap_commander_change_volume_offset(
1461 const struct bt_cap_commander_change_volume_offset_param *param)
1462 {
1463 const struct bt_cap_commander_proc_param *proc_param;
1464 struct bt_cap_common_proc *active_proc;
1465 struct bt_vcp_vol_ctlr *vol_ctlr;
1466 struct bt_conn *conn;
1467 int err;
1468
1469 if (bt_cap_common_proc_is_active()) {
1470 LOG_DBG("A CAP procedure is already in progress");
1471
1472 return -EBUSY;
1473 }
1474
1475 if (!valid_change_offset_param(param)) {
1476 return -EINVAL;
1477 }
1478
1479 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE, param->count);
1480
1481 vol_ctlr_cb.vocs_cb.set_offset = cap_commander_vcp_set_offset_cb;
1482 if (!vcp_cb_registered && cap_commander_register_vcp_cb() != 0) {
1483 LOG_DBG("Failed to register VCP callbacks");
1484
1485 return -ENOEXEC;
1486 }
1487
1488 active_proc = bt_cap_common_get_active_proc();
1489
1490 for (size_t i = 0U; i < param->count; i++) {
1491 const struct bt_cap_commander_change_volume_offset_member_param *member_param =
1492 ¶m->param[i];
1493 struct bt_conn *member_conn =
1494 bt_cap_common_get_member_conn(param->type, &member_param->member);
1495 struct bt_vcp_included included;
1496
1497 if (member_conn == NULL) {
1498 LOG_DBG("Invalid param->members[%zu]", i);
1499 return -EINVAL;
1500 }
1501
1502 vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(member_conn);
1503 if (vol_ctlr == NULL) {
1504 LOG_DBG("Invalid param->members[%zu] vol_ctlr", i);
1505 return -EINVAL;
1506 }
1507
1508 err = bt_vcp_vol_ctlr_included_get(vol_ctlr, &included);
1509 if (err != 0 || included.vocs_cnt == 0) {
1510 LOG_DBG("Invalid param->members[%zu] vocs", i);
1511 return -EINVAL;
1512 }
1513
1514 /* Store the necessary parameters as we cannot assume that the supplied parameters
1515 * are kept valid
1516 */
1517 active_proc->proc_param.commander[i].conn = member_conn;
1518 active_proc->proc_param.commander[i].change_offset.offset = member_param->offset;
1519 /* TODO: For now we just use the first VOCS instance
1520 * - How should we handle multiple?
1521 */
1522 active_proc->proc_param.commander[i].change_offset.vocs = included.vocs[0];
1523 }
1524
1525 proc_param = &active_proc->proc_param.commander[0];
1526 conn = proc_param->conn;
1527 active_proc->proc_initiated_cnt++;
1528
1529 err = bt_vocs_state_set(proc_param->change_offset.vocs, proc_param->change_offset.offset);
1530 if (err != 0) {
1531 LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err);
1532 return -ENOEXEC;
1533 }
1534
1535 return 0;
1536 }
1537 #endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */
1538 #endif /* CONFIG_BT_VCP_VOL_CTLR */
1539
1540 #if defined(CONFIG_BT_MICP_MIC_CTLR)
1541 static struct bt_micp_mic_ctlr_cb mic_ctlr_cb;
1542 static bool micp_callbacks_registered;
1543
cap_commander_register_micp_callbacks(void)1544 static int cap_commander_register_micp_callbacks(void)
1545 {
1546 int err;
1547
1548 err = bt_micp_mic_ctlr_cb_register(&mic_ctlr_cb);
1549 if (err != 0) {
1550 LOG_DBG("Failed to register MICP callbacks: %d", err);
1551
1552 return -ENOEXEC;
1553 }
1554
1555 micp_callbacks_registered = true;
1556
1557 return 0;
1558 }
1559
valid_change_microphone_mute_state_param(const struct bt_cap_commander_change_microphone_mute_state_param * param)1560 static bool valid_change_microphone_mute_state_param(
1561 const struct bt_cap_commander_change_microphone_mute_state_param *param)
1562 {
1563 CHECKIF(param == NULL) {
1564 LOG_DBG("param is NULL");
1565 return false;
1566 }
1567
1568 CHECKIF(param->count == 0) {
1569 LOG_DBG("Invalid param->count: %u", param->count);
1570 return false;
1571 }
1572
1573 CHECKIF(param->members == NULL) {
1574 LOG_DBG("param->members is NULL");
1575 return false;
1576 }
1577
1578 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
1579 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
1580 CONFIG_BT_MAX_CONN);
1581 return false;
1582 }
1583
1584 for (size_t i = 0U; i < param->count; i++) {
1585 const union bt_cap_set_member *member = ¶m->members[i];
1586 const struct bt_conn *member_conn =
1587 bt_cap_common_get_member_conn(param->type, member);
1588
1589 if (member == NULL) {
1590 LOG_DBG("param->members[%zu] is NULL", i);
1591 return false;
1592 }
1593
1594 if (member_conn == NULL) {
1595 LOG_DBG("Invalid param->members[%zu]", i);
1596 return false;
1597 }
1598
1599 CHECKIF(bt_micp_mic_ctlr_get_by_conn(member_conn) == NULL) {
1600 LOG_DBG("Microphone control not available for param->members[%zu]", i);
1601 return false;
1602 }
1603
1604 for (size_t j = 0U; j < i; j++) {
1605 const union bt_cap_set_member *other = ¶m->members[j];
1606
1607 CHECKIF(other == member) {
1608 LOG_DBG("param->members[%zu] (%p) is duplicated by "
1609 "param->members[%zu] (%p)",
1610 j, other, i, member);
1611 return false;
1612 }
1613 }
1614 }
1615
1616 return true;
1617 }
1618
cap_commander_micp_mic_mute_cb(struct bt_micp_mic_ctlr * mic_ctlr,int err)1619 static void cap_commander_micp_mic_mute_cb(struct bt_micp_mic_ctlr *mic_ctlr, int err)
1620 {
1621 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1622 struct bt_conn *conn;
1623 int micp_err;
1624
1625 LOG_DBG("mic_ctlr %p", (void *)mic_ctlr);
1626
1627 micp_err = bt_micp_mic_ctlr_conn_get(mic_ctlr, &conn);
1628 if (micp_err != 0) {
1629 LOG_ERR("Failed to get conn by mic_ctlr: %d", micp_err);
1630 return;
1631 }
1632
1633 LOG_DBG("conn %p", (void *)conn);
1634 if (!bt_cap_common_conn_in_active_proc(conn)) {
1635 /* State change happened outside of a procedure; ignore */
1636 return;
1637 }
1638
1639 if (err != 0) {
1640 LOG_DBG("Failed to change microphone mute: %d", err);
1641 bt_cap_common_abort_proc(conn, err);
1642 } else {
1643 active_proc->proc_done_cnt++;
1644
1645 LOG_DBG("Conn %p mute updated (%zu/%zu streams done)", (void *)conn,
1646 active_proc->proc_done_cnt, active_proc->proc_cnt);
1647 }
1648
1649 if (bt_cap_common_proc_is_aborted()) {
1650 LOG_DBG("Proc is aborted");
1651 if (bt_cap_common_proc_all_handled()) {
1652 LOG_DBG("All handled");
1653 cap_commander_proc_complete();
1654 }
1655
1656 return;
1657 }
1658
1659 if (!bt_cap_common_proc_is_done()) {
1660 const struct bt_cap_commander_proc_param *proc_param;
1661
1662 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
1663 conn = proc_param->conn;
1664 active_proc->proc_initiated_cnt++;
1665 if (proc_param->change_mic_mute.mute) {
1666 err = bt_micp_mic_ctlr_mute(bt_micp_mic_ctlr_get_by_conn(conn));
1667 } else {
1668 err = bt_micp_mic_ctlr_unmute(bt_micp_mic_ctlr_get_by_conn(conn));
1669 }
1670
1671 if (err != 0) {
1672 LOG_DBG("Failed to change mute for conn %p: %d", (void *)conn, err);
1673 bt_cap_common_abort_proc(conn, err);
1674 cap_commander_proc_complete();
1675 }
1676 } else {
1677 cap_commander_proc_complete();
1678 }
1679 }
1680
bt_cap_commander_change_microphone_mute_state(const struct bt_cap_commander_change_microphone_mute_state_param * param)1681 int bt_cap_commander_change_microphone_mute_state(
1682 const struct bt_cap_commander_change_microphone_mute_state_param *param)
1683 {
1684 const struct bt_cap_commander_proc_param *proc_param;
1685 struct bt_cap_common_proc *active_proc;
1686 struct bt_conn *conn;
1687 int err;
1688
1689 if (bt_cap_common_proc_is_active()) {
1690 LOG_DBG("A CAP procedure is already in progress");
1691
1692 return -EBUSY;
1693 }
1694
1695 if (!valid_change_microphone_mute_state_param(param)) {
1696 return -EINVAL;
1697 }
1698
1699 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_MICROPHONE_MUTE_CHANGE, param->count);
1700
1701 mic_ctlr_cb.mute_written = cap_commander_micp_mic_mute_cb;
1702 mic_ctlr_cb.unmute_written = cap_commander_micp_mic_mute_cb;
1703 if (!micp_callbacks_registered && cap_commander_register_micp_callbacks() != 0) {
1704 LOG_DBG("Failed to register MICP callbacks");
1705
1706 return -ENOEXEC;
1707 }
1708
1709 active_proc = bt_cap_common_get_active_proc();
1710
1711 for (size_t i = 0U; i < param->count; i++) {
1712 struct bt_conn *member_conn =
1713 bt_cap_common_get_member_conn(param->type, ¶m->members[i]);
1714
1715 CHECKIF(member_conn == NULL) {
1716 LOG_DBG("Invalid param->members[%zu]", i);
1717 return -EINVAL;
1718 }
1719
1720 /* Store the necessary parameters as we cannot assume that the supplied parameters
1721 * are kept valid
1722 */
1723 active_proc->proc_param.commander[i].conn = member_conn;
1724 active_proc->proc_param.commander[i].change_mic_mute.mute = param->mute;
1725 }
1726
1727 proc_param = &active_proc->proc_param.commander[0];
1728 conn = proc_param->conn;
1729 active_proc->proc_initiated_cnt++;
1730
1731 if (proc_param->change_mic_mute.mute) {
1732 err = bt_micp_mic_ctlr_mute(bt_micp_mic_ctlr_get_by_conn(conn));
1733 } else {
1734 err = bt_micp_mic_ctlr_unmute(bt_micp_mic_ctlr_get_by_conn(conn));
1735 }
1736
1737 if (err != 0) {
1738 LOG_DBG("Failed to set microphone mute state for conn %p: %d", (void *)conn, err);
1739 return -ENOEXEC;
1740 }
1741
1742 return 0;
1743 }
1744
1745 #if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
valid_change_microphone_gain_param(const struct bt_cap_commander_change_microphone_gain_setting_param * param)1746 static bool valid_change_microphone_gain_param(
1747 const struct bt_cap_commander_change_microphone_gain_setting_param *param)
1748 {
1749 CHECKIF(param == NULL) {
1750 LOG_DBG("param is NULL");
1751 return false;
1752 }
1753
1754 CHECKIF(param->count == 0) {
1755 LOG_DBG("Invalid param->count: %u", param->count);
1756 return false;
1757 }
1758
1759 CHECKIF(param->param == NULL) {
1760 LOG_DBG("param->param is NULL");
1761 return false;
1762 }
1763
1764 CHECKIF(param->count > CONFIG_BT_MAX_CONN) {
1765 LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count,
1766 CONFIG_BT_MAX_CONN);
1767 return false;
1768 }
1769
1770 for (size_t i = 0U; i < param->count; i++) {
1771 const union bt_cap_set_member *member = ¶m->param[i].member;
1772 const struct bt_conn *member_conn =
1773 bt_cap_common_get_member_conn(param->type, member);
1774 struct bt_micp_mic_ctlr *mic_ctlr;
1775 struct bt_micp_included included;
1776 int err;
1777
1778 if (member == NULL) {
1779 LOG_DBG("param->param[%zu].member is NULL", i);
1780 return false;
1781 }
1782
1783 if (member_conn == NULL) {
1784 LOG_DBG("Invalid param->param[%zu].member", i);
1785 return false;
1786 }
1787
1788 mic_ctlr = bt_micp_mic_ctlr_get_by_conn(member_conn);
1789 if (mic_ctlr == NULL) {
1790 LOG_DBG("Microphone control not available for param->param[%zu].member", i);
1791 return false;
1792 }
1793
1794 err = bt_micp_mic_ctlr_included_get(mic_ctlr, &included);
1795 if (err != 0 || included.aics_cnt == 0) {
1796 LOG_DBG("Microphone audio input control not available for "
1797 "param->param[%zu].member",
1798 i);
1799 return -ENOEXEC;
1800 }
1801
1802 for (size_t j = 0U; j < i; j++) {
1803 const union bt_cap_set_member *other = ¶m->param[j].member;
1804
1805 if (other == member) {
1806 LOG_DBG("param->param[%zu].member (%p) is duplicated by "
1807 "param->param[%zu].member (%p)",
1808 j, other, i, member);
1809 return false;
1810 }
1811 }
1812 }
1813
1814 return true;
1815 }
1816
cap_commander_micp_gain_set_cb(struct bt_aics * inst,int err)1817 static void cap_commander_micp_gain_set_cb(struct bt_aics *inst, int err)
1818 {
1819 struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc();
1820 struct bt_conn *conn;
1821 int micp_err;
1822
1823 LOG_DBG("bt_aics %p", (void *)inst);
1824
1825 micp_err = bt_aics_client_conn_get(inst, &conn);
1826 if (micp_err != 0) {
1827 LOG_ERR("Failed to get conn by aics: %d", micp_err);
1828 return;
1829 }
1830
1831 LOG_DBG("conn %p", (void *)conn);
1832 if (!bt_cap_common_conn_in_active_proc(conn)) {
1833 /* State change happened outside of a procedure; ignore */
1834 return;
1835 }
1836
1837 if (err != 0) {
1838 LOG_DBG("Failed to set gain: %d", err);
1839 bt_cap_common_abort_proc(conn, err);
1840 } else {
1841 active_proc->proc_done_cnt++;
1842
1843 LOG_DBG("Conn %p gain updated (%zu/%zu streams done)", (void *)conn,
1844 active_proc->proc_done_cnt, active_proc->proc_cnt);
1845 }
1846
1847 if (bt_cap_common_proc_is_aborted()) {
1848 LOG_DBG("Proc is aborted");
1849 if (bt_cap_common_proc_all_handled()) {
1850 LOG_DBG("All handled");
1851 cap_commander_proc_complete();
1852 }
1853
1854 return;
1855 }
1856
1857 if (!bt_cap_common_proc_is_done()) {
1858 const struct bt_cap_commander_proc_param *proc_param;
1859
1860 proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt];
1861 conn = proc_param->conn;
1862 active_proc->proc_initiated_cnt++;
1863 err = bt_aics_gain_set(proc_param->change_gain.aics, proc_param->change_gain.gain);
1864 if (err != 0) {
1865 LOG_DBG("Failed to set gain for conn %p: %d", (void *)conn, err);
1866 bt_cap_common_abort_proc(conn, err);
1867 cap_commander_proc_complete();
1868 }
1869 } else {
1870 cap_commander_proc_complete();
1871 }
1872 }
1873
bt_cap_commander_change_microphone_gain_setting(const struct bt_cap_commander_change_microphone_gain_setting_param * param)1874 int bt_cap_commander_change_microphone_gain_setting(
1875 const struct bt_cap_commander_change_microphone_gain_setting_param *param)
1876 {
1877 const struct bt_cap_commander_proc_param *proc_param;
1878 struct bt_cap_common_proc *active_proc;
1879 struct bt_conn *conn;
1880 int err;
1881
1882 if (bt_cap_common_proc_is_active()) {
1883 LOG_DBG("A CAP procedure is already in progress");
1884
1885 return -EBUSY;
1886 }
1887
1888 if (!valid_change_microphone_gain_param(param)) {
1889 return -EINVAL;
1890 }
1891
1892 bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_MICROPHONE_GAIN_CHANGE, param->count);
1893
1894 mic_ctlr_cb.aics_cb.set_gain = cap_commander_micp_gain_set_cb;
1895 if (!micp_callbacks_registered && cap_commander_register_micp_callbacks() != 0) {
1896 LOG_DBG("Failed to register MICP callbacks");
1897
1898 return -ENOEXEC;
1899 }
1900
1901 active_proc = bt_cap_common_get_active_proc();
1902
1903 for (size_t i = 0U; i < param->count; i++) {
1904 const union bt_cap_set_member *member = ¶m->param[i].member;
1905 struct bt_conn *member_conn = bt_cap_common_get_member_conn(param->type, member);
1906 struct bt_micp_mic_ctlr *mic_ctlr;
1907 struct bt_micp_included included;
1908
1909 if (member_conn == NULL) {
1910 LOG_DBG("Invalid param->param[%zu].member", i);
1911 return -EINVAL;
1912 }
1913
1914 mic_ctlr = bt_micp_mic_ctlr_get_by_conn(member_conn);
1915 if (mic_ctlr == NULL) {
1916 LOG_DBG("Invalid param->param[%zu].member mic_ctlr", i);
1917 return -EINVAL;
1918 }
1919
1920 err = bt_micp_mic_ctlr_included_get(mic_ctlr, &included);
1921 if (err != 0 || included.aics_cnt == 0) {
1922 LOG_DBG("Invalid param->param[%zu].member aics", i);
1923 return -EINVAL;
1924 }
1925
1926 /* Store the necessary parameters as we cannot assume that the supplied parameters
1927 * are kept valid
1928 */
1929 active_proc->proc_param.commander[i].conn = member_conn;
1930 active_proc->proc_param.commander[i].change_gain.gain = param->param[i].gain;
1931 /* TODO: For now we just use the first AICS instance
1932 * - How should we handle multiple?
1933 */
1934 active_proc->proc_param.commander[i].change_gain.aics = included.aics[0];
1935 }
1936
1937 proc_param = &active_proc->proc_param.commander[0];
1938 conn = proc_param->conn;
1939 active_proc->proc_initiated_cnt++;
1940
1941 err = bt_aics_gain_set(proc_param->change_gain.aics, proc_param->change_gain.gain);
1942 if (err != 0) {
1943 LOG_DBG("Failed to set gain for conn %p: %d", (void *)conn, err);
1944 return -ENOEXEC;
1945 }
1946
1947 return 0;
1948 }
1949 #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */
1950 #endif /* CONFIG_BT_MICP_MIC_CTLR */
1951