1 /* @file
2 * @brief Bluetooth PACS
3 */
4
5 /*
6 * Copyright (c) 2020 Intel Corporation
7 * Copyright (c) 2022-2023 Nordic Semiconductor ASA
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <errno.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <sys/types.h>
18
19 #include <zephyr/autoconf.h>
20 #include <zephyr/bluetooth/addr.h>
21 #include <zephyr/bluetooth/att.h>
22 #include <zephyr/bluetooth/audio/audio.h>
23 #include <zephyr/bluetooth/audio/pacs.h>
24 #include <zephyr/bluetooth/bluetooth.h>
25 #include <zephyr/bluetooth/conn.h>
26 #include <zephyr/bluetooth/gatt.h>
27 #include <zephyr/bluetooth/uuid.h>
28 #include <zephyr/device.h>
29 #include <zephyr/init.h>
30 #include <zephyr/kernel.h>
31 #include <zephyr/logging/log.h>
32 #include <zephyr/net_buf.h>
33 #include <zephyr/sys/__assert.h>
34 #include <zephyr/sys/atomic.h>
35 #include <zephyr/sys/byteorder.h>
36 #include <zephyr/sys/check.h>
37 #include <zephyr/sys/slist.h>
38 #include <zephyr/sys/util.h>
39 #include <zephyr/sys/util_macro.h>
40
41 #include "../host/conn_internal.h"
42 #include "../host/hci_core.h"
43 #include "common/bt_str.h"
44
45 #include "audio_internal.h"
46 #include "bap_unicast_server.h"
47 #include "pacs_internal.h"
48
49 LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL);
50
51 #define PAC_NOTIFY_TIMEOUT K_MSEC(10)
52 #define READ_BUF_SEM_TIMEOUT K_MSEC(50)
53
54 #if defined(CONFIG_BT_PAC_SRC)
55 static uint32_t pacs_src_location;
56 static sys_slist_t src_pacs_list = SYS_SLIST_STATIC_INIT(&src_pacs_list);
57 static uint16_t src_supported_contexts;
58 #endif /* CONFIG_BT_PAC_SRC */
59
60 #if defined(CONFIG_BT_PAC_SNK)
61 static uint32_t pacs_snk_location;
62 static sys_slist_t snk_pacs_list = SYS_SLIST_STATIC_INIT(&snk_pacs_list);
63 static uint16_t snk_supported_contexts;
64 #endif /* CONFIG_BT_PAC_SNK */
65
66 static uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
67 static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
68
69 enum {
70 FLAG_ACTIVE,
71 FLAG_SINK_PAC_CHANGED,
72 FLAG_SINK_AUDIO_LOCATIONS_CHANGED,
73 FLAG_SOURCE_PAC_CHANGED,
74 FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED,
75 FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED,
76 FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED,
77 FLAG_NUM,
78 };
79
80 static struct pacs_client {
81 bt_addr_le_t addr;
82
83 #if defined(CONFIG_BT_PAC_SNK)
84 /* Sink Available Contexts override value */
85 uint16_t *snk_available_contexts;
86 #endif /* CONFIG_BT_PAC_SNK */
87
88 #if defined(CONFIG_BT_PAC_SRC)
89 /* Source Available Contexts override value */
90 uint16_t *src_available_contexts;
91 #endif /* CONFIG_BT_PAC_SRC */
92
93 /* Pending notification flags */
94 ATOMIC_DEFINE(flags, FLAG_NUM);
95 } clients[CONFIG_BT_MAX_PAIRED];
96
97 static atomic_t notify_rdy;
98
99 static K_SEM_DEFINE(read_buf_sem, 1, 1);
100 NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN);
101
102 static int pacs_gatt_notify(struct bt_conn *conn,
103 const struct bt_uuid *uuid,
104 const struct bt_gatt_attr *attr,
105 const void *data,
106 uint16_t len);
107 static void deferred_nfy_work_handler(struct k_work *work);
108
109 static K_WORK_DEFINE(deferred_nfy_work, deferred_nfy_work_handler);
110
111 struct pac_records_build_data {
112 struct bt_pacs_read_rsp *rsp;
113 struct net_buf_simple *buf;
114 };
115
client_lookup_conn(const struct bt_conn * conn)116 static struct pacs_client *client_lookup_conn(const struct bt_conn *conn)
117 {
118 __ASSERT_NO_MSG(conn != NULL);
119
120 for (size_t i = 0; i < ARRAY_SIZE(clients); i++) {
121 if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) &&
122 bt_addr_le_eq(&clients[i].addr, bt_conn_get_dst(conn))) {
123 return &clients[i];
124 }
125 }
126
127 return NULL;
128 }
129
pacs_set_notify_bit(int bit)130 static void pacs_set_notify_bit(int bit)
131 {
132 for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
133 if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) {
134 atomic_set_bit(clients[i].flags, bit);
135 }
136 }
137 }
138
build_pac_records(const struct bt_pacs_cap * cap,void * user_data)139 static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data)
140 {
141 struct pac_records_build_data *data = user_data;
142 const struct bt_audio_codec_cap *codec_cap = cap->codec_cap;
143 struct net_buf_simple *buf = data->buf;
144 struct net_buf_simple_state state;
145 struct bt_pac_codec *pac_codec;
146
147 net_buf_simple_save(buf, &state);
148
149 if (net_buf_simple_tailroom(buf) < sizeof(*pac_codec)) {
150 goto fail;
151 }
152
153 pac_codec = net_buf_simple_add(buf, sizeof(*pac_codec));
154 pac_codec->id = codec_cap->id;
155 pac_codec->cid = sys_cpu_to_le16(codec_cap->cid);
156 pac_codec->vid = sys_cpu_to_le16(codec_cap->vid);
157
158 if (net_buf_simple_tailroom(buf) < (sizeof(struct bt_pac_ltv_data) + codec_cap->data_len)) {
159 goto fail;
160 }
161
162 net_buf_simple_add_u8(buf, codec_cap->data_len);
163 net_buf_simple_add_mem(buf, codec_cap->data, codec_cap->data_len);
164
165 if (net_buf_simple_tailroom(buf) < (sizeof(struct bt_pac_ltv_data) + codec_cap->meta_len)) {
166 goto fail;
167 }
168
169 net_buf_simple_add_u8(buf, codec_cap->meta_len);
170 net_buf_simple_add_mem(buf, codec_cap->meta, codec_cap->meta_len);
171
172 data->rsp->num_pac++;
173
174 return true;
175
176 fail:
177 __ASSERT(false, "No space for %p", cap);
178
179 net_buf_simple_restore(buf, &state);
180
181 return false;
182 }
183
foreach_cap(sys_slist_t * list,bt_pacs_cap_foreach_func_t func,void * user_data)184 static void foreach_cap(sys_slist_t *list, bt_pacs_cap_foreach_func_t func,
185 void *user_data)
186 {
187 struct bt_pacs_cap *cap;
188
189 SYS_SLIST_FOR_EACH_CONTAINER(list, cap, _node) {
190 if (!func(cap, user_data)) {
191 break;
192 }
193 }
194 }
195
get_pac_records(sys_slist_t * list,struct net_buf_simple * buf)196 static void get_pac_records(sys_slist_t *list, struct net_buf_simple *buf)
197 {
198 struct pac_records_build_data data;
199
200 /* Reset if buffer before using */
201 net_buf_simple_reset(buf);
202
203 data.rsp = net_buf_simple_add(buf, sizeof(*data.rsp));
204 data.rsp->num_pac = 0;
205 data.buf = buf;
206
207 foreach_cap(list, build_pac_records, &data);
208 }
209
available_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)210 static void available_context_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
211 {
212 LOG_DBG("attr %p value 0x%04x", attr, value);
213 }
214
pacs_get_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir)215 static enum bt_audio_context pacs_get_available_contexts_for_conn(struct bt_conn *conn,
216 enum bt_audio_dir dir)
217 {
218 const struct pacs_client *client;
219
220 client = client_lookup_conn(conn);
221 if (client == NULL) {
222 LOG_DBG("No client context for conn %p", (void *)conn);
223 return bt_pacs_get_available_contexts(dir);
224 }
225
226 switch (dir) {
227 case BT_AUDIO_DIR_SINK:
228 #if defined(CONFIG_BT_PAC_SNK)
229 if (client->snk_available_contexts != NULL) {
230 return POINTER_TO_UINT(client->snk_available_contexts);
231 }
232 #endif /* CONFIG_BT_PAC_SNK */
233 break;
234 case BT_AUDIO_DIR_SOURCE:
235 #if defined(CONFIG_BT_PAC_SRC)
236 if (client->src_available_contexts != NULL) {
237 return POINTER_TO_UINT(client->src_available_contexts);
238 }
239 #endif /* CONFIG_BT_PAC_SRC */
240 break;
241 }
242
243 return bt_pacs_get_available_contexts(dir);
244 }
245
available_contexts_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)246 static ssize_t available_contexts_read(struct bt_conn *conn,
247 const struct bt_gatt_attr *attr, void *buf,
248 uint16_t len, uint16_t offset)
249 {
250 struct bt_pacs_context context = {
251 .snk = sys_cpu_to_le16(
252 pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)),
253 .src = sys_cpu_to_le16(
254 pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)),
255 };
256
257 LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
258
259 return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
260 sizeof(context));
261 }
262
263 #if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
supported_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)264 static void supported_context_cfg_changed(const struct bt_gatt_attr *attr,
265 uint16_t value)
266 {
267 LOG_DBG("attr %p value 0x%04x", attr, value);
268 }
269 #endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
270
supported_context_get(enum bt_audio_dir dir)271 static uint16_t supported_context_get(enum bt_audio_dir dir)
272 {
273 switch (dir) {
274 #if defined(CONFIG_BT_PAC_SNK)
275 case BT_AUDIO_DIR_SINK:
276 return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
277 #endif /* CONFIG_BT_PAC_SNK */
278 #if defined(CONFIG_BT_PAC_SRC)
279 case BT_AUDIO_DIR_SOURCE:
280 return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
281 #endif /* CONFIG_BT_PAC_SRC */
282 default:
283 break;
284 }
285
286 return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
287 }
288
supported_context_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)289 static ssize_t supported_context_read(struct bt_conn *conn,
290 const struct bt_gatt_attr *attr,
291 void *buf, uint16_t len, uint16_t offset)
292 {
293 struct bt_pacs_context context = {
294 .snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)),
295 .src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)),
296 };
297
298 LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
299
300 return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
301 sizeof(context));
302 }
303
set_available_contexts(uint16_t contexts,uint16_t * available,uint16_t supported)304 static int set_available_contexts(uint16_t contexts, uint16_t *available,
305 uint16_t supported)
306 {
307 if (contexts & ~supported) {
308 return -ENOTSUP;
309 }
310
311 if (contexts == *available) {
312 return 0;
313 }
314
315 *available = contexts;
316
317 pacs_set_notify_bit(FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
318 k_work_submit(&deferred_nfy_work);
319
320 return 0;
321 }
322
set_supported_contexts(uint16_t contexts,uint16_t * supported,uint16_t * available)323 static int set_supported_contexts(uint16_t contexts, uint16_t *supported,
324 uint16_t *available)
325 {
326 int err;
327 uint16_t tmp_supported = *supported;
328 uint16_t tmp_available = *available;
329
330 /* Ensure unspecified is always supported */
331 contexts |= BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
332
333 if (*supported == contexts) {
334 return 0;
335 }
336
337 *supported = contexts;
338
339 /* Update available contexts if needed*/
340 if ((contexts & *available) != *available) {
341 err = set_available_contexts(contexts & *available, available, contexts);
342 if (err) {
343 *available = tmp_available;
344 *supported = tmp_supported;
345
346 return err;
347 }
348 }
349
350 if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)) {
351 pacs_set_notify_bit(FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
352 k_work_submit(&deferred_nfy_work);
353 }
354
355 return 0;
356 }
357
358 #if defined(CONFIG_BT_PAC_SNK)
snk_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)359 static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
360 void *buf, uint16_t len, uint16_t offset)
361 {
362 ssize_t ret_val;
363 int err;
364
365 LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
366
367 err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
368 if (err != 0) {
369 LOG_DBG("Failed to take read_buf_sem: %d", err);
370
371 return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
372 }
373
374 get_pac_records(&snk_pacs_list, &read_buf);
375
376 ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
377 read_buf.len);
378
379 k_sem_give(&read_buf_sem);
380
381 return ret_val;
382 }
383
384 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
385 static const struct bt_uuid *pacs_snk_uuid = BT_UUID_PACS_SNK;
386
snk_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)387 static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
388 {
389 LOG_DBG("attr %p value 0x%04x", attr, value);
390 }
391 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
392 #endif /* CONFIG_BT_PAC_SNK */
393
394 #if defined(CONFIG_BT_PAC_SNK_LOC)
snk_loc_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)395 static ssize_t snk_loc_read(struct bt_conn *conn,
396 const struct bt_gatt_attr *attr, void *buf,
397 uint16_t len, uint16_t offset)
398 {
399 uint32_t location = sys_cpu_to_le32(pacs_snk_location);
400
401 LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
402
403 return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
404 sizeof(location));
405 }
406
407 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
408 static const struct bt_uuid *pacs_snk_loc_uuid = BT_UUID_PACS_SNK_LOC;
409
snk_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)410 static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
411 {
412 LOG_DBG("attr %p value 0x%04x", attr, value);
413 }
414 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
415
set_snk_location(enum bt_audio_location audio_location)416 static void set_snk_location(enum bt_audio_location audio_location)
417 {
418 if (audio_location == pacs_snk_location) {
419 return;
420 }
421
422 pacs_snk_location = audio_location;
423
424 if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)) {
425 pacs_set_notify_bit(FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
426 k_work_submit(&deferred_nfy_work);
427 }
428 }
429 #else
set_snk_location(enum bt_audio_location location)430 static void set_snk_location(enum bt_audio_location location)
431 {
432 return;
433 }
434 #endif /* CONFIG_BT_PAC_SNK_LOC */
435
436 #if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE)
snk_loc_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * data,uint16_t len,uint16_t offset,uint8_t flags)437 static ssize_t snk_loc_write(struct bt_conn *conn,
438 const struct bt_gatt_attr *attr, const void *data,
439 uint16_t len, uint16_t offset, uint8_t flags)
440 {
441 enum bt_audio_location location;
442
443 if (offset) {
444 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
445 }
446
447 if (len != sizeof(location)) {
448 return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
449 }
450
451 location = (enum bt_audio_location)sys_get_le32(data);
452 if (location > BT_AUDIO_LOCATION_MASK) {
453 LOG_DBG("Invalid location value: 0x%08X", location);
454 return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
455 }
456
457 set_snk_location(location);
458
459 return len;
460 }
461 #endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
462
463 #if defined(CONFIG_BT_PAC_SRC)
src_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)464 static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
465 void *buf, uint16_t len, uint16_t offset)
466 {
467 ssize_t ret_val;
468 int err;
469
470 LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
471
472 err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
473 if (err != 0) {
474 LOG_DBG("Failed to take read_buf_sem: %d", err);
475
476 return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
477 }
478
479 get_pac_records(&src_pacs_list, &read_buf);
480
481 ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
482 read_buf.len);
483
484 k_sem_give(&read_buf_sem);
485
486 return ret_val;
487 }
488
489 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
490 static const struct bt_uuid *pacs_src_uuid = BT_UUID_PACS_SRC;
491
src_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)492 static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
493 {
494 LOG_DBG("attr %p value 0x%04x", attr, value);
495 }
496 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
497 #endif /* CONFIG_BT_PAC_SRC */
498
499 #if defined(CONFIG_BT_PAC_SRC_LOC)
src_loc_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)500 static ssize_t src_loc_read(struct bt_conn *conn,
501 const struct bt_gatt_attr *attr, void *buf,
502 uint16_t len, uint16_t offset)
503 {
504 uint32_t location = sys_cpu_to_le32(pacs_src_location);
505
506 LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
507
508 return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
509 sizeof(location));
510 }
511
512 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
513 static const struct bt_uuid *pacs_src_loc_uuid = BT_UUID_PACS_SRC_LOC;
514
src_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)515 static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
516 {
517 LOG_DBG("attr %p value 0x%04x", attr, value);
518 }
519 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
520
set_src_location(enum bt_audio_location audio_location)521 static void set_src_location(enum bt_audio_location audio_location)
522 {
523 if (audio_location == pacs_src_location) {
524 return;
525 }
526
527 pacs_src_location = audio_location;
528
529 if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)) {
530 pacs_set_notify_bit(FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
531 k_work_submit(&deferred_nfy_work);
532 }
533 }
534 #else
set_src_location(enum bt_audio_location location)535 static void set_src_location(enum bt_audio_location location)
536 {
537 return;
538 }
539 #endif /* CONFIG_BT_PAC_SRC_LOC */
540
541 #if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
src_loc_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * data,uint16_t len,uint16_t offset,uint8_t flags)542 static ssize_t src_loc_write(struct bt_conn *conn,
543 const struct bt_gatt_attr *attr, const void *data,
544 uint16_t len, uint16_t offset, uint8_t flags)
545 {
546 uint32_t location;
547
548 if (offset) {
549 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
550 }
551
552 if (len != sizeof(location)) {
553 return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
554 }
555
556 location = (enum bt_audio_location)sys_get_le32(data);
557 if (location > BT_AUDIO_LOCATION_MASK) {
558 LOG_DBG("Invalid location value: 0x%08X", location);
559 return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
560 }
561
562 set_src_location(location);
563
564 return len;
565 }
566 #endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
567
568
pacs_get(enum bt_audio_dir dir)569 static sys_slist_t *pacs_get(enum bt_audio_dir dir)
570 {
571 switch (dir) {
572 #if defined(CONFIG_BT_PAC_SNK)
573 case BT_AUDIO_DIR_SINK:
574 return &snk_pacs_list;
575 #endif /* CONFIG_BT_PAC_SNK */
576 #if defined(CONFIG_BT_PAC_SRC)
577 case BT_AUDIO_DIR_SOURCE:
578 return &src_pacs_list;
579 #endif /* CONFIG_BT_PAC_SRC */
580 default:
581 return NULL;
582 }
583 }
584
585 #define BT_PACS_SNK_PROP \
586 BT_GATT_CHRC_READ \
587 IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
588 #define BT_PAC_SNK(_read) \
589 BT_AUDIO_CHRC(BT_UUID_PACS_SNK, \
590 BT_PACS_SNK_PROP, \
591 BT_GATT_PERM_READ_ENCRYPT, \
592 _read, NULL, NULL), \
593 IF_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE, (BT_AUDIO_CCC(snk_cfg_changed),))
594
595 #define BT_PACS_SNK_LOC_PROP \
596 BT_GATT_CHRC_READ \
597 IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
598 IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
599
600 #define BT_PACS_SNK_LOC_PERM \
601 BT_GATT_PERM_READ_ENCRYPT \
602 IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
603
604 #define BT_PACS_SNK_LOC(_read) \
605 BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC, \
606 BT_PACS_SNK_LOC_PROP, \
607 BT_PACS_SNK_LOC_PERM, \
608 _read, \
609 COND_CODE_1(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (snk_loc_write), (NULL)), \
610 NULL), \
611 IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (BT_AUDIO_CCC(snk_loc_cfg_changed),))
612
613 #define BT_PACS_SRC_PROP \
614 BT_GATT_CHRC_READ \
615 IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
616 #define BT_PAC_SRC(_read) \
617 BT_AUDIO_CHRC(BT_UUID_PACS_SRC, \
618 BT_PACS_SRC_PROP, \
619 BT_GATT_PERM_READ_ENCRYPT, \
620 _read, NULL, NULL), \
621 IF_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE, (BT_AUDIO_CCC(src_cfg_changed),))
622
623 #define BT_PACS_SRC_LOC_PROP \
624 BT_GATT_CHRC_READ \
625 IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
626 IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
627
628 #define BT_PACS_SRC_LOC_PERM \
629 BT_GATT_PERM_READ_ENCRYPT \
630 IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
631
632 #define BT_PACS_SRC_LOC(_read) \
633 BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC, \
634 BT_PACS_SRC_LOC_PROP, \
635 BT_PACS_SRC_LOC_PERM, \
636 _read, \
637 COND_CODE_1(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (src_loc_write), (NULL)), \
638 NULL), \
639 IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (BT_AUDIO_CCC(src_loc_cfg_changed),))
640
641 #define BT_PAC_AVAILABLE_CONTEXT(_read) \
642 BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT, \
643 BT_GATT_CHRC_READ|BT_GATT_CHRC_NOTIFY, \
644 BT_GATT_PERM_READ_ENCRYPT, \
645 _read, NULL, NULL), \
646 BT_AUDIO_CCC(available_context_cfg_changed),
647
648 #define BT_PACS_SUPPORTED_CONTEXT_PROP \
649 BT_GATT_CHRC_READ \
650 IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
651
652 #define BT_PAC_SUPPORTED_CONTEXT(_read) \
653 BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT, \
654 BT_PACS_SUPPORTED_CONTEXT_PROP, \
655 BT_GATT_PERM_READ_ENCRYPT, \
656 _read, NULL, NULL), \
657 IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, \
658 (BT_AUDIO_CCC(supported_context_cfg_changed),))
659
660 BT_GATT_SERVICE_DEFINE(pacs_svc,
661 BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),
662 #if defined(CONFIG_BT_PAC_SNK)
663 BT_PAC_SNK(snk_read)
664 #if defined(CONFIG_BT_PAC_SNK_LOC)
665 BT_PACS_SNK_LOC(snk_loc_read)
666 #endif /* CONFIG_BT_PAC_SNK_LOC */
667 #endif /* CONFIG_BT_PAC_SNK */
668 #if defined(CONFIG_BT_PAC_SRC)
669 BT_PAC_SRC(src_read)
670 #if defined(CONFIG_BT_PAC_SRC_LOC)
671 BT_PACS_SRC_LOC(src_loc_read)
672 #endif /* CONFIG_BT_PAC_SRC_LOC */
673 #endif /* CONFIG_BT_PAC_SRC */
674 BT_PAC_AVAILABLE_CONTEXT(available_contexts_read)
675 BT_PAC_SUPPORTED_CONTEXT(supported_context_read)
676 );
677
678 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
pac_notify_loc(struct bt_conn * conn,enum bt_audio_dir dir)679 static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir)
680 {
681 uint32_t location_le;
682 int err;
683 const struct bt_uuid *uuid;
684
685 switch (dir) {
686 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
687 case BT_AUDIO_DIR_SINK:
688 location_le = sys_cpu_to_le32(pacs_snk_location);
689 uuid = pacs_snk_loc_uuid;
690 break;
691 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
692 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
693 case BT_AUDIO_DIR_SOURCE:
694 location_le = sys_cpu_to_le32(pacs_src_location);
695 uuid = pacs_src_loc_uuid;
696 break;
697 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
698 default:
699 return -EINVAL;
700 }
701
702 err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs, &location_le, sizeof(location_le));
703 if (err != 0 && err != -ENOTCONN) {
704 LOG_WRN("PACS notify_loc failed: %d", err);
705 return err;
706 }
707
708 return 0;
709 }
710 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
711
712 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
pac_notify(struct bt_conn * conn,enum bt_audio_dir dir)713 static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir)
714 {
715 int err = 0;
716 sys_slist_t *pacs;
717 const struct bt_uuid *uuid;
718
719 switch (dir) {
720 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
721 case BT_AUDIO_DIR_SINK:
722 uuid = pacs_snk_uuid;
723 break;
724 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
725 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
726 case BT_AUDIO_DIR_SOURCE:
727 uuid = pacs_src_uuid;
728 break;
729 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
730 default:
731 return -EINVAL;
732 }
733
734 err = k_sem_take(&read_buf_sem, K_NO_WAIT);
735 if (err != 0) {
736 LOG_DBG("Failed to take read_buf_sem: %d", err);
737
738 return err;
739 }
740
741 pacs = pacs_get(dir);
742 __ASSERT(pacs, "Failed to get pacs.\n");
743 get_pac_records(pacs, &read_buf);
744
745 err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs,
746 read_buf.data, read_buf.len);
747 if (err != 0 && err != -ENOTCONN) {
748 LOG_WRN("PACS notify failed: %d", err);
749 }
750
751 k_sem_give(&read_buf_sem);
752
753 if (err == -ENOTCONN) {
754 return 0;
755 } else {
756 return 0;
757 }
758 }
759 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE || CONFIG_BT_PAC_SRC_NOTIFIABLE */
760
available_contexts_notify(struct bt_conn * conn)761 static int available_contexts_notify(struct bt_conn *conn)
762 {
763 struct bt_pacs_context context = {
764 .snk = sys_cpu_to_le16(
765 pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)),
766 .src = sys_cpu_to_le16(
767 pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)),
768 };
769 int err;
770
771 err = pacs_gatt_notify(conn, BT_UUID_PACS_AVAILABLE_CONTEXT, pacs_svc.attrs,
772 &context, sizeof(context));
773 if (err != 0 && err != -ENOTCONN) {
774 LOG_WRN("Available Audio Contexts notify failed: %d", err);
775 return err;
776 }
777
778 return 0;
779 }
780
supported_contexts_notify(struct bt_conn * conn)781 static int supported_contexts_notify(struct bt_conn *conn)
782 {
783 struct bt_pacs_context context = {
784 .snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)),
785 .src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)),
786 };
787 int err;
788
789 err = pacs_gatt_notify(conn, BT_UUID_PACS_SUPPORTED_CONTEXT, pacs_svc.attrs,
790 &context, sizeof(context));
791 if (err != 0 && err != -ENOTCONN) {
792 LOG_WRN("Supported Audio Contexts notify failed: %d", err);
793
794 return err;
795 }
796 return 0;
797 }
798
pacs_gatt_notify_complete_cb(struct bt_conn * conn,void * user_data)799 void pacs_gatt_notify_complete_cb(struct bt_conn *conn, void *user_data)
800 {
801 /* Notification done, clear bit and reschedule work */
802 atomic_clear(¬ify_rdy);
803 k_work_submit(&deferred_nfy_work);
804 }
805
pacs_gatt_notify(struct bt_conn * conn,const struct bt_uuid * uuid,const struct bt_gatt_attr * attr,const void * data,uint16_t len)806 static int pacs_gatt_notify(struct bt_conn *conn,
807 const struct bt_uuid *uuid,
808 const struct bt_gatt_attr *attr,
809 const void *data,
810 uint16_t len)
811 {
812 int err;
813 struct bt_gatt_notify_params params;
814
815 memset(¶ms, 0, sizeof(params));
816 params.uuid = uuid;
817 params.attr = attr;
818 params.data = data;
819 params.len = len;
820 params.func = pacs_gatt_notify_complete_cb;
821
822 /* Mark notification in progress */
823 atomic_set(¬ify_rdy, 1);
824
825 err = bt_gatt_notify_cb(conn, ¶ms);
826 if (err != 0) {
827 atomic_clear(¬ify_rdy);
828 }
829
830 if (err && err != -ENOTCONN) {
831 return err;
832 }
833
834 return 0;
835 }
836
notify_cb(struct bt_conn * conn,void * data)837 static void notify_cb(struct bt_conn *conn, void *data)
838 {
839 struct pacs_client *client;
840 struct bt_conn_info info;
841 int err = 0;
842
843 LOG_DBG("");
844
845 err = bt_conn_get_info(conn, &info);
846 if (err != 0) {
847 LOG_ERR("Failed to get conn info: %d", err);
848 return;
849 }
850
851 if (info.state != BT_CONN_STATE_CONNECTED) {
852 /* Not connected */
853 return;
854 }
855
856 client = client_lookup_conn(conn);
857 if (client == NULL) {
858 return;
859 }
860
861 /* Check if we have unverified notifications in progress */
862 if (atomic_get(¬ify_rdy)) {
863 return;
864 }
865
866 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
867 if (atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) {
868 LOG_DBG("Notifying Sink PAC");
869 err = pac_notify(conn, BT_AUDIO_DIR_SINK);
870 if (!err) {
871 atomic_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED);
872 }
873 }
874 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
875
876 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
877 if (atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) {
878 LOG_DBG("Notifying Sink Audio Location");
879 err = pac_notify_loc(conn, BT_AUDIO_DIR_SINK);
880 if (!err) {
881 atomic_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
882 }
883 }
884 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
885
886 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
887 if (atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) {
888 LOG_DBG("Notifying Source PAC");
889 err = pac_notify(conn, BT_AUDIO_DIR_SOURCE);
890 if (!err) {
891 atomic_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED);
892 }
893 }
894 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
895
896 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
897 if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) {
898 LOG_DBG("Notifying Source Audio Location");
899 err = pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE);
900 if (!err) {
901 atomic_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
902 }
903 }
904 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
905
906 if (atomic_test_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) {
907 LOG_DBG("Notifying Available Contexts");
908 err = available_contexts_notify(conn);
909 if (!err) {
910 atomic_clear_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
911 }
912 }
913
914 if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) &&
915 atomic_test_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED)) {
916 LOG_DBG("Notifying Supported Contexts");
917 err = supported_contexts_notify(conn);
918 if (!err) {
919 atomic_clear_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
920 }
921 }
922 }
923
deferred_nfy_work_handler(struct k_work * work)924 static void deferred_nfy_work_handler(struct k_work *work)
925 {
926 bt_conn_foreach(BT_CONN_TYPE_LE, notify_cb, NULL);
927 }
928
pacs_auth_pairing_complete(struct bt_conn * conn,bool bonded)929 static void pacs_auth_pairing_complete(struct bt_conn *conn, bool bonded)
930 {
931 LOG_DBG("%s paired (%sbonded)", bt_addr_le_str(bt_conn_get_dst(conn)),
932 bonded ? "" : "not ");
933
934 if (!bonded) {
935 return;
936 }
937
938 /* Check if already in list, and do nothing if it is */
939 for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
940 if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) &&
941 bt_addr_le_eq(bt_conn_get_dst(conn), &clients[i].addr)) {
942 return;
943 }
944 }
945
946 /* Else add the device */
947 for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
948 if (!atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) {
949 atomic_set_bit(clients[i].flags, FLAG_ACTIVE);
950 memcpy(&clients[i].addr, bt_conn_get_dst(conn), sizeof(bt_addr_le_t));
951
952 /* Send out all pending notifications */
953 k_work_submit(&deferred_nfy_work);
954 return;
955 }
956 }
957 }
958
pacs_bond_deleted(uint8_t id,const bt_addr_le_t * peer)959 static void pacs_bond_deleted(uint8_t id, const bt_addr_le_t *peer)
960 {
961 /* Find the device entry to delete */
962 for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
963 /* Check if match, and if active, if so, reset */
964 if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) &&
965 bt_addr_le_eq(peer, &clients[i].addr)) {
966 for (size_t j = 0U; j < FLAG_NUM; j++) {
967 atomic_clear_bit(clients[i].flags, j);
968 }
969 (void)memset(&clients[i].addr, 0, sizeof(bt_addr_le_t));
970 return;
971 }
972 }
973 }
974
pacs_security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)975 static void pacs_security_changed(struct bt_conn *conn, bt_security_t level,
976 enum bt_security_err err)
977 {
978 LOG_DBG("%s changed security level to %d", bt_addr_le_str(bt_conn_get_dst(conn)), level);
979
980 if (err != 0 || conn->encrypt == 0) {
981 return;
982 }
983
984 if (!bt_addr_le_is_bonded(conn->id, &conn->le.dst)) {
985 return;
986 }
987
988 for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
989 for (size_t j = 0U; j < FLAG_NUM; j++) {
990 if (atomic_test_bit(clients[i].flags, j)) {
991
992 /**
993 * It's enough that one flag is set, as the defer work will go
994 * through all notifiable characteristics
995 */
996 k_work_submit(&deferred_nfy_work);
997 return;
998 }
999 }
1000 }
1001 }
1002
pacs_disconnected(struct bt_conn * conn,uint8_t reason)1003 static void pacs_disconnected(struct bt_conn *conn, uint8_t reason)
1004 {
1005 struct pacs_client *client;
1006
1007 client = client_lookup_conn(conn);
1008 if (client == NULL) {
1009 return;
1010 }
1011
1012 #if defined(CONFIG_BT_PAC_SNK)
1013 if (client->snk_available_contexts != NULL) {
1014 uint16_t old = POINTER_TO_UINT(client->snk_available_contexts);
1015 uint16_t new;
1016
1017 client->snk_available_contexts = NULL;
1018 new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK);
1019
1020 atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new);
1021 }
1022 #endif /* CONFIG_BT_PAC_SNK */
1023
1024 #if defined(CONFIG_BT_PAC_SRC)
1025 if (client->src_available_contexts != NULL) {
1026 uint16_t old = POINTER_TO_UINT(client->src_available_contexts);
1027 uint16_t new;
1028
1029 client->src_available_contexts = NULL;
1030 new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE);
1031
1032 atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new);
1033 }
1034 #endif /* CONFIG_BT_PAC_SRC */
1035 }
1036
1037 static struct bt_conn_cb conn_callbacks = {
1038 .security_changed = pacs_security_changed,
1039 .disconnected = pacs_disconnected,
1040 };
1041
1042 static struct bt_conn_auth_info_cb auth_callbacks = {
1043 .pairing_complete = pacs_auth_pairing_complete,
1044 .bond_deleted = pacs_bond_deleted
1045 };
1046
bt_pacs_cap_foreach(enum bt_audio_dir dir,bt_pacs_cap_foreach_func_t func,void * user_data)1047 void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data)
1048 {
1049 sys_slist_t *pac;
1050
1051 CHECKIF(func == NULL) {
1052 LOG_ERR("func is NULL");
1053 return;
1054 }
1055
1056 pac = pacs_get(dir);
1057 if (!pac) {
1058 return;
1059 }
1060
1061 foreach_cap(pac, func, user_data);
1062 }
1063
add_bonded_addr_to_client_list(const struct bt_bond_info * info,void * data)1064 static void add_bonded_addr_to_client_list(const struct bt_bond_info *info, void *data)
1065 {
1066 for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
1067 /* Check if device is registered, it not, add it */
1068 if (!atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) {
1069 char addr_str[BT_ADDR_LE_STR_LEN];
1070
1071 atomic_set_bit(clients[i].flags, FLAG_ACTIVE);
1072 memcpy(&clients[i].addr, &info->addr, sizeof(bt_addr_le_t));
1073 bt_addr_le_to_str(&clients[i].addr, addr_str, sizeof(addr_str));
1074 LOG_DBG("Added %s to bonded list\n", addr_str);
1075 return;
1076 }
1077 }
1078 }
1079
1080 /* Register Audio Capability */
bt_pacs_cap_register(enum bt_audio_dir dir,struct bt_pacs_cap * cap)1081 int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
1082 {
1083 const struct bt_audio_codec_cap *codec_cap;
1084 static bool callbacks_registered;
1085 sys_slist_t *pac;
1086
1087 if (!cap || !cap->codec_cap) {
1088 return -EINVAL;
1089 }
1090
1091 codec_cap = cap->codec_cap;
1092
1093 pac = pacs_get(dir);
1094 if (!pac) {
1095 return -EINVAL;
1096 }
1097
1098 /* Restore bonding list */
1099 bt_foreach_bond(BT_ID_DEFAULT, add_bonded_addr_to_client_list, NULL);
1100
1101 LOG_DBG("cap %p dir %s codec_cap id 0x%02x codec_cap cid 0x%04x codec_cap vid 0x%04x", cap,
1102 bt_audio_dir_str(dir), codec_cap->id, codec_cap->cid, codec_cap->vid);
1103
1104 sys_slist_append(pac, &cap->_node);
1105
1106 if (!callbacks_registered) {
1107 bt_conn_cb_register(&conn_callbacks);
1108 bt_conn_auth_info_cb_register(&auth_callbacks);
1109
1110 callbacks_registered = true;
1111 }
1112
1113 if (IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE) && dir == BT_AUDIO_DIR_SINK) {
1114 pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
1115 k_work_submit(&deferred_nfy_work);
1116 }
1117
1118 if (IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE) && dir == BT_AUDIO_DIR_SOURCE) {
1119 pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
1120 k_work_submit(&deferred_nfy_work);
1121 }
1122
1123 return 0;
1124 }
1125
1126 /* Unregister Audio Capability */
bt_pacs_cap_unregister(enum bt_audio_dir dir,struct bt_pacs_cap * cap)1127 int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
1128 {
1129 sys_slist_t *pac;
1130
1131 if (!cap) {
1132 return -EINVAL;
1133 }
1134
1135 pac = pacs_get(dir);
1136 if (!pac) {
1137 return -EINVAL;
1138 }
1139
1140 LOG_DBG("cap %p dir %s", cap, bt_audio_dir_str(dir));
1141
1142 if (!sys_slist_find_and_remove(pac, &cap->_node)) {
1143 return -ENOENT;
1144 }
1145
1146 switch (dir) {
1147 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
1148 case BT_AUDIO_DIR_SINK:
1149 pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
1150 k_work_submit(&deferred_nfy_work);
1151 break;
1152 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE) */
1153 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
1154 case BT_AUDIO_DIR_SOURCE:
1155 pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
1156 k_work_submit(&deferred_nfy_work);
1157 break;
1158 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
1159 default:
1160 return -EINVAL;
1161 }
1162
1163 return 0;
1164 }
1165
bt_pacs_set_location(enum bt_audio_dir dir,enum bt_audio_location location)1166 int bt_pacs_set_location(enum bt_audio_dir dir, enum bt_audio_location location)
1167 {
1168 switch (dir) {
1169 case BT_AUDIO_DIR_SINK:
1170 set_snk_location(location);
1171 break;
1172 case BT_AUDIO_DIR_SOURCE:
1173 set_src_location(location);
1174 break;
1175 default:
1176 return -EINVAL;
1177 }
1178
1179 return 0;
1180 }
1181
bt_pacs_set_available_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)1182 int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
1183 {
1184 switch (dir) {
1185 case BT_AUDIO_DIR_SINK:
1186 return set_available_contexts(contexts, &snk_available_contexts,
1187 supported_context_get(dir));
1188 case BT_AUDIO_DIR_SOURCE:
1189 return set_available_contexts(contexts, &src_available_contexts,
1190 supported_context_get(dir));
1191 }
1192
1193 return -EINVAL;
1194 }
1195
bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_context * contexts)1196 int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir,
1197 enum bt_audio_context *contexts)
1198 {
1199 enum bt_audio_context old = pacs_get_available_contexts_for_conn(conn, dir);
1200 struct bt_conn_info info = { 0 };
1201 struct pacs_client *client;
1202 int err;
1203
1204 client = client_lookup_conn(conn);
1205 if (client == NULL) {
1206 return -ENOENT;
1207 }
1208
1209 err = bt_conn_get_info(conn, &info);
1210 if (err < 0) {
1211 LOG_ERR("Could not get conn info: %d", err);
1212 return err;
1213 }
1214
1215 switch (dir) {
1216 #if defined(CONFIG_BT_PAC_SNK)
1217 case BT_AUDIO_DIR_SINK:
1218 if (contexts != NULL) {
1219 client->snk_available_contexts = UINT_TO_POINTER(*contexts);
1220 } else {
1221 client->snk_available_contexts = NULL;
1222 }
1223
1224 break;
1225 #endif /* CONFIG_BT_PAC_SNK */
1226 #if defined(CONFIG_BT_PAC_SRC)
1227 case BT_AUDIO_DIR_SOURCE:
1228 if (contexts != NULL) {
1229 client->src_available_contexts = UINT_TO_POINTER(*contexts);
1230 } else {
1231 client->src_available_contexts = NULL;
1232 }
1233
1234 break;
1235 #endif /* CONFIG_BT_PAC_SRC */
1236 default:
1237 return -EINVAL;
1238 }
1239
1240 if (pacs_get_available_contexts_for_conn(conn, dir) == old) {
1241 /* No change. Skip notification */
1242 return 0;
1243 }
1244
1245 atomic_set_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
1246
1247 /* Send notification on encrypted link only */
1248 if (info.security.level > BT_SECURITY_L1) {
1249 k_work_submit(&deferred_nfy_work);
1250 }
1251
1252 return 0;
1253 }
1254
bt_pacs_set_supported_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)1255 int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
1256 {
1257 uint16_t *supported_contexts = NULL;
1258 uint16_t *available_contexts = NULL;
1259
1260 switch (dir) {
1261 case BT_AUDIO_DIR_SINK:
1262 #if defined(CONFIG_BT_PAC_SNK)
1263 supported_contexts = &snk_supported_contexts;
1264 available_contexts = &snk_available_contexts;
1265 break;
1266 #endif /* CONFIG_BT_PAC_SNK */
1267 return -ENOTSUP;
1268 case BT_AUDIO_DIR_SOURCE:
1269 #if defined(CONFIG_BT_PAC_SRC)
1270 supported_contexts = &src_supported_contexts;
1271 available_contexts = &src_available_contexts;
1272 break;
1273 #endif /* CONFIG_BT_PAC_SRC */
1274 return -ENOTSUP;
1275 default:
1276 return -EINVAL;
1277 }
1278
1279 if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) || *supported_contexts == 0) {
1280 return set_supported_contexts(contexts, supported_contexts, available_contexts);
1281 }
1282
1283 return -EALREADY;
1284 }
1285
bt_pacs_get_available_contexts(enum bt_audio_dir dir)1286 enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir)
1287 {
1288 switch (dir) {
1289 case BT_AUDIO_DIR_SINK:
1290 return snk_available_contexts;
1291 case BT_AUDIO_DIR_SOURCE:
1292 return src_available_contexts;
1293 }
1294
1295 return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
1296 }
1297
bt_pacs_get_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir)1298 enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn,
1299 enum bt_audio_dir dir)
1300 {
1301 CHECKIF(conn == NULL) {
1302 LOG_ERR("NULL conn");
1303 return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
1304 }
1305
1306 return pacs_get_available_contexts_for_conn(conn, dir);
1307 }
1308