From efb362956c819c0d1152cafa087fab4ca9540864 Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Sun, 29 Sep 2024 10:51:10 +0800 Subject: [PATCH 1/4] Bluetooth: A2DP: clang-format the codes run clang-format Signed-off-by: Mark Wang --- include/zephyr/bluetooth/classic/a2dp.h | 145 +++++----- include/zephyr/bluetooth/classic/avdtp.h | 9 +- subsys/bluetooth/host/classic/a2dp.c | 101 +++---- subsys/bluetooth/host/classic/avdtp.c | 265 +++++++----------- .../bluetooth/host/classic/avdtp_internal.h | 100 +++---- 5 files changed, 286 insertions(+), 334 deletions(-) diff --git a/include/zephyr/bluetooth/classic/a2dp.h b/include/zephyr/bluetooth/classic/a2dp.h index ae276caa8d03a..51262c03b3694 100644 --- a/include/zephyr/bluetooth/classic/a2dp.h +++ b/include/zephyr/bluetooth/classic/a2dp.h @@ -30,34 +30,33 @@ extern "C" { /** MPEG2,4 IE length */ #define BT_A2DP_MPEG_2_4_IE_LENGTH (6u) /** The max IE (Codec Info Element) length */ -#define A2DP_MAX_IE_LENGTH (8U) +#define A2DP_MAX_IE_LENGTH (8U) /** @brief define the audio endpoint * @param _role BT_AVDTP_SOURCE or BT_AVDTP_SINK. * @param _codec value of enum bt_a2dp_codec_id. * @param _capability the codec capability. */ -#define BT_A2DP_EP_INIT(_role, _codec, _capability)\ -{\ - .codec_type = _codec,\ - .sep = {.sep_info = {.media_type = BT_AVDTP_AUDIO, .tsep = _role}},\ - .codec_cap = _capability,\ - .stream = NULL,\ -} +#define BT_A2DP_EP_INIT(_role, _codec, _capability) \ + { \ + .codec_type = _codec, \ + .sep = {.sep_info = {.media_type = BT_AVDTP_AUDIO, .tsep = _role}}, \ + .codec_cap = _capability, .stream = NULL, \ + } /** @brief define the audio sink endpoint * @param _codec value of enum bt_a2dp_codec_id. * @param _capability the codec capability. */ -#define BT_A2DP_SINK_EP_INIT(_codec, _capability)\ -BT_A2DP_EP_INIT(BT_AVDTP_SINK, _codec, _capability) +#define BT_A2DP_SINK_EP_INIT(_codec, _capability) \ + BT_A2DP_EP_INIT(BT_AVDTP_SINK, _codec, _capability) /** @brief define the audio source endpoint * @param _codec value of enum bt_a2dp_codec_id. * @param _capability the codec capability. */ -#define BT_A2DP_SOURCE_EP_INIT(_codec, _capability)\ -BT_A2DP_EP_INIT(BT_AVDTP_SOURCE, _codec, _capability) +#define BT_A2DP_SOURCE_EP_INIT(_codec, _capability) \ + BT_A2DP_EP_INIT(BT_AVDTP_SOURCE, _codec, _capability) /** @brief define the SBC sink endpoint that can be used as * bt_a2dp_register_endpoint's parameter. @@ -80,13 +79,14 @@ BT_A2DP_EP_INIT(BT_AVDTP_SOURCE, _codec, _capability) * @param _max_bitpool sbc codec max bit pool. for example: 35 * @ */ -#define BT_A2DP_SBC_SINK_EP(_name, _freq, _ch_mode, _blk_len, _subband,\ -_alloc_mthd, _min_bitpool, _max_bitpool)\ -static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name =\ -{.len = BT_A2DP_SBC_IE_LENGTH, .codec_ie = {_freq | _ch_mode,\ -_blk_len | _subband | _alloc_mthd, _min_bitpool, _max_bitpool}};\ -static struct bt_a2dp_ep _name = BT_A2DP_SINK_EP_INIT(BT_A2DP_SBC,\ -(&bt_a2dp_ep_cap_ie##_name)) +#define BT_A2DP_SBC_SINK_EP(_name, _freq, _ch_mode, _blk_len, _subband, _alloc_mthd, _min_bitpool, \ + _max_bitpool) \ + static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name = { \ + .len = BT_A2DP_SBC_IE_LENGTH, \ + .codec_ie = {_freq | _ch_mode, _blk_len | _subband | _alloc_mthd, _min_bitpool, \ + _max_bitpool}}; \ + static struct bt_a2dp_ep _name = \ + BT_A2DP_SINK_EP_INIT(BT_A2DP_SBC, (&bt_a2dp_ep_cap_ie##_name)) /** @brief define the SBC source endpoint that can be used as bt_a2dp_register_endpoint's * parameter. @@ -108,13 +108,14 @@ static struct bt_a2dp_ep _name = BT_A2DP_SINK_EP_INIT(BT_A2DP_SBC,\ * @param _min_bitpool sbc codec min bit pool. for example: 18 * @param _max_bitpool sbc codec max bit pool. for example: 35 */ -#define BT_A2DP_SBC_SOURCE_EP(_name, _freq, _ch_mode, _blk_len, _subband,\ -_alloc_mthd, _min_bitpool, _max_bitpool)\ -static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name =\ -{.len = BT_A2DP_SBC_IE_LENGTH, .codec_ie = {_freq | _ch_mode,\ -_blk_len | _subband | _alloc_mthd, _min_bitpool, _max_bitpool}};\ -static struct bt_a2dp_ep _name = BT_A2DP_SOURCE_EP_INIT(BT_A2DP_SBC,\ -&bt_a2dp_ep_cap_ie##_name) +#define BT_A2DP_SBC_SOURCE_EP(_name, _freq, _ch_mode, _blk_len, _subband, _alloc_mthd, \ + _min_bitpool, _max_bitpool) \ + static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name = { \ + .len = BT_A2DP_SBC_IE_LENGTH, \ + .codec_ie = {_freq | _ch_mode, _blk_len | _subband | _alloc_mthd, _min_bitpool, \ + _max_bitpool}}; \ + static struct bt_a2dp_ep _name = \ + BT_A2DP_SOURCE_EP_INIT(BT_A2DP_SBC, &bt_a2dp_ep_cap_ie##_name) /** @brief define the default SBC sink endpoint that can be used as * bt_a2dp_register_endpoint's parameter. @@ -124,14 +125,17 @@ static struct bt_a2dp_ep _name = BT_A2DP_SOURCE_EP_INIT(BT_A2DP_SBC,\ * * @param _name the endpoint variable name. */ -#define BT_A2DP_SBC_SINK_EP_DEFAULT(_name)\ -static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name =\ -{.len = BT_A2DP_SBC_IE_LENGTH, .codec_ie = {A2DP_SBC_SAMP_FREQ_44100 |\ -A2DP_SBC_SAMP_FREQ_48000 | A2DP_SBC_CH_MODE_MONO | A2DP_SBC_CH_MODE_STREO |\ -A2DP_SBC_CH_MODE_JOINT, A2DP_SBC_BLK_LEN_16 |\ -A2DP_SBC_SUBBAND_8 | A2DP_SBC_ALLOC_MTHD_LOUDNESS, 18U, 35U}};\ -static struct bt_a2dp_ep _name = BT_A2DP_SINK_EP_INIT(BT_A2DP_SBC,\ -&bt_a2dp_ep_cap_ie##_name) +#define BT_A2DP_SBC_SINK_EP_DEFAULT(_name) \ + static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name = { \ + .len = BT_A2DP_SBC_IE_LENGTH, \ + .codec_ie = {A2DP_SBC_SAMP_FREQ_44100 | A2DP_SBC_SAMP_FREQ_48000 | \ + A2DP_SBC_CH_MODE_MONO | A2DP_SBC_CH_MODE_STREO | \ + A2DP_SBC_CH_MODE_JOINT, \ + A2DP_SBC_BLK_LEN_16 | A2DP_SBC_SUBBAND_8 | \ + A2DP_SBC_ALLOC_MTHD_LOUDNESS, \ + 18U, 35U}}; \ + static struct bt_a2dp_ep _name = \ + BT_A2DP_SINK_EP_INIT(BT_A2DP_SBC, &bt_a2dp_ep_cap_ie##_name) /** @brief define the default SBC source endpoint that can be used as bt_a2dp_register_endpoint's * parameter. @@ -141,14 +145,18 @@ static struct bt_a2dp_ep _name = BT_A2DP_SINK_EP_INIT(BT_A2DP_SBC,\ * * @param _name the endpoint variable name. */ -#define BT_A2DP_SBC_SOURCE_EP_DEFAULT(_name)\ -static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name =\ -{.len = BT_A2DP_SBC_IE_LENGTH, .codec_ie = {A2DP_SBC_SAMP_FREQ_44100 | \ -A2DP_SBC_SAMP_FREQ_48000 | A2DP_SBC_CH_MODE_MONO | A2DP_SBC_CH_MODE_STREO | \ -A2DP_SBC_CH_MODE_JOINT, A2DP_SBC_BLK_LEN_16 | A2DP_SBC_SUBBAND_8 | A2DP_SBC_ALLOC_MTHD_LOUDNESS,\ -18U, 35U},};\ -static struct bt_a2dp_ep _name = BT_A2DP_SOURCE_EP_INIT(BT_A2DP_SBC,\ -&bt_a2dp_ep_cap_ie##_name) +#define BT_A2DP_SBC_SOURCE_EP_DEFAULT(_name) \ + static struct bt_a2dp_codec_ie bt_a2dp_ep_cap_ie##_name = { \ + .len = BT_A2DP_SBC_IE_LENGTH, \ + .codec_ie = {A2DP_SBC_SAMP_FREQ_44100 | A2DP_SBC_SAMP_FREQ_48000 | \ + A2DP_SBC_CH_MODE_MONO | A2DP_SBC_CH_MODE_STREO | \ + A2DP_SBC_CH_MODE_JOINT, \ + A2DP_SBC_BLK_LEN_16 | A2DP_SBC_SUBBAND_8 | \ + A2DP_SBC_ALLOC_MTHD_LOUDNESS, \ + 18U, 35U}, \ + }; \ + static struct bt_a2dp_ep _name = \ + BT_A2DP_SOURCE_EP_INIT(BT_A2DP_SBC, &bt_a2dp_ep_cap_ie##_name) /** @brief define the SBC default configuration. * @@ -166,23 +174,34 @@ static struct bt_a2dp_ep _name = BT_A2DP_SOURCE_EP_INIT(BT_A2DP_SBC,\ * @param _min_bitpool_cfg sbc codec min bit pool. for example: 18 * @param _max_bitpool_cfg sbc codec max bit pool. for example: 35 */ -#define BT_A2DP_SBC_EP_CFG(_name, _freq_cfg, _ch_mode_cfg, _blk_len_cfg, _subband_cfg,\ -_alloc_mthd_cfg, _min_bitpool_cfg, _max_bitpool_cfg)\ -static struct bt_a2dp_codec_ie bt_a2dp_codec_ie##_name = {\ -.len = BT_A2DP_SBC_IE_LENGTH, .codec_ie = {_freq_cfg | _ch_mode_cfg,\ -_blk_len_cfg | _subband_cfg | _alloc_mthd_cfg, _min_bitpool_cfg, _max_bitpool_cfg},};\ -struct bt_a2dp_codec_cfg _name = {.codec_config = &bt_a2dp_codec_ie##_name,} +#define BT_A2DP_SBC_EP_CFG(_name, _freq_cfg, _ch_mode_cfg, _blk_len_cfg, _subband_cfg, \ + _alloc_mthd_cfg, _min_bitpool_cfg, _max_bitpool_cfg) \ + static struct bt_a2dp_codec_ie bt_a2dp_codec_ie##_name = { \ + .len = BT_A2DP_SBC_IE_LENGTH, \ + .codec_ie = {_freq_cfg | _ch_mode_cfg, \ + _blk_len_cfg | _subband_cfg | _alloc_mthd_cfg, _min_bitpool_cfg, \ + _max_bitpool_cfg}, \ + }; \ + struct bt_a2dp_codec_cfg _name = { \ + .codec_config = &bt_a2dp_codec_ie##_name, \ + } /** @brief define the SBC default configuration. * * @param _name unique structure name postfix. * @param _freq_cfg the frequency to configure the remote same codec type endpoint. */ -#define BT_A2DP_SBC_EP_CFG_DEFAULT(_name, _freq_cfg)\ -static struct bt_a2dp_codec_ie bt_a2dp_codec_ie##_name = {\ -.len = BT_A2DP_SBC_IE_LENGTH, .codec_ie = {_freq_cfg | A2DP_SBC_CH_MODE_JOINT,\ -A2DP_SBC_BLK_LEN_16 | A2DP_SBC_SUBBAND_8 | A2DP_SBC_ALLOC_MTHD_LOUDNESS, 18U, 35U},};\ -struct bt_a2dp_codec_cfg _name = {.codec_config = &bt_a2dp_codec_ie##_name,} +#define BT_A2DP_SBC_EP_CFG_DEFAULT(_name, _freq_cfg) \ + static struct bt_a2dp_codec_ie bt_a2dp_codec_ie##_name = { \ + .len = BT_A2DP_SBC_IE_LENGTH, \ + .codec_ie = {_freq_cfg | A2DP_SBC_CH_MODE_JOINT, \ + A2DP_SBC_BLK_LEN_16 | A2DP_SBC_SUBBAND_8 | \ + A2DP_SBC_ALLOC_MTHD_LOUDNESS, \ + 18U, 35U}, \ + }; \ + struct bt_a2dp_codec_cfg _name = { \ + .codec_config = &bt_a2dp_codec_ie##_name, \ + } /** * @brief A2DP error code @@ -358,8 +377,8 @@ enum { * for next endpoint. By returning BT_A2DP_DISCOVER_EP_STOP user allows this * discovery continuation. */ -typedef uint8_t (*bt_a2dp_discover_ep_cb)(struct bt_a2dp *a2dp, - struct bt_a2dp_ep_info *info, struct bt_a2dp_ep **ep); +typedef uint8_t (*bt_a2dp_discover_ep_cb)(struct bt_a2dp *a2dp, struct bt_a2dp_ep_info *info, + struct bt_a2dp_ep **ep); struct bt_a2dp_discover_param { /** discover callback */ @@ -411,8 +430,8 @@ struct bt_a2dp_cb { * @return 0 in case of success or negative value in case of error. */ int (*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); + struct bt_a2dp_codec_cfg *codec_cfg, struct bt_a2dp_stream **stream, + uint8_t *rsp_err_code); /** @brief Callback function for bt_a2dp_stream_config() * * Called when the codec configure operation is completed. @@ -665,8 +684,8 @@ struct bt_a2dp_stream_ops { * @param seq_num the sequence number * @param ts the time stamp */ - void (*recv)(struct bt_a2dp_stream *stream, - struct net_buf *buf, uint16_t seq_num, uint32_t ts); + void (*recv)(struct bt_a2dp_stream *stream, struct net_buf *buf, uint16_t seq_num, + uint32_t ts); #endif #if defined(CONFIG_BT_A2DP_SOURCE) /** @@ -711,8 +730,8 @@ void bt_a2dp_stream_cb_register(struct bt_a2dp_stream *stream, struct bt_a2dp_st * @return 0 in case of success and error code in case of error. */ int bt_a2dp_stream_config(struct bt_a2dp *a2dp, struct bt_a2dp_stream *stream, - struct bt_a2dp_ep *local_ep, struct bt_a2dp_ep *remote_ep, - struct bt_a2dp_codec_cfg *config); + struct bt_a2dp_ep *local_ep, struct bt_a2dp_ep *remote_ep, + struct bt_a2dp_codec_cfg *config); /** @brief establish a2dp streamer. * @@ -785,8 +804,8 @@ uint32_t bt_a2dp_get_mtu(struct bt_a2dp_stream *stream); * * @return 0 in case of success and error code in case of error. */ -int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, - uint16_t seq_num, uint32_t ts); +int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, uint16_t seq_num, + uint32_t ts); #endif #ifdef __cplusplus diff --git a/include/zephyr/bluetooth/classic/avdtp.h b/include/zephyr/bluetooth/classic/avdtp.h index cfd419239783e..850e0945f36bf 100644 --- a/include/zephyr/bluetooth/classic/avdtp.h +++ b/include/zephyr/bluetooth/classic/avdtp.h @@ -87,11 +87,11 @@ enum bt_avdtp_media_type { */ struct bt_avdtp_sep_info { /** End Point usage status */ - uint8_t inuse:1; + uint8_t inuse: 1; /** Stream End Point ID that is the identifier of the stream endpoint */ - uint8_t id:6; + uint8_t id: 6; /** Reserved */ - uint8_t reserved:1; + uint8_t reserved: 1; /** Stream End-point Type that indicates if the stream end-point is SNK or SRC */ enum bt_avdtp_sep_type tsep; /** Media-type of the End Point @@ -127,8 +127,7 @@ struct bt_avdtp_sep { /** Media Transport Channel*/ struct bt_l2cap_br_chan chan; /** the endpoint media data */ - void (*media_data_cb)(struct bt_avdtp_sep *sep, - struct net_buf *buf); + void (*media_data_cb)(struct bt_avdtp_sep *sep, struct net_buf *buf); /** avdtp session */ struct bt_avdtp *session; /** SEP state */ diff --git a/subsys/bluetooth/host/classic/a2dp.c b/subsys/bluetooth/host/classic/a2dp.c index 5cb5203e6e28c..3c34c5ca7bc75 100644 --- a/subsys/bluetooth/host/classic/a2dp.c +++ b/subsys/bluetooth/host/classic/a2dp.c @@ -29,17 +29,17 @@ #define A2DP_AVDTP(_avdtp) CONTAINER_OF(_avdtp, struct bt_a2dp, session) #define DISCOVER_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_discover_params, req) -#define DISCOVER_PARAM(_discover_param) CONTAINER_OF(_discover_param, struct bt_a2dp,\ - discover_param) +#define DISCOVER_PARAM(_discover_param) \ + CONTAINER_OF(_discover_param, struct bt_a2dp, discover_param) #define GET_CAP_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_get_capabilities_params, req) -#define GET_CAP_PARAM(_get_cap_param) CONTAINER_OF(_get_cap_param, struct bt_a2dp,\ - get_capabilities_param) +#define GET_CAP_PARAM(_get_cap_param) \ + CONTAINER_OF(_get_cap_param, struct bt_a2dp, get_capabilities_param) #define SET_CONF_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_set_configuration_params, req) -#define SET_CONF_PARAM(_set_conf_param) CONTAINER_OF(_set_conf_param, struct bt_a2dp,\ - set_config_param) -#define OPEN_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_open_params, req) -#define OPEN_PARAM(_open_param) CONTAINER_OF(_open_param, struct bt_a2dp, open_param) -#define START_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_start_params, req) +#define SET_CONF_PARAM(_set_conf_param) \ + CONTAINER_OF(_set_conf_param, struct bt_a2dp, set_config_param) +#define OPEN_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_open_params, req) +#define OPEN_PARAM(_open_param) CONTAINER_OF(_open_param, struct bt_a2dp, open_param) +#define START_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_start_params, req) #define START_PARAM(_start_param) CONTAINER_OF(_start_param, struct bt_a2dp, start_param) #include "host/hci_core.h" @@ -75,7 +75,7 @@ struct bt_a2dp { static struct bt_a2dp_cb *a2dp_cb; K_MUTEX_DEFINE(a2dp_mutex); -#define A2DP_LOCK() k_mutex_lock(&a2dp_mutex, K_FOREVER) +#define A2DP_LOCK() k_mutex_lock(&a2dp_mutex, K_FOREVER) #define A2DP_UNLOCK() k_mutex_unlock(&a2dp_mutex) /* Connections */ @@ -106,8 +106,7 @@ static struct bt_a2dp *get_new_connection(struct bt_conn *conn) return &connection[i]; } - if (!connection[i].session.br_chan.chan.conn && - free == A2DP_NO_SPACE) { + if (!connection[i].session.br_chan.chan.conn && free == A2DP_NO_SPACE) { free = i; break; } @@ -160,7 +159,7 @@ static int a2dp_discovery_ind(struct bt_avdtp *session, uint8_t *errcode) } static int a2dp_get_capabilities_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, - struct net_buf *rsp_buf, uint8_t *errcode) + struct net_buf *rsp_buf, uint8_t *errcode) { struct bt_a2dp_ep *ep; @@ -182,8 +181,8 @@ static int a2dp_get_capabilities_ind(struct bt_avdtp *session, struct bt_avdtp_s return 0; } -static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, - uint8_t int_seid, struct net_buf *buf, uint8_t *errcode) +static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t int_seid, + struct net_buf *buf, uint8_t *errcode) { struct bt_a2dp *a2dp = A2DP_AVDTP(session); struct bt_a2dp_ep *ep; @@ -202,9 +201,8 @@ static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *se /* parse the configuration */ codec_info_element_len = 4U; - err = bt_avdtp_parse_capability_codec(buf, - &codec_type, &codec_info_element, - &codec_info_element_len); + err = bt_avdtp_parse_capability_codec(buf, &codec_type, &codec_info_element, + &codec_info_element_len); if (err) { *errcode = BT_AVDTP_BAD_ACP_SEID; return -1; @@ -222,10 +220,10 @@ static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *se sbc_set = (struct bt_a2dp_codec_sbc_params *)codec_info_element; sbc = (struct bt_a2dp_codec_sbc_params *)&ep->codec_cap->codec_ie[0]; if (((BT_A2DP_SBC_SAMP_FREQ(sbc_set) & BT_A2DP_SBC_SAMP_FREQ(sbc)) == 0) || - ((BT_A2DP_SBC_CHAN_MODE(sbc_set) & BT_A2DP_SBC_CHAN_MODE(sbc)) == 0) || - ((BT_A2DP_SBC_BLK_LEN(sbc_set) & BT_A2DP_SBC_BLK_LEN(sbc)) == 0) || - ((BT_A2DP_SBC_SUB_BAND(sbc_set) & BT_A2DP_SBC_SUB_BAND(sbc)) == 0) || - ((BT_A2DP_SBC_ALLOC_MTHD(sbc_set) & BT_A2DP_SBC_ALLOC_MTHD(sbc)) == 0)) { + ((BT_A2DP_SBC_CHAN_MODE(sbc_set) & BT_A2DP_SBC_CHAN_MODE(sbc)) == 0) || + ((BT_A2DP_SBC_BLK_LEN(sbc_set) & BT_A2DP_SBC_BLK_LEN(sbc)) == 0) || + ((BT_A2DP_SBC_SUB_BAND(sbc_set) & BT_A2DP_SBC_SUB_BAND(sbc)) == 0) || + ((BT_A2DP_SBC_ALLOC_MTHD(sbc_set) & BT_A2DP_SBC_ALLOC_MTHD(sbc)) == 0)) { *errcode = BT_AVDTP_BAD_ACP_SEID; return -1; } @@ -239,8 +237,8 @@ static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *se cfg.codec_config = &codec_config; cfg.codec_config->len = codec_info_element_len; memcpy(&cfg.codec_config->codec_ie[0], codec_info_element, - (codec_info_element_len > A2DP_MAX_IE_LENGTH ? - A2DP_MAX_IE_LENGTH : codec_info_element_len)); + (codec_info_element_len > A2DP_MAX_IE_LENGTH ? A2DP_MAX_IE_LENGTH + : codec_info_element_len)); err = a2dp_cb->config_req(a2dp, ep, &cfg, &stream, &rsp_err_code); if (err) { *errcode = rsp_err_code; @@ -263,9 +261,7 @@ static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *se } #if defined(CONFIG_BT_A2DP_SINK) -static void bt_a2dp_media_data_callback( - struct bt_avdtp_sep *sep, - struct net_buf *buf) +static void bt_a2dp_media_data_callback(struct bt_avdtp_sep *sep, struct net_buf *buf) { struct bt_avdtp_media_hdr *media_hdr; struct bt_a2dp_ep *ep; @@ -279,9 +275,8 @@ static void bt_a2dp_media_data_callback( media_hdr = net_buf_pull_mem(buf, sizeof(*media_hdr)); - stream->ops->recv(stream, buf, - sys_get_be16((uint8_t *)&media_hdr->sequence_number), - sys_get_be32((uint8_t *)&media_hdr->time_stamp)); + stream->ops->recv(stream, buf, sys_get_be16((uint8_t *)&media_hdr->sequence_number), + sys_get_be32((uint8_t *)&media_hdr->time_stamp)); } #endif @@ -484,16 +479,15 @@ static int bt_a2dp_get_capabilities_cb(struct bt_avdtp_req *req) LOG_DBG("GET CAPABILITIES result:%d", a2dp->get_capabilities_param.status); if (a2dp->get_capabilities_param.status) { - if ((a2dp->discover_cb_param != NULL) && - (a2dp->discover_cb_param->cb != NULL)) { + if ((a2dp->discover_cb_param != NULL) && (a2dp->discover_cb_param->cb != NULL)) { a2dp->discover_cb_param->cb(a2dp, NULL, NULL); a2dp->discover_cb_param = NULL; } return 0; } - err = bt_avdtp_parse_capability_codec(a2dp->get_capabilities_param.buf, - &codec_type, &codec_info_element, &codec_info_element_len); + err = bt_avdtp_parse_capability_codec(a2dp->get_capabilities_param.buf, &codec_type, + &codec_info_element, &codec_info_element_len); if (err) { LOG_DBG("codec capability parsing fail"); return 0; @@ -509,8 +503,7 @@ static int bt_a2dp_get_capabilities_cb(struct bt_avdtp_req *req) info->codec_type = codec_type; info->sep_info = a2dp->discover_cb_param->seps_info[a2dp->get_cap_index]; - memcpy(&info->codec_cap.codec_ie, - codec_info_element, codec_info_element_len); + memcpy(&info->codec_cap.codec_ie, codec_info_element, codec_info_element_len); info->codec_cap.len = codec_info_element_len; user_ret = a2dp->discover_cb_param->cb(a2dp, info, &ep); if (ep != NULL) { @@ -547,16 +540,15 @@ static int bt_a2dp_get_sep_caps(struct bt_a2dp *a2dp) a2dp->get_cap_index++; } - for (; a2dp->get_cap_index < a2dp->peer_seps_count; - a2dp->get_cap_index++) { + for (; a2dp->get_cap_index < a2dp->peer_seps_count; a2dp->get_cap_index++) { if (a2dp->discover_cb_param->seps_info[a2dp->get_cap_index].media_type == - BT_AVDTP_AUDIO) { + BT_AVDTP_AUDIO) { a2dp->get_capabilities_param.req.func = bt_a2dp_get_capabilities_cb; a2dp->get_capabilities_param.buf = NULL; a2dp->get_capabilities_param.stream_endpoint_id = a2dp->discover_cb_param->seps_info[a2dp->get_cap_index].id; err = bt_avdtp_get_capabilities(&a2dp->session, - &a2dp->get_capabilities_param); + &a2dp->get_capabilities_param); if (err) { LOG_DBG("AVDTP get codec_cap failed"); a2dp->discover_cb_param->cb(a2dp, NULL, NULL); @@ -595,11 +587,8 @@ static int bt_a2dp_discover_cb(struct bt_avdtp_req *req) break; } a2dp->peer_seps_count++; - LOG_DBG("id:%d, inuse:%d, media_type:%d, tsep:%d, ", - sep_info->id, - sep_info->inuse, - sep_info->media_type, - sep_info->tsep); + LOG_DBG("id:%d, inuse:%d, media_type:%d, tsep:%d, ", sep_info->id, + sep_info->inuse, sep_info->media_type, sep_info->tsep); } while (a2dp->peer_seps_count < a2dp->discover_cb_param->sep_count); /* trigger the getting capability */ @@ -684,11 +673,11 @@ void bt_a2dp_stream_cb_register(struct bt_a2dp_stream *stream, struct bt_a2dp_st } int bt_a2dp_stream_config(struct bt_a2dp *a2dp, struct bt_a2dp_stream *stream, - struct bt_a2dp_ep *local_ep, struct bt_a2dp_ep *remote_ep, - struct bt_a2dp_codec_cfg *config) + struct bt_a2dp_ep *local_ep, struct bt_a2dp_ep *remote_ep, + struct bt_a2dp_codec_cfg *config) { - if ((a2dp == NULL) || (stream == NULL) || (local_ep == NULL) || - (remote_ep == NULL) || (config == NULL)) { + if ((a2dp == NULL) || (stream == NULL) || (local_ep == NULL) || (remote_ep == NULL) || + (config == NULL)) { return -EINVAL; } @@ -724,8 +713,9 @@ int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream) a2dp = stream->a2dp; a2dp->open_param.req.func = bt_a2dp_open_cb; - a2dp->open_param.acp_stream_ep_id = stream->remote_ep != NULL ? - stream->remote_ep->sep.sep_info.id : stream->remote_ep_id; + a2dp->open_param.acp_stream_ep_id = stream->remote_ep != NULL + ? stream->remote_ep->sep.sep_info.id + : stream->remote_ep_id; a2dp->open_param.sep = &stream->local_ep->sep; return bt_avdtp_open(&a2dp->session, &a2dp->open_param); } @@ -746,8 +736,9 @@ int bt_a2dp_stream_start(struct bt_a2dp_stream *stream) a2dp = stream->a2dp; a2dp->start_param.req.func = bt_a2dp_start_cb; - a2dp->start_param.acp_stream_ep_id = stream->remote_ep != NULL ? - stream->remote_ep->sep.sep_info.id : stream->remote_ep_id; + a2dp->start_param.acp_stream_ep_id = stream->remote_ep != NULL + ? stream->remote_ep->sep.sep_info.id + : stream->remote_ep_id; a2dp->start_param.sep = &stream->local_ep->sep; return bt_avdtp_start(&a2dp->session, &a2dp->start_param); } @@ -774,8 +765,8 @@ uint32_t bt_a2dp_get_mtu(struct bt_a2dp_stream *stream) } #if defined(CONFIG_BT_A2DP_SOURCE) -int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, - uint16_t seq_num, uint32_t ts) +int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, uint16_t seq_num, + uint32_t ts) { struct bt_avdtp_media_hdr *media_hdr; diff --git a/subsys/bluetooth/host/classic/avdtp.c b/subsys/bluetooth/host/classic/avdtp.c index d3dbc970e9221..c0b285b3a95df 100644 --- a/subsys/bluetooth/host/classic/avdtp.c +++ b/subsys/bluetooth/host/classic/avdtp.c @@ -30,31 +30,32 @@ LOG_MODULE_REGISTER(bt_avdtp); #define AVDTP_MSG_POISTION 0x00 #define AVDTP_PKT_POSITION 0x02 #define AVDTP_TID_POSITION 0x04 -#define AVDTP_SIGID_MASK 0x3f +#define AVDTP_SIGID_MASK 0x3f -#define AVDTP_GET_TR_ID(hdr) ((hdr & 0xf0) >> AVDTP_TID_POSITION) +#define AVDTP_GET_TR_ID(hdr) ((hdr & 0xf0) >> AVDTP_TID_POSITION) #define AVDTP_GET_MSG_TYPE(hdr) (hdr & 0x03) #define AVDTP_GET_PKT_TYPE(hdr) ((hdr & 0x0c) >> AVDTP_PKT_POSITION) -#define AVDTP_GET_SIG_ID(s) (s & AVDTP_SIGID_MASK) +#define AVDTP_GET_SIG_ID(s) (s & AVDTP_SIGID_MASK) static struct bt_avdtp_event_cb *event_cb; static sys_slist_t seps; #define AVDTP_CHAN(_ch) CONTAINER_OF(_ch, struct bt_avdtp, br_chan.chan) -#define AVDTP_KWORK(_work) CONTAINER_OF(CONTAINER_OF(_work, struct k_work_delayable, work),\ - struct bt_avdtp, timeout_work) +#define AVDTP_KWORK(_work) \ + CONTAINER_OF(CONTAINER_OF(_work, struct k_work_delayable, work), struct bt_avdtp, \ + timeout_work) #define DISCOVER_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_discover_params, req) -#define GET_CAP_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_get_capabilities_params, req) +#define GET_CAP_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_get_capabilities_params, req) #define SET_CONF_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_set_configuration_params, req) -#define OPEN_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_open_params, req) -#define START_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_start_params, req) +#define OPEN_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_open_params, req) +#define START_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_start_params, req) #define AVDTP_TIMEOUT K_SECONDS(6) K_MUTEX_DEFINE(avdtp_mutex); -#define AVDTP_LOCK() k_mutex_lock(&avdtp_mutex, K_FOREVER) +#define AVDTP_LOCK() k_mutex_lock(&avdtp_mutex, K_FOREVER) #define AVDTP_UNLOCK() k_mutex_unlock(&avdtp_mutex) enum sep_state { @@ -72,8 +73,7 @@ enum sep_state { void bt_avdtp_media_l2cap_connected(struct bt_l2cap_chan *chan) { struct bt_avdtp *session; - struct bt_avdtp_sep *sep = - CONTAINER_OF(chan, struct bt_avdtp_sep, chan.chan); + struct bt_avdtp_sep *sep = CONTAINER_OF(chan, struct bt_avdtp_sep, chan.chan); if (!chan) { LOG_ERR("Invalid AVDTP chan"); @@ -102,8 +102,7 @@ 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_sep *sep = - CONTAINER_OF(chan, struct bt_avdtp_sep, chan.chan); + struct bt_avdtp_sep *sep = CONTAINER_OF(chan, struct bt_avdtp_sep, chan.chan); LOG_DBG("chan %p", chan); chan->conn = NULL; @@ -115,8 +114,7 @@ void bt_avdtp_media_l2cap_disconnected(struct bt_l2cap_chan *chan) int bt_avdtp_media_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) { /* media data is received */ - struct bt_avdtp_sep *sep = - CONTAINER_OF(chan, struct bt_avdtp_sep, chan.chan); + struct bt_avdtp_sep *sep = CONTAINER_OF(chan, struct bt_avdtp_sep, chan.chan); if (sep->media_data_cb != NULL) { sep->media_data_cb(sep, buf); @@ -126,11 +124,10 @@ int bt_avdtp_media_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) static int avdtp_media_connect(struct bt_avdtp *session, struct bt_avdtp_sep *sep) { - static const struct bt_l2cap_chan_ops ops = { - .connected = bt_avdtp_media_l2cap_connected, - .disconnected = bt_avdtp_media_l2cap_disconnected, - .recv = bt_avdtp_media_l2cap_recv - }; + static const struct bt_l2cap_chan_ops ops = {.connected = bt_avdtp_media_l2cap_connected, + .disconnected = + bt_avdtp_media_l2cap_disconnected, + .recv = bt_avdtp_media_l2cap_recv}; if (!session) { return -EINVAL; @@ -142,13 +139,11 @@ static int avdtp_media_connect(struct bt_avdtp *session, struct bt_avdtp_sep *se sep->chan.required_sec_level = BT_SECURITY_L2; return bt_l2cap_chan_connect(session->br_chan.chan.conn, &sep->chan.chan, - BT_L2CAP_PSM_AVDTP); + BT_L2CAP_PSM_AVDTP); } -static struct net_buf *avdtp_create_reply_pdu(uint8_t msg_type, - uint8_t pkt_type, - uint8_t sig_id, - uint8_t tid) +static struct net_buf *avdtp_create_reply_pdu(uint8_t msg_type, uint8_t pkt_type, uint8_t sig_id, + uint8_t tid) { struct net_buf *buf; struct bt_avdtp_single_sig_hdr *hdr; @@ -163,17 +158,15 @@ static struct net_buf *avdtp_create_reply_pdu(uint8_t msg_type, hdr = net_buf_add(buf, sizeof(*hdr)); - hdr->hdr = (msg_type | pkt_type << AVDTP_PKT_POSITION | - tid << AVDTP_TID_POSITION); + hdr->hdr = (msg_type | pkt_type << AVDTP_PKT_POSITION | tid << AVDTP_TID_POSITION); hdr->signal_id = sig_id & AVDTP_SIGID_MASK; LOG_DBG("hdr = 0x%02X, Signal_ID = 0x%02X", hdr->hdr, hdr->signal_id); return buf; } -static void avdtp_discover_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, - uint8_t tid) +static void avdtp_discover_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, + uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err; @@ -187,10 +180,9 @@ static void avdtp_discover_handler(struct bt_avdtp *session, err = session->ops->discovery_ind(session, &error_code); } - rsp_buf = avdtp_create_reply_pdu(err ? - BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_DISCOVER, tid); + rsp_buf = + avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, + BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_DISCOVER, tid); if (!rsp_buf) { return; } @@ -262,8 +254,8 @@ static struct bt_avdtp_sep *avdtp_get_sep(uint8_t stream_endpoint_id) return sep; } -static void avdtp_get_capabilities_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_get_capabilities_handler(struct bt_avdtp *session, struct net_buf *buf, + uint8_t msg_type, uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -280,24 +272,23 @@ static void avdtp_get_capabilities_handler(struct bt_avdtp *session, if ((sep == NULL) || (session->ops->get_capabilities_ind == NULL)) { err = -ENOTSUP; } else { - rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_GET_CAPABILITIES, - tid); + rsp_buf = + avdtp_create_reply_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, + BT_AVDTP_GET_CAPABILITIES, tid); if (!rsp_buf) { return; } - err = session->ops->get_capabilities_ind(session, - sep, rsp_buf, &error_code); + err = session->ops->get_capabilities_ind(session, sep, rsp_buf, + &error_code); if (err) { net_buf_unref(rsp_buf); } } if (err) { - rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_REJECT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_GET_CAPABILITIES, tid); + rsp_buf = + avdtp_create_reply_pdu(BT_AVDTP_REJECT, BT_AVDTP_PACKET_TYPE_SINGLE, + BT_AVDTP_GET_CAPABILITIES, tid); if (!rsp_buf) { return; } @@ -348,8 +339,8 @@ static void avdtp_get_capabilities_handler(struct bt_avdtp *session, } } -static void avdtp_process_configuration(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_process_configuration(struct bt_avdtp *session, struct net_buf *buf, + uint8_t msg_type, uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -379,15 +370,14 @@ static void avdtp_process_configuration(struct bt_avdtp *session, /* INT Stream Endpoint ID */ int_seid = net_buf_pull_u8(buf); - err = session->ops->set_configuration_ind(session, - sep, int_seid, buf, &error_code); + err = session->ops->set_configuration_ind(session, sep, int_seid, + buf, &error_code); } } - rsp_buf = avdtp_create_reply_pdu(err ? - BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_SET_CONFIGURATION, tid); + rsp_buf = avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, + BT_AVDTP_PACKET_TYPE_SINGLE, + BT_AVDTP_SET_CONFIGURATION, tid); if (!rsp_buf) { return; } @@ -444,22 +434,21 @@ static void avdtp_process_configuration(struct bt_avdtp *session, } } -static void avdtp_set_configuration_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_set_configuration_handler(struct bt_avdtp *session, struct net_buf *buf, + uint8_t msg_type, uint8_t tid) { avdtp_process_configuration(session, buf, msg_type, tid); } -static void avdtp_get_configuration_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_get_configuration_handler(struct bt_avdtp *session, struct net_buf *buf, + uint8_t msg_type, uint8_t tid) { /* todo: is not supported now, reply reject */ struct net_buf *rsp_buf; int err; - rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_REJECT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_GET_CONFIGURATION, tid); + rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_REJECT, BT_AVDTP_PACKET_TYPE_SINGLE, + BT_AVDTP_GET_CONFIGURATION, tid); if (!rsp_buf) { LOG_ERR("Error: No Buff available"); return; @@ -473,14 +462,14 @@ static void avdtp_get_configuration_handler(struct bt_avdtp *session, } } -static void avdtp_re_configure_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_re_configure_handler(struct bt_avdtp *session, struct net_buf *buf, + uint8_t msg_type, uint8_t tid) { avdtp_process_configuration(session, buf, msg_type, tid); } -static void avdtp_open_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_open_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, + uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -505,10 +494,8 @@ static void avdtp_open_handler(struct bt_avdtp *session, } } - rsp_buf = avdtp_create_reply_pdu(err ? - BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_OPEN, tid); + rsp_buf = avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, + BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_OPEN, tid); if (!rsp_buf) { return; } @@ -566,8 +553,8 @@ static void avdtp_open_handler(struct bt_avdtp *session, } } -static void avdtp_start_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_start_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, + uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -592,10 +579,8 @@ static void avdtp_start_handler(struct bt_avdtp *session, } } - rsp_buf = avdtp_create_reply_pdu(err ? - BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_START, tid); + rsp_buf = avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, + BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_START, tid); if (!rsp_buf) { return; } @@ -652,8 +637,8 @@ static void avdtp_start_handler(struct bt_avdtp *session, } } -static void avdtp_close_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_close_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, + uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -678,10 +663,8 @@ static void avdtp_close_handler(struct bt_avdtp *session, } } - rsp_buf = avdtp_create_reply_pdu(err ? - BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_CLOSE, tid); + 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) { return; } @@ -706,8 +689,8 @@ static void avdtp_close_handler(struct bt_avdtp *session, } } -static void avdtp_suspend_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_suspend_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, + uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -732,10 +715,9 @@ static void avdtp_suspend_handler(struct bt_avdtp *session, } } - rsp_buf = avdtp_create_reply_pdu(err ? - BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_SUSPEND, tid); + rsp_buf = + avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, + BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_SUSPEND, tid); if (!rsp_buf) { return; } @@ -759,8 +741,8 @@ static void avdtp_suspend_handler(struct bt_avdtp *session, } } -static void avdtp_abort_handler(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t tid) +static void avdtp_abort_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, + uint8_t tid) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -780,10 +762,8 @@ static void avdtp_abort_handler(struct bt_avdtp *session, 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); + 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) { return; } @@ -846,8 +826,7 @@ static void avdtp_timeout(struct k_work *work) } } -static int avdtp_send(struct bt_avdtp *session, - struct net_buf *buf, struct bt_avdtp_req *req) +static int avdtp_send(struct bt_avdtp *session, struct net_buf *buf, struct bt_avdtp_req *req) { int result; struct bt_avdtp_single_sig_hdr *hdr; @@ -883,9 +862,7 @@ static int avdtp_send(struct bt_avdtp *session, return result; } -static struct net_buf *avdtp_create_pdu(uint8_t msg_type, - uint8_t pkt_type, - uint8_t sig_id) +static struct net_buf *avdtp_create_pdu(uint8_t msg_type, uint8_t pkt_type, uint8_t sig_id) { struct net_buf *buf; static uint8_t tid; @@ -897,8 +874,7 @@ static struct net_buf *avdtp_create_pdu(uint8_t msg_type, hdr = net_buf_add(buf, sizeof(*hdr)); - hdr->hdr = (msg_type | pkt_type << AVDTP_PKT_POSITION | - tid++ << AVDTP_TID_POSITION); + hdr->hdr = (msg_type | pkt_type << AVDTP_PKT_POSITION | tid++ << AVDTP_TID_POSITION); tid %= 16; /* Loop for 16*/ hdr->signal_id = sig_id & AVDTP_SIGID_MASK; @@ -943,8 +919,7 @@ void bt_avdtp_l2cap_encrypt_changed(struct bt_l2cap_chan *chan, uint8_t status) static const struct { uint8_t sig_id; - void (*func)(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t tid); + void (*func)(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, uint8_t tid); } handler[] = { {BT_AVDTP_DISCOVER, avdtp_discover_handler}, {BT_AVDTP_GET_CAPABILITIES, avdtp_get_capabilities_handler}, @@ -975,8 +950,8 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) sigid = AVDTP_GET_SIG_ID(hdr->signal_id); tid = AVDTP_GET_TR_ID(hdr->hdr); - LOG_DBG("pack_type[0x%02x] msg_type[0x%02x] sig_id[0x%02x] tid[0x%02x]", - pack_type, msgtype, sigid, tid); + LOG_DBG("pack_type[0x%02x] msg_type[0x%02x] sig_id[0x%02x] tid[0x%02x]", pack_type, msgtype, + sigid, tid); /* TODO: only support single packet now */ if (pack_type != BT_AVDTP_PACKET_TYPE_SINGLE) { @@ -991,8 +966,7 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) sigid = net_buf_pull_u8(buf); rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_REJECT, - BT_AVDTP_PACKET_TYPE_SINGLE, - sigid, tid); + BT_AVDTP_PACKET_TYPE_SINGLE, sigid, tid); if (!rsp_buf) { LOG_ERR("Error: No Buff available"); return 0; @@ -1013,11 +987,10 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) return 0; } - if (session->req->sig != sigid || - session->req->tid != tid) { + if (session->req->sig != sigid || session->req->tid != tid) { LOG_DBG("Peer mismatch resp, expected sig[0x%02x]" - "tid[0x%02x]", session->req->sig, - session->req->tid); + "tid[0x%02x]", + session->req->sig, session->req->tid); return 0; } } @@ -1040,24 +1013,22 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) /*A2DP Layer interface */ int bt_avdtp_connect(struct bt_conn *conn, struct bt_avdtp *session) { - static const struct bt_l2cap_chan_ops ops = { - .connected = bt_avdtp_l2cap_connected, - .disconnected = bt_avdtp_l2cap_disconnected, - .encrypt_change = bt_avdtp_l2cap_encrypt_changed, - .recv = bt_avdtp_l2cap_recv - }; + static const struct bt_l2cap_chan_ops ops = {.connected = bt_avdtp_l2cap_connected, + .disconnected = bt_avdtp_l2cap_disconnected, + .encrypt_change = + bt_avdtp_l2cap_encrypt_changed, + .recv = bt_avdtp_l2cap_recv}; if (!session) { return -EINVAL; } session->signalling_l2cap_connected = 1; - session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; + session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; session->br_chan.chan.ops = &ops; session->br_chan.required_sec_level = BT_SECURITY_L2; - return bt_l2cap_chan_connect(conn, &session->br_chan.chan, - BT_L2CAP_PSM_AVDTP); + return bt_l2cap_chan_connect(conn, &session->br_chan.chan, BT_L2CAP_PSM_AVDTP); } int bt_avdtp_disconnect(struct bt_avdtp *session) @@ -1073,7 +1044,7 @@ int bt_avdtp_disconnect(struct bt_avdtp *session) } int bt_avdtp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server, - struct bt_l2cap_chan **chan) + struct bt_l2cap_chan **chan) { struct bt_avdtp *session = NULL; int result; @@ -1101,13 +1072,11 @@ int bt_avdtp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server, static const struct bt_l2cap_chan_ops ops = { .connected = bt_avdtp_media_l2cap_connected, .disconnected = bt_avdtp_media_l2cap_disconnected, - .recv = bt_avdtp_media_l2cap_recv - }; + .recv = bt_avdtp_media_l2cap_recv}; session->current_sep->session = session; session->current_sep->chan.chan.ops = &ops; session->current_sep->chan.rx.mtu = BT_L2CAP_RX_MTU; - session->current_sep->chan.required_sec_level = - BT_SECURITY_L2; + session->current_sep->chan.required_sec_level = BT_SECURITY_L2; *chan = &session->current_sep->chan.chan; session->current_sep = NULL; } @@ -1130,8 +1099,7 @@ int bt_avdtp_register(struct bt_avdtp_event_cb *cb) return 0; } -int bt_avdtp_register_sep(uint8_t media_type, uint8_t role, - struct bt_avdtp_sep *sep) +int bt_avdtp_register_sep(uint8_t media_type, uint8_t role, struct bt_avdtp_sep *sep) { LOG_DBG(""); @@ -1178,8 +1146,7 @@ int bt_avdtp_init(void) } /* AVDTP Discover Request */ -int bt_avdtp_discover(struct bt_avdtp *session, - struct bt_avdtp_discover_params *param) +int bt_avdtp_discover(struct bt_avdtp *session, struct bt_avdtp_discover_params *param) { struct net_buf *buf; @@ -1189,9 +1156,7 @@ int bt_avdtp_discover(struct bt_avdtp *session, return -EINVAL; } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_DISCOVER); + buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_DISCOVER); if (!buf) { LOG_ERR("Error: No Buff available"); return -ENOMEM; @@ -1220,7 +1185,7 @@ int bt_avdtp_parse_sep(struct net_buf *buf, struct bt_avdtp_sep_info *sep_info) /* AVDTP Get Capabilities Request */ int bt_avdtp_get_capabilities(struct bt_avdtp *session, - struct bt_avdtp_get_capabilities_params *param) + struct bt_avdtp_get_capabilities_params *param) { struct net_buf *buf; @@ -1230,9 +1195,8 @@ int bt_avdtp_get_capabilities(struct bt_avdtp *session, return -EINVAL; } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_GET_CAPABILITIES); + buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, + BT_AVDTP_GET_CAPABILITIES); if (!buf) { LOG_ERR("Error: No Buff available"); return -ENOMEM; @@ -1244,9 +1208,8 @@ int bt_avdtp_get_capabilities(struct bt_avdtp *session, return avdtp_send(session, buf, ¶m->req); } -int bt_avdtp_parse_capability_codec(struct net_buf *buf, - uint8_t *codec_type, uint8_t **codec_info_element, - uint16_t *codec_info_element_len) +int bt_avdtp_parse_capability_codec(struct net_buf *buf, uint8_t *codec_type, + uint8_t **codec_info_element, uint16_t *codec_info_element_len) { uint8_t data; uint8_t length; @@ -1310,9 +1273,8 @@ int bt_avdtp_parse_capability_codec(struct net_buf *buf, return -EIO; } -static int avdtp_process_configure_command(struct bt_avdtp *session, - uint8_t cmd, - struct bt_avdtp_set_configuration_params *param) +static int avdtp_process_configure_command(struct bt_avdtp *session, uint8_t cmd, + struct bt_avdtp_set_configuration_params *param) { struct net_buf *buf; @@ -1322,9 +1284,7 @@ static int avdtp_process_configure_command(struct bt_avdtp *session, return -EINVAL; } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - cmd); + buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, cmd); if (!buf) { LOG_ERR("Error: No Buff available"); return -ENOMEM; @@ -1354,7 +1314,7 @@ static int avdtp_process_configure_command(struct bt_avdtp *session, } int bt_avdtp_set_configuration(struct bt_avdtp *session, - struct bt_avdtp_set_configuration_params *param) + struct bt_avdtp_set_configuration_params *param) { if (!param || !session || !param->sep) { LOG_DBG("Error: parameters not valid"); @@ -1368,8 +1328,7 @@ int bt_avdtp_set_configuration(struct bt_avdtp *session, return avdtp_process_configure_command(session, BT_AVDTP_SET_CONFIGURATION, param); } -int bt_avdtp_reconfigure(struct bt_avdtp *session, - struct bt_avdtp_set_configuration_params *param) +int bt_avdtp_reconfigure(struct bt_avdtp *session, struct bt_avdtp_set_configuration_params *param) { if (!param || !session || !param->sep) { LOG_DBG("Error: parameters not valid"); @@ -1383,8 +1342,7 @@ int bt_avdtp_reconfigure(struct bt_avdtp *session, return avdtp_process_configure_command(session, BT_AVDTP_RECONFIGURE, param); } -int bt_avdtp_open(struct bt_avdtp *session, - struct bt_avdtp_open_params *param) +int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_open_params *param) { struct net_buf *buf; @@ -1398,9 +1356,7 @@ int bt_avdtp_open(struct bt_avdtp *session, return -EINVAL; } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_OPEN); + buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_OPEN); if (!buf) { LOG_ERR("Error: No Buff available"); return -ENOMEM; @@ -1413,8 +1369,7 @@ int bt_avdtp_open(struct bt_avdtp *session, return avdtp_send(session, buf, ¶m->req); } -int bt_avdtp_start(struct bt_avdtp *session, - struct bt_avdtp_start_params *param) +int bt_avdtp_start(struct bt_avdtp *session, struct bt_avdtp_start_params *param) { struct net_buf *buf; @@ -1428,9 +1383,7 @@ int bt_avdtp_start(struct bt_avdtp *session, return -EINVAL; } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_START); + buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_START); if (!buf) { LOG_ERR("Error: No Buff available"); return -ENOMEM; diff --git a/subsys/bluetooth/host/classic/avdtp_internal.h b/subsys/bluetooth/host/classic/avdtp_internal.h index dc756cb11a705..d4bb9c63fe22a 100644 --- a/subsys/bluetooth/host/classic/avdtp_internal.h +++ b/subsys/bluetooth/host/classic/avdtp_internal.h @@ -47,11 +47,11 @@ #define BT_AVDTP_DELAYREPORT 0x0d /* @brief AVDTP STREAM STATE */ -#define BT_AVDTP_STREAM_STATE_IDLE 0x01 -#define BT_AVDTP_STREAM_STATE_CONFIGURED 0x02 -#define BT_AVDTP_STREAM_STATE_OPEN 0x03 -#define BT_AVDTP_STREAM_STATE_STREAMING 0x04 -#define BT_AVDTP_STREAM_STATE_CLOSING 0x05 +#define BT_AVDTP_STREAM_STATE_IDLE 0x01 +#define BT_AVDTP_STREAM_STATE_CONFIGURED 0x02 +#define BT_AVDTP_STREAM_STATE_OPEN 0x03 +#define BT_AVDTP_STREAM_STATE_STREAMING 0x04 +#define BT_AVDTP_STREAM_STATE_CLOSING 0x05 /* @brief AVDTP Media TYPE */ #define BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT 0x01 @@ -93,19 +93,19 @@ struct bt_avdtp_sep_info; /** @brief AVDTP SEID Information AVDTP_SPEC V13 Table 8.8 */ struct bt_avdtp_sep_data { #ifdef CONFIG_LITTLE_ENDIAN - uint8_t rfa0:1; - uint8_t inuse:1; - uint8_t id:6; - uint8_t rfa1:3; - uint8_t tsep:1; - uint8_t media_type:4; + uint8_t rfa0: 1; + uint8_t inuse: 1; + uint8_t id: 6; + uint8_t rfa1: 3; + uint8_t tsep: 1; + uint8_t media_type: 4; #else - uint8_t id:6; - uint8_t inuse:1; - uint8_t rfa0:1; - uint8_t media_type:4; - uint8_t tsep:1; - uint8_t rfa1:3; + uint8_t id: 6; + uint8_t inuse: 1; + uint8_t rfa0: 1; + uint8_t media_type: 4; + uint8_t tsep: 1; + uint8_t rfa1: 3; #endif } __packed; @@ -124,19 +124,19 @@ struct bt_avdtp_single_sig_hdr { struct bt_avdtp_media_hdr { #ifdef CONFIG_LITTLE_ENDIAN - uint8_t CSRC_count:4; - uint8_t header_extension:1; - uint8_t padding:1; - uint8_t RTP_version:2; - uint8_t playload_type:7; - uint8_t marker:1; + uint8_t CSRC_count: 4; + uint8_t header_extension: 1; + uint8_t padding: 1; + uint8_t RTP_version: 2; + uint8_t playload_type: 7; + uint8_t marker: 1; #else - uint8_t RTP_version:2; - uint8_t padding:1; - uint8_t header_extension:1; - uint8_t CSRC_count:4; - uint8_t marker:1; - uint8_t playload_type:7; + uint8_t RTP_version: 2; + uint8_t padding: 1; + uint8_t header_extension: 1; + uint8_t CSRC_count: 4; + uint8_t marker: 1; + uint8_t playload_type: 7; #endif uint16_t sequence_number; uint32_t time_stamp; @@ -191,26 +191,21 @@ struct bt_avdtp_ops_cb { int (*discovery_ind)(struct bt_avdtp *session, uint8_t *errcode); - int (*get_capabilities_ind)(struct bt_avdtp *session, - struct bt_avdtp_sep *sep, struct net_buf *rsp_buf, uint8_t *errcode); + int (*get_capabilities_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, + struct net_buf *rsp_buf, uint8_t *errcode); int (*set_configuration_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, - uint8_t int_seid, struct net_buf *buf, uint8_t *errcode); + uint8_t int_seid, struct net_buf *buf, uint8_t *errcode); - int (*open_ind)(struct bt_avdtp *session, - struct bt_avdtp_sep *sep, uint8_t *errcode); + int (*open_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode); - int (*close_ind)(struct bt_avdtp *session, - struct bt_avdtp_sep *sep, uint8_t *errcode); + int (*close_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode); - int (*start_ind)(struct bt_avdtp *session, - struct bt_avdtp_sep *sep, uint8_t *errcode); + int (*start_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode); - int (*suspend_ind)(struct bt_avdtp *session, - struct bt_avdtp_sep *sep, uint8_t *errcode); + 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); + int (*abort_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode); }; /** @brief Global AVDTP session structure. */ @@ -240,39 +235,34 @@ int bt_avdtp_connect(struct bt_conn *conn, struct bt_avdtp *session); int bt_avdtp_disconnect(struct bt_avdtp *session); /* AVDTP SEP register function */ -int bt_avdtp_register_sep(uint8_t media_type, uint8_t role, - struct bt_avdtp_sep *sep); +int bt_avdtp_register_sep(uint8_t media_type, uint8_t sep_type, struct bt_avdtp_sep *sep); /* AVDTP Discover Request */ -int bt_avdtp_discover(struct bt_avdtp *session, - struct bt_avdtp_discover_params *param); +int bt_avdtp_discover(struct bt_avdtp *session, struct bt_avdtp_discover_params *param); /* Parse the sep of discovered result */ int bt_avdtp_parse_sep(struct net_buf *buf, struct bt_avdtp_sep_info *sep_info); /* AVDTP Get Capabilities */ int bt_avdtp_get_capabilities(struct bt_avdtp *session, - struct bt_avdtp_get_capabilities_params *param); + struct bt_avdtp_get_capabilities_params *param); /* Parse the codec type of capabilities */ int bt_avdtp_parse_capability_codec(struct net_buf *buf, uint8_t *codec_type, - uint8_t **codec_info_element, uint16_t *codec_info_element_len); + uint8_t **codec_info_element, uint16_t *codec_info_element_len); /* AVDTP Set Configuration */ int bt_avdtp_set_configuration(struct bt_avdtp *session, - struct bt_avdtp_set_configuration_params *param); + struct bt_avdtp_set_configuration_params *param); /* AVDTP reconfigure */ -int bt_avdtp_reconfigure(struct bt_avdtp *session, - struct bt_avdtp_set_configuration_params *param); +int bt_avdtp_reconfigure(struct bt_avdtp *session, struct bt_avdtp_set_configuration_params *param); /* AVDTP OPEN */ -int bt_avdtp_open(struct bt_avdtp *session, - struct bt_avdtp_open_params *param); +int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param); /* AVDTP START */ -int bt_avdtp_start(struct bt_avdtp *session, - struct bt_avdtp_start_params *param); +int bt_avdtp_start(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); From 71d59b17751eda376e7d88efe359ca6f5e26fcb2 Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Sun, 29 Sep 2024 11:35:12 +0800 Subject: [PATCH 2/4] Bluetooth: A2DP: implement reconfig and optimize codes Implement the bt_a2dp_stream_reconfig: Modify reconfig_req callback to pass codec_cfg to application. Remove reconfig_rsp callback, config_rsp is used. Remove reconfigured callback, configured callback is used. move the status to common struct bt_avdtp_req, use same bt_avdtp_ctrl_params to process control-like avdtp cmds (start, open etc), use the same a2dp_ctrl_ind to process control-like cmds (start, open etc), use the same bt_a2dp_ctrl_cb to process control-like cmds (start, open etc), use the same bt_avdtp_ctrl to process control-like cmds (start, open etc), optimize getting a2dp conn by index, use sem to replace mutex and optimze the lock codes to be based on context/instance. Signed-off-by: Mark Wang --- include/zephyr/bluetooth/classic/a2dp.h | 76 +-- include/zephyr/bluetooth/classic/avdtp.h | 2 + subsys/bluetooth/host/classic/a2dp.c | 534 ++++++++--------- subsys/bluetooth/host/classic/avdtp.c | 562 +++++++++--------- .../bluetooth/host/classic/avdtp_internal.h | 23 +- 5 files changed, 575 insertions(+), 622 deletions(-) diff --git a/include/zephyr/bluetooth/classic/a2dp.h b/include/zephyr/bluetooth/classic/a2dp.h index 51262c03b3694..e2fd27b743e53 100644 --- a/include/zephyr/bluetooth/classic/a2dp.h +++ b/include/zephyr/bluetooth/classic/a2dp.h @@ -21,16 +21,16 @@ extern "C" { #endif -#define BT_A2DP_STREAM_BUF_RESERVE (12u + BT_L2CAP_BUF_SIZE(0)) +#define BT_A2DP_STREAM_BUF_RESERVE (12U + BT_L2CAP_BUF_SIZE(0)) /** SBC IE length */ -#define BT_A2DP_SBC_IE_LENGTH (4u) +#define BT_A2DP_SBC_IE_LENGTH (4U) /** MPEG1,2 IE length */ -#define BT_A2DP_MPEG_1_2_IE_LENGTH (4u) +#define BT_A2DP_MPEG_1_2_IE_LENGTH (4U) /** MPEG2,4 IE length */ -#define BT_A2DP_MPEG_2_4_IE_LENGTH (6u) +#define BT_A2DP_MPEG_2_4_IE_LENGTH (6U) /** The max IE (Codec Info Element) length */ -#define A2DP_MAX_IE_LENGTH (8U) +#define BT_A2DP_MAX_IE_LENGTH (8U) /** @brief define the audio endpoint * @param _role BT_AVDTP_SOURCE or BT_AVDTP_SINK. @@ -314,7 +314,7 @@ struct bt_a2dp_codec_ie { /** Length of codec_cap */ uint8_t len; /** codec information element */ - uint8_t codec_ie[A2DP_MAX_IE_LENGTH]; + uint8_t codec_ie[BT_A2DP_MAX_IE_LENGTH]; }; /** @brief The endpoint configuration */ @@ -432,7 +432,21 @@ struct bt_a2dp_cb { int (*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); - /** @brief Callback function for bt_a2dp_stream_config() + /** + * @brief Endpoint config request callback + * + * The callback is called whenever an endpoint is requested to be + * reconfigured. + * + * @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 (*reconfig_req)(struct bt_a2dp_stream *stream, struct bt_a2dp_codec_cfg *codec_cfg, + uint8_t *rsp_err_code); + /** @brief Callback function for bt_a2dp_stream_config() and bt_a2dp_stream_reconfig() * * Called when the codec configure operation is completed. * @@ -442,7 +456,7 @@ struct bt_a2dp_cb { */ void (*config_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); /** - * @brief stream establishment request callback + * @brief Stream establishment request callback * * The callback is called whenever an stream is requested to be * established (open cmd and create the stream l2cap channel). @@ -465,7 +479,7 @@ struct bt_a2dp_cb { */ void (*establish_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); /** - * @brief stream release request callback + * @brief Stream release request callback * * The callback is called whenever an stream is requested to be * released (release cmd and release the l2cap channel) @@ -488,7 +502,7 @@ struct bt_a2dp_cb { */ void (*release_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); /** - * @brief stream start request callback + * @brief Stream start request callback * * The callback is called whenever an stream is requested to be * started. @@ -510,7 +524,7 @@ struct bt_a2dp_cb { */ void (*start_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); /** - * @brief Endpoint suspend request callback + * @brief Stream suspend request callback * * The callback is called whenever an stream is requested to be * suspended. @@ -531,28 +545,6 @@ 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 Endpoint config request callback - * - * The callback is called whenever an endpoint is requested to be - * reconfigured. - * - * @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 (*reconfig_req)(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code); - /** @brief Callback function for bt_a2dp_stream_reconfig() - * - * Called when the reconfig 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 (*reconfig_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); }; /** @brief A2DP Connect. @@ -585,12 +577,12 @@ int bt_a2dp_disconnect(struct bt_a2dp *a2dp); /** @brief Endpoint Registration. * * @param ep Pointer to bt_a2dp_ep structure. - * @param media_type Media type that the Endpoint is. - * @param role Role of Endpoint. + * @param media_type Media type that the Endpoint is, #bt_avdtp_media_type. + * @param sep_type Stream endpoint type, #bt_avdtp_sep_type. * * @return 0 in case of success and error code in case of error. */ -int bt_a2dp_register_ep(struct bt_a2dp_ep *ep, uint8_t media_type, uint8_t role); +int bt_a2dp_register_ep(struct bt_a2dp_ep *ep, uint8_t media_type, uint8_t sep_type); /** @brief register callback. * @@ -632,7 +624,7 @@ struct bt_a2dp_stream_ops { /** * @brief Stream configured callback * - * The callback is called whenever an Audio Stream has been configured. + * The callback is called whenever an Audio Stream has been configured or reconfigured. * * @param stream Stream object that has been configured. */ @@ -649,6 +641,7 @@ struct bt_a2dp_stream_ops { * @brief Stream release callback * * The callback is called whenever an Audio Stream has been released. + * After released, the stream becomes invalid. * * @param stream Stream object that has been released. */ @@ -669,14 +662,6 @@ struct bt_a2dp_stream_ops { * @param stream Stream object that has been suspended. */ void (*suspended)(struct bt_a2dp_stream *stream); - /** - * @brief Stream reconfigured callback - * - * The callback is called whenever an Audio Stream has been reconfigured. - * - * @param stream Stream object that has been reconfigured. - */ - void (*reconfigured)(struct bt_a2dp_stream *stream); #if defined(CONFIG_BT_A2DP_SINK) /** @brief the media streaming data, only for sink * @@ -746,6 +731,7 @@ int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream); /** @brief release a2dp streamer. * * This function sends the AVDTP_CLOSE command and release the l2cap channel. + * After release, the stream becomes invalid. * * @param stream The stream object. * diff --git a/include/zephyr/bluetooth/classic/avdtp.h b/include/zephyr/bluetooth/classic/avdtp.h index 850e0945f36bf..dd7307ae3748f 100644 --- a/include/zephyr/bluetooth/classic/avdtp.h +++ b/include/zephyr/bluetooth/classic/avdtp.h @@ -128,6 +128,8 @@ struct bt_avdtp_sep { struct bt_l2cap_br_chan chan; /** the endpoint media data */ void (*media_data_cb)(struct bt_avdtp_sep *sep, struct net_buf *buf); + /* semaphore for lock/unlock */ + struct k_sem sem_lock; /** avdtp session */ struct bt_avdtp *session; /** SEP state */ diff --git a/subsys/bluetooth/host/classic/a2dp.c b/subsys/bluetooth/host/classic/a2dp.c index 3c34c5ca7bc75..9cfb4f1622984 100644 --- a/subsys/bluetooth/host/classic/a2dp.c +++ b/subsys/bluetooth/host/classic/a2dp.c @@ -25,7 +25,7 @@ #include "common/assert.h" -#define A2DP_SBC_PAYLOAD_TYPE (0x60u) +#define A2DP_SBC_PAYLOAD_TYPE (0x60U) #define A2DP_AVDTP(_avdtp) CONTAINER_OF(_avdtp, struct bt_a2dp, session) #define DISCOVER_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_discover_params, req) @@ -37,10 +37,8 @@ #define SET_CONF_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_set_configuration_params, req) #define SET_CONF_PARAM(_set_conf_param) \ CONTAINER_OF(_set_conf_param, struct bt_a2dp, set_config_param) -#define OPEN_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_open_params, req) -#define OPEN_PARAM(_open_param) CONTAINER_OF(_open_param, struct bt_a2dp, open_param) -#define START_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_start_params, req) -#define START_PARAM(_start_param) CONTAINER_OF(_start_param, struct bt_a2dp, start_param) +#define CTRL_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_ctrl_params, req) +#define CTRL_PARAM(_ctrl_param) CONTAINER_OF(_ctrl_param, struct bt_a2dp, ctrl_param) #include "host/hci_core.h" #include "host/conn_internal.h" @@ -65,62 +63,27 @@ struct bt_a2dp { struct bt_a2dp_discover_param *discover_cb_param; struct bt_avdtp_get_capabilities_params get_capabilities_param; struct bt_avdtp_set_configuration_params set_config_param; - struct bt_avdtp_open_params open_param; - struct bt_avdtp_start_params start_param; + struct bt_avdtp_ctrl_params ctrl_param; uint8_t get_cap_index; enum bt_a2dp_internal_state a2dp_state; uint8_t peer_seps_count; }; static struct bt_a2dp_cb *a2dp_cb; -K_MUTEX_DEFINE(a2dp_mutex); - -#define A2DP_LOCK() k_mutex_lock(&a2dp_mutex, K_FOREVER) -#define A2DP_UNLOCK() k_mutex_unlock(&a2dp_mutex) - /* Connections */ static struct bt_a2dp connection[CONFIG_BT_MAX_CONN]; static int bt_a2dp_get_sep_caps(struct bt_a2dp *a2dp); -static void a2dp_reset(struct bt_a2dp *a2dp) -{ - (void)memset(a2dp, 0, sizeof(struct bt_a2dp)); -} - -static struct bt_a2dp *get_new_connection(struct bt_conn *conn) +static struct bt_a2dp *a2dp_get_connection(struct bt_conn *conn) { - int8_t i, free; - - free = A2DP_NO_SPACE; + struct bt_a2dp *a2dp = &connection[bt_conn_index(conn)]; - if (!conn) { - LOG_ERR("Invalid Input (err: %d)", -EINVAL); - return NULL; - } - - /* Find a space */ - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (connection[i].session.br_chan.chan.conn == conn) { - LOG_DBG("Conn already exists"); - return &connection[i]; - } - - if (!connection[i].session.br_chan.chan.conn && free == A2DP_NO_SPACE) { - free = i; - break; - } - } - - if (free == A2DP_NO_SPACE) { - LOG_DBG("More connection cannot be supported"); - return NULL; + if (a2dp->session.br_chan.chan.conn == NULL) { + /* Clean the memory area before returning */ + (void)memset(a2dp, 0, sizeof(struct bt_a2dp)); } - - /* Clean the memory area before returning */ - a2dp_reset(&connection[free]); - - return &connection[free]; + return a2dp; } /* The AVDTP L2CAP signal channel established */ @@ -163,6 +126,7 @@ static int a2dp_get_capabilities_ind(struct bt_avdtp *session, struct bt_avdtp_s { struct bt_a2dp_ep *ep; + __ASSERT(sep, "Invalid sep"); *errcode = 0; /* Service Category: Media Transport */ net_buf_add_u8(rsp_buf, BT_AVDTP_SERVICE_MEDIA_TRANSPORT); @@ -171,9 +135,9 @@ static int a2dp_get_capabilities_ind(struct bt_avdtp *session, struct bt_avdtp_s net_buf_add_u8(rsp_buf, BT_AVDTP_SERVICE_MEDIA_CODEC); ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep); /* Length Of Service Capability */ - net_buf_add_u8(rsp_buf, ep->codec_cap->len + 2u); + net_buf_add_u8(rsp_buf, ep->codec_cap->len + 2U); /* Media Type */ - net_buf_add_u8(rsp_buf, sep->sep_info.media_type << 4u); + net_buf_add_u8(rsp_buf, sep->sep_info.media_type << 4U); /* Media Codec Type */ net_buf_add_u8(rsp_buf, ep->codec_type); /* Codec Info Element */ @@ -181,16 +145,20 @@ static int a2dp_get_capabilities_ind(struct bt_avdtp *session, struct bt_avdtp_s return 0; } -static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t int_seid, - struct net_buf *buf, uint8_t *errcode) +static int a2dp_process_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, + uint8_t int_seid, struct net_buf *buf, uint8_t *errcode, + bool reconfig) { struct bt_a2dp *a2dp = A2DP_AVDTP(session); struct bt_a2dp_ep *ep; - struct bt_a2dp_stream *stream; + struct bt_a2dp_stream *stream = NULL; struct bt_a2dp_stream_ops *ops; uint8_t codec_type; uint8_t *codec_info_element; uint16_t codec_info_element_len; + struct bt_a2dp_codec_cfg cfg; + struct bt_a2dp_codec_ie codec_config; + uint8_t rsp_err_code; int err; *errcode = 0; @@ -205,7 +173,7 @@ static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *se &codec_info_element_len); if (err) { *errcode = BT_AVDTP_BAD_ACP_SEID; - return -1; + return -EINVAL; } if (codec_type == BT_A2DP_SBC) { @@ -214,7 +182,7 @@ static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *se if (codec_info_element_len != 4U) { *errcode = BT_AVDTP_BAD_ACP_SEID; - return -1; + return -EINVAL; } sbc_set = (struct bt_a2dp_codec_sbc_params *)codec_info_element; @@ -225,39 +193,75 @@ static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *se ((BT_A2DP_SBC_SUB_BAND(sbc_set) & BT_A2DP_SBC_SUB_BAND(sbc)) == 0) || ((BT_A2DP_SBC_ALLOC_MTHD(sbc_set) & BT_A2DP_SBC_ALLOC_MTHD(sbc)) == 0)) { *errcode = BT_AVDTP_BAD_ACP_SEID; - return -1; + return -EINVAL; } } - if ((a2dp_cb != NULL) && (a2dp_cb->config_req != NULL)) { - struct bt_a2dp_codec_cfg cfg; - struct bt_a2dp_codec_ie codec_config; - uint8_t rsp_err_code; + /* For reconfig, ep->stream must already be valid, callback can be NULL as default accept. + * For !reconfig, config_req must be set to get stream from upper layer + */ + if (reconfig) { + stream = ep->stream; + if (stream == NULL) { + *errcode = BT_AVDTP_BAD_ACP_SEID; + return -EINVAL; + } + + if (a2dp_cb == NULL || a2dp_cb->reconfig_req == NULL) { + goto process_done; + } + } else if (a2dp_cb == NULL || a2dp_cb->config_req == NULL) { + *errcode = BT_AVDTP_BAD_ACP_SEID; + return -EINVAL; + } - cfg.codec_config = &codec_config; - cfg.codec_config->len = codec_info_element_len; - memcpy(&cfg.codec_config->codec_ie[0], codec_info_element, - (codec_info_element_len > A2DP_MAX_IE_LENGTH ? A2DP_MAX_IE_LENGTH - : codec_info_element_len)); + cfg.codec_config = &codec_config; + cfg.codec_config->len = codec_info_element_len; + memcpy(&cfg.codec_config->codec_ie[0], codec_info_element, + (codec_info_element_len > BT_A2DP_MAX_IE_LENGTH ? BT_A2DP_MAX_IE_LENGTH + : codec_info_element_len)); + if (!reconfig) { err = a2dp_cb->config_req(a2dp, ep, &cfg, &stream, &rsp_err_code); - if (err) { - *errcode = rsp_err_code; - } else if (stream != NULL) { + if (!err && stream) { stream->a2dp = a2dp; stream->local_ep = ep; stream->remote_ep_id = int_seid; stream->remote_ep = NULL; stream->codec_config = *cfg.codec_config; ep->stream = stream; + } else { + *errcode = rsp_err_code != 0 ? rsp_err_code : BT_AVDTP_BAD_ACP_SEID; + } + } else { + err = a2dp_cb->reconfig_req(stream, &cfg, &rsp_err_code); + if (err) { + *errcode = rsp_err_code; + } + } - ops = stream->ops; - if ((ops != NULL) && (ops->configured != NULL)) { - ops->configured(stream); - } +process_done: + if (*errcode == 0) { + ops = stream->ops; + if ((ops != NULL) && (ops->configured != NULL)) { + ops->configured(stream); } } - return (*errcode == 0) ? 0 : -1; + return (*errcode == 0) ? 0 : -EINVAL; +} + +static int a2dp_set_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t int_seid, + struct net_buf *buf, uint8_t *errcode) +{ + __ASSERT(sep, "Invalid sep"); + return a2dp_process_config_ind(session, sep, int_seid, buf, errcode, false); +} + +static int a2dp_re_config_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t int_seid, + struct net_buf *buf, uint8_t *errcode) +{ + __ASSERT(sep, "Invalid sep"); + return a2dp_process_config_ind(session, sep, int_seid, buf, errcode, true); } #if defined(CONFIG_BT_A2DP_SINK) @@ -267,8 +271,9 @@ static void bt_a2dp_media_data_callback(struct bt_avdtp_sep *sep, struct net_buf struct bt_a2dp_ep *ep; struct bt_a2dp_stream *stream; + __ASSERT(sep, "Invalid sep"); ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep); - if ((ep == NULL) || (ep->stream == NULL)) { + if (ep->stream == NULL || buf->len < sizeof(*media_hdr)) { return; } stream = ep->stream; @@ -280,166 +285,70 @@ static void bt_a2dp_media_data_callback(struct bt_avdtp_sep *sep, struct net_buf } #endif -static int a2dp_open_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode) -{ - struct bt_a2dp_ep *ep; - struct bt_a2dp_stream *stream; - struct bt_a2dp_stream_ops *ops; - - *errcode = 0; - ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep); - if (ep->stream == NULL) { - *errcode = BT_AVDTP_BAD_ACP_SEID; - return -1; - } - stream = ep->stream; - - if ((a2dp_cb != NULL) && (a2dp_cb->establish_req != NULL)) { - uint8_t rsp_err_code; - int err; - - err = a2dp_cb->establish_req(stream, &rsp_err_code); - if (err) { - *errcode = rsp_err_code; - } - } - - ops = stream->ops; - if (*errcode == 0) { - if ((ops != NULL) && (stream->ops->established != NULL)) { - stream->ops->established(stream); - } - } - - return (*errcode == 0) ? 0 : -1; -} +typedef int (*bt_a2dp_ctrl_req_cb)(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code); +typedef void (*bt_a2dp_ctrl_done_cb)(struct bt_a2dp_stream *stream); -static int a2dp_start_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode) +static int a2dp_ctrl_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode, + bt_a2dp_ctrl_req_cb req_cb, bt_a2dp_ctrl_done_cb done_cb, + bool clear_stream) { struct bt_a2dp_ep *ep; struct bt_a2dp_stream *stream; - struct bt_a2dp_stream_ops *ops; *errcode = 0; ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep); if (ep->stream == NULL) { *errcode = BT_AVDTP_BAD_ACP_SEID; - return -1; + return -EINVAL; } stream = ep->stream; - if ((a2dp_cb != NULL) && (a2dp_cb->start_req != NULL)) { + if (req_cb != NULL) { uint8_t rsp_err_code; int err; - err = a2dp_cb->start_req(stream, &rsp_err_code); + err = req_cb(stream, &rsp_err_code); if (err) { *errcode = rsp_err_code; } } - ops = stream->ops; if (*errcode == 0) { - if ((ops != NULL) && (stream->ops->started != NULL)) { - stream->ops->started(stream); - } - } - - return (*errcode == 0) ? 0 : -1; -} - -static int a2dp_close_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode) -{ - struct bt_a2dp_ep *ep; - struct bt_a2dp_stream *stream; - struct bt_a2dp_stream_ops *ops; - - *errcode = 0; - ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep); - if (ep->stream == NULL) { - *errcode = BT_AVDTP_BAD_ACP_SEID; - return -1; - } - stream = ep->stream; - - if ((a2dp_cb != NULL) && (a2dp_cb->release_req != NULL)) { - uint8_t rsp_err_code; - int err; - - err = a2dp_cb->release_req(stream, &rsp_err_code); - if (err) { - *errcode = rsp_err_code; + if (clear_stream) { + ep->stream = NULL; } - } - ops = stream->ops; - if (*errcode == 0) { - if ((ops != NULL) && (stream->ops->released != NULL)) { - stream->ops->released(stream); + if (done_cb != NULL) { + done_cb(stream); } } - return (*errcode == 0) ? 0 : -1; + return (*errcode == 0) ? 0 : -EINVAL; } -static int a2dp_suspend_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode) +static int a2dp_open_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode) { - struct bt_a2dp_ep *ep; - struct bt_a2dp_stream *stream; - struct bt_a2dp_stream_ops *ops; + 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; - *errcode = 0; - ep = CONTAINER_OF(sep, struct bt_a2dp_ep, sep); - if (ep->stream == NULL) { - *errcode = BT_AVDTP_BAD_ACP_SEID; - return -1; - } - stream = ep->stream; - - if ((a2dp_cb != NULL) && (a2dp_cb->suspend_req != NULL)) { - uint8_t rsp_err_code; - int err; - - err = a2dp_cb->suspend_req(stream, &rsp_err_code); - if (err) { - *errcode = rsp_err_code; - } - } - - ops = stream->ops; - if (*errcode == 0) { - if ((ops != NULL) && (stream->ops->suspended != NULL)) { - stream->ops->suspended(stream); - } - } - - return (*errcode == 0) ? 0 : -1; + __ASSERT(sep, "Invalid sep"); + req_cb = a2dp_cb != NULL ? a2dp_cb->establish_req : NULL; + done_cb = (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->established + : NULL; + return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false); } -static int bt_a2dp_open_cb(struct bt_avdtp_req *req) +static int a2dp_start_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode) { - struct bt_a2dp *a2dp = OPEN_PARAM(OPEN_REQ(req)); - struct bt_a2dp_ep *ep; - struct bt_a2dp_stream *stream; - struct bt_a2dp_stream_ops *ops; + 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; - ep = CONTAINER_OF(a2dp->open_param.sep, struct bt_a2dp_ep, sep); - if (ep->stream == NULL) { - return -1; - } - stream = ep->stream; - - LOG_DBG("OPEN result:%d", a2dp->open_param.status); - - if ((a2dp_cb != NULL) && (a2dp_cb->establish_rsp != NULL)) { - a2dp_cb->establish_rsp(stream, a2dp->open_param.status); - } - - ops = stream->ops; - if ((!a2dp->open_param.status) && (ops->established != NULL)) { - ops->established(stream); - } - return 0; + __ASSERT(sep, "Invalid sep"); + req_cb = a2dp_cb != NULL ? a2dp_cb->start_req : NULL; + done_cb = (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->started : NULL; + return a2dp_ctrl_ind(session, sep, errcode, req_cb, done_cb, false); } static int bt_a2dp_set_config_cb(struct bt_avdtp_req *req) @@ -451,18 +360,21 @@ static int bt_a2dp_set_config_cb(struct bt_avdtp_req *req) ep = CONTAINER_OF(a2dp->set_config_param.sep, struct bt_a2dp_ep, sep); if (ep->stream == NULL) { - return -1; + return -EINVAL; + } + if ((ep->stream == NULL) || (SET_CONF_REQ(req) != &a2dp->set_config_param)) { + return -EINVAL; } stream = ep->stream; - LOG_DBG("SET CONFIGURATION result:%d", a2dp->set_config_param.status); + LOG_DBG("SET CONFIGURATION result:%d", req->status); if ((a2dp_cb != NULL) && (a2dp_cb->config_rsp != NULL)) { - a2dp_cb->config_rsp(stream, a2dp->set_config_param.status); + a2dp_cb->config_rsp(stream, req->status); } ops = stream->ops; - if ((!a2dp->set_config_param.status) && (ops->configured != NULL)) { + if ((!req->status) && (ops->configured != NULL)) { ops->configured(stream); } return 0; @@ -477,8 +389,12 @@ static int bt_a2dp_get_capabilities_cb(struct bt_avdtp_req *req) uint8_t codec_type; uint8_t user_ret; - LOG_DBG("GET CAPABILITIES result:%d", a2dp->get_capabilities_param.status); - if (a2dp->get_capabilities_param.status) { + if (GET_CAP_REQ(req) != &a2dp->get_capabilities_param) { + return -EINVAL; + } + + LOG_DBG("GET CAPABILITIES result:%d", req->status); + if (req->status) { if ((a2dp->discover_cb_param != NULL) && (a2dp->discover_cb_param->cb != NULL)) { a2dp->discover_cb_param->cb(a2dp, NULL, NULL); a2dp->discover_cb_param = NULL; @@ -493,12 +409,12 @@ static int bt_a2dp_get_capabilities_cb(struct bt_avdtp_req *req) return 0; } - if (codec_info_element_len > A2DP_MAX_IE_LENGTH) { - codec_info_element_len = A2DP_MAX_IE_LENGTH; + if (codec_info_element_len > BT_A2DP_MAX_IE_LENGTH) { + codec_info_element_len = BT_A2DP_MAX_IE_LENGTH; } if ((a2dp->discover_cb_param != NULL) && (a2dp->discover_cb_param->cb != NULL)) { - struct bt_a2dp_ep *ep; + struct bt_a2dp_ep *ep = NULL; struct bt_a2dp_ep_info *info = &a2dp->discover_cb_param->info; info->codec_type = codec_type; @@ -557,7 +473,7 @@ static int bt_a2dp_get_sep_caps(struct bt_a2dp *a2dp) return 0; } } - return -1; + return -EINVAL; } static int bt_a2dp_discover_cb(struct bt_avdtp_req *req) @@ -566,12 +482,12 @@ static int bt_a2dp_discover_cb(struct bt_avdtp_req *req) struct bt_avdtp_sep_info *sep_info; int err; - LOG_DBG("DISCOVER result:%d", DISCOVER_REQ(req)->status); + LOG_DBG("DISCOVER result:%d", req->status); if (a2dp->discover_cb_param == NULL) { return -EINVAL; } a2dp->peer_seps_count = 0U; - if (!(DISCOVER_REQ(req)->status)) { + if (!(req->status)) { if (a2dp->discover_cb_param->sep_count == 0) { if (a2dp->discover_cb_param->cb != NULL) { a2dp->discover_cb_param->cb(a2dp, NULL, NULL); @@ -610,32 +526,6 @@ static int bt_a2dp_discover_cb(struct bt_avdtp_req *req) return 0; } -static int bt_a2dp_start_cb(struct bt_avdtp_req *req) -{ - struct bt_a2dp *a2dp = START_PARAM(START_REQ(req)); - struct bt_a2dp_ep *ep; - struct bt_a2dp_stream *stream; - struct bt_a2dp_stream_ops *ops; - - ep = CONTAINER_OF(a2dp->start_param.sep, struct bt_a2dp_ep, sep); - if (ep->stream == NULL) { - return -1; - } - stream = ep->stream; - - LOG_DBG("START result:%d", a2dp->start_param.status); - - if ((a2dp_cb != NULL) && (a2dp_cb->start_rsp != NULL)) { - a2dp_cb->start_rsp(stream, a2dp->start_param.status); - } - - ops = stream->ops; - if ((!a2dp->start_param.status) && (ops->started != NULL)) { - ops->started(stream); - } - return 0; -} - int bt_a2dp_discover(struct bt_a2dp *a2dp, struct bt_a2dp_discover_param *param) { int err; @@ -668,10 +558,26 @@ int bt_a2dp_discover(struct bt_a2dp *a2dp, struct bt_a2dp_discover_param *param) void bt_a2dp_stream_cb_register(struct bt_a2dp_stream *stream, struct bt_a2dp_stream_ops *ops) { - BT_ASSERT(stream); + __ASSERT_NO_MSG(stream); stream->ops = ops; } +static inline void bt_a2dp_stream_config_set_param(struct bt_a2dp *a2dp, + struct bt_a2dp_codec_cfg *config, + bt_avdtp_func_t cb, uint8_t remote_id, + uint8_t int_id, uint8_t codec_type, + struct bt_avdtp_sep *sep) +{ + a2dp->set_config_param.req.func = cb; + a2dp->set_config_param.acp_stream_ep_id = remote_id; + a2dp->set_config_param.int_stream_endpoint_id = int_id; + a2dp->set_config_param.media_type = BT_AVDTP_AUDIO; + a2dp->set_config_param.media_codec_type = codec_type; + a2dp->set_config_param.codec_specific_ie_len = config->codec_config->len; + a2dp->set_config_param.codec_specific_ie = &config->codec_config->codec_ie[0]; + a2dp->set_config_param.sep = sep; +} + int bt_a2dp_stream_config(struct bt_a2dp *a2dp, struct bt_a2dp_stream *stream, struct bt_a2dp_ep *local_ep, struct bt_a2dp_ep *remote_ep, struct bt_a2dp_codec_cfg *config) @@ -692,41 +598,65 @@ int bt_a2dp_stream_config(struct bt_a2dp *a2dp, struct bt_a2dp_stream *stream, stream->a2dp = a2dp; local_ep->stream = stream; remote_ep->stream = stream; - a2dp->set_config_param.req.func = bt_a2dp_set_config_cb; - a2dp->set_config_param.acp_stream_ep_id = remote_ep->sep.sep_info.id; - a2dp->set_config_param.int_stream_endpoint_id = local_ep->sep.sep_info.id; - a2dp->set_config_param.media_type = BT_AVDTP_AUDIO; - a2dp->set_config_param.media_codec_type = local_ep->codec_type; - a2dp->set_config_param.codec_specific_ie_len = config->codec_config->len; - a2dp->set_config_param.codec_specific_ie = &config->codec_config->codec_ie[0]; - a2dp->set_config_param.sep = &local_ep->sep; + bt_a2dp_stream_config_set_param(a2dp, config, bt_a2dp_set_config_cb, + remote_ep->sep.sep_info.id, local_ep->sep.sep_info.id, + local_ep->codec_type, &local_ep->sep); return bt_avdtp_set_configuration(&a2dp->session, &a2dp->set_config_param); } -int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream) +typedef void (*bt_a2dp_rsp_cb)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); +typedef void (*bt_a2dp_done_cb)(struct bt_a2dp_stream *stream); + +static int bt_a2dp_ctrl_cb(struct bt_avdtp_req *req, bt_a2dp_rsp_cb rsp_cb, bt_a2dp_done_cb done_cb, + bool clear_stream) { - struct bt_a2dp *a2dp; + struct bt_a2dp *a2dp = CTRL_PARAM(CTRL_REQ(req)); + struct bt_a2dp_ep *ep; + struct bt_a2dp_stream *stream; - if ((stream == NULL) || (stream->local_ep == NULL) || (stream->a2dp == NULL)) { + ep = CONTAINER_OF(a2dp->ctrl_param.sep, struct bt_a2dp_ep, sep); + if ((ep->stream == NULL) || (CTRL_REQ(req) != &a2dp->ctrl_param)) { return -EINVAL; } + stream = ep->stream; + if (clear_stream) { + ep->stream = NULL; + } - a2dp = stream->a2dp; - a2dp->open_param.req.func = bt_a2dp_open_cb; - a2dp->open_param.acp_stream_ep_id = stream->remote_ep != NULL - ? stream->remote_ep->sep.sep_info.id - : stream->remote_ep_id; - a2dp->open_param.sep = &stream->local_ep->sep; - return bt_avdtp_open(&a2dp->session, &a2dp->open_param); + LOG_DBG("ctrl result:%d", req->status); + + if (rsp_cb != NULL) { + rsp_cb(stream, req->status); + } + + if ((!req->status) && (done_cb != NULL)) { + done_cb(stream); + } + return 0; } -int bt_a2dp_stream_release(struct bt_a2dp_stream *stream) +static int bt_a2dp_open_cb(struct bt_avdtp_req *req) { - /* todo: see the API description in a2dp.h */ - return -ENOTSUP; + 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->establish_rsp : NULL; + bt_a2dp_done_cb done_cb = (ep->stream != NULL && ep->stream->ops != NULL) + ? ep->stream->ops->established + : NULL; + + return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false); } -int bt_a2dp_stream_start(struct bt_a2dp_stream *stream) +static int bt_a2dp_start_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->start_rsp : NULL; + bt_a2dp_done_cb done_cb = + (ep->stream != NULL && ep->stream->ops != NULL) ? ep->stream->ops->started : NULL; + + return bt_a2dp_ctrl_cb(req, rsp_cb, done_cb, false); +} + +static int bt_a2dp_stream_ctrl_pre(struct bt_a2dp_stream *stream, bt_avdtp_func_t cb) { struct bt_a2dp *a2dp; @@ -735,30 +665,58 @@ int bt_a2dp_stream_start(struct bt_a2dp_stream *stream) } a2dp = stream->a2dp; - a2dp->start_param.req.func = bt_a2dp_start_cb; - a2dp->start_param.acp_stream_ep_id = stream->remote_ep != NULL - ? stream->remote_ep->sep.sep_info.id - : stream->remote_ep_id; - a2dp->start_param.sep = &stream->local_ep->sep; - return bt_avdtp_start(&a2dp->session, &a2dp->start_param); + a2dp->ctrl_param.req.func = cb; + a2dp->ctrl_param.acp_stream_ep_id = stream->remote_ep != NULL + ? stream->remote_ep->sep.sep_info.id + : stream->remote_ep_id; + a2dp->ctrl_param.sep = &stream->local_ep->sep; + return 0; } -int bt_a2dp_stream_suspend(struct bt_a2dp_stream *stream) +int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream) { - /* todo: see the API description in a2dp.h */ - return -ENOTSUP; + int err; + struct bt_a2dp *a2dp = stream->a2dp; + + err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_open_cb); + if (err) { + return err; + } + return bt_avdtp_open(&a2dp->session, &a2dp->ctrl_param); +} + +int bt_a2dp_stream_start(struct bt_a2dp_stream *stream) +{ + int err; + struct bt_a2dp *a2dp = stream->a2dp; + + err = bt_a2dp_stream_ctrl_pre(stream, bt_a2dp_start_cb); + if (err) { + return err; + } + return bt_avdtp_start(&a2dp->session, &a2dp->ctrl_param); } int bt_a2dp_stream_reconfig(struct bt_a2dp_stream *stream, struct bt_a2dp_codec_cfg *config) { - /* todo: see the API description in a2dp.h */ - return -ENOTSUP; + uint8_t remote_id; + + if ((stream == NULL) || (config == NULL)) { + return -EINVAL; + } + + remote_id = stream->remote_ep != NULL ? stream->remote_ep->sep.sep_info.id + : stream->remote_ep_id; + bt_a2dp_stream_config_set_param(stream->a2dp, config, bt_a2dp_set_config_cb, remote_id, + stream->local_ep->sep.sep_info.id, + stream->local_ep->codec_type, &stream->local_ep->sep); + return bt_avdtp_reconfigure(&stream->a2dp->session, &stream->a2dp->set_config_param); } uint32_t bt_a2dp_get_mtu(struct bt_a2dp_stream *stream) { if ((stream == NULL) || (stream->local_ep == NULL)) { - return -EINVAL; + return 0; } return bt_avdtp_get_media_mtu(&stream->local_ep->sep); @@ -770,16 +728,17 @@ int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, uint { struct bt_avdtp_media_hdr *media_hdr; - if (stream == NULL) { + if (stream == NULL || stream->local_ep == NULL) { return -EINVAL; } media_hdr = net_buf_push(buf, sizeof(struct bt_avdtp_media_hdr)); + memset(media_hdr, 0, sizeof(struct bt_avdtp_media_hdr)); if (stream->local_ep->codec_type == BT_A2DP_SBC) { media_hdr->playload_type = A2DP_SBC_PAYLOAD_TYPE; } - memset(media_hdr, 0, sizeof(struct bt_avdtp_media_hdr)); + media_hdr->RTP_version = BT_AVDTP_RTP_VERSION; media_hdr->synchronization_source = 0U; /* update time_stamp in the buf */ sys_put_be32(ts, (uint8_t *)&media_hdr->time_stamp); @@ -797,17 +756,16 @@ static const struct bt_avdtp_ops_cb signaling_avdtp_ops = { .discovery_ind = a2dp_discovery_ind, .get_capabilities_ind = a2dp_get_capabilities_ind, .set_configuration_ind = a2dp_set_config_ind, + .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, }; int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session) { struct bt_a2dp *a2dp; - a2dp = get_new_connection(conn); + a2dp = a2dp_get_connection(conn); if (!a2dp) { return -ENOMEM; } @@ -848,10 +806,8 @@ struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn) struct bt_a2dp *a2dp; int err; - A2DP_LOCK(); - a2dp = get_new_connection(conn); + a2dp = a2dp_get_connection(conn); if (!a2dp) { - A2DP_UNLOCK(); LOG_ERR("Cannot allocate memory"); return NULL; } @@ -861,32 +817,28 @@ struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn) a2dp->session.ops = &signaling_avdtp_ops; err = bt_avdtp_connect(conn, &(a2dp->session)); if (err < 0) { - /* If error occurs, undo the saving and return the error */ - a2dp_reset(a2dp); - A2DP_UNLOCK(); LOG_DBG("AVDTP Connect failed"); return NULL; } - A2DP_UNLOCK(); LOG_DBG("Connect request sent"); return a2dp; } int bt_a2dp_disconnect(struct bt_a2dp *a2dp) { - /* todo: see the API description in a2dp.h */ - return -ENOTSUP; + __ASSERT_NO_MSG(a2dp); + return bt_avdtp_disconnect(&a2dp->session); } -int bt_a2dp_register_ep(struct bt_a2dp_ep *ep, uint8_t media_type, uint8_t role) +int bt_a2dp_register_ep(struct bt_a2dp_ep *ep, uint8_t media_type, uint8_t sep_type) { int err; - BT_ASSERT(ep); + __ASSERT_NO_MSG(ep); #if defined(CONFIG_BT_A2DP_SINK) - if (role == BT_AVDTP_SINK) { + if (sep_type == BT_AVDTP_SINK) { ep->sep.media_data_cb = bt_a2dp_media_data_callback; } else { ep->sep.media_data_cb = NULL; @@ -894,9 +846,7 @@ int bt_a2dp_register_ep(struct bt_a2dp_ep *ep, uint8_t media_type, uint8_t role) #else ep->sep.media_data_cb = NULL; #endif - A2DP_LOCK(); - err = bt_avdtp_register_sep(media_type, role, &(ep->sep)); - A2DP_UNLOCK(); + err = bt_avdtp_register_sep(media_type, sep_type, &(ep->sep)); if (err < 0) { return err; } diff --git a/subsys/bluetooth/host/classic/avdtp.c b/subsys/bluetooth/host/classic/avdtp.c index c0b285b3a95df..d137a6218c6c7 100644 --- a/subsys/bluetooth/host/classic/avdtp.c +++ b/subsys/bluetooth/host/classic/avdtp.c @@ -49,26 +49,71 @@ static sys_slist_t seps; #define DISCOVER_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_discover_params, req) #define GET_CAP_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_get_capabilities_params, req) #define SET_CONF_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_set_configuration_params, req) -#define OPEN_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_open_params, req) -#define START_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_start_params, req) +#define CTRL_REQ(_req) CONTAINER_OF(_req, struct bt_avdtp_ctrl_params, req) #define AVDTP_TIMEOUT K_SECONDS(6) -K_MUTEX_DEFINE(avdtp_mutex); -#define AVDTP_LOCK() k_mutex_lock(&avdtp_mutex, K_FOREVER) -#define AVDTP_UNLOCK() k_mutex_unlock(&avdtp_mutex) +K_SEM_DEFINE(avdtp_sem_lock, 1U, 1U); enum sep_state { - AVDTP_IDLE = 0, - AVDTP_CONFIGURED, + AVDTP_IDLE = BIT(0), + AVDTP_CONFIGURED = BIT(1), /* establishing the transport sessions. */ - AVDTP_OPENING, - AVDTP_OPEN, - AVDTP_STREAMING, - AVDTP_CLOSING, - AVDTP_ABORTING, + AVDTP_OPENING = BIT(2), + AVDTP_OPEN = BIT(3), + AVDTP_STREAMING = BIT(4), + AVDTP_CLOSING = BIT(5), + AVDTP_ABORTING = BIT(6), }; +static void avdtp_lock(struct bt_avdtp *session) +{ + k_sem_take(&session->sem_lock, K_FOREVER); +} + +static void avdtp_unlock(struct bt_avdtp *session) +{ + k_sem_give(&session->sem_lock); +} + +static void avdtp_sep_lock(struct bt_avdtp_sep *sep) +{ + if (sep != NULL) { + k_sem_take(&sep->sem_lock, K_FOREVER); + } +} + +static void avdtp_sep_unlock(struct bt_avdtp_sep *sep) +{ + if (sep != NULL) { + k_sem_give(&sep->sem_lock); + } +} + +static void bt_avdtp_set_state(struct bt_avdtp_sep *sep, uint8_t state) +{ + sep->state = state; + if (state != AVDTP_IDLE) { + sep->sep_info.inuse = 1U; + } else { + sep->sep_info.inuse = 0U; + } +} + +static void bt_avdtp_set_state_lock(struct bt_avdtp_sep *sep, uint8_t state) +{ + avdtp_sep_lock(sep); + bt_avdtp_set_state(sep, state); + avdtp_sep_unlock(sep); +} + +static inline void bt_avdtp_clear_req(struct bt_avdtp *session) +{ + avdtp_lock(session); + session->req = NULL; + avdtp_unlock(session); +} + /* L2CAP Interface callbacks */ void bt_avdtp_media_l2cap_connected(struct bt_l2cap_chan *chan) { @@ -86,14 +131,12 @@ void bt_avdtp_media_l2cap_connected(struct bt_l2cap_chan *chan) } LOG_DBG("chan %p session %p", chan, session); - sep->state = AVDTP_OPEN; + bt_avdtp_set_state_lock(sep, AVDTP_OPEN); if (session->req != NULL) { struct bt_avdtp_req *req = session->req; - OPEN_REQ(req)->status = 0; - AVDTP_LOCK(); - session->req = NULL; - AVDTP_UNLOCK(); + req->status = 0; + bt_avdtp_clear_req(session); if (req->func != NULL) { req->func(req); } @@ -122,20 +165,21 @@ int bt_avdtp_media_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) return 0; } +static const struct bt_l2cap_chan_ops stream_chan_ops = { + .connected = bt_avdtp_media_l2cap_connected, + .disconnected = bt_avdtp_media_l2cap_disconnected, + .recv = bt_avdtp_media_l2cap_recv, +}; + static int avdtp_media_connect(struct bt_avdtp *session, struct bt_avdtp_sep *sep) { - static const struct bt_l2cap_chan_ops ops = {.connected = bt_avdtp_media_l2cap_connected, - .disconnected = - bt_avdtp_media_l2cap_disconnected, - .recv = bt_avdtp_media_l2cap_recv}; - if (!session) { return -EINVAL; } sep->session = session; sep->chan.rx.mtu = BT_L2CAP_RX_MTU; - sep->chan.chan.ops = &ops; + sep->chan.chan.ops = &stream_chan_ops; sep->chan.required_sec_level = BT_SECURITY_L2; return bt_l2cap_chan_connect(session->br_chan.chan.conn, &sep->chan.chan, @@ -165,6 +209,24 @@ static struct net_buf *avdtp_create_reply_pdu(uint8_t msg_type, uint8_t pkt_type return buf; } +static void avdtp_set_status(struct bt_avdtp_req *req, struct net_buf *buf, uint8_t msg_type) +{ + if (msg_type == BT_AVDTP_ACCEPT) { + req->status = 0; + } else if (msg_type == BT_AVDTP_REJECT) { + if (buf->len >= 1U) { + req->status = net_buf_pull_u8(buf); + } else { + LOG_WRN("Invalid RSP frame"); + req->status = BT_AVDTP_BAD_LENGTH; + } + } else if (msg_type == BT_AVDTP_GEN_REJECT) { + req->status = BT_AVDTP_NOT_SUPPORTED_COMMAND; + } else { + req->status = BT_AVDTP_BAD_HEADER_FORMAT; + } +} + static void avdtp_discover_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, uint8_t tid) { @@ -215,26 +277,17 @@ static void avdtp_discover_handler(struct bt_avdtp *session, struct net_buf *buf } else { struct bt_avdtp_req *req = session->req; - if (session->req == NULL) { + if (req == NULL) { return; } k_work_cancel_delayable(&session->timeout_work); if (msg_type == BT_AVDTP_ACCEPT) { - DISCOVER_REQ(session->req)->status = 0; - DISCOVER_REQ(session->req)->buf = buf; - } else if (msg_type == BT_AVDTP_REJECT) { - if (buf->len < 1) { - LOG_WRN("Invalid RSP frame"); - return; - } - - DISCOVER_REQ(session->req)->status = net_buf_pull_u8(buf); - } else if (msg_type == BT_AVDTP_GEN_REJECT) { - DISCOVER_REQ(session->req)->status = BT_AVDTP_NOT_SUPPORTED_COMMAND; + DISCOVER_REQ(req)->buf = buf; + } else { + DISCOVER_REQ(req)->buf = NULL; } - AVDTP_LOCK(); - session->req = NULL; - AVDTP_UNLOCK(); + avdtp_set_status(req, buf, msg_type); + bt_avdtp_clear_req(session); if (req->func != NULL) { req->func(req); } @@ -254,6 +307,18 @@ static struct bt_avdtp_sep *avdtp_get_sep(uint8_t stream_endpoint_id) return sep; } +static struct bt_avdtp_sep *avdtp_get_cmd_sep(struct net_buf *buf) +{ + struct bt_avdtp_sep *sep; + + if (buf->len < 1U) { + LOG_WRN("Invalid ACP SEID"); + return NULL; + } + sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2); + return sep; +} + static void avdtp_get_capabilities_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, uint8_t tid) { @@ -263,12 +328,7 @@ static void avdtp_get_capabilities_handler(struct bt_avdtp *session, struct net_ struct bt_avdtp_sep *sep; uint8_t error_code = 0; - if (buf->len < 1) { - LOG_WRN("Invalid ACP SEID"); - return; - } - - sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2); + sep = avdtp_get_cmd_sep(buf); if ((sep == NULL) || (session->ops->get_capabilities_ind == NULL)) { err = -ENOTSUP; } else { @@ -309,30 +369,17 @@ static void avdtp_get_capabilities_handler(struct bt_avdtp *session, struct net_ } else { struct bt_avdtp_req *req = session->req; - if (session->req == NULL) { + if (req == NULL) { return; } k_work_cancel_delayable(&session->timeout_work); GET_CAP_REQ(session->req)->buf = NULL; if (msg_type == BT_AVDTP_ACCEPT) { - GET_CAP_REQ(session->req)->status = 0; - if (session->req != NULL) { - GET_CAP_REQ(session->req)->buf = buf; - } - } else if (msg_type == BT_AVDTP_REJECT) { - if (buf->len < 1) { - LOG_WRN("Invalid RSP frame"); - return; - } - - GET_CAP_REQ(session->req)->status = net_buf_pull_u8(buf); - } else if (msg_type == BT_AVDTP_GEN_REJECT) { - GET_CAP_REQ(session->req)->status = BT_AVDTP_NOT_SUPPORTED_COMMAND; + GET_CAP_REQ(req)->buf = buf; } - AVDTP_LOCK(); - session->req = NULL; - AVDTP_UNLOCK(); + avdtp_set_status(req, buf, msg_type); + bt_avdtp_clear_req(session); if (req->func != NULL) { req->func(req); } @@ -340,45 +387,60 @@ static void avdtp_get_capabilities_handler(struct bt_avdtp *session, struct net_ } static void avdtp_process_configuration(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t tid) + uint8_t msg_type, uint8_t tid, bool reconfig) { 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; - if (buf->len < 1) { - LOG_WRN("Invalid ACP SEID"); - return; - } - - sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2); - if ((sep == NULL) || (session->ops->set_configuration_ind == NULL)) { + sep = avdtp_get_cmd_sep(buf); + avdtp_sep_lock(sep); + if (sep == NULL) { + err = -ENOTSUP; + } else if (!reconfig && session->ops->set_configuration_ind == NULL) { + err = -ENOTSUP; + } else if (reconfig && session->ops->re_configuration_ind == NULL) { err = -ENOTSUP; } else { - if (sep->state == AVDTP_STREAMING) { + uint8_t expected_state; + + if (reconfig) { + expected_state = AVDTP_OPEN | AVDTP_OPENING; + } else { + expected_state = AVDTP_IDLE; + } + + if (!(sep->state & expected_state)) { err = -ENOTSUP; error_code = BT_AVDTP_BAD_STATE; } else { uint8_t int_seid; - if (buf->len < 1) { + if (buf->len < 1U) { LOG_WRN("Invalid INT SEID"); + avdtp_sep_unlock(sep); return; } - /* INT Stream Endpoint ID */ - int_seid = net_buf_pull_u8(buf); - err = session->ops->set_configuration_ind(session, sep, int_seid, - buf, &error_code); + int_seid = net_buf_pull_u8(buf) >> 2; + if (!reconfig) { + err = session->ops->set_configuration_ind( + session, sep, int_seid, buf, &error_code); + } else { + err = session->ops->re_configuration_ind( + session, sep, int_seid, buf, &error_code); + } } } - rsp_buf = avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_SET_CONFIGURATION, tid); + rsp_buf = avdtp_create_reply_pdu( + err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, + reconfig ? BT_AVDTP_RECONFIGURE : BT_AVDTP_SET_CONFIGURATION, tid); if (!rsp_buf) { + avdtp_sep_unlock(sep); return; } @@ -393,41 +455,38 @@ static void avdtp_process_configuration(struct bt_avdtp *session, struct net_buf net_buf_add_u8(rsp_buf, 0); /* ERROR CODE */ net_buf_add_u8(rsp_buf, error_code); - } else { - sep->state = AVDTP_CONFIGURED; } - 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); - return; + LOG_ERR("Error:L2CAP send fail - result = %d", ret); + } + if (!reconfig && !err && !ret) { + bt_avdtp_set_state(sep, AVDTP_CONFIGURED); } + avdtp_sep_unlock(sep); } else { struct bt_avdtp_req *req = session->req; - if (session->req == NULL) { + if (req == NULL) { return; } k_work_cancel_delayable(&session->timeout_work); if (msg_type == BT_AVDTP_ACCEPT) { - SET_CONF_REQ(req)->status = 0; - SET_CONF_REQ(req)->sep->state = AVDTP_CONFIGURED; + if (!reconfig) { + bt_avdtp_set_state_lock(SET_CONF_REQ(req)->sep, AVDTP_CONFIGURED); + } } else if (msg_type == BT_AVDTP_REJECT) { - if (buf->len < 2) { + if (buf->len < 1U) { LOG_WRN("Invalid RSP frame"); return; } - /* Service Category */ net_buf_pull_u8(buf); - SET_CONF_REQ(req)->status = net_buf_pull_u8(buf); - } else if (msg_type == BT_AVDTP_GEN_REJECT) { - SET_CONF_REQ(req)->status = BT_AVDTP_NOT_SUPPORTED_COMMAND; } - AVDTP_LOCK(); - session->req = NULL; - AVDTP_UNLOCK(); + avdtp_set_status(req, buf, msg_type); + bt_avdtp_clear_req(session); if (req->func != NULL) { req->func(req); } @@ -437,7 +496,7 @@ static void avdtp_process_configuration(struct bt_avdtp *session, struct net_buf static void avdtp_set_configuration_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, uint8_t tid) { - avdtp_process_configuration(session, buf, msg_type, tid); + avdtp_process_configuration(session, buf, msg_type, tid, false); } static void avdtp_get_configuration_handler(struct bt_avdtp *session, struct net_buf *buf, @@ -465,7 +524,7 @@ static void avdtp_get_configuration_handler(struct bt_avdtp *session, struct net static void avdtp_re_configure_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, uint8_t tid) { - avdtp_process_configuration(session, buf, msg_type, tid); + avdtp_process_configuration(session, buf, msg_type, tid, true); } static void avdtp_open_handler(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, @@ -473,16 +532,13 @@ static void avdtp_open_handler(struct bt_avdtp *session, struct net_buf *buf, ui { 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; - if (buf->len < 1) { - LOG_WRN("Invalid ACP SEID"); - return; - } - - 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->open_ind == NULL)) { err = -ENOTSUP; } else { @@ -497,6 +553,7 @@ static void avdtp_open_handler(struct bt_avdtp *session, struct net_buf *buf, ui rsp_buf = avdtp_create_reply_pdu(err ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_OPEN, tid); if (!rsp_buf) { + avdtp_sep_unlock(sep); return; } @@ -508,44 +565,35 @@ static void avdtp_open_handler(struct bt_avdtp *session, struct net_buf *buf, ui net_buf_add_u8(rsp_buf, error_code); } else { session->current_sep = sep; - sep->state = AVDTP_OPENING; - sep->sep_info.inuse = 1u; } - 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); - return; + LOG_ERR("Error:L2CAP send fail - result = %d", ret); + } + + if (!err && !ret) { + bt_avdtp_set_state(sep, AVDTP_OPENING); } + avdtp_sep_unlock(sep); } else { struct bt_avdtp_req *req = session->req; - if (session->req == NULL) { + if (req == NULL) { return; } k_work_cancel_delayable(&session->timeout_work); + avdtp_set_status(req, buf, msg_type); if (msg_type == BT_AVDTP_ACCEPT) { - OPEN_REQ(req)->status = 0; - OPEN_REQ(req)->sep->state = AVDTP_OPENING; - if (!avdtp_media_connect(session, OPEN_REQ(req)->sep)) { - return; - } - } else if (msg_type == BT_AVDTP_REJECT) { - if (buf->len < 1) { - LOG_WRN("Invalid RSP frame"); + bt_avdtp_set_state_lock(CTRL_REQ(req)->sep, AVDTP_OPENING); + /* wait the media l2cap is established */ + if (!avdtp_media_connect(session, CTRL_REQ(req)->sep)) { return; } - - OPEN_REQ(req)->status = net_buf_pull_u8(buf); - } else if (msg_type == BT_AVDTP_GEN_REJECT) { - OPEN_REQ(req)->status = BT_AVDTP_NOT_SUPPORTED_COMMAND; } - if (OPEN_REQ(req)->status) { - /* wait the media l2cap is established */ - AVDTP_LOCK(); - session->req = NULL; - AVDTP_UNLOCK(); + if (req->status) { + bt_avdtp_clear_req(session); if (req->func != NULL) { req->func(req); } @@ -558,16 +606,13 @@ static void avdtp_start_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; - if (buf->len < 1) { - LOG_WRN("Invalid ACP SEID"); - return; - } - - 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->start_ind == NULL)) { err = -ENOTSUP; } else { @@ -582,6 +627,7 @@ static void avdtp_start_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_START, tid); if (!rsp_buf) { + avdtp_sep_unlock(sep); return; } @@ -591,46 +637,38 @@ static void avdtp_start_handler(struct bt_avdtp *session, struct net_buf *buf, u } LOG_DBG("start err code:%d", error_code); net_buf_add_u8(rsp_buf, error_code); - } else { - sep->state = AVDTP_STREAMING; } - 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); - return; + LOG_ERR("Error:L2CAP send fail - result = %d", ret); + } + if (!err && !ret) { + bt_avdtp_set_state(sep, AVDTP_STREAMING); } + avdtp_sep_unlock(sep); } else { struct bt_avdtp_req *req = session->req; - if (session->req == NULL) { + if (req == NULL) { return; } k_work_cancel_delayable(&session->timeout_work); if (msg_type == BT_AVDTP_ACCEPT) { - START_REQ(req)->status = 0; - START_REQ(req)->sep->state = AVDTP_STREAMING; + bt_avdtp_set_state_lock(CTRL_REQ(req)->sep, AVDTP_STREAMING); } else if (msg_type == BT_AVDTP_REJECT) { - uint8_t acp_seid; - - if (buf->len < 2) { - LOG_WRN("Invalid RSP frame"); - return; - } + if (buf->len > 1U) { + uint8_t acp_seid; - acp_seid = net_buf_pull_u8(buf); - if (acp_seid != START_REQ(req)->acp_stream_ep_id) { - return; + acp_seid = net_buf_pull_u8(buf); + if (acp_seid != CTRL_REQ(req)->acp_stream_ep_id) { + return; + } } - - START_REQ(req)->status = net_buf_pull_u8(buf); - } else if (msg_type == BT_AVDTP_GEN_REJECT) { - START_REQ(req)->status = BT_AVDTP_NOT_SUPPORTED_COMMAND; } - AVDTP_LOCK(); - session->req = NULL; - AVDTP_UNLOCK(); + avdtp_set_status(req, buf, msg_type); + bt_avdtp_clear_req(session); if (req->func != NULL) { req->func(req); } @@ -646,11 +684,6 @@ static void avdtp_close_handler(struct bt_avdtp *session, struct net_buf *buf, u struct net_buf *rsp_buf; uint8_t error_code = 0; - if (buf->len < 1) { - LOG_WRN("Invalid ACP SEID"); - return; - } - sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2); if ((sep == NULL) || (session->ops->close_ind == NULL)) { err = -ENOTSUP; @@ -698,11 +731,6 @@ static void avdtp_suspend_handler(struct bt_avdtp *session, struct net_buf *buf, struct net_buf *rsp_buf; uint8_t error_code = 0; - if (buf->len < 1) { - LOG_WRN("Invalid ACP SEID"); - return; - } - sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2); if ((sep == NULL) || (session->ops->suspend_ind == NULL)) { err = -ENOTSUP; @@ -750,11 +778,6 @@ static void avdtp_abort_handler(struct bt_avdtp *session, struct net_buf *buf, u struct net_buf *rsp_buf; uint8_t error_code = 0; - if (buf->len < 1) { - LOG_WRN("Invalid ACP SEID"); - return; - } - sep = avdtp_get_sep(net_buf_pull_u8(buf) >> 2); if ((sep == NULL) || (session->ops->abort_ind == NULL)) { err = -ENOTSUP; @@ -799,23 +822,14 @@ static void avdtp_timeout(struct k_work *work) switch (req->sig) { case BT_AVDTP_DISCOVER: - DISCOVER_REQ(req)->status = BT_AVDTP_TIME_OUT; - req->func(req); - break; case BT_AVDTP_GET_CAPABILITIES: - GET_CAP_REQ(req)->status = BT_AVDTP_TIME_OUT; - req->func(req); - break; case BT_AVDTP_SET_CONFIGURATION: - SET_CONF_REQ(req)->status = BT_AVDTP_TIME_OUT; - req->func(req); - break; + case BT_AVDTP_RECONFIGURE: case BT_AVDTP_OPEN: - OPEN_REQ(req)->status = BT_AVDTP_TIME_OUT; - req->func(req); - break; + case BT_AVDTP_CLOSE: case BT_AVDTP_START: - START_REQ(req)->status = BT_AVDTP_TIME_OUT; + case BT_AVDTP_SUSPEND: + req->status = BT_AVDTP_TIME_OUT; req->func(req); break; default: @@ -831,22 +845,20 @@ static int avdtp_send(struct bt_avdtp *session, struct net_buf *buf, struct bt_a int result; struct bt_avdtp_single_sig_hdr *hdr; - AVDTP_LOCK(); + avdtp_lock(session); if (session->req != NULL) { - AVDTP_UNLOCK(); + avdtp_unlock(session); return -EBUSY; } session->req = req; - AVDTP_UNLOCK(); + avdtp_unlock(session); hdr = (struct bt_avdtp_single_sig_hdr *)buf->data; result = bt_l2cap_chan_send(&session->br_chan.chan, buf); if (result < 0) { LOG_ERR("Error:L2CAP send fail - result = %d", result); net_buf_unref(buf); - AVDTP_LOCK(); - session->req = NULL; - AVDTP_UNLOCK(); + bt_avdtp_clear_req(session); return result; } @@ -905,18 +917,21 @@ void bt_avdtp_l2cap_disconnected(struct bt_l2cap_chan *chan) LOG_DBG("chan %p session %p", chan, session); session->br_chan.chan.conn = NULL; - session->signalling_l2cap_connected = 0; - /* todo: Clear the Pending req if set*/ + /* Clear the Pending req if set*/ + if (session->req) { + struct bt_avdtp_req *req = session->req; + + req->status = BT_AVDTP_BAD_STATE; + bt_avdtp_clear_req(session); + if (req->func != NULL) { + req->func(req); + } + } /* notify a2dp disconnect */ session->ops->disconnected(session); } -void bt_avdtp_l2cap_encrypt_changed(struct bt_l2cap_chan *chan, uint8_t status) -{ - LOG_DBG(""); -} - static const struct { uint8_t sig_id; void (*func)(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type, uint8_t tid); @@ -941,7 +956,7 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) if (buf->len < sizeof(*hdr)) { LOG_ERR("Recvd Wrong AVDTP Header"); - return 0; + return -EINVAL; } hdr = net_buf_pull_mem(buf, sizeof(*hdr)); @@ -959,17 +974,15 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) struct net_buf *rsp_buf; int err; - if (buf->len < sizeof(sigid)) { - LOG_ERR("Invalid AVDTP Header"); - return 0; + if (buf->len < 1U) { + return -EINVAL; } - sigid = net_buf_pull_u8(buf); rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_REJECT, BT_AVDTP_PACKET_TYPE_SINGLE, sigid, tid); if (!rsp_buf) { LOG_ERR("Error: No Buff available"); - return 0; + return -EINVAL; } err = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf); if (err < 0) { @@ -984,22 +997,17 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) if (msgtype != BT_AVDTP_CMD) { if (session->req == NULL) { LOG_DBG("Unexpected peer response"); - return 0; + return -EINVAL; } if (session->req->sig != sigid || session->req->tid != tid) { LOG_DBG("Peer mismatch resp, expected sig[0x%02x]" "tid[0x%02x]", session->req->sig, session->req->tid); - return 0; + return -EINVAL; } } - if (!session) { - LOG_DBG("Error: Session not valid"); - return 0; - } - for (i = 0U; i < ARRAY_SIZE(handler); i++) { if (sigid == handler[i].sig_id) { handler[i].func(session, buf, msgtype, tid); @@ -1010,22 +1018,35 @@ int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) return 0; } +static const struct bt_l2cap_chan_ops signal_chan_ops = { + .connected = bt_avdtp_l2cap_connected, + .disconnected = bt_avdtp_l2cap_disconnected, + .recv = bt_avdtp_l2cap_recv, +}; + /*A2DP Layer interface */ int bt_avdtp_connect(struct bt_conn *conn, struct bt_avdtp *session) { - static const struct bt_l2cap_chan_ops ops = {.connected = bt_avdtp_l2cap_connected, - .disconnected = bt_avdtp_l2cap_disconnected, - .encrypt_change = - bt_avdtp_l2cap_encrypt_changed, - .recv = bt_avdtp_l2cap_recv}; - if (!session) { return -EINVAL; } - session->signalling_l2cap_connected = 1; + /* there are headsets that initiate the AVDTP signal l2cap connection + * at the same time when DUT initiates the same l2cap connection. + * Use the `conn` to check whether the l2cap creation is already started. + * The whole `session` is cleared by upper layer if it is new l2cap connection. + */ + k_sem_take(&avdtp_sem_lock, K_FOREVER); + if (session->br_chan.chan.conn != NULL) { + k_sem_give(&avdtp_sem_lock); + return -ENOMEM; + } + session->br_chan.chan.conn = conn; + k_sem_give(&avdtp_sem_lock); + /* Locking semaphore initialized to 1 (unlocked) */ + k_sem_init(&session->sem_lock, 1, 1); session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; - session->br_chan.chan.ops = &ops; + session->br_chan.chan.ops = &signal_chan_ops; session->br_chan.required_sec_level = BT_SECURITY_L2; return bt_l2cap_chan_connect(conn, &session->br_chan.chan, BT_L2CAP_PSM_AVDTP); @@ -1039,7 +1060,6 @@ int bt_avdtp_disconnect(struct bt_avdtp *session) LOG_DBG("session %p", session); - session->signalling_l2cap_connected = 0; return bt_l2cap_chan_disconnect(&session->br_chan.chan); } @@ -1056,29 +1076,32 @@ int bt_avdtp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server, return result; } - if (session->signalling_l2cap_connected == 0) { - static const struct bt_l2cap_chan_ops ops = { - .connected = bt_avdtp_l2cap_connected, - .disconnected = bt_avdtp_l2cap_disconnected, - .recv = bt_avdtp_l2cap_recv, - }; - session->signalling_l2cap_connected = 1; - session->br_chan.chan.ops = &ops; + /* there are headsets that initiate the AVDTP signal l2cap connection + * at the same time when DUT initiates the same l2cap connection. + * Use the `conn` to check whether the l2cap creation is already started. + * The whole `session` is cleared by upper layer if it is new l2cap connection. + */ + k_sem_take(&avdtp_sem_lock, K_FOREVER); + if (session->br_chan.chan.conn == NULL) { + session->br_chan.chan.conn = conn; + k_sem_give(&avdtp_sem_lock); + /* Locking semaphore initialized to 1 (unlocked) */ + k_sem_init(&session->sem_lock, 1, 1); + session->br_chan.chan.ops = &signal_chan_ops; session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; *chan = &session->br_chan.chan; } else { + k_sem_give(&avdtp_sem_lock); /* get the current opening endpoint */ if (session->current_sep != NULL) { - static const struct bt_l2cap_chan_ops ops = { - .connected = bt_avdtp_media_l2cap_connected, - .disconnected = bt_avdtp_media_l2cap_disconnected, - .recv = bt_avdtp_media_l2cap_recv}; session->current_sep->session = session; - session->current_sep->chan.chan.ops = &ops; + session->current_sep->chan.chan.ops = &stream_chan_ops; session->current_sep->chan.rx.mtu = BT_L2CAP_RX_MTU; session->current_sep->chan.required_sec_level = BT_SECURITY_L2; *chan = &session->current_sep->chan.chan; session->current_sep = NULL; + } else { + return -ENOMEM; } } @@ -1099,7 +1122,7 @@ int bt_avdtp_register(struct bt_avdtp_event_cb *cb) return 0; } -int bt_avdtp_register_sep(uint8_t media_type, uint8_t role, struct bt_avdtp_sep *sep) +int bt_avdtp_register_sep(uint8_t media_type, uint8_t sep_type, struct bt_avdtp_sep *sep) { LOG_DBG(""); @@ -1113,13 +1136,18 @@ int bt_avdtp_register_sep(uint8_t media_type, uint8_t role, struct bt_avdtp_sep return -EIO; } + k_sem_take(&avdtp_sem_lock, K_FOREVER); + /* the id allocation need be locked to protect it */ sep->sep_info.id = bt_avdtp_sep++; sep->sep_info.inuse = 0U; sep->sep_info.media_type = media_type; - sep->sep_info.tsep = role; - sep->state = AVDTP_IDLE; + sep->sep_info.tsep = sep_type; + /* Locking semaphore initialized to 1 (unlocked) */ + k_sem_init(&sep->sem_lock, 1, 1); + bt_avdtp_set_state_lock(sep, AVDTP_IDLE); sys_slist_append(&seps, &sep->_node); + k_sem_give(&avdtp_sem_lock); return 0; } @@ -1203,7 +1231,7 @@ int bt_avdtp_get_capabilities(struct bt_avdtp *session, } /* Body of the message */ - net_buf_add_u8(buf, (param->stream_endpoint_id << 2u)); + net_buf_add_u8(buf, (param->stream_endpoint_id << 2U)); return avdtp_send(session, buf, ¶m->req); } @@ -1229,22 +1257,21 @@ int bt_avdtp_parse_capability_codec(struct net_buf *buf, uint8_t *codec_type, case BT_AVDTP_SERVICE_HEADER_COMPRESSION: case BT_AVDTP_SERVICE_MULTIPLEXING: case BT_AVDTP_SERVICE_DELAY_REPORTING: - if (buf->len < 1) { + if (buf->len < 1U) { return -EINVAL; } length = net_buf_pull_u8(buf); - if (buf->len < length) { - return -EINVAL; - } - if (length > 0) { + if (buf->len < length) { + return -EINVAL; + } net_buf_pull_mem(buf, length); } break; case BT_AVDTP_SERVICE_MEDIA_CODEC: - if (buf->len < 1) { + if (buf->len < 1U) { return -EINVAL; } @@ -1270,7 +1297,7 @@ int bt_avdtp_parse_capability_codec(struct net_buf *buf, uint8_t *codec_type, break; } } - return -EIO; + return -EINVAL; } static int avdtp_process_configure_command(struct bt_avdtp *session, uint8_t cmd, @@ -1292,9 +1319,9 @@ static int avdtp_process_configure_command(struct bt_avdtp *session, uint8_t cmd /* Body of the message */ /* ACP Stream Endpoint ID */ - net_buf_add_u8(buf, (param->acp_stream_ep_id << 2u)); + net_buf_add_u8(buf, (param->acp_stream_ep_id << 2U)); /* INT Stream Endpoint ID */ - net_buf_add_u8(buf, (param->int_stream_endpoint_id << 2u)); + net_buf_add_u8(buf, (param->int_stream_endpoint_id << 2U)); /* Service Category: Media Transport */ net_buf_add_u8(buf, BT_AVDTP_SERVICE_MEDIA_TRANSPORT); /* LOSC */ @@ -1342,7 +1369,8 @@ int bt_avdtp_reconfigure(struct bt_avdtp *session, struct bt_avdtp_set_configura return avdtp_process_configure_command(session, BT_AVDTP_RECONFIGURE, param); } -int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_open_params *param) +static int bt_avdtp_ctrl(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param, uint8_t ctrl, + uint8_t check_state) { struct net_buf *buf; @@ -1352,11 +1380,11 @@ int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_open_params *param) return -EINVAL; } - if (param->sep->state != AVDTP_CONFIGURED) { + if (!(param->sep->state & check_state)) { return -EINVAL; } - buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_OPEN); + buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, ctrl); if (!buf) { LOG_ERR("Error: No Buff available"); return -ENOMEM; @@ -1364,43 +1392,33 @@ int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_open_params *param) /* Body of the message */ /* ACP Stream Endpoint ID */ - net_buf_add_u8(buf, (param->acp_stream_ep_id << 2u)); + net_buf_add_u8(buf, (param->acp_stream_ep_id << 2U)); return avdtp_send(session, buf, ¶m->req); } -int bt_avdtp_start(struct bt_avdtp *session, struct bt_avdtp_start_params *param) +int bt_avdtp_open(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param) { - struct net_buf *buf; - - LOG_DBG(""); - if (!param || !session || !param->sep) { - LOG_DBG("Error: parameters not valid"); - return -EINVAL; - } + return bt_avdtp_ctrl(session, param, BT_AVDTP_OPEN, AVDTP_CONFIGURED); +} - if (param->sep->state != AVDTP_OPEN) { - return -EINVAL; - } +int bt_avdtp_start(struct bt_avdtp *session, struct bt_avdtp_ctrl_params *param) +{ + int err; - buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_START); - if (!buf) { - LOG_ERR("Error: No Buff available"); - return -ENOMEM; + err = bt_avdtp_ctrl(session, param, BT_AVDTP_START, AVDTP_OPEN); + if (!err && param->sep->sep_info.tsep == BT_AVDTP_SINK) { + bt_avdtp_set_state_lock(param->sep, AVDTP_STREAMING); } - /* Body of the message */ - /* ACP Stream Endpoint ID */ - net_buf_add_u8(buf, (param->acp_stream_ep_id << 2u)); - - return avdtp_send(session, buf, ¶m->req); + return err; } int bt_avdtp_send_media_data(struct bt_avdtp_sep *sep, struct net_buf *buf) { int err; - if (sep->state != AVDTP_STREAMING) { + if (sep->state != AVDTP_STREAMING || sep->sep_info.tsep != BT_AVDTP_SOURCE) { return -EIO; } diff --git a/subsys/bluetooth/host/classic/avdtp_internal.h b/subsys/bluetooth/host/classic/avdtp_internal.h index d4bb9c63fe22a..af1cc364ad391 100644 --- a/subsys/bluetooth/host/classic/avdtp_internal.h +++ b/subsys/bluetooth/host/classic/avdtp_internal.h @@ -86,6 +86,8 @@ #define BT_AVDTP_MIN_SEID 0x01 #define BT_AVDTP_MAX_SEID 0x3E +#define BT_AVDTP_RTP_VERSION 2 + struct bt_avdtp; struct bt_avdtp_req; struct bt_avdtp_sep_info; @@ -114,6 +116,7 @@ typedef int (*bt_avdtp_func_t)(struct bt_avdtp_req *req); struct bt_avdtp_req { uint8_t sig; uint8_t tid; + uint8_t status; bt_avdtp_func_t func; }; @@ -145,13 +148,11 @@ struct bt_avdtp_media_hdr { struct bt_avdtp_discover_params { struct bt_avdtp_req req; - uint8_t status; struct net_buf *buf; }; struct bt_avdtp_get_capabilities_params { struct bt_avdtp_req req; - uint8_t status; uint8_t stream_endpoint_id; struct net_buf *buf; }; @@ -159,7 +160,6 @@ struct bt_avdtp_get_capabilities_params { struct bt_avdtp_set_configuration_params { struct bt_avdtp_req req; struct bt_avdtp_sep *sep; - uint8_t status; uint8_t acp_stream_ep_id; uint8_t int_stream_endpoint_id; uint8_t media_type; @@ -168,17 +168,10 @@ struct bt_avdtp_set_configuration_params { uint8_t *codec_specific_ie; }; -struct bt_avdtp_open_params { +/* avdtp_open, avdtp_close, avdtp_start, avdtp_suspend */ +struct bt_avdtp_ctrl_params { struct bt_avdtp_req req; struct bt_avdtp_sep *sep; - uint8_t status; - uint8_t acp_stream_ep_id; -}; - -struct bt_avdtp_start_params { - struct bt_avdtp_req req; - struct bt_avdtp_sep *sep; - uint8_t status; uint8_t acp_stream_ep_id; }; @@ -197,6 +190,9 @@ struct bt_avdtp_ops_cb { int (*set_configuration_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t int_seid, struct net_buf *buf, uint8_t *errcode); + int (*re_configuration_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, + uint8_t int_seid, struct net_buf *buf, uint8_t *errcode); + int (*open_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode); int (*close_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode); @@ -215,7 +211,8 @@ struct bt_avdtp { const struct bt_avdtp_ops_cb *ops; struct bt_avdtp_sep *current_sep; struct k_work_delayable timeout_work; - uint8_t signalling_l2cap_connected; + /* semaphore for lock/unlock */ + struct k_sem sem_lock; }; struct bt_avdtp_event_cb { From a51a0e1d077abbe819e38336f0228a0558c7cf00 Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Sun, 29 Sep 2024 11:38:37 +0800 Subject: [PATCH 3/4] Bluetooth: A2DP: implement close, suspend and abort implement avdtp close, suspend and abort and the a2dp interfaces. Signed-off-by: Mark Wang --- include/zephyr/bluetooth/classic/a2dp.h | 42 ++++ subsys/bluetooth/host/classic/a2dp.c | 132 ++++++++++++ subsys/bluetooth/host/classic/avdtp.c | 188 ++++++++++++++++-- .../bluetooth/host/classic/avdtp_internal.h | 12 ++ 4 files changed, 353 insertions(+), 21 deletions(-) diff --git a/include/zephyr/bluetooth/classic/a2dp.h b/include/zephyr/bluetooth/classic/a2dp.h index e2fd27b743e53..95b1899cebc92 100644 --- a/include/zephyr/bluetooth/classic/a2dp.h +++ b/include/zephyr/bluetooth/classic/a2dp.h @@ -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. diff --git a/subsys/bluetooth/host/classic/a2dp.c b/subsys/bluetooth/host/classic/a2dp.c index 9cfb4f1622984..4fdbbb8b76688 100644 --- a/subsys/bluetooth/host/classic/a2dp.c +++ b/subsys/bluetooth/host/classic/a2dp.c @@ -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) diff --git a/subsys/bluetooth/host/classic/avdtp.c b/subsys/bluetooth/host/classic/avdtp.c index d137a6218c6c7..237568d5e916f 100644 --- a/subsys/bluetooth/host/classic/avdtp.c +++ b/subsys/bluetooth/host/classic/avdtp.c @@ -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; diff --git a/subsys/bluetooth/host/classic/avdtp_internal.h b/subsys/bluetooth/host/classic/avdtp_internal.h index af1cc364ad391..86b3c7a2bc741 100644 --- a/subsys/bluetooth/host/classic/avdtp_internal.h +++ b/subsys/bluetooth/host/classic/avdtp_internal.h @@ -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); From dc179c001dddd69fc30488c54493e0e7ff190e21 Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Sun, 29 Sep 2024 11:39:16 +0800 Subject: [PATCH 4/4] tests: bluetooth: shell: add a2dp new features test add test for reconfigure, release, suspend, abort and disconnect. app_config_req and app_reconfig_req always accept the req, so don't need to handle reject case. Signed-off-by: Mark Wang --- .../bluetooth/shell/classic/a2dp.rst | 15 +- subsys/bluetooth/host/classic/shell/a2dp.c | 158 +++++++++++++++--- 2 files changed, 148 insertions(+), 25 deletions(-) diff --git a/doc/connectivity/bluetooth/shell/classic/a2dp.rst b/doc/connectivity/bluetooth/shell/classic/a2dp.rst index 2895b41b23349..503214445ce75 100644 --- a/doc/connectivity/bluetooth/shell/classic/a2dp.rst +++ b/doc/connectivity/bluetooth/shell/classic/a2dp.rst @@ -14,6 +14,8 @@ Here is a example connecting two devices: * Source or Sink establish the stream. using :code:`a2dp establish`. * Source or Sink start the media. using :code:`a2dp start`. * Source test the media sending. using :code:`a2dp send_media` to send one test packet data. + * Source or Sink suspend the media. using :code:`a2dp suspend`. + * Source or Sink release the media. using :code:`a2dp release`. .. tabs:: @@ -58,6 +60,12 @@ Here is a example connecting two devices: uart:~$ a2dp send_media frames num: 1, data length: 160 data: 1, 2, 3, 4, 5, 6 ...... + uart:~$ a2dp suspend + success to suspend + stream suspended + uart:~$ a2dp release + success to release + stream released .. group-tab:: Device B (Audio Sink Side) @@ -74,7 +82,6 @@ Here is a example connecting two devices: a2dp connected receive requesting config and accept - SBC configure success sample rate 44100Hz stream configured @@ -86,4 +93,10 @@ Here is a example connecting two devices: received, num of frames: 1, data length: 160 data: 1, 2, 3, 4, 5, 6 ...... + + receive requesting suspend and accept + stream suspended + + receive requesting release and accept + stream released ... diff --git a/subsys/bluetooth/host/classic/shell/a2dp.c b/subsys/bluetooth/host/classic/shell/a2dp.c index f8e363a417787..2e8ffc5a08ccb 100644 --- a/subsys/bluetooth/host/classic/shell/a2dp.c +++ b/subsys/bluetooth/host/classic/shell/a2dp.c @@ -98,7 +98,7 @@ static struct bt_sdp_attribute a2dp_sink_attrs[] = { }, { BT_SDP_TYPE_SIZE(BT_SDP_UINT16), /* 09 */ - BT_SDP_ARRAY_16(0X0100u) /* AVDTP version: 01 00 */ + BT_SDP_ARRAY_16(0x0100U) /* AVDTP version: 01 00 */ }, ) }, @@ -167,7 +167,7 @@ static struct bt_sdp_attribute a2dp_source_attrs[] = { }, { BT_SDP_TYPE_SIZE(BT_SDP_UINT16), - BT_SDP_ARRAY_16(0X0100u) + BT_SDP_ARRAY_16(0x0100U) }, ) }, @@ -306,21 +306,31 @@ 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) { + uint32_t sample_rate; + 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; + 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); + + return 0; +} + +int app_reconfig_req(struct bt_a2dp_stream *stream, + struct bt_a2dp_codec_cfg *codec_cfg, uint8_t *rsp_err_code) +{ + uint32_t sample_rate; + + *rsp_err_code = 0; + shell_print(ctx_shell, "receive requesting reconfig and accept"); + 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); - 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; } @@ -349,6 +359,22 @@ void app_establish_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code) } } +int app_release_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code) +{ + *rsp_err_code = 0; + shell_print(ctx_shell, "receive requesting release and accept"); + return 0; +} + +void app_release_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code) +{ + if (rsp_err_code == 0) { + shell_print(ctx_shell, "success to release"); + } else { + shell_print(ctx_shell, "fail to release"); + } +} + int app_start_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code) { *rsp_err_code = 0; @@ -365,6 +391,22 @@ void app_start_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code) } } +int app_suspend_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code) +{ + *rsp_err_code = 0; + shell_print(ctx_shell, "receive requesting suspend and accept"); + return 0; +} + +void app_suspend_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code) +{ + if (rsp_err_code == 0) { + shell_print(ctx_shell, "success to suspend"); + } else { + shell_print(ctx_shell, "fail to suspend"); + } +} + void stream_configured(struct bt_a2dp_stream *stream) { shell_print(ctx_shell, "stream configured"); @@ -385,11 +427,24 @@ void stream_started(struct bt_a2dp_stream *stream) shell_print(ctx_shell, "stream started"); } +void stream_suspended(struct bt_a2dp_stream *stream) +{ + shell_print(ctx_shell, "stream suspended"); +} + +void stream_aborted(struct bt_a2dp_stream *stream) +{ + shell_print(ctx_shell, "stream aborted"); +} + 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; + if (buf->len < 1U) { + return; + } 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); @@ -410,14 +465,13 @@ struct bt_a2dp_cb a2dp_cb = { .config_rsp = app_config_rsp, .establish_req = app_establish_req, .establish_rsp = app_establish_rsp, - .release_req = NULL, - .release_rsp = NULL, + .release_req = app_release_req, + .release_rsp = app_release_rsp, .start_req = app_start_req, .start_rsp = app_start_rsp, - .suspend_req = NULL, - .suspend_rsp = NULL, - .reconfig_req = NULL, - .reconfig_rsp = NULL, + .suspend_req = app_suspend_req, + .suspend_rsp = app_suspend_rsp, + .reconfig_req = app_reconfig_req, }; static int cmd_register_cb(const struct shell *sh, int32_t argc, char *argv[]) @@ -539,8 +593,8 @@ static struct bt_a2dp_stream_ops stream_ops = { .established = stream_established, .released = stream_released, .started = stream_started, - .suspended = NULL, - .reconfigured = NULL, + .suspended = stream_suspended, + .aborted = stream_aborted, #if defined(CONFIG_BT_A2DP_SINK) .recv = stream_recv, #endif @@ -584,6 +638,19 @@ static int cmd_configure(const struct shell *sh, int32_t argc, char *argv[]) return 0; } +static int cmd_reconfigure(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_reconfig(&sbc_stream, &sbc_cfg_default) != 0) { + shell_print(sh, "fail"); + } + 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) { @@ -639,6 +706,19 @@ static int cmd_establish(const struct shell *sh, int32_t argc, char *argv[]) return 0; } +static int cmd_release(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_release(&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) { @@ -652,6 +732,32 @@ static int cmd_start(const struct shell *sh, int32_t argc, char *argv[]) return 0; } +static int cmd_suspend(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_suspend(&sbc_stream) != 0) { + shell_print(sh, "fail"); + } + return 0; +} + +static int cmd_abort(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_abort(&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) @@ -669,11 +775,11 @@ static int cmd_send_media(const struct shell *sh, int32_t argc, char *argv[]) /* 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, "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); + 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); @@ -692,9 +798,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(a2dp_cmds, 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(configure, NULL, "\"configure/enable the stream\"", cmd_configure, 1, 0), + SHELL_CMD_ARG(establish, NULL, "\"establish the stream\"", cmd_establish, 1, 0), + SHELL_CMD_ARG(reconfigure, NULL, "\"reconfigure the stream\"", cmd_reconfigure, 1, 0), + SHELL_CMD_ARG(release, NULL, "\"release the stream\"", cmd_release, 1, 0), + SHELL_CMD_ARG(start, NULL, "\"start the stream\"", cmd_start, 1, 0), + SHELL_CMD_ARG(suspend, NULL, "\"suspend the stream\"", cmd_suspend, 1, 0), + SHELL_CMD_ARG(abort, NULL, "\"abort the stream\"", cmd_abort, 1, 0), SHELL_CMD_ARG(send_media, NULL, HELP_NONE, cmd_send_media, 1, 0), SHELL_SUBCMD_SET_END );