1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include <zephyr/autoconf.h>
14 #include <zephyr/bluetooth/audio/audio.h>
15 #include <zephyr/bluetooth/audio/bap.h>
16 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
17 #include <zephyr/bluetooth/audio/cap.h>
18 #include <zephyr/bluetooth/audio/csip.h>
19 #include <zephyr/bluetooth/audio/lc3.h>
20 #include <zephyr/bluetooth/audio/pacs.h>
21 #include <zephyr/bluetooth/audio/gmap.h>
22 #include <zephyr/bluetooth/bluetooth.h>
23 #include <zephyr/bluetooth/gap.h>
24 #include <zephyr/bluetooth/uuid.h>
25 #include <zephyr/sys/printk.h>
26 #include <zephyr/sys/util.h>
27 #include <zephyr/sys/util_macro.h>
28 
29 #include "bstests.h"
30 #include "common.h"
31 #include "bap_common.h"
32 
33 #if defined(CONFIG_BT_CAP_ACCEPTOR)
34 extern enum bst_result_t bst_result;
35 
36 #define CONTEXT  (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_GAME)
37 #define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT)
38 
39 static uint8_t csis_rank = 1;
40 
41 static struct bt_audio_codec_cap codec_cap =
42 	BT_AUDIO_CODEC_CAP_LC3(BT_AUDIO_CODEC_CAP_FREQ_ANY, BT_AUDIO_CODEC_CAP_DURATION_ANY,
43 			       BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, CONTEXT);
44 
45 static const struct bt_bap_qos_cfg_pref unicast_qos_pref =
46 	BT_BAP_QOS_CFG_PREF(true, BT_GAP_LE_PHY_2M, 0U, 60U, 10000U, 60000U, 10000U, 60000U);
47 
48 #define UNICAST_CHANNEL_COUNT_1 BIT(0)
49 
50 static struct bt_cap_stream
51 	unicast_streams[CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT];
52 
53 CREATE_FLAG(flag_unicast_stream_started);
54 CREATE_FLAG(flag_gmap_discovered);
55 
unicast_stream_enabled_cb(struct bt_bap_stream * stream)56 static void unicast_stream_enabled_cb(struct bt_bap_stream *stream)
57 {
58 	struct bt_bap_ep_info ep_info;
59 	int err;
60 
61 	printk("Enabled: stream %p\n", stream);
62 
63 	err = bt_bap_ep_get_info(stream->ep, &ep_info);
64 	if (err != 0) {
65 		FAIL("Failed to get ep info: %d\n", err);
66 		return;
67 	}
68 
69 	if (ep_info.dir == BT_AUDIO_DIR_SINK) {
70 		/* Automatically do the receiver start ready operation */
71 		err = bt_bap_stream_start(stream);
72 
73 		if (err != 0) {
74 			FAIL("Failed to start stream: %d\n", err);
75 			return;
76 		}
77 	}
78 }
79 
unicast_stream_started_cb(struct bt_bap_stream * stream)80 static void unicast_stream_started_cb(struct bt_bap_stream *stream)
81 {
82 	printk("Started: stream %p\n", stream);
83 	SET_FLAG(flag_unicast_stream_started);
84 }
85 
86 static struct bt_bap_stream_ops unicast_stream_ops = {
87 	.enabled = unicast_stream_enabled_cb,
88 	.started = unicast_stream_started_cb,
89 };
90 
91 /* TODO: Expand with GMAP service data */
92 static const struct bt_data gmap_acceptor_ad[] = {
93 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
94 	BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_CAS_VAL)),
95 };
96 
97 static struct bt_csip_set_member_svc_inst *csip_set_member;
98 
unicast_stream_alloc(void)99 static struct bt_bap_stream *unicast_stream_alloc(void)
100 {
101 	for (size_t i = 0; i < ARRAY_SIZE(unicast_streams); i++) {
102 		struct bt_bap_stream *stream = &unicast_streams[i].bap_stream;
103 
104 		if (!stream->conn) {
105 			return stream;
106 		}
107 	}
108 
109 	return NULL;
110 }
111 
unicast_server_config(struct bt_conn * conn,const struct bt_bap_ep * ep,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_stream ** stream,struct bt_bap_qos_cfg_pref * const pref,struct bt_bap_ascs_rsp * rsp)112 static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *ep,
113 				 enum bt_audio_dir dir, const struct bt_audio_codec_cfg *codec_cfg,
114 				 struct bt_bap_stream **stream,
115 				 struct bt_bap_qos_cfg_pref *const pref,
116 				 struct bt_bap_ascs_rsp *rsp)
117 {
118 	printk("ASE Codec Config: conn %p ep %p dir %u\n", conn, ep, dir);
119 
120 	print_codec_cfg(codec_cfg);
121 
122 	*stream = unicast_stream_alloc();
123 	if (*stream == NULL) {
124 		printk("No streams available\n");
125 		*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
126 
127 		return -ENOMEM;
128 	}
129 
130 	printk("ASE Codec Config stream %p\n", *stream);
131 
132 	*pref = unicast_qos_pref;
133 
134 	return 0;
135 }
136 
unicast_server_reconfig(struct bt_bap_stream * stream,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_qos_cfg_pref * const pref,struct bt_bap_ascs_rsp * rsp)137 static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
138 				   const struct bt_audio_codec_cfg *codec_cfg,
139 				   struct bt_bap_qos_cfg_pref *const pref,
140 				   struct bt_bap_ascs_rsp *rsp)
141 {
142 	printk("ASE Codec Reconfig: stream %p\n", stream);
143 
144 	print_codec_cfg(codec_cfg);
145 
146 	*pref = unicast_qos_pref;
147 
148 	*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE);
149 
150 	/* We only support one QoS at the moment, reject changes */
151 	return -ENOEXEC;
152 }
153 
unicast_server_qos(struct bt_bap_stream * stream,const struct bt_bap_qos_cfg * qos,struct bt_bap_ascs_rsp * rsp)154 static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg *qos,
155 			      struct bt_bap_ascs_rsp *rsp)
156 {
157 	printk("QoS: stream %p qos %p\n", stream, qos);
158 
159 	print_qos(qos);
160 
161 	return 0;
162 }
163 
data_func_cb(struct bt_data * data,void * user_data)164 static bool data_func_cb(struct bt_data *data, void *user_data)
165 {
166 	struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
167 
168 	if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
169 		printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
170 		*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
171 
172 		return -EINVAL;
173 	}
174 
175 	return true;
176 }
177 
unicast_server_enable(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)178 static int unicast_server_enable(struct bt_bap_stream *stream, const uint8_t meta[],
179 				 size_t meta_len, struct bt_bap_ascs_rsp *rsp)
180 {
181 	printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
182 
183 	return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
184 }
185 
unicast_server_start(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)186 static int unicast_server_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
187 {
188 	printk("Start: stream %p\n", stream);
189 
190 	return 0;
191 }
192 
unicast_server_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)193 static int unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
194 				   size_t meta_len, struct bt_bap_ascs_rsp *rsp)
195 {
196 	printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
197 
198 	return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
199 }
200 
unicast_server_disable(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)201 static int unicast_server_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
202 {
203 	printk("Disable: stream %p\n", stream);
204 
205 	return 0;
206 }
207 
unicast_server_stop(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)208 static int unicast_server_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
209 {
210 	printk("Stop: stream %p\n", stream);
211 
212 	return 0;
213 }
214 
unicast_server_release(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)215 static int unicast_server_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
216 {
217 	printk("Release: stream %p\n", stream);
218 
219 	return 0;
220 }
221 
222 static struct bt_bap_unicast_server_register_param param = {
223 	CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT,
224 	CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT
225 };
226 
227 static struct bt_bap_unicast_server_cb unicast_server_cbs = {
228 	.config = unicast_server_config,
229 	.reconfig = unicast_server_reconfig,
230 	.qos = unicast_server_qos,
231 	.enable = unicast_server_enable,
232 	.start = unicast_server_start,
233 	.metadata = unicast_server_metadata,
234 	.disable = unicast_server_disable,
235 	.stop = unicast_server_stop,
236 	.release = unicast_server_release,
237 };
238 
set_location(void)239 static void set_location(void)
240 {
241 	int err;
242 
243 	if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) {
244 		err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, LOCATION);
245 		if (err != 0) {
246 			FAIL("Failed to set sink location (err %d)\n", err);
247 			return;
248 		}
249 	}
250 
251 	if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) {
252 		err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, LOCATION);
253 		if (err != 0) {
254 			FAIL("Failed to set source location (err %d)\n", err);
255 			return;
256 		}
257 	}
258 
259 	printk("Location successfully set\n");
260 }
261 
set_supported_contexts(void)262 static int set_supported_contexts(void)
263 {
264 	int err;
265 
266 	if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
267 		err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, CONTEXT);
268 		if (err != 0) {
269 			printk("Failed to set sink supported contexts (err %d)\n", err);
270 
271 			return err;
272 		}
273 	}
274 
275 	if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
276 		err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE, CONTEXT);
277 		if (err != 0) {
278 			printk("Failed to set source supported contexts (err %d)\n", err);
279 
280 			return err;
281 		}
282 	}
283 
284 	printk("Supported contexts successfully set\n");
285 
286 	return 0;
287 }
288 
set_available_contexts(void)289 static void set_available_contexts(void)
290 {
291 	int err;
292 
293 	err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, CONTEXT);
294 	if (IS_ENABLED(CONFIG_BT_PAC_SNK) && err != 0) {
295 		FAIL("Failed to set sink available contexts (err %d)\n", err);
296 		return;
297 	}
298 
299 	err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE, CONTEXT);
300 	if (IS_ENABLED(CONFIG_BT_PAC_SRC) && err != 0) {
301 		FAIL("Failed to set source available contexts (err %d)\n", err);
302 		return;
303 	}
304 
305 	printk("Available contexts successfully set\n");
306 }
307 
gmap_discover_cb(struct bt_conn * conn,int err,enum bt_gmap_role role,struct bt_gmap_feat features)308 static void gmap_discover_cb(struct bt_conn *conn, int err, enum bt_gmap_role role,
309 			     struct bt_gmap_feat features)
310 {
311 	enum bt_gmap_ugg_feat ugg_feat;
312 
313 	if (err != 0) {
314 		FAIL("GMAP discovery (err %d)\n", err);
315 		return;
316 	}
317 
318 	printk("GMAP discovered for conn %p:\n\trole 0x%02x\n\tugg_feat 0x%02x\n\tugt_feat "
319 	       "0x%02x\n\tbgs_feat 0x%02x\n\tbgr_feat 0x%02x\n",
320 	       conn, role, features.ugg_feat, features.ugt_feat, features.bgs_feat,
321 	       features.bgr_feat);
322 
323 	if ((role & BT_GMAP_ROLE_UGG) == 0) {
324 		FAIL("Remote GMAP device is not a UGG\n");
325 		return;
326 	}
327 
328 	ugg_feat = features.ugg_feat;
329 	if ((ugg_feat & BT_GMAP_UGG_FEAT_MULTIPLEX) == 0 ||
330 	    (ugg_feat & BT_GMAP_UGG_FEAT_96KBPS_SOURCE) == 0 ||
331 	    (ugg_feat & BT_GMAP_UGG_FEAT_MULTISINK) == 0) {
332 		FAIL("Remote GMAP device does not have expected UGG features: %d\n", ugg_feat);
333 		return;
334 	}
335 
336 	SET_FLAG(flag_gmap_discovered);
337 }
338 
339 static const struct bt_gmap_cb gmap_cb = {
340 	.discover = gmap_discover_cb,
341 };
342 
discover_gmas(struct bt_conn * conn)343 static void discover_gmas(struct bt_conn *conn)
344 {
345 	int err;
346 
347 	UNSET_FLAG(flag_gmap_discovered);
348 
349 	err = bt_gmap_discover(conn);
350 	if (err != 0) {
351 		printk("Failed to discover GMAS: %d\n", err);
352 		return;
353 	}
354 
355 	WAIT_FOR_FLAG(flag_gmap_discovered);
356 }
357 
test_main(void)358 static void test_main(void)
359 {
360 	/* TODO: Register all GMAP codec capabilities */
361 	const enum bt_gmap_role role = BT_GMAP_ROLE_UGT;
362 	const struct bt_gmap_feat features = {
363 		.ugt_feat = (BT_GMAP_UGT_FEAT_SOURCE | BT_GMAP_UGT_FEAT_80KBPS_SOURCE |
364 			     BT_GMAP_UGT_FEAT_SINK | BT_GMAP_UGT_FEAT_64KBPS_SINK |
365 			     BT_GMAP_UGT_FEAT_MULTIPLEX | BT_GMAP_UGT_FEAT_MULTISINK |
366 			     BT_GMAP_UGT_FEAT_MULTISOURCE),
367 	};
368 	static struct bt_pacs_cap unicast_cap = {
369 		.codec_cap = &codec_cap,
370 	};
371 	int err;
372 
373 	err = bt_enable(NULL);
374 	if (err != 0) {
375 		FAIL("Bluetooth enable failed (err %d)\n", err);
376 		return;
377 	}
378 
379 	printk("Bluetooth initialized\n");
380 
381 	if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) {
382 		const struct bt_csip_set_member_register_param csip_set_member_param = {
383 			.set_size = 2,
384 			.rank = csis_rank,
385 			.lockable = true,
386 			/* Using the CSIP_SET_MEMBER test sample SIRK */
387 			.sirk = { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce,
388 				  0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 },
389 		};
390 
391 		err = bt_cap_acceptor_register(&csip_set_member_param, &csip_set_member);
392 		if (err != 0) {
393 			FAIL("CAP acceptor failed to register (err %d)\n", err);
394 			return;
395 		}
396 	}
397 
398 	err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &unicast_cap);
399 	if (err != 0) {
400 		FAIL("Capability register failed (err %d)\n", err);
401 
402 		return;
403 	}
404 
405 	err = bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &unicast_cap);
406 	if (err != 0) {
407 		FAIL("Capability register failed (err %d)\n", err);
408 
409 		return;
410 	}
411 
412 	err = bt_bap_unicast_server_register(&param);
413 	if (err != 0) {
414 		FAIL("Failed to register unicast server (err %d)\n", err);
415 
416 		return;
417 	}
418 
419 	err = bt_bap_unicast_server_register_cb(&unicast_server_cbs);
420 	if (err != 0) {
421 		FAIL("Failed to register unicast server callbacks (err %d)\n", err);
422 
423 		return;
424 	}
425 
426 	for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
427 		bt_cap_stream_ops_register(&unicast_streams[i], &unicast_stream_ops);
428 	}
429 
430 	set_supported_contexts();
431 	set_available_contexts();
432 	set_location();
433 
434 	err = bt_gmap_register(role, features);
435 	if (err != 0) {
436 		FAIL("Failed to register GMAS (err %d)\n", err);
437 
438 		return;
439 	}
440 
441 	err = bt_gmap_cb_register(&gmap_cb);
442 	if (err != 0) {
443 		FAIL("Failed to register callbacks (err %d)\n", err);
444 
445 		return;
446 	}
447 
448 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, gmap_acceptor_ad, ARRAY_SIZE(gmap_acceptor_ad),
449 			      NULL, 0);
450 	if (err != 0) {
451 		FAIL("Advertising failed to start (err %d)\n", err);
452 		return;
453 	}
454 
455 	WAIT_FOR_FLAG(flag_connected);
456 
457 	discover_gmas(default_conn);
458 	discover_gmas(default_conn); /* test that we can discover twice */
459 
460 	WAIT_FOR_FLAG(flag_disconnected);
461 
462 	PASS("GMAP UGT passed\n");
463 }
464 
test_args(int argc,char * argv[])465 static void test_args(int argc, char *argv[])
466 {
467 	for (size_t argn = 0; argn < argc; argn++) {
468 		const char *arg = argv[argn];
469 
470 		if (strcmp(arg, "rank") == 0) {
471 			csis_rank = strtoul(argv[++argn], NULL, 10);
472 		} else {
473 			FAIL("Invalid arg: %s\n", arg);
474 		}
475 	}
476 }
477 
478 static const struct bst_test_instance test_gmap_ugt[] = {
479 	{
480 		.test_id = "gmap_ugt",
481 		.test_pre_init_f = test_init,
482 		.test_tick_f = test_tick,
483 		.test_main_f = test_main,
484 		.test_args_f = test_args,
485 	},
486 	BSTEST_END_MARKER,
487 };
488 
test_gmap_ugt_install(struct bst_test_list * tests)489 struct bst_test_list *test_gmap_ugt_install(struct bst_test_list *tests)
490 {
491 	return bst_add_tests(tests, test_gmap_ugt);
492 }
493 
494 #else /* !(CONFIG_BT_CAP_ACCEPTOR) */
495 
test_gmap_ugt_install(struct bst_test_list * tests)496 struct bst_test_list *test_gmap_ugt_install(struct bst_test_list *tests)
497 {
498 	return tests;
499 }
500 
501 #endif /* CONFIG_BT_CAP_ACCEPTOR */
502