1 /* btp_bap_unicast.c - Bluetooth BAP Tester */
2
3 /*
4 * Copyright (c) 2023 Codecoup
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <stddef.h>
10 #include <errno.h>
11
12 #include <zephyr/types.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/ring_buffer.h>
15 #include <zephyr/bluetooth/audio/audio.h>
16 #include <zephyr/bluetooth/hci_types.h>
17 #include <hci_core.h>
18
19 #include "bap_endpoint.h"
20 #include <zephyr/logging/log.h>
21 #include <zephyr/sys/byteorder.h>
22 #define LOG_MODULE_NAME bttester_bap_unicast
23 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
24 #include "btp/btp.h"
25 #include "btp_bap_audio_stream.h"
26 #include "btp_bap_unicast.h"
27
28 static struct bt_audio_codec_qos_pref qos_pref =
29 BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 10000, 40000, 10000, 40000);
30
31 static struct btp_bap_unicast_connection connections[CONFIG_BT_MAX_CONN];
32 static struct btp_bap_unicast_group cigs[CONFIG_BT_ISO_MAX_CIG];
33
stream_bap_to_unicast(struct bt_bap_stream * stream)34 static inline struct btp_bap_unicast_stream *stream_bap_to_unicast(struct bt_bap_stream *stream)
35 {
36 return CONTAINER_OF(CONTAINER_OF(CONTAINER_OF(stream, struct bt_cap_stream, bap_stream),
37 struct btp_bap_audio_stream, cap_stream),
38 struct btp_bap_unicast_stream, audio_stream);
39 }
40
stream_unicast_to_bap(struct btp_bap_unicast_stream * stream)41 static inline struct bt_bap_stream *stream_unicast_to_bap(struct btp_bap_unicast_stream *stream)
42 {
43 return &stream->audio_stream.cap_stream.bap_stream;
44 }
45
print_cb(struct bt_data * data,void * user_data)46 static bool print_cb(struct bt_data *data, void *user_data)
47 {
48 const char *str = (const char *)user_data;
49
50 LOG_DBG("%s: type 0x%02x value_len %u", str, data->type, data->data_len);
51 LOG_HEXDUMP_DBG(data->data, data->data_len, "");
52
53 return true;
54 }
55
print_codec_cfg(const struct bt_audio_codec_cfg * codec_cfg)56 static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
57 {
58 LOG_DBG("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u", codec_cfg->id, codec_cfg->cid,
59 codec_cfg->vid, codec_cfg->data_len);
60
61 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
62 enum bt_audio_location chan_allocation;
63 int ret;
64
65 /* LC3 uses the generic LTV format - other codecs might do as well */
66
67 bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
68
69 ret = bt_audio_codec_cfg_get_freq(codec_cfg);
70 if (ret > 0) {
71 LOG_DBG(" Frequency: %d Hz", bt_audio_codec_cfg_freq_to_freq_hz(ret));
72 }
73
74 ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
75 if (ret > 0) {
76 LOG_DBG(" Frame Duration: %d us",
77 bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret));
78 }
79
80 ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
81 if (ret == 0) {
82 LOG_DBG(" Channel allocation: 0x%x", chan_allocation);
83 }
84
85 LOG_DBG(" Octets per frame: %d (negative means value not pressent)",
86 bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
87 LOG_DBG(" Frames per SDU: %d",
88 bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
89 } else {
90 LOG_HEXDUMP_DBG(codec_cfg->data, codec_cfg->data_len, "data");
91 }
92
93 bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
94 }
95
print_codec_cap(const struct bt_audio_codec_cap * codec_cap)96 static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
97 {
98 LOG_DBG("codec_cap 0x%02x cid 0x%04x vid 0x%04x count %zu", codec_cap->id, codec_cap->cid,
99 codec_cap->vid, codec_cap->data_len);
100
101 if (codec_cap->id == BT_HCI_CODING_FORMAT_LC3) {
102 bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data");
103 } else {
104 LOG_HEXDUMP_DBG(codec_cap->data, codec_cap->data_len, "data");
105 }
106
107 bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta");
108 }
109
btp_bap_unicast_stream_free(struct btp_bap_unicast_stream * stream)110 void btp_bap_unicast_stream_free(struct btp_bap_unicast_stream *stream)
111 {
112 (void)memset(stream, 0, sizeof(*stream));
113 }
114
btp_bap_unicast_stream_find(struct btp_bap_unicast_connection * conn,uint8_t ase_id)115 struct btp_bap_unicast_stream *btp_bap_unicast_stream_find(
116 struct btp_bap_unicast_connection *conn, uint8_t ase_id)
117 {
118 for (size_t i = 0; i < ARRAY_SIZE(conn->streams); i++) {
119 struct bt_bap_stream *stream = stream_unicast_to_bap(&conn->streams[i]);
120 struct bt_bap_ep_info info;
121
122 if (stream->ep == NULL) {
123 continue;
124 }
125
126 (void)bt_bap_ep_get_info(stream->ep, &info);
127 if (info.id == ase_id) {
128 return &conn->streams[i];
129 }
130 }
131
132 return NULL;
133 }
134
btp_bap_unicast_end_point_find(struct btp_bap_unicast_connection * conn,uint8_t ase_id)135 struct bt_bap_ep *btp_bap_unicast_end_point_find(struct btp_bap_unicast_connection *conn,
136 uint8_t ase_id)
137 {
138 for (size_t i = 0; i < ARRAY_SIZE(conn->end_points); i++) {
139 struct bt_bap_ep_info info;
140 struct bt_bap_ep *ep = conn->end_points[i];
141
142 if (ep == NULL) {
143 continue;
144 }
145
146 (void)bt_bap_ep_get_info(ep, &info);
147 if (info.id == ase_id) {
148 return ep;
149 }
150 }
151
152 return NULL;
153 }
154
btp_send_ascs_ase_state_changed_ev(struct bt_conn * conn,uint8_t ase_id,uint8_t state)155 static void btp_send_ascs_ase_state_changed_ev(struct bt_conn *conn, uint8_t ase_id, uint8_t state)
156 {
157 struct btp_ascs_ase_state_changed_ev ev;
158
159 bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
160 ev.ase_id = ase_id;
161 ev.state = state;
162
163 tester_event(BTP_SERVICE_ID_ASCS, BTP_ASCS_EV_ASE_STATE_CHANGED, &ev, sizeof(ev));
164 }
165
btp_send_ascs_operation_completed_ev(struct bt_conn * conn,uint8_t ase_id,uint8_t opcode,uint8_t status)166 static void btp_send_ascs_operation_completed_ev(struct bt_conn *conn, uint8_t ase_id,
167 uint8_t opcode, uint8_t status)
168 {
169 struct btp_ascs_operation_completed_ev ev;
170
171 bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
172 ev.ase_id = ase_id;
173 ev.opcode = opcode;
174 ev.status = status;
175 ev.flags = 0;
176
177 tester_event(BTP_SERVICE_ID_ASCS, BTP_ASCS_EV_OPERATION_COMPLETED, &ev, sizeof(ev));
178 }
179
180 struct search_type_param {
181 uint8_t type;
182 const uint8_t *data;
183 };
184
data_type_search_cb(struct bt_data * data,void * user_data)185 static bool data_type_search_cb(struct bt_data *data, void *user_data)
186 {
187 struct search_type_param *param = (struct search_type_param *)user_data;
188
189 if (param->type == data->type) {
190 param->data = data->data;
191
192 return false;
193 }
194
195 return true;
196 }
197
codec_cap_get_val(const struct bt_audio_codec_cap * codec_cap,uint8_t type,const uint8_t ** data)198 static bool codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, uint8_t type,
199 const uint8_t **data)
200 {
201 struct search_type_param param = {
202 .type = type,
203 .data = NULL,
204 };
205 int err;
206
207 err = bt_audio_data_parse(codec_cap->data, codec_cap->data_len, data_type_search_cb,
208 ¶m);
209 if (err != 0 && err != -ECANCELED) {
210 LOG_DBG("Could not parse the data: %d", err);
211
212 return false;
213 }
214
215 if (param.data == NULL) {
216 LOG_DBG("Could not find the type %u", type);
217
218 return false;
219 }
220
221 *data = param.data;
222
223 return true;
224 }
225
btp_send_pac_codec_found_ev(struct bt_conn * conn,const struct bt_audio_codec_cap * codec_cap,enum bt_audio_dir dir)226 static void btp_send_pac_codec_found_ev(struct bt_conn *conn,
227 const struct bt_audio_codec_cap *codec_cap,
228 enum bt_audio_dir dir)
229 {
230 struct btp_bap_codec_cap_found_ev ev;
231 const uint8_t *data;
232
233 bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
234
235 ev.dir = dir;
236 ev.coding_format = codec_cap->id;
237
238 if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FREQ, &data)) {
239 memcpy(&ev.frequencies, data, sizeof(ev.frequencies));
240 }
241
242 if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_DURATION, &data)) {
243 memcpy(&ev.frame_durations, data, sizeof(ev.frame_durations));
244 }
245
246 if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_FRAME_LEN, &data)) {
247 memcpy(&ev.octets_per_frame, data, sizeof(ev.octets_per_frame));
248 }
249
250 if (codec_cap_get_val(codec_cap, BT_AUDIO_CODEC_CAP_TYPE_CHAN_COUNT, &data)) {
251 memcpy(&ev.channel_counts, data, sizeof(ev.channel_counts));
252 }
253
254 tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_CODEC_CAP_FOUND, &ev, sizeof(ev));
255 }
256
btp_send_ase_found_ev(struct bt_conn * conn,struct bt_bap_ep * ep)257 static void btp_send_ase_found_ev(struct bt_conn *conn, struct bt_bap_ep *ep)
258 {
259 struct bt_bap_ep_info info;
260 struct btp_ascs_ase_found_ev ev;
261
262 bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
263
264 (void)bt_bap_ep_get_info(ep, &info);
265 ev.ase_id = info.id;
266 ev.dir = info.dir;
267
268 tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_ASE_FOUND, &ev, sizeof(ev));
269 }
270
print_qos(const struct bt_audio_codec_qos * qos)271 static inline void print_qos(const struct bt_audio_codec_qos *qos)
272 {
273 LOG_DBG("QoS: interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u latency %u pd %u",
274 qos->interval, qos->framing, qos->phy, qos->sdu, qos->rtn, qos->latency, qos->pd);
275 }
276
validate_codec_parameters(const struct bt_audio_codec_cfg * codec_cfg)277 static int validate_codec_parameters(const struct bt_audio_codec_cfg *codec_cfg)
278 {
279 int frames_per_sdu;
280 int octets_per_frame;
281 int chan_allocation_err;
282 enum bt_audio_location chan_allocation;
283 int ret;
284
285 chan_allocation_err =
286 bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &chan_allocation, false);
287 octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
288 frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
289
290 ret = bt_audio_codec_cfg_get_freq(codec_cfg);
291 if (ret < 0) {
292 LOG_DBG("Error: Invalid codec frequency: %d", ret);
293 return -EINVAL;
294 }
295
296 ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
297 if (ret < 0) {
298 LOG_DBG("Error: Invalid frame duration: %d", ret);
299 return -EINVAL;
300 }
301
302 if (octets_per_frame < 0) {
303 LOG_DBG("Error: Invalid octets per frame.");
304 return -EINVAL;
305 }
306
307 if (frames_per_sdu < 0) {
308 /* The absence of the Codec_Frame_Blocks_Per_SDU LTV structure shall be
309 * interpreted as equivalent to a Codec_Frame_Blocks_Per_SDU value of 0x01
310 */
311 LOG_DBG("Codec_Frame_Blocks_Per_SDU LTV structure not defined.");
312 }
313
314 if (chan_allocation_err < 0) {
315 /* The absence of the Audio_Channel_Allocation LTV structure shall be
316 * interpreted as a single channel with no specified Audio Location.
317 */
318 LOG_DBG("Audio_Channel_Allocation LTV structure not defined.");
319 }
320
321 return 0;
322 }
323
lc3_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_audio_codec_qos_pref * const pref,struct bt_bap_ascs_rsp * rsp)324 static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
325 const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream,
326 struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
327 {
328 struct bt_bap_ep_info info;
329 struct btp_bap_unicast_connection *u_conn;
330 struct btp_bap_unicast_stream *u_stream;
331
332 LOG_DBG("ASE Codec Config: ep %p dir %u", ep, dir);
333
334 print_codec_cfg(codec_cfg);
335 (void)bt_bap_ep_get_info(ep, &info);
336
337 if (validate_codec_parameters(codec_cfg)) {
338 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_REJECTED,
339 BT_BAP_ASCS_REASON_CODEC_DATA);
340
341 btp_send_ascs_operation_completed_ev(conn, info.id, BT_ASCS_CONFIG_OP,
342 BTP_ASCS_STATUS_FAILED);
343
344 return -ENOTSUP;
345 }
346
347 u_conn = &connections[bt_conn_index(conn)];
348 u_stream = btp_bap_unicast_stream_alloc(u_conn);
349 if (u_stream == NULL) {
350 LOG_DBG("No free stream available");
351 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
352
353 btp_send_ascs_operation_completed_ev(conn, info.id, BT_ASCS_CONFIG_OP,
354 BTP_ASCS_STATUS_FAILED);
355
356 return -ENOMEM;
357 }
358
359 *stream = stream_unicast_to_bap(u_stream);
360 LOG_DBG("ASE Codec Config stream %p", *stream);
361
362 if (dir == BT_AUDIO_DIR_SOURCE) {
363 u_conn->configured_source_stream_count++;
364 } else {
365 u_conn->configured_sink_stream_count++;
366 }
367
368 *pref = qos_pref;
369
370 return 0;
371 }
372
lc3_reconfig(struct bt_bap_stream * stream,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_audio_codec_qos_pref * const pref,struct bt_bap_ascs_rsp * rsp)373 static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
374 const struct bt_audio_codec_cfg *codec_cfg,
375 struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
376 {
377 LOG_DBG("ASE Codec Reconfig: stream %p", stream);
378
379 print_codec_cfg(codec_cfg);
380
381 return 0;
382 }
383
lc3_qos(struct bt_bap_stream * stream,const struct bt_audio_codec_qos * qos,struct bt_bap_ascs_rsp * rsp)384 static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos,
385 struct bt_bap_ascs_rsp *rsp)
386 {
387 LOG_DBG("QoS: stream %p qos %p", stream, qos);
388
389 print_qos(qos);
390
391 return 0;
392 }
393
valid_metadata_type(uint8_t type,uint8_t len,const uint8_t * data)394 static bool valid_metadata_type(uint8_t type, uint8_t len, const uint8_t *data)
395 {
396 /* PTS checks if we are able to reject unsupported metadata type or RFU vale.
397 * The only RFU value PTS seems to check for now is the streaming context.
398 */
399 if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(type)) {
400 return false;
401 }
402
403 if (type == BT_AUDIO_METADATA_TYPE_PREF_CONTEXT ||
404 type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
405 /* PTS wants us to reject the parameter if reserved bits are set */
406 if ((sys_get_le16(data) & ~(uint16_t)(BT_AUDIO_CONTEXT_TYPE_ANY)) > 0) {
407 return false;
408 }
409 }
410
411 return true;
412 }
413
data_func_cb(struct bt_data * data,void * user_data)414 static bool data_func_cb(struct bt_data *data, void *user_data)
415 {
416 struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
417
418 if (!valid_metadata_type(data->type, data->data_len, data->data)) {
419 LOG_DBG("Invalid metadata type %u or length %u", data->type, data->data_len);
420 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
421 return false;
422 }
423
424 return true;
425 }
426
lc3_enable(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)427 static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
428 struct bt_bap_ascs_rsp *rsp)
429 {
430 int err;
431 struct bt_bap_ep_info info;
432
433 LOG_DBG("Metadata: stream %p meta_len %zu", stream, meta_len);
434
435 err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
436 if (err != 0) {
437 (void)bt_bap_ep_get_info(stream->ep, &info);
438 btp_send_ascs_operation_completed_ev(stream->conn, info.id,
439 BT_ASCS_ENABLE_OP, BTP_ASCS_STATUS_FAILED);
440 }
441
442 return err;
443 }
444
lc3_start(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)445 static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
446 {
447 LOG_DBG("Start: stream %p", stream);
448
449 return 0;
450 }
451
lc3_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)452 static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
453 struct bt_bap_ascs_rsp *rsp)
454 {
455 int err;
456 struct bt_bap_ep_info info;
457
458 LOG_DBG("Metadata: stream %p meta_count %zu", stream, meta_len);
459
460 err = bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
461 if (err != 0) {
462 (void)bt_bap_ep_get_info(stream->ep, &info);
463 btp_send_ascs_operation_completed_ev(stream->conn, info.id,
464 BT_ASCS_METADATA_OP, BTP_ASCS_STATUS_FAILED);
465 }
466
467 return err;
468 }
469
lc3_disable(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)470 static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
471 {
472 LOG_DBG("Disable: stream %p", stream);
473
474 return 0;
475 }
476
lc3_stop(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)477 static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
478 {
479 LOG_DBG("Stop: stream %p", stream);
480
481 return 0;
482 }
483
lc3_release(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)484 static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
485 {
486 LOG_DBG("Release: stream %p", stream);
487
488 return 0;
489 }
490
491 static const struct bt_bap_unicast_server_cb unicast_server_cb = {
492 .config = lc3_config,
493 .reconfig = lc3_reconfig,
494 .qos = lc3_qos,
495 .enable = lc3_enable,
496 .start = lc3_start,
497 .metadata = lc3_metadata,
498 .disable = lc3_disable,
499 .stop = lc3_stop,
500 .release = lc3_release,
501 };
502
stream_configured(struct bt_bap_stream * stream,const struct bt_audio_codec_qos_pref * pref)503 static void stream_configured(struct bt_bap_stream *stream,
504 const struct bt_audio_codec_qos_pref *pref)
505 {
506 struct bt_bap_ep_info info;
507 struct btp_bap_unicast_connection *u_conn;
508 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
509
510 (void)bt_bap_ep_get_info(stream->ep, &info);
511 LOG_DBG("Configured stream %p, ep %u, dir %u", stream, info.id, info.dir);
512
513 u_stream->conn_id = bt_conn_index(stream->conn);
514 u_conn = &connections[u_stream->conn_id];
515 u_stream->ase_id = info.id;
516
517 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
518 BT_ASCS_CONFIG_OP, BTP_ASCS_STATUS_SUCCESS);
519 }
520
stream_qos_set(struct bt_bap_stream * stream)521 static void stream_qos_set(struct bt_bap_stream *stream)
522 {
523 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
524
525 LOG_DBG("QoS set stream %p", stream);
526 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
527 BT_ASCS_QOS_OP, BTP_ASCS_STATUS_SUCCESS);
528 }
529
stream_enabled(struct bt_bap_stream * stream)530 static void stream_enabled(struct bt_bap_stream *stream)
531 {
532 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
533 struct bt_bap_ep_info info;
534 struct bt_conn_info conn_info;
535 int err;
536
537 LOG_DBG("Enabled stream %p", stream);
538
539 (void)bt_bap_ep_get_info(stream->ep, &info);
540 (void)bt_conn_get_info(stream->conn, &conn_info);
541 if (conn_info.role == BT_HCI_ROLE_PERIPHERAL && info.dir == BT_AUDIO_DIR_SINK) {
542 /* Automatically do the receiver start ready operation */
543 err = bt_bap_stream_start(stream);
544 if (err != 0) {
545 LOG_DBG("Failed to start stream %p", stream);
546 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
547 BT_ASCS_ENABLE_OP,
548 BTP_ASCS_STATUS_FAILED);
549
550 return;
551 }
552 }
553
554 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
555 BT_ASCS_ENABLE_OP, BTP_ASCS_STATUS_SUCCESS);
556 }
557
stream_metadata_updated(struct bt_bap_stream * stream)558 static void stream_metadata_updated(struct bt_bap_stream *stream)
559 {
560 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
561
562 LOG_DBG("Metadata updated stream %p", stream);
563 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
564 BT_ASCS_METADATA_OP, BTP_ASCS_STATUS_SUCCESS);
565 }
566
stream_disabled(struct bt_bap_stream * stream)567 static void stream_disabled(struct bt_bap_stream *stream)
568 {
569 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
570
571 LOG_DBG("Disabled stream %p", stream);
572
573 /* Stop send timer */
574 btp_bap_audio_stream_stopped(&u_stream->audio_stream);
575
576 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
577 BT_ASCS_DISABLE_OP, BTP_ASCS_STATUS_SUCCESS);
578 }
579
stream_released(struct bt_bap_stream * stream)580 static void stream_released(struct bt_bap_stream *stream)
581 {
582 uint8_t cig_id;
583 struct bt_bap_ep_info info;
584 struct btp_bap_unicast_connection *u_conn;
585 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
586
587 LOG_DBG("Released stream %p", stream);
588
589 u_conn = &connections[u_stream->conn_id];
590
591 /* Stop send timer */
592 btp_bap_audio_stream_stopped(&u_stream->audio_stream);
593
594 if (stream->ep != NULL) {
595 (void)bt_bap_ep_get_info(stream->ep, &info);
596 if (info.dir == BT_AUDIO_DIR_SINK) {
597 u_conn->configured_sink_stream_count--;
598 } else {
599 u_conn->configured_source_stream_count--;
600 }
601 }
602
603 cig_id = u_stream->cig_id;
604 btp_bap_unicast_stream_free(u_stream);
605
606 if (cigs[cig_id].in_use == true &&
607 u_conn->configured_sink_stream_count == 0 &&
608 u_conn->configured_source_stream_count == 0) {
609 struct btp_bap_unicast_group *u_cig = &cigs[cig_id];
610
611 /* The unicast group will be deleted only at release of the last stream */
612 LOG_DBG("Deleting unicast group");
613
614 int err = bt_bap_unicast_group_delete(u_cig->cig);
615
616 if (err != 0) {
617 LOG_DBG("Unable to delete unicast group: %d", err);
618
619 return;
620 }
621
622 memset(u_cig, 0, sizeof(*u_cig));
623 }
624 }
625
stream_started(struct bt_bap_stream * stream)626 static void stream_started(struct bt_bap_stream *stream)
627 {
628 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
629 struct bt_bap_ep_info info;
630
631 /* Callback called on transition to Streaming state */
632
633 LOG_DBG("Started stream %p", stream);
634
635 btp_bap_audio_stream_started(&u_stream->audio_stream);
636
637 (void)bt_bap_ep_get_info(stream->ep, &info);
638 btp_send_ascs_ase_state_changed_ev(stream->conn, u_stream->ase_id, info.state);
639 }
640
stream_connected(struct bt_bap_stream * stream)641 static void stream_connected(struct bt_bap_stream *stream)
642 {
643 struct bt_conn_info conn_info;
644 struct bt_bap_ep_info ep_info;
645 int err;
646
647 LOG_DBG("Connected stream %p", stream);
648
649 (void)bt_bap_ep_get_info(stream->ep, &ep_info);
650 (void)bt_conn_get_info(stream->conn, &conn_info);
651 if (conn_info.role == BT_HCI_ROLE_CENTRAL && ep_info.dir == BT_AUDIO_DIR_SOURCE) {
652 /* Automatically do the receiver start ready operation for source ASEs as the client
653 */
654 err = bt_bap_stream_start(stream);
655 if (err != 0) {
656 LOG_ERR("Failed to start stream %p", stream);
657 }
658 }
659 }
660
stream_stopped(struct bt_bap_stream * stream,uint8_t reason)661 static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason)
662 {
663 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
664
665 LOG_DBG("Stopped stream %p with reason 0x%02X", stream, reason);
666
667 btp_bap_audio_stream_stopped(&u_stream->audio_stream);
668
669 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
670 BT_ASCS_STOP_OP, BTP_STATUS_SUCCESS);
671 }
672
send_stream_received_ev(struct bt_conn * conn,struct bt_bap_ep * ep,uint8_t data_len,uint8_t * data)673 static void send_stream_received_ev(struct bt_conn *conn, struct bt_bap_ep *ep,
674 uint8_t data_len, uint8_t *data)
675 {
676 struct btp_bap_stream_received_ev *ev;
677
678 tester_rsp_buffer_lock();
679 tester_rsp_buffer_allocate(sizeof(*ev) + data_len, (uint8_t **)&ev);
680
681 LOG_DBG("Stream received, ep %d, dir %d, len %d", ep->status.id, ep->dir,
682 data_len);
683
684 bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn));
685
686 ev->ase_id = ep->status.id;
687 ev->data_len = data_len;
688 memcpy(ev->data, data, data_len);
689
690 tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_STREAM_RECEIVED, ev, sizeof(*ev) + data_len);
691
692 tester_rsp_buffer_free();
693 tester_rsp_buffer_unlock();
694 }
695
stream_recv(struct bt_bap_stream * stream,const struct bt_iso_recv_info * info,struct net_buf * buf)696 static void stream_recv(struct bt_bap_stream *stream,
697 const struct bt_iso_recv_info *info,
698 struct net_buf *buf)
699 {
700 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
701
702 if (u_stream->already_sent == false) {
703 /* For now, send just a first packet, to limit the number
704 * of logs and not unnecessarily spam through btp.
705 */
706 LOG_DBG("Incoming audio on stream %p len %u", stream, buf->len);
707 u_stream->already_sent = true;
708 send_stream_received_ev(stream->conn, stream->ep, buf->len, buf->data);
709 }
710 }
711
stream_sent(struct bt_bap_stream * stream)712 static void stream_sent(struct bt_bap_stream *stream)
713 {
714 LOG_DBG("Stream %p sent", stream);
715 }
716
717 static struct bt_bap_stream_ops stream_ops = {
718 .configured = stream_configured,
719 .qos_set = stream_qos_set,
720 .enabled = stream_enabled,
721 .metadata_updated = stream_metadata_updated,
722 .disabled = stream_disabled,
723 .released = stream_released,
724 .started = stream_started,
725 .stopped = stream_stopped,
726 .recv = stream_recv,
727 .sent = stream_sent,
728 .connected = stream_connected,
729 };
730
btp_bap_unicast_stream_alloc(struct btp_bap_unicast_connection * conn)731 struct btp_bap_unicast_stream *btp_bap_unicast_stream_alloc(
732 struct btp_bap_unicast_connection *conn)
733 {
734 for (size_t i = 0; i < ARRAY_SIZE(conn->streams); i++) {
735 struct btp_bap_unicast_stream *stream = &conn->streams[i];
736
737 if (stream->in_use == false) {
738 bt_bap_stream_cb_register(stream_unicast_to_bap(stream), &stream_ops);
739 stream->in_use = true;
740
741 return stream;
742 }
743 }
744
745 return NULL;
746 }
747
unicast_client_location_cb(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_location loc)748 static void unicast_client_location_cb(struct bt_conn *conn,
749 enum bt_audio_dir dir,
750 enum bt_audio_location loc)
751 {
752 LOG_DBG("dir %u loc %X", dir, loc);
753 }
754
available_contexts_cb(struct bt_conn * conn,enum bt_audio_context snk_ctx,enum bt_audio_context src_ctx)755 static void available_contexts_cb(struct bt_conn *conn,
756 enum bt_audio_context snk_ctx,
757 enum bt_audio_context src_ctx)
758 {
759 LOG_DBG("snk ctx %u src ctx %u", snk_ctx, src_ctx);
760 }
761
config_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)762 static void config_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
763 enum bt_bap_ascs_reason reason)
764 {
765 LOG_DBG("stream %p config operation rsp_code %u reason %u", stream, rsp_code, reason);
766 }
767
qos_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)768 static void qos_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
769 enum bt_bap_ascs_reason reason)
770 {
771 LOG_DBG("stream %p qos operation rsp_code %u reason %u", stream, rsp_code, reason);
772 }
773
enable_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)774 static void enable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
775 enum bt_bap_ascs_reason reason)
776 {
777 LOG_DBG("stream %p enable operation rsp_code %u reason %u", stream, rsp_code, reason);
778 }
779
start_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)780 static void start_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
781 enum bt_bap_ascs_reason reason)
782 {
783 struct btp_bap_unicast_stream *u_stream = stream_bap_to_unicast(stream);
784
785 /* Callback called on Receiver Start Ready notification from ASE Control Point */
786
787 LOG_DBG("stream %p start operation rsp_code %u reason %u", stream, rsp_code, reason);
788 u_stream->already_sent = false;
789
790 btp_send_ascs_operation_completed_ev(stream->conn, u_stream->ase_id,
791 BT_ASCS_START_OP, BTP_STATUS_SUCCESS);
792 }
793
stop_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)794 static void stop_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
795 enum bt_bap_ascs_reason reason)
796 {
797 LOG_DBG("stream %p stop operation rsp_code %u reason %u", stream, rsp_code, reason);
798 }
799
disable_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)800 static void disable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
801 enum bt_bap_ascs_reason reason)
802 {
803 LOG_DBG("stream %p disable operation rsp_code %u reason %u", stream, rsp_code, reason);
804 }
805
metadata_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)806 static void metadata_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
807 enum bt_bap_ascs_reason reason)
808 {
809 LOG_DBG("stream %p metadata operation rsp_code %u reason %u", stream, rsp_code, reason);
810 }
811
release_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)812 static void release_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
813 enum bt_bap_ascs_reason reason)
814 {
815 LOG_DBG("stream %p release operation rsp_code %u reason %u", stream, rsp_code, reason);
816 }
817
pac_record_cb(struct bt_conn * conn,enum bt_audio_dir dir,const struct bt_audio_codec_cap * codec_cap)818 static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir,
819 const struct bt_audio_codec_cap *codec_cap)
820 {
821 LOG_DBG("");
822
823 if (codec_cap != NULL) {
824 LOG_DBG("Discovered codec capabilities %p", codec_cap);
825 print_codec_cap(codec_cap);
826 btp_send_pac_codec_found_ev(conn, codec_cap, dir);
827 }
828 }
829
btp_send_discovery_completed_ev(struct bt_conn * conn,uint8_t status)830 static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status)
831 {
832 struct btp_bap_discovery_completed_ev ev;
833
834 bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
835 ev.status = status;
836
837 tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev));
838 }
839
endpoint_cb(struct bt_conn * conn,enum bt_audio_dir dir,struct bt_bap_ep * ep)840 static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep)
841 {
842 struct btp_bap_unicast_connection *u_conn;
843
844 LOG_DBG("");
845
846 if (ep != NULL) {
847 LOG_DBG("Discovered ASE %p, id %u, dir 0x%02x", ep, ep->status.id, ep->dir);
848
849 u_conn = &connections[bt_conn_index(conn)];
850
851 if (u_conn->end_points_count >= CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT +
852 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT) {
853 LOG_DBG("Failed to cache ep %p due to configured limit: %zu", ep,
854 u_conn->end_points_count);
855
856 btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED);
857
858 return;
859 }
860
861 u_conn->end_points[u_conn->end_points_count++] = ep;
862 btp_send_ase_found_ev(conn, ep);
863
864 return;
865 }
866 }
867
discover_cb(struct bt_conn * conn,int err,enum bt_audio_dir dir)868 static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
869 {
870 LOG_DBG("");
871
872 if (err != 0 && err != BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) {
873 LOG_DBG("Discover remote ASEs failed: %d", err);
874 btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED);
875 return;
876 }
877
878 LOG_DBG("Discover complete");
879
880 if (err == BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) {
881 LOG_DBG("Discover remote ASEs completed without finding any source ASEs");
882 } else {
883 LOG_DBG("Discover remote ASEs complete: err %d", err);
884 }
885
886 if (dir == BT_AUDIO_DIR_SINK) {
887 err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SOURCE);
888
889 if (err != 0) {
890 LOG_DBG("Failed to discover source ASEs: %d", err);
891 btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_FAILED);
892 }
893
894 return;
895 }
896
897 btp_send_discovery_completed_ev(conn, BTP_BAP_DISCOVERY_STATUS_SUCCESS);
898 }
899
900 static struct bt_bap_unicast_client_cb unicast_client_cbs = {
901 .location = unicast_client_location_cb,
902 .available_contexts = available_contexts_cb,
903 .config = config_cb,
904 .qos = qos_cb,
905 .enable = enable_cb,
906 .start = start_cb,
907 .stop = stop_cb,
908 .disable = disable_cb,
909 .metadata = metadata_cb,
910 .release = release_cb,
911 .pac_record = pac_record_cb,
912 .endpoint = endpoint_cb,
913 .discover = discover_cb,
914 };
915
btp_bap_discover(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)916 uint8_t btp_bap_discover(const void *cmd, uint16_t cmd_len,
917 void *rsp, uint16_t *rsp_len)
918 {
919 const struct btp_bap_discover_cmd *cp = cmd;
920 struct bt_conn *conn;
921 struct btp_bap_unicast_connection *u_conn;
922 struct bt_conn_info conn_info;
923 int err;
924
925 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
926 if (!conn) {
927 LOG_ERR("Unknown connection");
928 return BTP_STATUS_FAILED;
929 }
930
931 u_conn = &connections[bt_conn_index(conn)];
932 (void)bt_conn_get_info(conn, &conn_info);
933
934 if (u_conn->end_points_count > 0 || conn_info.role != BT_HCI_ROLE_CENTRAL) {
935 bt_conn_unref(conn);
936
937 return BTP_STATUS_FAILED;
938 }
939
940 err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SINK);
941 if (err != 0) {
942 LOG_DBG("Failed to discover remote ASEs: %d", err);
943 bt_conn_unref(conn);
944
945 return BTP_STATUS_FAILED;
946 }
947
948 bt_conn_unref(conn);
949
950 return BTP_STATUS_SUCCESS;
951 }
952
server_stream_config(struct bt_conn * conn,struct bt_bap_stream * stream,struct bt_audio_codec_cfg * codec_cfg,struct bt_audio_codec_qos_pref * qos)953 static int server_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream,
954 struct bt_audio_codec_cfg *codec_cfg,
955 struct bt_audio_codec_qos_pref *qos)
956 {
957 int err;
958 struct bt_bap_ep_info info;
959
960 err = bt_bap_unicast_server_config_ase(conn, stream, codec_cfg, qos);
961 if (err != 0) {
962 return err;
963 }
964
965 print_codec_cfg(codec_cfg);
966 (void)bt_bap_ep_get_info(stream->ep, &info);
967
968 LOG_DBG("ASE Codec Config: ase_id %u dir %u", info.id, info.dir);
969 LOG_DBG("ASE Codec Config stream %p", stream);
970
971 return 0;
972 }
973
client_add_ase_to_cis(struct btp_bap_unicast_connection * u_conn,uint8_t ase_id,uint8_t cis_id,uint8_t cig_id)974 static uint8_t client_add_ase_to_cis(struct btp_bap_unicast_connection *u_conn, uint8_t ase_id,
975 uint8_t cis_id, uint8_t cig_id)
976 {
977 struct btp_bap_unicast_stream *stream;
978
979 if (cig_id >= CONFIG_BT_ISO_MAX_CIG ||
980 cis_id >= CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) {
981 return -EINVAL;
982 }
983
984 stream = btp_bap_unicast_stream_find(u_conn, ase_id);
985 if (stream == NULL) {
986 return -EINVAL;
987 }
988
989 LOG_DBG("Added ASE %u to CIS %u at CIG %u", ase_id, cis_id, cig_id);
990
991 stream->cig_id = cig_id;
992 stream->cis_id = cis_id;
993
994 return 0;
995 }
996
client_unicast_group_param_set(struct btp_bap_unicast_connection * u_conn,uint8_t cig_id,struct bt_bap_unicast_group_stream_pair_param * pair_params,struct bt_bap_unicast_group_stream_param ** stream_param_ptr)997 static int client_unicast_group_param_set(struct btp_bap_unicast_connection *u_conn, uint8_t cig_id,
998 struct bt_bap_unicast_group_stream_pair_param *pair_params,
999 struct bt_bap_unicast_group_stream_param **stream_param_ptr)
1000 {
1001 struct bt_bap_unicast_group_stream_param *stream_params = *stream_param_ptr;
1002
1003 for (size_t i = 0; i < ARRAY_SIZE(u_conn->streams); i++) {
1004 struct bt_bap_ep_info info;
1005 struct bt_bap_ep *ep;
1006 struct btp_bap_unicast_stream *u_stream = &u_conn->streams[i];
1007 struct bt_bap_stream *stream = stream_unicast_to_bap(u_stream);
1008
1009 if (u_stream->in_use == false || u_stream->cig_id != cig_id) {
1010 continue;
1011 }
1012
1013 ep = btp_bap_unicast_end_point_find(u_conn, u_stream->ase_id);
1014 if (ep == NULL) {
1015 return -EINVAL;
1016 }
1017
1018 stream_params->stream = stream;
1019 stream_params->qos = &cigs[u_stream->cig_id].qos[u_stream->cis_id];
1020
1021 (void)bt_bap_ep_get_info(ep, &info);
1022 if (info.dir == BT_AUDIO_DIR_SOURCE) {
1023 if (pair_params[u_stream->cis_id].rx_param != NULL) {
1024 return -EINVAL;
1025 }
1026
1027 pair_params[u_stream->cis_id].rx_param = stream_params;
1028 } else {
1029 if (pair_params[u_stream->cis_id].tx_param != NULL) {
1030 return -EINVAL;
1031 }
1032
1033 pair_params[u_stream->cis_id].tx_param = stream_params;
1034 }
1035
1036 stream_params++;
1037 }
1038
1039 *stream_param_ptr = stream_params;
1040
1041 return 0;
1042 }
1043
btp_bap_unicast_group_create(uint8_t cig_id,struct btp_bap_unicast_group ** out_unicast_group)1044 int btp_bap_unicast_group_create(uint8_t cig_id,
1045 struct btp_bap_unicast_group **out_unicast_group)
1046 {
1047 int err;
1048 struct bt_bap_unicast_group_stream_pair_param
1049 pair_params[BTP_BAP_UNICAST_MAX_STREAMS_COUNT];
1050 struct bt_bap_unicast_group_stream_param stream_params[BTP_BAP_UNICAST_MAX_STREAMS_COUNT];
1051 struct bt_bap_unicast_group_stream_param *stream_param_ptr;
1052 struct bt_bap_unicast_group_param param;
1053 size_t cis_cnt = 0;
1054
1055 (void)memset(pair_params, 0, sizeof(pair_params));
1056 (void)memset(stream_params, 0, sizeof(stream_params));
1057 *out_unicast_group = NULL;
1058
1059 if (cig_id >= CONFIG_BT_ISO_MAX_CIG) {
1060 return -EINVAL;
1061 }
1062
1063 /* API does not allow to assign a CIG ID freely, so ensure we create groups
1064 * in the right order.
1065 */
1066 for (uint8_t i = 0; i < cig_id; i++) {
1067 if (cigs[i].in_use == false) {
1068 return -EINVAL;
1069 }
1070 }
1071
1072 if (cigs[cig_id].in_use == true) {
1073 struct btp_bap_unicast_group *u_cig = &cigs[cig_id];
1074
1075 err = bt_bap_unicast_group_delete(u_cig->cig);
1076 if (err != 0) {
1077 LOG_DBG("Failed to delete the unicast group, err %d", err);
1078
1079 return BTP_STATUS_FAILED;
1080 }
1081
1082 memset(u_cig, 0, sizeof(*u_cig));
1083 }
1084
1085 stream_param_ptr = stream_params;
1086 for (size_t i = 0; i < CONFIG_BT_MAX_CONN; i++) {
1087 struct btp_bap_unicast_connection *unicast_conn = &connections[i];
1088
1089 if (unicast_conn->end_points_count == 0) {
1090 continue;
1091 }
1092
1093 /* CISes have been assigned earlier to CIGs with client_add_ase_to_cis() */
1094 err = client_unicast_group_param_set(unicast_conn, cig_id, pair_params,
1095 &stream_param_ptr);
1096 if (err != 0) {
1097 return err;
1098 }
1099 }
1100
1101 /* Count CISes to be established */
1102 for (size_t count = ARRAY_SIZE(pair_params); count > 0; --count) {
1103 size_t i = count - 1;
1104
1105 if (pair_params[i].tx_param != NULL || pair_params[i].rx_param != NULL) {
1106 cis_cnt++;
1107
1108 continue;
1109 }
1110
1111 if (cis_cnt > 0) {
1112 /* No gaps allowed */
1113 return -EINVAL;
1114 }
1115 }
1116
1117 param.params = pair_params;
1118 param.params_count = cis_cnt;
1119 param.packing = BT_ISO_PACKING_SEQUENTIAL;
1120
1121 LOG_DBG("Creating unicast group");
1122 err = bt_bap_unicast_group_create(¶m, &cigs[cig_id].cig);
1123 if (err != 0) {
1124 LOG_DBG("Could not create unicast group (err %d)", err);
1125 return -EINVAL;
1126 }
1127
1128 cigs[cig_id].in_use = true;
1129 *out_unicast_group = &cigs[cig_id];
1130
1131 return 0;
1132 }
1133
btp_bap_unicast_group_find(uint8_t cig_id)1134 struct btp_bap_unicast_group *btp_bap_unicast_group_find(uint8_t cig_id)
1135 {
1136 if (cig_id >= CONFIG_BT_ISO_MAX_CIG) {
1137 return NULL;
1138 }
1139
1140 return &cigs[cig_id];
1141 }
1142
client_configure_codec(struct btp_bap_unicast_connection * u_conn,struct bt_conn * conn,uint8_t ase_id,struct bt_audio_codec_cfg * codec_cfg)1143 static int client_configure_codec(struct btp_bap_unicast_connection *u_conn, struct bt_conn *conn,
1144 uint8_t ase_id, struct bt_audio_codec_cfg *codec_cfg)
1145 {
1146 int err;
1147 struct bt_bap_ep *ep;
1148 struct btp_bap_unicast_stream *stream;
1149
1150 stream = btp_bap_unicast_stream_find(u_conn, ase_id);
1151 if (stream == NULL) {
1152 /* Configure a new stream */
1153 stream = btp_bap_unicast_stream_alloc(u_conn);
1154 if (stream == NULL) {
1155 LOG_DBG("No streams available");
1156
1157 return -ENOMEM;
1158 }
1159
1160 if (u_conn->end_points_count == 0) {
1161 return -EINVAL;
1162 }
1163
1164 ep = btp_bap_unicast_end_point_find(u_conn, ase_id);
1165 if (ep == NULL) {
1166 return -EINVAL;
1167 }
1168
1169 memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg));
1170 err = bt_bap_stream_config(conn, stream_unicast_to_bap(stream), ep,
1171 &stream->codec_cfg);
1172 } else {
1173 /* Reconfigure a stream */
1174 memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg));
1175 err = bt_bap_stream_reconfig(stream_unicast_to_bap(stream),
1176 &stream->codec_cfg);
1177 }
1178
1179 return err;
1180 }
1181
server_configure_codec(struct btp_bap_unicast_connection * u_conn,struct bt_conn * conn,uint8_t ase_id,struct bt_audio_codec_cfg * codec_cfg)1182 static int server_configure_codec(struct btp_bap_unicast_connection *u_conn, struct bt_conn *conn,
1183 uint8_t ase_id, struct bt_audio_codec_cfg *codec_cfg)
1184 {
1185 struct btp_bap_unicast_stream *stream;
1186 int err = 0;
1187
1188 stream = btp_bap_unicast_stream_find(u_conn, ase_id);
1189 if (stream == NULL) {
1190 /* Zephyr allocates ASE instances for remote clients dynamically.
1191 * To initiate Codec Config operation autonomously in server the role,
1192 * we have to initialize all ASEs with a smaller ID first.
1193 * Fortunately, the PTS has nothing against such behavior.
1194 */
1195 for (uint8_t i = 1; i <= ase_id; i++) {
1196 stream = btp_bap_unicast_stream_find(u_conn, i);
1197 if (stream != NULL) {
1198 continue;
1199 }
1200
1201 /* Configure a new stream */
1202 stream = btp_bap_unicast_stream_alloc(u_conn);
1203 if (stream == NULL) {
1204 LOG_DBG("No streams available");
1205
1206 return -ENOMEM;
1207 }
1208
1209 memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg));
1210 err = server_stream_config(conn, stream_unicast_to_bap(stream),
1211 &stream->codec_cfg, &qos_pref);
1212 }
1213 } else {
1214 /* Reconfigure a stream */
1215 memcpy(&stream->codec_cfg, codec_cfg, sizeof(*codec_cfg));
1216 err = bt_bap_stream_reconfig(stream_unicast_to_bap(stream), &stream->codec_cfg);
1217 }
1218
1219 return err;
1220 }
1221
btp_ascs_configure_codec(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1222 uint8_t btp_ascs_configure_codec(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
1223 {
1224 int err;
1225 const struct btp_ascs_configure_codec_cmd *cp = cmd;
1226 struct bt_conn *conn;
1227 struct bt_conn_info conn_info;
1228 struct btp_bap_unicast_connection *u_conn;
1229 struct bt_audio_codec_cfg codec_cfg;
1230
1231 LOG_DBG("");
1232
1233 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1234 if (!conn) {
1235 LOG_ERR("Unknown connection");
1236 return BTP_STATUS_FAILED;
1237 }
1238
1239 u_conn = &connections[bt_conn_index(conn)];
1240
1241 (void)bt_conn_get_info(conn, &conn_info);
1242
1243 memset(&codec_cfg, 0, sizeof(codec_cfg));
1244
1245 codec_cfg.id = cp->coding_format;
1246 codec_cfg.vid = cp->vid;
1247 codec_cfg.cid = cp->cid;
1248
1249 if (cp->cc_ltvs_len != 0) {
1250 codec_cfg.data_len = cp->cc_ltvs_len;
1251 memcpy(codec_cfg.data, cp->cc_ltvs, cp->cc_ltvs_len);
1252 }
1253
1254 if (conn_info.role == BT_HCI_ROLE_CENTRAL) {
1255 err = client_configure_codec(u_conn, conn, cp->ase_id, &codec_cfg);
1256 } else {
1257 err = server_configure_codec(u_conn, conn, cp->ase_id, &codec_cfg);
1258 }
1259
1260 bt_conn_unref(conn);
1261
1262 if (err) {
1263 LOG_DBG("Failed to configure stream (err %d)", err);
1264 return BTP_STATUS_FAILED;
1265 }
1266
1267 return BTP_STATUS_SUCCESS;
1268 }
1269
btp_ascs_preconfigure_qos(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1270 uint8_t btp_ascs_preconfigure_qos(const void *cmd, uint16_t cmd_len,
1271 void *rsp, uint16_t *rsp_len)
1272 {
1273 const struct btp_ascs_preconfigure_qos_cmd *cp = cmd;
1274 struct bt_audio_codec_qos *qos;
1275
1276 LOG_DBG("");
1277
1278 qos = &cigs[cp->cig_id].qos[cp->cis_id];
1279 memset(qos, 0, sizeof(*qos));
1280
1281 qos->phy = BT_AUDIO_CODEC_QOS_2M;
1282 qos->framing = cp->framing;
1283 qos->rtn = cp->retransmission_num;
1284 qos->sdu = sys_le16_to_cpu(cp->max_sdu);
1285 qos->latency = sys_le16_to_cpu(cp->max_transport_latency);
1286 qos->interval = sys_get_le24(cp->sdu_interval);
1287 qos->pd = sys_get_le24(cp->presentation_delay);
1288
1289 return BTP_STATUS_SUCCESS;
1290 }
1291
btp_ascs_configure_qos(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1292 uint8_t btp_ascs_configure_qos(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
1293 {
1294 int err;
1295 const struct btp_ascs_configure_qos_cmd *cp = cmd;
1296 struct bt_conn_info conn_info;
1297 struct bt_conn *conn;
1298 struct btp_bap_unicast_group *out_unicast_group;
1299
1300 LOG_DBG("");
1301
1302 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1303 if (!conn) {
1304 LOG_ERR("Unknown connection");
1305
1306 return BTP_STATUS_FAILED;
1307 }
1308
1309 (void)bt_conn_get_info(conn, &conn_info);
1310 if (conn_info.role == BT_HCI_ROLE_PERIPHERAL) {
1311 bt_conn_unref(conn);
1312
1313 return BTP_STATUS_FAILED;
1314 }
1315
1316 if (cigs[cp->cig_id].in_use == false) {
1317 err = btp_bap_unicast_group_create(cp->cig_id, &out_unicast_group);
1318 if (err != 0) {
1319 LOG_DBG("Unable to create unicast group, err %d", err);
1320 bt_conn_unref(conn);
1321
1322 return BTP_STATUS_FAILED;
1323 }
1324 }
1325
1326 LOG_DBG("QoS configuring streams");
1327 err = bt_bap_stream_qos(conn, cigs[cp->cig_id].cig);
1328 bt_conn_unref(conn);
1329
1330 if (err != 0) {
1331 LOG_DBG("Unable to QoS configure streams: %d", err);
1332
1333 return BTP_STATUS_FAILED;
1334 }
1335
1336 return BTP_STATUS_SUCCESS;
1337 }
1338
btp_ascs_enable(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1339 uint8_t btp_ascs_enable(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
1340 {
1341 int err;
1342 const struct btp_ascs_enable_cmd *cp = cmd;
1343 struct btp_bap_unicast_connection *u_conn;
1344 struct btp_bap_unicast_stream *stream;
1345 struct bt_conn *conn;
1346
1347 LOG_DBG("");
1348
1349 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1350 if (!conn) {
1351 LOG_ERR("Unknown connection");
1352 return BTP_STATUS_FAILED;
1353 }
1354
1355 u_conn = &connections[bt_conn_index(conn)];
1356 bt_conn_unref(conn);
1357
1358 stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id);
1359 if (stream == NULL) {
1360 return BTP_STATUS_FAILED;
1361 }
1362
1363 LOG_DBG("Enabling stream");
1364 err = bt_bap_stream_enable(stream_unicast_to_bap(stream), NULL, 0);
1365 if (err != 0) {
1366 LOG_DBG("Could not enable stream: %d", err);
1367 return BTP_STATUS_FAILED;
1368 }
1369
1370 return BTP_STATUS_SUCCESS;
1371 }
1372
btp_ascs_disable(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1373 uint8_t btp_ascs_disable(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
1374 {
1375 int err;
1376 const struct btp_ascs_disable_cmd *cp = cmd;
1377 struct btp_bap_unicast_connection *u_conn;
1378 struct btp_bap_unicast_stream *stream;
1379 struct bt_conn *conn;
1380
1381 LOG_DBG("");
1382
1383 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1384 if (!conn) {
1385 LOG_ERR("Unknown connection");
1386 return BTP_STATUS_FAILED;
1387 }
1388
1389 u_conn = &connections[bt_conn_index(conn)];
1390 bt_conn_unref(conn);
1391
1392 stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id);
1393 if (stream == NULL) {
1394 return BTP_STATUS_FAILED;
1395 }
1396
1397 LOG_DBG("Disabling stream");
1398
1399 err = bt_bap_stream_disable(stream_unicast_to_bap(stream));
1400 if (err != 0) {
1401 LOG_DBG("Could not disable stream: %d", err);
1402 return BTP_STATUS_FAILED;
1403 }
1404
1405 return BTP_STATUS_SUCCESS;
1406 }
1407
btp_ascs_receiver_start_ready(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1408 uint8_t btp_ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len,
1409 void *rsp, uint16_t *rsp_len)
1410 {
1411 int err;
1412 const struct btp_ascs_receiver_start_ready_cmd *cp = cmd;
1413 struct btp_bap_unicast_connection *u_conn;
1414 struct btp_bap_unicast_stream *stream;
1415 struct bt_bap_stream *bap_stream;
1416 struct bt_bap_ep_info info;
1417 struct bt_conn *conn;
1418
1419 LOG_DBG("");
1420
1421 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1422 if (!conn) {
1423 LOG_ERR("Unknown connection");
1424 return BTP_STATUS_FAILED;
1425 }
1426
1427 u_conn = &connections[bt_conn_index(conn)];
1428 bt_conn_unref(conn);
1429
1430 stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id);
1431 if (stream == NULL) {
1432 return BTP_STATUS_FAILED;
1433 }
1434
1435 bap_stream = stream_unicast_to_bap(stream);
1436 (void)bt_bap_ep_get_info(bap_stream->ep, &info);
1437 if (info.state == BT_BAP_EP_STATE_STREAMING) {
1438 /* Already started */
1439 return BTP_STATUS_SUCCESS;
1440 }
1441
1442 LOG_DBG("Starting stream %p, ep %u, dir %u", bap_stream, cp->ase_id, info.dir);
1443
1444 while (true) {
1445 err = bt_bap_stream_connect(bap_stream);
1446 if (err == -EBUSY) {
1447 /* TODO: How to determine if a controller is ready again after
1448 * bt_bap_stream_start? In AC 6(i) tests the PTS sends Receiver Start Ready
1449 * only after all CISes are established.
1450 */
1451 k_sleep(K_MSEC(1000));
1452 continue;
1453 } else if (err != 0 && err != -EALREADY) {
1454 LOG_DBG("Could not connect stream: %d", err);
1455 return BTP_STATUS_FAILED;
1456 }
1457
1458 break;
1459 };
1460
1461 return BTP_STATUS_SUCCESS;
1462 }
1463
btp_ascs_receiver_stop_ready(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1464 uint8_t btp_ascs_receiver_stop_ready(const void *cmd, uint16_t cmd_len,
1465 void *rsp, uint16_t *rsp_len)
1466 {
1467 int err;
1468 const struct btp_ascs_receiver_stop_ready_cmd *cp = cmd;
1469 struct btp_bap_unicast_connection *u_conn;
1470 struct btp_bap_unicast_stream *stream;
1471 struct bt_conn *conn;
1472
1473 LOG_DBG("");
1474
1475 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1476 if (!conn) {
1477 LOG_ERR("Unknown connection");
1478 return BTP_STATUS_FAILED;
1479 }
1480
1481 u_conn = &connections[bt_conn_index(conn)];
1482 bt_conn_unref(conn);
1483
1484 stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id);
1485 if (stream == NULL) {
1486 return BTP_STATUS_FAILED;
1487 }
1488
1489 LOG_DBG("Stopping stream");
1490 err = bt_bap_stream_stop(stream_unicast_to_bap(stream));
1491 if (err != 0) {
1492 LOG_DBG("Could not stop stream: %d", err);
1493 return BTP_STATUS_FAILED;
1494 }
1495
1496 return BTP_STATUS_SUCCESS;
1497 }
1498
btp_ascs_release(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1499 uint8_t btp_ascs_release(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
1500 {
1501 int err;
1502 const struct btp_ascs_release_cmd *cp = cmd;
1503 struct btp_bap_unicast_connection *u_conn;
1504 struct btp_bap_unicast_stream *stream;
1505 struct bt_conn *conn;
1506
1507 LOG_DBG("");
1508
1509 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1510 if (!conn) {
1511 LOG_ERR("Unknown connection");
1512 return BTP_STATUS_FAILED;
1513 }
1514
1515 u_conn = &connections[bt_conn_index(conn)];
1516 bt_conn_unref(conn);
1517
1518 stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id);
1519 if (stream == NULL) {
1520 return BTP_STATUS_FAILED;
1521 }
1522
1523 LOG_DBG("Releasing stream");
1524 err = bt_bap_stream_release(stream_unicast_to_bap(stream));
1525 if (err != 0) {
1526 LOG_DBG("Unable to release stream, err %d", err);
1527 return BTP_STATUS_FAILED;
1528 }
1529
1530 return BTP_STATUS_SUCCESS;
1531 }
1532
btp_ascs_update_metadata(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1533 uint8_t btp_ascs_update_metadata(const void *cmd, uint16_t cmd_len,
1534 void *rsp, uint16_t *rsp_len)
1535 {
1536 const uint8_t meta[] = {
1537 BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
1538 BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_ANY)),
1539 };
1540 const struct btp_ascs_update_metadata_cmd *cp = cmd;
1541 struct btp_bap_unicast_connection *u_conn;
1542 struct btp_bap_unicast_stream *stream;
1543 struct bt_conn *conn;
1544 int err;
1545
1546 LOG_DBG("");
1547
1548 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1549 if (!conn) {
1550 LOG_ERR("Unknown connection");
1551 return BTP_STATUS_FAILED;
1552 }
1553
1554 u_conn = &connections[bt_conn_index(conn)];
1555 bt_conn_unref(conn);
1556
1557 stream = btp_bap_unicast_stream_find(u_conn, cp->ase_id);
1558 if (stream == NULL) {
1559 return BTP_STATUS_FAILED;
1560 }
1561
1562 LOG_DBG("Updating stream metadata");
1563 err = bt_bap_stream_metadata(stream_unicast_to_bap(stream), meta, ARRAY_SIZE(meta));
1564 if (err != 0) {
1565 LOG_DBG("Failed to update stream metadata, err %d", err);
1566 return BTP_STATUS_FAILED;
1567 }
1568
1569 return BTP_STATUS_SUCCESS;
1570 }
1571
btp_ascs_add_ase_to_cis(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)1572 uint8_t btp_ascs_add_ase_to_cis(const void *cmd, uint16_t cmd_len,
1573 void *rsp, uint16_t *rsp_len)
1574 {
1575 int err;
1576 struct bt_conn *conn;
1577 struct btp_bap_unicast_connection *u_conn;
1578 struct bt_conn_info conn_info;
1579 const struct btp_ascs_add_ase_to_cis *cp = cmd;
1580
1581 LOG_DBG("");
1582
1583 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
1584 if (!conn) {
1585 LOG_ERR("Unknown connection");
1586
1587 return BTP_STATUS_FAILED;
1588 }
1589
1590 (void)bt_conn_get_info(conn, &conn_info);
1591 if (conn_info.role == BT_HCI_ROLE_PERIPHERAL) {
1592 bt_conn_unref(conn);
1593
1594 return BTP_STATUS_FAILED;
1595 }
1596
1597 u_conn = &connections[bt_conn_index(conn)];
1598 bt_conn_unref(conn);
1599
1600 err = client_add_ase_to_cis(u_conn, cp->ase_id, cp->cis_id, cp->cig_id);
1601
1602 return BTP_STATUS_VAL(err);
1603 }
1604
btp_bap_unicast_conn_get(size_t conn_index)1605 struct btp_bap_unicast_connection *btp_bap_unicast_conn_get(size_t conn_index)
1606 {
1607 return &connections[conn_index];
1608 }
1609
connected(struct bt_conn * conn,uint8_t err)1610 static void connected(struct bt_conn *conn, uint8_t err)
1611 {
1612 struct btp_bap_unicast_connection *u_conn;
1613 char addr[BT_ADDR_LE_STR_LEN];
1614
1615 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
1616
1617 if (err != 0) {
1618 LOG_DBG("Failed to connect to %s (%u)", addr, err);
1619 return;
1620 }
1621
1622 LOG_DBG("Connected: %s", addr);
1623
1624 u_conn = &connections[bt_conn_index(conn)];
1625 memset(u_conn, 0, sizeof(*u_conn));
1626 bt_addr_le_copy(&u_conn->address, bt_conn_get_dst(conn));
1627 }
1628
disconnected(struct bt_conn * conn,uint8_t reason)1629 static void disconnected(struct bt_conn *conn, uint8_t reason)
1630 {
1631 char addr[BT_ADDR_LE_STR_LEN];
1632
1633 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
1634
1635 LOG_DBG("Disconnected: %s (reason 0x%02x)", addr, reason);
1636 }
1637
1638 static struct bt_conn_cb conn_callbacks = {
1639 .connected = connected,
1640 .disconnected = disconnected,
1641 };
1642
1643 static bool unicast_inited;
1644
btp_bap_unicast_init(void)1645 int btp_bap_unicast_init(void)
1646 {
1647 int err;
1648
1649 if (unicast_inited) {
1650 return 0;
1651 }
1652
1653 (void)memset(connections, 0, sizeof(connections));
1654
1655 err = bt_bap_unicast_server_register_cb(&unicast_server_cb);
1656 if (err != 0) {
1657 LOG_DBG("Failed to register client callbacks: %d", err);
1658 return err;
1659 }
1660
1661 err = bt_bap_unicast_client_register_cb(&unicast_client_cbs);
1662 if (err != 0) {
1663 LOG_DBG("Failed to register client callbacks: %d", err);
1664 return err;
1665 }
1666
1667 bt_conn_cb_register(&conn_callbacks);
1668
1669 unicast_inited = true;
1670
1671 return 0;
1672 }
1673