zephyr/subsys/bluetooth/shell/a2dp.c
Zihao Gao 6ebb65d163 Bluetooth: fix compiling issue when either A2DP SRC or SNK are not enabled
Some of the A2DP interfaces are not defined if the corresponding feature
is not enabled, and therefore shall not be initialized.
This patchs include the interfaces/variables by the configurations to
go through the compiling stage.

Signed-off-by: Zihao Gao <gaozihao@xiaomi.com>
2024-07-09 14:03:07 +02:00

717 lines
18 KiB
C

/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/settings/settings.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/l2cap.h>
#include <zephyr/bluetooth/classic/a2dp_codec_sbc.h>
#include <zephyr/bluetooth/classic/a2dp.h>
#include <zephyr/bluetooth/classic/sdp.h>
#include <zephyr/shell/shell.h>
#include "bt.h"
struct bt_a2dp *default_a2dp;
static uint8_t a2dp_sink_sdp_registered;
static uint8_t a2dp_source_sdp_registered;
static uint8_t a2dp_initied;
BT_A2DP_SBC_SINK_EP_DEFAULT(sink_sbc_endpoint);
BT_A2DP_SBC_SOURCE_EP_DEFAULT(source_sbc_endpoint);
struct bt_a2dp_codec_ie peer_sbc_capabilities;
static struct bt_a2dp_ep peer_sbc_endpoint = {
.codec_cap = &peer_sbc_capabilities,
};
static struct bt_a2dp_ep *found_peer_sbc_endpoint;
static struct bt_a2dp_ep *registered_sbc_endpoint;
static struct bt_a2dp_stream sbc_stream;
static struct bt_a2dp_stream_ops stream_ops;
#if defined(CONFIG_BT_A2DP_SOURCE)
static uint8_t media_data[] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
};
#endif
NET_BUF_POOL_DEFINE(a2dp_tx_pool, CONFIG_BT_MAX_CONN,
BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
static struct bt_sdp_attribute a2dp_sink_attrs[] = {
BT_SDP_NEW_SERVICE,
BT_SDP_LIST(
BT_SDP_ATTR_SVCLASS_ID_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3), /* 35 03 */
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
BT_SDP_ARRAY_16(BT_SDP_AUDIO_SINK_SVCLASS) /* 11 0B */
},
)
),
BT_SDP_LIST(
BT_SDP_ATTR_PROTO_DESC_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),/* 35 10 */
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),/* 35 06 */
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP) /* 01 00 */
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT16), /* 09 */
BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL) /* 00 19 */
},
)
},
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),/* 35 06 */
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL) /* 00 19 */
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT16), /* 09 */
BT_SDP_ARRAY_16(0X0100u) /* AVDTP version: 01 00 */
},
)
},
)
),
BT_SDP_LIST(
BT_SDP_ATTR_PROFILE_DESC_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8), /* 35 08 */
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6), /* 35 06 */
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16), /* 19 */
BT_SDP_ARRAY_16(BT_SDP_ADVANCED_AUDIO_SVCLASS) /* 11 0d */
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT16), /* 09 */
BT_SDP_ARRAY_16(0x0103U) /* 01 03 */
},
)
},
)
),
BT_SDP_SERVICE_NAME("A2DPSink"),
BT_SDP_SUPPORTED_FEATURES(0x0001U),
};
static struct bt_sdp_record a2dp_sink_rec = BT_SDP_RECORD(a2dp_sink_attrs);
static struct bt_sdp_attribute a2dp_source_attrs[] = {
BT_SDP_NEW_SERVICE,
BT_SDP_LIST(
BT_SDP_ATTR_SVCLASS_ID_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_AUDIO_SOURCE_SVCLASS)
},
)
),
BT_SDP_LIST(
BT_SDP_ATTR_PROTO_DESC_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL)
},
)
},
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_UUID_AVDTP_VAL)
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(0X0100u)
},
)
},
)
),
BT_SDP_LIST(
BT_SDP_ATTR_PROFILE_DESC_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_ADVANCED_AUDIO_SVCLASS)
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(0x0103U)
},
)
},
)
),
BT_SDP_SERVICE_NAME("A2DPSink"),
BT_SDP_SUPPORTED_FEATURES(0x0001U),
};
static struct bt_sdp_record a2dp_source_rec = BT_SDP_RECORD(a2dp_source_attrs);
static void shell_a2dp_print_capabilities(struct bt_a2dp_ep_info *ep_info)
{
uint8_t codec_type;
uint8_t *codec_ie;
uint16_t codec_ie_len;
codec_type = ep_info->codec_type;
codec_ie = ep_info->codec_cap.codec_ie;
codec_ie_len = ep_info->codec_cap.len;
shell_print(ctx_shell, "endpoint id: %d, %s, %s:", ep_info->sep_info.id,
(ep_info->sep_info.tsep == BT_AVDTP_SINK) ? "(sink)" : "(source)",
(ep_info->sep_info.inuse) ? "(in use)" : "(idle)");
if (BT_A2DP_SBC == codec_type) {
shell_print(ctx_shell, " codec type: SBC");
if (BT_A2DP_SBC_IE_LENGTH != codec_ie_len) {
shell_error(ctx_shell, " wrong sbc codec ie");
return;
}
shell_print(ctx_shell, " sample frequency:");
if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_16000)) {
shell_print(ctx_shell, " 16000 ");
}
if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_32000)) {
shell_print(ctx_shell, " 32000 ");
}
if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_44100)) {
shell_print(ctx_shell, " 44100 ");
}
if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_48000)) {
shell_print(ctx_shell, " 48000");
}
shell_print(ctx_shell, " channel mode:");
if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_MONO)) {
shell_print(ctx_shell, " Mono ");
}
if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_DUAL)) {
shell_print(ctx_shell, " Dual ");
}
if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_STREO)) {
shell_print(ctx_shell, " Stereo ");
}
if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_JOINT)) {
shell_print(ctx_shell, " Joint-Stereo");
}
/* Decode Support for Block Length */
shell_print(ctx_shell, " Block Length:");
if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_4)) {
shell_print(ctx_shell, " 4 ");
}
if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_8)) {
shell_print(ctx_shell, " 8 ");
}
if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_12)) {
shell_print(ctx_shell, " 12 ");
}
if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_16)) {
shell_print(ctx_shell, " 16");
}
/* Decode Support for Subbands */
shell_print(ctx_shell, " Subbands:");
if (0U != (codec_ie[1U] & A2DP_SBC_SUBBAND_4)) {
shell_print(ctx_shell, " 4 ");
}
if (0U != (codec_ie[1U] & A2DP_SBC_SUBBAND_8)) {
shell_print(ctx_shell, " 8");
}
/* Decode Support for Allocation Method */
shell_print(ctx_shell, " Allocation Method:");
if (0U != (codec_ie[1U] & A2DP_SBC_ALLOC_MTHD_SNR)) {
shell_print(ctx_shell, " SNR ");
}
if (0U != (codec_ie[1U] & A2DP_SBC_ALLOC_MTHD_LOUDNESS)) {
shell_print(ctx_shell, " Loudness");
}
shell_print(ctx_shell, " Bitpool Range: %d - %d",
codec_ie[2U], codec_ie[3U]);
} else {
shell_print(ctx_shell, " not SBC codecs");
}
}
void app_connected(struct bt_a2dp *a2dp, int err)
{
if (!err) {
default_a2dp = a2dp;
shell_print(ctx_shell, "a2dp connected");
} else {
shell_print(ctx_shell, "a2dp connecting fail");
}
}
void app_disconnected(struct bt_a2dp *a2dp)
{
found_peer_sbc_endpoint = NULL;
shell_print(ctx_shell, "a2dp disconnected");
}
int 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)
{
bt_a2dp_stream_cb_register(&sbc_stream, &stream_ops);
*stream = &sbc_stream;
*rsp_err_code = 0;
shell_print(ctx_shell, "receive requesting config and accept");
if (*rsp_err_code == 0) {
uint32_t sample_rate;
shell_print(ctx_shell, "SBC configure success");
sample_rate = bt_a2dp_sbc_get_sampling_frequency(
(struct bt_a2dp_codec_sbc_params *)&codec_cfg->codec_config->codec_ie[0]);
shell_print(ctx_shell, "sample rate %dHz", sample_rate);
} else {
shell_print(ctx_shell, "configure err");
}
return 0;
}
void app_config_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
{
if (rsp_err_code == 0) {
shell_print(ctx_shell, "success to configure");
} else {
shell_print(ctx_shell, "fail to configure");
}
}
int app_establish_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code)
{
*rsp_err_code = 0;
shell_print(ctx_shell, "receive requesting establishment and accept");
return 0;
}
void app_establish_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
{
if (rsp_err_code == 0) {
shell_print(ctx_shell, "success to establish");
} else {
shell_print(ctx_shell, "fail to establish");
}
}
int app_start_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code)
{
*rsp_err_code = 0;
shell_print(ctx_shell, "receive requesting start and accept");
return 0;
}
void app_start_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code)
{
if (rsp_err_code == 0) {
shell_print(ctx_shell, "success to start");
} else {
shell_print(ctx_shell, "fail to start");
}
}
void stream_configured(struct bt_a2dp_stream *stream)
{
shell_print(ctx_shell, "stream configured");
}
void stream_established(struct bt_a2dp_stream *stream)
{
shell_print(ctx_shell, "stream established");
}
void stream_released(struct bt_a2dp_stream *stream)
{
shell_print(ctx_shell, "stream released");
}
void stream_started(struct bt_a2dp_stream *stream)
{
shell_print(ctx_shell, "stream started");
}
void sink_sbc_streamer_data(struct bt_a2dp_stream *stream, struct net_buf *buf,
uint16_t seq_num, uint32_t ts)
{
uint8_t sbc_hdr;
sbc_hdr = net_buf_pull_u8(buf);
shell_print(ctx_shell, "received, num of frames: %d, data length:%d",
(uint8_t)BT_A2DP_SBC_MEDIA_HDR_NUM_FRAMES_GET(sbc_hdr), buf->len);
shell_print(ctx_shell, "data: %d, %d, %d, %d, %d, %d ......", buf->data[0],
buf->data[1], buf->data[2], buf->data[3], buf->data[4], buf->data[5]);
}
void stream_recv(struct bt_a2dp_stream *stream,
struct net_buf *buf, uint16_t seq_num, uint32_t ts)
{
sink_sbc_streamer_data(stream, buf, seq_num, ts);
}
struct bt_a2dp_cb a2dp_cb = {
.connected = app_connected,
.disconnected = app_disconnected,
.config_req = app_config_req,
.config_rsp = app_config_rsp,
.establish_req = app_establish_req,
.establish_rsp = app_establish_rsp,
.release_req = NULL,
.release_rsp = NULL,
.start_req = app_start_req,
.start_rsp = app_start_rsp,
.suspend_req = NULL,
.suspend_rsp = NULL,
.reconfig_req = NULL,
.reconfig_rsp = NULL,
};
static int cmd_register_cb(const struct shell *sh, int32_t argc, char *argv[])
{
int err = -1;
if (a2dp_initied == 0) {
a2dp_initied = 1;
err = bt_a2dp_register_cb(&a2dp_cb);
if (!err) {
shell_print(sh, "success");
} else {
shell_print(sh, "fail");
}
} else {
shell_print(sh, "already registered");
}
return 0;
}
static int cmd_register_ep(const struct shell *sh, int32_t argc, char *argv[])
{
int err = -1;
const char *type;
const char *action;
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
type = argv[1];
action = argv[2];
if (!strcmp(action, "sbc")) {
if (!strcmp(type, "sink")) {
if (a2dp_sink_sdp_registered == 0) {
a2dp_sink_sdp_registered = 1;
bt_sdp_register_service(&a2dp_sink_rec);
}
err = bt_a2dp_register_ep(&sink_sbc_endpoint,
BT_AVDTP_AUDIO, BT_AVDTP_SINK);
if (!err) {
shell_print(sh, "SBC sink endpoint is registered");
registered_sbc_endpoint = &sink_sbc_endpoint;
}
} else if (!strcmp(type, "source")) {
if (a2dp_source_sdp_registered == 0) {
a2dp_source_sdp_registered = 1;
bt_sdp_register_service(&a2dp_source_rec);
}
err = bt_a2dp_register_ep(&source_sbc_endpoint,
BT_AVDTP_AUDIO, BT_AVDTP_SOURCE);
if (!err) {
shell_print(sh, "SBC source endpoint is registered");
registered_sbc_endpoint = &source_sbc_endpoint;
}
} else {
shell_help(sh);
return 0;
}
} else {
shell_help(sh);
return 0;
}
if (err) {
shell_print(sh, "fail to register endpoint");
}
return 0;
}
static int cmd_connect(const struct shell *sh, int32_t argc, char *argv[])
{
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
default_a2dp = bt_a2dp_connect(default_conn);
if (NULL == default_a2dp) {
shell_error(sh, "fail to connect a2dp");
}
return 0;
}
static int cmd_disconnect(const struct shell *sh, int32_t argc, char *argv[])
{
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
if (default_a2dp != NULL) {
bt_a2dp_disconnect(default_a2dp);
default_a2dp = NULL;
} else {
shell_error(sh, "a2dp is not connected");
}
return 0;
}
void app_configured(int err)
{
if (err) {
shell_print(ctx_shell, "configure fail");
}
}
static struct bt_a2dp_stream_ops stream_ops = {
.configured = stream_configured,
.established = stream_established,
.released = stream_released,
.started = stream_started,
.suspended = NULL,
.reconfigured = NULL,
#if defined(CONFIG_BT_A2DP_SINK)
.recv = stream_recv,
#endif
#if defined(CONFIG_BT_A2DP_SOURCE)
.sent = NULL,
#endif
};
BT_A2DP_SBC_EP_CFG_DEFAULT(sbc_cfg_default, A2DP_SBC_SAMP_FREQ_44100);
static int cmd_configure(const struct shell *sh, int32_t argc, char *argv[])
{
int err;
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
if (default_a2dp != NULL) {
if (registered_sbc_endpoint == NULL) {
shell_error(sh, "no endpoint");
return 0;
}
if (found_peer_sbc_endpoint == NULL) {
shell_error(sh, "don't find the peer sbc endpoint");
return 0;
}
bt_a2dp_stream_cb_register(&sbc_stream, &stream_ops);
err = bt_a2dp_stream_config(default_a2dp, &sbc_stream,
registered_sbc_endpoint, found_peer_sbc_endpoint,
&sbc_cfg_default);
if (err) {
shell_error(sh, "fail to configure");
}
} else {
shell_error(sh, "a2dp is not connected");
}
return 0;
}
static uint8_t bt_a2dp_discover_peer_endpoint_cb(struct bt_a2dp *a2dp,
struct bt_a2dp_ep_info *info, struct bt_a2dp_ep **ep)
{
if (info != NULL) {
shell_print(ctx_shell, "find one endpoint");
shell_a2dp_print_capabilities(info);
if ((info->codec_type == BT_A2DP_SBC) &&
(ep != NULL)) {
*ep = &peer_sbc_endpoint;
found_peer_sbc_endpoint = &peer_sbc_endpoint;
}
}
return BT_A2DP_DISCOVER_EP_CONTINUE;
}
static struct bt_avdtp_sep_info found_seps[5];
struct bt_a2dp_discover_param discover_param = {
.cb = bt_a2dp_discover_peer_endpoint_cb,
.seps_info = &found_seps[0],
.sep_count = 5,
};
static int cmd_get_peer_eps(const struct shell *sh, int32_t argc, char *argv[])
{
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
if (default_a2dp != NULL) {
int err = bt_a2dp_discover(default_a2dp, &discover_param);
if (err) {
shell_error(sh, "discover fail");
}
} else {
shell_error(sh, "a2dp is not connected");
}
return 0;
}
static int cmd_establish(const struct shell *sh, int32_t argc, char *argv[])
{
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
if (bt_a2dp_stream_establish(&sbc_stream) != 0) {
shell_print(sh, "fail");
}
return 0;
}
static int cmd_start(const struct shell *sh, int32_t argc, char *argv[])
{
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
if (bt_a2dp_stream_start(&sbc_stream) != 0) {
shell_print(sh, "fail");
}
return 0;
}
static int cmd_send_media(const struct shell *sh, int32_t argc, char *argv[])
{
#if defined(CONFIG_BT_A2DP_SOURCE)
struct net_buf *buf;
int ret;
if (a2dp_initied == 0) {
shell_print(sh, "need to register a2dp connection callbacks");
return -ENOEXEC;
}
buf = net_buf_alloc(&a2dp_tx_pool, K_FOREVER);
net_buf_reserve(buf, BT_A2DP_STREAM_BUF_RESERVE);
/* num of frames is 1 */
net_buf_add_u8(buf, (uint8_t)BT_A2DP_SBC_MEDIA_HDR_ENCODE(1, 0, 0, 0));
net_buf_add_mem(buf, media_data, sizeof(media_data));
shell_print(sh, "num of frames: %d, data length: %d", 1u, sizeof(media_data));
shell_print(sh, "data: %d, %d, %d, %d, %d, %d ......", media_data[0],
media_data[1], media_data[2], media_data[3], media_data[4], media_data[5]);
ret = bt_a2dp_stream_send(&sbc_stream, buf, 0u, 0u);
if (ret < 0) {
printk(" Failed to send SBC audio data on streams(%d)\n", ret);
net_buf_unref(buf);
}
#endif
return 0;
}
#define HELP_NONE "[none]"
SHELL_STATIC_SUBCMD_SET_CREATE(a2dp_cmds,
SHELL_CMD_ARG(register_cb, NULL, "register a2dp connection callbacks",
cmd_register_cb, 1, 0),
SHELL_CMD_ARG(register_ep, NULL, "<type: sink or source> <value: sbc>",
cmd_register_ep, 3, 0),
SHELL_CMD_ARG(connect, NULL, HELP_NONE, cmd_connect, 1, 0),
SHELL_CMD_ARG(disconnect, NULL, HELP_NONE, cmd_disconnect, 1, 0),
SHELL_CMD_ARG(discover_peer_eps, NULL, HELP_NONE, cmd_get_peer_eps, 1, 0),
SHELL_CMD_ARG(configure, NULL, HELP_NONE, cmd_configure, 1, 0),
SHELL_CMD_ARG(establish, NULL, HELP_NONE, cmd_establish, 1, 0),
SHELL_CMD_ARG(start, NULL, "\"start the default selected ep\"", cmd_start, 1, 0),
SHELL_CMD_ARG(send_media, NULL, HELP_NONE, cmd_send_media, 1, 0),
SHELL_SUBCMD_SET_END
);
static int cmd_a2dp(const struct shell *sh, size_t argc, char **argv)
{
if (argc == 1) {
shell_help(sh);
/* sh returns 1 when help is printed */
return 1;
}
shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
return -ENOEXEC;
}
SHELL_CMD_ARG_REGISTER(a2dp, &a2dp_cmds, "Bluetooth A2DP sh commands",
cmd_a2dp, 1, 1);