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