1 /* btp_cap.c - Bluetooth CAP Tester */
2
3 /*
4 * Copyright (c) 2023 Codecoup
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8 #include <errno.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12
13 #include <zephyr/autoconf.h>
14 #include <zephyr/bluetooth/addr.h>
15 #include <zephyr/bluetooth/audio/audio.h>
16 #include <zephyr/bluetooth/audio/bap.h>
17 #include <zephyr/bluetooth/audio/cap.h>
18 #include <zephyr/bluetooth/audio/csip.h>
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/conn.h>
21 #include <zephyr/bluetooth/gap.h>
22 #include <zephyr/bluetooth/iso.h>
23 #include <zephyr/bluetooth/uuid.h>
24 #include <zephyr/kernel.h>
25 #include <zephyr/logging/log.h>
26 #include <zephyr/net_buf.h>
27 #include <zephyr/sys/byteorder.h>
28 #include <zephyr/sys/util.h>
29 #include <zephyr/sys/util_macro.h>
30
31 #include "btp/btp.h"
32 #include "btp_bap_audio_stream.h"
33 #include "bap_endpoint.h"
34
35 #include "btp_bap_unicast.h"
36 #include "btp_bap_broadcast.h"
37
38 #define LOG_MODULE_NAME bttester_cap
39 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
40
41 static struct btp_bap_unicast_group *u_group;
42
43 static K_SEM_DEFINE(source_stopped_sem, 0U, CONFIG_BT_BAP_BROADCAST_SRC_COUNT);
44
45 struct cap_initiator_broadcast_params {
46 struct bt_cap_initiator_broadcast_subgroup_param
47 cap_subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
48 struct bt_cap_initiator_broadcast_stream_param
49 cap_stream_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT]
50 [CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
51 };
52
53 static struct cap_initiator_broadcast_params
54 cap_broadcast_params[CONFIG_BT_BAP_BROADCAST_SRC_COUNT];
55
56
57 extern struct bt_csip_set_coordinator_set_member *btp_csip_set_members[CONFIG_BT_MAX_CONN];
58
stream_unicast_to_bap(struct btp_bap_unicast_stream * stream)59 static struct bt_bap_stream *stream_unicast_to_bap(struct btp_bap_unicast_stream *stream)
60 {
61 return &stream->audio_stream.cap_stream.bap_stream;
62 }
63
stream_unicast_to_cap(struct btp_bap_unicast_stream * stream)64 static struct bt_cap_stream *stream_unicast_to_cap(struct btp_bap_unicast_stream *stream)
65 {
66 return &stream->audio_stream.cap_stream;
67 }
68
stream_broadcast_to_cap(struct btp_bap_broadcast_stream * stream)69 static struct bt_cap_stream *stream_broadcast_to_cap(struct btp_bap_broadcast_stream *stream)
70 {
71 return &stream->audio_stream.cap_stream;
72 }
73
btp_send_discovery_completed_ev(struct bt_conn * conn,uint8_t status)74 static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status)
75 {
76 struct btp_cap_discovery_completed_ev ev;
77
78 bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
79 ev.status = status;
80
81 tester_event(BTP_SERVICE_ID_CAP, BTP_CAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev));
82 }
83
cap_discovery_complete_cb(struct bt_conn * conn,int err,const struct bt_csip_set_coordinator_set_member * member,const struct bt_csip_set_coordinator_csis_inst * csis_inst)84 static void cap_discovery_complete_cb(struct bt_conn *conn, int err,
85 const struct bt_csip_set_coordinator_set_member *member,
86 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
87 {
88 LOG_DBG("");
89
90 if (err != 0) {
91 LOG_DBG("Failed to discover CAS: %d", err);
92 btp_send_discovery_completed_ev(conn, BTP_CAP_DISCOVERY_STATUS_FAILED);
93
94 return;
95 }
96
97 if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) {
98 if (csis_inst == NULL) {
99 LOG_DBG("Failed to discover CAS CSIS");
100 btp_send_discovery_completed_ev(conn, BTP_CAP_DISCOVERY_STATUS_FAILED);
101
102 return;
103 }
104
105 LOG_DBG("Found CAS with CSIS %p", csis_inst);
106 } else {
107 LOG_DBG("Found CAS");
108 }
109
110 btp_send_discovery_completed_ev(conn, BTP_CAP_DISCOVERY_STATUS_SUCCESS);
111 }
112
btp_send_cap_unicast_start_completed_ev(uint8_t cig_id,uint8_t status)113 static void btp_send_cap_unicast_start_completed_ev(uint8_t cig_id, uint8_t status)
114 {
115 struct btp_cap_unicast_start_completed_ev ev;
116
117 ev.cig_id = cig_id;
118 ev.status = status;
119
120 tester_event(BTP_SERVICE_ID_CAP, BTP_CAP_EV_UNICAST_START_COMPLETED, &ev, sizeof(ev));
121 }
122
btp_send_cap_unicast_stop_completed_ev(uint8_t cig_id,uint8_t status)123 static void btp_send_cap_unicast_stop_completed_ev(uint8_t cig_id, uint8_t status)
124 {
125 struct btp_cap_unicast_stop_completed_ev ev;
126
127 ev.cig_id = cig_id;
128 ev.status = status;
129
130 tester_event(BTP_SERVICE_ID_CAP, BTP_CAP_EV_UNICAST_STOP_COMPLETED, &ev, sizeof(ev));
131 }
132
unicast_start_complete_cb(int err,struct bt_conn * conn)133 static void unicast_start_complete_cb(int err, struct bt_conn *conn)
134 {
135 LOG_DBG("");
136
137 if (err != 0) {
138 LOG_DBG("Failed to unicast-start, err %d", err);
139 btp_send_cap_unicast_start_completed_ev(u_group->cig_id,
140 BTP_CAP_UNICAST_START_STATUS_FAILED);
141
142 return;
143 }
144
145 btp_send_cap_unicast_start_completed_ev(u_group->cig_id,
146 BTP_CAP_UNICAST_START_STATUS_SUCCESS);
147 }
148
unicast_update_complete_cb(int err,struct bt_conn * conn)149 static void unicast_update_complete_cb(int err, struct bt_conn *conn)
150 {
151 LOG_DBG("");
152
153 if (err != 0) {
154 LOG_DBG("Failed to unicast-update, err %d", err);
155 }
156 }
157
unicast_stop_complete_cb(int err,struct bt_conn * conn)158 static void unicast_stop_complete_cb(int err, struct bt_conn *conn)
159 {
160 LOG_DBG("");
161
162 if (err != 0) {
163 LOG_DBG("Failed to unicast-stop, err %d", err);
164 btp_send_cap_unicast_stop_completed_ev(u_group->cig_id,
165 BTP_CAP_UNICAST_START_STATUS_FAILED);
166
167 return;
168 }
169
170 btp_send_cap_unicast_stop_completed_ev(u_group->cig_id,
171 BTP_CAP_UNICAST_START_STATUS_SUCCESS);
172 }
173
broadcast_stopped_cb(struct bt_cap_broadcast_source * source,uint8_t reason)174 static void broadcast_stopped_cb(struct bt_cap_broadcast_source *source, uint8_t reason)
175 {
176 LOG_DBG("");
177
178 k_sem_give(&source_stopped_sem);
179 }
180
181 static struct bt_cap_initiator_cb cap_cb = {
182 .unicast_discovery_complete = cap_discovery_complete_cb,
183 .unicast_start_complete = unicast_start_complete_cb,
184 .unicast_update_complete = unicast_update_complete_cb,
185 .unicast_stop_complete = unicast_stop_complete_cb,
186 .broadcast_stopped = broadcast_stopped_cb,
187 };
188
btp_cap_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)189 static uint8_t btp_cap_supported_commands(const void *cmd, uint16_t cmd_len,
190 void *rsp, uint16_t *rsp_len)
191 {
192 struct btp_cap_read_supported_commands_rp *rp = rsp;
193
194 *rsp_len = tester_supported_commands(BTP_SERVICE_ID_CAP, rp->data);
195 *rsp_len += sizeof(*rp);
196
197 return BTP_STATUS_SUCCESS;
198 }
199
btp_cap_discover(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)200 static uint8_t btp_cap_discover(const void *cmd, uint16_t cmd_len,
201 void *rsp, uint16_t *rsp_len)
202 {
203 const struct btp_cap_discover_cmd *cp = cmd;
204 struct bt_conn *conn;
205 int err;
206
207 LOG_DBG("");
208
209 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
210 if (!conn) {
211 LOG_ERR("Unknown connection");
212 return BTP_STATUS_FAILED;
213 }
214
215 err = bt_cap_initiator_unicast_discover(conn);
216 if (err != 0) {
217 LOG_DBG("Failed to discover remote ASEs: %d", err);
218 bt_conn_unref(conn);
219
220 return BTP_STATUS_FAILED;
221 }
222
223 bt_conn_unref(conn);
224
225 return BTP_STATUS_SUCCESS;
226 }
227
cap_unicast_setup_ase(struct bt_conn * conn,uint8_t ase_id,uint8_t cis_id,uint8_t cig_id,struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_qos_cfg * qos)228 static int cap_unicast_setup_ase(struct bt_conn *conn, uint8_t ase_id, uint8_t cis_id,
229 uint8_t cig_id, struct bt_audio_codec_cfg *codec_cfg,
230 struct bt_bap_qos_cfg *qos)
231 {
232 struct btp_bap_unicast_group *group;
233 struct btp_bap_unicast_stream *u_stream;
234 struct bt_bap_stream *stream;
235 struct btp_bap_unicast_connection *u_conn = btp_bap_unicast_conn_get(bt_conn_index(conn));
236
237 u_stream = btp_bap_unicast_stream_find(u_conn, ase_id);
238 if (u_stream == NULL) {
239 /* Configure a new u_stream */
240 u_stream = btp_bap_unicast_stream_alloc(u_conn);
241 if (u_stream == NULL) {
242 LOG_DBG("No streams available");
243
244 return -ENOMEM;
245 }
246 }
247
248 stream = stream_unicast_to_bap(u_stream);
249 bt_cap_stream_ops_register(&u_stream->audio_stream.cap_stream, stream->ops);
250
251 u_stream->conn_id = bt_conn_index(conn);
252 u_stream->ase_id = ase_id;
253 u_stream->cig_id = cig_id;
254 u_stream->cis_id = cis_id;
255 memcpy(&u_stream->codec_cfg, codec_cfg, sizeof(*codec_cfg));
256
257 group = btp_bap_unicast_group_find(cig_id);
258 if (group == NULL) {
259 return -EINVAL;
260 }
261
262 memcpy(&group->qos[cis_id], qos, sizeof(*qos));
263
264 return 0;
265 }
266
btp_cap_unicast_setup_ase(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)267 static uint8_t btp_cap_unicast_setup_ase(const void *cmd, uint16_t cmd_len,
268 void *rsp, uint16_t *rsp_len)
269 {
270 const struct btp_cap_unicast_setup_ase_cmd *cp = cmd;
271 struct bt_audio_codec_cfg codec_cfg;
272 struct bt_bap_qos_cfg qos;
273 struct bt_conn *conn;
274 const uint8_t *ltv_ptr;
275 int err;
276
277 LOG_DBG("");
278
279 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
280 if (!conn) {
281 LOG_ERR("Unknown connection");
282
283 return BTP_STATUS_FAILED;
284 }
285
286 memset(&qos, 0, sizeof(qos));
287 qos.phy = BT_BAP_QOS_CFG_2M;
288 qos.framing = cp->framing;
289 qos.rtn = cp->retransmission_num;
290 qos.sdu = sys_le16_to_cpu(cp->max_sdu);
291 qos.latency = sys_le16_to_cpu(cp->max_transport_latency);
292 qos.interval = sys_get_le24(cp->sdu_interval);
293 qos.pd = sys_get_le24(cp->presentation_delay);
294
295 memset(&codec_cfg, 0, sizeof(codec_cfg));
296 codec_cfg.target_latency = BT_AUDIO_CODEC_CFG_TARGET_LATENCY_BALANCED;
297 codec_cfg.target_phy = BT_AUDIO_CODEC_CFG_TARGET_PHY_2M;
298 codec_cfg.id = cp->coding_format;
299 codec_cfg.vid = cp->vid;
300 codec_cfg.cid = cp->cid;
301
302 ltv_ptr = cp->ltvs;
303 if (cp->cc_ltvs_len != 0) {
304 codec_cfg.data_len = cp->cc_ltvs_len;
305 memcpy(codec_cfg.data, ltv_ptr, cp->cc_ltvs_len);
306 ltv_ptr += cp->cc_ltvs_len;
307 }
308
309 if (cp->metadata_ltvs_len != 0) {
310 codec_cfg.meta_len = cp->metadata_ltvs_len;
311 memcpy(codec_cfg.meta, ltv_ptr, cp->metadata_ltvs_len);
312 }
313
314 err = cap_unicast_setup_ase(conn, cp->ase_id, cp->cis_id, cp->cig_id, &codec_cfg, &qos);
315 bt_conn_unref(conn);
316
317 return BTP_STATUS_VAL(err);
318 }
319
btp_cap_unicast_audio_start(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)320 static uint8_t btp_cap_unicast_audio_start(const void *cmd, uint16_t cmd_len,
321 void *rsp, uint16_t *rsp_len)
322 {
323 int err;
324 size_t stream_count = 0;
325 const struct btp_cap_unicast_audio_start_cmd *cp = cmd;
326 struct bt_cap_unicast_audio_start_param start_param;
327 struct bt_cap_unicast_audio_start_stream_param stream_params[
328 ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT];
329
330 LOG_DBG("");
331
332 err = btp_bap_unicast_group_create(cp->cig_id, &u_group);
333 if (err != 0) {
334 LOG_ERR("Failed to create unicast group");
335
336 return BTP_STATUS_FAILED;
337 }
338
339 for (size_t conn_index = 0; conn_index < ARRAY_SIZE(btp_csip_set_members); conn_index++) {
340 struct btp_bap_unicast_connection *u_conn = btp_bap_unicast_conn_get(conn_index);
341
342 if (u_conn->end_points_count == 0) {
343 /* Connection not initialized */
344 continue;
345 }
346
347 for (size_t i = 0; i < ARRAY_SIZE(u_conn->streams); i++) {
348 struct bt_cap_unicast_audio_start_stream_param *stream_param;
349 struct btp_bap_unicast_stream *u_stream = &u_conn->streams[i];
350
351 if (!u_stream->in_use || u_stream->cig_id != cp->cig_id) {
352 continue;
353 }
354
355 stream_param = &stream_params[stream_count++];
356 stream_param->stream = stream_unicast_to_cap(u_stream);
357 stream_param->codec_cfg = &u_stream->codec_cfg;
358 stream_param->member.member = bt_conn_lookup_addr_le(BT_ID_DEFAULT,
359 &u_conn->address);
360 stream_param->ep = btp_bap_unicast_end_point_find(u_conn, u_stream->ase_id);
361 }
362 }
363
364 start_param.type = cp->set_type;
365 start_param.count = stream_count;
366 start_param.stream_params = stream_params;
367
368 err = bt_cap_initiator_unicast_audio_start(&start_param);
369 if (err != 0) {
370 LOG_ERR("Failed to start unicast audio: %d", err);
371
372 return BTP_STATUS_FAILED;
373 }
374
375 return BTP_STATUS_SUCCESS;
376 }
377
btp_cap_unicast_audio_update(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)378 static uint8_t btp_cap_unicast_audio_update(const void *cmd, uint16_t cmd_len,
379 void *rsp, uint16_t *rsp_len)
380 {
381 int err;
382 const uint8_t *data_ptr;
383 const struct btp_cap_unicast_audio_update_cmd *cp = cmd;
384 struct bt_cap_unicast_audio_update_stream_param
385 stream_params[ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT];
386 struct bt_cap_unicast_audio_update_param param = {0};
387
388 LOG_DBG("");
389
390 if (cp->stream_count == 0) {
391 return BTP_STATUS_FAILED;
392 }
393
394 data_ptr = cp->update_data;
395 for (size_t i = 0; i < cp->stream_count; i++) {
396 struct btp_bap_unicast_connection *u_conn;
397 struct btp_bap_unicast_stream *u_stream;
398 struct bt_conn *conn;
399 struct btp_cap_unicast_audio_update_data *update_data =
400 (struct btp_cap_unicast_audio_update_data *)data_ptr;
401 struct bt_cap_unicast_audio_update_stream_param *stream_param = &stream_params[i];
402
403 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &update_data->address);
404 if (!conn) {
405 LOG_ERR("Unknown connection");
406
407 return BTP_STATUS_FAILED;
408 }
409
410 u_conn = btp_bap_unicast_conn_get(bt_conn_index(conn));
411 bt_conn_unref(conn);
412 if (u_conn->end_points_count == 0) {
413 /* Connection not initialized */
414
415 return BTP_STATUS_FAILED;
416 }
417
418 u_stream = btp_bap_unicast_stream_find(u_conn, update_data->ase_id);
419 if (u_stream == NULL) {
420 return BTP_STATUS_FAILED;
421 }
422
423 stream_param->stream = &u_stream->audio_stream.cap_stream;
424 stream_param->meta_len = update_data->metadata_ltvs_len;
425 stream_param->meta = update_data->metadata_ltvs;
426
427 data_ptr = ((uint8_t *)update_data) + stream_param->meta_len +
428 sizeof(struct btp_cap_unicast_audio_update_data);
429 }
430
431 param.count = cp->stream_count;
432 param.stream_params = stream_params;
433 param.type = BT_CAP_SET_TYPE_AD_HOC;
434
435 err = bt_cap_initiator_unicast_audio_update(¶m);
436 if (err != 0) {
437 LOG_ERR("Failed to start unicast audio: %d", err);
438
439 return BTP_STATUS_FAILED;
440 }
441
442 return BTP_STATUS_SUCCESS;
443 }
444
btp_cap_unicast_audio_stop(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)445 static uint8_t btp_cap_unicast_audio_stop(const void *cmd, uint16_t cmd_len,
446 void *rsp, uint16_t *rsp_len)
447 {
448 struct bt_cap_stream
449 *streams[ARRAY_SIZE(btp_csip_set_members) * BTP_BAP_UNICAST_MAX_STREAMS_COUNT];
450 struct bt_cap_unicast_audio_stop_param param = {0};
451 int err;
452 const struct btp_cap_unicast_audio_stop_cmd *cp = cmd;
453 size_t stream_cnt = 0U;
454
455 LOG_DBG("");
456
457 /* Get generate the same stream list as used by btp_cap_unicast_audio_start */
458 for (size_t conn_index = 0; conn_index < ARRAY_SIZE(btp_csip_set_members); conn_index++) {
459 struct btp_bap_unicast_connection *u_conn = btp_bap_unicast_conn_get(conn_index);
460
461 if (u_conn->end_points_count == 0) {
462 /* Connection not initialized */
463 continue;
464 }
465
466 for (size_t i = 0; i < ARRAY_SIZE(u_conn->streams); i++) {
467 struct btp_bap_unicast_stream *u_stream = &u_conn->streams[i];
468
469 if (!u_stream->in_use || u_stream->cig_id != cp->cig_id) {
470 continue;
471 }
472
473 streams[stream_cnt++] = stream_unicast_to_cap(u_stream);
474 }
475 }
476
477 param.streams = streams;
478 param.count = stream_cnt;
479 param.type = BT_CAP_SET_TYPE_AD_HOC;
480 param.release = (cp->flags & BTP_CAP_UNICAST_AUDIO_STOP_FLAG_RELEASE) != 0;
481
482 err = bt_cap_initiator_unicast_audio_stop(¶m);
483 if (err != 0) {
484 LOG_ERR("Failed to start unicast audio: %d", err);
485
486 return BTP_STATUS_FAILED;
487 }
488
489 return BTP_STATUS_SUCCESS;
490 }
491
btp_cap_broadcast_source_setup_stream(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)492 static uint8_t btp_cap_broadcast_source_setup_stream(const void *cmd, uint16_t cmd_len,
493 void *rsp, uint16_t *rsp_len)
494 {
495 const uint8_t *ltv_ptr;
496 struct btp_bap_broadcast_stream *stream;
497 const struct btp_cap_broadcast_source_setup_stream_cmd *cp = cmd;
498 struct btp_bap_broadcast_local_source *source =
499 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
500
501 if (source == NULL) {
502 return BTP_STATUS_FAILED;
503 }
504
505 struct bt_audio_codec_cfg *codec_cfg;
506
507 stream = btp_bap_broadcast_stream_alloc(source);
508 if (stream == NULL) {
509 return BTP_STATUS_FAILED;
510 }
511
512 stream->subgroup_id = cp->subgroup_id;
513 codec_cfg = &stream->codec_cfg;
514 memset(codec_cfg, 0, sizeof(*codec_cfg));
515 codec_cfg->id = cp->coding_format;
516 codec_cfg->vid = cp->vid;
517 codec_cfg->cid = cp->cid;
518
519 ltv_ptr = cp->ltvs;
520 if (cp->cc_ltvs_len != 0) {
521 codec_cfg->data_len = cp->cc_ltvs_len;
522 memcpy(codec_cfg->data, ltv_ptr, cp->cc_ltvs_len);
523 ltv_ptr += cp->cc_ltvs_len;
524 }
525
526 if (cp->metadata_ltvs_len != 0) {
527 codec_cfg->meta_len = cp->metadata_ltvs_len;
528 memcpy(codec_cfg->meta, ltv_ptr, cp->metadata_ltvs_len);
529 }
530
531 return BTP_STATUS_SUCCESS;
532 }
533
btp_cap_broadcast_source_setup_subgroup(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)534 static uint8_t btp_cap_broadcast_source_setup_subgroup(const void *cmd, uint16_t cmd_len,
535 void *rsp, uint16_t *rsp_len)
536 {
537 const uint8_t *ltv_ptr;
538 struct bt_audio_codec_cfg *codec_cfg;
539 const struct btp_cap_broadcast_source_setup_subgroup_cmd *cp = cmd;
540 struct btp_bap_broadcast_local_source *source =
541 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
542
543 if (source == NULL) {
544 return BTP_STATUS_FAILED;
545 }
546
547 if (cp->subgroup_id >= ARRAY_SIZE(cap_broadcast_params[0].cap_subgroup_params)) {
548 return BTP_STATUS_FAILED;
549 }
550
551 uint8_t idx = btp_bap_broadcast_local_source_idx_get(source);
552
553 if (idx >= ARRAY_SIZE(cap_broadcast_params)) {
554 return BTP_STATUS_FAILED;
555 }
556
557 struct bt_cap_initiator_broadcast_subgroup_param *subgroup_param =
558 &cap_broadcast_params[idx].cap_subgroup_params[cp->subgroup_id];
559
560 subgroup_param->codec_cfg = &source->subgroup_codec_cfg[cp->subgroup_id];
561
562 codec_cfg = subgroup_param->codec_cfg;
563
564 memset(codec_cfg, 0, sizeof(*codec_cfg));
565 codec_cfg->id = cp->coding_format;
566 codec_cfg->vid = cp->vid;
567 codec_cfg->cid = cp->cid;
568
569 ltv_ptr = cp->ltvs;
570 if (cp->cc_ltvs_len != 0) {
571 codec_cfg->data_len = cp->cc_ltvs_len;
572 memcpy(codec_cfg->data, ltv_ptr, cp->cc_ltvs_len);
573 ltv_ptr += cp->cc_ltvs_len;
574 }
575
576 if (cp->metadata_ltvs_len != 0) {
577 codec_cfg->meta_len = cp->metadata_ltvs_len;
578 memcpy(codec_cfg->meta, ltv_ptr, cp->metadata_ltvs_len);
579 }
580
581 return BTP_STATUS_SUCCESS;
582 }
583
cap_broadcast_source_adv_setup(struct btp_bap_broadcast_local_source * source,uint32_t * gap_settings)584 static int cap_broadcast_source_adv_setup(struct btp_bap_broadcast_local_source *source,
585 uint32_t *gap_settings)
586 {
587 int err;
588
589 NET_BUF_SIMPLE_DEFINE(base_buf, 128);
590
591 /* Broadcast Audio Streaming Endpoint advertising data */
592 struct bt_data per_ad;
593
594 /* A more specialized adv instance may already have been created by another btp module */
595 if (source->ext_adv == NULL) {
596 struct bt_le_adv_param param = *BT_LE_EXT_ADV_NCONN;
597 struct bt_data base_ad[2];
598
599 NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
600 *gap_settings = BIT(BTP_GAP_SETTINGS_DISCOVERABLE) |
601 BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING);
602 /* Setup extended advertising data */
603 net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
604 net_buf_simple_add_le24(&ad_buf, source->broadcast_id);
605 base_ad[0].type = BT_DATA_SVC_DATA16;
606 base_ad[0].data_len = ad_buf.len;
607 base_ad[0].data = ad_buf.data;
608 base_ad[1].type = BT_DATA_NAME_COMPLETE;
609 base_ad[1].data_len = sizeof(CONFIG_BT_DEVICE_NAME) - 1;
610 base_ad[1].data = CONFIG_BT_DEVICE_NAME;
611
612 err = tester_gap_create_adv_instance(¶m, BTP_GAP_ADDR_TYPE_IDENTITY,
613 base_ad, 2, NULL, 0, gap_settings,
614 &source->ext_adv);
615 if (err != 0) {
616 LOG_DBG("Failed to create extended advertising instance: %d", err);
617 return -EINVAL;
618 }
619 }
620
621 err = tester_gap_padv_configure(source->ext_adv,
622 BT_LE_PER_ADV_PARAM(BT_GAP_PER_ADV_FAST_INT_MIN_2,
623 BT_GAP_PER_ADV_FAST_INT_MAX_2,
624 BT_LE_PER_ADV_OPT_NONE));
625 if (err != 0) {
626 LOG_DBG("Failed to configure periodic advertising: %d", err);
627
628 return -EINVAL;
629 }
630
631 err = bt_cap_initiator_broadcast_get_base(source->cap_broadcast, &base_buf);
632 if (err != 0) {
633 LOG_DBG("Failed to get encoded BASE: %d\n", err);
634
635 return -EINVAL;
636 }
637
638 per_ad.type = BT_DATA_SVC_DATA16;
639 per_ad.data_len = base_buf.len;
640 per_ad.data = base_buf.data;
641 err = tester_gap_padv_set_data(source->ext_adv, &per_ad, 1);
642 if (err != 0) {
643 return -EINVAL;
644 }
645
646 return 0;
647 }
648
btp_cap_broadcast_source_setup(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)649 static uint8_t btp_cap_broadcast_source_setup(const void *cmd, uint16_t cmd_len,
650 void *rsp, uint16_t *rsp_len)
651 {
652 int err;
653 uint32_t gap_settings;
654 static struct bt_cap_initiator_broadcast_create_param create_param;
655 const struct btp_cap_broadcast_source_setup_cmd *cp = cmd;
656 struct btp_cap_broadcast_source_setup_rp *rp = rsp;
657 struct btp_bap_broadcast_local_source *source =
658 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
659
660 if (source == NULL) {
661 return BTP_STATUS_FAILED;
662 }
663
664 struct cap_initiator_broadcast_params *cap_params =
665 &cap_broadcast_params[cp->source_id];
666
667 struct bt_bap_qos_cfg *qos = &source->qos;
668
669 LOG_DBG("");
670
671 memset(&create_param, 0, sizeof(create_param));
672
673 for (size_t i = 0; i < ARRAY_SIZE(source->streams); i++) {
674 struct btp_bap_broadcast_stream *stream = &source->streams[i];
675 struct bt_cap_initiator_broadcast_stream_param *stream_param;
676 uint8_t bis_id;
677
678 if (!stream->in_use) {
679 /* No more streams set up */
680 break;
681 }
682
683 bis_id = cap_params->cap_subgroup_params[stream->subgroup_id].stream_count++;
684 stream_param = &cap_params->cap_stream_params[stream->subgroup_id][bis_id];
685
686 stream_param->stream = stream_broadcast_to_cap(stream);
687
688 if (cp->flags & BTP_CAP_BROADCAST_SOURCE_SETUP_FLAG_SUBGROUP_CODEC) {
689 stream_param->data_len = 0;
690 stream_param->data = NULL;
691 } else {
692 stream_param->data_len = stream->codec_cfg.data_len;
693 stream_param->data = stream->codec_cfg.data;
694 }
695 }
696
697 for (size_t i = 0; i < ARRAY_SIZE(cap_params->cap_subgroup_params); i++) {
698 if (cap_params->cap_subgroup_params[i].stream_count == 0) {
699 /* No gaps allowed */
700 break;
701 }
702
703 cap_params->cap_subgroup_params[i].stream_params = cap_params->cap_stream_params[i];
704 create_param.subgroup_count++;
705 }
706
707 if (create_param.subgroup_count == 0) {
708 return BTP_STATUS_FAILED;
709 }
710
711 memset(qos, 0, sizeof(*qos));
712 qos->phy = BT_BAP_QOS_CFG_2M;
713 qos->framing = cp->framing;
714 qos->rtn = cp->retransmission_num;
715 qos->sdu = sys_le16_to_cpu(cp->max_sdu);
716 qos->latency = sys_le16_to_cpu(cp->max_transport_latency);
717 qos->interval = sys_get_le24(cp->sdu_interval);
718 qos->pd = sys_get_le24(cp->presentation_delay);
719
720 create_param.subgroup_params = cap_params->cap_subgroup_params;
721 create_param.qos = qos;
722 create_param.packing = BT_ISO_PACKING_SEQUENTIAL;
723 create_param.encryption = cp->flags & BTP_CAP_BROADCAST_SOURCE_SETUP_FLAG_ENCRYPTION;
724 memcpy(create_param.broadcast_code, cp->broadcast_code, sizeof(cp->broadcast_code));
725
726 err = bt_cap_initiator_broadcast_audio_create(&create_param, &source->cap_broadcast);
727 memset(&cap_params->cap_subgroup_params, 0, sizeof(cap_params->cap_subgroup_params));
728 memset(&create_param, 0, sizeof(create_param));
729 if (err != 0) {
730 LOG_ERR("Failed to create audio source: %d", err);
731
732 return BTP_STATUS_FAILED;
733 }
734
735 err = cap_broadcast_source_adv_setup(source, &gap_settings);
736 if (err != 0) {
737 return BTP_STATUS_FAILED;
738 }
739
740 rp->gap_settings = gap_settings;
741 sys_put_le24(source->broadcast_id, rp->broadcast_id);
742 *rsp_len = sizeof(*rp);
743
744 return BTP_STATUS_SUCCESS;
745 }
746
btp_cap_broadcast_source_release(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)747 static uint8_t btp_cap_broadcast_source_release(const void *cmd, uint16_t cmd_len,
748 void *rsp, uint16_t *rsp_len)
749 {
750 int err;
751 const struct btp_cap_broadcast_source_release_cmd *cp = cmd;
752 struct btp_bap_broadcast_local_source *source =
753 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
754
755 LOG_DBG("");
756
757 /* If no source has been created yet, there is nothing to release */
758 if (source == NULL || source->cap_broadcast == NULL) {
759 return BTP_STATUS_SUCCESS;
760 }
761
762 err = bt_cap_initiator_broadcast_audio_delete(source->cap_broadcast);
763 if (err != 0) {
764 LOG_DBG("Unable to delete broadcast source: %d", err);
765
766 return BTP_STATUS_FAILED;
767 }
768
769 memset(source, 0, sizeof(*source));
770
771 return BTP_STATUS_SUCCESS;
772 }
773
btp_cap_broadcast_adv_start(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)774 static uint8_t btp_cap_broadcast_adv_start(const void *cmd, uint16_t cmd_len,
775 void *rsp, uint16_t *rsp_len)
776 {
777 int err;
778 const struct btp_cap_broadcast_adv_start_cmd *cp = cmd;
779 struct btp_bap_broadcast_local_source *source =
780 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
781
782 if (source == NULL) {
783 return BTP_STATUS_FAILED;
784 }
785
786 if (source->ext_adv == NULL) {
787 return BTP_STATUS_FAILED;
788 }
789
790 err = tester_gap_start_ext_adv(source->ext_adv);
791 if (err != 0) {
792 return BTP_STATUS_FAILED;
793 }
794
795 err = tester_gap_padv_start(source->ext_adv);
796 if (err != 0) {
797 LOG_DBG("Unable to start periodic advertising: %d", err);
798
799 return BTP_STATUS_FAILED;
800 }
801
802 return BTP_STATUS_SUCCESS;
803 }
804
btp_cap_broadcast_adv_stop(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)805 static uint8_t btp_cap_broadcast_adv_stop(const void *cmd, uint16_t cmd_len,
806 void *rsp, uint16_t *rsp_len)
807 {
808 int err;
809 const struct btp_cap_broadcast_adv_stop_cmd *cp = cmd;
810
811 LOG_DBG("");
812
813 struct btp_bap_broadcast_local_source *source =
814 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
815
816 if (source == NULL) {
817 return BTP_STATUS_FAILED;
818 }
819
820 err = tester_gap_padv_stop(source->ext_adv);
821 if (err == -ESRCH) {
822 /* Ext adv hasn't been created yet */
823 return BTP_STATUS_SUCCESS;
824 } else if (err != 0) {
825 LOG_DBG("Failed to stop periodic adv, err: %d", err);
826 return BTP_STATUS_FAILED;
827 }
828
829 err = tester_gap_stop_ext_adv(source->ext_adv);
830
831 return BTP_STATUS_VAL(err);
832 }
833
btp_cap_broadcast_source_start(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)834 static uint8_t btp_cap_broadcast_source_start(const void *cmd, uint16_t cmd_len,
835 void *rsp, uint16_t *rsp_len)
836 {
837 int err;
838 const struct btp_cap_broadcast_source_start_cmd *cp = cmd;
839 struct btp_bap_broadcast_local_source *source =
840 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
841
842 if (source == NULL) {
843 return BTP_STATUS_FAILED;
844 }
845
846 LOG_DBG("");
847
848 if (source->ext_adv == NULL) {
849 return BTP_STATUS_FAILED;
850 }
851
852 err = bt_cap_initiator_broadcast_audio_start(source->cap_broadcast, source->ext_adv);
853 if (err != 0) {
854 LOG_ERR("Failed to start audio source: %d", err);
855
856 return BTP_STATUS_FAILED;
857 }
858
859 return BTP_STATUS_SUCCESS;
860 }
861
btp_cap_broadcast_source_stop(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)862 static uint8_t btp_cap_broadcast_source_stop(const void *cmd, uint16_t cmd_len,
863 void *rsp, uint16_t *rsp_len)
864 {
865 int err;
866 const struct btp_cap_broadcast_source_stop_cmd *cp = cmd;
867 struct btp_bap_broadcast_local_source *source =
868 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
869
870 /* If no source has been started yet, there is nothing to stop */
871 if (source == NULL || source->cap_broadcast == NULL) {
872 return BTP_STATUS_SUCCESS;
873 }
874
875 err = bt_cap_initiator_broadcast_audio_stop(source->cap_broadcast);
876 if (err != 0) {
877 LOG_ERR("Failed to stop audio source: %d", err);
878
879 return BTP_STATUS_FAILED;
880 }
881
882 /* Make sure source is stopped before proceeding */
883 err = k_sem_take(&source_stopped_sem, K_SECONDS(1));
884 if (err) {
885 LOG_ERR("Semaphore timed out: %d", err);
886
887 return BTP_STATUS_FAILED;
888 }
889
890 return BTP_STATUS_SUCCESS;
891 }
892
btp_cap_broadcast_source_update(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)893 static uint8_t btp_cap_broadcast_source_update(const void *cmd, uint16_t cmd_len,
894 void *rsp, uint16_t *rsp_len)
895 {
896 int err;
897 struct bt_data per_ad;
898 const struct btp_cap_broadcast_source_update_cmd *cp = cmd;
899 struct btp_bap_broadcast_local_source *source =
900 btp_bap_broadcast_local_source_from_src_id_get(cp->source_id);
901
902 if (source == NULL) {
903 return BTP_STATUS_FAILED;
904 }
905
906 NET_BUF_SIMPLE_DEFINE(base_buf, 128);
907
908 LOG_DBG("");
909
910 if (cp->metadata_ltvs_len == 0) {
911 return BTP_STATUS_FAILED;
912 }
913
914 err = bt_cap_initiator_broadcast_audio_update(source->cap_broadcast, cp->metadata_ltvs,
915 cp->metadata_ltvs_len);
916 if (err != 0) {
917 LOG_ERR("Failed to update audio source: %d", err);
918
919 return BTP_STATUS_FAILED;
920 }
921
922 err = bt_cap_initiator_broadcast_get_base(source->cap_broadcast, &base_buf);
923 if (err != 0) {
924 LOG_DBG("Failed to get encoded BASE: %d\n", err);
925
926 return -EINVAL;
927 }
928
929 per_ad.type = BT_DATA_SVC_DATA16;
930 per_ad.data_len = base_buf.len;
931 per_ad.data = base_buf.data;
932 err = tester_gap_padv_set_data(source->ext_adv, &per_ad, 1);
933 if (err != 0) {
934 return -EINVAL;
935 }
936
937 return BTP_STATUS_SUCCESS;
938 }
939
940 static const struct btp_handler cap_handlers[] = {
941 {
942 .opcode = BTP_CAP_READ_SUPPORTED_COMMANDS,
943 .index = BTP_INDEX_NONE,
944 .expect_len = 0,
945 .func = btp_cap_supported_commands
946 },
947 {
948 .opcode = BTP_CAP_DISCOVER,
949 .expect_len = sizeof(struct btp_cap_discover_cmd),
950 .func = btp_cap_discover
951 },
952 {
953 .opcode = BTP_CAP_UNICAST_SETUP_ASE,
954 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
955 .func = btp_cap_unicast_setup_ase
956 },
957 {
958 .opcode = BTP_CAP_UNICAST_AUDIO_START,
959 .expect_len = sizeof(struct btp_cap_unicast_audio_start_cmd),
960 .func = btp_cap_unicast_audio_start
961 },
962 {
963 .opcode = BTP_CAP_UNICAST_AUDIO_UPDATE,
964 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
965 .func = btp_cap_unicast_audio_update
966 },
967 {
968 .opcode = BTP_CAP_UNICAST_AUDIO_STOP,
969 .expect_len = sizeof(struct btp_cap_unicast_audio_stop_cmd),
970 .func = btp_cap_unicast_audio_stop
971 },
972 {
973 .opcode = BTP_CAP_BROADCAST_SOURCE_SETUP_STREAM,
974 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
975 .func = btp_cap_broadcast_source_setup_stream
976 },
977 {
978 .opcode = BTP_CAP_BROADCAST_SOURCE_SETUP_SUBGROUP,
979 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
980 .func = btp_cap_broadcast_source_setup_subgroup
981 },
982 {
983 .opcode = BTP_CAP_BROADCAST_SOURCE_SETUP,
984 .expect_len = sizeof(struct btp_cap_broadcast_source_setup_cmd),
985 .func = btp_cap_broadcast_source_setup
986 },
987 {
988 .opcode = BTP_CAP_BROADCAST_SOURCE_RELEASE,
989 .expect_len = sizeof(struct btp_cap_broadcast_source_release_cmd),
990 .func = btp_cap_broadcast_source_release
991 },
992 {
993 .opcode = BTP_CAP_BROADCAST_ADV_START,
994 .expect_len = sizeof(struct btp_cap_broadcast_adv_start_cmd),
995 .func = btp_cap_broadcast_adv_start
996 },
997 {
998 .opcode = BTP_CAP_BROADCAST_ADV_STOP,
999 .expect_len = sizeof(struct btp_cap_broadcast_adv_stop_cmd),
1000 .func = btp_cap_broadcast_adv_stop
1001 },
1002 {
1003 .opcode = BTP_CAP_BROADCAST_SOURCE_START,
1004 .expect_len = sizeof(struct btp_cap_broadcast_source_start_cmd),
1005 .func = btp_cap_broadcast_source_start
1006 },
1007 {
1008 .opcode = BTP_CAP_BROADCAST_SOURCE_STOP,
1009 .expect_len = sizeof(struct btp_cap_broadcast_source_stop_cmd),
1010 .func = btp_cap_broadcast_source_stop
1011 },
1012 {
1013 .opcode = BTP_CAP_BROADCAST_SOURCE_UPDATE,
1014 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
1015 .func = btp_cap_broadcast_source_update
1016 },
1017 };
1018
tester_init_cap(void)1019 uint8_t tester_init_cap(void)
1020 {
1021 int err;
1022
1023 err = bt_cap_initiator_register_cb(&cap_cb);
1024 if (err != 0) {
1025 LOG_DBG("Failed to register CAP callbacks (err %d)", err);
1026 return err;
1027 }
1028
1029 tester_register_command_handlers(BTP_SERVICE_ID_CAP, cap_handlers,
1030 ARRAY_SIZE(cap_handlers));
1031
1032 return BTP_STATUS_SUCCESS;
1033 }
1034
tester_unregister_cap(void)1035 uint8_t tester_unregister_cap(void)
1036 {
1037 return BTP_STATUS_SUCCESS;
1038 }
1039