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