1 /* btp_bap.c - Bluetooth BAP Tester */
2
3 /*
4 * Copyright (c) 2023 Codecoup
5 * Copyright (c) 2024 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <stdint.h>
11 #include <stddef.h>
12 #include <errno.h>
13
14 #include <zephyr/types.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/sys/ring_buffer.h>
17 #include <zephyr/bluetooth/audio/pacs.h>
18 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
19 #include <hci_core.h>
20
21 #include <zephyr/logging/log.h>
22 #include <zephyr/sys/byteorder.h>
23 #define LOG_MODULE_NAME bttester_bap
24 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
25 #include "btp/btp.h"
26 #include "btp_bap_audio_stream.h"
27 #include "btp_bap_unicast.h"
28 #include "btp_bap_broadcast.h"
29
30 #define SUPPORTED_SINK_CONTEXT BT_AUDIO_CONTEXT_TYPE_ANY
31 #define SUPPORTED_SOURCE_CONTEXT BT_AUDIO_CONTEXT_TYPE_ANY
32
33 #define AVAILABLE_SINK_CONTEXT SUPPORTED_SINK_CONTEXT
34 #define AVAILABLE_SOURCE_CONTEXT SUPPORTED_SOURCE_CONTEXT
35
36 static const struct bt_audio_codec_cap default_codec_cap = BT_AUDIO_CODEC_CAP_LC3(
37 BT_AUDIO_CODEC_CAP_FREQ_ANY, BT_AUDIO_CODEC_CAP_DURATION_7_5 |
38 BT_AUDIO_CODEC_CAP_DURATION_10, BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 26u, 155u, 1u,
39 BT_AUDIO_CONTEXT_TYPE_ANY);
40
41 static const struct bt_audio_codec_cap vendor_codec_cap = BT_AUDIO_CODEC_CAP(
42 0xff, 0xffff, 0xffff, BT_AUDIO_CODEC_CAP_LC3_DATA(BT_AUDIO_CODEC_CAP_FREQ_ANY,
43 BT_AUDIO_CODEC_CAP_DURATION_7_5 | BT_AUDIO_CODEC_CAP_DURATION_10,
44 BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 26u, 155, 1u),
45 BT_AUDIO_CODEC_CAP_LC3_META(BT_AUDIO_CONTEXT_TYPE_ANY));
46
47 static struct bt_pacs_cap cap_sink = {
48 .codec_cap = &default_codec_cap,
49 };
50
51 static struct bt_pacs_cap cap_source = {
52 .codec_cap = &default_codec_cap,
53 };
54
55 static struct bt_pacs_cap vendor_cap_sink = {
56 .codec_cap = &vendor_codec_cap,
57 };
58
59 static struct bt_pacs_cap vendor_cap_source = {
60 .codec_cap = &vendor_codec_cap,
61 };
62
btp_ascs_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)63 static uint8_t btp_ascs_supported_commands(const void *cmd, uint16_t cmd_len,
64 void *rsp, uint16_t *rsp_len)
65 {
66 struct btp_ascs_read_supported_commands_rp *rp = rsp;
67
68 /* octet 0 */
69 tester_set_bit(rp->data, BTP_ASCS_READ_SUPPORTED_COMMANDS);
70
71 *rsp_len = sizeof(*rp) + 1;
72
73 return BTP_STATUS_SUCCESS;
74 }
75
76 static const struct btp_handler ascs_handlers[] = {
77 {
78 .opcode = BTP_ASCS_READ_SUPPORTED_COMMANDS,
79 .index = BTP_INDEX_NONE,
80 .expect_len = 0,
81 .func = btp_ascs_supported_commands,
82 },
83 {
84 .opcode = BTP_ASCS_CONFIGURE_CODEC,
85 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
86 .func = btp_ascs_configure_codec,
87 },
88 {
89 .opcode = BTP_ASCS_CONFIGURE_QOS,
90 .expect_len = sizeof(struct btp_ascs_configure_qos_cmd),
91 .func = btp_ascs_configure_qos,
92 },
93 {
94 .opcode = BTP_ASCS_ENABLE,
95 .expect_len = sizeof(struct btp_ascs_enable_cmd),
96 .func = btp_ascs_enable,
97 },
98 {
99 .opcode = BTP_ASCS_RECEIVER_START_READY,
100 .expect_len = sizeof(struct btp_ascs_receiver_start_ready_cmd),
101 .func = btp_ascs_receiver_start_ready,
102 },
103 {
104 .opcode = BTP_ASCS_RECEIVER_STOP_READY,
105 .expect_len = sizeof(struct btp_ascs_receiver_stop_ready_cmd),
106 .func = btp_ascs_receiver_stop_ready,
107 },
108 {
109 .opcode = BTP_ASCS_DISABLE,
110 .expect_len = sizeof(struct btp_ascs_disable_cmd),
111 .func = btp_ascs_disable,
112 },
113 {
114 .opcode = BTP_ASCS_RELEASE,
115 .expect_len = sizeof(struct btp_ascs_release_cmd),
116 .func = btp_ascs_release,
117 },
118 {
119 .opcode = BTP_ASCS_UPDATE_METADATA,
120 .expect_len = sizeof(struct btp_ascs_update_metadata_cmd),
121 .func = btp_ascs_update_metadata,
122 },
123 {
124 .opcode = BTP_ASCS_ADD_ASE_TO_CIS,
125 .expect_len = sizeof(struct btp_ascs_add_ase_to_cis),
126 .func = btp_ascs_add_ase_to_cis,
127 },
128 {
129 .opcode = BTP_ASCS_PRECONFIGURE_QOS,
130 .expect_len = sizeof(struct btp_ascs_preconfigure_qos_cmd),
131 .func = btp_ascs_preconfigure_qos,
132 },
133 };
134
set_location(void)135 static int set_location(void)
136 {
137 int err;
138
139 err = bt_pacs_set_location(BT_AUDIO_DIR_SINK,
140 BT_AUDIO_LOCATION_FRONT_CENTER |
141 BT_AUDIO_LOCATION_FRONT_RIGHT);
142 if (err != 0) {
143 return err;
144 }
145
146 err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE,
147 (BT_AUDIO_LOCATION_FRONT_LEFT |
148 BT_AUDIO_LOCATION_FRONT_RIGHT));
149 if (err != 0) {
150 return err;
151 }
152
153 return 0;
154 }
155
set_available_contexts(void)156 static int set_available_contexts(void)
157 {
158 int err;
159
160 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
161 AVAILABLE_SOURCE_CONTEXT);
162 if (err != 0) {
163 return err;
164 }
165
166 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK,
167 AVAILABLE_SINK_CONTEXT);
168 if (err != 0) {
169 return err;
170 }
171
172 return 0;
173 }
174
set_supported_contexts(void)175 static int set_supported_contexts(void)
176 {
177 int err;
178
179 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE,
180 SUPPORTED_SOURCE_CONTEXT);
181 if (err != 0) {
182 return err;
183 }
184
185 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK,
186 SUPPORTED_SINK_CONTEXT);
187 if (err != 0) {
188 return err;
189 }
190
191 return 0;
192 }
193
pacs_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)194 static uint8_t pacs_supported_commands(const void *cmd, uint16_t cmd_len,
195 void *rsp, uint16_t *rsp_len)
196 {
197 struct btp_pacs_read_supported_commands_rp *rp = rsp;
198
199 /* octet 0 */
200 tester_set_bit(rp->data, BTP_PACS_READ_SUPPORTED_COMMANDS);
201 tester_set_bit(rp->data, BTP_PACS_UPDATE_CHARACTERISTIC);
202 tester_set_bit(rp->data, BTP_PACS_SET_LOCATION);
203 tester_set_bit(rp->data, BTP_PACS_SET_AVAILABLE_CONTEXTS);
204 tester_set_bit(rp->data, BTP_PACS_SET_SUPPORTED_CONTEXTS);
205
206 *rsp_len = sizeof(*rp) + 1;
207
208 return BTP_STATUS_SUCCESS;
209 }
210
pacs_update_characteristic(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)211 static uint8_t pacs_update_characteristic(const void *cmd, uint16_t cmd_len,
212 void *rsp, uint16_t *rsp_len)
213 {
214 const struct btp_pacs_update_characteristic_cmd *cp = cmd;
215 int err;
216
217 switch (cp->characteristic) {
218 case BTP_PACS_CHARACTERISTIC_SINK_PAC:
219 err = bt_pacs_cap_unregister(BT_AUDIO_DIR_SINK,
220 &cap_sink);
221 break;
222 case BTP_PACS_CHARACTERISTIC_SOURCE_PAC:
223 err = bt_pacs_cap_unregister(BT_AUDIO_DIR_SOURCE,
224 &cap_source);
225 break;
226 case BTP_PACS_CHARACTERISTIC_SINK_AUDIO_LOCATIONS:
227 err = bt_pacs_set_location(BT_AUDIO_DIR_SINK,
228 BT_AUDIO_LOCATION_FRONT_CENTER |
229 BT_AUDIO_LOCATION_BACK_CENTER);
230 break;
231 case BTP_PACS_CHARACTERISTIC_SOURCE_AUDIO_LOCATIONS:
232 err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE,
233 (BT_AUDIO_LOCATION_FRONT_LEFT |
234 BT_AUDIO_LOCATION_FRONT_RIGHT |
235 BT_AUDIO_LOCATION_FRONT_CENTER));
236 break;
237 case BTP_PACS_CHARACTERISTIC_AVAILABLE_AUDIO_CONTEXTS:
238 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
239 BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
240 break;
241 case BTP_PACS_CHARACTERISTIC_SUPPORTED_AUDIO_CONTEXTS:
242 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE,
243 SUPPORTED_SOURCE_CONTEXT |
244 BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL);
245 break;
246 default:
247 return BTP_STATUS_FAILED;
248 }
249
250 return BTP_STATUS_VAL(err);
251 }
252
pacs_set_location(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)253 static uint8_t pacs_set_location(const void *cmd, uint16_t cmd_len,
254 void *rsp, uint16_t *rsp_len)
255 {
256 const struct btp_pacs_set_location_cmd *cp = cmd;
257 int err;
258
259 err = bt_pacs_set_location((enum bt_audio_dir)cp->dir,
260 (enum bt_audio_location)cp->location);
261
262 return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS;
263 }
264
pacs_set_available_contexts(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)265 static uint8_t pacs_set_available_contexts(const void *cmd, uint16_t cmd_len,
266 void *rsp, uint16_t *rsp_len)
267 {
268 const struct btp_pacs_set_available_contexts_cmd *cp = cmd;
269 int err;
270
271 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK,
272 (enum bt_audio_context)cp->sink_contexts);
273 if (err) {
274 return BTP_STATUS_FAILED;
275 }
276 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
277 (enum bt_audio_context)cp->source_contexts);
278
279 return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS;
280 }
281
pacs_set_supported_contexts(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)282 static uint8_t pacs_set_supported_contexts(const void *cmd, uint16_t cmd_len,
283 void *rsp, uint16_t *rsp_len)
284 {
285 const struct btp_pacs_set_supported_contexts_cmd *cp = cmd;
286 int err;
287
288 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK,
289 (enum bt_audio_context)cp->sink_contexts);
290 if (err) {
291 return BTP_STATUS_FAILED;
292 }
293 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE,
294 (enum bt_audio_context)cp->source_contexts);
295
296 return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS;
297 }
298
299 static const struct btp_handler pacs_handlers[] = {
300 {
301 .opcode = BTP_PACS_READ_SUPPORTED_COMMANDS,
302 .index = BTP_INDEX_NONE,
303 .expect_len = 0,
304 .func = pacs_supported_commands,
305 },
306 {
307 .opcode = BTP_PACS_UPDATE_CHARACTERISTIC,
308 .expect_len = sizeof(struct btp_pacs_update_characteristic_cmd),
309 .func = pacs_update_characteristic,
310 },
311 {
312 .opcode = BTP_PACS_SET_LOCATION,
313 .expect_len = sizeof(struct btp_pacs_set_location_cmd),
314 .func = pacs_set_location
315 },
316 {
317 .opcode = BTP_PACS_SET_AVAILABLE_CONTEXTS,
318 .expect_len = sizeof(struct btp_pacs_set_available_contexts_cmd),
319 .func = pacs_set_available_contexts
320 },
321 {
322 .opcode = BTP_PACS_SET_SUPPORTED_CONTEXTS,
323 .expect_len = sizeof(struct btp_pacs_set_supported_contexts_cmd),
324 .func = pacs_set_supported_contexts
325 }
326 };
327
btp_bap_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)328 static uint8_t btp_bap_supported_commands(const void *cmd, uint16_t cmd_len,
329 void *rsp, uint16_t *rsp_len)
330 {
331 struct btp_bap_read_supported_commands_rp *rp = rsp;
332
333 /* octet 0 */
334 tester_set_bit(rp->data, BTP_BAP_READ_SUPPORTED_COMMANDS);
335
336 *rsp_len = sizeof(*rp) + 1;
337
338 return BTP_STATUS_SUCCESS;
339 }
340
btp_bap_audio_stream_send(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)341 uint8_t btp_bap_audio_stream_send(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
342 {
343 struct btp_bap_send_rp *rp = rsp;
344 const struct btp_bap_send_cmd *cp = cmd;
345
346 /* Always send dummy success for now until the command has be deprecated
347 * https://github.com/auto-pts/auto-pts/issues/1317
348 */
349 rp->data_len = cp->data_len;
350 *rsp_len = sizeof(*rp);
351
352 return BTP_STATUS_SUCCESS;
353 }
354
355 static const struct btp_handler bap_handlers[] = {
356 {
357 .opcode = BTP_BAP_READ_SUPPORTED_COMMANDS,
358 .index = BTP_INDEX_NONE,
359 .expect_len = 0,
360 .func = btp_bap_supported_commands,
361 },
362 {
363 .opcode = BTP_BAP_DISCOVER,
364 .expect_len = sizeof(struct btp_bap_discover_cmd),
365 .func = btp_bap_discover,
366 },
367 {
368 .opcode = BTP_BAP_SEND,
369 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
370 .func = btp_bap_audio_stream_send,
371 },
372 #if defined(CONFIG_BT_BAP_BROADCAST_SINK) || defined(CONFIG_BT_BAP_BROADCAST_SINK)
373 {
374 .opcode = BTP_BAP_BROADCAST_SOURCE_SETUP,
375 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
376 .func = btp_bap_broadcast_source_setup,
377 },
378 {
379 .opcode = BTP_BAP_BROADCAST_SOURCE_RELEASE,
380 .expect_len = sizeof(struct btp_bap_broadcast_source_release_cmd),
381 .func = btp_bap_broadcast_source_release,
382 },
383 {
384 .opcode = BTP_BAP_BROADCAST_ADV_START,
385 .expect_len = sizeof(struct btp_bap_broadcast_adv_start_cmd),
386 .func = btp_bap_broadcast_adv_start,
387 },
388 {
389 .opcode = BTP_BAP_BROADCAST_ADV_STOP,
390 .expect_len = sizeof(struct btp_bap_broadcast_adv_stop_cmd),
391 .func = btp_bap_broadcast_adv_stop,
392 },
393 {
394 .opcode = BTP_BAP_BROADCAST_SOURCE_START,
395 .expect_len = sizeof(struct btp_bap_broadcast_source_start_cmd),
396 .func = btp_bap_broadcast_source_start,
397 },
398 {
399 .opcode = BTP_BAP_BROADCAST_SOURCE_STOP,
400 .expect_len = sizeof(struct btp_bap_broadcast_source_stop_cmd),
401 .func = btp_bap_broadcast_source_stop,
402 },
403 {
404 .opcode = BTP_BAP_BROADCAST_SINK_SETUP,
405 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
406 .func = btp_bap_broadcast_sink_setup,
407 },
408 {
409 .opcode = BTP_BAP_BROADCAST_SINK_RELEASE,
410 .expect_len = sizeof(struct btp_bap_broadcast_sink_release_cmd),
411 .func = btp_bap_broadcast_sink_release,
412 },
413 {
414 .opcode = BTP_BAP_BROADCAST_SCAN_START,
415 .expect_len = sizeof(struct btp_bap_broadcast_scan_start_cmd),
416 .func = btp_bap_broadcast_scan_start,
417 },
418 {
419 .opcode = BTP_BAP_BROADCAST_SCAN_STOP,
420 .expect_len = sizeof(struct btp_bap_broadcast_scan_stop_cmd),
421 .func = btp_bap_broadcast_scan_stop,
422 },
423 {
424 .opcode = BTP_BAP_BROADCAST_SINK_SYNC,
425 .expect_len = sizeof(struct btp_bap_broadcast_sink_sync_cmd),
426 .func = btp_bap_broadcast_sink_sync,
427 },
428 {
429 .opcode = BTP_BAP_BROADCAST_SINK_STOP,
430 .expect_len = sizeof(struct btp_bap_broadcast_sink_stop_cmd),
431 .func = btp_bap_broadcast_sink_stop,
432 },
433 {
434 .opcode = BTP_BAP_BROADCAST_SINK_BIS_SYNC,
435 .expect_len = sizeof(struct btp_bap_broadcast_sink_bis_sync_cmd),
436 .func = btp_bap_broadcast_sink_bis_sync,
437 },
438 {
439 .opcode = BTP_BAP_DISCOVER_SCAN_DELEGATORS,
440 .expect_len = sizeof(struct btp_bap_discover_scan_delegators_cmd),
441 .func = btp_bap_broadcast_discover_scan_delegators,
442 },
443 {
444 .opcode = BTP_BAP_BROADCAST_ASSISTANT_SCAN_START,
445 .expect_len = sizeof(struct btp_bap_broadcast_assistant_scan_start_cmd),
446 .func = btp_bap_broadcast_assistant_scan_start,
447 },
448 {
449 .opcode = BTP_BAP_BROADCAST_ASSISTANT_SCAN_STOP,
450 .expect_len = sizeof(struct btp_bap_broadcast_assistant_scan_stop_cmd),
451 .func = btp_bap_broadcast_assistant_scan_stop,
452 },
453 {
454 .opcode = BTP_BAP_ADD_BROADCAST_SRC,
455 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
456 .func = btp_bap_broadcast_assistant_add_src,
457 },
458 {
459 .opcode = BTP_BAP_REMOVE_BROADCAST_SRC,
460 .expect_len = sizeof(struct btp_bap_remove_broadcast_src_cmd),
461 .func = btp_bap_broadcast_assistant_remove_src,
462 },
463 {
464 .opcode = BTP_BAP_MODIFY_BROADCAST_SRC,
465 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
466 .func = btp_bap_broadcast_assistant_modify_src,
467 },
468 {
469 .opcode = BTP_BAP_SET_BROADCAST_CODE,
470 .expect_len = sizeof(struct btp_bap_set_broadcast_code_cmd),
471 .func = btp_bap_broadcast_assistant_set_broadcast_code,
472 },
473 {
474 .opcode = BTP_BAP_SEND_PAST,
475 .expect_len = sizeof(struct btp_bap_send_past_cmd),
476 .func = btp_bap_broadcast_assistant_send_past,
477 },
478 #endif /* CONFIG_BT_BAP_BROADCAST_SINK || CONFIG_BT_BAP_BROADCAST_SINK */
479 };
480
tester_init_pacs(void)481 uint8_t tester_init_pacs(void)
482 {
483 int err;
484
485 btp_bap_unicast_init();
486
487 bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
488 bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source);
489 bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &vendor_cap_sink);
490 bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &vendor_cap_source);
491
492 err = set_location();
493 if (err != 0) {
494 return BTP_STATUS_FAILED;
495 }
496
497 err = set_supported_contexts();
498 if (err != 0) {
499 return BTP_STATUS_FAILED;
500 }
501
502 err = set_available_contexts();
503 if (err != 0) {
504 return BTP_STATUS_FAILED;
505 }
506
507 tester_register_command_handlers(BTP_SERVICE_ID_PACS, pacs_handlers,
508 ARRAY_SIZE(pacs_handlers));
509
510 return BTP_STATUS_SUCCESS;
511 }
512
tester_unregister_pacs(void)513 uint8_t tester_unregister_pacs(void)
514 {
515 return BTP_STATUS_SUCCESS;
516 }
517
tester_init_ascs(void)518 uint8_t tester_init_ascs(void)
519 {
520 int err;
521
522 err = btp_bap_unicast_init();
523 if (err != 0) {
524 return BTP_STATUS_FAILED;
525 }
526
527 tester_register_command_handlers(BTP_SERVICE_ID_ASCS, ascs_handlers,
528 ARRAY_SIZE(ascs_handlers));
529
530 return BTP_STATUS_SUCCESS;
531 }
532
tester_unregister_ascs(void)533 uint8_t tester_unregister_ascs(void)
534 {
535 return BTP_STATUS_SUCCESS;
536 }
537
tester_init_bap(void)538 uint8_t tester_init_bap(void)
539 {
540 int err;
541
542 err = btp_bap_unicast_init();
543 if (err != 0) {
544 return BTP_STATUS_FAILED;
545 }
546
547 err = btp_bap_broadcast_init();
548 if (err != 0) {
549 return BTP_STATUS_FAILED;
550 }
551
552 btp_bap_audio_stream_tx_init();
553
554 tester_register_command_handlers(BTP_SERVICE_ID_BAP, bap_handlers,
555 ARRAY_SIZE(bap_handlers));
556
557 return BTP_STATUS_SUCCESS;
558 }
559
tester_unregister_bap(void)560 uint8_t tester_unregister_bap(void)
561 {
562 return BTP_STATUS_SUCCESS;
563 }
564