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