1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <autoconf.h>
8 #include <errno.h>
9 #include <stdbool.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 
13 #include <zephyr/bluetooth/addr.h>
14 #include <zephyr/bluetooth/audio/audio.h>
15 #include <zephyr/bluetooth/audio/bap.h>
16 #include <zephyr/bluetooth/audio/cap.h>
17 #include <zephyr/bluetooth/audio/lc3.h>
18 #include <zephyr/bluetooth/audio/pacs.h>
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/byteorder.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/gap.h>
23 #include <zephyr/bluetooth/hci.h>
24 #include <zephyr/bluetooth/hci_types.h>
25 #include <zephyr/bluetooth/uuid.h>
26 #include <zephyr/kernel.h>
27 #include <zephyr/logging/log.h>
28 #include <zephyr/logging/log_core.h>
29 #include <zephyr/sys/util.h>
30 #include <zephyr/sys/util_macro.h>
31 
32 #include "cap_acceptor.h"
33 
34 LOG_MODULE_REGISTER(cap_acceptor, LOG_LEVEL_INF);
35 
36 #define SUPPORTED_DURATION  (BT_AUDIO_CODEC_CAP_DURATION_7_5 | BT_AUDIO_CODEC_CAP_DURATION_10)
37 #define MAX_CHAN_PER_STREAM BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(2)
38 #define SUPPORTED_FREQ      BT_AUDIO_CODEC_CAP_FREQ_ANY
39 #define SEM_TIMEOUT         K_SECONDS(5)
40 #define MAX_SDU             155U
41 #define MIN_SDU             30U
42 #define FRAMES_PER_SDU      2
43 
44 static const struct bt_data ad[] = {
45 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
46 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
47 	BT_DATA_BYTES(BT_DATA_UUID16_SOME,
48 		      BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL),
49 		      BT_UUID_16_ENCODE(BT_UUID_CAS_VAL)),
50 	BT_DATA_BYTES(BT_DATA_SVC_DATA16,
51 		      BT_UUID_16_ENCODE(BT_UUID_CAS_VAL),
52 		      BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED),
53 	IF_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER,
54 		   (BT_DATA_BYTES(BT_DATA_SVC_DATA16,
55 				  BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL),
56 				  BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED,
57 				  BT_BYTES_LIST_LE16(SINK_CONTEXT),
58 				  BT_BYTES_LIST_LE16(SOURCE_CONTEXT),
59 				  0x00, /* Metadata length */),
60 	))
61 	IF_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR,
62 		   (BT_DATA_BYTES(BT_DATA_SVC_DATA16,
63 				  BT_UUID_16_ENCODE(BT_UUID_BASS_VAL)),
64 	))
65 };
66 
67 static struct bt_le_ext_adv *adv;
68 static struct peer_config peer;
69 
70 static K_SEM_DEFINE(sem_state_change, 0, 1);
71 
connected_cb(struct bt_conn * conn,uint8_t err)72 static void connected_cb(struct bt_conn *conn, uint8_t err)
73 {
74 	char addr[BT_ADDR_LE_STR_LEN];
75 
76 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
77 	LOG_INF("Connected: %s", addr);
78 
79 	peer.conn = bt_conn_ref(conn);
80 	k_sem_give(&sem_state_change);
81 }
82 
disconnected_cb(struct bt_conn * conn,uint8_t reason)83 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
84 {
85 	char addr[BT_ADDR_LE_STR_LEN];
86 
87 	if (conn != peer.conn) {
88 		return;
89 	}
90 
91 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
92 	LOG_INF("Disconnected: %s, reason 0x%02x %s", addr, reason, bt_hci_err_to_str(reason));
93 
94 	bt_conn_unref(peer.conn);
95 	peer.conn = NULL;
96 	k_sem_give(&sem_state_change);
97 }
98 
99 BT_CONN_CB_DEFINE(conn_callbacks) = {
100 	.connected = connected_cb,
101 	.disconnected = disconnected_cb,
102 };
103 
advertise(void)104 static int advertise(void)
105 {
106 	int err;
107 
108 	err = bt_le_ext_adv_create(BT_BAP_ADV_PARAM_CONN_QUICK, NULL, &adv);
109 	if (err) {
110 		LOG_ERR("Failed to create advertising set: %d", err);
111 
112 		return err;
113 	}
114 
115 	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
116 	if (err) {
117 		LOG_ERR("Failed to set advertising data: %d", err);
118 
119 		return err;
120 	}
121 
122 	err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
123 	if (err) {
124 		LOG_ERR("Failed to start advertising set: %d", err);
125 
126 		return err;
127 	}
128 
129 	LOG_INF("Advertising successfully started");
130 
131 	/* Wait for connection*/
132 	err = k_sem_take(&sem_state_change, K_FOREVER);
133 	if (err != 0) {
134 		LOG_ERR("Failed to take sem_state_change: err %d", err);
135 
136 		return err;
137 	}
138 
139 	return 0;
140 }
141 
stream_alloc(enum bt_audio_dir dir)142 struct bt_cap_stream *stream_alloc(enum bt_audio_dir dir)
143 {
144 	if (dir == BT_AUDIO_DIR_SINK && peer.sink_stream.bap_stream.ep == NULL) {
145 		return &peer.sink_stream;
146 	} else if (dir == BT_AUDIO_DIR_SOURCE && peer.source_stream.bap_stream.ep == NULL) {
147 		return &peer.source_stream;
148 	}
149 
150 	return NULL;
151 }
152 
stream_released(const struct bt_cap_stream * cap_stream)153 void stream_released(const struct bt_cap_stream *cap_stream)
154 {
155 	if (cap_stream == &peer.source_stream) {
156 		k_sem_give(&peer.source_stream_sem);
157 	} else if (cap_stream == &peer.sink_stream) {
158 		k_sem_give(&peer.sink_stream_sem);
159 	}
160 }
161 
reset_cap_acceptor(void)162 static int reset_cap_acceptor(void)
163 {
164 	int err;
165 
166 	LOG_INF("Resetting");
167 
168 	if (peer.conn != NULL) {
169 		err = bt_conn_disconnect(peer.conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
170 		if (err != 0) {
171 			return err;
172 		}
173 
174 		err = k_sem_take(&sem_state_change, K_FOREVER);
175 		if (err != 0) {
176 			LOG_ERR("Timeout on disconnect: %d", err);
177 			return err;
178 		}
179 	}
180 
181 	if (adv != NULL) {
182 		err = bt_le_ext_adv_stop(adv);
183 		if (err != 0) {
184 			LOG_ERR("Failed to stop advertiser: %d", err);
185 			return err;
186 		}
187 
188 		err = bt_le_ext_adv_delete(adv);
189 		if (err != 0) {
190 			LOG_ERR("Failed to delete advertiser: %d", err);
191 			return err;
192 		}
193 
194 		adv = NULL;
195 	}
196 
197 	if (peer.source_stream.bap_stream.ep != NULL) {
198 		err = k_sem_take(&peer.source_stream_sem, SEM_TIMEOUT);
199 		if (err != 0) {
200 			LOG_ERR("Timeout on source_stream_sem: %d", err);
201 			return err;
202 		}
203 	}
204 
205 	if (peer.sink_stream.bap_stream.ep != NULL) {
206 		err = k_sem_take(&peer.sink_stream_sem, SEM_TIMEOUT);
207 		if (err != 0) {
208 			LOG_ERR("Timeout on sink_stream_sem: %d", err);
209 			return err;
210 		}
211 	}
212 
213 	k_sem_reset(&sem_state_change);
214 
215 	return 0;
216 }
217 
218 /** Register the PAC records for PACS */
register_pac(enum bt_audio_dir dir,enum bt_audio_context context,struct bt_pacs_cap * cap)219 static int register_pac(enum bt_audio_dir dir, enum bt_audio_context context,
220 			struct bt_pacs_cap *cap)
221 {
222 	int err;
223 
224 	err = bt_pacs_cap_register(dir, cap);
225 	if (err != 0) {
226 		LOG_ERR("Failed to register capabilities: %d", err);
227 
228 		return err;
229 	}
230 
231 	err = bt_pacs_set_location(dir, BT_AUDIO_LOCATION_MONO_AUDIO);
232 	if (err != 0) {
233 		LOG_ERR("Failed to set location: %d", err);
234 
235 		return err;
236 	}
237 
238 	err = bt_pacs_set_supported_contexts(dir, context);
239 	if (err != 0 && err != -EALREADY) {
240 		LOG_ERR("Failed to set supported contexts: %d", err);
241 
242 		return err;
243 	}
244 
245 	err = bt_pacs_set_available_contexts(dir, context);
246 	if (err != 0 && err != -EALREADY) {
247 		LOG_ERR("Failed to set available contexts: %d", err);
248 
249 		return err;
250 	}
251 
252 	return 0;
253 }
254 
init_cap_acceptor(void)255 static int init_cap_acceptor(void)
256 {
257 	static const struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_CAP_LC3(
258 		SUPPORTED_FREQ, SUPPORTED_DURATION, MAX_CHAN_PER_STREAM, MIN_SDU, MAX_SDU,
259 		FRAMES_PER_SDU, (SINK_CONTEXT | SOURCE_CONTEXT));
260 	const struct bt_pacs_register_param pacs_param = {
261 		.snk_pac = true,
262 		.snk_loc = true,
263 		.src_pac = true,
264 		.src_loc = true,
265 	};
266 	int err;
267 
268 	err = bt_enable(NULL);
269 	if (err != 0) {
270 		LOG_ERR("Bluetooth enable failed: %d", err);
271 
272 		return 0;
273 	}
274 
275 	LOG_INF("Bluetooth initialized");
276 
277 	err = bt_pacs_register(&pacs_param);
278 	if (err) {
279 		LOG_ERR("Could not register PACS (err %d)", err);
280 		return 0;
281 	}
282 
283 	if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
284 		static struct bt_pacs_cap sink_cap = {
285 			.codec_cap = &lc3_codec_cap,
286 		};
287 		int err;
288 
289 		err = register_pac(BT_AUDIO_DIR_SINK, SINK_CONTEXT, &sink_cap);
290 		if (err != 0) {
291 			LOG_ERR("Failed to register sink capabilities: %d", err);
292 
293 			return -ENOEXEC;
294 		}
295 	}
296 
297 	if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
298 		static struct bt_pacs_cap source_cap = {
299 			.codec_cap = &lc3_codec_cap,
300 		};
301 		int err;
302 
303 		err = register_pac(BT_AUDIO_DIR_SOURCE, SOURCE_CONTEXT, &source_cap);
304 		if (err != 0) {
305 			LOG_ERR("Failed to register sink capabilities: %d", err);
306 
307 			return -ENOEXEC;
308 		}
309 	}
310 
311 	return 0;
312 }
313 
main(void)314 int main(void)
315 {
316 	int err;
317 
318 	err = init_cap_acceptor();
319 	if (err != 0) {
320 		return 0;
321 	}
322 
323 	if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER)) {
324 		err = init_cap_acceptor_unicast(&peer);
325 		if (err != 0) {
326 			return 0;
327 		}
328 	}
329 
330 	if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK)) {
331 		err = init_cap_acceptor_broadcast();
332 		if (err != 0) {
333 			return 0;
334 		}
335 	}
336 
337 	LOG_INF("CAP Acceptor initialized");
338 
339 	while (true) {
340 		err = reset_cap_acceptor();
341 		if (err != 0) {
342 			LOG_ERR("Failed to reset");
343 
344 			break;
345 		}
346 
347 		/* Start advertising as a CAP Acceptor, which includes setting the required
348 		 * advertising data based on the roles we support. The Common Audio Service data is
349 		 * always advertised, as CAP Initiators and CAP Commanders will use this to identify
350 		 * our device as a CAP Acceptor.
351 		 */
352 		err = advertise();
353 		if (err != 0) {
354 			continue;
355 		}
356 
357 		/* After advertising we expect CAP Initiators to connect to us and setup streams,
358 		 * and eventually disconnect again. As a CAP Acceptor we just need to react to their
359 		 * requests and not do anything else.
360 		 */
361 
362 		/* Reset if disconnected */
363 		err = k_sem_take(&sem_state_change, K_FOREVER);
364 		if (err != 0) {
365 			LOG_ERR("Failed to take sem_state_change: err %d", err);
366 
367 			break;
368 		}
369 	}
370 
371 	return 0;
372 }
373