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