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 "../host/conn_internal.h"
25 
26 #include <zephyr/logging/log.h>
27 
28 LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL);
29 
30 #include "common/bt_str.h"
31 
32 #include "audio_internal.h"
33 #include "pacs_internal.h"
34 #include "bap_unicast_server.h"
35 
36 #define PAC_NOTIFY_TIMEOUT	K_MSEC(10)
37 #define READ_BUF_SEM_TIMEOUT    K_MSEC(50)
38 
39 #define PACS(_name, _work_handler) \
40 	struct pacs _name = { \
41 		.work = Z_WORK_DELAYABLE_INITIALIZER(_work_handler), \
42 	};
43 
44 #define PACS_LOCATION(_name, _work_handler) \
45 	struct pacs_location _name = { \
46 		.work = Z_WORK_DELAYABLE_INITIALIZER(_work_handler), \
47 	};
48 
49 struct pacs_location {
50 	struct k_work_delayable work;
51 	uint32_t location;
52 };
53 
54 struct pacs {
55 	struct k_work_delayable work;
56 	sys_slist_t list;
57 };
58 
59 #if defined(CONFIG_BT_PAC_SNK)
60 static uint16_t snk_available_contexts;
61 static uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
62 #else
63 static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
64 static uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
65 #endif /* CONFIG_BT_PAC_SNK */
66 
67 #if defined(CONFIG_BT_PAC_SRC)
68 static uint16_t src_available_contexts;
69 static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
70 #else
71 static uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
72 static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
73 #endif /* CONFIG_BT_PAC_SRC */
74 
75 static K_SEM_DEFINE(read_buf_sem, 1, 1);
76 NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN);
77 
pac_data_add(struct net_buf_simple * buf,size_t count,struct bt_codec_data * data)78 static ssize_t pac_data_add(struct net_buf_simple *buf, size_t count,
79 			    struct bt_codec_data *data)
80 {
81 	size_t len = 0;
82 
83 	for (size_t i = 0; i < count; i++) {
84 		struct bt_pac_ltv *ltv;
85 		struct bt_data *d = &data[i].data;
86 		const size_t ltv_len = sizeof(*ltv) + d->data_len;
87 
88 		if (net_buf_simple_tailroom(buf) < ltv_len) {
89 			return -ENOMEM;
90 		}
91 
92 		ltv = net_buf_simple_add(buf, sizeof(*ltv));
93 		ltv->len = d->data_len + sizeof(ltv->type);
94 		ltv->type = d->type;
95 		net_buf_simple_add_mem(buf, d->data, d->data_len);
96 
97 		len += ltv_len;
98 	}
99 
100 	return len;
101 }
102 
103 struct pac_records_build_data {
104 	struct bt_pacs_read_rsp *rsp;
105 	struct net_buf_simple *buf;
106 };
107 
build_pac_records(const struct bt_pacs_cap * cap,void * user_data)108 static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data)
109 {
110 	struct pac_records_build_data *data = user_data;
111 	struct bt_codec *codec = cap->codec;
112 	struct net_buf_simple *buf = data->buf;
113 	struct net_buf_simple_state state;
114 	struct bt_pac_ltv_data *cc, *meta;
115 	struct bt_pac_codec *pac_codec;
116 	ssize_t len;
117 
118 	net_buf_simple_save(buf, &state);
119 
120 	if (net_buf_simple_tailroom(buf) < sizeof(*pac_codec)) {
121 		goto fail;
122 	}
123 
124 	pac_codec = net_buf_simple_add(buf, sizeof(*pac_codec));
125 	pac_codec->id = codec->id;
126 	pac_codec->cid = sys_cpu_to_le16(codec->cid);
127 	pac_codec->vid = sys_cpu_to_le16(codec->vid);
128 
129 	if (net_buf_simple_tailroom(buf) < sizeof(*cc)) {
130 		goto fail;
131 	}
132 
133 	cc = net_buf_simple_add(buf, sizeof(*cc));
134 
135 	len = pac_data_add(buf, codec->data_count, codec->data);
136 	if (len < 0 || len > UINT8_MAX) {
137 		goto fail;
138 	}
139 
140 	cc->len = len;
141 
142 	if (net_buf_simple_tailroom(buf) < sizeof(*meta)) {
143 		goto fail;
144 	}
145 
146 	meta = net_buf_simple_add(buf, sizeof(*meta));
147 
148 	len = pac_data_add(buf, codec->meta_count, codec->meta);
149 	if (len < 0 || len > UINT8_MAX) {
150 		goto fail;
151 	}
152 
153 	meta->len = len;
154 
155 	data->rsp->num_pac++;
156 
157 	return true;
158 
159 fail:
160 	__ASSERT(false, "No space for %p", cap);
161 
162 	net_buf_simple_restore(buf, &state);
163 
164 	return false;
165 }
166 
foreach_cap(sys_slist_t * list,bt_pacs_cap_foreach_func_t func,void * user_data)167 static void foreach_cap(sys_slist_t *list, bt_pacs_cap_foreach_func_t func,
168 			void *user_data)
169 {
170 	struct bt_pacs_cap *cap;
171 
172 	SYS_SLIST_FOR_EACH_CONTAINER(list, cap, _node) {
173 		if (!func(cap, user_data)) {
174 			break;
175 		}
176 	}
177 }
178 
get_pac_records(sys_slist_t * list,struct net_buf_simple * buf)179 static void get_pac_records(sys_slist_t *list, struct net_buf_simple *buf)
180 {
181 	struct pac_records_build_data data;
182 
183 	/* Reset if buffer before using */
184 	net_buf_simple_reset(buf);
185 
186 	data.rsp = net_buf_simple_add(buf, sizeof(*data.rsp));
187 	data.rsp->num_pac = 0;
188 	data.buf = buf;
189 
190 	foreach_cap(list, build_pac_records, &data);
191 }
192 
available_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)193 static void available_context_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
194 {
195 	LOG_DBG("attr %p value 0x%04x", attr, value);
196 }
197 
available_contexts_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)198 static ssize_t available_contexts_read(struct bt_conn *conn,
199 				       const struct bt_gatt_attr *attr, void *buf,
200 				       uint16_t len, uint16_t offset)
201 {
202 	struct bt_pacs_context context = {
203 		.snk = sys_cpu_to_le16(snk_available_contexts),
204 		.src = sys_cpu_to_le16(src_available_contexts),
205 	};
206 
207 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
208 
209 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
210 				 sizeof(context));
211 }
212 
supported_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)213 static void supported_context_cfg_changed(const struct bt_gatt_attr *attr,
214 					  uint16_t value)
215 {
216 	LOG_DBG("attr %p value 0x%04x", attr, value);
217 }
218 
supported_context_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)219 static ssize_t supported_context_read(struct bt_conn *conn,
220 				      const struct bt_gatt_attr *attr,
221 				      void *buf, uint16_t len, uint16_t offset)
222 {
223 	struct bt_pacs_context context = {
224 		.snk = sys_cpu_to_le16(snk_supported_contexts),
225 		.src = sys_cpu_to_le16(src_supported_contexts),
226 	};
227 
228 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
229 
230 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
231 				 sizeof(context));
232 }
233 
234 static void available_contexts_notify(struct k_work *work);
235 static void supported_contexts_notify(struct k_work *work);
236 static K_WORK_DELAYABLE_DEFINE(available_contexts_work, available_contexts_notify);
237 static K_WORK_DELAYABLE_DEFINE(supported_contexts_work, supported_contexts_notify);
238 
set_available_contexts(uint16_t contexts,uint16_t * available,uint16_t supported)239 static int set_available_contexts(uint16_t contexts, uint16_t *available,
240 				  uint16_t supported)
241 {
242 	int err;
243 
244 	if (contexts & ~supported) {
245 		return -ENOTSUP;
246 	}
247 
248 	if (contexts == *available) {
249 		return 0;
250 	}
251 
252 	err = k_work_reschedule(&available_contexts_work, PAC_NOTIFY_TIMEOUT);
253 	if (err < 0) {
254 		return err;
255 	}
256 
257 	*available = contexts;
258 
259 	return 0;
260 }
261 
set_supported_contexts(uint16_t contexts,uint16_t * supported,uint16_t * available)262 static int set_supported_contexts(uint16_t contexts, uint16_t *supported,
263 				  uint16_t *available)
264 {
265 	int err;
266 
267 	/* Ensure unspecified is always supported */
268 	contexts |= BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
269 
270 	if (*supported == contexts) {
271 		return 0;
272 	}
273 
274 	err = k_work_reschedule(&supported_contexts_work, PAC_NOTIFY_TIMEOUT);
275 	if (err < 0) {
276 		return err;
277 	}
278 
279 	*supported = contexts;
280 
281 	/* Update available contexts if needed*/
282 	if ((contexts & *available) != *available) {
283 		*available = *available & contexts;
284 		err = k_work_reschedule(&available_contexts_work,
285 					PAC_NOTIFY_TIMEOUT);
286 		if (err < 0) {
287 			LOG_WRN("Update available contexts notify failed: %d", err);
288 		}
289 	}
290 
291 	return 0;
292 }
293 
294 #if defined(CONFIG_BT_PAC_SNK)
295 static void pac_notify_snk(struct k_work *work);
296 static PACS(snk_pacs, pac_notify_snk);
297 
snk_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)298 static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
299 			void *buf, uint16_t len, uint16_t offset)
300 {
301 	ssize_t ret_val;
302 	int err;
303 
304 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
305 
306 	err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
307 	if (err != 0) {
308 		LOG_DBG("Failed to take read_buf_sem: %d", err);
309 
310 		return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
311 	}
312 
313 	get_pac_records(&snk_pacs.list, &read_buf);
314 
315 	ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
316 				    read_buf.len);
317 
318 	k_sem_give(&read_buf_sem);
319 
320 	return ret_val;
321 }
322 
snk_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)323 static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
324 {
325 	LOG_DBG("attr %p value 0x%04x", attr, value);
326 }
327 
set_snk_available_contexts(uint16_t contexts)328 static inline int set_snk_available_contexts(uint16_t contexts)
329 {
330 	return set_available_contexts(contexts, &snk_available_contexts,
331 				      snk_supported_contexts);
332 }
333 
set_snk_supported_contexts(uint16_t contexts)334 static inline int set_snk_supported_contexts(uint16_t contexts)
335 {
336 	return set_supported_contexts(contexts, &snk_supported_contexts,
337 				      &snk_available_contexts);
338 }
339 #else
set_snk_available_contexts(uint16_t contexts)340 static inline int set_snk_available_contexts(uint16_t contexts)
341 {
342 	return -ENOTSUP;
343 }
344 
set_snk_supported_contexts(uint16_t contexts)345 static inline int set_snk_supported_contexts(uint16_t contexts)
346 {
347 	return -ENOTSUP;
348 }
349 #endif /* CONFIG_BT_PAC_SNK */
350 
351 #if defined(CONFIG_BT_PAC_SNK_LOC)
352 static void pac_notify_snk_loc(struct k_work *work);
353 static PACS_LOCATION(snk_location, pac_notify_snk_loc);
354 
snk_loc_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)355 static ssize_t snk_loc_read(struct bt_conn *conn,
356 			    const struct bt_gatt_attr *attr, void *buf,
357 			    uint16_t len, uint16_t offset)
358 {
359 	uint32_t location = sys_cpu_to_le32(snk_location.location);
360 
361 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
362 
363 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
364 				 sizeof(location));
365 }
366 
snk_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)367 static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
368 {
369 	LOG_DBG("attr %p value 0x%04x", attr, value);
370 }
371 
set_snk_location(enum bt_audio_location audio_location)372 static int set_snk_location(enum bt_audio_location audio_location)
373 {
374 	if (audio_location == snk_location.location) {
375 		return 0;
376 	}
377 
378 	snk_location.location = audio_location;
379 
380 	k_work_reschedule(&snk_location.work, PAC_NOTIFY_TIMEOUT);
381 
382 	return 0;
383 }
384 #else
set_snk_location(enum bt_audio_location location)385 static int set_snk_location(enum bt_audio_location location)
386 {
387 	return -ENOTSUP;
388 }
389 #endif /* CONFIG_BT_PAC_SNK_LOC */
390 
391 #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)392 static ssize_t snk_loc_write(struct bt_conn *conn,
393 			     const struct bt_gatt_attr *attr, const void *data,
394 			     uint16_t len, uint16_t offset, uint8_t flags)
395 {
396 	int err;
397 	enum bt_audio_location location;
398 
399 	if (offset) {
400 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
401 	}
402 
403 	if (len != sizeof(location)) {
404 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
405 	}
406 
407 	location = (enum bt_audio_location)sys_get_le32(data);
408 	if (location > BT_AUDIO_LOCATION_MASK || location == 0) {
409 		LOG_DBG("Invalid location value: 0x%08X", location);
410 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
411 	}
412 
413 	err = set_snk_location(location);
414 	if (err != 0) {
415 		LOG_DBG("write_location returned %d", err);
416 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
417 	}
418 
419 	return len;
420 }
421 #endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
422 
423 #if defined(CONFIG_BT_PAC_SRC)
424 static void pac_notify_src(struct k_work *work);
425 static PACS(src_pacs, pac_notify_src);
426 
src_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)427 static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
428 			void *buf, uint16_t len, uint16_t offset)
429 {
430 	ssize_t ret_val;
431 	int err;
432 
433 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
434 
435 	err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
436 	if (err != 0) {
437 		LOG_DBG("Failed to take read_buf_sem: %d", err);
438 
439 		return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
440 	}
441 
442 	get_pac_records(&src_pacs.list, &read_buf);
443 
444 	ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
445 				    read_buf.len);
446 
447 	k_sem_give(&read_buf_sem);
448 
449 	return ret_val;
450 }
451 
src_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)452 static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
453 {
454 	LOG_DBG("attr %p value 0x%04x", attr, value);
455 }
456 
set_src_available_contexts(uint16_t contexts)457 static inline int set_src_available_contexts(uint16_t contexts)
458 {
459 	return set_available_contexts(contexts, &src_available_contexts,
460 				      src_supported_contexts);
461 }
462 
set_src_supported_contexts(uint16_t contexts)463 static inline int set_src_supported_contexts(uint16_t contexts)
464 {
465 	return set_supported_contexts(contexts, &src_supported_contexts,
466 				      &src_available_contexts);
467 }
468 #else
set_src_available_contexts(uint16_t contexts)469 static inline int set_src_available_contexts(uint16_t contexts)
470 {
471 	return -ENOTSUP;
472 }
473 
set_src_supported_contexts(uint16_t contexts)474 static inline int set_src_supported_contexts(uint16_t contexts)
475 {
476 	return -ENOTSUP;
477 }
478 #endif /* CONFIG_BT_PAC_SRC */
479 
480 #if defined(CONFIG_BT_PAC_SRC_LOC)
481 static void pac_notify_src_loc(struct k_work *work);
482 static PACS_LOCATION(src_location, pac_notify_src_loc);
483 
src_loc_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)484 static ssize_t src_loc_read(struct bt_conn *conn,
485 			    const struct bt_gatt_attr *attr, void *buf,
486 			    uint16_t len, uint16_t offset)
487 {
488 	uint32_t location = sys_cpu_to_le32(src_location.location);
489 
490 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
491 
492 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
493 				 sizeof(location));
494 }
495 
src_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)496 static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
497 {
498 	LOG_DBG("attr %p value 0x%04x", attr, value);
499 }
500 
set_src_location(enum bt_audio_location audio_location)501 static int set_src_location(enum bt_audio_location audio_location)
502 {
503 	if (audio_location == src_location.location) {
504 		return 0;
505 	}
506 
507 	src_location.location = audio_location;
508 
509 	k_work_reschedule(&src_location.work, PAC_NOTIFY_TIMEOUT);
510 
511 	return 0;
512 }
513 #else
set_src_location(enum bt_audio_location location)514 static int set_src_location(enum bt_audio_location location)
515 {
516 	return -ENOTSUP;
517 }
518 #endif /* CONFIG_BT_PAC_SRC_LOC */
519 
520 #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)521 static ssize_t src_loc_write(struct bt_conn *conn,
522 			     const struct bt_gatt_attr *attr, const void *data,
523 			     uint16_t len, uint16_t offset, uint8_t flags)
524 {
525 	int err;
526 	uint32_t location;
527 
528 	if (offset) {
529 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
530 	}
531 
532 	if (len != sizeof(location)) {
533 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
534 	}
535 
536 	location = (enum bt_audio_location)sys_get_le32(data);
537 	if (location > BT_AUDIO_LOCATION_MASK || location == 0) {
538 		LOG_DBG("Invalid location value: 0x%08X", location);
539 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
540 	}
541 
542 	err = set_src_location(location);
543 	if (err != 0) {
544 		LOG_DBG("write_location returned %d", err);
545 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
546 	}
547 
548 	return len;
549 }
550 #endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
551 
552 BT_GATT_SERVICE_DEFINE(pacs_svc,
553 	BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),
554 #if defined(CONFIG_BT_PAC_SNK)
555 	BT_AUDIO_CHRC(BT_UUID_PACS_SNK,
556 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
557 		      BT_GATT_PERM_READ_ENCRYPT,
558 		      snk_read, NULL, NULL),
559 	BT_AUDIO_CCC(snk_cfg_changed),
560 #if defined(CONFIG_BT_PAC_SNK_LOC)
561 #if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE)
562 	BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
563 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
564 		      BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
565 		      snk_loc_read, snk_loc_write, NULL),
566 #else
567 	BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
568 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
569 		      BT_GATT_PERM_READ_ENCRYPT,
570 		      snk_loc_read, NULL, NULL),
571 #endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
572 	BT_AUDIO_CCC(snk_loc_cfg_changed),
573 #endif /* CONFIG_BT_PAC_SNK_LOC */
574 #endif /* CONFIG_BT_PAC_SNK */
575 #if defined(CONFIG_BT_PAC_SRC)
576 	BT_AUDIO_CHRC(BT_UUID_PACS_SRC,
577 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
578 		      BT_GATT_PERM_READ_ENCRYPT,
579 		      src_read, NULL, NULL),
580 	BT_AUDIO_CCC(src_cfg_changed),
581 #if defined(CONFIG_BT_PAC_SRC_LOC)
582 #if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
583 	BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
584 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
585 		      BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
586 		      src_loc_read, src_loc_write, NULL),
587 #else
588 	BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
589 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
590 		      BT_GATT_PERM_READ_ENCRYPT,
591 		      src_loc_read, NULL, NULL),
592 #endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
593 	BT_AUDIO_CCC(src_loc_cfg_changed),
594 #endif /* CONFIG_BT_PAC_SRC_LOC */
595 #endif /* CONFIG_BT_PAC_SRC */
596 	BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT,
597 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
598 		      BT_GATT_PERM_READ_ENCRYPT,
599 		      available_contexts_read, NULL, NULL),
600 	BT_AUDIO_CCC(available_context_cfg_changed),
601 	BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT,
602 		      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
603 		      BT_GATT_PERM_READ_ENCRYPT,
604 		      supported_context_read, NULL, NULL),
605 	BT_AUDIO_CCC(supported_context_cfg_changed)
606 );
607 
608 #if defined(CONFIG_BT_PAC_SNK_LOC)
pac_notify_snk_loc(struct k_work * work)609 static void pac_notify_snk_loc(struct k_work *work)
610 {
611 	struct pacs_location *location = CONTAINER_OF(work, struct pacs_location, work);
612 	uint32_t location_le = sys_cpu_to_le32(location->location);
613 	int err;
614 
615 	err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SNK_LOC, pacs_svc.attrs, &location_le,
616 				  sizeof(location_le));
617 	if (err != 0 && err != -ENOTCONN) {
618 		LOG_WRN("PACS notify_loc failed: %d", err);
619 	}
620 }
621 #endif /* CONFIG_BT_PAC_SNK_LOC */
622 
623 #if defined(CONFIG_BT_PAC_SRC_LOC)
pac_notify_src_loc(struct k_work * work)624 static void pac_notify_src_loc(struct k_work *work)
625 {
626 	struct pacs_location *location = CONTAINER_OF(work, struct pacs_location, work);
627 	uint32_t location_le = sys_cpu_to_le32(location->location);
628 	int err;
629 
630 	err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SRC_LOC, pacs_svc.attrs, &location_le,
631 				  sizeof(location_le));
632 	if (err != 0 && err != -ENOTCONN) {
633 		LOG_WRN("PACS notify_loc failed: %d", err);
634 	}
635 }
636 #endif /* CONFIG_BT_PAC_SRC_LOC */
637 
638 #if defined(CONFIG_BT_PAC_SNK)
pac_notify_snk(struct k_work * work)639 static void pac_notify_snk(struct k_work *work)
640 {
641 	struct pacs *pac = CONTAINER_OF(work, struct pacs, work);
642 	int err;
643 
644 	err = k_sem_take(&read_buf_sem, K_NO_WAIT);
645 	if (err != 0) {
646 		LOG_DBG("Failed to take read_buf_sem: %d", err);
647 
648 		/* Try again later */
649 		k_work_reschedule(k_work_delayable_from_work(work),
650 				  PAC_NOTIFY_TIMEOUT);
651 
652 		return;
653 	}
654 
655 	get_pac_records(&pac->list, &read_buf);
656 
657 	err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SNK, pacs_svc.attrs,
658 				  read_buf.data, read_buf.len);
659 	if (err != 0 && err != -ENOTCONN) {
660 		LOG_WRN("PACS notify failed: %d", err);
661 	}
662 
663 	k_sem_give(&read_buf_sem);
664 }
665 #endif /* CONFIG_BT_PAC_SNK */
666 
667 #if defined(CONFIG_BT_PAC_SRC)
pac_notify_src(struct k_work * work)668 static void pac_notify_src(struct k_work *work)
669 {
670 	struct pacs *pac = CONTAINER_OF(work, struct pacs, work);
671 	int err = 0;
672 
673 	err = k_sem_take(&read_buf_sem, K_NO_WAIT);
674 	if (err != 0) {
675 		LOG_DBG("Failed to take read_buf_sem: %d", err);
676 
677 		/* Try again later */
678 		k_work_reschedule(k_work_delayable_from_work(work),
679 				  PAC_NOTIFY_TIMEOUT);
680 
681 		return;
682 	}
683 
684 	get_pac_records(&pac->list, &read_buf);
685 
686 	err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SRC, pacs_svc.attrs,
687 				  read_buf.data, read_buf.len);
688 	if (err != 0 && err != -ENOTCONN) {
689 		LOG_WRN("PACS notify failed: %d", err);
690 	}
691 
692 	k_sem_give(&read_buf_sem);
693 }
694 #endif /* CONFIG_BT_PAC_SRC */
695 
pacs_changed(struct pacs * caps)696 static void pacs_changed(struct pacs *caps)
697 {
698 	k_work_reschedule(&caps->work, PAC_NOTIFY_TIMEOUT);
699 }
700 
available_contexts_notify(struct k_work * work)701 static void available_contexts_notify(struct k_work *work)
702 {
703 	struct bt_pacs_context context = {
704 		.snk = sys_cpu_to_le16(snk_available_contexts),
705 		.src = sys_cpu_to_le16(src_available_contexts),
706 	};
707 	int err;
708 
709 	err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_AVAILABLE_CONTEXT, pacs_svc.attrs,
710 				  &context, sizeof(context));
711 	if (err != 0 && err != -ENOTCONN) {
712 		LOG_WRN("Available Audio Contexts notify failed: %d", err);
713 	}
714 }
715 
supported_contexts_notify(struct k_work * work)716 static void supported_contexts_notify(struct k_work *work)
717 {
718 	struct bt_pacs_context context = {
719 		.snk = sys_cpu_to_le16(snk_supported_contexts),
720 		.src = sys_cpu_to_le16(src_supported_contexts),
721 	};
722 	int err;
723 
724 	err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SUPPORTED_CONTEXT, pacs_svc.attrs,
725 				  &context, sizeof(context));
726 	if (err != 0 && err != -ENOTCONN) {
727 		LOG_WRN("Supported Audio Contexts notify failed: %d", err);
728 	}
729 }
730 
bt_pacs_context_available(enum bt_audio_dir dir,uint16_t context)731 bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context)
732 {
733 	if (dir == BT_AUDIO_DIR_SOURCE) {
734 		return (context & src_available_contexts) == context;
735 	}
736 
737 	if (dir == BT_AUDIO_DIR_SINK) {
738 		return (context & snk_available_contexts) == context;
739 	}
740 
741 	return false;
742 }
743 
pacs_get(enum bt_audio_dir dir)744 static struct pacs *pacs_get(enum bt_audio_dir dir)
745 {
746 	switch (dir) {
747 #if defined(CONFIG_BT_PAC_SNK)
748 	case BT_AUDIO_DIR_SINK:
749 		return &snk_pacs;
750 #endif /* CONFIG_BT_PAC_SNK */
751 #if defined(CONFIG_BT_PAC_SRC)
752 	case BT_AUDIO_DIR_SOURCE:
753 		return &src_pacs;
754 #endif /* CONFIG_BT_PAC_SRC */
755 	default:
756 		return NULL;
757 	}
758 }
759 
bt_pacs_cap_foreach(enum bt_audio_dir dir,bt_pacs_cap_foreach_func_t func,void * user_data)760 void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data)
761 {
762 	struct pacs *pac;
763 
764 	CHECKIF(func == NULL) {
765 		LOG_ERR("func is NULL");
766 		return;
767 	}
768 
769 	pac = pacs_get(dir);
770 	if (!pac) {
771 		return;
772 	}
773 
774 	foreach_cap(&pac->list, func, user_data);
775 }
776 
777 /* Register Audio Capability */
bt_pacs_cap_register(enum bt_audio_dir dir,struct bt_pacs_cap * cap)778 int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
779 {
780 	struct pacs *pac;
781 
782 	if (!cap || !cap->codec) {
783 		return -EINVAL;
784 	}
785 
786 	pac = pacs_get(dir);
787 	if (!pac) {
788 		return -EINVAL;
789 	}
790 
791 	LOG_DBG("cap %p dir %s codec 0x%02x codec cid 0x%04x "
792 	       "codec vid 0x%04x", cap, bt_audio_dir_str(dir), cap->codec->id,
793 	       cap->codec->cid, cap->codec->vid);
794 
795 	sys_slist_append(&pac->list, &cap->_node);
796 
797 	pacs_changed(pac);
798 
799 	return 0;
800 }
801 
802 /* Unregister Audio Capability */
bt_pacs_cap_unregister(enum bt_audio_dir dir,struct bt_pacs_cap * cap)803 int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
804 {
805 	struct pacs *pac;
806 
807 	if (!cap) {
808 		return -EINVAL;
809 	}
810 
811 	pac = pacs_get(dir);
812 	if (!pac) {
813 		return -EINVAL;
814 	}
815 
816 	LOG_DBG("cap %p dir %s", cap, bt_audio_dir_str(dir));
817 
818 	if (!sys_slist_find_and_remove(&pac->list, &cap->_node)) {
819 		return -ENOENT;
820 	}
821 
822 	pacs_changed(pac);
823 
824 	return 0;
825 }
826 
bt_pacs_set_location(enum bt_audio_dir dir,enum bt_audio_location location)827 int bt_pacs_set_location(enum bt_audio_dir dir, enum bt_audio_location location)
828 {
829 	switch (dir) {
830 	case BT_AUDIO_DIR_SINK:
831 		return set_snk_location(location);
832 	case BT_AUDIO_DIR_SOURCE:
833 		return set_src_location(location);
834 	}
835 
836 	return -EINVAL;
837 }
838 
bt_pacs_set_available_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)839 int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
840 {
841 	switch (dir) {
842 	case BT_AUDIO_DIR_SINK:
843 		return set_snk_available_contexts(contexts);
844 	case BT_AUDIO_DIR_SOURCE:
845 		return set_src_available_contexts(contexts);
846 	}
847 
848 	return -EINVAL;
849 }
850 
bt_pacs_set_supported_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)851 int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
852 {
853 	switch (dir) {
854 	case BT_AUDIO_DIR_SINK:
855 		return set_snk_supported_contexts(contexts);
856 	case BT_AUDIO_DIR_SOURCE:
857 		return set_src_supported_contexts(contexts);
858 	}
859 
860 	return -EINVAL;
861 }
862 
bt_pacs_get_available_contexts(enum bt_audio_dir dir)863 enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir)
864 {
865 	switch (dir) {
866 	case BT_AUDIO_DIR_SINK:
867 		return snk_available_contexts;
868 	case BT_AUDIO_DIR_SOURCE:
869 		return src_available_contexts;
870 	}
871 
872 	return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
873 }
874