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