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