Bluetooth: A2DP: implement close, suspend and abort
implement avdtp close, suspend and abort and the a2dp interfaces. Signed-off-by: Mark Wang <yichang.wang@nxp.com>
This commit is contained in:
parent
6a6f2c2fca
commit
70c73aa317
4 changed files with 353 additions and 21 deletions
|
|
@ -545,6 +545,28 @@ struct bt_a2dp_cb {
|
|||
* bt_a2dp_err_code or bt_avdtp_err_code
|
||||
*/
|
||||
void (*suspend_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code);
|
||||
/**
|
||||
* @brief Stream abort request callback
|
||||
*
|
||||
* The callback is called whenever an stream is requested to be
|
||||
* aborted.
|
||||
*
|
||||
* @param[in] stream Pointer to stream object.
|
||||
* @param[out] rsp_err_code give the error code if response error.
|
||||
* bt_a2dp_err_code or bt_avdtp_err_code
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int (*abort_req)(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code);
|
||||
/** @brief Callback function for bt_a2dp_stream_abort()
|
||||
*
|
||||
* Called when the abort operation is completed.
|
||||
*
|
||||
* @param[in] stream Pointer to stream object.
|
||||
* @param[in] rsp_err_code the remote responded error code
|
||||
* bt_a2dp_err_code or bt_avdtp_err_code
|
||||
*/
|
||||
void (*abort_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code);
|
||||
};
|
||||
|
||||
/** @brief A2DP Connect.
|
||||
|
|
@ -662,6 +684,15 @@ struct bt_a2dp_stream_ops {
|
|||
* @param stream Stream object that has been suspended.
|
||||
*/
|
||||
void (*suspended)(struct bt_a2dp_stream *stream);
|
||||
/**
|
||||
* @brief Stream abort callback
|
||||
*
|
||||
* The callback is called whenever an Audio Stream has been aborted.
|
||||
* After aborted, the stream becomes invalid.
|
||||
*
|
||||
* @param stream Stream object that has been aborted.
|
||||
*/
|
||||
void (*aborted)(struct bt_a2dp_stream *stream);
|
||||
#if defined(CONFIG_BT_A2DP_SINK)
|
||||
/** @brief the media streaming data, only for sink
|
||||
*
|
||||
|
|
@ -770,6 +801,17 @@ int bt_a2dp_stream_suspend(struct bt_a2dp_stream *stream);
|
|||
*/
|
||||
int bt_a2dp_stream_reconfig(struct bt_a2dp_stream *stream, struct bt_a2dp_codec_cfg *config);
|
||||
|
||||
/** @brief abort a2dp streamer.
|
||||
*
|
||||
* This function sends the AVDTP_ABORT command.
|
||||
* After abort, the stream becomes invalid.
|
||||
*
|
||||
* @param stream The stream object.
|
||||
*
|
||||
* @return 0 in case of success and error code in case of error.
|
||||
*/
|
||||
int bt_a2dp_stream_abort(struct bt_a2dp_stream *stream);
|
||||
|
||||
/** @brief get the stream l2cap mtu
|
||||
*
|
||||
* @param stream The stream object.
|
||||
|
|
|
|||
|
|
@ -351,6 +351,44 @@ static int a2dp_start_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, ui
|
|||
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false);
|
||||
}
|
||||
|
||||
static int a2dp_suspend_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
|
||||
{
|
||||
struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
|
||||
bt_a2dp_ctrl_req_cb req_cb;
|
||||
bt_a2dp_ctrl_done_cb done_cb;
|
||||
|
||||
__ASSERT(sep, "Invalid sep");
|
||||
req_cb = a2dp_cb != NULL ? a2dp_cb->suspend_req : NULL;
|
||||
done_cb =
|
||||
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->suspended : NULL;
|
||||
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false);
|
||||
}
|
||||
|
||||
static int a2dp_close_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
|
||||
{
|
||||
struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
|
||||
bt_a2dp_ctrl_req_cb req_cb;
|
||||
bt_a2dp_ctrl_done_cb done_cb;
|
||||
|
||||
__ASSERT(sep, "Invalid sep");
|
||||
req_cb = a2dp_cb != NULL ? a2dp_cb->release_req : NULL;
|
||||
done_cb =
|
||||
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->released : NULL;
|
||||
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, true);
|
||||
}
|
||||
|
||||
static int a2dp_abort_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
|
||||
{
|
||||
struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
|
||||
bt_a2dp_ctrl_req_cb req_cb;
|
||||
bt_a2dp_ctrl_done_cb done_cb;
|
||||
|
||||
__ASSERT(sep, "Invalid sep");
|
||||
req_cb = a2dp_cb != NULL ? a2dp_cb->abort_req : NULL;
|
||||
done_cb = (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->aborted : NULL;
|
||||
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, true);
|
||||
}
|
||||
|
||||
static int bt_a2dp_set_config_cb(struct bt_avdtp_req *req)
|
||||
{
|
||||
struct bt_a2dp *a2dp = SET_CONF_PARAM(SET_CONF_REQ(req));
|
||||
|
|
@ -656,6 +694,36 @@ static int bt_a2dp_start_cb(struct bt_avdtp_req *req)
|
|||
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false);
|
||||
}
|
||||
|
||||
static int bt_a2dp_suspend_cb(struct bt_avdtp_req *req)
|
||||
{
|
||||
struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
|
||||
bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->suspend_rsp : NULL;
|
||||
bt_a2dp_done_cb done_cb =
|
||||
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->suspended : NULL;
|
||||
|
||||
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false);
|
||||
}
|
||||
|
||||
static int bt_a2dp_close_cb(struct bt_avdtp_req *req)
|
||||
{
|
||||
struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
|
||||
bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->release_rsp : NULL;
|
||||
bt_a2dp_done_cb done_cb =
|
||||
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->released : NULL;
|
||||
|
||||
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, true);
|
||||
}
|
||||
|
||||
static int bt_a2dp_abort_cb(struct bt_avdtp_req *req)
|
||||
{
|
||||
struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
|
||||
bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->abort_rsp : NULL;
|
||||
bt_a2dp_done_cb done_cb =
|
||||
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->aborted : NULL;
|
||||
|
||||
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, true);
|
||||
}
|
||||
|
||||
static int bt_a2dp_stream_ctrl_pre(struct bt_a2dp_stream *stream, bt_avdtp_func_t cb)
|
||||
{
|
||||
struct bt_a2dp *a2dp;
|
||||
|
|
@ -685,6 +753,18 @@ int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream)
|
|||
return bt_avdtp_open(&a2dp->session, &a2dp->ctrl_param);
|
||||
}
|
||||
|
||||
int bt_a2dp_stream_release(struct bt_a2dp_stream *stream)
|
||||
{
|
||||
int err;
|
||||
struct bt_a2dp *a2dp = stream->a2dp;
|
||||
|
||||
err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_close_cb);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
return bt_avdtp_close(&a2dp->session, &a2dp->ctrl_param);
|
||||
}
|
||||
|
||||
int bt_a2dp_stream_start(struct bt_a2dp_stream *stream)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -697,6 +777,30 @@ int bt_a2dp_stream_start(struct bt_a2dp_stream *stream)
|
|||
return bt_avdtp_start(&a2dp->session, &a2dp->ctrl_param);
|
||||
}
|
||||
|
||||
int bt_a2dp_stream_suspend(struct bt_a2dp_stream *stream)
|
||||
{
|
||||
int err;
|
||||
struct bt_a2dp *a2dp = stream->a2dp;
|
||||
|
||||
err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_suspend_cb);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
return bt_avdtp_suspend(&a2dp->session, &a2dp->ctrl_param);
|
||||
}
|
||||
|
||||
int bt_a2dp_stream_abort(struct bt_a2dp_stream *stream)
|
||||
{
|
||||
int err;
|
||||
struct bt_a2dp *a2dp = stream->a2dp;
|
||||
|
||||
err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_abort_cb);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
return bt_avdtp_abort(&a2dp->session, &a2dp->ctrl_param);
|
||||
}
|
||||
|
||||
int bt_a2dp_stream_reconfig(struct bt_a2dp_stream *stream, struct bt_a2dp_codec_cfg *config)
|
||||
{
|
||||
uint8_t remote_id;
|
||||
|
|
@ -749,6 +853,30 @@ int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, uint
|
|||
}
|
||||
#endif
|
||||
|
||||
int a2dp_stream_l2cap_disconnected(struct bt_avdtp *session, struct bt_avdtp_sep *sep)
|
||||
{
|
||||
struct bt_a2dp_ep *ep;
|
||||
|
||||
__ASSERT(sep, "Invalid sep");
|
||||
ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
|
||||
if (ep->stream != NULL) {
|
||||
struct bt_a2dp_stream_ops *ops;
|
||||
struct bt_a2dp_stream *stream = ep->stream;
|
||||
|
||||
ops = stream->ops;
|
||||
/* Many places set ep->stream as NULL like abort and close.
|
||||
* it should be OK without lock protection because
|
||||
* all the related callbacks are in the same zephyr task context.
|
||||
*/
|
||||
ep->stream = NULL;
|
||||
if ((ops != NULL) && (ops->released != NULL)) {
|
||||
ops->released(stream);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bt_avdtp_ops_cb signaling_avdtp_ops = {
|
||||
.connected = a2dp_connected,
|
||||
.disconnected = a2dp_disconnected,
|
||||
|
|
@ -759,6 +887,10 @@ static const struct bt_avdtp_ops_cb signaling_avdtp_ops = {
|
|||
.re_configuration_ind = a2dp_re_config_ind,
|
||||
.open_ind = a2dp_open_ind,
|
||||
.start_ind = a2dp_start_ind,
|
||||
.close_ind = a2dp_close_ind,
|
||||
.suspend_ind = a2dp_suspend_ind,
|
||||
.abort_ind = a2dp_abort_ind,
|
||||
.stream_l2cap_disconnected = a2dp_stream_l2cap_disconnected,
|
||||
};
|
||||
|
||||
int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session)
|
||||
|
|
|
|||
|
|
@ -145,12 +145,36 @@ void bt_avdtp_media_l2cap_connected(struct bt_l2cap_chan *chan)
|
|||
|
||||
void bt_avdtp_media_l2cap_disconnected(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
struct bt_avdtp *session;
|
||||
struct bt_avdtp_sep *sep = CONTAINER_OF(chan, struct bt_avdtp_sep, chan.chan);
|
||||
|
||||
session = sep->session;
|
||||
if (session == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("chan %p", chan);
|
||||
chan->conn = NULL;
|
||||
if (sep->state > AVDTP_OPENING) {
|
||||
sep->state = AVDTP_OPENING;
|
||||
avdtp_sep_lock(sep);
|
||||
if ((sep->state == AVDTP_CLOSING) && (session->req != NULL) &&
|
||||
(session->req->sig == BT_AVDTP_CLOSE)) {
|
||||
/* closing the stream */
|
||||
struct bt_avdtp_req *req = session->req;
|
||||
|
||||
bt_avdtp_set_state(sep, AVDTP_IDLE);
|
||||
avdtp_sep_unlock(sep);
|
||||
req->status = 0;
|
||||
bt_avdtp_clear_req(session);
|
||||
if (req->func != NULL) {
|
||||
req->func(req);
|
||||
}
|
||||
} else if (sep->state > AVDTP_OPENING) {
|
||||
bt_avdtp_set_state(sep, AVDTP_IDLE);
|
||||
avdtp_sep_unlock(sep);
|
||||
/* the l2cap is disconnected by other unexpected reasons */
|
||||
session->ops->stream_l2cap_disconnected(session, sep);
|
||||
} else {
|
||||
avdtp_sep_unlock(sep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,6 +210,15 @@ static int avdtp_media_connect(struct bt_avdtp *session, struct bt_avdtp_sep *se
|
|||
BT_L2CAP_PSM_AVDTP);
|
||||
}
|
||||
|
||||
static int avdtp_media_disconnect(struct bt_avdtp_sep *sep)
|
||||
{
|
||||
if (sep == NULL || sep->chan.chan.conn == NULL || sep->chan.chan.ops == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return bt_l2cap_chan_disconnect(&sep->chan.chan);
|
||||
}
|
||||
|
||||
static struct net_buf *avdtp_create_reply_pdu(uint8_t msg_type, uint8_t pkt_type, uint8_t sig_id,
|
||||
uint8_t tid)
|
||||
{
|
||||
|
|
@ -680,15 +713,17 @@ static void avdtp_close_handler(struct bt_avdtp *session, struct net_buf *buf, u
|
|||
{
|
||||
if (msg_type == BT_AVDTP_CMD) {
|
||||
int err = 0;
|
||||
int ret;
|
||||
struct bt_avdtp_sep *sep;
|
||||
struct net_buf *rsp_buf;
|
||||
uint8_t error_code = 0;
|
||||
|
||||
sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2);
|
||||
sep = avdtp_get_cmd_sep(buf);
|
||||
avdtp_sep_lock(sep);
|
||||
if ((sep == NULL) || (session->ops->close_ind == NULL)) {
|
||||
err = -ENOTSUP;
|
||||
} else {
|
||||
if (sep->state != AVDTP_OPEN) {
|
||||
if (!(sep->state & (AVDTP_OPEN | AVDTP_STREAMING))) {
|
||||
err = -ENOTSUP;
|
||||
error_code = BT_AVDTP_BAD_STATE;
|
||||
} else {
|
||||
|
|
@ -699,6 +734,7 @@ static void avdtp_close_handler(struct bt_avdtp *session, struct net_buf *buf, u
|
|||
rsp_buf = avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT,
|
||||
BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_CLOSE, tid);
|
||||
if (!rsp_buf) {
|
||||
avdtp_sep_unlock(sep);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -709,16 +745,36 @@ static void avdtp_close_handler(struct bt_avdtp *session, struct net_buf *buf, u
|
|||
LOG_DBG("close err code:%d", error_code);
|
||||
net_buf_add_u8(rsp_buf, error_code);
|
||||
} else {
|
||||
sep->state = AVDTP_CONFIGURED;
|
||||
sep->sep_info.inuse = 0u;
|
||||
bt_avdtp_set_state(sep, AVDTP_CLOSING);
|
||||
}
|
||||
|
||||
err = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
|
||||
if (err < 0) {
|
||||
ret = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
|
||||
if (ret) {
|
||||
net_buf_unref(rsp_buf);
|
||||
LOG_ERR("Error:L2CAP send fail - result = %d", err);
|
||||
LOG_ERR("Error:L2CAP send fail - result = %d", ret);
|
||||
}
|
||||
if (!err && !ret) {
|
||||
bt_avdtp_set_state(sep, AVDTP_IDLE);
|
||||
}
|
||||
avdtp_sep_unlock(sep);
|
||||
} else {
|
||||
struct bt_avdtp_req *req = session->req;
|
||||
|
||||
if (req == NULL) {
|
||||
return;
|
||||
}
|
||||
k_work_cancel_delayable(&session->timeout_work);
|
||||
avdtp_set_status(req, buf, msg_type);
|
||||
if (msg_type == BT_AVDTP_ACCEPT) {
|
||||
bt_avdtp_set_state_lock(CTRL_REQ(req)->sep, AVDTP_CLOSING);
|
||||
if (!avdtp_media_disconnect(CTRL_REQ(req)->sep)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
bt_avdtp_clear_req(session);
|
||||
if (req->func != NULL) {
|
||||
req->func(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -727,11 +783,13 @@ static void avdtp_suspend_handler(struct bt_avdtp *session, struct net_buf *buf,
|
|||
{
|
||||
if (msg_type == BT_AVDTP_CMD) {
|
||||
int err = 0;
|
||||
int ret;
|
||||
struct bt_avdtp_sep *sep;
|
||||
struct net_buf *rsp_buf;
|
||||
uint8_t error_code = 0;
|
||||
|
||||
sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2);
|
||||
sep = avdtp_get_cmd_sep(buf);
|
||||
avdtp_sep_lock(sep);
|
||||
if ((sep == NULL) || (session->ops->suspend_ind == NULL)) {
|
||||
err = -ENOTSUP;
|
||||
} else {
|
||||
|
|
@ -747,6 +805,7 @@ static void avdtp_suspend_handler(struct bt_avdtp *session, struct net_buf *buf,
|
|||
avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT,
|
||||
BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_SUSPEND, tid);
|
||||
if (!rsp_buf) {
|
||||
avdtp_sep_unlock(sep);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -756,16 +815,41 @@ static void avdtp_suspend_handler(struct bt_avdtp *session, struct net_buf *buf,
|
|||
}
|
||||
LOG_DBG("suspend err code:%d", error_code);
|
||||
net_buf_add_u8(rsp_buf, error_code);
|
||||
} else {
|
||||
sep->state = AVDTP_OPEN;
|
||||
}
|
||||
|
||||
err = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
|
||||
if (err < 0) {
|
||||
ret = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
|
||||
if (ret) {
|
||||
net_buf_unref(rsp_buf);
|
||||
LOG_ERR("Error:L2CAP send fail - result = %d", err);
|
||||
LOG_ERR("Error:L2CAP send fail - result = %d", ret);
|
||||
}
|
||||
if (!err && !ret) {
|
||||
bt_avdtp_set_state(sep, AVDTP_OPEN);
|
||||
}
|
||||
avdtp_sep_unlock(sep);
|
||||
} else {
|
||||
struct bt_avdtp_req *req = session->req;
|
||||
|
||||
if (req == NULL) {
|
||||
return;
|
||||
}
|
||||
k_work_cancel_delayable(&session->timeout_work);
|
||||
if (msg_type == BT_AVDTP_ACCEPT) {
|
||||
bt_avdtp_set_state_lock(CTRL_REQ(req)->sep, AVDTP_OPEN);
|
||||
} else if (msg_type == BT_AVDTP_REJECT) {
|
||||
if (buf->len >= 1U) {
|
||||
uint8_t acp_seid;
|
||||
|
||||
acp_seid = net_buf_pull_u8(buf);
|
||||
if (acp_seid != CTRL_REQ(req)->acp_stream_ep_id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
avdtp_set_status(req, buf, msg_type);
|
||||
bt_avdtp_clear_req(session);
|
||||
if (req->func != NULL) {
|
||||
req->func(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -774,20 +858,24 @@ static void avdtp_abort_handler(struct bt_avdtp *session, struct net_buf *buf, u
|
|||
{
|
||||
if (msg_type == BT_AVDTP_CMD) {
|
||||
int err = 0;
|
||||
int ret;
|
||||
struct bt_avdtp_sep *sep;
|
||||
struct net_buf *rsp_buf;
|
||||
uint8_t error_code = 0;
|
||||
|
||||
sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2);
|
||||
sep = avdtp_get_cmd_sep(buf);
|
||||
avdtp_sep_lock(sep);
|
||||
if ((sep == NULL) || (session->ops->abort_ind == NULL)) {
|
||||
err = -ENOTSUP;
|
||||
} else {
|
||||
/* all current sep state is OK for abort operation */
|
||||
err = session->ops->abort_ind(session, sep, &error_code);
|
||||
}
|
||||
|
||||
rsp_buf = avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT,
|
||||
BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_ABORT, tid);
|
||||
if (!rsp_buf) {
|
||||
avdtp_sep_unlock(sep);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -797,16 +885,57 @@ static void avdtp_abort_handler(struct bt_avdtp *session, struct net_buf *buf, u
|
|||
}
|
||||
LOG_DBG("abort err code:%d", error_code);
|
||||
net_buf_add_u8(rsp_buf, error_code);
|
||||
} else {
|
||||
sep->state = AVDTP_IDLE;
|
||||
}
|
||||
|
||||
err = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
|
||||
if (err < 0) {
|
||||
ret = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
|
||||
if (ret) {
|
||||
net_buf_unref(rsp_buf);
|
||||
LOG_ERR("Error:L2CAP send fail - result = %d", err);
|
||||
LOG_ERR("Error:L2CAP send fail - result = %d", ret);
|
||||
}
|
||||
if (!err && !ret) {
|
||||
if ((sep->state & (AVDTP_OPEN | AVDTP_STREAMING)) &&
|
||||
(sep->chan.state == BT_L2CAP_CONNECTED)) {
|
||||
bt_avdtp_set_state(sep, AVDTP_ABORTING);
|
||||
} else {
|
||||
bt_avdtp_set_state(sep, AVDTP_IDLE);
|
||||
}
|
||||
}
|
||||
avdtp_sep_unlock(sep);
|
||||
} else {
|
||||
struct bt_avdtp_req *req = session->req;
|
||||
|
||||
if (req == NULL) {
|
||||
return;
|
||||
}
|
||||
k_work_cancel_delayable(&session->timeout_work);
|
||||
if (msg_type == BT_AVDTP_ACCEPT) {
|
||||
uint8_t pre_state = CTRL_REQ(req)->sep->state;
|
||||
|
||||
bt_avdtp_set_state_lock(CTRL_REQ(req)->sep, AVDTP_ABORTING);
|
||||
/* release stream */
|
||||
if (pre_state & (AVDTP_OPEN | AVDTP_STREAMING)) {
|
||||
avdtp_media_disconnect(CTRL_REQ(req)->sep);
|
||||
}
|
||||
|
||||
/* For abort, make sure the state revert to IDLE state after
|
||||
* releasing l2cap channel.
|
||||
*/
|
||||
bt_avdtp_set_state_lock(CTRL_REQ(req)->sep, AVDTP_IDLE);
|
||||
} else if (msg_type == BT_AVDTP_REJECT) {
|
||||
if (buf->len >= 1U) {
|
||||
uint8_t acp_seid;
|
||||
|
||||
acp_seid = net_buf_pull_u8(buf);
|
||||
if (acp_seid != CTRL_REQ(req)->acp_stream_ep_id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
avdtp_set_status(req, buf, msg_type);
|
||||
bt_avdtp_clear_req(session);
|
||||
if (req->func != NULL) {
|
||||
req->func(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1402,6 +1531,11 @@ int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param)
|
|||
return bt_avdtp_ctrl(session, param, BT_AVDTP_OPEN, AVDTP_CONFIGURED);
|
||||
}
|
||||
|
||||
int bt_avdtp_close(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param)
|
||||
{
|
||||
return bt_avdtp_ctrl(session, param, BT_AVDTP_CLOSE, AVDTP_OPEN | AVDTP_STREAMING);
|
||||
}
|
||||
|
||||
int bt_avdtp_start(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -1414,6 +1548,18 @@ int bt_avdtp_start(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param)
|
|||
return err;
|
||||
}
|
||||
|
||||
int bt_avdtp_suspend(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param)
|
||||
{
|
||||
return bt_avdtp_ctrl(session, param, BT_AVDTP_SUSPEND, AVDTP_STREAMING);
|
||||
}
|
||||
|
||||
int bt_avdtp_abort(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param)
|
||||
{
|
||||
return bt_avdtp_ctrl(session, param, BT_AVDTP_ABORT,
|
||||
AVDTP_CONFIGURED | AVDTP_OPENING | AVDTP_OPEN | AVDTP_STREAMING |
|
||||
AVDTP_CLOSING);
|
||||
}
|
||||
|
||||
int bt_avdtp_send_media_data(struct bt_avdtp_sep *sep, struct net_buf *buf)
|
||||
{
|
||||
int err;
|
||||
|
|
|
|||
|
|
@ -202,6 +202,9 @@ struct bt_avdtp_ops_cb {
|
|||
int (*suspend_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode);
|
||||
|
||||
int (*abort_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode);
|
||||
|
||||
/* stream l2cap is closed */
|
||||
int (*stream_l2cap_disconnected)(struct bt_avdtp *session, struct bt_avdtp_sep *sep);
|
||||
};
|
||||
|
||||
/** @brief Global AVDTP session structure. */
|
||||
|
|
@ -258,9 +261,18 @@ int bt_avdtp_reconfigure(struct bt_avdtp *session, struct bt_avdtp_set_configura
|
|||
/* AVDTP OPEN */
|
||||
int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param);
|
||||
|
||||
/* AVDTP CLOSE */
|
||||
int bt_avdtp_close(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param);
|
||||
|
||||
/* AVDTP START */
|
||||
int bt_avdtp_start(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param);
|
||||
|
||||
/* AVDTP SUSPEND */
|
||||
int bt_avdtp_suspend(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param);
|
||||
|
||||
/* AVDTP ABORT */
|
||||
int bt_avdtp_abort(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param);
|
||||
|
||||
/* AVDTP send data */
|
||||
int bt_avdtp_send_media_data(struct bt_avdtp_sep *sep, struct net_buf *buf);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue