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 				  &param);
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(&param, &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