1 /*
2 * Copyright (c) 2023-2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/att.h>
14 #include <zephyr/bluetooth/audio/cap.h>
15 #include <zephyr/bluetooth/audio/csip.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/gatt.h>
19 #include <zephyr/bluetooth/uuid.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/sys/atomic.h>
22 #include <zephyr/sys/check.h>
23 #include <zephyr/sys/util.h>
24 #include <zephyr/sys/util_macro.h>
25
26 #include "cap_internal.h"
27 #include "csip_internal.h"
28
29 LOG_MODULE_REGISTER(bt_cap_common, CONFIG_BT_CAP_COMMON_LOG_LEVEL);
30
31 #include "common/bt_str.h"
32
33 static struct bt_cap_common_client bt_cap_common_clients[CONFIG_BT_MAX_CONN];
34 static const struct bt_uuid *cas_uuid = BT_UUID_CAS;
35 static struct bt_cap_common_proc active_proc;
36
bt_cap_common_get_active_proc(void)37 struct bt_cap_common_proc *bt_cap_common_get_active_proc(void)
38 {
39 return &active_proc;
40 }
41
bt_cap_common_clear_active_proc(void)42 void bt_cap_common_clear_active_proc(void)
43 {
44 (void)memset(&active_proc, 0, sizeof(active_proc));
45 }
46
bt_cap_common_set_proc(enum bt_cap_common_proc_type proc_type,size_t proc_cnt)47 void bt_cap_common_set_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt)
48 {
49 LOG_DBG("Setting proc to %d for %zu streams", proc_type, proc_cnt);
50
51 active_proc.proc_cnt = proc_cnt;
52 active_proc.proc_type = proc_type;
53 active_proc.proc_done_cnt = 0U;
54 active_proc.proc_initiated_cnt = 0U;
55 }
56
57 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type)58 void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type)
59 {
60 LOG_DBG("Setting subproc to %d", subproc_type);
61
62 active_proc.proc_done_cnt = 0U;
63 active_proc.proc_initiated_cnt = 0U;
64 active_proc.subproc_type = subproc_type;
65 }
66
bt_cap_common_proc_is_type(enum bt_cap_common_proc_type proc_type)67 bool bt_cap_common_proc_is_type(enum bt_cap_common_proc_type proc_type)
68 {
69 return active_proc.proc_type == proc_type;
70 }
71
bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type)72 bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type)
73 {
74 return active_proc.subproc_type == subproc_type;
75 }
76 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
77
78 #if defined(CONFIG_BT_CAP_HANDOVER)
bt_cap_common_set_handover_active(void)79 void bt_cap_common_set_handover_active(void)
80 {
81 atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_HANDOVER);
82 }
83
bt_cap_common_handover_is_active(void)84 bool bt_cap_common_handover_is_active(void)
85 {
86 return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_HANDOVER);
87 }
88 #endif /* CONFIG_BT_CAP_HANDOVER */
89
bt_cap_common_get_member_conn(enum bt_cap_set_type type,const union bt_cap_set_member * member)90 struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type,
91 const union bt_cap_set_member *member)
92 {
93 if (member == NULL) {
94 return NULL;
95 }
96
97 if (type == BT_CAP_SET_TYPE_CSIP) {
98 struct bt_cap_common_client *client;
99
100 /* We have verified that `client` won't be NULL in
101 * `valid_change_volume_param`.
102 */
103
104 client = bt_cap_common_get_client_by_csis(member->csip);
105 if (client == NULL) {
106 return NULL;
107 }
108
109 return client->conn;
110 }
111
112 return member->member;
113 }
114
bt_cap_common_test_and_set_proc_active(void)115 bool bt_cap_common_test_and_set_proc_active(void)
116 {
117 return atomic_test_and_set_bit(active_proc.proc_state_flags,
118 BT_CAP_COMMON_PROC_STATE_ACTIVE);
119 }
120
bt_cap_common_proc_is_active(void)121 bool bt_cap_common_proc_is_active(void)
122 {
123 return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE);
124 }
125
bt_cap_common_proc_is_aborted(void)126 bool bt_cap_common_proc_is_aborted(void)
127 {
128 return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED);
129 }
130
bt_cap_common_proc_all_handled(void)131 bool bt_cap_common_proc_all_handled(void)
132 {
133 return active_proc.proc_done_cnt == active_proc.proc_initiated_cnt;
134 }
135
bt_cap_common_proc_is_done(void)136 bool bt_cap_common_proc_is_done(void)
137 {
138 return active_proc.proc_done_cnt == active_proc.proc_cnt;
139 }
140
bt_cap_common_abort_proc(struct bt_conn * conn,int err)141 void bt_cap_common_abort_proc(struct bt_conn *conn, int err)
142 {
143 if (bt_cap_common_proc_is_aborted()) {
144 /* no-op */
145 return;
146 }
147
148 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
149 LOG_DBG("Aborting proc %d with subproc %d for %p: %d", active_proc.proc_type,
150 active_proc.subproc_type, (void *)conn, err);
151 #else /* !CONFIG_BT_CAP_INITIATOR_UNICAST */
152 LOG_DBG("Aborting proc %d for %p: %d", active_proc.proc_type, (void *)conn, err);
153 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
154
155 active_proc.err = err;
156 active_proc.failed_conn = conn;
157 atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED);
158 }
159
160 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
active_proc_is_initiator(void)161 static bool active_proc_is_initiator(void)
162 {
163 switch (active_proc.proc_type) {
164 case BT_CAP_COMMON_PROC_TYPE_START:
165 case BT_CAP_COMMON_PROC_TYPE_UPDATE:
166 case BT_CAP_COMMON_PROC_TYPE_STOP:
167 return true;
168 default:
169 return false;
170 }
171 }
172 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
173
174 #if defined(CONFIG_BT_CAP_COMMANDER)
active_proc_is_commander(void)175 static bool active_proc_is_commander(void)
176 {
177 switch (active_proc.proc_type) {
178 case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE:
179 case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE:
180 case BT_CAP_COMMON_PROC_TYPE_VOLUME_MUTE_CHANGE:
181 case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_GAIN_CHANGE:
182 case BT_CAP_COMMON_PROC_TYPE_MICROPHONE_MUTE_CHANGE:
183 case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_START:
184 case BT_CAP_COMMON_PROC_TYPE_BROADCAST_RECEPTION_STOP:
185 case BT_CAP_COMMON_PROC_TYPE_DISTRIBUTE_BROADCAST_CODE:
186 return true;
187 default:
188 return false;
189 }
190 }
191 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
192
bt_cap_common_conn_in_active_proc(const struct bt_conn * conn)193 bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn)
194 {
195 if (!bt_cap_common_proc_is_active()) {
196 return false;
197 }
198
199 for (size_t i = 0U; i < active_proc.proc_initiated_cnt; i++) {
200 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
201 if (active_proc_is_initiator()) {
202 if (active_proc.proc_param.initiator[i].stream->bap_stream.conn == conn) {
203 return true;
204 }
205 }
206 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
207 #if defined(CONFIG_BT_CAP_COMMANDER)
208 if (active_proc_is_commander()) {
209 if (active_proc.proc_param.commander[i].conn == conn) {
210 return true;
211 }
212 }
213 #endif /* CONFIG_BT_CAP_COMMANDER */
214 }
215
216 return false;
217 }
218
bt_cap_common_stream_in_active_proc(const struct bt_cap_stream * cap_stream)219 bool bt_cap_common_stream_in_active_proc(const struct bt_cap_stream *cap_stream)
220 {
221 if (!bt_cap_common_proc_is_active()) {
222 return false;
223 }
224
225 #if defined(CONFIG_BT_CAP_INITIATOR_UNICAST)
226 if (active_proc_is_initiator()) {
227 for (size_t i = 0U; i < active_proc.proc_cnt; i++) {
228 if (active_proc.proc_param.initiator[i].stream == cap_stream) {
229 return true;
230 }
231 }
232 }
233 #endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */
234
235 return false;
236 }
237
bt_cap_common_disconnected(struct bt_conn * conn,uint8_t reason)238 void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason)
239 {
240 struct bt_cap_common_client *client = bt_cap_common_get_client_by_acl(conn);
241
242 if (client->conn != NULL) {
243 bt_conn_unref(client->conn);
244 }
245 (void)memset(client, 0, sizeof(*client));
246
247 if (bt_cap_common_conn_in_active_proc(conn)) {
248 bt_cap_common_abort_proc(conn, -ENOTCONN);
249 }
250 }
251
252 BT_CONN_CB_DEFINE(conn_callbacks) = {
253 .disconnected = bt_cap_common_disconnected,
254 };
255
bt_cap_common_get_client_by_acl(const struct bt_conn * acl)256 struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl)
257 {
258 if (acl == NULL) {
259 return NULL;
260 }
261
262 return &bt_cap_common_clients[bt_conn_index(acl)];
263 }
264
265 struct bt_cap_common_client *
bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst * csis_inst)266 bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst)
267 {
268 if (csis_inst == NULL) {
269 return NULL;
270 }
271
272 for (size_t i = 0U; i < ARRAY_SIZE(bt_cap_common_clients); i++) {
273 struct bt_cap_common_client *client = &bt_cap_common_clients[i];
274
275 if (client->csis_inst == csis_inst) {
276 return client;
277 }
278 }
279
280 return NULL;
281 }
282
cap_common_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)283 static void cap_common_discover_complete(struct bt_conn *conn, int err,
284 const struct bt_csip_set_coordinator_set_member *member,
285 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
286 {
287 struct bt_cap_common_client *client;
288
289 client = bt_cap_common_get_client_by_acl(conn);
290 if (client != NULL && client->discover_cb_func != NULL) {
291 const bt_cap_common_discover_func_t cb_func = client->discover_cb_func;
292
293 client->discover_cb_func = NULL;
294 cb_func(conn, err, member, csis_inst);
295 }
296 }
297
csis_client_discover_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_set_member * member,int err,size_t set_count)298 static void csis_client_discover_cb(struct bt_conn *conn,
299 const struct bt_csip_set_coordinator_set_member *member,
300 int err, size_t set_count)
301 {
302 struct bt_cap_common_client *client;
303
304 if (err != 0) {
305 LOG_DBG("CSIS client discover failed: %d", err);
306
307 cap_common_discover_complete(conn, err, NULL, NULL);
308
309 return;
310 }
311
312 client = bt_cap_common_get_client_by_acl(conn);
313 client->csis_inst =
314 bt_csip_set_coordinator_csis_inst_by_handle(conn, client->csis_start_handle);
315
316 if (member == NULL || set_count == 0 || client->csis_inst == NULL) {
317 LOG_ERR("Unable to find CSIS for CAS");
318
319 cap_common_discover_complete(conn, -ENODATA, NULL, NULL);
320 } else {
321 LOG_DBG("Found CAS with CSIS");
322 cap_common_discover_complete(conn, 0, member, client->csis_inst);
323 }
324 }
325
bt_cap_common_discover_included_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)326 static uint8_t bt_cap_common_discover_included_cb(struct bt_conn *conn,
327 const struct bt_gatt_attr *attr,
328 struct bt_gatt_discover_params *params)
329 {
330 if (attr == NULL) {
331 LOG_DBG("CAS CSIS include not found");
332
333 cap_common_discover_complete(conn, 0, NULL, NULL);
334 } else {
335 const struct bt_gatt_include *included_service = attr->user_data;
336 struct bt_cap_common_client *client =
337 CONTAINER_OF(params, struct bt_cap_common_client, param);
338
339 /* If the remote CAS includes CSIS, we first check if we
340 * have already discovered it, and if so we can just retrieve it
341 * and forward it to the application. If not, then we start
342 * CSIS discovery
343 */
344 client->csis_start_handle = included_service->start_handle;
345 client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle(
346 conn, client->csis_start_handle);
347 if (client->csis_inst == NULL) {
348 static struct bt_csip_set_coordinator_cb csis_client_cb = {
349 .discover = csis_client_discover_cb,
350 };
351 static bool csis_cbs_registered;
352 int err;
353
354 LOG_DBG("CAS CSIS not known, discovering");
355
356 if (!csis_cbs_registered) {
357 bt_csip_set_coordinator_register_cb(&csis_client_cb);
358 csis_cbs_registered = true;
359 }
360
361 err = bt_csip_set_coordinator_discover(conn);
362 if (err != 0) {
363 LOG_DBG("Discover failed (err %d)", err);
364 cap_common_discover_complete(conn, err, NULL, NULL);
365 }
366 } else {
367 const struct bt_csip_set_coordinator_set_member *member =
368 bt_csip_set_coordinator_set_member_by_conn(conn);
369
370 LOG_DBG("Found CAS with CSIS");
371
372 cap_common_discover_complete(conn, 0, member, client->csis_inst);
373 }
374 }
375
376 return BT_GATT_ITER_STOP;
377 }
378
bt_cap_common_discover_cas_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)379 static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
380 struct bt_gatt_discover_params *params)
381 {
382 if (attr == NULL) {
383 cap_common_discover_complete(conn, -ENODATA, NULL, NULL);
384 } else {
385 const struct bt_gatt_service_val *prim_service = attr->user_data;
386 struct bt_cap_common_client *client =
387 CONTAINER_OF(params, struct bt_cap_common_client, param);
388 int err;
389
390 client->conn = bt_conn_ref(conn);
391
392 if (attr->handle == prim_service->end_handle) {
393 LOG_DBG("Found CAS without CSIS");
394 cap_common_discover_complete(conn, 0, NULL, NULL);
395
396 return BT_GATT_ITER_STOP;
397 }
398
399 LOG_DBG("Found CAS, discovering included CSIS");
400
401 params->uuid = NULL;
402 params->start_handle = attr->handle + 1;
403 params->end_handle = prim_service->end_handle;
404 params->type = BT_GATT_DISCOVER_INCLUDE;
405 params->func = bt_cap_common_discover_included_cb;
406
407 err = bt_gatt_discover(conn, params);
408 if (err != 0) {
409 LOG_DBG("Discover failed (err %d)", err);
410
411 cap_common_discover_complete(conn, err, NULL, NULL);
412 }
413 }
414
415 return BT_GATT_ITER_STOP;
416 }
417
bt_cap_common_discover(struct bt_conn * conn,bt_cap_common_discover_func_t func)418 int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func)
419 {
420 struct bt_gatt_discover_params *param;
421 struct bt_cap_common_client *client;
422 int err;
423
424 client = bt_cap_common_get_client_by_acl(conn);
425 if (client->discover_cb_func != NULL) {
426 return -EBUSY;
427 }
428
429 param = &client->param;
430 param->func = bt_cap_common_discover_cas_cb;
431 param->uuid = cas_uuid;
432 param->type = BT_GATT_DISCOVER_PRIMARY;
433 param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
434 param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
435
436 client->discover_cb_func = func;
437
438 err = bt_gatt_discover(conn, param);
439 if (err != 0) {
440 client->discover_cb_func = NULL;
441
442 /* Report expected possible errors */
443 if (err == -ENOTCONN || err == -ENOMEM) {
444 return err;
445 }
446
447 LOG_DBG("Unexpected err %d from bt_gatt_discover", err);
448 return -ENOEXEC;
449 }
450
451 return 0;
452 }
453