Skip to content

Commit 70c73aa

Browse files
MarkWangChinesekartben
authored andcommitted
Bluetooth: A2DP: implement close, suspend and abort
implement avdtp close, suspend and abort and the a2dp interfaces. Signed-off-by: Mark Wang <[email protected]>
1 parent 6a6f2c2 commit 70c73aa

File tree

4 files changed

+353
-21
lines changed

4 files changed

+353
-21
lines changed

include/zephyr/bluetooth/classic/a2dp.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,28 @@ struct bt_a2dp_cb {
545545
* bt_a2dp_err_code or bt_avdtp_err_code
546546
*/
547547
void (*suspend_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code);
548+
/**
549+
* @brief Stream abort request callback
550+
*
551+
* The callback is called whenever an stream is requested to be
552+
* aborted.
553+
*
554+
* @param[in] stream Pointer to stream object.
555+
* @param[out] rsp_err_code give the error code if response error.
556+
* bt_a2dp_err_code or bt_avdtp_err_code
557+
*
558+
* @return 0 in case of success or negative value in case of error.
559+
*/
560+
int (*abort_req)(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code);
561+
/** @brief Callback function for bt_a2dp_stream_abort()
562+
*
563+
* Called when the abort operation is completed.
564+
*
565+
* @param[in] stream Pointer to stream object.
566+
* @param[in] rsp_err_code the remote responded error code
567+
* bt_a2dp_err_code or bt_avdtp_err_code
568+
*/
569+
void (*abort_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code);
548570
};
549571

550572
/** @brief A2DP Connect.
@@ -662,6 +684,15 @@ struct bt_a2dp_stream_ops {
662684
* @param stream Stream object that has been suspended.
663685
*/
664686
void (*suspended)(struct bt_a2dp_stream *stream);
687+
/**
688+
* @brief Stream abort callback
689+
*
690+
* The callback is called whenever an Audio Stream has been aborted.
691+
* After aborted, the stream becomes invalid.
692+
*
693+
* @param stream Stream object that has been aborted.
694+
*/
695+
void (*aborted)(struct bt_a2dp_stream *stream);
665696
#if defined(CONFIG_BT_A2DP_SINK)
666697
/** @brief the media streaming data, only for sink
667698
*
@@ -770,6 +801,17 @@ int bt_a2dp_stream_suspend(struct bt_a2dp_stream *stream);
770801
*/
771802
int bt_a2dp_stream_reconfig(struct bt_a2dp_stream *stream, struct bt_a2dp_codec_cfg *config);
772803

804+
/** @brief abort a2dp streamer.
805+
*
806+
* This function sends the AVDTP_ABORT command.
807+
* After abort, the stream becomes invalid.
808+
*
809+
* @param stream The stream object.
810+
*
811+
* @return 0 in case of success and error code in case of error.
812+
*/
813+
int bt_a2dp_stream_abort(struct bt_a2dp_stream *stream);
814+
773815
/** @brief get the stream l2cap mtu
774816
*
775817
* @param stream The stream object.

subsys/bluetooth/host/classic/a2dp.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,44 @@ static int a2dp_start_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, ui
351351
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false);
352352
}
353353

354+
static int a2dp_suspend_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
355+
{
356+
struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
357+
bt_a2dp_ctrl_req_cb req_cb;
358+
bt_a2dp_ctrl_done_cb done_cb;
359+
360+
__ASSERT(sep, "Invalid sep");
361+
req_cb = a2dp_cb != NULL ? a2dp_cb->suspend_req : NULL;
362+
done_cb =
363+
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->suspended : NULL;
364+
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false);
365+
}
366+
367+
static int a2dp_close_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
368+
{
369+
struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
370+
bt_a2dp_ctrl_req_cb req_cb;
371+
bt_a2dp_ctrl_done_cb done_cb;
372+
373+
__ASSERT(sep, "Invalid sep");
374+
req_cb = a2dp_cb != NULL ? a2dp_cb->release_req : NULL;
375+
done_cb =
376+
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->released : NULL;
377+
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, true);
378+
}
379+
380+
static int a2dp_abort_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode)
381+
{
382+
struct bt_a2dp_ep *ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
383+
bt_a2dp_ctrl_req_cb req_cb;
384+
bt_a2dp_ctrl_done_cb done_cb;
385+
386+
__ASSERT(sep, "Invalid sep");
387+
req_cb = a2dp_cb != NULL ? a2dp_cb->abort_req : NULL;
388+
done_cb = (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->aborted : NULL;
389+
return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, true);
390+
}
391+
354392
static int bt_a2dp_set_config_cb(struct bt_avdtp_req *req)
355393
{
356394
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)
656694
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false);
657695
}
658696

697+
static int bt_a2dp_suspend_cb(struct bt_avdtp_req *req)
698+
{
699+
struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
700+
bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->suspend_rsp : NULL;
701+
bt_a2dp_done_cb done_cb =
702+
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->suspended : NULL;
703+
704+
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false);
705+
}
706+
707+
static int bt_a2dp_close_cb(struct bt_avdtp_req *req)
708+
{
709+
struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
710+
bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->release_rsp : NULL;
711+
bt_a2dp_done_cb done_cb =
712+
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->released : NULL;
713+
714+
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, true);
715+
}
716+
717+
static int bt_a2dp_abort_cb(struct bt_avdtp_req *req)
718+
{
719+
struct bt_a2dp_ep *ep = CONTAINER_OF(CTRL_REQ(req)->sep, struct bt_a2dp_ep, sep);
720+
bt_a2dp_rsp_cb rsp_cb = a2dp_cb != NULL ? a2dp_cb->abort_rsp : NULL;
721+
bt_a2dp_done_cb done_cb =
722+
(ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->aborted : NULL;
723+
724+
return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, true);
725+
}
726+
659727
static int bt_a2dp_stream_ctrl_pre(struct bt_a2dp_stream *stream, bt_avdtp_func_t cb)
660728
{
661729
struct bt_a2dp *a2dp;
@@ -685,6 +753,18 @@ int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream)
685753
return bt_avdtp_open(&a2dp->session, &a2dp->ctrl_param);
686754
}
687755

756+
int bt_a2dp_stream_release(struct bt_a2dp_stream *stream)
757+
{
758+
int err;
759+
struct bt_a2dp *a2dp = stream->a2dp;
760+
761+
err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_close_cb);
762+
if (err) {
763+
return err;
764+
}
765+
return bt_avdtp_close(&a2dp->session, &a2dp->ctrl_param);
766+
}
767+
688768
int bt_a2dp_stream_start(struct bt_a2dp_stream *stream)
689769
{
690770
int err;
@@ -697,6 +777,30 @@ int bt_a2dp_stream_start(struct bt_a2dp_stream *stream)
697777
return bt_avdtp_start(&a2dp->session, &a2dp->ctrl_param);
698778
}
699779

780+
int bt_a2dp_stream_suspend(struct bt_a2dp_stream *stream)
781+
{
782+
int err;
783+
struct bt_a2dp *a2dp = stream->a2dp;
784+
785+
err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_suspend_cb);
786+
if (err) {
787+
return err;
788+
}
789+
return bt_avdtp_suspend(&a2dp->session, &a2dp->ctrl_param);
790+
}
791+
792+
int bt_a2dp_stream_abort(struct bt_a2dp_stream *stream)
793+
{
794+
int err;
795+
struct bt_a2dp *a2dp = stream->a2dp;
796+
797+
err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_abort_cb);
798+
if (err) {
799+
return err;
800+
}
801+
return bt_avdtp_abort(&a2dp->session, &a2dp->ctrl_param);
802+
}
803+
700804
int bt_a2dp_stream_reconfig(struct bt_a2dp_stream *stream, struct bt_a2dp_codec_cfg *config)
701805
{
702806
uint8_t remote_id;
@@ -749,6 +853,30 @@ int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, uint
749853
}
750854
#endif
751855

856+
int a2dp_stream_l2cap_disconnected(struct bt_avdtp *session, struct bt_avdtp_sep *sep)
857+
{
858+
struct bt_a2dp_ep *ep;
859+
860+
__ASSERT(sep, "Invalid sep");
861+
ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep);
862+
if (ep->stream != NULL) {
863+
struct bt_a2dp_stream_ops *ops;
864+
struct bt_a2dp_stream *stream = ep->stream;
865+
866+
ops = stream->ops;
867+
/* Many places set ep->stream as NULL like abort and close.
868+
* it should be OK without lock protection because
869+
* all the related callbacks are in the same zephyr task context.
870+
*/
871+
ep->stream = NULL;
872+
if ((ops != NULL) && (ops->released != NULL)) {
873+
ops->released(stream);
874+
}
875+
}
876+
877+
return 0;
878+
}
879+
752880
static const struct bt_avdtp_ops_cb signaling_avdtp_ops = {
753881
.connected = a2dp_connected,
754882
.disconnected = a2dp_disconnected,
@@ -759,6 +887,10 @@ static const struct bt_avdtp_ops_cb signaling_avdtp_ops = {
759887
.re_configuration_ind = a2dp_re_config_ind,
760888
.open_ind = a2dp_open_ind,
761889
.start_ind = a2dp_start_ind,
890+
.close_ind = a2dp_close_ind,
891+
.suspend_ind = a2dp_suspend_ind,
892+
.abort_ind = a2dp_abort_ind,
893+
.stream_l2cap_disconnected = a2dp_stream_l2cap_disconnected,
762894
};
763895

764896
int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session)

0 commit comments

Comments
 (0)