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