1 /** @file
2  * @brief Advance Audio Distribution Profile.
3  */
4 
5 /*
6  * Copyright (c) 2015-2016 Intel Corporation
7  * Copyright 2021,2024 NXP
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #include <zephyr/kernel.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <zephyr/sys/atomic.h>
16 #include <zephyr/sys/byteorder.h>
17 #include <zephyr/sys/util.h>
18 #include <zephyr/sys/printk.h>
19 
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/l2cap.h>
22 #include <zephyr/bluetooth/classic/avdtp.h>
23 #include <zephyr/bluetooth/classic/a2dp_codec_sbc.h>
24 #include <zephyr/bluetooth/classic/a2dp.h>
25 
26 #include "common/assert.h"
27 
28 #define A2DP_SBC_PAYLOAD_TYPE (0x60U)
29 
30 #define A2DP_AVDTP(_avdtp) CONTAINER_OF(_avdtp, struct bt_a2dp, session)
31 #define DISCOVER_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_discover_params, req)
32 #define DISCOVER_PARAM(_discover_param)                                                            \
33 	CONTAINER_OF(_discover_param, struct bt_a2dp, discover_param)
34 #define GET_CAP_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_get_capabilities_params, req)
35 #define GET_CAP_PARAM(_get_cap_param)                                                              \
36 	CONTAINER_OF(_get_cap_param, struct bt_a2dp, get_capabilities_param)
37 #define SET_CONF_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_set_configuration_params, req)
38 #define SET_CONF_PARAM(_set_conf_param)                                                            \
39 	CONTAINER_OF(_set_conf_param, struct bt_a2dp, set_config_param)
40 #define CTRL_REQ(_req)          CONTAINER_OF(_req, struct bt_avdtp_ctrl_params, req)
41 #define CTRL_PARAM(_ctrl_param) CONTAINER_OF(_ctrl_param, struct bt_a2dp, ctrl_param)
42 
43 #include "host/hci_core.h"
44 #include "host/conn_internal.h"
45 #include "host/l2cap_internal.h"
46 #include "avdtp_internal.h"
47 #include "a2dp_internal.h"
48 
49 #define LOG_LEVEL CONFIG_BT_A2DP_LOG_LEVEL
50 #include <zephyr/logging/log.h>
51 LOG_MODULE_REGISTER(bt_a2dp);
52 
53 #define A2DP_NO_SPACE (-1)
54 
55 enum bt_a2dp_internal_state {
56 	INTERNAL_STATE_IDLE = 0,
57 	INTERNAL_STATE_AVDTP_CONNECTED,
58 };
59 
60 struct bt_a2dp {
61 	struct bt_avdtp session;
62 	struct bt_avdtp_discover_params discover_param;
63 	struct bt_a2dp_discover_param *discover_cb_param;
64 	struct bt_avdtp_get_capabilities_params get_capabilities_param;
65 	struct bt_avdtp_set_configuration_params set_config_param;
66 	struct bt_avdtp_ctrl_params ctrl_param;
67 	uint8_t get_cap_index;
68 	enum bt_a2dp_internal_state a2dp_state;
69 	uint8_t peer_seps_count;
70 };
71 
72 static struct bt_a2dp_cb *a2dp_cb;
73 /* Connections */
74 static struct bt_a2dp connection[CONFIG_BT_MAX_CONN];
75 
76 static int bt_a2dp_get_sep_caps(struct bt_a2dp *a2dp);
77 
a2dp_get_connection(struct bt_conn * conn)78 static struct bt_a2dp *a2dp_get_connection(struct bt_conn *conn)
79 {
80 	struct bt_a2dp *a2dp = &connection[bt_conn_index(conn)];
81 
82 	if (a2dp->session.br_chan.chan.conn == NULL) {
83 		/* Clean the memory area before returning */
84 		(void)memset(a2dp, 0, sizeof(struct bt_a2dp));
85 	}
86 
87 	return a2dp;
88 }
89 
90 /* The AVDTP L2CAP signal channel established */
a2dp_connected(struct bt_avdtp * session)91 static void a2dp_connected(struct bt_avdtp *session)
92 {
93 	struct bt_a2dp *a2dp = A2DP_AVDTP(session);
94 
95 	a2dp->a2dp_state = INTERNAL_STATE_AVDTP_CONNECTED;
96 
97 	/* notify a2dp app the connection. */
98 	if ((a2dp_cb != NULL) && (a2dp_cb->connected != NULL)) {
99 		a2dp_cb->connected(a2dp, 0);
100 	}
101 }
102 
103 /* The AVDTP L2CAP signal channel released */
a2dp_disconnected(struct bt_avdtp * session)104 static void a2dp_disconnected(struct bt_avdtp *session)
105 {
106 	struct bt_a2dp *a2dp = A2DP_AVDTP(session);
107 
108 	/* notify a2dp app the disconnection. */
109 	if ((a2dp_cb != NULL) && (a2dp_cb->disconnected != NULL)) {
110 		a2dp_cb->disconnected(a2dp);
111 	}
112 }
113 
114 /* avdtp alloc buf from upper layer */
a2dp_alloc_buf(struct bt_avdtp * session)115 static struct net_buf *a2dp_alloc_buf(struct bt_avdtp *session)
116 {
117 	return NULL;
118 }
119 
a2dp_discovery_ind(struct bt_avdtp * session,uint8_t * errcode)120 static int a2dp_discovery_ind(struct bt_avdtp *session, uint8_t *errcode)
121 {
122 	*errcode = 0;
123 	return 0;
124 }
125 
a2dp_get_capabilities_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,struct net_buf * rsp_buf,uint8_t * errcode)126 static int a2dp_get_capabilities_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep,
127 				     struct net_buf *rsp_buf, uint8_t *errcode)
128 {
129 	struct bt_a2dp_ep *ep;
130 
131 	__ASSERT(sep, "Invalid sep");
132 	*errcode = 0;
133 	/* Service Category: Media Transport */
134 	net_buf_add_u8(rsp_buf, BT_AVDTP_SERVICE_MEDIA_TRANSPORT);
135 	net_buf_add_u8(rsp_buf, 0);
136 	/* Service Category: Media Codec */
137 	net_buf_add_u8(rsp_buf, BT_AVDTP_SERVICE_MEDIA_CODEC);
138 	ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
139 	/* Length Of Service Capability */
140 	net_buf_add_u8(rsp_buf, ep->codec_cap->len + 2U);
141 	/* Media Type */
142 	net_buf_add_u8(rsp_buf, sep->sep_info.media_type << 4U);
143 	/* Media Codec Type */
144 	net_buf_add_u8(rsp_buf, ep->codec_type);
145 	/* Codec Info Element */
146 	net_buf_add_mem(rsp_buf, &ep->codec_cap->codec_ie[0], ep->codec_cap->len);
147 	return 0;
148 }
149 
a2dp_process_config_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t int_seid,struct net_buf * buf,uint8_t * errcode,bool reconfig)150 static int a2dp_process_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep,
151 				   uint8_t int_seid, struct net_buf *buf, uint8_t *errcode,
152 				   bool reconfig)
153 {
154 	struct bt_a2dp *a2dp = A2DP_AVDTP(session);
155 	struct bt_a2dp_ep *ep;
156 	struct bt_a2dp_stream *stream = NULL;
157 	struct bt_a2dp_stream_ops *ops;
158 	uint8_t codec_type;
159 	uint8_t *codec_info_element;
160 	uint16_t codec_info_element_len;
161 	struct bt_a2dp_codec_cfg cfg;
162 	struct bt_a2dp_codec_ie codec_config;
163 	uint8_t rsp_err_code;
164 	int err;
165 
166 	*errcode = 0;
167 
168 	__ASSERT(sep, "Invalid sep");
169 
170 	ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
171 
172 	/* parse the configuration */
173 	codec_info_element_len = 4U;
174 	err = bt_avdtp_parse_capability_codec(buf, &codec_type, &codec_info_element,
175 					      &codec_info_element_len);
176 	if (err) {
177 		*errcode = BT_AVDTP_BAD_ACP_SEID;
178 		return -EINVAL;
179 	}
180 
181 	if (codec_type == BT_A2DP_SBC) {
182 		struct bt_a2dp_codec_sbc_params *sbc_set;
183 		struct bt_a2dp_codec_sbc_params *sbc;
184 
185 		if (codec_info_element_len != 4U) {
186 			*errcode = BT_AVDTP_BAD_ACP_SEID;
187 			return -EINVAL;
188 		}
189 
190 		sbc_set = (struct bt_a2dp_codec_sbc_params *)codec_info_element;
191 		sbc = (struct bt_a2dp_codec_sbc_params *)&ep->codec_cap->codec_ie[0];
192 		if (((BT_A2DP_SBC_SAMP_FREQ(sbc_set) & BT_A2DP_SBC_SAMP_FREQ(sbc)) == 0) ||
193 		    ((BT_A2DP_SBC_CHAN_MODE(sbc_set) & BT_A2DP_SBC_CHAN_MODE(sbc)) == 0) ||
194 		    ((BT_A2DP_SBC_BLK_LEN(sbc_set) & BT_A2DP_SBC_BLK_LEN(sbc)) == 0) ||
195 		    ((BT_A2DP_SBC_SUB_BAND(sbc_set) & BT_A2DP_SBC_SUB_BAND(sbc)) == 0) ||
196 		    ((BT_A2DP_SBC_ALLOC_MTHD(sbc_set) & BT_A2DP_SBC_ALLOC_MTHD(sbc)) == 0)) {
197 			*errcode = BT_AVDTP_BAD_ACP_SEID;
198 			return -EINVAL;
199 		}
200 	}
201 
202 	/* For reconfig, ep->stream must already be valid, callback can be NULL as default accept.
203 	 * For !reconfig, config_req must be set to get stream from upper layer
204 	 */
205 	if (reconfig) {
206 		stream = ep->stream;
207 		if (stream == NULL) {
208 			*errcode = BT_AVDTP_BAD_ACP_SEID;
209 			return -EINVAL;
210 		}
211 
212 		if (a2dp_cb == NULL || a2dp_cb->reconfig_req == NULL) {
213 			goto process_done;
214 		}
215 	} else if (a2dp_cb == NULL || a2dp_cb->config_req == NULL) {
216 		*errcode = BT_AVDTP_BAD_ACP_SEID;
217 		return -EINVAL;
218 	}
219 
220 	cfg.codec_config = &codec_config;
221 	cfg.codec_config->len = codec_info_element_len;
222 	memcpy(&cfg.codec_config->codec_ie[0], codec_info_element,
223 	       (codec_info_element_len > BT_A2DP_MAX_IE_LENGTH ? BT_A2DP_MAX_IE_LENGTH
224 							       : codec_info_element_len));
225 	if (!reconfig) {
226 		err = a2dp_cb->config_req(a2dp, ep, &cfg, &stream, &rsp_err_code);
227 		if (!err && stream) {
228 			stream->a2dp = a2dp;
229 			stream->local_ep = ep;
230 			stream->remote_ep_id = int_seid;
231 			stream->remote_ep = NULL;
232 			stream->codec_config = *cfg.codec_config;
233 			ep->stream = stream;
234 		} else {
235 			*errcode = rsp_err_code != 0 ? rsp_err_code : BT_AVDTP_BAD_ACP_SEID;
236 		}
237 	} else {
238 		err = a2dp_cb->reconfig_req(stream, &cfg, &rsp_err_code);
239 		if (err) {
240 			*errcode = rsp_err_code;
241 		}
242 	}
243 
244 process_done:
245 	if (*errcode == 0) {
246 		ops = stream->ops;
247 		if ((ops != NULL) && (ops->configured != NULL)) {
248 			ops->configured(stream);
249 		}
250 	}
251 
252 	return (*errcode == 0) ? 0 : -EINVAL;
253 }
254 
a2dp_set_config_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t int_seid,struct net_buf * buf,uint8_t * errcode)255 static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t int_seid,
256 			       struct net_buf *buf, uint8_t *errcode)
257 {
258 	__ASSERT(sep, "Invalid sep");
259 	return a2dp_process_config_ind(session, sep, int_seid, buf, errcode, false);
260 }
261 
a2dp_re_config_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t int_seid,struct net_buf * buf,uint8_t * errcode)262 static int a2dp_re_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t int_seid,
263 			      struct net_buf *buf, uint8_t *errcode)
264 {
265 	__ASSERT(sep, "Invalid sep");
266 	return a2dp_process_config_ind(session, sep, int_seid, buf, errcode, true);
267 }
268 
269 #if defined(CONFIG_BT_A2DP_SINK)
bt_a2dp_media_data_callback(struct bt_avdtp_sep * sep,struct net_buf * buf)270 static void bt_a2dp_media_data_callback(struct bt_avdtp_sep *sep, struct net_buf *buf)
271 {
272 	struct bt_avdtp_media_hdr *media_hdr;
273 	struct bt_a2dp_ep *ep;
274 	struct bt_a2dp_stream *stream;
275 
276 	__ASSERT(sep, "Invalid sep");
277 	ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
278 	if (ep->stream == NULL || buf->len < sizeof(*media_hdr)) {
279 		return;
280 	}
281 
282 	stream = ep->stream;
283 	media_hdr = net_buf_pull_mem(buf, sizeof(*media_hdr));
284 
285 	stream->ops->recv(stream, buf, sys_get_be16((uint8_t *)&media_hdr->sequence_number),
286 			  sys_get_be32((uint8_t *)&media_hdr->time_stamp));
287 }
288 #endif
289 
290 typedef int (*bt_a2dp_ctrl_req_cb)(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code);
291 typedef void (*bt_a2dp_ctrl_done_cb)(struct bt_a2dp_stream *stream);
292 
a2dp_ctrl_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t * errcode,bt_a2dp_ctrl_req_cb req_cb,bt_a2dp_ctrl_done_cb done_cb,bool clear_stream)293 static int a2dp_ctrl_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode,
294 			 bt_a2dp_ctrl_req_cb req_cb, bt_a2dp_ctrl_done_cb done_cb,
295 			 bool clear_stream)
296 {
297 	struct bt_a2dp_ep *ep;
298 	struct bt_a2dp_stream *stream;
299 
300 	*errcode = 0;
301 	ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
302 	if (ep->stream == NULL) {
303 		*errcode = BT_AVDTP_BAD_ACP_SEID;
304 		return -EINVAL;
305 	}
306 
307 	stream = ep->stream;
308 
309 	if (req_cb != NULL) {
310 		uint8_t rsp_err_code;
311 		int err;
312 
313 		err = req_cb(stream, &rsp_err_code);
314 		if (err) {
315 			*errcode = rsp_err_code;
316 		}
317 	}
318 
319 	if (*errcode == 0) {
320 		if (clear_stream) {
321 			ep->stream = NULL;
322 		}
323 
324 		if (done_cb != NULL) {
325 			done_cb(stream);
326 		}
327 	}
328 
329 	return (*errcode == 0) ? 0 : -EINVAL;
330 }
331 
a2dp_open_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t * errcode)332 static int a2dp_open_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
333 {
334 	struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
335 	bt_a2dp_ctrl_req_cb req_cb;
336 	bt_a2dp_ctrl_done_cb done_cb;
337 
338 	__ASSERT(sep, "Invalid sep");
339 	req_cb = a2dp_cb != NULL ? a2dp_cb->establish_req : NULL;
340 	done_cb = (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->established
341 								  : NULL;
342 	return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false);
343 }
344 
a2dp_start_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t * errcode)345 static int a2dp_start_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
346 {
347 	struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
348 	bt_a2dp_ctrl_req_cb req_cb;
349 	bt_a2dp_ctrl_done_cb done_cb;
350 
351 	__ASSERT(sep, "Invalid sep");
352 	req_cb = a2dp_cb != NULL ? a2dp_cb->start_req : NULL;
353 	done_cb = (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->started : NULL;
354 	return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false);
355 }
356 
a2dp_suspend_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t * errcode)357 static int a2dp_suspend_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
358 {
359 	struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
360 	bt_a2dp_ctrl_req_cb req_cb;
361 	bt_a2dp_ctrl_done_cb done_cb;
362 
363 	__ASSERT(sep, "Invalid sep");
364 	req_cb = a2dp_cb != NULL ? a2dp_cb->suspend_req : NULL;
365 	done_cb =
366 		(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->suspended : NULL;
367 	return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false);
368 }
369 
a2dp_close_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t * errcode)370 static int a2dp_close_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
371 {
372 	struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
373 	bt_a2dp_ctrl_req_cb req_cb;
374 	bt_a2dp_ctrl_done_cb done_cb;
375 
376 	__ASSERT(sep, "Invalid sep");
377 	req_cb = a2dp_cb != NULL ? a2dp_cb->release_req : NULL;
378 	done_cb =
379 		(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->released : NULL;
380 	return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, true);
381 }
382 
a2dp_abort_ind(struct bt_avdtp * session,struct bt_avdtp_sep * sep,uint8_t * errcode)383 static int a2dp_abort_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
384 {
385 	struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
386 	bt_a2dp_ctrl_req_cb req_cb;
387 	bt_a2dp_ctrl_done_cb done_cb;
388 
389 	__ASSERT(sep, "Invalid sep");
390 	req_cb = a2dp_cb != NULL ? a2dp_cb->abort_req : NULL;
391 	done_cb = (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->aborted : NULL;
392 	return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, true);
393 }
394 
bt_a2dp_set_config_cb(struct bt_avdtp_req * req,struct net_buf * buf)395 static int bt_a2dp_set_config_cb(struct bt_avdtp_req *req, struct net_buf *buf)
396 {
397 	struct bt_a2dp *a2dp = SET_CONF_PARAM(SET_CONF_REQ(req));
398 	struct bt_a2dp_ep *ep;
399 	struct bt_a2dp_stream *stream;
400 	struct bt_a2dp_stream_ops *ops;
401 
402 	ep = CONTAINER_OF(a2dp->set_config_param.sep, struct bt_a2dp_ep, sep);
403 	if (ep->stream == NULL) {
404 		return -EINVAL;
405 	}
406 
407 	if ((ep->stream == NULL) || (SET_CONF_REQ(req) != &a2dp->set_config_param)) {
408 		return -EINVAL;
409 	}
410 
411 	stream = ep->stream;
412 	LOG_DBG("SET CONFIGURATION result:%d", req->status);
413 
414 	if ((a2dp_cb != NULL) && (a2dp_cb->config_rsp != NULL)) {
415 		a2dp_cb->config_rsp(stream, req->status);
416 	}
417 
418 	ops = stream->ops;
419 	if ((!req->status) && (ops->configured != NULL)) {
420 		ops->configured(stream);
421 	}
422 	return 0;
423 }
424 
bt_a2dp_get_capabilities_cb(struct bt_avdtp_req * req,struct net_buf * buf)425 static int bt_a2dp_get_capabilities_cb(struct bt_avdtp_req *req, struct net_buf *buf)
426 {
427 	int err;
428 	uint8_t *codec_info_element;
429 	struct bt_a2dp *a2dp = GET_CAP_PARAM(GET_CAP_REQ(req));
430 	uint16_t codec_info_element_len;
431 	uint8_t codec_type;
432 	uint8_t user_ret;
433 
434 	if (GET_CAP_REQ(req) != &a2dp->get_capabilities_param || buf == NULL) {
435 		return -EINVAL;
436 	}
437 
438 	LOG_DBG("GET CAPABILITIES result:%d", req->status);
439 	if (req->status) {
440 		if ((a2dp->discover_cb_param != NULL) && (a2dp->discover_cb_param->cb != NULL)) {
441 			a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
442 			a2dp->discover_cb_param = NULL;
443 		}
444 		return 0;
445 	}
446 
447 	err = bt_avdtp_parse_capability_codec(buf, &codec_type,
448 					      &codec_info_element, &codec_info_element_len);
449 	if (err) {
450 		LOG_DBG("codec capability parsing fail");
451 		return 0;
452 	}
453 
454 	if (codec_info_element_len > BT_A2DP_MAX_IE_LENGTH) {
455 		codec_info_element_len = BT_A2DP_MAX_IE_LENGTH;
456 	}
457 
458 	if ((a2dp->discover_cb_param != NULL) && (a2dp->discover_cb_param->cb != NULL)) {
459 		struct bt_a2dp_ep *ep = NULL;
460 		struct bt_a2dp_ep_info *info = &a2dp->discover_cb_param->info;
461 
462 		info->codec_type = codec_type;
463 		info->sep_info = &a2dp->discover_cb_param->seps_info[a2dp->get_cap_index];
464 		memcpy(&info->codec_cap.codec_ie, codec_info_element, codec_info_element_len);
465 		info->codec_cap.len = codec_info_element_len;
466 		user_ret = a2dp->discover_cb_param->cb(a2dp, info, &ep);
467 
468 		if (ep != NULL) {
469 			ep->codec_type = info->codec_type;
470 			ep->sep.sep_info = *info->sep_info;
471 			*ep->codec_cap = info->codec_cap;
472 			ep->stream = NULL;
473 		}
474 
475 		if (user_ret == BT_A2DP_DISCOVER_EP_CONTINUE) {
476 			if (bt_a2dp_get_sep_caps(a2dp) != 0) {
477 				a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
478 				a2dp->discover_cb_param = NULL;
479 			}
480 		} else {
481 			a2dp->discover_cb_param = NULL;
482 		}
483 	}
484 
485 	return 0;
486 }
487 
bt_a2dp_get_sep_caps(struct bt_a2dp * a2dp)488 static int bt_a2dp_get_sep_caps(struct bt_a2dp *a2dp)
489 {
490 	int err;
491 
492 	if ((a2dp->discover_cb_param == NULL) || (a2dp->discover_cb_param->cb == NULL)) {
493 		return -EINVAL;
494 	}
495 
496 	if (a2dp->get_cap_index == 0xFFu) {
497 		a2dp->get_cap_index = 0U;
498 	} else {
499 		a2dp->get_cap_index++;
500 	}
501 
502 	for (; a2dp->get_cap_index < a2dp->peer_seps_count; a2dp->get_cap_index++) {
503 		if (a2dp->discover_cb_param->seps_info[a2dp->get_cap_index].media_type ==
504 		    BT_AVDTP_AUDIO) {
505 			memset(&a2dp->get_capabilities_param, 0U,
506 			       sizeof(a2dp->get_capabilities_param));
507 			a2dp->get_capabilities_param.req.func = bt_a2dp_get_capabilities_cb;
508 			a2dp->get_capabilities_param.stream_endpoint_id =
509 				a2dp->discover_cb_param->seps_info[a2dp->get_cap_index].id;
510 			err = bt_avdtp_get_capabilities(&a2dp->session,
511 							&a2dp->get_capabilities_param);
512 
513 			if (err) {
514 				LOG_DBG("AVDTP get codec_cap failed");
515 				a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
516 				a2dp->discover_cb_param = NULL;
517 			}
518 
519 			return 0;
520 		}
521 	}
522 	return -EINVAL;
523 }
524 
bt_a2dp_discover_cb(struct bt_avdtp_req * req,struct net_buf * buf)525 static int bt_a2dp_discover_cb(struct bt_avdtp_req *req, struct net_buf *buf)
526 {
527 	struct bt_a2dp *a2dp = DISCOVER_PARAM(DISCOVER_REQ(req));
528 	struct bt_avdtp_sep_info *sep_info;
529 	int err;
530 
531 	LOG_DBG("DISCOVER result:%d", req->status);
532 	if (a2dp->discover_cb_param == NULL || buf == NULL) {
533 		return -EINVAL;
534 	}
535 
536 	a2dp->peer_seps_count = 0U;
537 
538 	if (!(req->status)) {
539 		if (a2dp->discover_cb_param->sep_count == 0) {
540 			if (a2dp->discover_cb_param->cb != NULL) {
541 				a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
542 				a2dp->discover_cb_param = NULL;
543 			}
544 
545 			return -EINVAL;
546 		}
547 
548 		do {
549 			sep_info = &a2dp->discover_cb_param->seps_info[a2dp->peer_seps_count];
550 			err = bt_avdtp_parse_sep(buf, sep_info);
551 
552 			if (err) {
553 				break;
554 			}
555 
556 			a2dp->peer_seps_count++;
557 			LOG_DBG("id:%d, inuse:%d, media_type:%d, tsep:%d, ", sep_info->id,
558 				sep_info->inuse, sep_info->media_type, sep_info->tsep);
559 		} while (a2dp->peer_seps_count < a2dp->discover_cb_param->sep_count);
560 
561 		/* trigger the getting capability */
562 		a2dp->get_cap_index = 0xFFu;
563 		if (bt_a2dp_get_sep_caps(a2dp) != 0) {
564 			/* the peer_seps' caps is done.*/
565 			if (a2dp->discover_cb_param->cb != NULL) {
566 				a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
567 				a2dp->discover_cb_param = NULL;
568 			}
569 		}
570 	} else {
571 		if (a2dp->discover_cb_param->cb != NULL) {
572 			a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
573 			a2dp->discover_cb_param = NULL;
574 		}
575 	}
576 
577 	return 0;
578 }
579 
bt_a2dp_discover(struct bt_a2dp * a2dp,struct bt_a2dp_discover_param * param)580 int bt_a2dp_discover(struct bt_a2dp *a2dp, struct bt_a2dp_discover_param *param)
581 {
582 	int err;
583 
584 	if ((a2dp == NULL) || (param == NULL)) {
585 		return -EINVAL;
586 	}
587 
588 	if (a2dp->a2dp_state != INTERNAL_STATE_AVDTP_CONNECTED) {
589 		return -EIO;
590 	}
591 
592 	if (a2dp->discover_cb_param != NULL) {
593 		return -EBUSY;
594 	}
595 
596 	memset(&a2dp->discover_cb_param, 0U, sizeof(a2dp->discover_cb_param));
597 	a2dp->discover_cb_param = param;
598 	a2dp->discover_param.req.func = bt_a2dp_discover_cb;
599 
600 	err = bt_avdtp_discover(&a2dp->session, &a2dp->discover_param);
601 	if (err) {
602 		if (a2dp->discover_cb_param->cb != NULL) {
603 			a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
604 		}
605 
606 		a2dp->discover_cb_param = NULL;
607 	}
608 
609 	return err;
610 }
611 
bt_a2dp_stream_cb_register(struct bt_a2dp_stream * stream,struct bt_a2dp_stream_ops * ops)612 void bt_a2dp_stream_cb_register(struct bt_a2dp_stream *stream, struct bt_a2dp_stream_ops *ops)
613 {
614 	__ASSERT_NO_MSG(stream);
615 	stream->ops = ops;
616 }
617 
bt_a2dp_stream_config_set_param(struct bt_a2dp * a2dp,struct bt_a2dp_codec_cfg * config,bt_avdtp_func_t cb,uint8_t remote_id,uint8_t int_id,uint8_t codec_type,struct bt_avdtp_sep * sep)618 static inline void bt_a2dp_stream_config_set_param(struct bt_a2dp *a2dp,
619 						   struct bt_a2dp_codec_cfg *config,
620 						   bt_avdtp_func_t cb, uint8_t remote_id,
621 						   uint8_t int_id, uint8_t codec_type,
622 						   struct bt_avdtp_sep *sep)
623 {
624 	memset(&a2dp->set_config_param, 0U, sizeof(a2dp->set_config_param));
625 	a2dp->set_config_param.req.func = cb;
626 	a2dp->set_config_param.acp_stream_ep_id = remote_id;
627 	a2dp->set_config_param.int_stream_endpoint_id = int_id;
628 	a2dp->set_config_param.media_type = BT_AVDTP_AUDIO;
629 	a2dp->set_config_param.media_codec_type = codec_type;
630 	a2dp->set_config_param.codec_specific_ie_len = config->codec_config->len;
631 	a2dp->set_config_param.codec_specific_ie = &config->codec_config->codec_ie[0];
632 	a2dp->set_config_param.sep = sep;
633 }
634 
bt_a2dp_stream_config(struct bt_a2dp * a2dp,struct bt_a2dp_stream * stream,struct bt_a2dp_ep * local_ep,struct bt_a2dp_ep * remote_ep,struct bt_a2dp_codec_cfg * config)635 int bt_a2dp_stream_config(struct bt_a2dp *a2dp, struct bt_a2dp_stream *stream,
636 			  struct bt_a2dp_ep *local_ep, struct bt_a2dp_ep *remote_ep,
637 			  struct bt_a2dp_codec_cfg *config)
638 {
639 	if ((a2dp == NULL) || (stream == NULL) || (local_ep == NULL) || (remote_ep == NULL) ||
640 	    (config == NULL)) {
641 		return -EINVAL;
642 	}
643 
644 	if ((local_ep->sep.sep_info.tsep == remote_ep->sep.sep_info.tsep) ||
645 	    (local_ep->codec_type != remote_ep->codec_type)) {
646 		return -EINVAL;
647 	}
648 
649 	stream->local_ep = local_ep;
650 	stream->remote_ep = remote_ep;
651 	stream->remote_ep_id = remote_ep->sep.sep_info.id;
652 	stream->a2dp = a2dp;
653 	local_ep->stream = stream;
654 	remote_ep->stream = stream;
655 	bt_a2dp_stream_config_set_param(a2dp, config, bt_a2dp_set_config_cb,
656 					remote_ep->sep.sep_info.id, local_ep->sep.sep_info.id,
657 					local_ep->codec_type, &local_ep->sep);
658 	return bt_avdtp_set_configuration(&a2dp->session, &a2dp->set_config_param);
659 }
660 
661 typedef void (*bt_a2dp_rsp_cb)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code);
662 typedef void (*bt_a2dp_done_cb)(struct bt_a2dp_stream *stream);
663 
bt_a2dp_ctrl_cb(struct bt_avdtp_req * req,bt_a2dp_rsp_cb rsp_cb,bt_a2dp_done_cb done_cb,bool clear_stream)664 static int bt_a2dp_ctrl_cb(struct bt_avdtp_req *req, bt_a2dp_rsp_cb rsp_cb, bt_a2dp_done_cb done_cb,
665 			   bool clear_stream)
666 {
667 	struct bt_a2dp *a2dp = CTRL_PARAM(CTRL_REQ(req));
668 	struct bt_a2dp_ep *ep;
669 	struct bt_a2dp_stream *stream;
670 
671 	ep = CONTAINER_OF(a2dp->ctrl_param.sep, struct bt_a2dp_ep, sep);
672 	if ((ep->stream == NULL) || (CTRL_REQ(req) != &a2dp->ctrl_param)) {
673 		return -EINVAL;
674 	}
675 
676 	stream = ep->stream;
677 
678 	if (clear_stream) {
679 		ep->stream = NULL;
680 	}
681 
682 	LOG_DBG("ctrl result:%d", req->status);
683 
684 	if (rsp_cb != NULL) {
685 		rsp_cb(stream, req->status);
686 	}
687 
688 	if ((!req->status) && (done_cb != NULL)) {
689 		done_cb(stream);
690 	}
691 
692 	return 0;
693 }
694 
bt_a2dp_open_cb(struct bt_avdtp_req * req,struct net_buf * buf)695 static int bt_a2dp_open_cb(struct bt_avdtp_req *req, struct net_buf *buf)
696 {
697 	struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
698 	bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->establish_rsp : NULL;
699 	bt_a2dp_done_cb done_cb = (ep->stream != NULL && ep->stream->ops != NULL)
700 					  ? ep->stream->ops->established
701 					  : NULL;
702 
703 	return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false);
704 }
705 
bt_a2dp_start_cb(struct bt_avdtp_req * req,struct net_buf * buf)706 static int bt_a2dp_start_cb(struct bt_avdtp_req *req, struct net_buf *buf)
707 {
708 	struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
709 	bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->start_rsp : NULL;
710 	bt_a2dp_done_cb done_cb =
711 		(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->started : NULL;
712 
713 	return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false);
714 }
715 
bt_a2dp_suspend_cb(struct bt_avdtp_req * req,struct net_buf * buf)716 static int bt_a2dp_suspend_cb(struct bt_avdtp_req *req, struct net_buf *buf)
717 {
718 	struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
719 	bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->suspend_rsp : NULL;
720 	bt_a2dp_done_cb done_cb =
721 		(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->suspended : NULL;
722 
723 	return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false);
724 }
725 
bt_a2dp_close_cb(struct bt_avdtp_req * req,struct net_buf * buf)726 static int bt_a2dp_close_cb(struct bt_avdtp_req *req, struct net_buf *buf)
727 {
728 	struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
729 	bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->release_rsp : NULL;
730 	bt_a2dp_done_cb done_cb =
731 		(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->released : NULL;
732 
733 	return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, true);
734 }
735 
bt_a2dp_abort_cb(struct bt_avdtp_req * req,struct net_buf * buf)736 static int bt_a2dp_abort_cb(struct bt_avdtp_req *req, struct net_buf *buf)
737 {
738 	struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
739 	bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->abort_rsp : NULL;
740 	bt_a2dp_done_cb done_cb =
741 		(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->aborted : NULL;
742 
743 	return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, true);
744 }
745 
bt_a2dp_stream_ctrl_pre(struct bt_a2dp_stream * stream,bt_avdtp_func_t cb)746 static int bt_a2dp_stream_ctrl_pre(struct bt_a2dp_stream *stream, bt_avdtp_func_t cb)
747 {
748 	struct bt_a2dp *a2dp;
749 
750 	if ((stream == NULL) || (stream->local_ep == NULL) || (stream->a2dp == NULL)) {
751 		return -EINVAL;
752 	}
753 
754 	a2dp = stream->a2dp;
755 	memset(&a2dp->ctrl_param, 0U, sizeof(a2dp->ctrl_param));
756 	a2dp->ctrl_param.req.func = cb;
757 	a2dp->ctrl_param.acp_stream_ep_id = stream->remote_ep != NULL
758 						    ? stream->remote_ep->sep.sep_info.id
759 						    : stream->remote_ep_id;
760 	a2dp->ctrl_param.sep = &stream->local_ep->sep;
761 	return 0;
762 }
763 
bt_a2dp_stream_establish(struct bt_a2dp_stream * stream)764 int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream)
765 {
766 	int err;
767 	struct bt_a2dp *a2dp = stream->a2dp;
768 
769 	err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_open_cb);
770 	if (err) {
771 		return err;
772 	}
773 
774 	return bt_avdtp_open(&a2dp->session, &a2dp->ctrl_param);
775 }
776 
bt_a2dp_stream_release(struct bt_a2dp_stream * stream)777 int bt_a2dp_stream_release(struct bt_a2dp_stream *stream)
778 {
779 	int err;
780 	struct bt_a2dp *a2dp = stream->a2dp;
781 
782 	err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_close_cb);
783 	if (err) {
784 		return err;
785 	}
786 
787 	return bt_avdtp_close(&a2dp->session, &a2dp->ctrl_param);
788 }
789 
bt_a2dp_stream_start(struct bt_a2dp_stream * stream)790 int bt_a2dp_stream_start(struct bt_a2dp_stream *stream)
791 {
792 	int err;
793 	struct bt_a2dp *a2dp = stream->a2dp;
794 
795 	err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_start_cb);
796 	if (err) {
797 		return err;
798 	}
799 
800 	return bt_avdtp_start(&a2dp->session, &a2dp->ctrl_param);
801 }
802 
bt_a2dp_stream_suspend(struct bt_a2dp_stream * stream)803 int bt_a2dp_stream_suspend(struct bt_a2dp_stream *stream)
804 {
805 	int err;
806 	struct bt_a2dp *a2dp = stream->a2dp;
807 
808 	err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_suspend_cb);
809 	if (err) {
810 		return err;
811 	}
812 
813 	return bt_avdtp_suspend(&a2dp->session, &a2dp->ctrl_param);
814 }
815 
bt_a2dp_stream_abort(struct bt_a2dp_stream * stream)816 int bt_a2dp_stream_abort(struct bt_a2dp_stream *stream)
817 {
818 	int err;
819 	struct bt_a2dp *a2dp = stream->a2dp;
820 
821 	err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_abort_cb);
822 	if (err) {
823 		return err;
824 	}
825 
826 	return bt_avdtp_abort(&a2dp->session, &a2dp->ctrl_param);
827 }
828 
bt_a2dp_stream_reconfig(struct bt_a2dp_stream * stream,struct bt_a2dp_codec_cfg * config)829 int bt_a2dp_stream_reconfig(struct bt_a2dp_stream *stream, struct bt_a2dp_codec_cfg *config)
830 {
831 	uint8_t remote_id;
832 
833 	if ((stream == NULL) || (config == NULL)) {
834 		return -EINVAL;
835 	}
836 
837 	remote_id = stream->remote_ep != NULL ? stream->remote_ep->sep.sep_info.id
838 					      : stream->remote_ep_id;
839 	bt_a2dp_stream_config_set_param(stream->a2dp, config, bt_a2dp_set_config_cb, remote_id,
840 					stream->local_ep->sep.sep_info.id,
841 					stream->local_ep->codec_type, &stream->local_ep->sep);
842 	return bt_avdtp_reconfigure(&stream->a2dp->session, &stream->a2dp->set_config_param);
843 }
844 
bt_a2dp_get_mtu(struct bt_a2dp_stream * stream)845 uint32_t bt_a2dp_get_mtu(struct bt_a2dp_stream *stream)
846 {
847 	if ((stream == NULL) || (stream->local_ep == NULL)) {
848 		return 0;
849 	}
850 
851 	return bt_avdtp_get_media_mtu(&stream->local_ep->sep);
852 }
853 
854 #if defined(CONFIG_BT_A2DP_SOURCE)
bt_a2dp_stream_send(struct bt_a2dp_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts)855 int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, uint16_t seq_num,
856 			uint32_t ts)
857 {
858 	struct bt_avdtp_media_hdr *media_hdr;
859 
860 	if (stream == NULL || stream->local_ep == NULL) {
861 		return -EINVAL;
862 	}
863 
864 	media_hdr = net_buf_push(buf, sizeof(struct bt_avdtp_media_hdr));
865 	memset(media_hdr, 0, sizeof(struct bt_avdtp_media_hdr));
866 
867 	if (stream->local_ep->codec_type == BT_A2DP_SBC) {
868 		media_hdr->playload_type = A2DP_SBC_PAYLOAD_TYPE;
869 	}
870 
871 	media_hdr->RTP_version = BT_AVDTP_RTP_VERSION;
872 	media_hdr->synchronization_source = 0U;
873 	/* update time_stamp in the buf */
874 	sys_put_be32(ts, (uint8_t *)&media_hdr->time_stamp);
875 	/* update sequence_number in the buf */
876 	sys_put_be16(seq_num, (uint8_t *)&media_hdr->sequence_number);
877 	/* send the buf */
878 	return bt_avdtp_send_media_data(&stream->local_ep->sep, buf);
879 }
880 #endif
881 
a2dp_stream_l2cap_disconnected(struct bt_avdtp * session,struct bt_avdtp_sep * sep)882 int a2dp_stream_l2cap_disconnected(struct bt_avdtp *session, struct bt_avdtp_sep *sep)
883 {
884 	struct bt_a2dp_ep *ep;
885 
886 	__ASSERT(sep, "Invalid sep");
887 	ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
888 
889 	if (ep->stream != NULL) {
890 		struct bt_a2dp_stream_ops *ops;
891 		struct bt_a2dp_stream *stream = ep->stream;
892 
893 		ops = stream->ops;
894 		/* Many places set ep->stream as NULL like abort and close.
895 		 * it should be OK without lock protection because
896 		 * all the related callbacks are in the same zephyr task context.
897 		 */
898 		ep->stream = NULL;
899 
900 		if ((ops != NULL) && (ops->released != NULL)) {
901 			ops->released(stream);
902 		}
903 	}
904 
905 	return 0;
906 }
907 
908 static const struct bt_avdtp_ops_cb signaling_avdtp_ops = {
909 	.connected = a2dp_connected,
910 	.disconnected = a2dp_disconnected,
911 	.alloc_buf = a2dp_alloc_buf,
912 	.discovery_ind = a2dp_discovery_ind,
913 	.get_capabilities_ind = a2dp_get_capabilities_ind,
914 	.set_configuration_ind = a2dp_set_config_ind,
915 	.re_configuration_ind = a2dp_re_config_ind,
916 	.open_ind = a2dp_open_ind,
917 	.start_ind = a2dp_start_ind,
918 	.close_ind = a2dp_close_ind,
919 	.suspend_ind = a2dp_suspend_ind,
920 	.abort_ind = a2dp_abort_ind,
921 	.stream_l2cap_disconnected = a2dp_stream_l2cap_disconnected,
922 };
923 
a2dp_accept(struct bt_conn * conn,struct bt_avdtp ** session)924 int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session)
925 {
926 	struct bt_a2dp *a2dp;
927 
928 	a2dp = a2dp_get_connection(conn);
929 	if (!a2dp) {
930 		return -ENOMEM;
931 	}
932 
933 	*session = &(a2dp->session);
934 	a2dp->session.ops = &signaling_avdtp_ops;
935 	LOG_DBG("session: %p", &(a2dp->session));
936 
937 	return 0;
938 }
939 
940 /* The above callback structures need to be packed and passed to AVDTP */
941 static struct bt_avdtp_event_cb avdtp_cb = {
942 	.accept = a2dp_accept,
943 };
944 
bt_a2dp_init(void)945 int bt_a2dp_init(void)
946 {
947 	int err;
948 
949 	/* Register event handlers with AVDTP */
950 	err = bt_avdtp_register(&avdtp_cb);
951 	if (err < 0) {
952 		LOG_ERR("A2DP registration failed");
953 		return err;
954 	}
955 
956 	for (uint8_t i = 0; i < CONFIG_BT_MAX_CONN; i++) {
957 		memset(&connection[i], 0, sizeof(struct bt_a2dp));
958 	}
959 
960 	LOG_DBG("A2DP Initialized successfully.");
961 	return 0;
962 }
963 
bt_a2dp_connect(struct bt_conn * conn)964 struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn)
965 {
966 	struct bt_a2dp *a2dp;
967 	int err;
968 
969 	a2dp = a2dp_get_connection(conn);
970 	if (!a2dp) {
971 		LOG_ERR("Cannot allocate memory");
972 		return NULL;
973 	}
974 
975 	a2dp->a2dp_state = INTERNAL_STATE_IDLE;
976 	a2dp->session.ops = &signaling_avdtp_ops;
977 
978 	err = bt_avdtp_connect(conn, &(a2dp->session));
979 	if (err < 0) {
980 		LOG_DBG("AVDTP Connect failed");
981 		return NULL;
982 	}
983 
984 	LOG_DBG("Connect request sent");
985 	return a2dp;
986 }
987 
bt_a2dp_disconnect(struct bt_a2dp * a2dp)988 int bt_a2dp_disconnect(struct bt_a2dp *a2dp)
989 {
990 	__ASSERT_NO_MSG(a2dp);
991 	return bt_avdtp_disconnect(&a2dp->session);
992 }
993 
bt_a2dp_register_ep(struct bt_a2dp_ep * ep,uint8_t media_type,uint8_t sep_type)994 int bt_a2dp_register_ep(struct bt_a2dp_ep *ep, uint8_t media_type, uint8_t sep_type)
995 {
996 	int err;
997 
998 	__ASSERT_NO_MSG(ep);
999 
1000 #if defined(CONFIG_BT_A2DP_SINK)
1001 	if (sep_type == BT_AVDTP_SINK) {
1002 		ep->sep.media_data_cb = bt_a2dp_media_data_callback;
1003 	} else {
1004 		ep->sep.media_data_cb = NULL;
1005 	}
1006 #else
1007 	ep->sep.media_data_cb = NULL;
1008 #endif
1009 
1010 	err = bt_avdtp_register_sep(media_type, sep_type, &(ep->sep));
1011 	if (err < 0) {
1012 		return err;
1013 	}
1014 
1015 	return 0;
1016 }
1017 
bt_a2dp_register_cb(struct bt_a2dp_cb * cb)1018 int bt_a2dp_register_cb(struct bt_a2dp_cb *cb)
1019 {
1020 	a2dp_cb = cb;
1021 	return 0;
1022 }
1023