1 /*
2  * Copyright 2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/types.h>
9 #include <stddef.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/kernel.h>
14 
15 #include <zephyr/settings/settings.h>
16 
17 #include <zephyr/bluetooth/hci.h>
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/l2cap.h>
21 #include <zephyr/bluetooth/classic/a2dp_codec_sbc.h>
22 #include <zephyr/bluetooth/classic/a2dp.h>
23 #include <zephyr/bluetooth/classic/sdp.h>
24 
25 #include <zephyr/shell/shell.h>
26 
27 #include "host/shell/bt.h"
28 
29 struct bt_a2dp *default_a2dp;
30 static uint8_t a2dp_sink_sdp_registered;
31 static uint8_t a2dp_source_sdp_registered;
32 static uint8_t a2dp_initied;
33 BT_A2DP_SBC_SINK_EP_DEFAULT(sink_sbc_endpoint);
34 BT_A2DP_SBC_SOURCE_EP_DEFAULT(source_sbc_endpoint);
35 struct bt_a2dp_codec_ie peer_sbc_capabilities;
36 static struct bt_a2dp_ep peer_sbc_endpoint = {
37 	.codec_cap = &peer_sbc_capabilities,
38 };
39 static struct bt_a2dp_ep *found_peer_sbc_endpoint;
40 static struct bt_a2dp_ep *registered_sbc_endpoint;
41 static struct bt_a2dp_stream sbc_stream;
42 static struct bt_a2dp_stream_ops stream_ops;
43 
44 #if defined(CONFIG_BT_A2DP_SOURCE)
45 static uint8_t media_data[] = {
46 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
47 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
48 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
49 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
50 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
51 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
52 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
53 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
54 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
55 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
56 };
57 #endif
58 
59 NET_BUF_POOL_DEFINE(a2dp_tx_pool, CONFIG_BT_MAX_CONN,
60 		BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
61 		CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
62 
63 static struct bt_sdp_attribute a2dp_sink_attrs[] = {
64 	BT_SDP_NEW_SERVICE,
65 	BT_SDP_LIST(
66 		BT_SDP_ATTR_SVCLASS_ID_LIST,
67 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3), /* 35 03 */
68 		BT_SDP_DATA_ELEM_LIST(
69 		{
70 			BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
71 			BT_SDP_ARRAY_16(BT_SDP_AUDIO_SINK_SVCLASS) /* 11 0B */
72 		},
73 		)
74 	),
75 	BT_SDP_LIST(
76 		BT_SDP_ATTR_PROTO_DESC_LIST,
77 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),/* 35 10 */
78 		BT_SDP_DATA_ELEM_LIST(
79 		{
80 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),/* 35 06 */
81 			BT_SDP_DATA_ELEM_LIST(
82 			{
83 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
84 				BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP) /* 01 00 */
85 			},
86 			{
87 				BT_SDP_TYPE_SIZE(BT_SDP_UINT16), /* 09 */
88 				BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL) /* 00 19 */
89 			},
90 			)
91 		},
92 		{
93 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),/* 35 06 */
94 			BT_SDP_DATA_ELEM_LIST(
95 			{
96 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
97 				BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL) /* 00 19 */
98 			},
99 			{
100 				BT_SDP_TYPE_SIZE(BT_SDP_UINT16), /* 09 */
101 				BT_SDP_ARRAY_16(0x0100U) /* AVDTP version: 01 00 */
102 			},
103 			)
104 		},
105 		)
106 	),
107 	BT_SDP_LIST(
108 		BT_SDP_ATTR_PROFILE_DESC_LIST,
109 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8), /* 35 08 */
110 		BT_SDP_DATA_ELEM_LIST(
111 		{
112 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6), /* 35 06 */
113 			BT_SDP_DATA_ELEM_LIST(
114 			{
115 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
116 				BT_SDP_ARRAY_16(BT_SDP_ADVANCED_AUDIO_SVCLASS) /* 11 0d */
117 			},
118 			{
119 				BT_SDP_TYPE_SIZE(BT_SDP_UINT16), /* 09 */
120 				BT_SDP_ARRAY_16(0x0103U) /* 01 03 */
121 			},
122 			)
123 		},
124 		)
125 	),
126 	BT_SDP_SERVICE_NAME("A2DPSink"),
127 	BT_SDP_SUPPORTED_FEATURES(0x0001U),
128 };
129 
130 static struct bt_sdp_record a2dp_sink_rec = BT_SDP_RECORD(a2dp_sink_attrs);
131 
132 static struct bt_sdp_attribute a2dp_source_attrs[] = {
133 	BT_SDP_NEW_SERVICE,
134 	BT_SDP_LIST(
135 		BT_SDP_ATTR_SVCLASS_ID_LIST,
136 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
137 		BT_SDP_DATA_ELEM_LIST(
138 		{
139 			BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
140 			BT_SDP_ARRAY_16(BT_SDP_AUDIO_SOURCE_SVCLASS)
141 		},
142 		)
143 	),
144 	BT_SDP_LIST(
145 		BT_SDP_ATTR_PROTO_DESC_LIST,
146 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),
147 		BT_SDP_DATA_ELEM_LIST(
148 		{
149 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
150 			BT_SDP_DATA_ELEM_LIST(
151 			{
152 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
153 				BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
154 			},
155 			{
156 				BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
157 				BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL)
158 			},
159 			)
160 		},
161 		{
162 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
163 			BT_SDP_DATA_ELEM_LIST(
164 			{
165 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
166 				BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL)
167 			},
168 			{
169 				BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
170 				BT_SDP_ARRAY_16(0x0100U)
171 			},
172 			)
173 		},
174 		)
175 	),
176 	BT_SDP_LIST(
177 		BT_SDP_ATTR_PROFILE_DESC_LIST,
178 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
179 		BT_SDP_DATA_ELEM_LIST(
180 		{
181 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
182 			BT_SDP_DATA_ELEM_LIST(
183 			{
184 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
185 				BT_SDP_ARRAY_16(BT_SDP_ADVANCED_AUDIO_SVCLASS)
186 			},
187 			{
188 				BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
189 				BT_SDP_ARRAY_16(0x0103U)
190 			},
191 			)
192 		},
193 		)
194 	),
195 	BT_SDP_SERVICE_NAME("A2DPSink"),
196 	BT_SDP_SUPPORTED_FEATURES(0x0001U),
197 };
198 
199 static struct bt_sdp_record a2dp_source_rec = BT_SDP_RECORD(a2dp_source_attrs);
200 
shell_a2dp_print_capabilities(struct bt_a2dp_ep_info * ep_info)201 static void shell_a2dp_print_capabilities(struct bt_a2dp_ep_info *ep_info)
202 {
203 	uint8_t codec_type;
204 	uint8_t *codec_ie;
205 	uint16_t codec_ie_len;
206 
207 	codec_type = ep_info->codec_type;
208 	codec_ie = ep_info->codec_cap.codec_ie;
209 	codec_ie_len = ep_info->codec_cap.len;
210 	shell_print(ctx_shell, "endpoint id: %d, %s, %s:", ep_info->sep_info.id,
211 			(ep_info->sep_info.tsep == BT_AVDTP_SINK) ? "(sink)" : "(source)",
212 			(ep_info->sep_info.inuse) ? "(in use)" : "(idle)");
213 	if (BT_A2DP_SBC == codec_type) {
214 		shell_print(ctx_shell, "  codec type: SBC");
215 
216 		if (BT_A2DP_SBC_IE_LENGTH != codec_ie_len) {
217 			shell_error(ctx_shell, "  wrong sbc codec ie");
218 			return;
219 		}
220 
221 		shell_print(ctx_shell, "  sample frequency:");
222 		if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_16000)) {
223 			shell_print(ctx_shell, "	16000 ");
224 		}
225 		if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_32000)) {
226 			shell_print(ctx_shell, "	32000 ");
227 		}
228 		if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_44100)) {
229 			shell_print(ctx_shell, "	44100 ");
230 		}
231 		if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_48000)) {
232 			shell_print(ctx_shell, "	48000");
233 		}
234 
235 		shell_print(ctx_shell, "  channel mode:");
236 		if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_MONO)) {
237 			shell_print(ctx_shell, "	Mono ");
238 		}
239 		if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_DUAL)) {
240 			shell_print(ctx_shell, "	Dual ");
241 		}
242 		if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_STREO)) {
243 			shell_print(ctx_shell, "	Stereo ");
244 		}
245 		if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_JOINT)) {
246 			shell_print(ctx_shell, "	Joint-Stereo");
247 		}
248 
249 		 /* Decode Support for Block Length */
250 		shell_print(ctx_shell, "  Block Length:");
251 		if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_4)) {
252 			shell_print(ctx_shell, "	4 ");
253 		}
254 		if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_8)) {
255 			shell_print(ctx_shell, "	8 ");
256 		}
257 		if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_12)) {
258 			shell_print(ctx_shell, "	12 ");
259 		}
260 		if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_16)) {
261 			shell_print(ctx_shell, "	16");
262 		}
263 
264 		/* Decode Support for Subbands */
265 		shell_print(ctx_shell, "  Subbands:");
266 		if (0U != (codec_ie[1U] & A2DP_SBC_SUBBAND_4)) {
267 			shell_print(ctx_shell, "	4 ");
268 		}
269 		if (0U != (codec_ie[1U] & A2DP_SBC_SUBBAND_8)) {
270 			shell_print(ctx_shell, "	8");
271 		}
272 
273 		/* Decode Support for Allocation Method */
274 		shell_print(ctx_shell, "  Allocation Method:");
275 		if (0U != (codec_ie[1U] & A2DP_SBC_ALLOC_MTHD_SNR)) {
276 			shell_print(ctx_shell, "	SNR ");
277 		}
278 		if (0U != (codec_ie[1U] & A2DP_SBC_ALLOC_MTHD_LOUDNESS)) {
279 			shell_print(ctx_shell, "	Loudness");
280 		}
281 
282 		shell_print(ctx_shell, "  Bitpool Range: %d - %d",
283 					codec_ie[2U], codec_ie[3U]);
284 	} else {
285 		shell_print(ctx_shell, "  not SBC codecs");
286 	}
287 }
288 
app_connected(struct bt_a2dp * a2dp,int err)289 void app_connected(struct bt_a2dp *a2dp, int err)
290 {
291 	if (!err) {
292 		default_a2dp = a2dp;
293 		shell_print(ctx_shell, "a2dp connected");
294 	} else {
295 		shell_print(ctx_shell, "a2dp connecting fail");
296 	}
297 }
298 
app_disconnected(struct bt_a2dp * a2dp)299 void app_disconnected(struct bt_a2dp *a2dp)
300 {
301 	found_peer_sbc_endpoint = NULL;
302 	shell_print(ctx_shell, "a2dp disconnected");
303 }
304 
app_config_req(struct bt_a2dp * a2dp,struct bt_a2dp_ep * ep,struct bt_a2dp_codec_cfg * codec_cfg,struct bt_a2dp_stream ** stream,uint8_t * rsp_err_code)305 int app_config_req(struct bt_a2dp *a2dp, struct bt_a2dp_ep *ep,
306 		struct bt_a2dp_codec_cfg *codec_cfg, struct bt_a2dp_stream **stream,
307 		uint8_t *rsp_err_code)
308 {
309 	uint32_t sample_rate;
310 
311 	bt_a2dp_stream_cb_register(&sbc_stream, &stream_ops);
312 	*stream = &sbc_stream;
313 	*rsp_err_code = 0;
314 
315 	shell_print(ctx_shell, "receive requesting config and accept");
316 	sample_rate = bt_a2dp_sbc_get_sampling_frequency(
317 		(struct bt_a2dp_codec_sbc_params *)&codec_cfg->codec_config->codec_ie[0]);
318 	shell_print(ctx_shell, "sample rate %dHz", sample_rate);
319 
320 	return 0;
321 }
322 
app_reconfig_req(struct bt_a2dp_stream * stream,struct bt_a2dp_codec_cfg * codec_cfg,uint8_t * rsp_err_code)323 int app_reconfig_req(struct bt_a2dp_stream *stream,
324 	struct bt_a2dp_codec_cfg *codec_cfg, uint8_t *rsp_err_code)
325 {
326 	uint32_t sample_rate;
327 
328 	*rsp_err_code = 0;
329 	shell_print(ctx_shell, "receive requesting reconfig and accept");
330 	sample_rate = bt_a2dp_sbc_get_sampling_frequency(
331 		(struct bt_a2dp_codec_sbc_params *)&codec_cfg->codec_config->codec_ie[0]);
332 	shell_print(ctx_shell, "sample rate %dHz", sample_rate);
333 
334 	return 0;
335 }
336 
app_config_rsp(struct bt_a2dp_stream * stream,uint8_t rsp_err_code)337 void app_config_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
338 {
339 	if (rsp_err_code == 0) {
340 		shell_print(ctx_shell, "success to configure");
341 	} else {
342 		shell_print(ctx_shell, "fail to configure");
343 	}
344 }
345 
app_establish_req(struct bt_a2dp_stream * stream,uint8_t * rsp_err_code)346 int app_establish_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code)
347 {
348 	*rsp_err_code = 0;
349 	shell_print(ctx_shell, "receive requesting establishment and accept");
350 	return 0;
351 }
352 
app_establish_rsp(struct bt_a2dp_stream * stream,uint8_t rsp_err_code)353 void app_establish_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
354 {
355 	if (rsp_err_code == 0) {
356 		shell_print(ctx_shell, "success to establish");
357 	} else {
358 		shell_print(ctx_shell, "fail to establish");
359 	}
360 }
361 
app_release_req(struct bt_a2dp_stream * stream,uint8_t * rsp_err_code)362 int app_release_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code)
363 {
364 	*rsp_err_code = 0;
365 	shell_print(ctx_shell, "receive requesting release and accept");
366 	return 0;
367 }
368 
app_release_rsp(struct bt_a2dp_stream * stream,uint8_t rsp_err_code)369 void app_release_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
370 {
371 	if (rsp_err_code == 0) {
372 		shell_print(ctx_shell, "success to release");
373 	} else {
374 		shell_print(ctx_shell, "fail to release");
375 	}
376 }
377 
app_start_req(struct bt_a2dp_stream * stream,uint8_t * rsp_err_code)378 int app_start_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code)
379 {
380 	*rsp_err_code = 0;
381 	shell_print(ctx_shell, "receive requesting start and accept");
382 	return 0;
383 }
384 
app_start_rsp(struct bt_a2dp_stream * stream,uint8_t rsp_err_code)385 void app_start_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
386 {
387 	if (rsp_err_code == 0) {
388 		shell_print(ctx_shell, "success to start");
389 	} else {
390 		shell_print(ctx_shell, "fail to start");
391 	}
392 }
393 
app_suspend_req(struct bt_a2dp_stream * stream,uint8_t * rsp_err_code)394 int app_suspend_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code)
395 {
396 	*rsp_err_code = 0;
397 	shell_print(ctx_shell, "receive requesting suspend and accept");
398 	return 0;
399 }
400 
app_suspend_rsp(struct bt_a2dp_stream * stream,uint8_t rsp_err_code)401 void app_suspend_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
402 {
403 	if (rsp_err_code == 0) {
404 		shell_print(ctx_shell, "success to suspend");
405 	} else {
406 		shell_print(ctx_shell, "fail to suspend");
407 	}
408 }
409 
stream_configured(struct bt_a2dp_stream * stream)410 void stream_configured(struct bt_a2dp_stream *stream)
411 {
412 	shell_print(ctx_shell, "stream configured");
413 }
414 
stream_established(struct bt_a2dp_stream * stream)415 void stream_established(struct bt_a2dp_stream *stream)
416 {
417 	shell_print(ctx_shell, "stream established");
418 }
419 
stream_released(struct bt_a2dp_stream * stream)420 void stream_released(struct bt_a2dp_stream *stream)
421 {
422 	shell_print(ctx_shell, "stream released");
423 }
424 
stream_started(struct bt_a2dp_stream * stream)425 void stream_started(struct bt_a2dp_stream *stream)
426 {
427 	shell_print(ctx_shell, "stream started");
428 }
429 
stream_suspended(struct bt_a2dp_stream * stream)430 void stream_suspended(struct bt_a2dp_stream *stream)
431 {
432 	shell_print(ctx_shell, "stream suspended");
433 }
434 
stream_aborted(struct bt_a2dp_stream * stream)435 void stream_aborted(struct bt_a2dp_stream *stream)
436 {
437 	shell_print(ctx_shell, "stream aborted");
438 }
439 
sink_sbc_streamer_data(struct bt_a2dp_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts)440 void sink_sbc_streamer_data(struct bt_a2dp_stream *stream, struct net_buf *buf,
441 			uint16_t seq_num, uint32_t ts)
442 {
443 	uint8_t sbc_hdr;
444 
445 	if (buf->len < 1U) {
446 		return;
447 	}
448 	sbc_hdr = net_buf_pull_u8(buf);
449 	shell_print(ctx_shell, "received, num of frames: %d, data length:%d",
450 		(uint8_t)BT_A2DP_SBC_MEDIA_HDR_NUM_FRAMES_GET(sbc_hdr), buf->len);
451 	shell_print(ctx_shell, "data: %d, %d, %d, %d, %d, %d ......", buf->data[0],
452 		buf->data[1], buf->data[2], buf->data[3], buf->data[4], buf->data[5]);
453 }
454 
stream_recv(struct bt_a2dp_stream * stream,struct net_buf * buf,uint16_t seq_num,uint32_t ts)455 void stream_recv(struct bt_a2dp_stream *stream,
456 		struct net_buf *buf, uint16_t seq_num, uint32_t ts)
457 {
458 	sink_sbc_streamer_data(stream, buf, seq_num, ts);
459 }
460 
461 struct bt_a2dp_cb a2dp_cb = {
462 	.connected = app_connected,
463 	.disconnected = app_disconnected,
464 	.config_req = app_config_req,
465 	.config_rsp = app_config_rsp,
466 	.establish_req = app_establish_req,
467 	.establish_rsp = app_establish_rsp,
468 	.release_req = app_release_req,
469 	.release_rsp = app_release_rsp,
470 	.start_req = app_start_req,
471 	.start_rsp = app_start_rsp,
472 	.suspend_req = app_suspend_req,
473 	.suspend_rsp = app_suspend_rsp,
474 	.reconfig_req = app_reconfig_req,
475 };
476 
cmd_register_cb(const struct shell * sh,int32_t argc,char * argv[])477 static int cmd_register_cb(const struct shell *sh, int32_t argc, char *argv[])
478 {
479 	int err = -1;
480 
481 	if (a2dp_initied == 0) {
482 		a2dp_initied = 1;
483 
484 		err = bt_a2dp_register_cb(&a2dp_cb);
485 		if (!err) {
486 			shell_print(sh, "success");
487 		} else {
488 			shell_print(sh, "fail");
489 		}
490 	} else {
491 		shell_print(sh, "already registered");
492 	}
493 
494 	return 0;
495 }
496 
cmd_register_ep(const struct shell * sh,int32_t argc,char * argv[])497 static int cmd_register_ep(const struct shell *sh, int32_t argc, char *argv[])
498 {
499 	int err = -1;
500 	const char *type;
501 	const char *action;
502 
503 	if (a2dp_initied == 0) {
504 		shell_print(sh, "need to register a2dp connection callbacks");
505 		return -ENOEXEC;
506 	}
507 
508 	type = argv[1];
509 	action = argv[2];
510 	if (!strcmp(action, "sbc")) {
511 		if (!strcmp(type, "sink")) {
512 			if (a2dp_sink_sdp_registered == 0) {
513 				a2dp_sink_sdp_registered = 1;
514 				bt_sdp_register_service(&a2dp_sink_rec);
515 			}
516 			err = bt_a2dp_register_ep(&sink_sbc_endpoint,
517 				BT_AVDTP_AUDIO, BT_AVDTP_SINK);
518 			if (!err) {
519 				shell_print(sh, "SBC sink endpoint is registered");
520 				registered_sbc_endpoint = &sink_sbc_endpoint;
521 			}
522 		} else if (!strcmp(type, "source")) {
523 			if (a2dp_source_sdp_registered == 0) {
524 				a2dp_source_sdp_registered = 1;
525 				bt_sdp_register_service(&a2dp_source_rec);
526 			}
527 			err = bt_a2dp_register_ep(&source_sbc_endpoint,
528 				BT_AVDTP_AUDIO, BT_AVDTP_SOURCE);
529 			if (!err) {
530 				shell_print(sh, "SBC source endpoint is registered");
531 				registered_sbc_endpoint = &source_sbc_endpoint;
532 			}
533 		} else {
534 			shell_help(sh);
535 			return 0;
536 		}
537 	} else {
538 		shell_help(sh);
539 		return 0;
540 	}
541 
542 	if (err) {
543 		shell_print(sh, "fail to register endpoint");
544 	}
545 
546 	return 0;
547 }
548 
cmd_connect(const struct shell * sh,int32_t argc,char * argv[])549 static int cmd_connect(const struct shell *sh, int32_t argc, char *argv[])
550 {
551 	if (a2dp_initied == 0) {
552 		shell_print(sh, "need to register a2dp connection callbacks");
553 		return -ENOEXEC;
554 	}
555 
556 	if (!default_conn) {
557 		shell_error(sh, "Not connected");
558 		return -ENOEXEC;
559 	}
560 
561 	default_a2dp = bt_a2dp_connect(default_conn);
562 	if (NULL == default_a2dp) {
563 		shell_error(sh, "fail to connect a2dp");
564 	}
565 	return 0;
566 }
567 
cmd_disconnect(const struct shell * sh,int32_t argc,char * argv[])568 static int cmd_disconnect(const struct shell *sh, int32_t argc, char *argv[])
569 {
570 	if (a2dp_initied == 0) {
571 		shell_print(sh, "need to register a2dp connection callbacks");
572 		return -ENOEXEC;
573 	}
574 
575 	if (default_a2dp != NULL) {
576 		bt_a2dp_disconnect(default_a2dp);
577 		default_a2dp = NULL;
578 	} else {
579 		shell_error(sh, "a2dp is not connected");
580 	}
581 	return 0;
582 }
583 
app_configured(int err)584 void app_configured(int err)
585 {
586 	if (err) {
587 		shell_print(ctx_shell, "configure fail");
588 	}
589 }
590 
591 static struct bt_a2dp_stream_ops stream_ops = {
592 	.configured = stream_configured,
593 	.established = stream_established,
594 	.released = stream_released,
595 	.started = stream_started,
596 	.suspended = stream_suspended,
597 	.aborted = stream_aborted,
598 #if defined(CONFIG_BT_A2DP_SINK)
599 	.recv = stream_recv,
600 #endif
601 #if defined(CONFIG_BT_A2DP_SOURCE)
602 	.sent = NULL,
603 #endif
604 };
605 
606 BT_A2DP_SBC_EP_CFG_DEFAULT(sbc_cfg_default, A2DP_SBC_SAMP_FREQ_44100);
cmd_configure(const struct shell * sh,int32_t argc,char * argv[])607 static int cmd_configure(const struct shell *sh, int32_t argc, char *argv[])
608 {
609 	int err;
610 
611 	if (a2dp_initied == 0) {
612 		shell_print(sh, "need to register a2dp connection callbacks");
613 		return -ENOEXEC;
614 	}
615 
616 	if (default_a2dp != NULL) {
617 		if (registered_sbc_endpoint == NULL) {
618 			shell_error(sh, "no endpoint");
619 			return 0;
620 		}
621 
622 		if (found_peer_sbc_endpoint == NULL) {
623 			shell_error(sh, "don't find the peer sbc endpoint");
624 			return 0;
625 		}
626 
627 		bt_a2dp_stream_cb_register(&sbc_stream, &stream_ops);
628 
629 		err = bt_a2dp_stream_config(default_a2dp, &sbc_stream,
630 			registered_sbc_endpoint, found_peer_sbc_endpoint,
631 			&sbc_cfg_default);
632 		if (err) {
633 			shell_error(sh, "fail to configure");
634 		}
635 	} else {
636 		shell_error(sh, "a2dp is not connected");
637 	}
638 	return 0;
639 }
640 
cmd_reconfigure(const struct shell * sh,int32_t argc,char * argv[])641 static int cmd_reconfigure(const struct shell *sh, int32_t argc, char *argv[])
642 {
643 	if (a2dp_initied == 0) {
644 		shell_print(sh, "need to register a2dp connection callbacks");
645 		return -ENOEXEC;
646 	}
647 
648 	if (bt_a2dp_stream_reconfig(&sbc_stream, &sbc_cfg_default) != 0) {
649 		shell_print(sh, "fail");
650 	}
651 	return 0;
652 }
653 
bt_a2dp_discover_peer_endpoint_cb(struct bt_a2dp * a2dp,struct bt_a2dp_ep_info * info,struct bt_a2dp_ep ** ep)654 static uint8_t bt_a2dp_discover_peer_endpoint_cb(struct bt_a2dp *a2dp,
655 		struct bt_a2dp_ep_info *info, struct bt_a2dp_ep **ep)
656 {
657 	if (info != NULL) {
658 		shell_print(ctx_shell, "find one endpoint");
659 		shell_a2dp_print_capabilities(info);
660 		if ((info->codec_type == BT_A2DP_SBC) &&
661 		    (ep != NULL)) {
662 			*ep = &peer_sbc_endpoint;
663 			found_peer_sbc_endpoint = &peer_sbc_endpoint;
664 		}
665 	}
666 	return BT_A2DP_DISCOVER_EP_CONTINUE;
667 }
668 
669 static struct bt_avdtp_sep_info found_seps[5];
670 
671 struct bt_a2dp_discover_param discover_param = {
672 	.cb = bt_a2dp_discover_peer_endpoint_cb,
673 	.seps_info = &found_seps[0],
674 	.sep_count = 5,
675 };
676 
cmd_get_peer_eps(const struct shell * sh,int32_t argc,char * argv[])677 static int cmd_get_peer_eps(const struct shell *sh, int32_t argc, char *argv[])
678 {
679 	if (a2dp_initied == 0) {
680 		shell_print(sh, "need to register a2dp connection callbacks");
681 		return -ENOEXEC;
682 	}
683 
684 	if (default_a2dp != NULL) {
685 		int err = bt_a2dp_discover(default_a2dp, &discover_param);
686 
687 		if (err) {
688 			shell_error(sh, "discover fail");
689 		}
690 	} else {
691 		shell_error(sh, "a2dp is not connected");
692 	}
693 	return 0;
694 }
695 
cmd_establish(const struct shell * sh,int32_t argc,char * argv[])696 static int cmd_establish(const struct shell *sh, int32_t argc, char *argv[])
697 {
698 	if (a2dp_initied == 0) {
699 		shell_print(sh, "need to register a2dp connection callbacks");
700 		return -ENOEXEC;
701 	}
702 
703 	if (bt_a2dp_stream_establish(&sbc_stream) != 0) {
704 		shell_print(sh, "fail");
705 	}
706 	return 0;
707 }
708 
cmd_release(const struct shell * sh,int32_t argc,char * argv[])709 static int cmd_release(const struct shell *sh, int32_t argc, char *argv[])
710 {
711 	if (a2dp_initied == 0) {
712 		shell_print(sh, "need to register a2dp connection callbacks");
713 		return -ENOEXEC;
714 	}
715 
716 	if (bt_a2dp_stream_release(&sbc_stream) != 0) {
717 		shell_print(sh, "fail");
718 	}
719 	return 0;
720 }
721 
cmd_start(const struct shell * sh,int32_t argc,char * argv[])722 static int cmd_start(const struct shell *sh, int32_t argc, char *argv[])
723 {
724 	if (a2dp_initied == 0) {
725 		shell_print(sh, "need to register a2dp connection callbacks");
726 		return -ENOEXEC;
727 	}
728 
729 	if (bt_a2dp_stream_start(&sbc_stream) != 0) {
730 		shell_print(sh, "fail");
731 	}
732 	return 0;
733 }
734 
cmd_suspend(const struct shell * sh,int32_t argc,char * argv[])735 static int cmd_suspend(const struct shell *sh, int32_t argc, char *argv[])
736 {
737 	if (a2dp_initied == 0) {
738 		shell_print(sh, "need to register a2dp connection callbacks");
739 		return -ENOEXEC;
740 	}
741 
742 	if (bt_a2dp_stream_suspend(&sbc_stream) != 0) {
743 		shell_print(sh, "fail");
744 	}
745 	return 0;
746 }
747 
cmd_abort(const struct shell * sh,int32_t argc,char * argv[])748 static int cmd_abort(const struct shell *sh, int32_t argc, char *argv[])
749 {
750 	if (a2dp_initied == 0) {
751 		shell_print(sh, "need to register a2dp connection callbacks");
752 		return -ENOEXEC;
753 	}
754 
755 	if (bt_a2dp_stream_abort(&sbc_stream) != 0) {
756 		shell_print(sh, "fail");
757 	}
758 	return 0;
759 }
760 
cmd_send_media(const struct shell * sh,int32_t argc,char * argv[])761 static int cmd_send_media(const struct shell *sh, int32_t argc, char *argv[])
762 {
763 #if defined(CONFIG_BT_A2DP_SOURCE)
764 	struct net_buf *buf;
765 	int ret;
766 
767 	if (a2dp_initied == 0) {
768 		shell_print(sh, "need to register a2dp connection callbacks");
769 		return -ENOEXEC;
770 	}
771 
772 	buf = net_buf_alloc(&a2dp_tx_pool, K_FOREVER);
773 	net_buf_reserve(buf, BT_A2DP_STREAM_BUF_RESERVE);
774 
775 	/* num of frames is 1 */
776 	net_buf_add_u8(buf, (uint8_t)BT_A2DP_SBC_MEDIA_HDR_ENCODE(1, 0, 0, 0));
777 	net_buf_add_mem(buf, media_data, sizeof(media_data));
778 	shell_print(sh, "num of frames: %d, data length: %d", 1U, sizeof(media_data));
779 	shell_print(sh, "data: %d, %d, %d, %d, %d, %d ......", media_data[0],
780 		media_data[1], media_data[2], media_data[3], media_data[4], media_data[5]);
781 
782 	ret = bt_a2dp_stream_send(&sbc_stream, buf, 0U, 0U);
783 	if (ret < 0) {
784 		printk("  Failed to send SBC audio data on streams(%d)\n", ret);
785 		net_buf_unref(buf);
786 	}
787 #endif
788 	return 0;
789 }
790 
791 #define HELP_NONE "[none]"
792 
793 SHELL_STATIC_SUBCMD_SET_CREATE(a2dp_cmds,
794 	SHELL_CMD_ARG(register_cb, NULL, "register a2dp connection callbacks",
795 			cmd_register_cb, 1, 0),
796 	SHELL_CMD_ARG(register_ep, NULL, "<type: sink or source> <value: sbc>",
797 			cmd_register_ep, 3, 0),
798 	SHELL_CMD_ARG(connect, NULL, HELP_NONE, cmd_connect, 1, 0),
799 	SHELL_CMD_ARG(disconnect, NULL, HELP_NONE, cmd_disconnect, 1, 0),
800 	SHELL_CMD_ARG(discover_peer_eps, NULL, HELP_NONE, cmd_get_peer_eps, 1, 0),
801 	SHELL_CMD_ARG(configure, NULL, "\"configure/enable the stream\"", cmd_configure, 1, 0),
802 	SHELL_CMD_ARG(establish, NULL, "\"establish the stream\"", cmd_establish, 1, 0),
803 	SHELL_CMD_ARG(reconfigure, NULL, "\"reconfigure the stream\"", cmd_reconfigure, 1, 0),
804 	SHELL_CMD_ARG(release, NULL, "\"release the stream\"", cmd_release, 1, 0),
805 	SHELL_CMD_ARG(start, NULL, "\"start the stream\"", cmd_start, 1, 0),
806 	SHELL_CMD_ARG(suspend, NULL, "\"suspend the stream\"", cmd_suspend, 1, 0),
807 	SHELL_CMD_ARG(abort, NULL, "\"abort the stream\"", cmd_abort, 1, 0),
808 	SHELL_CMD_ARG(send_media, NULL, HELP_NONE, cmd_send_media, 1, 0),
809 	SHELL_SUBCMD_SET_END
810 );
811 
cmd_a2dp(const struct shell * sh,size_t argc,char ** argv)812 static int cmd_a2dp(const struct shell *sh, size_t argc, char **argv)
813 {
814 	if (argc == 1) {
815 		shell_help(sh);
816 		/* sh returns 1 when help is printed */
817 		return 1;
818 	}
819 
820 	shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
821 
822 	return -ENOEXEC;
823 }
824 
825 SHELL_CMD_ARG_REGISTER(a2dp, &a2dp_cmds, "Bluetooth A2DP sh commands",
826 			   cmd_a2dp, 1, 1);
827