diff --git a/include/zephyr/bluetooth/classic/a2dp.h b/include/zephyr/bluetooth/classic/a2dp.h index ae276caa8d0..303f61a17c7 100644 --- a/include/zephyr/bluetooth/classic/a2dp.h +++ b/include/zephyr/bluetooth/classic/a2dp.h @@ -21,43 +21,42 @@ 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. * @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 @@ -295,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 */ @@ -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 */ @@ -386,7 +405,7 @@ struct bt_a2dp_cb { * @param a2dp a2dp connection object. * @param err error code. */ - void (*connected)(struct bt_a2dp *a2dp, int err); + void (*connected)(struct bt_conn* conn, struct bt_a2dp *a2dp, int err); /** @brief A a2dp connection has been disconnected. * * This callback notifies the application that a a2dp connection @@ -411,9 +430,23 @@ 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); - /** @brief Callback function for bt_a2dp_stream_config() + struct bt_a2dp_codec_cfg *codec_cfg, 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, 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. * @@ -423,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). @@ -446,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) @@ -469,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. @@ -491,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. @@ -513,10 +546,10 @@ struct bt_a2dp_cb { */ void (*suspend_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); /** - * @brief Endpoint config request callback + * @brief Stream abort request callback * - * The callback is called whenever an endpoint is requested to be - * reconfigured. + * 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. @@ -524,16 +557,16 @@ struct bt_a2dp_cb { * * @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() + int (*abort_req)(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code); + /** @brief Callback function for bt_a2dp_stream_abort() * - * Called when the reconfig operation is completed. + * 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 (*reconfig_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); + void (*abort_rsp)(struct bt_a2dp_stream *stream, uint8_t rsp_err_code); }; /** @brief A2DP Connect. @@ -566,12 +599,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. * @@ -613,7 +646,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. */ @@ -630,6 +663,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. */ @@ -651,13 +685,14 @@ struct bt_a2dp_stream_ops { */ void (*suspended)(struct bt_a2dp_stream *stream); /** - * @brief Stream reconfigured callback + * @brief Stream abort callback * - * The callback is called whenever an Audio Stream has been reconfigured. + * The callback is called whenever an Audio Stream has been aborted. + * After aborted, the stream becomes invalid. * - * @param stream Stream object that has been reconfigured. + * @param stream Stream object that has been aborted. */ - void (*reconfigured)(struct bt_a2dp_stream *stream); + void (*aborted)(struct bt_a2dp_stream *stream); #if defined(CONFIG_BT_A2DP_SINK) /** @brief the media streaming data, only for sink * @@ -665,8 +700,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 +746,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. * @@ -727,6 +762,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. * @@ -765,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. @@ -785,8 +832,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 cfd41923978..dd7307ae374 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,9 @@ 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); + /* semaphore for lock/unlock */ + struct k_sem sem_lock; /** avdtp session */ struct bt_avdtp *session; /** SEP state */ diff --git a/include/zephyr/bluetooth/zephyr3/a2dp-codec.h b/include/zephyr/bluetooth/zephyr3/a2dp-codec.h deleted file mode 100644 index 611c61ba5e0..00000000000 --- a/include/zephyr/bluetooth/zephyr3/a2dp-codec.h +++ /dev/null @@ -1,123 +0,0 @@ -/** @file - * @brief Advance Audio Distribution Profile - SBC Codec header. - */ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) 2015-2016 Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_A2DP_CODEC_H_ -#define ZEPHYR_INCLUDE_BLUETOOTH_A2DP_CODEC_H_ -#ifdef __cplusplus -extern "C" { -#endif -/** @brief A2dp connect channel Role */ -enum A2DP_ROLE_TYPE { - /** Unkown role */ - BT_A2DP_CH_UNKOWN = 0x00, - /** Source Role */ - BT_A2DP_CH_SOURCE = 0x01, - /** Sink Role */ - BT_A2DP_CH_SINK = 0x02, - /** For a2dp media session connect */ - BT_A2DP_CH_MEDIA = 0x03 -}; -/** @brief Stream End Point Media Type */ -enum MEDIA_TYPE { - /** Audio Media Type */ - BT_A2DP_AUDIO = 0x00, - /** Video Media Type */ - BT_A2DP_VIDEO = 0x01, - /** Multimedia Media Type */ - BT_A2DP_MULTIMEDIA = 0x02 -}; -/** @brief Stream End Point Role */ -enum A2DP_EP_ROLE_TYPE { - /** Source Role */ - BT_A2DP_EP_SOURCE = 0x00, - /** Sink Role */ - BT_A2DP_EP_SINK = 0x01 -}; -/** @brief Codec ID */ -enum bt_a2dp_codec_id { - /** Codec SBC */ - BT_A2DP_SBC = 0x00, - /** Codec MPEG-1 */ - BT_A2DP_MPEG1 = 0x01, - /** Codec MPEG-2 */ - BT_A2DP_MPEG2 = 0x02, - /** Codec ATRAC */ - BT_A2DP_ATRAC = 0x04, - /** Codec Non-A2DP */ - BT_A2DP_VENDOR = 0xff -}; -enum{ - BT_A2DP_SBC_48000 = 1, - BT_A2DP_SBC_44100 = 2, - BT_A2DP_SBC_32000 = 4, - BT_A2DP_SBC_16000 = 8, - BT_A2DP_SBC_FREQ_MASK = 0xF, -}; -enum{ - BT_A2DP_SBC_JOINT_STEREO = 1, - BT_A2DP_SBC_STEREO = 2, - BT_A2DP_SBC_DUAL_CHANNEL = 4, - BT_A2DP_SBC_MONO = 8, - BT_A2DP_SBC_CHANNEL_MODE_MASK = 0xF, -}; -enum{ - BT_A2DP_SBC_BLOCK_LENGTH_16 = 1, - BT_A2DP_SBC_BLOCK_LENGTH_12 = 2, - BT_A2DP_SBC_BLOCK_LENGTH_8 = 4, - BT_A2DP_SBC_BLOCK_LENGTH_4 = 8, - BT_A2DP_SBC_BLOCK_LENGTH_MASK = 0xF, -}; -enum{ - BT_A2DP_SBC_SUBBANDS_8 = 1, - BT_A2DP_SBC_SUBBANDS_4 = 2, - BT_A2DP_SBC_SUBBANDS_MASK = 0x3, -}; -enum{ - BT_A2DP_SBC_ALLOCATION_METHOD_LOUDNESS = 1, - BT_A2DP_SBC_ALLOCATION_METHOD_SNR = 2, - BT_A2DP_SBC_ALLOCATION_METHOD_MASK = 0x3, -}; -enum{ - BT_A2DP_AAC_OBJ_MPEG2_AAC_LC = (0x1 << 7), - BT_A2DP_AAC_OBJ_MPEG4_AAC_LC = (0x1 << 6), - BT_A2DP_AAC_OBJ_MPEG4_AAC_LTP = (0x1 << 5), - BT_A2DP_AAC_OBJ_MPEG4_AAC_SCALABLE = (0x1 << 4), -}; -enum{ - BT_A2DP_AAC_8000 = (0x1 << 11), - BT_A2DP_AAC_11025 = (0x1 << 10), - BT_A2DP_AAC_12000 = (0x1 << 9), - BT_A2DP_AAC_16000 = (0x1 << 8), - BT_A2DP_AAC_22050 = (0x1 << 7), - BT_A2DP_AAC_24000 = (0x1 << 6), - BT_A2DP_AAC_32000 = (0x1 << 5), - BT_A2DP_AAC_44100 = (0x1 << 4), - BT_A2DP_AAC_48000 = (0x1 << 3), - BT_A2DP_AAC_64000 = (0x1 << 2), - BT_A2DP_AAC_88200 = (0x1 << 1), - BT_A2DP_AAC_96000 = (0x1 << 0), -}; -enum { - BT_A2DP_AAC_CHANNELS_1 = (0x1 << 1), - BT_A2DP_AAC_CHANNELS_2 = (0x1 << 0), -}; -#ifdef __cplusplus -} -#endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_A2DP_CODEC_H_ */ \ No newline at end of file diff --git a/include/zephyr/bluetooth/zephyr3/a2dp.h b/include/zephyr/bluetooth/zephyr3/a2dp.h deleted file mode 100644 index a026ee05afc..00000000000 --- a/include/zephyr/bluetooth/zephyr3/a2dp.h +++ /dev/null @@ -1,113 +0,0 @@ -/** @file - * @brief Advance Audio Distribution Profile header. - */ -/* - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_A2DP_H_ -#define ZEPHYR_INCLUDE_BLUETOOTH_A2DP_H_ -#include -#include -#include -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Stream End Point */ -struct bt_a2dp_endpoint { - /** Stream End Point Information */ - struct bt_avdtp_seid_lsep info; -}; -enum { - BT_A2DP_MEDIA_STATE_OPEN = 0x06, - BT_A2DP_MEDIA_STATE_START = 0x07, - BT_A2DP_MEDIA_STATE_CLOSE = 0x08, - BT_A2DP_MEDIA_STATE_SUSPEND = 0x09, - BT_A2DP_MEDIA_STATE_PENDING_AHEAD_START = 0x80, -}; -struct bt_a2dp_app_cb { - void (*connected)(struct bt_conn *conn); - void (*disconnected)(struct bt_conn *conn); - void (*media_handler)(struct bt_conn *conn, uint8_t *data, uint16_t len); - /* Return 0: accepte state request, other: reject state request */ - int (*media_state_req)(struct bt_conn *conn, uint8_t state); - void (*seted_codec)(struct bt_conn *conn, struct bt_a2dp_media_codec *codec, uint8_t cp_type); -}; -/** @brief A2DP Connect. - * - * This function is to be called after the conn parameter is obtained by - * performing a GAP procedure. The API is to be used to establish A2DP - * connection between devices. - * - * @param conn Pointer to bt_conn structure. - * @param role a2dp as source or sink role - * - * @return 0 in case of success and error code in case of error. - * of error. - */ -int bt_a2dp_connect(struct bt_conn *conn, uint8_t role); -/* Disconnect a2dp session */ -int bt_a2dp_disconnect(struct bt_conn *conn); -/** @brief Endpoint Registration. - * - * This function is used for registering the stream end points. The user has - * to take care of allocating the memory, the preset pointer and then pass the - * required arguments. Also, only one sep can be registered at a time. - * - * @param endpoint Pointer to bt_a2dp_endpoint structure. - * @param media_type Media type that the Endpoint is. - * @param role Role of Endpoint. - * - * @return 0 in case of success and error code in case of error. - */ -int bt_a2dp_register_endpoint(struct bt_a2dp_endpoint *endpoint, - uint8_t media_type, uint8_t role); -/** @brief halt/resume registed endpoint. - * - * This function is used for halt/resume registed endpoint - * - * @param endpoint Pointer to bt_a2dp_endpoint structure. - * @param halt true: halt , false: resume; - * - * @return 0 in case of success and error code in case of error. - */ -int bt_a2dp_halt_endpoint(struct bt_a2dp_endpoint *endpoint, bool halt); -/* Register app callback */ -int bt_a2dp_register_cb(struct bt_a2dp_app_cb *cb); -/* Start a2dp play */ -int bt_a2dp_start(struct bt_conn *conn); -/* Suspend a2dp play */ -int bt_a2dp_suspend(struct bt_conn *conn); -/* Reconfig a2dp codec config */ -int bt_a2dp_reconfig(struct bt_conn *conn, struct bt_a2dp_media_codec *codec); -/* Send delay report to source */ -int bt_a2dp_send_delay_report(struct bt_conn *conn, uint16_t delay_time); -/* Send a2dp audio data */ -int bt_a2dp_send_audio_data(struct bt_conn *conn, uint8_t *data, uint16_t len); -/* Get a2dp seted codec */ -struct bt_a2dp_media_codec *bt_a2dp_get_seted_codec(struct bt_conn *conn); -/* Get a2dp role(source or sink) */ -uint8_t bt_a2dp_get_a2dp_role(struct bt_conn *conn); -/* Get a2dp media tx mtu */ -uint16_t bt_a2dp_get_a2dp_media_tx_mtu(struct bt_conn *conn); -/* Send a2dp audio data with callback */ -int bt_a2dp_send_audio_data_with_cb(struct bt_conn *conn, uint8_t *data, uint16_t len, - void (*cb)(struct bt_conn *, void *)); -/* Start a2dp discover */ -int bt_a2dp_discover(struct bt_conn *conn, uint8_t role); -/* A2dp pts interface */ -int bt_pts_a2dp_discover(struct bt_conn *conn); -int bt_pts_a2dp_get_capabilities(struct bt_conn *conn); -int bt_pts_a2dp_get_all_capabilities(struct bt_conn *conn); -int bt_pts_a2dp_set_configuration(struct bt_conn *conn); -int bt_pts_a2dp_open(struct bt_conn *conn); -int bt_pts_a2dp_close(struct bt_conn *conn); -int bt_pts_a2dp_abort(struct bt_conn *conn); -int bt_pts_a2dp_disconnect_media_session(struct bt_conn *conn); -void bt_pts_a2dp_set_err_code(uint8_t err_code); -#ifdef __cplusplus -} -#endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_A2DP_H_ */ \ No newline at end of file diff --git a/include/zephyr/bluetooth/zephyr3/avdtp.h b/include/zephyr/bluetooth/zephyr3/avdtp.h deleted file mode 100644 index 7c65ca61a9d..00000000000 --- a/include/zephyr/bluetooth/zephyr3/avdtp.h +++ /dev/null @@ -1,132 +0,0 @@ -/** @file - * @brief Audio/Video Distribution Transport Protocol header. - */ -/* - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AVDTP_H_ -#define ZEPHYR_INCLUDE_BLUETOOTH_AVDTP_H_ -#include -#ifdef __cplusplus -extern "C" { -#endif -enum { - BT_AVDTP_SIGNALING_SESSION = 0x0, - BT_AVDTP_MEDIA_SESSION = 0x1, - BT_AVDTP_REPORTING_SESSION = 0x2, - BT_AVDTP_RECOVERY_SESSION = 0x3, - BT_AVDTP_MAX_SESSION = 4, -}; -enum { - BT_AVDTP_MEDIA_TYPE_AUDIO = 0, - BT_AVDTP_MEDIA_TYPE_VIDEO, - BT_AVDTP_MEDIA_TYPE_MULTIMEDIA, -}; -enum { - BT_AVDTP_AV_CP_TYPE_NONE = 0, - BT_AVDTP_AV_CP_TYPE_DTCP = 1, - BT_AVDTP_AV_CP_TYPE_SCMS_T = 2, -}; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -/** @brief AVDTP SEID Information */ -struct bt_avdtp_seid_info { - /** Reserved */ - uint8_t rfa0:1; - /** End Point usage status */ - uint8_t inuse:1; - /** Stream End Point ID */ - uint8_t id:6; - /** Reserved */ - uint8_t rfa1:3; - /** TSEP of the End Point */ - uint8_t tsep:1; - /** Media-type of the End Point */ - uint8_t media_type:4; -} __packed; -struct bt_a2dp_media_codec_head { - uint8_t rfa0:4; - uint8_t media_type:4; - uint8_t codec_type; -} __packed; -struct bt_a2dp_media_sbc_codec { - uint8_t rfa0:4; - uint8_t media_type:4; - uint8_t codec_type; - uint8_t channel_mode:4; - uint8_t freq:4; - uint8_t alloc_method:2; - uint8_t subbands:2; - uint8_t block_len:4; - uint8_t min_bitpool; - uint8_t max_bitpool; -} __packed; -struct bt_a2dp_media_aac_codec { - uint8_t rfa0:4; - uint8_t media_type:4; - uint8_t codec_type; - uint8_t obj_type; - uint8_t freq0; - uint8_t rfa1:2; - uint8_t channels:2; - uint8_t freq1:4; - uint8_t bit_rate0:7; - uint8_t vbr:1; - uint8_t bit_rate1; - uint8_t bit_rate2; -} __packed; -struct bt_a2dp_media_codec { - union { - struct bt_a2dp_media_codec_head head; - struct bt_a2dp_media_sbc_codec sbc; - struct bt_a2dp_media_aac_codec aac; - }; -}; -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -/** @brief AVDTP SEID Information */ -struct bt_avdtp_seid_info { - /** Stream End Point ID */ - uint8_t id:6; - /** End Point usage status */ - uint8_t inuse:1; - /** Reserved */ - uint8_t rfa0:1; - /** Media-type of the End Point */ - uint8_t media_type:4; - /** TSEP of the End Point */ - uint8_t tsep:1; - /** Reserved */ - uint8_t rfa1:3; -} __packed; -#endif -/** @brief AVDTP Local SEP*/ -struct bt_avdtp_seid_lsep { - /** Stream End Point information */ - struct bt_avdtp_seid_info sid; - /** Pointer to media codec */ - struct bt_a2dp_media_codec *codec; - /** Content protection: support SCMS-T */ - uint8_t a2dp_cp_scms_t:1; - /** A2dp delay report */ - uint8_t a2dp_delay_report:1; - /** For upper layer halt/resume register endpoint */ - uint8_t ep_halt:1; - /** Pointer to next local Stream End Point structure */ - struct bt_avdtp_seid_lsep *next; -}; -/** @brief AVDTP Stream */ -struct bt_avdtp_stream { - struct bt_avdtp_seid_info lsid; /* Configured Local sep info */ - struct bt_avdtp_seid_info rsid; /* Configured Remote sep info*/ - struct bt_a2dp_media_codec codec; /* Codec config */ - uint8_t cp_type; /* Content protection type */ - uint8_t delay_report:1; /* Support delay report */ - uint8_t stream_state; /* current state of the stream */ - uint8_t acp_state; /* Device as acp state */ - uint8_t int_state; /* Device as int state */ -}; -#ifdef __cplusplus -} -#endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AVDTP_H_ */ \ No newline at end of file diff --git a/subsys/bluetooth/host/classic/a2dp.c b/subsys/bluetooth/host/classic/a2dp.c index 5cb5203e6e2..b34736991c6 100644 --- a/subsys/bluetooth/host/classic/a2dp.c +++ b/subsys/bluetooth/host/classic/a2dp.c @@ -25,22 +25,20 @@ #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) -#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 START_PARAM(_start_param) CONTAINER_OF(_start_param, struct bt_a2dp, start_param) +#define SET_CONF_PARAM(_set_conf_param) \ + CONTAINER_OF(_set_conf_param, struct bt_a2dp, set_config_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,63 +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; - - if (!conn) { - LOG_ERR("Invalid Input (err: %d)", -EINVAL); - return NULL; - } + struct bt_a2dp *a2dp = &connection[bt_conn_index(conn)]; - /* 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 (a2dp->session.br_chan.chan.conn == NULL) { + /* Clean the memory area before returning */ + (void)memset(a2dp, 0, sizeof(struct bt_a2dp)); } - - if (free == A2DP_NO_SPACE) { - LOG_DBG("More connection cannot be supported"); - return NULL; - } - - /* Clean the memory area before returning */ - a2dp_reset(&connection[free]); - - return &connection[free]; + return a2dp; } /* The AVDTP L2CAP signal channel established */ @@ -132,7 +94,7 @@ static void a2dp_connected(struct bt_avdtp *session) a2dp->a2dp_state = INTERNAL_STATE_AVDTP_CONNECTED; /* notify a2dp app the connection. */ if ((a2dp_cb != NULL) && (a2dp_cb->connected != NULL)) { - a2dp_cb->connected(a2dp, 0); + a2dp_cb->connected(session->br_chan.chan.conn, a2dp, 0); } } @@ -160,10 +122,11 @@ 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; + __ASSERT(sep, "Invalid sep"); *errcode = 0; /* Service Category: Media Transport */ net_buf_add_u8(rsp_buf, BT_AVDTP_SERVICE_MEDIA_TRANSPORT); @@ -172,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 */ @@ -182,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; @@ -202,12 +169,11 @@ 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; + return -EINVAL; } if (codec_type == BT_A2DP_SBC) { @@ -216,235 +182,211 @@ 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; 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; + 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; + } - 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)); + 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 > 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) -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; 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; 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 -static int a2dp_open_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep, uint8_t *errcode) +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_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->establish_req != NULL)) { + if (req_cb != NULL) { uint8_t rsp_err_code; int err; - err = a2dp_cb->establish_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->established != NULL)) { - stream->ops->established(stream); - } - } - - return (*errcode == 0) ? 0 : -1; -} - -static int a2dp_start_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->start_req != NULL)) { - uint8_t rsp_err_code; - int err; - - err = a2dp_cb->start_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->started != NULL)) { - stream->ops->started(stream); + if (done_cb != NULL) { + done_cb(stream); } } - return (*errcode == 0) ? 0 : -1; + return (*errcode == 0) ? 0 : -EINVAL; } -static int a2dp_close_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->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; - } - } + __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); +} - ops = stream->ops; - if (*errcode == 0) { - if ((ops != NULL) && (stream->ops->released != NULL)) { - stream->ops->released(stream); - } - } +static int a2dp_start_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; - return (*errcode == 0) ? 0 : -1; + __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 a2dp_suspend_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->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 bt_a2dp_open_cb(struct bt_avdtp_req *req) +static int a2dp_close_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); + __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); +} - if ((a2dp_cb != NULL) && (a2dp_cb->establish_rsp != NULL)) { - a2dp_cb->establish_rsp(stream, a2dp->open_param.status); - } +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; - 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->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) @@ -456,18 +398,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; @@ -482,35 +427,37 @@ 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 ((a2dp->discover_cb_param != NULL) && - (a2dp->discover_cb_param->cb != NULL)) { + 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; } 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; } - 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; 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 +494,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); @@ -565,7 +511,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) @@ -574,12 +520,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); @@ -595,11 +541,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 */ @@ -621,32 +564,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; @@ -679,16 +596,32 @@ 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) + 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; } @@ -703,40 +636,95 @@ 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_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; @@ -745,50 +733,116 @@ 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_establish(struct bt_a2dp_stream *stream) +{ + 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_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; + 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_suspend(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_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) { - /* 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); } #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; - 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); @@ -799,6 +853,30 @@ int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf, } #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, @@ -806,17 +884,20 @@ 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, + .abort_ind = a2dp_abort_ind, + .stream_l2cap_disconnected = a2dp_stream_l2cap_disconnected, }; 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; } @@ -857,10 +938,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; } @@ -870,32 +949,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; @@ -903,9 +978,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 c036d00f5e7..fe21e278c30 100644 --- a/subsys/bluetooth/host/classic/avdtp.c +++ b/subsys/bluetooth/host/classic/avdtp.c @@ -30,50 +30,95 @@ 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 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) { 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"); @@ -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); } @@ -102,21 +145,43 @@ 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 *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); } } 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); @@ -124,31 +189,38 @@ 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, - 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 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) { struct net_buf *buf; struct bt_avdtp_single_sig_hdr *hdr; @@ -163,17 +235,33 @@ 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_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) { if (msg_type == BT_AVDTP_CMD) { int err; @@ -187,10 +275,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; } @@ -223,21 +310,17 @@ static void avdtp_discover_handler(struct bt_avdtp *session, } 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) { - 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); } @@ -257,8 +340,20 @@ 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 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) { if (msg_type == BT_AVDTP_CMD) { int err = 0; @@ -266,28 +361,27 @@ static void avdtp_get_capabilities_handler(struct bt_avdtp *session, struct bt_avdtp_sep *sep; uint8_t error_code = 0; - 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 { - 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; } @@ -308,62 +402,78 @@ static void avdtp_get_capabilities_handler(struct bt_avdtp *session, } 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) { - 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); } } } -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, 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; - 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 < 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; } @@ -378,58 +488,59 @@ static void avdtp_process_configuration(struct bt_avdtp *session, 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 < 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); } } } -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); + avdtp_process_configuration(session, buf, msg_type, tid, false); } -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; @@ -443,22 +554,24 @@ 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); + 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, 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; + 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->open_ind == NULL)) { err = -ENOTSUP; } else { @@ -470,11 +583,10 @@ 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) { + avdtp_sep_unlock(sep); return; } @@ -486,39 +598,35 @@ static void avdtp_open_handler(struct bt_avdtp *session, 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)) { + 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; } - } else if (msg_type == BT_AVDTP_REJECT) { - 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); } @@ -526,16 +634,18 @@ 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; + 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->start_ind == NULL)) { err = -ENOTSUP; } else { @@ -547,11 +657,10 @@ 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) { + avdtp_sep_unlock(sep); return; } @@ -561,61 +670,60 @@ static void avdtp_start_handler(struct bt_avdtp *session, } 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 > 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); } } } -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; + 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 { @@ -623,11 +731,10 @@ 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) { + avdtp_sep_unlock(sep); return; } @@ -638,29 +745,51 @@ static void avdtp_close_handler(struct bt_avdtp *session, 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); + } } } -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; + 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 { @@ -672,11 +801,11 @@ 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) { + avdtp_sep_unlock(sep); return; } @@ -686,40 +815,67 @@ static void avdtp_suspend_handler(struct bt_avdtp *session, } 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); + } } } -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; + 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); + 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; } @@ -729,16 +885,57 @@ static void avdtp_abort_handler(struct bt_avdtp *session, } 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); + } } } @@ -754,23 +951,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: @@ -781,28 +969,24 @@ 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; - 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; } @@ -818,9 +1002,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; @@ -832,8 +1014,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; @@ -864,22 +1045,24 @@ 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); + 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}, @@ -901,7 +1084,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)); @@ -910,8 +1093,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) { @@ -919,18 +1102,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); + 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) { @@ -945,23 +1125,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) { + 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; + "tid[0x%02x]", + session->req->sig, session->req->tid); + 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); @@ -972,27 +1146,38 @@ 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; - session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; - 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) { + 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 = &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); + return bt_l2cap_chan_connect(conn, &session->br_chan.chan, BT_L2CAP_PSM_AVDTP); } int bt_avdtp_disconnect(struct bt_avdtp *session) @@ -1003,12 +1188,11 @@ 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); } 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; @@ -1020,31 +1204,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; + session->current_sep->chan.required_sec_level = BT_SECURITY_L2; *chan = &session->current_sep->chan.chan; session->current_sep = NULL; + } else { + return -ENOMEM; } } @@ -1065,8 +1250,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(""); @@ -1080,13 +1264,18 @@ int bt_avdtp_register_sep(uint8_t media_type, uint8_t role, 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; } @@ -1113,10 +1302,10 @@ 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; + int err; LOG_DBG(""); if (!param || !session) { @@ -1124,15 +1313,18 @@ 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; } - return avdtp_send(session, buf, ¶m->req); + err = avdtp_send(session, buf, ¶m->req); + if (err) { + net_buf_unref(buf); + } + + return err; } int bt_avdtp_parse_sep(struct net_buf *buf, struct bt_avdtp_sep_info *sep_info) @@ -1155,9 +1347,10 @@ 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; + int err; LOG_DBG(""); if (!param || !session) { @@ -1165,23 +1358,26 @@ 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; } /* Body of the message */ - net_buf_add_u8(buf, (param->stream_endpoint_id << 2u)); + net_buf_add_u8(buf, (param->stream_endpoint_id << 2U)); + + err = avdtp_send(session, buf, ¶m->req); + if (err) { + net_buf_unref(buf); + } - return avdtp_send(session, buf, ¶m->req); + return err; } -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; @@ -1201,19 +1397,31 @@ int bt_avdtp_parse_capability_codec(struct net_buf *buf, case BT_AVDTP_SERVICE_HEADER_COMPRESSION: case BT_AVDTP_SERVICE_MULTIPLEXING: case BT_AVDTP_SERVICE_DELAY_REPORTING: + if (buf->len < 1U) { + return -EINVAL; + } + length = net_buf_pull_u8(buf); 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 < 1U) { + return -EINVAL; + } + length = net_buf_pull_u8(buf); + if (buf->len < length) { + return -EINVAL; + } + if (length > 3) { data = net_buf_pull_u8(buf); - if (net_buf_tailroom(buf) < (length - 1)) { - return -EINVAL; - } if (data == BT_AVDTP_AUDIO) { data = net_buf_pull_u8(buf); *codec_type = data; @@ -1229,14 +1437,14 @@ int bt_avdtp_parse_capability_codec(struct net_buf *buf, break; } } - return -EIO; + return -EINVAL; } -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; + int err; LOG_DBG(""); if (!param || !session) { @@ -1244,9 +1452,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; @@ -1254,9 +1460,9 @@ static int avdtp_process_configure_command(struct bt_avdtp *session, /* 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 */ @@ -1272,11 +1478,16 @@ static int avdtp_process_configure_command(struct bt_avdtp *session, /* Codec Info Element */ net_buf_add_mem(buf, param->codec_specific_ie, param->codec_specific_ie_len); - return avdtp_send(session, buf, ¶m->req); + err = avdtp_send(session, buf, ¶m->req); + if (err) { + net_buf_unref(buf); + } + + return err; } 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"); @@ -1290,8 +1501,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"); @@ -1305,10 +1515,11 @@ 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) +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; + int err; LOG_DBG(""); if (!param || !session || !param->sep) { @@ -1316,13 +1527,11 @@ int bt_avdtp_open(struct bt_avdtp *session, 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; @@ -1330,46 +1539,55 @@ int bt_avdtp_open(struct bt_avdtp *session, /* 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)); + + err = avdtp_send(session, buf, ¶m->req); + if (err) { + net_buf_unref(buf); + } - return avdtp_send(session, buf, ¶m->req); + return err; } -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; + return bt_avdtp_ctrl(session, param, BT_AVDTP_OPEN, AVDTP_CONFIGURED); +} - LOG_DBG(""); - if (!param || !session || !param->sep) { - LOG_DBG("Error: parameters not valid"); - return -EINVAL; - } +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); +} - 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 err; +} - return avdtp_send(session, buf, ¶m->req); +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; - 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 dc756cb11a7..86b3c7a2bc7 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 @@ -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; @@ -93,19 +95,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; @@ -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; }; @@ -124,19 +127,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; @@ -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; }; @@ -191,26 +184,27 @@ 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 (*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 (*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); + + /* stream l2cap is closed */ + int (*stream_l2cap_disconnected)(struct bt_avdtp *session, struct bt_avdtp_sep *sep); }; /** @brief Global AVDTP session structure. */ @@ -220,7 +214,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 { @@ -240,39 +235,43 @@ 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 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_start_params *param); +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); diff --git a/subsys/bluetooth/host/classic/shell/a2dp.c b/subsys/bluetooth/host/classic/shell/a2dp.c index f8e363a4177..26e2b137a0f 100644 --- a/subsys/bluetooth/host/classic/shell/a2dp.c +++ b/subsys/bluetooth/host/classic/shell/a2dp.c @@ -25,6 +25,7 @@ #include #include "host/shell/bt.h" +#include "common/bt_shell_private.h" struct bt_a2dp *default_a2dp; static uint8_t a2dp_sink_sdp_registered; @@ -98,7 +99,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 +168,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) }, ) }, @@ -207,82 +208,82 @@ static void shell_a2dp_print_capabilities(struct bt_a2dp_ep_info *ep_info) codec_type = ep_info->codec_type; codec_ie = ep_info->codec_cap.codec_ie; codec_ie_len = ep_info->codec_cap.len; - shell_print(ctx_shell, "endpoint id: %d, %s, %s:", ep_info->sep_info.id, - (ep_info->sep_info.tsep == BT_AVDTP_SINK) ? "(sink)" : "(source)", - (ep_info->sep_info.inuse) ? "(in use)" : "(idle)"); + bt_shell_print("endpoint id: %d, %s, %s:", ep_info->sep_info.id, + (ep_info->sep_info.tsep == BT_AVDTP_SINK) ? "(sink)" : "(source)", + (ep_info->sep_info.inuse) ? "(in use)" : "(idle)"); if (BT_A2DP_SBC == codec_type) { - shell_print(ctx_shell, " codec type: SBC"); + bt_shell_print(" codec type: SBC"); if (BT_A2DP_SBC_IE_LENGTH != codec_ie_len) { - shell_error(ctx_shell, " wrong sbc codec ie"); + bt_shell_error(" wrong sbc codec ie"); return; } - shell_print(ctx_shell, " sample frequency:"); + bt_shell_print(" sample frequency:"); if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_16000)) { - shell_print(ctx_shell, " 16000 "); + bt_shell_print(" 16000 "); } if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_32000)) { - shell_print(ctx_shell, " 32000 "); + bt_shell_print(" 32000 "); } if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_44100)) { - shell_print(ctx_shell, " 44100 "); + bt_shell_print(" 44100 "); } if (0U != (codec_ie[0U] & A2DP_SBC_SAMP_FREQ_48000)) { - shell_print(ctx_shell, " 48000"); + bt_shell_print(" 48000"); } - shell_print(ctx_shell, " channel mode:"); + bt_shell_print(" channel mode:"); if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_MONO)) { - shell_print(ctx_shell, " Mono "); + bt_shell_print(" Mono "); } if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_DUAL)) { - shell_print(ctx_shell, " Dual "); + bt_shell_print(" Dual "); } if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_STREO)) { - shell_print(ctx_shell, " Stereo "); + bt_shell_print(" Stereo "); } if (0U != (codec_ie[0U] & A2DP_SBC_CH_MODE_JOINT)) { - shell_print(ctx_shell, " Joint-Stereo"); + bt_shell_print(" Joint-Stereo"); } - /* Decode Support for Block Length */ - shell_print(ctx_shell, " Block Length:"); + /* Decode Support for Block Length */ + bt_shell_print(" Block Length:"); if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_4)) { - shell_print(ctx_shell, " 4 "); + bt_shell_print(" 4 "); } if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_8)) { - shell_print(ctx_shell, " 8 "); + bt_shell_print(" 8 "); } if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_12)) { - shell_print(ctx_shell, " 12 "); + bt_shell_print(" 12 "); } if (0U != (codec_ie[1U] & A2DP_SBC_BLK_LEN_16)) { - shell_print(ctx_shell, " 16"); + bt_shell_print(" 16"); } /* Decode Support for Subbands */ - shell_print(ctx_shell, " Subbands:"); + bt_shell_print(" Subbands:"); if (0U != (codec_ie[1U] & A2DP_SBC_SUBBAND_4)) { - shell_print(ctx_shell, " 4 "); + bt_shell_print(" 4 "); } if (0U != (codec_ie[1U] & A2DP_SBC_SUBBAND_8)) { - shell_print(ctx_shell, " 8"); + bt_shell_print(" 8"); } /* Decode Support for Allocation Method */ - shell_print(ctx_shell, " Allocation Method:"); + bt_shell_print(" Allocation Method:"); if (0U != (codec_ie[1U] & A2DP_SBC_ALLOC_MTHD_SNR)) { - shell_print(ctx_shell, " SNR "); + bt_shell_print(" SNR "); } if (0U != (codec_ie[1U] & A2DP_SBC_ALLOC_MTHD_LOUDNESS)) { - shell_print(ctx_shell, " Loudness"); + bt_shell_print(" Loudness"); } - shell_print(ctx_shell, " Bitpool Range: %d - %d", - codec_ie[2U], codec_ie[3U]); + bt_shell_print(" Bitpool Range: %d - %d", + codec_ie[2U], codec_ie[3U]); } else { - shell_print(ctx_shell, " not SBC codecs"); + bt_shell_print(" not SBC codecs"); } } @@ -290,99 +291,151 @@ void app_connected(struct bt_a2dp *a2dp, int err) { if (!err) { default_a2dp = a2dp; - shell_print(ctx_shell, "a2dp connected"); + bt_shell_print("a2dp connected"); } else { - shell_print(ctx_shell, "a2dp connecting fail"); + bt_shell_print("a2dp connecting fail"); } } void app_disconnected(struct bt_a2dp *a2dp) { found_peer_sbc_endpoint = NULL; - shell_print(ctx_shell, "a2dp disconnected"); + bt_shell_print("a2dp disconnected"); } int app_config_req(struct bt_a2dp *a2dp, struct bt_a2dp_ep *ep, struct bt_a2dp_codec_cfg *codec_cfg, struct bt_a2dp_stream **stream, uint8_t *rsp_err_code) { + 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; + bt_shell_print("receive requesting config and accept"); + sample_rate = bt_a2dp_sbc_get_sampling_frequency( + (struct bt_a2dp_codec_sbc_params *)&codec_cfg->codec_config->codec_ie[0]); + bt_shell_print("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; + bt_shell_print("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]); + bt_shell_print("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; } void app_config_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code) { if (rsp_err_code == 0) { - shell_print(ctx_shell, "success to configure"); + bt_shell_print("success to configure"); } else { - shell_print(ctx_shell, "fail to configure"); + bt_shell_print("fail to configure"); } } int app_establish_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code) { *rsp_err_code = 0; - shell_print(ctx_shell, "receive requesting establishment and accept"); + bt_shell_print("receive requesting establishment and accept"); return 0; } void app_establish_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code) { if (rsp_err_code == 0) { - shell_print(ctx_shell, "success to establish"); + bt_shell_print("success to establish"); + } else { + bt_shell_print("fail to establish"); + } +} + +int app_release_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code) +{ + *rsp_err_code = 0; + bt_shell_print("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) { + bt_shell_print("success to release"); } else { - shell_print(ctx_shell, "fail to establish"); + bt_shell_print("fail to release"); } } int app_start_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code) { *rsp_err_code = 0; - shell_print(ctx_shell, "receive requesting start and accept"); + bt_shell_print("receive requesting start and accept"); return 0; } void app_start_rsp(struct bt_a2dp_stream *stream, uint8_t rsp_err_code) { if (rsp_err_code == 0) { - shell_print(ctx_shell, "success to start"); + bt_shell_print("success to start"); } else { - shell_print(ctx_shell, "fail to start"); + bt_shell_print("fail to start"); + } +} + +int app_suspend_req(struct bt_a2dp_stream *stream, uint8_t *rsp_err_code) +{ + *rsp_err_code = 0; + bt_shell_print("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) { + bt_shell_print("success to suspend"); + } else { + bt_shell_print("fail to suspend"); } } void stream_configured(struct bt_a2dp_stream *stream) { - shell_print(ctx_shell, "stream configured"); + bt_shell_print("stream configured"); } void stream_established(struct bt_a2dp_stream *stream) { - shell_print(ctx_shell, "stream established"); + bt_shell_print("stream established"); } void stream_released(struct bt_a2dp_stream *stream) { - shell_print(ctx_shell, "stream released"); + bt_shell_print("stream released"); } void stream_started(struct bt_a2dp_stream *stream) { - shell_print(ctx_shell, "stream started"); + bt_shell_print("stream started"); +} + +void stream_suspended(struct bt_a2dp_stream *stream) +{ + bt_shell_print("stream suspended"); +} + +void stream_aborted(struct bt_a2dp_stream *stream) +{ + bt_shell_print("stream aborted"); } void sink_sbc_streamer_data(struct bt_a2dp_stream *stream, struct net_buf *buf, @@ -390,10 +443,13 @@ void sink_sbc_streamer_data(struct bt_a2dp_stream *stream, struct net_buf *buf, { 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); - shell_print(ctx_shell, "data: %d, %d, %d, %d, %d, %d ......", buf->data[0], + bt_shell_print("received, num of frames: %d, data length:%d", + (uint8_t)BT_A2DP_SBC_MEDIA_HDR_NUM_FRAMES_GET(sbc_hdr), buf->len); + bt_shell_print("data: %d, %d, %d, %d, %d, %d ......", buf->data[0], buf->data[1], buf->data[2], buf->data[3], buf->data[4], buf->data[5]); } @@ -410,14 +466,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[]) @@ -530,7 +585,7 @@ static int cmd_disconnect(const struct shell *sh, int32_t argc, char *argv[]) void app_configured(int err) { if (err) { - shell_print(ctx_shell, "configure fail"); + bt_shell_print("configure fail"); } } @@ -539,8 +594,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,11 +639,24 @@ 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) { if (info != NULL) { - shell_print(ctx_shell, "find one endpoint"); + bt_shell_print("find one endpoint"); shell_a2dp_print_capabilities(info); if ((info->codec_type == BT_A2DP_SBC) && (ep != NULL)) { @@ -639,6 +707,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 +733,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 +776,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 +799,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 ); diff --git a/subsys/bluetooth/host/classic/zephyr3/a2dp.c b/subsys/bluetooth/host/classic/zephyr3/a2dp.c deleted file mode 100644 index 0dcbc9a239c..00000000000 --- a/subsys/bluetooth/host/classic/zephyr3/a2dp.c +++ /dev/null @@ -1,576 +0,0 @@ -/** @file - * @brief Advance Audio Distribution Profile. - */ - -/* - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -//#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_A2DP) -#define LOG_MODULE_NAME bt_a2dp -#include "avdtp_internal.h" -#include "common/assert.h" -#include -#include "host/hci_core.h" -#include "host/conn_internal.h" -#include "host/classic/l2cap_br_internal.h" -struct bt_avdtp_conn avdtp_conn[CONFIG_BT_MAX_CONN]; - -/* A2dp app register call back handler */ -static struct bt_a2dp_app_cb *reg_a2dp_app_cb; - -static struct bt_avdtp *a2dp_get_new_connection(struct bt_conn *conn) -{ - uint8_t i, free, find, index; - uint8_t session_priority = 0; - struct bt_avdtp *session = NULL; - if (!conn) { - LOG_ERR("Invalid Input (err: %d)", -EINVAL); - return NULL; - } - find = CONFIG_BT_MAX_CONN; - free = CONFIG_BT_MAX_CONN; - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (avdtp_conn[i].signal_session.br_chan.chan.conn == conn) { - LOG_DBG("Conn:%p already connected signal_session: %p", conn, &avdtp_conn[i]); - session_priority++; - find = i; - if (avdtp_conn[i].media_session.br_chan.chan.conn == conn) { - session_priority++; - } - break; - } else if (!avdtp_conn[i].signal_session.br_chan.chan.conn) { - if (avdtp_conn[i].media_session.br_chan.chan.conn == conn) { - LOG_ERR("media session exist (err: %d)", -EEXIST); - return NULL; - } - free = i; - } - } - if ((free == CONFIG_BT_MAX_CONN) && (find == CONFIG_BT_MAX_CONN)) { - LOG_DBG("More connection cannot be supported"); - return NULL; - } - if (find != CONFIG_BT_MAX_CONN) { - index = find; - } else { - index = free; - } - /* Clean the memory area before returning */ - switch (session_priority) { - case BT_AVDTP_SIGNALING_SESSION: - memset(&avdtp_conn[index], 0, sizeof(struct bt_avdtp_conn)); - avdtp_conn[index].signal_session.session_priority = session_priority; - session = &avdtp_conn[index].signal_session; - break; - case BT_AVDTP_MEDIA_SESSION: - avdtp_conn[index].media_session.session_priority = session_priority; - session = &avdtp_conn[index].media_session; - break; - default: - LOG_ERR("Wait TODO!"); - break; - } - return session; -} - -static struct bt_avdtp_conn *a2dp_lookup_by_conn(struct bt_conn *conn) -{ - uint8_t i; - if (!conn) { - return NULL; - } - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (avdtp_conn[i].signal_session.br_chan.chan.conn == conn) { - return &avdtp_conn[i]; - } - } - return NULL; -} - -int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session) -{ - struct bt_avdtp *avdtp_session; - avdtp_session = a2dp_get_new_connection(conn); - if (!avdtp_session) { - return -ENOMEM; - } - avdtp_session->intacp_role = BT_AVDTP_ACP; - *session = avdtp_session; - LOG_DBG("session: %p", avdtp_session); - return 0; -} - -static void a2dp_avdtp_connected_cb(struct bt_avdtp *session) -{ - struct bt_avdtp_conn *pAvdtp_conn; - if ((session->session_priority == BT_AVDTP_SIGNALING_SESSION) && - (session->intacp_role == BT_AVDTP_INT)) { - /* Only as initiator to trigger discover */ - bt_avdtp_discover(session); - } - if (reg_a2dp_app_cb && reg_a2dp_app_cb->connected && - (session->session_priority == BT_AVDTP_MEDIA_SESSION)) { - /* Tell app a2dp connected after media session connected and signal session connected */ - pAvdtp_conn = AVDTP_CONN_BY_MEDIA(session); - if (pAvdtp_conn->signal_session.connected) { - reg_a2dp_app_cb->connected(session->br_chan.chan.conn); - } - } -} - -static void a2dp_avdtp_disconnected_cb(struct bt_avdtp *session) -{ - if (reg_a2dp_app_cb && reg_a2dp_app_cb->disconnected && - (session->session_priority == BT_AVDTP_SIGNALING_SESSION) && - session->connected) { - reg_a2dp_app_cb->disconnected(session->br_chan.chan.conn); - } -} - -static void a2dp_avdtp_do_media_connect_cb(struct bt_avdtp *session, bool isconnect) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if (isconnect) { - bt_a2dp_connect(session->br_chan.chan.conn, BT_A2DP_CH_MEDIA); - } else if (pAvdtp_conn->media_session.connected) { - bt_avdtp_disconnect(&pAvdtp_conn->media_session); - } -} - -static void a2dp_avdtp_media_handler_cb(struct bt_avdtp *session, struct net_buf *buf) -{ - if (reg_a2dp_app_cb && reg_a2dp_app_cb->media_handler) { - reg_a2dp_app_cb->media_handler(session->br_chan.chan.conn, buf->data, buf->len); - } -} -static int a2dp_avdtp_media_state_req_cb(struct bt_avdtp *session, uint8_t sig_id) -{ - if (reg_a2dp_app_cb && reg_a2dp_app_cb->media_state_req) { - return reg_a2dp_app_cb->media_state_req(session->br_chan.chan.conn, sig_id); - } - return 0; -} -static int a2dp_intiator_connect_result_cb(struct bt_avdtp *session, bool success) -{ - if (success) { - /* As intiator, connect success, do nothing */ - } else { - /* This session is BT_AVDTP_SIGNALING_SESSION session */ - bt_a2dp_disconnect(session->br_chan.chan.conn); - } - return 0; -} -static void a2dp_avdtp_seted_codec_cb(struct bt_avdtp *session, - struct bt_a2dp_media_codec *codec, uint8_t cp_type) -{ - if (reg_a2dp_app_cb && reg_a2dp_app_cb->seted_codec) { - reg_a2dp_app_cb->seted_codec(session->br_chan.chan.conn, codec, cp_type); - } -} - -/* The above callback structures need to be packed and passed to AVDTP */ -static const struct bt_avdtp_event_cb avdtp_cb = { - .accept = a2dp_accept, - .connected = a2dp_avdtp_connected_cb, - .disconnected = a2dp_avdtp_disconnected_cb, - .do_media_connect = a2dp_avdtp_do_media_connect_cb, - .media_handler = a2dp_avdtp_media_handler_cb, - .media_state_req = a2dp_avdtp_media_state_req_cb, - .intiator_connect_result = a2dp_intiator_connect_result_cb, - .seted_codec = a2dp_avdtp_seted_codec_cb, -}; - -static void bt_a2dp_env_init(void) -{ - memset(avdtp_conn, 0, sizeof(struct bt_avdtp_conn)*CONFIG_BT_MAX_CONN); - reg_a2dp_app_cb = NULL; -} - -int bt_a2dp_init(void) -{ - int err; - bt_a2dp_env_init(); - /* Register event handlers with AVDTP */ - err = bt_avdtp_register((struct bt_avdtp_event_cb *)&avdtp_cb); - if (err < 0) { - LOG_ERR("A2DP registration failed"); - return err; - } - LOG_DBG("A2DP Initialized successfully."); - return 0; -} -static struct bt_avdtp_conn *a2dp_lookup_by_media_conn(struct bt_conn *conn) -{ - uint8_t i; - if (!conn) { - return NULL; - } - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if ((avdtp_conn[i].signal_session.br_chan.chan.conn == NULL) && - (avdtp_conn[i].media_session.br_chan.chan.conn == conn)) { - return &avdtp_conn[i]; - } - } - return NULL; -} - -static int a2dp_connect_check_conflict(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn = a2dp_lookup_by_media_conn(conn); - if (!pAvdtp_conn) { - return 0; - } - if ((pAvdtp_conn->signal_session.connected == 0) && (pAvdtp_conn->media_session.connected == 1)) { - printk("A2dp connect conflict\n"); - bt_avdtp_disconnect(&pAvdtp_conn->media_session); - return 1; - } - if ((pAvdtp_conn->signal_session.connected == 0) && pAvdtp_conn->media_session.connected == 0) { - printk("media connect pending, wait.\n"); - return 1; - } - return 0; -} -int bt_a2dp_connect(struct bt_conn *conn, uint8_t role) -{ - struct bt_avdtp *avdtp_session; - int err; - if ((role == BT_A2DP_CH_SOURCE) || (role == BT_A2DP_CH_SINK)) { - if (a2dp_connect_check_conflict(conn)) { - LOG_INF("Connect conflict"); - return 0; - } - if (a2dp_lookup_by_conn(conn)) { - LOG_INF("Already connect"); - return 0; - } - } - avdtp_session = a2dp_get_new_connection(conn); - if (!avdtp_session) { - LOG_ERR("Cannot allocate memory"); - return -EIO; - } - err = bt_avdtp_connect(conn, avdtp_session, role); - if (err < 0) { - /* If error occurs, undo the saving and return the error */ - memset(avdtp_session, 0, sizeof(struct bt_avdtp)); - LOG_DBG("AVDTP Connect failed"); - return err; - } - LOG_DBG("Connect request sent"); - return 0; -} - -int bt_a2dp_disconnect(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn) { - return -EEXIST; - } - if (pAvdtp_conn->media_session.connected) { - bt_avdtp_disconnect(&pAvdtp_conn->media_session); - } - if (pAvdtp_conn->signal_session.connected) { - bt_avdtp_disconnect(&pAvdtp_conn->signal_session); - } - return 0; -} -int bt_a2dp_register_endpoint(struct bt_a2dp_endpoint *endpoint, - uint8_t media_type, uint8_t role) -{ - BT_ASSERT(endpoint); - return bt_avdtp_ep_register_sep(media_type, role, &(endpoint->info)); -} -int bt_a2dp_halt_endpoint(struct bt_a2dp_endpoint *endpoint, bool halt) -{ - BT_ASSERT(endpoint); - return bt_avdtp_ep_halt_sep(&(endpoint->info), halt); -} -int bt_a2dp_register_cb(struct bt_a2dp_app_cb *cb) -{ - if (reg_a2dp_app_cb) { - LOG_WRN("Already register app_cb"); - } - reg_a2dp_app_cb = cb; - return 0; -} - -int bt_a2dp_start(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || - (pAvdtp_conn->signal_session.connected == 0) || - (pAvdtp_conn->media_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_start(&pAvdtp_conn->signal_session); -} -int bt_a2dp_suspend(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || - (pAvdtp_conn->signal_session.connected == 0) || - (pAvdtp_conn->media_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_suspend(&pAvdtp_conn->signal_session); -} - -int bt_a2dp_reconfig(struct bt_conn *conn, struct bt_a2dp_media_codec *codec) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || - (pAvdtp_conn->signal_session.connected == 0) || - (pAvdtp_conn->media_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_reconfig(&pAvdtp_conn->signal_session, codec); -} - -int bt_a2dp_send_delay_report(struct bt_conn *conn, uint16_t delay_time) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_delayreport(&pAvdtp_conn->signal_session, delay_time); -} - -int bt_a2dp_send_audio_data(struct bt_conn *conn, uint8_t *data, uint16_t len) -{ - struct net_buf *buf; - struct bt_avdtp_conn *pAvdtp_conn; - int ret; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->media_session.connected == 0)) { - return -EIO; - } - /* if (len > bt_inner_value.l2cap_tx_mtu) { */ - if (len > BT_L2CAP_TX_MTU) { - return -EFBIG; - } - buf = bt_l2cap_create_pdu(NULL, 0); - if (!buf) { - return -ENOMEM; - } - net_buf_add_mem(buf, data, len); - ret = bt_l2cap_chan_send(&pAvdtp_conn->media_session.br_chan.chan, buf); - if (ret < 0) { - net_buf_unref(buf); - return ret; - } else { - return (int)len; - } -} - -struct bt_a2dp_media_codec *bt_a2dp_get_seted_codec(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return NULL; - } - return bt_avdtp_get_seted_codec(&pAvdtp_conn->signal_session); -} - -uint8_t bt_a2dp_get_a2dp_role(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return 0; - } - return pAvdtp_conn->signal_session.role; -} - -bool bt_a2dp_is_media_rx_channel(uint16_t handle, uint16_t cid) -{ - int i; - struct bt_conn *conn; - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (avdtp_conn[i].signal_session.br_chan.chan.conn && - avdtp_conn[i].media_session.br_chan.chan.conn) { - conn = avdtp_conn[i].media_session.br_chan.chan.conn; - if ((conn->handle == handle) && - (avdtp_conn[i].media_session.br_chan.rx.cid == cid)) { - return true; - } - } - } - return false; -} - -bool bt_a2dp_is_media_tx_channel(uint16_t handle, uint16_t cid) -{ - int i; - struct bt_conn *conn; - for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { - if (avdtp_conn[i].signal_session.br_chan.chan.conn && - avdtp_conn[i].media_session.br_chan.chan.conn) { - conn = avdtp_conn[i].media_session.br_chan.chan.conn; - if ((conn->handle == handle) && - (avdtp_conn[i].media_session.br_chan.tx.cid == cid)) { - return true; - } - } - } - return false; -} - -uint16_t bt_a2dp_get_a2dp_media_tx_mtu(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->media_session.connected == 0)) { - return 0; - } - //printk("bt_a2dp_get_a2dp_media_tx_mtu pAvdtp_conn->media_session.br_chan.tx.mtu=%d\n", pAvdtp_conn->media_session.br_chan.tx.mtu); - return pAvdtp_conn->media_session.br_chan.tx.mtu; -} - -int bt_a2dp_send_audio_data_with_cb(struct bt_conn *conn, uint8_t *data, uint16_t len, - void (*cb)(struct bt_conn *, void *)) -{ - struct net_buf *buf; - struct bt_avdtp_conn *pAvdtp_conn; - int ret; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->media_session.connected == 0)) { - return -EIO; - } - /* if (len > bt_inner_value.l2cap_tx_mtu) { */ - if (len > BT_L2CAP_TX_MTU) { - return -EFBIG; - } - - buf = bt_l2cap_create_pdu(NULL, 0); - if (!buf) { - return -ENOMEM; - } - net_buf_add_mem(buf, data, len); - ret = bt_l2cap_chan_send_with_cb(&pAvdtp_conn->media_session.br_chan.chan, buf, cb); - if (ret < 0) { - net_buf_unref(buf); - return ret; - } else { - return (int)len; - } -} - -int bt_a2dp_discover(struct bt_conn *conn, uint8_t role) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - LOG_INF("int_state %d acp_state %d\n", - pAvdtp_conn->stream.int_state,pAvdtp_conn->stream.acp_state); - if ((pAvdtp_conn->stream.int_state != BT_AVDTP_ACPINT_STATE_IDLE) || - (pAvdtp_conn->stream.acp_state != BT_AVDTP_ACPINT_STATE_IDLE)) { - return -EEXIST; - } - pAvdtp_conn->signal_session.intacp_role = BT_AVDTP_INT; - pAvdtp_conn->signal_session.role = role; - return bt_avdtp_discover(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_discover(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_discover(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_get_capabilities(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_get_capabilities(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_get_all_capabilities(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_get_all_capabilities(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_set_configuration(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_set_configuration(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_open(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_open(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_close(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_close(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_abort(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_abort(&pAvdtp_conn->signal_session); -} - -int bt_pts_a2dp_disconnect_media_session(struct bt_conn *conn) -{ - struct bt_avdtp_conn *pAvdtp_conn; - pAvdtp_conn = a2dp_lookup_by_conn(conn); - if (!pAvdtp_conn || (pAvdtp_conn->signal_session.connected == 0)) { - return -EIO; - } - return bt_avdtp_disconnect(&pAvdtp_conn->signal_session); -} \ No newline at end of file diff --git a/subsys/bluetooth/host/classic/zephyr3/avdtp.c b/subsys/bluetooth/host/classic/zephyr3/avdtp.c deleted file mode 100644 index 6113df22dbc..00000000000 --- a/subsys/bluetooth/host/classic/zephyr3/avdtp.c +++ /dev/null @@ -1,1217 +0,0 @@ -/* - * Audio Video Distribution Protocol - * - * SPDX-License-Identifier: Apache-2.0 - * - */ -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_AVDTP) -#define LOG_MODULE_NAME bt_avdtp -#include -#include "host/hci_core.h" -#include "avdtp_internal.h" -#include "host/conn_internal.h" -#include "host/classic/l2cap_br_internal.h" -#define AVDTP_DEBUG_LOG 1 -#if AVDTP_DEBUG_LOG -#define avdtp_log(fmt, ...) \ - do { \ - printk(fmt, ##__VA_ARGS__); \ - } while (0) -#else -#define avdtp_log(fmt, ...) -#endif -#define AVDTP_TIMEOUT K_SECONDS(5) -#define AVDTP_MSG_POISTION 0x00 -#define AVDTP_PKT_POSITION 0x02 -#define AVDTP_TID_POSITION 0x04 -#define AVDTP_SIGID_MASK 0x3f - -#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_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_req, timeout_work) - -static struct bt_avdtp_event_cb *event_cb; -static struct net_buf *avdtp_create_pdu(uint8_t msg_type, - uint8_t pkt_type, uint8_t sig_id, uint8_t rxtid, uint8_t *cmdtid); -static int avdtp_send(struct bt_avdtp *session, struct net_buf *buf); -static int bt_avdtp_send_timeout_handler(struct bt_avdtp *session, - struct bt_avdtp_req *req); -static int bt_avdtp_state_sm(struct bt_avdtp *session, struct bt_avdtp_req *req); -/* Capabilities service length */ -static const uint8_t avdtp_cap_svr_len[] = { - 0xFF, /* Not used */ - 0x00, /* BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT */ - 0x00, /* BT_AVDTP_SERVICE_CAT_REPORTING */ - 0x03, /* BT_AVDTP_SERVICE_CAT_RECOVERY */ - 0xFF, /* BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION, length depend on service */ - 0x01, /* BT_AVDTP_SERVICE_CAT_HDR_COMPRESSION */ - 0xFF, /* BT_AVDTP_SERVICE_CAT_MULTIPLEXING, length depend on service */ - 0xFF, /* BT_AVDTP_SERVICE_CAT_MEDIA_CODEC, length depend on service */ - 0x00 /* BT_AVDTP_SERVICE_CAT_DELAYREPORTING */ -}; -static int avdtp_check_capabilities(struct net_buf *buf, - uint8_t sig_id, struct bt_avdtp_conf_rej *rej) -{ - uint8_t len; - struct bt_avdtp_cap *cap = (void *)buf->data; - for (len = 0; len < buf->len; ) { - if (cap->cat == 0 || cap->cat > BT_AVDTP_SERVICE_CAT_MAX) { - rej->category = cap->cat; - rej->error = BT_AVDTP_ERR_BAD_SERV_CATEGORY; - return -EINVAL; - } - if (sig_id == BT_AVDTP_RECONFIGURE && cap->cat == BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT) { - rej->category = cap->cat; - rej->error = BT_AVDTP_ERR_INVALID_CAPABILITIES; - return -EINVAL; - } - if ((avdtp_cap_svr_len[cap->cat] != 0xFF) && - (avdtp_cap_svr_len[cap->cat] != cap->len)) { - rej->category = cap->cat; - switch (cap->cat) { - case BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT: - rej->error = BT_AVDTP_ERR_BAD_MEDIA_TRANSPORT_FORMAT; - break; - case BT_AVDTP_SERVICE_CAT_RECOVERY: - rej->error = BT_AVDTP_ERR_BAD_RECOVERY_FORMAT; - break; - case BT_AVDTP_SERVICE_CAT_MULTIPLEXING: - rej->error = BT_AVDTP_ERR_BAD_MULTIPLEXING_FORMAT; - break; - default: - rej->error = BT_AVDTP_ERR_BAD_ROHC_FORMAT; - break; - } - return -EINVAL; - } - len += cap->len + 2; - cap = (void *)&buf->data[len]; - } - if (len != buf->len) { - rej->category = 0; - rej->error = BT_AVDTP_ERR_BAD_LENGTH; - return -EINVAL; - } - return 0; -} -static int avdtp_send_accept_resp(struct bt_avdtp *session, - uint8_t sig_id, uint8_t rxtid) -{ - struct net_buf *buf; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - sig_id, rxtid, &pAvdtp_conn->req.cmdtid); - if (!buf) { - return -ENOMEM; - } - return avdtp_send(session, buf); -} -static int avdtp_check_cmd_format(struct bt_avdtp *session, - struct net_buf *buf, uint8_t sig_id, uint8_t rxtid, uint8_t *reqSeid) -{ - struct net_buf *resp_buf; - uint8_t seid, tmp; - uint8_t error_code = BT_AVDTP_SUCCESS; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - /* Check length */ - switch (sig_id) { - case BT_AVDTP_DISCOVER: - if (buf->len == 0) { - return 0; - } - error_code = BT_AVDTP_ERR_BAD_LENGTH; - break; - case BT_AVDTP_GET_CAPABILITIES: - case BT_AVDTP_GET_ALL_CAPABILITIES: - case BT_AVDTP_GET_CONFIGURATION: - case BT_AVDTP_OPEN: - case BT_AVDTP_START: - case BT_AVDTP_CLOSE: - case BT_AVDTP_SUSPEND: - if (buf->len != 1) { - error_code = BT_AVDTP_ERR_BAD_LENGTH; - } - break; - case BT_AVDTP_SET_CONFIGURATION: - case BT_AVDTP_RECONFIGURE: - if (buf->len < 2) { - error_code = BT_AVDTP_ERR_BAD_LENGTH; - } - break; - case BT_AVDTP_ABORT: - /* ABORT: no response shall be sent. */ - return 0; - } - seid = buf->data[0] >> 2; - if (error_code != BT_AVDTP_SUCCESS) { - goto send_reject; - } - /* Check acp seid */ - switch (sig_id) { - case BT_AVDTP_GET_CAPABILITIES: - case BT_AVDTP_GET_ALL_CAPABILITIES: - case BT_AVDTP_SET_CONFIGURATION: - case BT_AVDTP_RECONFIGURE: - case BT_AVDTP_OPEN: - case BT_AVDTP_START: - case BT_AVDTP_CLOSE: - case BT_AVDTP_SUSPEND: - if (!find_lsep_by_seid(seid)) { - error_code = BT_AVDTP_ERR_BAD_ACP_SEID; - } - break; - default: - break; - } - if (error_code != BT_AVDTP_SUCCESS) { - goto send_reject; - } - /* Check if command can be doing at current state */ - switch (sig_id) { - case BT_AVDTP_SET_CONFIGURATION: - if (lsep_seid_inused(seid)) { - error_code = BT_AVDTP_ERR_SEP_IN_USE; - } - break; - case BT_AVDTP_OPEN: - if (pAvdtp_conn->stream.stream_state != BT_AVDTP_STREAM_STATE_CONFIGURED) { - error_code = BT_AVDTP_ERR_BAD_STATE; - } - break; - case BT_AVDTP_START: - if (!pAvdtp_conn->media_session.connected) { - pAvdtp_conn->pending_ahead_start = 1; - } else if (!(pAvdtp_conn->stream.stream_state == BT_AVDTP_STREAM_STATE_OPEN || - pAvdtp_conn->stream.stream_state == BT_AVDTP_STREAM_STATE_SUSPEND)) { - error_code = BT_AVDTP_ERR_BAD_STATE; - } - break; - case BT_AVDTP_SUSPEND: - if (pAvdtp_conn->stream.stream_state != BT_AVDTP_STREAM_STATE_STREAMING) { - error_code = BT_AVDTP_ERR_BAD_STATE; - } - break; - default: - break; - } - if (error_code == BT_AVDTP_SUCCESS) { - if (reqSeid) { - *reqSeid = seid; - } - return 0; - } -send_reject: - resp_buf = avdtp_create_pdu(BT_AVDTP_REJECT, - BT_AVDTP_PACKET_TYPE_SINGLE, - sig_id, rxtid, &pAvdtp_conn->req.cmdtid); - if (!resp_buf) { - return -ENOMEM; - } - seid = seid << 2; - switch (sig_id) { - case BT_AVDTP_SET_CONFIGURATION: - case BT_AVDTP_RECONFIGURE: - tmp = 0; /* Service Category */ - net_buf_add_mem(resp_buf, &tmp, sizeof(tmp)); - break; - case BT_AVDTP_START: - case BT_AVDTP_SUSPEND: - net_buf_add_mem(resp_buf, &seid, sizeof(seid)); - break; - case BT_AVDTP_OPEN: - case BT_AVDTP_CLOSE: - default: - break; - } - net_buf_add_mem(resp_buf, &error_code, sizeof(error_code)); - avdtp_send(session, resp_buf); - return -error_code; -} -static void avdtp_discover_cmd_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t rxtid) -{ - struct net_buf *resp_buf; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - resp_buf = avdtp_create_pdu((bt_avdtp_ep_empty() ? BT_AVDTP_REJECT : BT_AVDTP_ACCEPT), - BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_DISCOVER, - rxtid, &pAvdtp_conn->req.cmdtid); - if (!resp_buf) { - return; - } - bt_avdtp_ep_append_seid(resp_buf); - avdtp_send(session, resp_buf); - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_DISCOVERED; -} -static void avdtp_discover_resp_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type) -{ - struct bt_avdtp_seid_info *seid; - uint8_t i, add_flag; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if (msg_type != BT_AVDTP_ACCEPT) { - return; - } - pAvdtp_conn->get_seid_num = 0; - pAvdtp_conn->get_rsid_cap_index = 0; - memset(pAvdtp_conn->get_seid, 0, sizeof(pAvdtp_conn->get_seid)); - for (i = 0; i < buf->len; i += 2) { - /* Is better GET_ALL_CAPABILITIES and select that right seid */ - if ((session->role == BT_A2DP_CH_SINK) && find_free_lsep_by_role_codectype(BT_A2DP_EP_SINK, BT_A2DP_MPEG2)) { - /* Get from last seid, most phone aac in last */ - seid = (struct bt_avdtp_seid_info *)&buf->data[buf->len - 2 - i]; - } else { - /* Get from first seid, most phone sbc in first */ - seid = (struct bt_avdtp_seid_info *)&buf->data[i]; - } - add_flag = 0; - if ((seid->media_type == BT_AVDTP_MEDIA_TYPE_AUDIO) && (!seid->inuse)) { - if ((session->role == BT_A2DP_CH_SOURCE) && (seid->tsep == BT_A2DP_EP_SINK) && - find_free_lsep_by_role(BT_A2DP_EP_SOURCE)) { - add_flag = 1; - } else if ((session->role == BT_A2DP_CH_SINK) && (seid->tsep == BT_A2DP_EP_SOURCE) && - find_free_lsep_by_role(BT_A2DP_EP_SINK)) { - add_flag = 1; - } else if ((session->role == BT_A2DP_CH_UNKOWN) && (seid->tsep == BT_A2DP_EP_SINK) && - find_free_lsep_by_role(BT_A2DP_EP_SOURCE)) { - add_flag = 1; - } else if ((session->role == BT_A2DP_CH_UNKOWN) && (seid->tsep == BT_A2DP_EP_SOURCE) && - find_free_lsep_by_role(BT_A2DP_EP_SINK)) { - add_flag = 1; - } - } - if (add_flag) { - if (pAvdtp_conn->get_seid_num < BT_AVDTP_GET_SEID_MAX) { - memcpy(&pAvdtp_conn->get_seid[pAvdtp_conn->get_seid_num], seid, sizeof(struct bt_avdtp_seid_info)); - pAvdtp_conn->get_seid_num++; - } else { - avdtp_log("avdtp cache get seid full!\n"); - } - } - } - if (pAvdtp_conn->get_seid_num == 0) { - return; - } - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_DISCOVERED; -} -static void avdtp_discover_handle(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t rxtid) -{ - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - avdtp_discover_cmd_handle(session, buf, rxtid); - } else { - avdtp_discover_resp_handle(session, buf, msg_type); - } -} -static int avdtp_get_capabilities_cmd_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t sig_id, uint8_t rxtid) -{ - struct net_buf *resp_buf = NULL; - uint8_t reqSeid = BT_AVDTP_GET_SEID_MAX; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if (avdtp_check_cmd_format(session, buf, sig_id, rxtid, &reqSeid)) { - return -EINVAL; - } - resp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - sig_id, rxtid, &pAvdtp_conn->req.cmdtid); - if (!resp_buf) { - return -ENOMEM; - } - bt_avdtp_ep_append_capabilities(resp_buf, reqSeid); - avdtp_send(session, resp_buf); - pAvdtp_conn->stream.acp_state = BT_AVDTP_SIG_ID_TO_STATE_ED(sig_id); - return 0; -} -static void avdtp_get_capabilities_resp_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t sig_id) -{ - int ret; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if (msg_type != BT_AVDTP_ACCEPT) { - /* Reject: what todo? */ - return; - } - ret = bt_avdtp_ep_check_set_codec_cp(session, buf, 0, sig_id); - if (!ret) { - /* Get capabilities success */ - pAvdtp_conn->stream.int_state = BT_AVDTP_SIG_ID_TO_STATE_ED(sig_id); - pAvdtp_conn->get_rsid_cap_index = 0; - } else { - /* Rsid cap is not the right one, try next index rsid. - * For same device, first source rsid id not sbc(maybe not sbc/aac), - * it will failed, so need try next rsid. - */ - pAvdtp_conn->stream.int_state = BT_AVDTP_SIG_ID_TO_STATE_EXT(sig_id); - } -} -static void avdtp_get_capabilities_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t rxtid) -{ - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - avdtp_get_capabilities_cmd_handle(session, buf, - BT_AVDTP_GET_CAPABILITIES, rxtid); - } else { - avdtp_get_capabilities_resp_handle(session, buf, msg_type, BT_AVDTP_GET_CAPABILITIES); - } -} -static void avdtp_get_all_capabilities_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t rxtid) -{ - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - avdtp_get_capabilities_cmd_handle(session, buf, - BT_AVDTP_GET_ALL_CAPABILITIES, rxtid); - } else { - avdtp_get_capabilities_resp_handle(session, buf, msg_type, BT_AVDTP_GET_ALL_CAPABILITIES); - } -} -static uint8_t a2dp_test_pts_err_code = 0xFF; -void bt_pts_a2dp_set_err_code(uint8_t err_code) -{ - a2dp_test_pts_err_code = err_code; -} -static int avdtp_setreset_configuration_cmd_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t rxtid, uint8_t *int_seid, uint8_t *acp_seid, uint8_t sig_id) -{ - int ret = 0; - struct bt_avdtp_setconf_req *req = (void *)buf->data; - struct bt_avdtp_reconf_req *req_reconf = (void *)buf->data; - struct net_buf *resp_buf; - struct bt_avdtp_conf_rej rej = {0, BT_AVDTP_SUCCESS}; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG(""); - if (avdtp_check_cmd_format(session, buf, sig_id, rxtid, NULL)) { - return -EINVAL; - } - if (sig_id == BT_AVDTP_SET_CONFIGURATION) { - *int_seid = req->int_seid; - *acp_seid = req->acp_seid; - net_buf_pull(buf, sizeof(*req)); - } else { - *acp_seid = req_reconf->acp_seid; - net_buf_pull(buf, sizeof(*req_reconf)); - } - /* check services */ - if (avdtp_check_capabilities(buf, sig_id, &rej)) { - goto out; - } - ret = bt_avdtp_ep_check_set_codec_cp(session, buf, *acp_seid, sig_id); - if (ret) { - rej.category = BT_AVDTP_SERVICE_CAT_MEDIA_CODEC; - rej.error = (uint8_t)(-ret); - goto out; - } -out: - if (rej.error == BT_AVDTP_SUCCESS) { - resp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, - BT_AVDTP_PACKET_TYPE_SINGLE, - sig_id, rxtid, &pAvdtp_conn->req.cmdtid); - if (!resp_buf) { - return -ENOMEM; - } else { - ret = 0; - } - } else { - resp_buf = avdtp_create_pdu(BT_AVDTP_REJECT, - BT_AVDTP_PACKET_TYPE_SINGLE, - sig_id, rxtid, &pAvdtp_conn->req.cmdtid); - if (!resp_buf) { - return -ENOMEM; - } else { - net_buf_add_mem(resp_buf, &rej, sizeof(struct bt_avdtp_conf_rej)); - ret = -rej.error; - } - } - avdtp_send(session, resp_buf); - return ret; -} -static void avdtp_set_configuration_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t rxtid) -{ - uint8_t acp_seid, int_seid; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - if (avdtp_setreset_configuration_cmd_handle(session, buf, rxtid, &int_seid, - &acp_seid, BT_AVDTP_SET_CONFIGURATION) == 0) { - lsep_set_seid_used_by_seid(acp_seid, &pAvdtp_conn->stream); - if (pAvdtp_conn->stream.lsid.tsep == BT_A2DP_EP_SOURCE) { - session->role = BT_A2DP_CH_SOURCE; - pAvdtp_conn->stream.rsid.tsep = BT_A2DP_EP_SINK; - pAvdtp_conn->stream.rsid.id = int_seid; - } else if (pAvdtp_conn->stream.lsid.tsep == BT_A2DP_EP_SINK) { - session->role = BT_A2DP_CH_SINK; - pAvdtp_conn->stream.rsid.tsep = BT_A2DP_CH_SOURCE; - pAvdtp_conn->stream.rsid.id = int_seid; - } - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_CONFIGURED; - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_SET_CFGED; - event_cb->seted_codec(session, &pAvdtp_conn->stream.codec, pAvdtp_conn->stream.cp_type); - } - } else if (msg_type == BT_AVDTP_ACCEPT) { - /* As INT, session->role is set in start connect */ - lsep_set_seid_used_by_stream(&pAvdtp_conn->stream); - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_CONFIGURED; - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_SET_CFGED; - event_cb->seted_codec(session, &pAvdtp_conn->stream.codec, pAvdtp_conn->stream.cp_type); - } else { - /* Reject: what todo? */ - } -} -static void avdtp_reconfigure_handle(struct bt_avdtp *session, - struct net_buf *buf, uint8_t msg_type, uint8_t rxtid) -{ - uint8_t acp_seid; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - if (avdtp_setreset_configuration_cmd_handle(session, buf, rxtid, 0, - &acp_seid, BT_AVDTP_RECONFIGURE) == 0) { - event_cb->seted_codec(session, &pAvdtp_conn->stream.codec, pAvdtp_conn->stream.cp_type); - } - } else if (msg_type == BT_AVDTP_ACCEPT) { - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_RECFGED; - event_cb->seted_codec(session, &pAvdtp_conn->stream.codec, pAvdtp_conn->stream.cp_type); - } else { - /* Reject: what todo? */ - } -} -static void avdtp_open_handle(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t rxtid) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - if (avdtp_check_cmd_format(session, buf, BT_AVDTP_OPEN, rxtid, NULL)) { - avdtp_log("avdtp_check_cmd_format failed\n"); - return; - } - if (avdtp_send_accept_resp(session, BT_AVDTP_OPEN, rxtid) > 0) { - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_OPEN; - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_OPENED; - event_cb->media_state_req(session, BT_AVDTP_OPEN); - } - } else if (msg_type == BT_AVDTP_ACCEPT) { - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_OPEN; - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_OPENED; - event_cb->media_state_req(session, BT_AVDTP_OPEN); - } else { - /* Reject: what todo? */ - } -} -static void avdtp_start_handle(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t rxtid) -{ - struct net_buf *resp_buf; - uint8_t resp_msg, error_code; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - if (avdtp_check_cmd_format(session, buf, BT_AVDTP_START, rxtid, NULL)) { - return; - } - if (event_cb->media_state_req(session, BT_AVDTP_START) == 0) { - resp_msg = BT_AVDTP_ACCEPT; - } else { - resp_msg = BT_AVDTP_REJECT; - error_code = BT_AVDTP_ERR_BAD_STATE; - } - resp_buf = avdtp_create_pdu(resp_msg, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_START, rxtid, &pAvdtp_conn->req.cmdtid); - if (!resp_buf) { - return; - } - if (resp_msg != BT_AVDTP_ACCEPT) { - net_buf_add_mem(resp_buf, &error_code, sizeof(error_code)); - } else { - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_STREAMING; - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_STARTED; - } - if (pAvdtp_conn->pending_ahead_start) { - if (pAvdtp_conn->pending_resp_buf) { - net_buf_unref(pAvdtp_conn->pending_resp_buf); - } - pAvdtp_conn->pending_resp_buf = resp_buf; - } else { - avdtp_send(session, resp_buf); - } - } else if (msg_type == BT_AVDTP_ACCEPT) { - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_STREAMING; - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_STARTED; - event_cb->media_state_req(session, BT_AVDTP_START); - } else { - /* Reject: what todo? */ - } -} -static void avdtp_close_handle(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t rxtid) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - if (avdtp_check_cmd_format(session, buf, BT_AVDTP_CLOSE, rxtid, NULL)) { - return; - } - /* avdtp_check_cmd_format have check seid exist */ - lsep_set_seid_free(buf->data[0] >> 2); - if (avdtp_send_accept_resp(session, BT_AVDTP_CLOSE, rxtid) > 0) { - event_cb->media_state_req(session, BT_AVDTP_CLOSE); - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_CLOSED; - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_CLOSEED; - } - } else if (msg_type == BT_AVDTP_ACCEPT) { - lsep_set_seid_free(pAvdtp_conn->stream.lsid.id); - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_CLOSED; - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_CLOSEED; - event_cb->media_state_req(session, BT_AVDTP_CLOSE); - } else { - /* Reject: what todo? */ - } -} -static void avdtp_suspend_handle(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t rxtid) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - if (avdtp_check_cmd_format(session, buf, BT_AVDTP_SUSPEND, rxtid, NULL)) { - return; - } - if (avdtp_send_accept_resp(session, BT_AVDTP_SUSPEND, rxtid) > 0) { - event_cb->media_state_req(session, BT_AVDTP_SUSPEND); - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_SUSPEND; - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_SUSPENDED; - } - } else if (msg_type == BT_AVDTP_ACCEPT) { - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_SUSPEND; - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_SUSPENDED; - event_cb->media_state_req(session, BT_AVDTP_SUSPEND); - } else { - /* Reject: what todo? */ - } -} -static void avdtp_abort_handle(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t rxtid) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG("msg_type %d", msg_type); - if (msg_type == BT_AVDTP_CMD) { - if (avdtp_check_cmd_format(session, buf, BT_AVDTP_ABORT, rxtid, NULL)) { - return; - } - if (avdtp_send_accept_resp(session, BT_AVDTP_ABORT, rxtid) > 0) { - event_cb->media_state_req(session, BT_AVDTP_ABORT); - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_ABORTING; - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_ABORTED; - } - } else if (msg_type == BT_AVDTP_ACCEPT) { - pAvdtp_conn->stream.stream_state = BT_AVDTP_STREAM_STATE_ABORTING; - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_ABORTED; - event_cb->media_state_req(session, BT_AVDTP_ABORT); - } else { - /* Reject: what todo? */ - } -} -struct avdtp_signaling_handler { - uint8_t sig_id; - void (*func)(struct bt_avdtp *session, struct net_buf *buf, - uint8_t msg_type, uint8_t rxtid); -}; -static const struct avdtp_signaling_handler handler[] = { - { BT_AVDTP_DISCOVER, avdtp_discover_handle }, - { BT_AVDTP_GET_CAPABILITIES, avdtp_get_capabilities_handle }, - { BT_AVDTP_GET_ALL_CAPABILITIES, avdtp_get_all_capabilities_handle }, - { BT_AVDTP_SET_CONFIGURATION, avdtp_set_configuration_handle }, - { BT_AVDTP_RECONFIGURE, avdtp_reconfigure_handle }, - { BT_AVDTP_OPEN, avdtp_open_handle }, - { BT_AVDTP_START, avdtp_start_handle }, - { BT_AVDTP_CLOSE, avdtp_close_handle }, - { BT_AVDTP_SUSPEND, avdtp_suspend_handle }, - { BT_AVDTP_ABORT, avdtp_abort_handle }, -}; -/* Send failed, response to unref buf */ -static int avdtp_send(struct bt_avdtp *session, struct net_buf *buf) -{ - int result; - struct bt_avdtp_single_sig_hdr hdr; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - memcpy(&hdr, buf->data, sizeof(struct bt_avdtp_single_sig_hdr)); - avdtp_log("avdtp send sig:0x%x, msg:%d\n", AVDTP_GET_SIG_ID(hdr.signal_id), AVDTP_GET_MSG_TYPE(hdr.hdr)); - result = bt_l2cap_chan_send(&session->br_chan.chan, buf); - if (result < 0) { - net_buf_unref(buf); - LOG_ERR("Error:L2CAP send fail - result = %d", result); - return result; - } - if (AVDTP_GET_MSG_TYPE(hdr.hdr) == BT_AVDTP_CMD) { - /* Not replase session->req */ - pAvdtp_conn->req.sig = AVDTP_GET_SIG_ID(hdr.signal_id); - pAvdtp_conn->req.tid = AVDTP_GET_TR_ID(hdr.hdr); - pAvdtp_conn->req.func = bt_avdtp_send_timeout_handler; - /* Send command, Start timeout work */ - k_work_schedule(&pAvdtp_conn->req.timeout_work, AVDTP_TIMEOUT); - pAvdtp_conn->stream.int_state = BT_AVDTP_SIG_ID_TO_STATE_ING(pAvdtp_conn->req.sig); - } - return result; -} -static struct net_buf *avdtp_create_pdu(uint8_t msg_type, - uint8_t pkt_type, uint8_t sig_id, uint8_t rxtid, uint8_t *cmdtid) -{ - struct net_buf *buf; - struct bt_avdtp_single_sig_hdr *hdr; - LOG_DBG(""); - buf = bt_l2cap_create_pdu(NULL, 0); - if (!buf) { - LOG_ERR("Can't get buf for msg_type:%d, sig_id:%d", msg_type, sig_id); - return buf; - } - hdr = net_buf_add(buf, sizeof(*hdr)); - hdr->hdr = (msg_type | pkt_type << AVDTP_PKT_POSITION | - ((msg_type == BT_AVDTP_CMD) ? *cmdtid : rxtid) << AVDTP_TID_POSITION); - hdr->signal_id = sig_id & AVDTP_SIGID_MASK; - if (msg_type == BT_AVDTP_CMD) { - (*cmdtid) += 1; - (*cmdtid) %= 16; /* Loop for 16*/ - } - LOG_DBG("hdr = 0x%02X, Signal_ID = 0x%02X", hdr->hdr, hdr->signal_id); - return buf; -} -/* Timeout handler */ -static void avdtp_timeout(struct k_work *work) -{ - struct bt_avdtp_req *req = AVDTP_KWORK(work); - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_REQ(req); - LOG_DBG("Failed Signal_id = %d", req->sig); - if (req->func) { - req->func(&pAvdtp_conn->signal_session, req); - } -} -static void avdtp_state_sm_work(struct bt_avdtp_req *req) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_REQ(req); - if (req->state_sm_func) { - req->state_sm_func(&pAvdtp_conn->signal_session, req); - } -} -/* L2CAP Interface callbacks */ -void bt_avdtp_l2cap_connected(struct bt_l2cap_chan *chan) -{ - struct bt_avdtp *session; - struct bt_avdtp_conn *pAvdtp_conn; - if (!chan) { - LOG_ERR("Invalid AVDTP chan"); - return; - } - session = AVDTP_CHAN(chan); - LOG_DBG("chan %p session %p", chan, session); - if (session->session_priority == BT_AVDTP_SIGNALING_SESSION) { - pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - pAvdtp_conn->stream.acp_state = BT_AVDTP_ACPINT_STATE_IDLE; - pAvdtp_conn->stream.int_state = BT_AVDTP_ACPINT_STATE_IDLE; - if (session->role == BT_A2DP_CH_SOURCE) { - pAvdtp_conn->stream.lsid.tsep = BT_A2DP_EP_SOURCE; - } else if (session->role == BT_A2DP_CH_SINK) { - pAvdtp_conn->stream.lsid.tsep = BT_A2DP_EP_SINK; - } - /* Init the timer */ - k_work_init_delayable(&pAvdtp_conn->req.timeout_work, avdtp_timeout); - pAvdtp_conn->req.state_sm_func = bt_avdtp_state_sm; - } - session->connected = 1; - avdtp_log("avdtp connected:%d\n", session->session_priority); - event_cb->connected(session); - if (session->session_priority == BT_AVDTP_MEDIA_SESSION) { - pAvdtp_conn = AVDTP_CONN_BY_MEDIA(session); - if (pAvdtp_conn->pending_ahead_start) { - pAvdtp_conn->pending_ahead_start = 0; - if (pAvdtp_conn->pending_resp_buf) { - avdtp_send(&pAvdtp_conn->signal_session, pAvdtp_conn->pending_resp_buf); - pAvdtp_conn->pending_resp_buf = NULL; - event_cb->media_state_req(&pAvdtp_conn->signal_session, BT_AVDTP_PENDING_AHEAD_START); - } - } - } -} -void bt_avdtp_l2cap_disconnected(struct bt_l2cap_chan *chan) -{ - struct bt_avdtp *session = AVDTP_CHAN(chan); - struct bt_avdtp_conn *pAvdtp_conn; - avdtp_log("avdtp disconnected:%d\n", session->session_priority); - event_cb->disconnected(session); - LOG_DBG("chan %p session %p", chan, session); - session->br_chan.chan.conn = NULL; - if ((session->session_priority == BT_AVDTP_SIGNALING_SESSION) && - session->connected) { - pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - /* Only need free stream after connected */ - lsep_set_seid_free(pAvdtp_conn->stream.lsid.id); - /* Clear the Pending req if set*/ - k_work_cancel_delayable(&pAvdtp_conn->req.timeout_work); - pAvdtp_conn->req.state_sm_func = NULL; - pAvdtp_conn->pending_ahead_start = 0; - if (pAvdtp_conn->pending_resp_buf) { - net_buf_unref(pAvdtp_conn->pending_resp_buf); - pAvdtp_conn->pending_resp_buf = NULL; - } - } - session->connected = 0; -} -void bt_avdtp_l2cap_encrypt_changed(struct bt_l2cap_chan *chan, uint8_t status) -{ - LOG_DBG(""); -} -static int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) -{ - struct bt_avdtp_single_sig_hdr *hdr = (void *)buf->data; - struct bt_avdtp *session = AVDTP_CHAN(chan); - uint8_t i, msgtype, sigid, tid; - struct bt_avdtp_conn *pAvdtp_conn; - if (session->session_priority == BT_AVDTP_MEDIA_SESSION) { - event_cb->media_handler(session, buf); - return 0; - } - pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if (buf->len < sizeof(*hdr)) { - LOG_ERR("Recvd Wrong AVDTP Header"); - return -EINVAL; - } - msgtype = AVDTP_GET_MSG_TYPE(hdr->hdr); - sigid = AVDTP_GET_SIG_ID(hdr->signal_id); - tid = AVDTP_GET_TR_ID(hdr->hdr); - LOG_DBG("msg_type[0x%02x] sig_id[0x%02x] tid[0x%02x]", - msgtype, sigid, tid); - net_buf_pull(buf, sizeof(*hdr)); - /* validate if there is an outstanding resp expected*/ - if (msgtype != BT_AVDTP_CMD) { - if (pAvdtp_conn->req.sig != sigid || - pAvdtp_conn->req.tid != tid) { - avdtp_log("Peer mismatch resp, expected sig[0x%02x]" - "tid[0x%02x] sigid[0x%02x] tid[0x%02x]", pAvdtp_conn->req.sig, - pAvdtp_conn->req.tid, sigid, tid); - return -EINVAL; - } - /* Get responed, cancel delay work */ - k_work_cancel_delayable(&pAvdtp_conn->req.timeout_work); - pAvdtp_conn->req.msg_type = msgtype; - } - avdtp_log("avdtp rcv sig:0x%x, msg:%d\n", sigid, msgtype); - for (i = 0; i < ARRAY_SIZE(handler); i++) { - if (sigid == handler[i].sig_id) { - handler[i].func(session, buf, msgtype, tid); - if (msgtype != BT_AVDTP_CMD) { - avdtp_state_sm_work(&pAvdtp_conn->req); - } - return 0; - } - } - if (msgtype == BT_AVDTP_CMD && - (sigid == 0 || sigid > BT_AVDTP_DELAYREPORT)) {/*invalid sigid */ - struct net_buf *resp_buf; - struct bt_avdtp_single_sig_hdr *hdr; - resp_buf = bt_l2cap_create_pdu(NULL, 0); - if (!resp_buf) { - return 0; - } - hdr = net_buf_add(resp_buf, sizeof(*hdr)); - hdr->hdr = BT_AVDTP_GEN_REJECT | 0 << AVDTP_PKT_POSITION | - (tid << AVDTP_TID_POSITION); - hdr->signal_id = sigid & AVDTP_SIGID_MASK; - avdtp_send(session, resp_buf); - } - return 0; -} -static bool bt_avdtp_is_media_aac_codec(struct bt_avdtp *session) -{ - struct bt_avdtp_conn *pAvdtp_conn; - struct bt_a2dp_media_codec *codec; - if (session->session_priority != BT_AVDTP_MEDIA_SESSION) { - return false; - } - pAvdtp_conn = AVDTP_CONN_BY_MEDIA(session); - codec = &pAvdtp_conn->stream.codec; - if (codec == NULL) { - return false; - } - if (codec->head.codec_type == BT_A2DP_MPEG2) { - return true; - } else { - return false; - } -} -/*A2DP Layer interface */ -int bt_avdtp_connect(struct bt_conn *conn, struct bt_avdtp *session, uint8_t role) -{ - 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->role = role; - session->intacp_role = BT_AVDTP_INT; - session->br_chan.chan.ops = (struct bt_l2cap_chan_ops *)&ops; - session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; - return bt_l2cap_chan_connect(conn, &session->br_chan.chan, - BT_L2CAP_PSM_AVDTP); -} -int bt_avdtp_disconnect(struct bt_avdtp *session) -{ - if (!session) { - return -EINVAL; - } - LOG_DBG("session %p", session); - return bt_l2cap_chan_disconnect(&session->br_chan.chan); -} -int bt_avdtp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server, - struct bt_l2cap_chan **chan) -{ - struct bt_avdtp *session = NULL; - int result; - static const struct bt_l2cap_chan_ops ops = { - .connected = bt_avdtp_l2cap_connected, - .disconnected = bt_avdtp_l2cap_disconnected, - .recv = bt_avdtp_l2cap_recv, - }; - LOG_DBG("conn %p", conn); - /* Get the AVDTP session from upper layer */ - result = event_cb->accept(conn, &session); - if (result < 0) { - return result; - } - session->br_chan.chan.ops = (struct bt_l2cap_chan_ops *)&ops; - session->br_chan.rx.mtu = BT_L2CAP_RX_MTU; - *chan = &session->br_chan.chan; - return 0; -} -/* Application will register its callback */ -int bt_avdtp_register(struct bt_avdtp_event_cb *cb) -{ - LOG_DBG(""); - if (event_cb) { - return -EALREADY; - } - event_cb = cb; - return 0; -} -static void bt_avdtp_env_init(void) -{ - event_cb = NULL; - bt_avdtp_ep_env_init(); -} -/* init function */ -int bt_avdtp_init(void) -{ - int err; - static struct bt_l2cap_server avdtp_l2cap = { - .psm = BT_L2CAP_PSM_AVDTP, - .sec_level = BT_SECURITY_L2, - .accept = bt_avdtp_l2cap_accept, - }; - LOG_DBG(""); - bt_avdtp_env_init(); - /* Register AVDTP PSM with L2CAP */ - err = bt_l2cap_br_server_register(&avdtp_l2cap); - if (err < 0) { - LOG_ERR("AVDTP L2CAP Registration failed %d", err); - } - return err; -} -/* AVDTP Discover Request */ -int bt_avdtp_discover(struct bt_avdtp *session) -{ - struct net_buf *buf; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG(""); - if (!session) { - LOG_DBG("Error: Callback/Session not valid"); - return -EINVAL; - } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_DISCOVER, 0, &pAvdtp_conn->req.cmdtid); - if (!buf) { - return -ENOMEM; - } - return avdtp_send(session, buf); -} -static int bt_avdtp_req_cmd_seid(struct bt_avdtp *session, uint8_t sig_id) -{ - struct net_buf *buf; - struct bt_avdtp_get_capabilities_req req; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG(""); - if (!session || !session->connected) { - LOG_ERR("Error: Session not valid or stream is NULL"); - return -EINVAL; - } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - sig_id, 0, &pAvdtp_conn->req.cmdtid); - if (!buf) { - return -ENOMEM; - } - req.rfa0 = 0; - req.seid = pAvdtp_conn->stream.rsid.id; - net_buf_add_mem(buf, &req, sizeof(struct bt_avdtp_get_capabilities_req)); - return avdtp_send(session, buf); -} -static int bt_avdtp_get_cap_cmd(struct bt_avdtp *session, uint8_t sig_id) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if (pAvdtp_conn->get_rsid_cap_index >= pAvdtp_conn->get_seid_num) { - /* Do a2dp disconnect */ - avdtp_log("avdtp get cap mismatch disconnect\n"); - event_cb->intiator_connect_result(session, false); - return -EIO; - } - memcpy(&pAvdtp_conn->stream.rsid, &pAvdtp_conn->get_seid[pAvdtp_conn->get_rsid_cap_index], sizeof(struct bt_avdtp_seid_info)); - pAvdtp_conn->get_rsid_cap_index++; - return bt_avdtp_req_cmd_seid(session, sig_id); -} -int bt_avdtp_get_capabilities(struct bt_avdtp *session) -{ - return bt_avdtp_get_cap_cmd(session, BT_AVDTP_GET_CAPABILITIES); -} -int bt_avdtp_get_all_capabilities(struct bt_avdtp *session) -{ - return bt_avdtp_get_cap_cmd(session, BT_AVDTP_GET_ALL_CAPABILITIES); -} -static int bt_avdtp_setreset_configuration(struct bt_avdtp *session, uint8_t sig_id, - struct bt_a2dp_media_codec *codec) -{ - struct net_buf *buf; - struct bt_avdtp_setconf_req req; - struct bt_avdtp_cap cap; - struct bt_avdtp_seid_lsep *lsep; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG(""); - if (!session || !session->connected) { - LOG_DBG("Error: Session not valid or stream is NULL"); - return -EINVAL; - } - if ((sig_id == BT_AVDTP_RECONFIGURE) && - (pAvdtp_conn->stream.stream_state != BT_AVDTP_STREAM_STATE_OPEN) && - (pAvdtp_conn->stream.stream_state != BT_AVDTP_STREAM_STATE_SUSPEND)) { - return -EACCES; - } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - sig_id, 0, &pAvdtp_conn->req.cmdtid); - if (!buf) { - return -ENOMEM; - } - if (!pAvdtp_conn->stream.lsid.id) { - uint8_t local_role; - if (pAvdtp_conn->stream.rsid.tsep == BT_A2DP_EP_SINK) - local_role = BT_A2DP_EP_SOURCE; - else - local_role = BT_A2DP_EP_SINK; - lsep = find_free_lsep_by_role_codectype(local_role, pAvdtp_conn->stream.codec.head.codec_type); - if (lsep) - pAvdtp_conn->stream.lsid.id = lsep->sid.id; - } - /* Add acp int id */ - memset(&req, 0, sizeof(struct bt_avdtp_setconf_req)); - req.acp_seid = pAvdtp_conn->stream.rsid.id; - req.int_seid = pAvdtp_conn->stream.lsid.id; - if (sig_id == BT_AVDTP_RECONFIGURE) { - /* Reconfigure only need acp seid */ - net_buf_add_mem(buf, &req, sizeof(struct bt_avdtp_reconf_req)); - } else { - net_buf_add_mem(buf, &req, sizeof(struct bt_avdtp_setconf_req)); - } - if (sig_id == BT_AVDTP_SET_CONFIGURATION) { - /* Add BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT */ - cap.cat = BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT; - cap.len = 0; - net_buf_add_mem(buf, &cap, sizeof(struct bt_avdtp_cap)); - } - /* Add BT_AVDTP_SERVICE_CAT_MEDIA_CODEC */ - cap.cat = BT_AVDTP_SERVICE_CAT_MEDIA_CODEC; - if (sig_id == BT_AVDTP_SET_CONFIGURATION) { - cap.len = bt_avdtp_ep_get_codec_len(&pAvdtp_conn->stream.codec); - } else { - cap.len = bt_avdtp_ep_get_codec_len(codec); - memcpy(&pAvdtp_conn->stream.codec, codec, cap.len); - } - net_buf_add_mem(buf, &cap, sizeof(struct bt_avdtp_cap)); - /* Add codec */ - if (cap.len) { - net_buf_add_mem(buf, &pAvdtp_conn->stream.codec, cap.len); - } - /* Add content protection type */ - if (pAvdtp_conn->stream.cp_type == BT_AVDTP_AV_CP_TYPE_SCMS_T) { - cap.cat = BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION; - cap.len = 2; - net_buf_add_mem(buf, &cap, sizeof(struct bt_avdtp_cap)); - net_buf_add_le16(buf, BT_AVDTP_AV_CP_TYPE_SCMS_T); - } - /* Add delay report */ - if (pAvdtp_conn->stream.delay_report) { - cap.cat = BT_AVDTP_SERVICE_CAT_DELAYREPORTING; - cap.len = 2; - net_buf_add_mem(buf, &cap, sizeof(struct bt_avdtp_cap)); - } - return avdtp_send(session, buf); -} -int bt_avdtp_set_configuration(struct bt_avdtp *session) -{ - return bt_avdtp_setreset_configuration(session, BT_AVDTP_SET_CONFIGURATION, NULL); -} -int bt_avdtp_reconfig(struct bt_avdtp *session, struct bt_a2dp_media_codec *codec) -{ - return bt_avdtp_setreset_configuration(session, BT_AVDTP_RECONFIGURE, codec); -} -int bt_avdtp_open(struct bt_avdtp *session) -{ - return bt_avdtp_req_cmd_seid(session, BT_AVDTP_OPEN); -} -int bt_avdtp_start(struct bt_avdtp *session) -{ - return bt_avdtp_req_cmd_seid(session, BT_AVDTP_START); -} -int bt_avdtp_suspend(struct bt_avdtp *session) -{ - return bt_avdtp_req_cmd_seid(session, BT_AVDTP_SUSPEND); -} -int bt_avdtp_close(struct bt_avdtp *session) -{ - return bt_avdtp_req_cmd_seid(session, BT_AVDTP_CLOSE); -} -int bt_avdtp_abort(struct bt_avdtp *session) -{ - return bt_avdtp_req_cmd_seid(session, BT_AVDTP_ABORT); -} -/* delay_time: 1/10 milliseconds */ -int bt_avdtp_delayreport(struct bt_avdtp *session, uint16_t delay_time) -{ - struct net_buf *buf; - struct bt_avdtp_get_capabilities_req req; - uint8_t time[2]; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - LOG_DBG(""); - if (!session || !session->connected) { - LOG_DBG("Error: Session not valid or stream is NULL"); - return -EINVAL; - } - if (!pAvdtp_conn->stream.delay_report) { - return -EIO; - } - buf = avdtp_create_pdu(BT_AVDTP_CMD, - BT_AVDTP_PACKET_TYPE_SINGLE, - BT_AVDTP_DELAYREPORT, 0, &pAvdtp_conn->req.cmdtid); - if (!buf) { - return -ENOMEM; - } - req.rfa0 = 0; - req.seid = pAvdtp_conn->stream.rsid.id; - net_buf_add_mem(buf, &req, sizeof(struct bt_avdtp_get_capabilities_req)); - time[0] = (delay_time >> 8)&0xFF; - time[1] = delay_time&0xFF; - net_buf_add_mem(buf, time, sizeof(time)); - return avdtp_send(session, buf); -} -static int bt_avdtp_send_timeout_handler(struct bt_avdtp *session, - struct bt_avdtp_req *req) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - avdtp_log("avdtp send timeout state:0x%x, sig:0x%x\n", pAvdtp_conn->stream.int_state, req->sig); - if (BT_AVDTP_IS_ACPINT_STATE_ING(pAvdtp_conn->stream.int_state) && - (pAvdtp_conn->stream.stream_state < BT_AVDTP_STREAM_STATE_OPEN)) { - /* Do a2dp disconnect */ - avdtp_log("avdtp send timeout disconnect\n"); - event_cb->intiator_connect_result(session, false); - } - return 0; -} -static int bt_avdtp_state_sm(struct bt_avdtp *session, struct bt_avdtp_req *req) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if ((pAvdtp_conn->stream.int_state != BT_AVDTP_ACPINT_STATE_OPENED) && - (pAvdtp_conn->stream.int_state != BT_AVDTP_ACPINT_STATE_RECFGED) && - (pAvdtp_conn->stream.acp_state >= BT_AVDTP_ACPINT_STATE_SET_CFGED)) { - /* If pair device start avdtp as initiator, and we not recieve open accept, change us to acceptor */ - avdtp_log("avdtp sm change to acp\n"); - session->intacp_role = BT_AVDTP_ACP; - } - if (session->intacp_role != BT_AVDTP_INT) { - /* Not as initiator role, do nothing */ - avdtp_log("avdtp sm acp role\n"); - return 0; - } - if (BT_AVDTP_IS_ACPINT_STATE_ING(pAvdtp_conn->stream.int_state) && - (pAvdtp_conn->stream.stream_state < BT_AVDTP_STREAM_STATE_OPEN)) { - /* Do a2dp disconnect */ - avdtp_log("avdtp sm cmd not accecpt int_state:0x%x, sig:0x%x\n", pAvdtp_conn->stream.int_state, req->sig); - event_cb->intiator_connect_result(session, false); - return 0; - } - avdtp_log("avdtp sm state:0x%x\n", pAvdtp_conn->stream.int_state); - switch (pAvdtp_conn->stream.int_state) { - case BT_AVDTP_ACPINT_STATE_DISCOVERED: - case BT_AVDTP_ACPINT_STATE_GET_CAPEXT: - bt_avdtp_get_capabilities(session); - break; - case BT_AVDTP_ACPINT_STATE_GET_ACFGEXT: - bt_avdtp_get_all_capabilities(session); - break; - case BT_AVDTP_ACPINT_STATE_GET_CAPED: - if ((session->role == BT_A2DP_CH_SOURCE) - || (session->role == BT_A2DP_CH_SINK)) { - if (find_free_lsep_by_role_codectype(pAvdtp_conn->stream.lsid.tsep, - pAvdtp_conn->stream.codec.head.codec_type)) { - bt_avdtp_set_configuration(session); - } - } - break; - case BT_AVDTP_ACPINT_STATE_SET_CFGED: - if (pAvdtp_conn->stream.stream_state < BT_AVDTP_STREAM_STATE_OPEN) { - bt_avdtp_open(session); - } - break; - case BT_AVDTP_ACPINT_STATE_OPENED: - event_cb->do_media_connect(session, true); - break; - case BT_AVDTP_ACPINT_STATE_CLOSEED: - event_cb->do_media_connect(session, false); - break; - } - return 0; -} -struct bt_a2dp_media_codec *bt_avdtp_get_seted_codec(struct bt_avdtp *session) -{ - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - switch (pAvdtp_conn->stream.stream_state) { - case BT_AVDTP_STREAM_STATE_OPEN: - case BT_AVDTP_STREAM_STATE_STREAMING: - case BT_AVDTP_STREAM_STATE_SUSPEND: - return &pAvdtp_conn->stream.codec; - default: - break; - } - return NULL; -} diff --git a/subsys/bluetooth/host/classic/zephyr3/avdtp_ep.c b/subsys/bluetooth/host/classic/zephyr3/avdtp_ep.c deleted file mode 100644 index 957b15902fb..00000000000 --- a/subsys/bluetooth/host/classic/zephyr3/avdtp_ep.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Audio Video Distribution Protocol - * - * SPDX-License-Identifier: Apache-2.0 - * - */ -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_AVDTP) -#define LOG_MODULE_NAME bt_avdtp_ep -#include -#include "host/hci_core.h" -#include "host/conn_internal.h" -#include "host/classic/l2cap_br_internal.h" -#include "avdtp_internal.h" -#include -#include -#define AVDTP_EP_DEBUG_LOG 1 -#if AVDTP_EP_DEBUG_LOG -#define avdtp_ep_log(fmt, ...) printk(fmt, ##__VA_ARGS__) -#else -#define avdtp_ep_log(fmt, ...) -#endif -#define BT_AVDTP_MIN_SEID 0x01 -#define BT_AVDTP_MAX_SEID 0x3E -static uint8_t bt_avdtp_seid = BT_AVDTP_MIN_SEID; -static struct bt_avdtp_seid_lsep *lseps; -#define LSEP_FOREACH(lsep) \ - for ((lsep) = (lseps); (lsep); (lsep) = (lsep)->next) -bool bt_avdtp_ep_empty(void) -{ - return (lseps == NULL) ? true : false; -} -struct bt_avdtp_seid_lsep *find_lsep_by_seid(uint8_t seid) -{ - struct bt_avdtp_seid_lsep *lsep; - LSEP_FOREACH(lsep) { - if (lsep->sid.id == seid) - return lsep; - } - return NULL; -} -struct bt_avdtp_seid_lsep *find_free_lsep_by_role(uint8_t role) -{ - struct bt_avdtp_seid_lsep *lsep; - LSEP_FOREACH(lsep) { - if ((lsep->sid.tsep == role) && (!lsep->sid.inuse) && (!lsep->ep_halt)) - return lsep; - } - return NULL; -} -struct bt_avdtp_seid_lsep *find_free_lsep_by_role_codectype(uint8_t role, uint8_t codectype) -{ - struct bt_avdtp_seid_lsep *lsep; - LSEP_FOREACH(lsep) { - if ((lsep->sid.tsep == role) && - (lsep->codec->head.codec_type == codectype) && - (!lsep->sid.inuse) && (!lsep->ep_halt)) - return lsep; - } - return NULL; -} -bool lsep_seid_inused(uint8_t seid) -{ - struct bt_avdtp_seid_lsep *lsep; - LSEP_FOREACH(lsep) { - if (lsep->sid.id == seid) - return (lsep->sid.inuse) ? true : false; - } - return false; -} -bool lsep_set_seid_used_by_seid(uint8_t seid, struct bt_avdtp_stream *stream) -{ - struct bt_avdtp_seid_lsep *lsep; - lsep = find_lsep_by_seid(seid); - if (lsep) { - lsep->sid.inuse = 1; - stream->lsid.id = lsep->sid.id; - stream->lsid.tsep = lsep->sid.tsep; - return true; - } - return false; -} -bool lsep_set_seid_used_by_stream(struct bt_avdtp_stream *stream) -{ - struct bt_avdtp_seid_lsep *lsep; - LSEP_FOREACH(lsep) { - if ((!lsep->sid.inuse) && (!lsep->ep_halt) && - (lsep->sid.tsep == stream->lsid.tsep) && - (lsep->codec->head.codec_type == stream->codec.head.codec_type)) { - lsep->sid.inuse = 1; - stream->lsid.id = lsep->sid.id; - return true; - } - } - return false; -} -void lsep_set_seid_free(uint8_t seid) -{ - struct bt_avdtp_seid_lsep *lsep; - lsep = find_lsep_by_seid(seid); - if (lsep) { - lsep->sid.inuse = 0; - } -} -static int find_cap_codec(const uint8_t *data, uint8_t len, - struct bt_a2dp_media_codec **codec) -{ - struct bt_avdtp_cap *cap; - uint8_t i; - for (i = 0; i < len; ) { - cap = (struct bt_avdtp_cap *)&data[i]; - if (cap->cat == BT_AVDTP_SERVICE_CAT_MEDIA_CODEC) { - *codec = (struct bt_a2dp_media_codec *)cap->data; - return 0; - } - i += cap->len + 2; - } - return -EEXIST; -} -static int check_local_remote_codec_sbc(struct bt_a2dp_media_codec *lcodec, - struct bt_a2dp_media_codec *rcodec, - struct bt_a2dp_media_codec *setcodec, uint8_t sig_id) -{ - uint8_t bit_map; - if (!((lcodec->sbc.channel_mode & rcodec->sbc.channel_mode) && - (lcodec->sbc.freq & rcodec->sbc.freq) && - (lcodec->sbc.alloc_method & rcodec->sbc.alloc_method) && - (lcodec->sbc.subbands & rcodec->sbc.subbands) && - (lcodec->sbc.block_len & rcodec->sbc.block_len))) { - return -BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION; - } - /* Need compare bitpool ?? */ - if (sig_id == BT_AVDTP_SET_CONFIGURATION || - sig_id == BT_AVDTP_RECONFIGURE) { - if (rcodec->sbc.min_bitpool < lcodec->sbc.min_bitpool || - rcodec->sbc.max_bitpool > lcodec->sbc.max_bitpool) { - return -BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION; - } - } - if (!setcodec) { - return 0; - } - memset(setcodec, 0, sizeof(struct bt_a2dp_media_codec)); - setcodec->sbc.media_type = rcodec->sbc.media_type; - setcodec->sbc.codec_type = rcodec->sbc.codec_type; - bit_map = lcodec->sbc.freq & rcodec->sbc.freq; - if (bit_map & BT_A2DP_SBC_44100) { - setcodec->sbc.freq = BT_A2DP_SBC_44100; - } else if (bit_map & BT_A2DP_SBC_48000) { - setcodec->sbc.freq = BT_A2DP_SBC_48000; - } else if (bit_map & BT_A2DP_SBC_32000) { - setcodec->sbc.freq = BT_A2DP_SBC_32000; - } else { - setcodec->sbc.freq = BT_A2DP_SBC_16000; - } - bit_map = lcodec->sbc.channel_mode & rcodec->sbc.channel_mode; - if (bit_map & BT_A2DP_SBC_JOINT_STEREO) { - setcodec->sbc.channel_mode = BT_A2DP_SBC_JOINT_STEREO; - } else if (bit_map & BT_A2DP_SBC_STEREO) { - setcodec->sbc.channel_mode = BT_A2DP_SBC_STEREO; - } else if (bit_map & BT_A2DP_SBC_DUAL_CHANNEL) { - setcodec->sbc.channel_mode = BT_A2DP_SBC_DUAL_CHANNEL; - } else { - setcodec->sbc.channel_mode = BT_A2DP_SBC_MONO; - } - bit_map = lcodec->sbc.block_len & rcodec->sbc.block_len; - if (bit_map & BT_A2DP_SBC_BLOCK_LENGTH_16) { - setcodec->sbc.block_len = BT_A2DP_SBC_BLOCK_LENGTH_16; - } else if (bit_map & BT_A2DP_SBC_BLOCK_LENGTH_12) { - setcodec->sbc.block_len = BT_A2DP_SBC_BLOCK_LENGTH_12; - } else if (bit_map & BT_A2DP_SBC_BLOCK_LENGTH_8) { - setcodec->sbc.block_len = BT_A2DP_SBC_BLOCK_LENGTH_8; - } else { - setcodec->sbc.block_len = BT_A2DP_SBC_BLOCK_LENGTH_4; - } - bit_map = lcodec->sbc.subbands & rcodec->sbc.subbands; - if (bit_map & BT_A2DP_SBC_SUBBANDS_8) { - setcodec->sbc.subbands = BT_A2DP_SBC_SUBBANDS_8; - } else { - setcodec->sbc.subbands = BT_A2DP_SBC_SUBBANDS_4; - } - bit_map = lcodec->sbc.alloc_method & rcodec->sbc.alloc_method; - if (bit_map & BT_A2DP_SBC_ALLOCATION_METHOD_LOUDNESS) { - setcodec->sbc.alloc_method = BT_A2DP_SBC_ALLOCATION_METHOD_LOUDNESS; - } else { - setcodec->sbc.alloc_method = BT_A2DP_SBC_ALLOCATION_METHOD_SNR; - } - setcodec->sbc.min_bitpool = MAX(rcodec->sbc.min_bitpool, lcodec->sbc.min_bitpool); - setcodec->sbc.max_bitpool = MIN(rcodec->sbc.max_bitpool, lcodec->sbc.max_bitpool); - return 0; -} -static int cal_bitmap_bits(uint32_t bitmap, uint8_t bit_len) -{ - int i, bits = 0; - for (i=0; (i<32 && iaac.freq0 << 4) | lcodec->aac.freq1; - Rfreq = (rcodec->aac.freq0 << 4) | rcodec->aac.freq1; - Lbitrate = (lcodec->aac.bit_rate0 << 16) | (lcodec->aac.bit_rate1 << 8) | lcodec->aac.bit_rate2; - Rbitrate = (rcodec->aac.bit_rate0 << 16) | (rcodec->aac.bit_rate1 << 8) | rcodec->aac.bit_rate2; - check_bitrate = 1; - if (!get_cap_rsp) { - if (lcodec->aac.vbr == 0) { - if (rcodec->aac.vbr == 0) { - check_bitrate = 1; - } else { - check_bitrate = 0; - } - } else { - if (rcodec->aac.vbr == 0) { - check_bitrate = 1; - } else { - check_bitrate = ((~Lbitrate) & Rbitrate) ? 0 : 1; - } - } - } - if (cal_bitmap_bits(Rbitrate, 23) == 0) { - check_bitrate = 0; - } - check_obj = (lcodec->aac.obj_type & rcodec->aac.obj_type) ? 1 : 0; - check_channels = (lcodec->aac.channels & rcodec->aac.channels) ? 1 : 0; - check_freq = (Lfreq & Rfreq) ? 1 : 0; - if (!get_cap_rsp) { - check_obj = (cal_bitmap_bits(rcodec->aac.obj_type, 8) == 1) ? check_obj : 0; - check_channels = (cal_bitmap_bits(rcodec->aac.channels, 2) == 1) ? check_channels : 0; - check_freq = (cal_bitmap_bits(Rfreq, 16) == 1) ? check_freq : 0; - } - if (!(check_obj && check_channels && check_freq && check_bitrate)) { - return -BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION; - } - if (!setcodec) { - return 0; - } - memset(setcodec, 0, sizeof(struct bt_a2dp_media_codec)); - if (!get_cap_rsp) { - memcpy(&setcodec->aac, &rcodec->aac, sizeof(rcodec->aac)); - return 0; - } - setcodec->aac.media_type = rcodec->aac.media_type; - setcodec->aac.codec_type = rcodec->aac.codec_type; - for (i = 0; i < 4; i++) { - if (lcodec->aac.obj_type & rcodec->aac.obj_type & (BT_A2DP_AAC_OBJ_MPEG2_AAC_LC >> i)) { - setcodec->aac.obj_type = (BT_A2DP_AAC_OBJ_MPEG2_AAC_LC >> i); - break; - } - } - if (lcodec->aac.channels & rcodec->aac.channels & BT_A2DP_AAC_CHANNELS_2) { - setcodec->aac.channels = BT_A2DP_AAC_CHANNELS_2; - } else { - setcodec->aac.channels = BT_A2DP_AAC_CHANNELS_1; - } - Lfreq = Lfreq & Rfreq; - for (i = 0; i < 12; i++) { - if (Lfreq & (BT_A2DP_AAC_96000 << i)) { - setcodec->aac.freq0 = ((BT_A2DP_AAC_96000 << i) >> 4) & 0xFF; - setcodec->aac.freq1 = (BT_A2DP_AAC_96000 << i) & 0xF; - break; - } - } - setcodec->aac.vbr = lcodec->aac.vbr & rcodec->aac.vbr; - Lbitrate = Lbitrate & Rbitrate; - setcodec->aac.bit_rate0 = (Lbitrate >> 16) & 0x7F; - setcodec->aac.bit_rate1 = (Lbitrate >> 8) & 0xFF; - setcodec->aac.bit_rate2 = Lbitrate & 0xFF; - return 0; -} -static int check_local_remote_codec(struct bt_a2dp_media_codec *lcodec, - struct bt_a2dp_media_codec *rcodec, - struct bt_a2dp_media_codec *setcodec, uint8_t sig_id) -{ - if (!lcodec || !rcodec || - (lcodec->head.media_type != rcodec->head.media_type) || - (lcodec->head.codec_type != rcodec->head.codec_type)) { - return -BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION; - } - switch (lcodec->head.codec_type) { - case BT_A2DP_SBC: - return check_local_remote_codec_sbc(lcodec, rcodec, setcodec, sig_id); - case BT_A2DP_MPEG2: - return check_local_remote_codec_aac(lcodec, rcodec, setcodec, sig_id); - default: - return -BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION; - } -} -static int check_local_remote_cp_type(struct net_buf *buf, struct bt_avdtp_seid_lsep *lsep, uint8_t *cp_type, uint8_t sig_id) -{ - struct bt_avdtp_cap *cap; - uint8_t i, len, *data, parse_cp_type = BT_AVDTP_AV_CP_TYPE_NONE; - uint16_t rx_cp_type = 0xFFFF; - data = buf->data; - len = buf->len; - for (i = 0; i < len; ) { - cap = (struct bt_avdtp_cap *)&data[i]; - if (cap->cat == BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION) { - rx_cp_type = cap->data[0] | (cap->data[1] << 8); - if (rx_cp_type == BT_AVDTP_AV_CP_TYPE_SCMS_T) { - parse_cp_type = BT_AVDTP_AV_CP_TYPE_SCMS_T; - break; - } - } - i += cap->len + 2; - } - if (rx_cp_type == 0xFFFF && sig_id == BT_AVDTP_RECONFIGURE) { - /* Reconfig command without CAT_CONTENT_PROTECTION - * Not need change cp_type. - */ - return 0; - } - if (parse_cp_type == BT_AVDTP_AV_CP_TYPE_NONE) { - *cp_type = parse_cp_type; - return 0; - } else if (sig_id == BT_AVDTP_SET_CONFIGURATION || - sig_id == BT_AVDTP_RECONFIGURE) { - if (parse_cp_type == BT_AVDTP_AV_CP_TYPE_SCMS_T && lsep->a2dp_cp_scms_t) { - *cp_type = parse_cp_type; - return 0; - } else { - *cp_type = BT_AVDTP_AV_CP_TYPE_NONE; - return -EINVAL; - } - } else { - if (parse_cp_type == BT_AVDTP_AV_CP_TYPE_SCMS_T && lsep->a2dp_cp_scms_t) { - *cp_type = parse_cp_type; - } else { - *cp_type = BT_AVDTP_AV_CP_TYPE_NONE; - } - return 0; - } -} -static uint8_t check_local_remote_delay_report(struct net_buf *buf, struct bt_avdtp_seid_lsep *lsep, - uint8_t sig_id, uint8_t old_delay_report) -{ - struct bt_avdtp_cap *cap; - uint8_t i, len, *data, rx_delay_report = 0; - if (!lsep->a2dp_delay_report) { - return rx_delay_report; - } - data = buf->data; - len = buf->len; - for (i = 0; i < len; ) { - cap = (struct bt_avdtp_cap *)&data[i]; - if (cap->cat == BT_AVDTP_SERVICE_CAT_DELAYREPORTING) { - rx_delay_report = 1; - break; - } - i += cap->len + 2; - } - if (rx_delay_report == 0 && sig_id == BT_AVDTP_RECONFIGURE) { - /* Reconfig command without delay report, - * Not need change delay report. - */ - return old_delay_report; - } - return rx_delay_report; -} -static int bt_avdtp_ep_check_cfg_media_codec(struct bt_a2dp_media_codec *rcodec) -{ - switch (rcodec->head.codec_type) { - case BT_A2DP_SBC: - case BT_A2DP_MPEG2: - break; - case BT_A2DP_MPEG1: - case BT_A2DP_ATRAC: - return -BT_AVDTP_ERR_NOT_SUPPORTED_CODEC_TYPE; - case BT_A2DP_VENDOR: - default: - return -BT_AVDTP_ERR_INVALID_CODEC_TYPE; - }; - if (rcodec->head.codec_type == BT_A2DP_SBC) { - if (cal_bitmap_bits(rcodec->sbc.freq, 4) != 1) { - return -BT_AVDTP_ERR_INVALID_SAMPLING_FREQUENCY; - } else if (cal_bitmap_bits(rcodec->sbc.channel_mode, 4) != 1) { - return -BT_AVDTP_ERR_INVALID_CHANNEL_MODE; - } else if (cal_bitmap_bits(rcodec->sbc.block_len, 4) != 1) { - return -BT_AVDTP_ERR_INVALID_BLOCK_LENGTH; - } else if (cal_bitmap_bits(rcodec->sbc.subbands, 2) != 1) { - return -BT_AVDTP_ERR_INVALID_SUBBANDS; - } else if (cal_bitmap_bits(rcodec->sbc.alloc_method, 2) != 1) { - return -BT_AVDTP_ERR_INVALID_ALLOCATION_METHOD; - } else if (rcodec->sbc.min_bitpool < BT_AVDTP_MIX_BITPOOL || rcodec->sbc.min_bitpool > BT_AVDTP_MAX_BITPOOL) { - return -BT_AVDTP_ERR_INVALID_MINIMUM_BITPOOL_VALUE; - } else if (rcodec->sbc.max_bitpool < BT_AVDTP_MIX_BITPOOL || rcodec->sbc.max_bitpool > BT_AVDTP_MAX_BITPOOL) { - return -BT_AVDTP_ERR_INVALID_MAXIMUM_BITPOOL_VALUE; - } - } - return 0; -} -int bt_avdtp_ep_check_set_codec_cp(struct bt_avdtp *session, struct net_buf *buf, uint8_t acp_seid, uint8_t sig_id) -{ - int ret; - struct bt_avdtp_seid_lsep *lsep; - struct bt_a2dp_media_codec *rcodec; - struct bt_a2dp_media_codec setcodec; - struct bt_avdtp_conn *pAvdtp_conn = AVDTP_CONN_BY_SIGNAL(session); - if (find_cap_codec(buf->data, buf->len, &rcodec)) { - return -BT_AVDTP_ERR_BAD_SERV_CATEGORY; - } - if (sig_id == BT_AVDTP_SET_CONFIGURATION || - sig_id == BT_AVDTP_RECONFIGURE) { - ret = bt_avdtp_ep_check_cfg_media_codec(rcodec); - if (ret) { - return ret; - } - } - if (acp_seid) { - lsep = find_lsep_by_seid(acp_seid); - } else { - lsep = find_free_lsep_by_role_codectype(pAvdtp_conn->stream.lsid.tsep, rcodec->head.codec_type); - } - if (!lsep) { - return -BT_AVDTP_ERR_SEP_IN_USE; - } - if (check_local_remote_codec(lsep->codec, rcodec, &setcodec, sig_id)) { - return -BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION; - } - if (check_local_remote_cp_type(buf, lsep, &pAvdtp_conn->stream.cp_type, sig_id)) { - return -BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION; - } - pAvdtp_conn->stream.delay_report = check_local_remote_delay_report(buf, lsep, sig_id, pAvdtp_conn->stream.delay_report); - memcpy(&pAvdtp_conn->stream.codec, &setcodec, sizeof(struct bt_a2dp_media_codec)); - return 0; -} -void bt_avdtp_ep_append_seid(struct net_buf *resp_buf) -{ - struct bt_avdtp_seid_lsep *lsep; - int add = 0; - LSEP_FOREACH(lsep) { - /* TO DO:macbook may choose inuse seid,so here we don't add inuse seid */ - if (!lsep->sid.inuse && !lsep->ep_halt) { - net_buf_add_mem(resp_buf, &lsep->sid, - sizeof(struct bt_avdtp_seid_info)); - add = 1; - } - } - /* There shall be at least one SEP in an AVDTP_DISCOVER_RSP - * AVDTP spec 8.6.2 - */ - if (!add) { - LSEP_FOREACH(lsep) { - if (!lsep->ep_halt) { - net_buf_add_mem(resp_buf, &lsep->sid, - sizeof(struct bt_avdtp_seid_info)); - } - } - } -} -void bt_avdtp_ep_append_capabilities(struct net_buf *resp_buf, uint8_t reqSeid) -{ - struct bt_avdtp_cap cap; - struct bt_avdtp_seid_lsep *lsep = find_lsep_by_seid(reqSeid); /* Run to here, lsep exist */ - uint8_t codec_len; - /* Add MEDIA_TRANSPORT */ - cap.cat = BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT; - cap.len = 0; - net_buf_add_mem(resp_buf, &cap, sizeof(struct bt_avdtp_cap)); - /* Add MEDIA_CODEC */ - if (lsep->codec->head.codec_type == BT_A2DP_SBC) { - codec_len = sizeof(struct bt_a2dp_media_sbc_codec); - } else if (lsep->codec->head.codec_type == BT_A2DP_MPEG2) { - codec_len = sizeof(struct bt_a2dp_media_aac_codec); - } else { - codec_len = 0; - } - cap.cat = BT_AVDTP_SERVICE_CAT_MEDIA_CODEC; - cap.len = codec_len; - net_buf_add_mem(resp_buf, &cap, sizeof(struct bt_avdtp_cap)); - if (codec_len) { - net_buf_add_mem(resp_buf, (const void *)lsep->codec, codec_len); - } - /* Add content protection SCMS-T */ - if (lsep->a2dp_cp_scms_t) { - cap.cat = BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION; - cap.len = 2; - net_buf_add_mem(resp_buf, &cap, sizeof(struct bt_avdtp_cap)); - net_buf_add_le16(resp_buf, BT_AVDTP_AV_CP_TYPE_SCMS_T); - } - /* Add Delay Reporting Capabilities */ - if (lsep->a2dp_delay_report) { - cap.cat = BT_AVDTP_SERVICE_CAT_DELAYREPORTING; - cap.len = 0; - net_buf_add_mem(resp_buf, &cap, sizeof(struct bt_avdtp_cap)); - } -} -uint8_t bt_avdtp_ep_get_codec_len(struct bt_a2dp_media_codec *codec) -{ - switch (codec->head.codec_type) { - case BT_A2DP_SBC: - return sizeof(struct bt_a2dp_media_sbc_codec); - case BT_A2DP_MPEG2: - return sizeof(struct bt_a2dp_media_aac_codec); - default: - break; - } - return 0; -} -int bt_avdtp_ep_register_sep(uint8_t media_type, uint8_t role, - struct bt_avdtp_seid_lsep *lsep) -{ - LOG_DBG(""); - if (!lsep) { - return -EIO; - } - if (bt_avdtp_seid == BT_AVDTP_MAX_SEID) { - return -EIO; - } - lsep->sid.id = bt_avdtp_seid++; - lsep->sid.inuse = 0; - lsep->sid.media_type = media_type; - lsep->sid.tsep = role; - lsep->ep_halt = 0; - lsep->next = lseps; - lseps = lsep; - return 0; -} -int bt_avdtp_ep_halt_sep(struct bt_avdtp_seid_lsep *lsep, bool halt) -{ - if (!lsep) { - return -EIO; - } - if (halt) { - if (lsep->sid.inuse) { - LOG_ERR("sep busy!"); - return -EBUSY; - } else { - lsep->ep_halt = 1; - } - } else { - lsep->ep_halt = 0; - } - return 0; -} -void bt_avdtp_ep_env_init(void) -{ - bt_avdtp_seid = BT_AVDTP_MIN_SEID; - lseps = NULL; -} \ No newline at end of file diff --git a/subsys/bluetooth/host/classic/zephyr3/avdtp_internal.h b/subsys/bluetooth/host/classic/zephyr3/avdtp_internal.h deleted file mode 100644 index a69727347fd..00000000000 --- a/subsys/bluetooth/host/classic/zephyr3/avdtp_internal.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * avdtp_internal.h - avdtp handling - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -/* @brief A2DP ROLE's */ -#define A2DP_SRC_ROLE 0x00 -#define A2DP_SNK_ROLE 0x01 -/* @brief AVDTP Role */ -#define BT_AVDTP_INT 0x00 -#define BT_AVDTP_ACP 0x01 -#define BT_L2CAP_PSM_AVDTP 0x0019 -/* AVDTP SIGNAL HEADER - Packet Type*/ -#define BT_AVDTP_PACKET_TYPE_SINGLE 0x00 -#define BT_AVDTP_PACKET_TYPE_START 0x01 -#define BT_AVDTP_PACKET_TYPE_CONTINUE 0x02 -#define BT_AVDTP_PACKET_TYPE_END 0x03 -/* AVDTP SIGNAL HEADER - MESSAGE TYPE */ -#define BT_AVDTP_CMD 0x00 -#define BT_AVDTP_GEN_REJECT 0x01 -#define BT_AVDTP_ACCEPT 0x02 -#define BT_AVDTP_REJECT 0x03 -/* @brief AVDTP SIGNAL HEADER - Signal Identifier */ -#define BT_AVDTP_DISCOVER 0x01 -#define BT_AVDTP_GET_CAPABILITIES 0x02 -#define BT_AVDTP_SET_CONFIGURATION 0x03 -#define BT_AVDTP_GET_CONFIGURATION 0x04 -#define BT_AVDTP_RECONFIGURE 0x05 -#define BT_AVDTP_OPEN 0x06 -#define BT_AVDTP_START 0x07 -#define BT_AVDTP_CLOSE 0x08 -#define BT_AVDTP_SUSPEND 0x09 -#define BT_AVDTP_ABORT 0x0a -#define BT_AVDTP_SECURITY_CONTROL 0x0b -#define BT_AVDTP_GET_ALL_CAPABILITIES 0x0c -#define BT_AVDTP_DELAYREPORT 0x0d -/* Actions add command, just for notify upper layer */ -#define BT_AVDTP_PENDING_AHEAD_START 0x80 -/* @brief AVDTP STREAM STATE */ -#define BT_AVDTP_STREAM_STATE_UNUSED 0x00 -#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_CLOSED 0x06 -#define BT_AVDTP_STREAM_STATE_SUSPEND 0x07 -#define BT_AVDTP_STREAM_STATE_ABORTING 0x08 -#define BT_AVDTP_SIG_ID_TO_STATE_ING(x) (((x) << 4) | 0x01) -#define BT_AVDTP_SIG_ID_TO_STATE_ED(x) (((x) << 4) | 0x02) -#define BT_AVDTP_SIG_ID_TO_STATE_EXT(x) (((x) << 4) | 0x03) -#define BT_AVDTP_IS_ACPINT_STATE_ING(x) ((x&0x0F) == 0x01) -#define BT_AVDTP_IS_ACPINT_STATE_ED(x) ((x&0x0F) == 0x02) -#define BT_AVDTP_IS_ACPINT_STATE_EXT(x) ((x&0x0F) == 0x03) -/* @brief AVDTP ACCEPTOR/INITIATOR STATE */ -#define BT_AVDTP_ACPINT_STATE_IDLE 0x00 /* ACP/INT in idle state, not send/receive cmd */ -#define BT_AVDTP_ACPINT_STATE_DISCOVERING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_DISCOVER) /* Send/Receive discover command */ -#define BT_AVDTP_ACPINT_STATE_DISCOVERED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_DISCOVER) /* Discover command process finish */ -#define BT_AVDTP_ACPINT_STATE_GET_CAPING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_GET_CAPABILITIES) -#define BT_AVDTP_ACPINT_STATE_GET_CAPED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_GET_CAPABILITIES) -#define BT_AVDTP_ACPINT_STATE_GET_CAPEXT BT_AVDTP_SIG_ID_TO_STATE_EXT(BT_AVDTP_GET_CAPABILITIES) -#define BT_AVDTP_ACPINT_STATE_SET_CFGING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_SET_CONFIGURATION) -#define BT_AVDTP_ACPINT_STATE_SET_CFGED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_SET_CONFIGURATION) -#define BT_AVDTP_ACPINT_STATE_GET_CFGING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_GET_CONFIGURATION) -#define BT_AVDTP_ACPINT_STATE_GET_CFGED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_GET_CONFIGURATION) -#define BT_AVDTP_ACPINT_STATE_RECFGING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_RECONFIGURE) -#define BT_AVDTP_ACPINT_STATE_RECFGED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_RECONFIGURE) -#define BT_AVDTP_ACPINT_STATE_OPENING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_OPEN) -#define BT_AVDTP_ACPINT_STATE_OPENED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_OPEN) -#define BT_AVDTP_ACPINT_STATE_STARTING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_START) -#define BT_AVDTP_ACPINT_STATE_STARTED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_START) -#define BT_AVDTP_ACPINT_STATE_CLOSEING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_CLOSE) -#define BT_AVDTP_ACPINT_STATE_CLOSEED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_CLOSE) -#define BT_AVDTP_ACPINT_STATE_SUSPENDING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_SUSPEND) -#define BT_AVDTP_ACPINT_STATE_SUSPENDED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_SUSPEND) -#define BT_AVDTP_ACPINT_STATE_ABORTING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_ABORT) -#define BT_AVDTP_ACPINT_STATE_ABORTED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_ABORT) -#define BT_AVDTP_ACPINT_STATE_SECTRLING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_SECURITY_CONTROL) -#define BT_AVDTP_ACPINT_STATE_SECTRLED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_SECURITY_CONTROL) -#define BT_AVDTP_ACPINT_STATE_GET_ACFGING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_GET_ALL_CAPABILITIES) -#define BT_AVDTP_ACPINT_STATE_GET_ACFGED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_GET_ALL_CAPABILITIES) -#define BT_AVDTP_ACPINT_STATE_GET_ACFGEXT BT_AVDTP_SIG_ID_TO_STATE_EXT(BT_AVDTP_GET_ALL_CAPABILITIES) -#define BT_AVDTP_ACPINT_STATE_DEREPORTING BT_AVDTP_SIG_ID_TO_STATE_ING(BT_AVDTP_DELAYREPORT) -#define BT_AVDTP_ACPINT_STATE_DEREPORTED BT_AVDTP_SIG_ID_TO_STATE_ED(BT_AVDTP_DELAYREPORT) -/* @brief AVDTP Media TYPE */ -#define BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT 0x01 -#define BT_AVDTP_SERVICE_CAT_REPORTING 0x02 -#define BT_AVDTP_SERVICE_CAT_RECOVERY 0x03 -#define BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION 0x04 -#define BT_AVDTP_SERVICE_CAT_HDR_COMPRESSION 0x05 -#define BT_AVDTP_SERVICE_CAT_MULTIPLEXING 0x06 -#define BT_AVDTP_SERVICE_CAT_MEDIA_CODEC 0x07 -#define BT_AVDTP_SERVICE_CAT_DELAYREPORTING 0x08 -#define BT_AVDTP_SERVICE_CAT_MAX BT_AVDTP_SERVICE_CAT_DELAYREPORTING -/* AVDTP Error Codes */ -#define BT_AVDTP_SUCCESS 0x00 -#define BT_AVDTP_ERR_BAD_HDR_FORMAT 0x01 -#define BT_AVDTP_ERR_BAD_LENGTH 0x11 -#define BT_AVDTP_ERR_BAD_ACP_SEID 0x12 -#define BT_AVDTP_ERR_SEP_IN_USE 0x13 -#define BT_AVDTP_ERR_SEP_NOT_IN_USE 0x14 -#define BT_AVDTP_ERR_BAD_SERV_CATEGORY 0x17 -#define BT_AVDTP_ERR_BAD_PAYLOAD_FORMAT 0x18 -#define BT_AVDTP_ERR_NOT_SUPPORTED_COMMAND 0x19 -#define BT_AVDTP_ERR_INVALID_CAPABILITIES 0x1a -#define BT_AVDTP_ERR_BAD_RECOVERY_TYPE 0x22 -#define BT_AVDTP_ERR_BAD_MEDIA_TRANSPORT_FORMAT 0x23 -#define BT_AVDTP_ERR_BAD_RECOVERY_FORMAT 0x25 -#define BT_AVDTP_ERR_BAD_ROHC_FORMAT 0x26 -#define BT_AVDTP_ERR_BAD_CP_FORMAT 0x27 -#define BT_AVDTP_ERR_BAD_MULTIPLEXING_FORMAT 0x28 -#define BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION 0x29 -#define BT_AVDTP_ERR_BAD_STATE 0x31 -#define BT_AVDTP_ERR_INVALID_CODEC_TYPE 0xC1 -#define BT_AVDTP_ERR_NOT_SUPPORTED_CODEC_TYPE 0xC2 -#define BT_AVDTP_ERR_INVALID_SAMPLING_FREQUENCY 0xC3 -#define BT_AVDTP_ERR_NOT_SUPPORTED_SAMPLING_FREQUENCY 0xC4 -#define BT_AVDTP_ERR_INVALID_CHANNEL_MODE 0xC5 -#define BT_AVDTP_ERR_NOT_SUPPORTED_CHANNEL_MODE 0xC6 -#define BT_AVDTP_ERR_INVALID_SUBBANDS 0xC7 -#define BT_AVDTP_ERR_NOT_SUPPORTED_SUBBANDS 0xC8 -#define BT_AVDTP_ERR_INVALID_ALLOCATION_METHOD 0xC9 -#define BT_AVDTP_ERR_NOT_SUPPORTED_ALLOCATION_METHOD 0xCA -#define BT_AVDTP_ERR_INVALID_MINIMUM_BITPOOL_VALUE 0xCB -#define BT_AVDTP_ERR_NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE 0xCC -#define BT_AVDTP_ERR_INVALID_MAXIMUM_BITPOOL_VALUE 0xCD -#define BT_AVDTP_ERR_NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE 0xCE -#define BT_AVDTP_ERR_INVALID_BLOCK_LENGTH 0xDD -#define BT_AVDTP_ERR_INVALID_CP_TYPE 0xE0 -#define BT_AVDTP_ERR_INVALID_CP_FORMAT 0xE1 -#define BT_AVDTP_ERR_INVALID_CODEC_PARAMETER 0xE2 -#define BT_AVDTP_ERR_NOT_SUPPORTED_CODEC_PARAMETER 0xE3 -#define BT_AVDTP_MIX_BITPOOL 2 -#define BT_AVDTP_MAX_BITPOOL 53 -#define BT_AVDTP_MAX_MTU CONFIG_BT_L2CAP_RX_MTU -#define BT_AVDTP_GET_SEID_MAX 20 -enum { - BT_AVDTP_STATE_CLOSE = 0, - BT_AVDTP_STATE_DISCOVER, - BT_AVDTP_STATE_GET_CAPABILITIES, - BT_AVDTP_STATE_CONFIGURATION, - BT_AVDTP_STATE_RECONFIGURE, - BT_AVDTP_STATE_STREAM_OPEN, - BT_AVDTP_STATE_STREAM_START, - BT_AVDTP_STATE_STREAM_SUSPEND, - BT_AVDTP_STATE_STREAM_CLOSE, - BT_AVDTP_STATE_DELAYREPORT, -}; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -struct bt_avdtp_get_capabilities_req { - uint8_t rfa0:2; - uint8_t seid:6; -} __packed; -typedef struct bt_avdtp_get_capabilities_req bt_avdtp_open_req; -struct bt_avdtp_setconf_req { - uint8_t rfa0:2; - uint8_t acp_seid:6; - uint8_t rfa1:2; - uint8_t int_seid:6; - uint8_t caps[0]; -} __packed; -struct bt_avdtp_reconf_req { - uint8_t rfa0:2; - uint8_t acp_seid:6; - uint8_t caps[0]; -} __packed; -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -struct bt_avdtp_setconf_req { - uint8_t acp_seid:6; - uint8_t rfa0:2; - uint8_t int_seid:6; - uint8_t rfa1:2; - uint8_t caps[0]; -} __packed; -struct bt_avdtp_reconf_req { - uint8_t acp_seid:6; - uint8_t rfa0:2; - uint8_t caps[0]; -} __packed; -#endif -struct bt_avdtp; -struct bt_avdtp_req; -struct bt_avdtp_cap; -typedef int (*bt_avdtp_func_t)(struct bt_avdtp *session, - struct bt_avdtp_req *req); -struct bt_avdtp_req { - uint8_t cmdtid; - uint8_t sig; - uint8_t tid; - uint8_t msg_type; - bt_avdtp_func_t func; - struct k_work_delayable timeout_work; - bt_avdtp_func_t state_sm_func; -}; -struct bt_avdtp_conf_rej { - uint8_t category; - uint8_t error; -} __packed; -struct bt_avdtp_single_sig_hdr { - uint8_t hdr; - uint8_t signal_id; -} __packed; -#define BT_AVDTP_SIG_HDR_LEN sizeof(struct bt_avdtp_single_sig_hdr) -struct bt_avdtp_cap { - uint8_t cat; - uint8_t len; - uint8_t data[0]; -}; -struct bt_avdtp_sep { - uint8_t seid; - uint8_t len; - struct bt_avdtp_cap caps[0]; -}; -/** @brief Global AVDTP session structure. */ -struct bt_avdtp { - struct bt_l2cap_br_chan br_chan; - uint8_t session_priority:3; - uint8_t role:3; /* Source/sink/media role */ - uint8_t intacp_role:1; /* As initial or accept */ - uint8_t connected:1; /* A2dp connect or not */ -}; -struct bt_avdtp_conn { - struct bt_avdtp signal_session; - struct bt_avdtp media_session; - struct bt_avdtp_stream stream; - struct bt_avdtp_req req; - struct bt_avdtp_seid_info get_seid[BT_AVDTP_GET_SEID_MAX]; - uint8_t get_seid_num:4; - uint8_t get_rsid_cap_index:4; - uint8_t pending_ahead_start:1; - struct net_buf *pending_resp_buf; -}; -#define AVDTP_CONN_BY_SIGNAL(_ch) CONTAINER_OF(_ch, struct bt_avdtp_conn, signal_session) -#define AVDTP_CONN_BY_MEDIA(_ch) CONTAINER_OF(_ch, struct bt_avdtp_conn, media_session) -#define AVDTP_CONN_BY_STREAM(_ch) CONTAINER_OF(_ch, struct bt_avdtp_conn, stream) -#define AVDTP_CONN_BY_REQ(_ch) CONTAINER_OF(_ch, struct bt_avdtp_conn, req) -struct bt_avdtp_event_cb { - int (*accept)(struct bt_conn *conn, struct bt_avdtp **session); - void (*connected)(struct bt_avdtp *session); - void (*disconnected)(struct bt_avdtp *session); - void (*do_media_connect)(struct bt_avdtp *session, bool isconnect); - void (*media_handler)(struct bt_avdtp *session, struct net_buf *buf); - int (*media_state_req)(struct bt_avdtp *session, uint8_t sig_id); - int (*intiator_connect_result)(struct bt_avdtp *session, bool success); - void (*seted_codec)(struct bt_avdtp *session, struct bt_a2dp_media_codec *codec, uint8_t cp_type); -}; -/* Initialize AVDTP layer*/ -int bt_avdtp_init(void); -/* Application register with AVDTP layer */ -int bt_avdtp_register(struct bt_avdtp_event_cb *cb); -/* AVDTP connect */ -int bt_avdtp_connect(struct bt_conn *conn, struct bt_avdtp *session, uint8_t role); -/* AVDTP disconnect */ -int bt_avdtp_disconnect(struct bt_avdtp *session); -/* AVDTP SEP register function */ -int bt_avdtp_ep_register_sep(uint8_t media_type, uint8_t role, - struct bt_avdtp_seid_lsep *lsep); -int bt_avdtp_ep_halt_sep(struct bt_avdtp_seid_lsep *lsep, bool halt); -/* AVDTP Discover Request */ -int bt_avdtp_discover(struct bt_avdtp *session); -int bt_avdtp_get_capabilities(struct bt_avdtp *session); -int bt_avdtp_get_all_capabilities(struct bt_avdtp *session); -int bt_avdtp_set_configuration(struct bt_avdtp *session); -int bt_avdtp_reconfig(struct bt_avdtp *session, struct bt_a2dp_media_codec *codec); -int bt_avdtp_open(struct bt_avdtp *session); -int bt_avdtp_start(struct bt_avdtp *session); -int bt_avdtp_suspend(struct bt_avdtp *session); -int bt_avdtp_close(struct bt_avdtp *session); -int bt_avdtp_abort(struct bt_avdtp *session); -int bt_avdtp_delayreport(struct bt_avdtp *session, uint16_t delay_time); -struct bt_a2dp_media_codec *bt_avdtp_get_seted_codec(struct bt_avdtp *session); -bool bt_avdtp_ep_empty(void); -struct bt_avdtp_seid_lsep *find_lsep_by_seid(uint8_t seid); -struct bt_avdtp_seid_lsep *find_free_lsep_by_role(uint8_t role); -struct bt_avdtp_seid_lsep *find_free_lsep_by_role_codectype(uint8_t role, uint8_t codectype); -bool lsep_seid_inused(uint8_t seid); -bool lsep_set_seid_used_by_seid(uint8_t seid, struct bt_avdtp_stream *stream); -bool lsep_set_seid_used_by_stream(struct bt_avdtp_stream *stream); -void lsep_set_seid_free(uint8_t seid); -int bt_avdtp_ep_check_set_codec_cp(struct bt_avdtp *session, struct net_buf *buf, uint8_t acp_seid, uint8_t sig_id); -void bt_avdtp_ep_append_seid(struct net_buf *resp_buf); -void bt_avdtp_ep_append_capabilities(struct net_buf *resp_buf, uint8_t reqSeid); -uint8_t bt_avdtp_ep_get_codec_len(struct bt_a2dp_media_codec *codec); -void bt_avdtp_ep_env_init(void); \ No newline at end of file