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/__assert.h>
30 #include <zephyr/sys/util.h>
31 #include <zephyr/sys/util_macro.h>
32 
33 #include "cap_acceptor.h"
34 
35 LOG_MODULE_REGISTER(cap_acceptor, LOG_LEVEL_INF);
36 
37 #define SUPPORTED_DURATION (BT_AUDIO_CODEC_CAP_DURATION_7_5 | BT_AUDIO_CODEC_CAP_DURATION_10)
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 	struct bt_cap_stream *ret_stream;
145 
146 	if (dir == BT_AUDIO_DIR_SINK) {
147 		ret_stream = NULL;
148 		ARRAY_FOR_EACH_PTR(peer.sink_streams, stream) {
149 			if (stream->bap_stream.ep == NULL) {
150 				ret_stream = stream;
151 			}
152 		}
153 	} else if (dir == BT_AUDIO_DIR_SOURCE && peer.source_stream.bap_stream.ep == NULL) {
154 		ret_stream = &peer.source_stream;
155 	} else {
156 		ret_stream = NULL;
157 	}
158 
159 	return ret_stream;
160 }
161 
stream_released(const struct bt_cap_stream * cap_stream)162 void stream_released(const struct bt_cap_stream *cap_stream)
163 {
164 	if (cap_stream == &peer.source_stream) {
165 		k_sem_give(&peer.source_stream_sem);
166 	} else if (IS_ARRAY_ELEMENT(peer.sink_streams, cap_stream)) {
167 		k_sem_give(&peer.sink_stream_sem);
168 	} else {
169 		__ASSERT(false, "Invalid stream: %p", cap_stream);
170 	}
171 }
172 
reset_cap_acceptor(void)173 static int reset_cap_acceptor(void)
174 {
175 	int err;
176 
177 	LOG_INF("Resetting");
178 
179 	if (peer.conn != NULL) {
180 		err = bt_conn_disconnect(peer.conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
181 		if (err != 0) {
182 			return err;
183 		}
184 
185 		err = k_sem_take(&sem_state_change, K_FOREVER);
186 		if (err != 0) {
187 			LOG_ERR("Timeout on disconnect: %d", err);
188 			return err;
189 		}
190 	}
191 
192 	if (adv != NULL) {
193 		err = bt_le_ext_adv_stop(adv);
194 		if (err != 0) {
195 			LOG_ERR("Failed to stop advertiser: %d", err);
196 			return err;
197 		}
198 
199 		err = bt_le_ext_adv_delete(adv);
200 		if (err != 0) {
201 			LOG_ERR("Failed to delete advertiser: %d", err);
202 			return err;
203 		}
204 
205 		adv = NULL;
206 	}
207 
208 	if (peer.source_stream.bap_stream.ep != NULL) {
209 		err = k_sem_take(&peer.source_stream_sem, SEM_TIMEOUT);
210 		if (err != 0) {
211 			LOG_ERR("Timeout on source_stream_sem: %d", err);
212 			return err;
213 		}
214 	}
215 
216 	ARRAY_FOR_EACH_PTR(peer.sink_streams, stream) {
217 		if (stream->bap_stream.ep != NULL) {
218 			err = k_sem_take(&peer.sink_stream_sem, SEM_TIMEOUT);
219 			if (err != 0) {
220 				LOG_ERR("Timeout on sink_stream_sem: %d", err);
221 				return err;
222 			}
223 		}
224 	}
225 
226 	k_sem_reset(&sem_state_change);
227 
228 	return 0;
229 }
230 
231 /** Register the PAC records for PACS */
register_pac(enum bt_audio_dir dir,enum bt_audio_context context,struct bt_pacs_cap * cap,enum bt_audio_location locations)232 static int register_pac(enum bt_audio_dir dir, enum bt_audio_context context,
233 			struct bt_pacs_cap *cap, enum bt_audio_location locations)
234 {
235 	int err;
236 
237 	err = bt_pacs_cap_register(dir, cap);
238 	if (err != 0) {
239 		LOG_ERR("Failed to register capabilities: %d", err);
240 
241 		return err;
242 	}
243 
244 	err = bt_pacs_set_location(dir, locations);
245 	if (err != 0) {
246 		LOG_ERR("Failed to set location: %d", err);
247 
248 		return err;
249 	}
250 
251 	err = bt_pacs_set_supported_contexts(dir, context);
252 	if (err != 0 && err != -EALREADY) {
253 		LOG_ERR("Failed to set supported contexts: %d", err);
254 
255 		return err;
256 	}
257 
258 	err = bt_pacs_set_available_contexts(dir, context);
259 	if (err != 0 && err != -EALREADY) {
260 		LOG_ERR("Failed to set available contexts: %d", err);
261 
262 		return err;
263 	}
264 
265 	return 0;
266 }
267 
init_cap_acceptor(void)268 static int init_cap_acceptor(void)
269 {
270 	const struct bt_pacs_register_param pacs_param = {
271 		.snk_pac = true,
272 		.snk_loc = true,
273 		.src_pac = true,
274 		.src_loc = true,
275 	};
276 	int err;
277 
278 	err = bt_enable(NULL);
279 	if (err != 0) {
280 		LOG_ERR("Bluetooth enable failed: %d", err);
281 
282 		return 0;
283 	}
284 
285 	LOG_INF("Bluetooth initialized");
286 
287 	err = bt_pacs_register(&pacs_param);
288 	if (err) {
289 		LOG_ERR("Could not register PACS (err %d)", err);
290 		return 0;
291 	}
292 
293 	if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
294 		static const struct bt_audio_codec_cap lc3_codec_cap_sink =
295 			BT_AUDIO_CODEC_CAP_LC3(SUPPORTED_FREQ, SUPPORTED_DURATION,
296 					       BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(2), MIN_SDU,
297 					       MAX_SDU, FRAMES_PER_SDU, SINK_CONTEXT);
298 		static struct bt_pacs_cap sink_cap = {
299 			.codec_cap = &lc3_codec_cap_sink,
300 		};
301 		int err;
302 
303 		err = register_pac(BT_AUDIO_DIR_SINK, SINK_CONTEXT, &sink_cap,
304 				   BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT);
305 		if (err != 0) {
306 			LOG_ERR("Failed to register sink capabilities: %d", err);
307 
308 			return -ENOEXEC;
309 		}
310 	}
311 
312 	if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
313 		static const struct bt_audio_codec_cap lc3_codec_cap_source =
314 			BT_AUDIO_CODEC_CAP_LC3(SUPPORTED_FREQ, SUPPORTED_DURATION,
315 					       BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1), MIN_SDU,
316 					       MAX_SDU, FRAMES_PER_SDU, SOURCE_CONTEXT);
317 		static struct bt_pacs_cap source_cap = {
318 			.codec_cap = &lc3_codec_cap_source,
319 		};
320 		int err;
321 
322 		err = register_pac(BT_AUDIO_DIR_SOURCE, SOURCE_CONTEXT, &source_cap,
323 				   BT_AUDIO_LOCATION_FRONT_CENTER);
324 		if (err != 0) {
325 			LOG_ERR("Failed to register sink capabilities: %d", err);
326 
327 			return -ENOEXEC;
328 		}
329 	}
330 
331 	return 0;
332 }
333 
main(void)334 int main(void)
335 {
336 	int err;
337 
338 	err = init_cap_acceptor();
339 	if (err != 0) {
340 		return 0;
341 	}
342 
343 	if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER)) {
344 		err = init_cap_acceptor_unicast(&peer);
345 		if (err != 0) {
346 			return 0;
347 		}
348 	}
349 
350 	if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK)) {
351 		err = init_cap_acceptor_broadcast();
352 		if (err != 0) {
353 			return 0;
354 		}
355 	}
356 
357 	LOG_INF("CAP Acceptor initialized");
358 
359 	while (true) {
360 		err = reset_cap_acceptor();
361 		if (err != 0) {
362 			LOG_ERR("Failed to reset");
363 
364 			break;
365 		}
366 
367 		/* Start advertising as a CAP Acceptor, which includes setting the required
368 		 * advertising data based on the roles we support. The Common Audio Service data is
369 		 * always advertised, as CAP Initiators and CAP Commanders will use this to identify
370 		 * our device as a CAP Acceptor.
371 		 */
372 		err = advertise();
373 		if (err != 0) {
374 			continue;
375 		}
376 
377 		/* After advertising we expect CAP Initiators to connect to us and setup streams,
378 		 * and eventually disconnect again. As a CAP Acceptor we just need to react to their
379 		 * requests and not do anything else.
380 		 */
381 
382 		/* Reset if disconnected */
383 		err = k_sem_take(&sem_state_change, K_FOREVER);
384 		if (err != 0) {
385 			LOG_ERR("Failed to take sem_state_change: err %d", err);
386 
387 			break;
388 		}
389 	}
390 
391 	return 0;
392 }
393