diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index 21c8930051..f8a88cba01 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -89,6 +89,15 @@ config BT_A2DP_ENABLE help Advanced Audio Distribution Profile +config BT_A2DP_USE_EXTERNAL_CODEC + bool "Use External Codec for A2DP" + depends on BT_A2DP_ENABLE + default n + help + If enable, user shall register audio codec capability to A2DP and encode/decode + audio data in application layer. The internal codec in A2DP will be remove in + the future, it is recommend to use external codec for new design. + config BT_AVRCP_ENABLED bool depends on BT_A2DP_ENABLE @@ -184,6 +193,15 @@ choice BT_HFP_AUDIO_DATA_PATH bool "HCI" endchoice +config BT_HFP_USE_EXTERNAL_CODEC + bool "Use External Codec for HFP" + depends on BT_HFP_ENABLE && BT_HFP_AUDIO_DATA_PATH_HCI + default n + help + If enable, user shall encode/decode audio data in application layer. The internal + codec in HFP will be remove in the future, it is recommend to use external codec + for new design. + config BT_HFP_WBS_ENABLE bool "Wide Band Speech" depends on BT_HFP_ENABLE && BT_HFP_AUDIO_DATA_PATH_HCI diff --git a/components/bt/host/bluedroid/api/esp_hf_ag_api.c b/components/bt/host/bluedroid/api/esp_hf_ag_api.c index 6eb6a6b523..babe753a49 100644 --- a/components/bt/host/bluedroid/api/esp_hf_ag_api.c +++ b/components/bt/host/bluedroid/api/esp_hf_ag_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -528,6 +528,8 @@ esp_err_t esp_hf_ag_out_call(esp_bd_addr_t remote_addr, int num_active, int num_ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; } +#if (BTM_SCO_HCI_INCLUDED == TRUE) + esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send) { if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { @@ -548,7 +550,73 @@ esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_h return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; } -#if (BTM_SCO_HCI_INCLUDED == TRUE) +esp_err_t esp_hf_ag_register_audio_data_callback(esp_hf_ag_audio_data_cb_t callback) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF; + msg.act = BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT; + + btc_hf_args_t arg; + memset(&arg, 0, sizeof(btc_hf_args_t)); + arg.reg_audio_data_cb.callback = callback; + + /* Switch to BTC context */ + bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL, NULL); + return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_hf_audio_buff_t *esp_hf_ag_audio_buff_alloc(uint16_t size) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return NULL; + } + + if (size == 0) { + return NULL; + } + + uint8_t *p_buf = NULL, *p_data; + BTA_AgAudioBuffAlloc(size, &p_buf, &p_data); + if (p_buf == NULL) { + return NULL; + } + + esp_hf_audio_buff_t *audio_buf = (esp_hf_audio_buff_t *)p_buf; + audio_buf->buff_size = size; + audio_buf->data_len = 0; + audio_buf->data = p_data; + return audio_buf; +} + +void esp_hf_ag_audio_buff_free(esp_hf_audio_buff_t *audio_buf) +{ + if (audio_buf == NULL) { + return; + } + BTA_AgAudioBuffFree((UINT8 *)audio_buf); +} + +esp_err_t esp_hf_ag_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (audio_buf == NULL || audio_buf->data_len == 0) { + return ESP_ERR_INVALID_ARG; + } + + if (btc_hf_ag_audio_data_send(sync_conn_hdl, (uint8_t *)audio_buf, audio_buf->data, audio_buf->data_len)) { + return ESP_OK; + } + return ESP_FAIL; +} + esp_err_t esp_hf_ag_pkt_stat_nums_get(uint16_t sync_conn_handle) { if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { diff --git a/components/bt/host/bluedroid/api/esp_hf_client_api.c b/components/bt/host/bluedroid/api/esp_hf_client_api.c index 9909f4423a..1b3c9a4294 100644 --- a/components/bt/host/bluedroid/api/esp_hf_client_api.c +++ b/components/bt/host/bluedroid/api/esp_hf_client_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -541,6 +541,71 @@ void esp_hf_client_outgoing_data_ready(void) BTA_HfClientCiData(); } +esp_err_t esp_hf_client_register_audio_data_callback(esp_hf_client_audio_data_cb_t callback) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_HF_CLIENT; + msg.act = BTC_HF_CLIENT_REGISTER_AUDIO_DATA_CALLBACK_EVT; + + btc_hf_client_args_t arg; + memset(&arg, 0, sizeof(btc_hf_client_args_t)); + arg.reg_audio_data_cb.callback = callback; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_client_args_t), NULL, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_hf_audio_buff_t *esp_hf_client_audio_buff_alloc(uint16_t size) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return NULL; + } + + if (size == 0) { + return NULL; + } + + uint8_t *p_buf = NULL, *p_data; + BTA_HfClientAudioBuffAlloc(size, &p_buf, &p_data); + if (p_buf == NULL) { + return NULL; + } + + esp_hf_audio_buff_t *audio_buf = (esp_hf_audio_buff_t *)p_buf; + audio_buf->buff_size = size; + audio_buf->data_len = 0; + audio_buf->data = p_data; + return audio_buf; +} + +void esp_hf_client_audio_buff_free(esp_hf_audio_buff_t *audio_buf) +{ + if (audio_buf == NULL) { + return; + } + BTA_HfClientAudioBuffFree((UINT8 *)audio_buf); +} + +esp_err_t esp_hf_client_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (audio_buf == NULL || audio_buf->data_len == 0) { + return ESP_ERR_INVALID_ARG; + } + + BTA_HfClientAudioDataSend(sync_conn_hdl, (uint8_t *)audio_buf, audio_buf->data, audio_buf->data_len); + return ESP_OK; +} + void esp_hf_client_pcm_resample_init(uint32_t src_sps, uint32_t bits, uint32_t channels) { BTA_DmPcmInitSamples(src_sps, bits, channels); diff --git a/components/bt/host/bluedroid/api/include/api/esp_hf_ag_api.h b/components/bt/host/bluedroid/api/include/api/esp_hf_ag_api.h index c079614b29..44ed5109a6 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_hf_ag_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_hf_ag_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include "esp_err.h" #include "esp_bt_defs.h" #include "esp_hf_defs.h" +#include "esp_hf_ag_legacy_api.h" #ifdef __cplusplus extern "C" { @@ -93,7 +94,8 @@ typedef union struct hf_audio_stat_param { esp_bd_addr_t remote_addr; /*!< Remote bluetooth device address */ esp_hf_audio_state_t state; /*!< Audio connection state */ - uint16_t sync_conn_handle; /*!< (e)SCO connection handle */ + esp_hf_sync_conn_hdl_t sync_conn_handle; /*!< (e)SCO connection handle */ + uint16_t preferred_frame_size; /*!< Valid only when Voice Over HCI is enabled, recommended frame size to send */ } audio_stat; /*!< AG callback param of ESP_HF_AUDIO_STATE_EVT */ /** @@ -233,35 +235,6 @@ typedef union } esp_hf_cb_param_t; /*!< HFP AG callback param compound*/ -/** - * @brief AG incoming data callback function, the callback is useful in case of - * Voice Over HCI. - * - * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the - * buffer is allocated inside bluetooth protocol stack and will be released after - * invoke of the callback is finished. - * - * @param[in] len : size(in bytes) in buf - */ -typedef void (* esp_hf_incoming_data_cb_t)(const uint8_t *buf, uint32_t len); - -/** - * @brief AG outgoing data callback function, the callback is useful in case of - * Voice Over HCI. Once audio connection is set up and the application layer has - * prepared data to send, the lower layer will call this function to read data - * and then send. This callback is supposed to be implemented as non-blocking, - * and if data is not enough, return value 0 is supposed. - * - * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the - * buffer is allocated inside bluetooth protocol stack and will be released after - * invoke of the callback is finished. - * - * @param[in] len : size(in bytes) in buf - * - * @return length of data successfully read - */ -typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len); - /** * @brief HF AG callback function type * @@ -271,6 +244,20 @@ typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len); */ typedef void (* esp_hf_cb_t) (esp_hf_cb_event_t event, esp_hf_cb_param_t *param); +/** + * @brief HFP AG incoming audio data callback function, user should copy audio_buf struct + * to other place before return. This callback is used in case of Voice Over HCI. + * + * @param[in] sync_conn_hdl: (e)SCO connection handle + * + * @param[in] audio_buf: pointer to incoming data(payload of HCI synchronous data packet), user + * should free audio buffer by calling esp_hf_ag_audio_buff_free + * + * @param[in] is_bad_frame: whether this packet is marked as bad frame by baseband + * + */ +typedef void (* esp_hf_ag_audio_data_cb_t)(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf, bool is_bad_frame); + /************************************************************************************ ** ESP HF API ************************************************************************************/ @@ -678,19 +665,58 @@ esp_err_t esp_hf_ag_end_call(esp_bd_addr_t remote_addr, int num_active, int num_ char *number, esp_hf_call_addr_type_t call_addr_type); /** - * @brief Register AG data output function. - * The callback is only used in the case that Voice Over HCI is enabled. + * @brief Register HFP AG audio data output function; the callback is only used in + * the case that Voice Over HCI is enabled. * - * @param[in] recv: HFP client incoming data callback function - * @param[in] send: HFP client outgoing data callback function + * @param[in] callback: HFP AG incoming audio data callback function * * @return * - ESP_OK: success * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled - * - ESP_FAIL: if callback is a NULL function pointer + * - ESP_FAIL: others * */ -esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send); +esp_err_t esp_hf_ag_register_audio_data_callback(esp_hf_ag_audio_data_cb_t callback); + +/** + * @brief Allocate a audio buffer to store and send audio data. This function is only + * used in the case that Voice Over HCI is enabled. + * + * @param[in] size: buffer size to allocate + * + * @return allocated audio buffer, if Bluedroid is not enabled, no memory, or size is + * zeros, will return NULL + * + */ +esp_hf_audio_buff_t *esp_hf_ag_audio_buff_alloc(uint16_t size); + +/** + * @brief Free a audio buffer allocated by esp_hf_ag_audio_buff_alloc. This function + * is only used in the case that Voice Over HCI is enabled. + * + * @param[in] audio_buf: audio buffer to free + * + */ +void esp_hf_ag_audio_buff_free(esp_hf_audio_buff_t *audio_buf); + +/** + * @brief Send audio data, the audio buffer should by allocated by esp_hf_ag_audio_buff_alloc. + * If the length of the audio data is equal to preferred_frame_size indicated by + * ESP_HF_AUDIO_STATE_EVT, then we can reduce one memory copy inside the Bluedroid stack. + * This function is only used in the case that Voice Over HCI is enabled. + * + * @param[in] sync_conn_hdl: (e)SCO connection handle + * + * @param[in] audio_buf: audio buffer that audio data stored + * + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_ERR_INVALID_ARG: invalid parameter + * - ESP_FAIL: others + * + */ +esp_err_t esp_hf_ag_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf); /** * @@ -709,16 +735,6 @@ esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_h */ esp_err_t esp_hf_ag_pkt_stat_nums_get(uint16_t sync_conn_handle); -/** - * @brief Trigger the lower-layer to fetch and send audio data. - * - * This function is only used in the case that Voice Over HCI is enabled. - * As a precondition to use this API, Service Level Connection shall exist with HFP client. - * After this function is called, lower layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data - * - */ -void esp_hf_ag_outgoing_data_ready(void); - #ifdef __cplusplus } #endif diff --git a/components/bt/host/bluedroid/api/include/api/esp_hf_ag_legacy_api.h b/components/bt/host/bluedroid/api/include/api/esp_hf_ag_legacy_api.h new file mode 100644 index 0000000000..7cd0769b48 --- /dev/null +++ b/components/bt/host/bluedroid/api/include/api/esp_hf_ag_legacy_api.h @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Some legacy APIs of HFP AG, will be removed in the future + */ + +#pragma once + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_hf_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief AG incoming data callback function, the callback is useful in case of + * Voice Over HCI. + * + * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the + * buffer is allocated inside bluetooth protocol stack and will be released after + * invoke of the callback is finished. + * + * @param[in] len : size(in bytes) in buf + */ +typedef void (* esp_hf_incoming_data_cb_t)(const uint8_t *buf, uint32_t len); + +/** + * @brief AG outgoing data callback function, the callback is useful in case of + * Voice Over HCI. Once audio connection is set up and the application layer has + * prepared data to send, the lower layer will call this function to read data + * and then send. This callback is supposed to be implemented as non-blocking, + * and if data is not enough, return value 0 is supposed. + * + * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the + * buffer is allocated inside bluetooth protocol stack and will be released after + * invoke of the callback is finished. + * + * @param[in] len : size(in bytes) in buf + * + * @return length of data successfully read + */ +typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len); + +/** + * @brief Register AG data output function. + * The callback is only used in the case that Voice Over HCI is enabled. + * + * @param[in] recv: HFP client incoming data callback function + * @param[in] send: HFP client outgoing data callback function + * + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: if callback is a NULL function pointer + * + */ +esp_err_t esp_hf_ag_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send); + +/** + * @brief Trigger the lower-layer to fetch and send audio data. + * + * This function is only used in the case that Voice Over HCI is enabled. + * As a precondition to use this API, Service Level Connection shall exist with HFP client. + * After this function is called, lower layer will invoke esp_hf_ag_outgoing_data_cb_t to fetch data + * + */ +void esp_hf_ag_outgoing_data_ready(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h b/components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h index cbc7277e65..2a3f579f55 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include "esp_err.h" #include "esp_bt_defs.h" #include "esp_hf_defs.h" +#include "esp_hf_client_legacy_api.h" #ifdef __cplusplus extern "C" { @@ -118,7 +119,8 @@ typedef union { struct hf_client_audio_stat_param { esp_hf_client_audio_state_t state; /*!< audio connection state */ esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */ - uint16_t sync_conn_handle; /*!< (e)SCO connection handle */ + esp_hf_sync_conn_hdl_t sync_conn_handle; /*!< (e)SCO connection handle */ + uint16_t preferred_frame_size; /*!< valid only when Voice Over HCI is enabled, recommended frame size to send */ } audio_stat; /*!< HF callback param of ESP_HF_CLIENT_AUDIO_STATE_EVT */ /** @@ -277,32 +279,18 @@ typedef union { } esp_hf_client_cb_param_t; /*!< HFP client callback parameters */ /** - * @brief HFP client incoming data callback function, the callback is useful in case of - * Voice Over HCI. - * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the - * buffer is allocated inside bluetooth protocol stack and will be released after - * invoke of the callback is finished. - * @param[in] len : size(in bytes) in buf - */ -typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t len); - -/** - * @brief HFP client outgoing data callback function, the callback is useful in case of - * Voice Over HCI. Once audio connection is set up and the application layer has - * prepared data to send, the lower layer will call this function to read data - * and then send. This callback is supposed to be implemented as non-blocking, - * and if data is not enough, return value 0 is supposed. + * @brief HFP client incoming audio data callback function, user should copy audio_buf struct + * to other place before return. This callback is used in case of Voice Over HCI. * - * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the - * buffer is allocated inside bluetooth protocol stack and will be released after - * invoke of the callback is finished. + * @param[in] sync_conn_hdl: (e)SCO connection handle * - * @param[in] len : size(in bytes) in buf + * @param[in] audio_buf: pointer to incoming data(payload of HCI synchronous data packet), user + * should free audio buffer by calling esp_hf_client_audio_buff_free * - * @return length of data successfully read + * @param[in] is_bad_frame: whether this packet is marked as bad frame by baseband * */ -typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len); +typedef void (* esp_hf_client_audio_data_cb_t)(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf, bool is_bad_frame); /** * @brief HFP client callback function type @@ -662,24 +650,6 @@ esp_err_t esp_hf_client_request_last_voice_tag_number(void); */ esp_err_t esp_hf_client_send_nrec(void); - -/** - * @brief Register HFP client data output function; the callback is only used in - * the case that Voice Over HCI is enabled. - * - * @param[in] recv: HFP client incoming data callback function - * - * @param[in] send: HFP client outgoing data callback function - * - * @return - * - ESP_OK: success - * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled - * - ESP_FAIL: if callback is a NULL function pointer - * - */ -esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t recv, - esp_hf_client_outgoing_data_cb_t send); - /** * * @brief Get the number of packets received and sent @@ -697,15 +667,57 @@ esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t esp_err_t esp_hf_client_pkt_stat_nums_get(uint16_t sync_conn_handle); /** - * @brief Trigger the lower-layer to fetch and send audio data. - * This function is only only used in the case that Voice Over HCI is enabled. After this - * function is called, lower layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data. + * @brief Register HFP client audio data output function; the callback is only used in + * the case that Voice Over HCI is enabled. * - * As a precondition to use this API, Service Level Connection shall exist with AG. + * @param[in] callback: HFP client incoming audio data callback function + * + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others * */ -void esp_hf_client_outgoing_data_ready(void); +esp_err_t esp_hf_client_register_audio_data_callback(esp_hf_client_audio_data_cb_t callback); +/** + * @brief Allocate a audio buffer to store and send audio data. This function is only + * used in the case that Voice Over HCI is enabled. + * + * @param[in] size: buffer size to allocate + * + * @return allocated audio buffer, if Bluedroid is not enabled, no memory, or size is + * zeros, will return NULL + * + */ +esp_hf_audio_buff_t *esp_hf_client_audio_buff_alloc(uint16_t size); + +/** + * @brief Free a audio buffer allocated by esp_hf_client_audio_buff_alloc. This function + * is only used in the case that Voice Over HCI is enabled. + * + * @param[in] audio_buf: audio buffer to free + * + */ +void esp_hf_client_audio_buff_free(esp_hf_audio_buff_t *audio_buf); + +/** + * @brief Send audio data, the audio buffer should by allocated by esp_hf_client_audio_buff_alloc. + * If the length of the audio data is equal to preferred_frame_size indicated by + * ESP_HF_CLIENT_AUDIO_STATE_EVT, then we can reduce one memory copy inside the Bluedroid stack. + * This function is only used in the case that Voice Over HCI is enabled. + * + * @param[in] sync_conn_hdl: (e)SCO connection handle + * + * @param[in] audio_buf: audio buffer that audio data stored + * + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_ERR_INVALID_ARG: invalid parameter + * + */ +esp_err_t esp_hf_client_audio_data_send(esp_hf_sync_conn_hdl_t sync_conn_hdl, esp_hf_audio_buff_t *audio_buf); /** * @brief Initialize the down sampling converter. This is a utility function that can diff --git a/components/bt/host/bluedroid/api/include/api/esp_hf_client_legacy_api.h b/components/bt/host/bluedroid/api/include/api/esp_hf_client_legacy_api.h new file mode 100644 index 0000000000..6441bfc4b4 --- /dev/null +++ b/components/bt/host/bluedroid/api/include/api/esp_hf_client_legacy_api.h @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Some legacy APIs of HFP HF, will be removed in the future + */ + +#pragma once + +#include "esp_err.h" +#include "esp_bt_defs.h" +#include "esp_hf_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief HFP client incoming data callback function, the callback is useful in case of + * Voice Over HCI. + * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the + * buffer is allocated inside bluetooth protocol stack and will be released after + * invoke of the callback is finished. + * @param[in] len : size(in bytes) in buf + */ +typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t len); + +/** + * @brief HFP client outgoing data callback function, the callback is useful in case of + * Voice Over HCI. Once audio connection is set up and the application layer has + * prepared data to send, the lower layer will call this function to read data + * and then send. This callback is supposed to be implemented as non-blocking, + * and if data is not enough, return value 0 is supposed. + * + * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the + * buffer is allocated inside bluetooth protocol stack and will be released after + * invoke of the callback is finished. + * + * @param[in] len : size(in bytes) in buf + * + * @return length of data successfully read + * + */ +typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len); + +/** + * @brief Register HFP client data output function; the callback is only used in + * the case that Voice Over HCI is enabled. + * + * @param[in] recv: HFP client incoming data callback function + * + * @param[in] send: HFP client outgoing data callback function + * + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: if callback is a NULL function pointer + * + */ +esp_err_t esp_hf_client_register_data_callback(esp_hf_client_incoming_data_cb_t recv, + esp_hf_client_outgoing_data_cb_t send); + +/** + * @brief Trigger the lower-layer to fetch and send audio data. + * This function is only only used in the case that Voice Over HCI is enabled. After this + * function is called, lower layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data. + * + * As a precondition to use this API, Service Level Connection shall exist with AG. + * + */ +void esp_hf_client_outgoing_data_ready(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/bt/host/bluedroid/api/include/api/esp_hf_defs.h b/components/bt/host/bluedroid/api/include/api/esp_hf_defs.h index ec41b8641a..e6ca2e70ee 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_hf_defs.h +++ b/components/bt/host/bluedroid/api/include/api/esp_hf_defs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,8 @@ extern "C" { #endif +typedef uint16_t esp_hf_sync_conn_hdl_t; + /// profile states typedef enum { ESP_HF_INIT_SUCCESS = 0, /*!< Indicate init successful */ @@ -249,6 +251,25 @@ typedef enum { ESP_HF_CME_NETWORK_NOT_ALLOWED = 32, /*!< network not allowed --emergency calls only */ } esp_hf_cme_err_t; +/* Since HFP uses a fixed set of mSBC codec parameters, define it here */ +#define ESP_HF_MSBC_CHANNEL_MODE "Mono" /*!< mSBC channel mode */ +#define ESP_HF_MSBC_SAMPLING_RATE "16 kHz" /*!< mSBC sampling rate */ +#define ESP_HF_MSBC_ALLOCATION_METHOD "Loudness" /*!< mSBC allocation method */ +#define ESP_HF_MSBC_SUBBANDS 8 /*!< mSBC subbands */ +#define ESP_HF_MSBC_BLOCK_LENGTH 15 /*!< mSBC block length */ +#define ESP_HF_MSBC_BITPOOL 26 /*!< mSBC bitpool */ +/* frame size after mSBC encoded */ +#define ESP_HF_MSBC_ENCODED_FRAME_SIZE 57 /*!< mSBC frame size */ + +/** + * @brief HFP audio buffer + */ +typedef struct { + uint16_t buff_size; /*!< buffer size */ + uint16_t data_len; /*!< audio data length, data length should not greater than buffer size */ + uint8_t *data; /*!< pointer to audio data start */ +} esp_hf_audio_buff_t; /*!< struct to store audio data */ + #ifdef __cplusplus } #endif diff --git a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_api.c b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_api.c index 4b1d91eef5..331f6595e6 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_api.c +++ b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_api.c @@ -339,6 +339,73 @@ void BTA_AgCiData(UINT16 handle) bta_sys_sendmsg(p_buf); } } + +/******************************************************************************* +** +** Function BTA_AgAudioBuffAlloc +** +** Description Allocate an audio buffer with specific size, reserve enough +** space and offset for lower layer to send the buffer directly. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data) +{ + /* reserve 1 byte at last, when the size is mSBC frame size (57), then we got a buffer that can hold 60 bytes data */ + BT_HDR *p_buf= (BT_HDR *)osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_H2_HEADER_LEN + size + 1); + if (p_buf != NULL) { + /* mSBC offset is large than CVSD, so this is also work in CVSD air mode */ + p_buf->offset = BTA_AG_BUFF_OFFSET_MIN + BTA_AG_H2_HEADER_LEN; + *pp_buff = (UINT8 *)p_buf; + *pp_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + } +} + +/******************************************************************************* +** +** Function BTA_AgAudioBuffFree +** +** Description Free an audio buffer. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioBuffFree(UINT8 *p_buf) +{ + osi_free(p_buf); +} + +/******************************************************************************* +** +** Function BTA_AgAudioDataSend +** +** Description Send audio data to lower level, whether success or not, buffer +** is consumed. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioDataSend(UINT16 handle, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len) +{ + BT_HDR *p_buf = (BT_HDR *)p_buff_start; + tBTA_AG_SCB *p_scb; + assert(p_data - (UINT8 *)(p_buf + 1) >= 0); + if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) { + p_buf->event = BTA_AG_API_SCO_DATA_SEND_EVT; + p_buf->layer_specific = handle; + p_buf->offset = p_data - (UINT8 *)(p_buf + 1); + p_buf->len = data_len; + bta_sys_sendmsg(p_buf); + } + else { + osi_free(p_buf); + } +} + #endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */ #endif /* #if (BTA_AG_INCLUDED == TRUE)*/ diff --git a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_main.c b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_main.c index bcf3cc6ec0..39daa0de6b 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_main.c +++ b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_main.c @@ -89,6 +89,8 @@ enum BTA_AG_SETCODEC, BTA_AG_SEND_RING, BTA_AG_CI_SCO_DATA, + BTA_AG_SCO_DATA_SEND, + BTA_AG_SCO_DATA_FREE, BTA_AG_CI_RX_DATA, BTA_AG_RCVD_SLC_READY, BTA_AG_PKT_STAT_NUMS, @@ -133,6 +135,8 @@ const tBTA_AG_ACTION bta_ag_action[] = bta_ag_setcodec, bta_ag_send_ring, bta_ag_ci_sco_data, + bta_ag_sco_data_send, + bta_ag_sco_data_free, bta_ag_ci_rx_data, bta_ag_rcvd_slc_ready, bta_ag_pkt_stat_nums @@ -155,6 +159,7 @@ const UINT8 bta_ag_st_init[][BTA_AG_NUM_COLS] = /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_FREE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, /* RFC_OPEN_EVT */ {BTA_AG_RFC_ACP_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST}, /* RFC_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, @@ -185,6 +190,7 @@ const UINT8 bta_ag_st_opening[][BTA_AG_NUM_COLS] = /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_FREE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, /* RFC_OPEN_EVT */ {BTA_AG_RFC_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST}, /* RFC_CLOSE_EVT */ {BTA_AG_RFC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, @@ -215,6 +221,7 @@ const UINT8 bta_ag_st_open[][BTA_AG_NUM_COLS] = /* API_AUDIO_CLOSE_EVT */ {BTA_AG_SCO_CLOSE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, /* API_RESULT_EVT */ {BTA_AG_RESULT, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, /* API_SETCODEC_EVT */ {BTA_AG_SETCODEC, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_SEND, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, /* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, /* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, @@ -245,6 +252,7 @@ const UINT8 bta_ag_st_closing[][BTA_AG_NUM_COLS] = /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_SCO_DATA_SEND_EVT */ {BTA_AG_SCO_DATA_FREE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, /* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, /* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, @@ -360,9 +368,9 @@ static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result) case BTA_AG_API_DISABLE_EVT: return "Disable AG"; case BTA_AG_CI_SCO_DATA_EVT: - return "SCO data Callin"; + return "SCO data Call In"; case BTA_AG_CI_SLC_READY_EVT: - return "SLC Ready Callin"; + return "SLC Ready Call In"; case BTA_AG_PKT_STAT_NUMS_GET_EVT: return "Get Packet Nums"; default: @@ -433,6 +441,7 @@ static tBTA_AG_SCB *bta_ag_scb_alloc(void) #if (BTM_WBS_INCLUDED == TRUE) p_scb->codec_updated = FALSE; #endif + p_scb->p_sco_data = NULL; /* set up timers */ p_scb->act_timer.param = (UINT32) p_scb; p_scb->act_timer.p_cback = bta_ag_timer_cback; @@ -473,6 +482,10 @@ void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb) #if (BTM_WBS_INCLUDED == TRUE) bta_sys_free_timer(&p_scb->cn_timer); #endif + if (p_scb->p_sco_data != NULL) { + osi_free(p_scb->p_sco_data); + p_scb->p_sco_data = NULL; + } bta_sys_free_timer(&p_scb->colli_timer); /* initialize control block */ @@ -774,7 +787,7 @@ static void bta_ag_api_enable(tBTA_AG_DATA *p_data) bta_ag_cb.scb->negotiated_codec = BTM_SCO_CODEC_CVSD; } - /* set deault setting for eSCO/SCO */ + /* set default setting for eSCO/SCO */ BTM_WriteVoiceSettings(AG_VOICE_SETTINGS); bta_sys_collision_register (BTA_ID_AG, bta_ag_collision_cback); /* call callback with enable event */ @@ -943,6 +956,7 @@ void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data) BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg) { tBTA_AG_SCB *p_scb; + BOOLEAN free_msg = TRUE; APPL_TRACE_DEBUG("bta_ag_hdl_event: Event 0x%04x ", p_msg->event); switch (p_msg->event) { @@ -966,15 +980,22 @@ BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg) bta_ag_api_result((tBTA_AG_DATA *) p_msg); break; - /* all others reference scb by handle */ + case BTA_AG_API_SCO_DATA_SEND_EVT: + free_msg = FALSE; + /* fall through */ default: + /* all others reference scb by handle */ if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL) { APPL_TRACE_DEBUG("bta_ag_hdl_event: p_scb 0x%08x ", (unsigned int)p_scb); bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg); } + else { + /* free message if p_scb not found */ + free_msg = TRUE; + } break; } - return TRUE; + return free_msg; } #endif /* #if (BTA_AG_INCLUDED == TRUE) */ diff --git a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c index 661d237266..f2196c6b2a 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c +++ b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c @@ -345,9 +345,10 @@ static void bta_ag_sco_read_cback(UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_ APPL_TRACE_DEBUG("bta_ag_sco_read_cback: status(%d)", status); } +#if (BTA_HFP_EXT_CODEC == FALSE) /* Callout function must free the data. */ bta_ag_sco_co_in_data(p_data, status); - osi_free(p_data); +#endif } #endif /******************************************************************************* @@ -459,6 +460,37 @@ static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p } } +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + +/******************************************************************************* +** +** Function bta_ag_sco_get_frame_size +** +** Description Get SCO frame size. +** +** +** Returns SCO frame size +** +*******************************************************************************/ +static UINT16 bta_ag_sco_get_frame_size(tBTA_AG_SCB *p_scb) +{ + UINT16 frame_size = 0; + switch (p_scb->air_mode) + { + case BTM_SCO_AIR_MODE_CVSD: + frame_size = p_scb->out_pkt_len; + break; + case BTM_SCO_AIR_MODE_TRANSPNT: + frame_size = BTA_AG_MSBC_FRAME_SIZE; + break; + default: + break; + } + return frame_size; +} + +#endif + /******************************************************************************* ** ** Function bta_ag_cback_sco @@ -471,14 +503,19 @@ static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p *******************************************************************************/ static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event) { - tBTA_AG_HDR sco; + tBTA_AG_AUDIO_STAT audio_stat = {0}; - sco.handle = bta_ag_scb_to_idx(p_scb); - sco.app_id = p_scb->app_id; - sco.sync_conn_handle = BTM_ReadScoHandle(p_scb->sco_idx); + audio_stat.hdr.handle = bta_ag_scb_to_idx(p_scb); + audio_stat.hdr.app_id = p_scb->app_id; + audio_stat.hdr.sync_conn_handle = BTM_ReadScoHandle(p_scb->sco_idx); +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + if (event != BTA_AG_AUDIO_CLOSE_EVT) { + audio_stat.preferred_frame_size = bta_ag_sco_get_frame_size(p_scb); + } +#endif /* call close cback */ - (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco); + (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &audio_stat); } /******************************************************************************* @@ -784,7 +821,7 @@ static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event) p_scb->sco_idx, p_sco->state, bta_ag_sco_state_str(p_sco->state), event, bta_ag_sco_evt_str(event)); -#if (BTM_SCO_HCI_INCLUDED == TRUE) +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == FALSE) BT_HDR *p_buf; if (event == BTA_AG_SCO_CI_DATA_E) { @@ -1633,6 +1670,11 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } + if (p_scb->p_sco_data != NULL) { + osi_free(p_scb->p_sco_data); + p_scb->p_sco_data = NULL; + } + /* call app callback */ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT); #if (BTM_WBS_INCLUDED == TRUE) @@ -1665,7 +1707,7 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST || bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST) { - /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */ + /* If script override sco parameter by BTA_CMD_SET_ESCO_PARAM */ if (bta_ag_cb.sco.param_updated) { resp = bta_ag_cb.sco.params; @@ -1736,7 +1778,7 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data ** ** Function bta_ag_ci_sco_data ** -** Description Process the SCO data ready callin event +** Description Process the SCO data ready call in event ** ** ** Returns void @@ -1752,6 +1794,288 @@ void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) #endif } +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + +/******************************************************************************* +** +** Function bta_ag_write_sco_data +** +** Description Write two SCO data buffers to specified instance +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_write_sco_data(tBTA_AG_SCB *p_scb, BT_HDR *p_buf1, BT_HDR *p_buf2) +{ + BTM_WriteScoData(p_scb->sco_idx, p_buf1); + if (p_buf2 != NULL) { + BTM_WriteScoData(p_scb->sco_idx, p_buf2); + } +} + +/******************************************************************************* +** +** Function bta_ag_sco_data_send_cvsd +** +** Description Process SCO data of CVSD air mode +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_sco_data_send_cvsd(tBTA_AG_SCB *p_scb, BT_HDR *p_buf) +{ + UINT16 out_pkt_len = p_scb->out_pkt_len; + + if (p_scb->p_sco_data != NULL) { + /* the remaining data of last sending operation */ + BT_HDR *p_buf_last = p_scb->p_sco_data; + /* remaining data len should small than out_pkt_len */ + assert(p_buf_last->len < out_pkt_len); + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + out_pkt_len); + if (p_buf2 == NULL) { + osi_free(p_buf); + osi_free(p_buf_last); + p_scb->p_sco_data = NULL; + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + return; + } + p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN; + UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + memcpy(p_data, (UINT8 *)(p_buf_last + 1) + p_buf_last->offset, p_buf_last->len); + + if (p_buf->len + p_buf_last->len < out_pkt_len) { + memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len); + p_buf2->len = p_buf->len + p_buf_last->len; + osi_free(p_buf); + osi_free(p_buf_last); + p_scb->p_sco_data = p_buf2; + } + else { + UINT16 copy_len = out_pkt_len - p_buf_last->len; + memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len); + p_buf2->len = out_pkt_len; + p_buf->offset += copy_len; + p_buf->len -= copy_len; + osi_free(p_buf_last); + p_scb->p_sco_data = NULL; + bta_ag_write_sco_data(p_scb, p_buf2, NULL); + + if (p_buf->len == 0) { + osi_free(p_buf); + } + else { + /* recursive call, this will only called once */ + bta_ag_sco_data_send_cvsd(p_scb, p_buf); + } + } + } + else if (p_buf->len < out_pkt_len) { + p_scb->p_sco_data = p_buf; + } + else { + /* p_scb->p_sco_data != NULL && p_buf->len >= out_pkt_len */ + while (1) { + if (p_buf->len == out_pkt_len) { + bta_ag_write_sco_data(p_scb, p_buf, NULL); + break; + } + else { + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + out_pkt_len); + if (p_buf2 == NULL) { + osi_free(p_buf); + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + return; + } + p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN; + UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + memcpy(p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, out_pkt_len); + p_buf2->len = out_pkt_len; + p_buf->offset += out_pkt_len; + p_buf->len -= out_pkt_len; + bta_ag_write_sco_data(p_scb, p_buf2, NULL); + } + if (p_buf->len < out_pkt_len) { + p_scb->p_sco_data = p_buf; + break; + } + } + } +} + +/******************************************************************************* +** +** Function bta_ag_sco_data_send_msbc +** +** Description Process SCO data of mSBC air mode +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_sco_data_send_msbc(tBTA_AG_SCB *p_scb, BT_HDR *p_buf) +{ + UINT16 out_pkt_len = p_scb->out_pkt_len; + if (p_buf->len == BTA_AG_MSBC_FRAME_SIZE && p_buf->offset >= BTA_AG_BUFF_OFFSET_MIN + BTA_AG_H2_HEADER_LEN) { + /* add H2 header */ + p_buf->offset -= BTA_AG_H2_HEADER_LEN; + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + bta_ag_h2_header((UINT16 *)p_data); + /* add header len, add addition one bytes, the len is BTA_AG_SCO_OUT_PKT_LEN_2EV3 now */ + p_buf->len += BTA_AG_H2_HEADER_LEN + 1; + + if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_2EV3) { + /* mSBC frame can be send directly */ + bta_ag_write_sco_data(p_scb, p_buf, NULL); + } + else if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_EV3) { + /* need to split into 2 sco packages for sending */ + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_EV3); + if (p_buf2 == NULL) { + /* free the first buff too */ + osi_free(p_buf); + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + return; + } + p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN; + p_buf2->len = BTA_AG_SCO_OUT_PKT_LEN_EV3; + UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + memcpy(p_data2, p_data + BTA_AG_SCO_OUT_PKT_LEN_EV3, BTA_AG_SCO_OUT_PKT_LEN_EV3); + /* update the first packet len */ + p_buf->len = BTA_AG_SCO_OUT_PKT_LEN_EV3; + bta_ag_write_sco_data(p_scb, p_buf, p_buf2); + } + else { + osi_free(p_buf); + APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len); + } + } + else if (p_buf->len != 0 && p_buf->len % BTA_AG_MSBC_FRAME_SIZE == 0) { + /* multiple mSBC frame in the buffer, or just one but offset is too small */ + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT16 total_len = p_buf->len; + if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_2EV3) { + while (total_len != 0) { + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_2EV3); + if (p_buf2 == NULL) { + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + break; + } + p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN; + p_buf2->len = BTA_AG_SCO_OUT_PKT_LEN_2EV3; + UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + bta_ag_h2_header((UINT16 *)p_data2); + p_data2 += BTA_AG_H2_HEADER_LEN; + memcpy(p_data2, p_data, BTA_AG_MSBC_FRAME_SIZE); + p_data += BTA_AG_MSBC_FRAME_SIZE; + total_len -= BTA_AG_MSBC_FRAME_SIZE; + bta_ag_write_sco_data(p_scb, p_buf2, NULL); + } + } + else if (out_pkt_len == BTA_AG_SCO_OUT_PKT_LEN_EV3) { + while (total_len != 0) { + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_EV3); + if (p_buf2 == NULL) { + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + break; + } + BT_HDR *p_buf3 = osi_calloc(sizeof(BT_HDR) + BTA_AG_BUFF_OFFSET_MIN + BTA_AG_SCO_OUT_PKT_LEN_EV3); + if (p_buf3 == NULL) { + /* free the first buff too */ + osi_free(p_buf2); + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + break; + } + + /* build first packet, include H2 header */ + p_buf2->offset = BTA_AG_BUFF_OFFSET_MIN; + p_buf2->len = BTA_AG_SCO_OUT_PKT_LEN_EV3; + UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + bta_ag_h2_header((UINT16 *)p_data2); + p_data2 += BTA_AG_H2_HEADER_LEN; + memcpy(p_data2, p_data, BTA_AG_SCO_OUT_PKT_LEN_EV3 - BTA_AG_H2_HEADER_LEN); + p_data += BTA_AG_SCO_OUT_PKT_LEN_EV3 - BTA_AG_H2_HEADER_LEN; + total_len -= BTA_AG_SCO_OUT_PKT_LEN_EV3 - BTA_AG_H2_HEADER_LEN; + + /* build second packet, not include header */ + p_buf3->offset = BTA_AG_BUFF_OFFSET_MIN; + p_buf3->len = BTA_AG_SCO_OUT_PKT_LEN_EV3; + UINT8 *p_data3 = (UINT8 *)(p_buf3 + 1) + p_buf3->offset; + memcpy(p_data3, p_data, BTA_AG_MSBC_FRAME_SIZE - BTA_AG_H2_HEADER_LEN - BTA_AG_SCO_OUT_PKT_LEN_EV3); + p_data += BTA_AG_MSBC_FRAME_SIZE - BTA_AG_H2_HEADER_LEN - BTA_AG_SCO_OUT_PKT_LEN_EV3; + total_len -= BTA_AG_MSBC_FRAME_SIZE - BTA_AG_H2_HEADER_LEN - BTA_AG_SCO_OUT_PKT_LEN_EV3; + bta_ag_write_sco_data(p_scb, p_buf2, p_buf3); + } + } + else { + APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len); + } + osi_free(p_buf); + } + else { + APPL_TRACE_WARNING("%s, unaccepted data len: %d", __FUNCTION__, p_buf->len); + osi_free(p_buf); + } +} + +#endif + +/******************************************************************************* +** +** Function bta_ag_sco_data_send +** +** Description Route SCO data to specific processing function based on air mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_data_send(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + BT_HDR *p_buf = (BT_HDR *) p_data; + +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + if (bta_ag_cb.sco.state != BTA_AG_SCO_OPEN_ST || bta_ag_cb.sco.cur_idx != p_scb->sco_idx) { + osi_free(p_data); + APPL_TRACE_WARNING("%s: SCO invalid state", __FUNCTION__); + return; + } + + switch (p_scb->air_mode) + { + case BTM_SCO_AIR_MODE_CVSD: + bta_ag_sco_data_send_cvsd(p_scb, p_buf); + break; + case BTM_SCO_AIR_MODE_TRANSPNT: + bta_ag_sco_data_send_msbc(p_scb, p_buf); + break; + default: + osi_free(p_buf); + APPL_TRACE_WARNING("%s: unsupported air mode: %d", __FUNCTION__, p_scb->air_mode); + break; + } +#else + osi_free(p_buf); +#endif +} + +/******************************************************************************* +** +** Function bta_ag_sco_data_free +** +** Description Free SCO data +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_data_free(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UNUSED(p_scb); + osi_free(p_data); +} + /******************************************************************************* ** ** Function bta_ag_set_esco_param diff --git a/components/bt/host/bluedroid/bta/hf_ag/include/bta_ag_int.h b/components/bt/host/bluedroid/bta/hf_ag/include/bta_ag_int.h index 9ced8b3665..c8b7be36ea 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/include/bta_ag_int.h +++ b/components/bt/host/bluedroid/bta/hf_ag/include/bta_ag_int.h @@ -96,6 +96,19 @@ BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \ BTA_AG_FEAT_VTAG) +#if (BTM_SCO_HCI_INCLUDED == TRUE) +/* 1 (offset can not be 0) + HCI_SCO_PREAMBLE */ +#define BTA_AG_BUFF_OFFSET_MIN (1 + HCI_SCO_PREAMBLE_SIZE) +/* mSBC H2 header length */ +#define BTA_AG_H2_HEADER_LEN 2 +/* mSBC frame size not include H1/H2 header */ +#define BTA_AG_MSBC_FRAME_SIZE 57 +/* max user data len of sco packet type EV3 */ +#define BTA_AG_SCO_OUT_PKT_LEN_EV3 30 +/* max user data len of sco packet type 2-EV3 */ +#define BTA_AG_SCO_OUT_PKT_LEN_2EV3 60 +#endif + enum { /* these events are handled by the state machine */ @@ -107,6 +120,7 @@ enum BTA_AG_API_AUDIO_CLOSE_EVT, BTA_AG_API_RESULT_EVT, BTA_AG_API_SETCODEC_EVT, + BTA_AG_API_SCO_DATA_SEND_EVT, BTA_AG_RFC_OPEN_EVT, BTA_AG_RFC_CLOSE_EVT, BTA_AG_RFC_SRV_CLOSE_EVT, @@ -295,6 +309,7 @@ typedef struct TIMER_LIST_ENT cn_timer; /* codec negotiation timer */ #endif UINT16 sco_idx; /* SCO connection index */ + BT_HDR *p_sco_data; /* remaining SCO data of last sending operation */ BOOLEAN in_use; /* scb in use */ BOOLEAN dealloc; /* TRUE if service shutting down */ BOOLEAN clip_enabled; /* set to TRUE if HF enables CLIP reporting */ @@ -452,10 +467,13 @@ extern void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); extern void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); extern void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); extern void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_sco_data_send(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_sco_data_free(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param); extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); extern void bta_ag_pkt_stat_nums(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_h2_header(UINT16 *p_buf); #endif /* #if (BTA_AG_INCLUDED == TRUE) */ diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_api.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_api.c index 6149d8c418..748d62db0f 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_api.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_api.c @@ -44,9 +44,9 @@ static const uint8_t bta_hf_client_cb_data_size[] = { sizeof(tBTA_HF_CLIENT_OPEN), // #define BTA_HF_CLIENT_OPEN_EVT 2 0, // #define BTA_HF_CLIENT_CLOSE_EVT 3 sizeof(tBTA_HF_CLIENT_CONN), // #define BTA_HF_CLIENT_CONN_EVT 4 - sizeof(tBTA_HF_CLIENT_HDR), // #define BTA_HF_CLIENT_AUDIO_OPEN_EVT 5 - sizeof(tBTA_HF_CLIENT_HDR), //#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT 6 - sizeof(tBTA_HF_CLIENT_HDR), // #define BTA_HF_CLIENT_AUDIO_CLOSE_EVT 7 + sizeof(tBTA_HF_CLIENT_AUDIO_STAT), // #define BTA_HF_CLIENT_AUDIO_OPEN_EVT 5 + sizeof(tBTA_HF_CLIENT_AUDIO_STAT), // #define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT 6 + sizeof(tBTA_HF_CLIENT_AUDIO_STAT), // #define BTA_HF_CLIENT_AUDIO_CLOSE_EVT 7 sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_SPK_EVT 8 sizeof(tBTA_HF_CLIENT_VAL), // #define BTA_HF_CLIENT_MIC_EVT 9 sizeof(tBTA_HF_CLIENT_IND), //#define BTA_HF_CLIENT_IND_EVT 10 @@ -322,6 +322,16 @@ void BTA_HfClientPktStatsNumsGet(UINT16 sync_conn_handle) } } +/******************************************************************************* +** +** Function BTA_HfClientCiData +** +** Description Send SCO outgoing data ready event +** +** +** Returns void +** +*******************************************************************************/ void BTA_HfClientCiData(void) { BT_HDR *p_buf; @@ -330,8 +340,79 @@ void BTA_HfClientCiData(void) bta_sys_sendmsg(p_buf); } } + +/******************************************************************************* +** +** Function BTA_HfClientAudioBuffAlloc +** +** Description Allocate an audio buffer with specific size, reserve enough +** space and offset for lower layer to send the buffer directly. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data) +{ + /* reserve 1 byte at last, when the size is mSBC frame size (57), then we got a buffer that can hold 60 bytes data */ + BT_HDR *p_buf= (BT_HDR *)osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_H2_HEADER_LEN + size + 1); + if (p_buf != NULL) { + /* mSBC offset is large than CVSD, so this is work in CVSD air mode */ + p_buf->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_H2_HEADER_LEN; + *pp_buff = (UINT8 *)p_buf; + *pp_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + } +} + +/******************************************************************************* +** +** Function BTA_HfClientAudioBuffFree +** +** Description Free an audio buffer. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioBuffFree(UINT8 *p_buf) +{ + osi_free(p_buf); +} + +/******************************************************************************* +** +** Function BTA_HfClientAudioDataSend +** +** Description Send audio data to lower layer, whether success or not, buffer +** is consumed. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioDataSend(UINT16 sync_conn_hdl, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len) +{ + /* currently, sync_conn_hdl is not used */ + BT_HDR *p_buf = (BT_HDR *)p_buff_start; + assert(p_data - (UINT8 *)(p_buf + 1) >= 0); + p_buf->event = BTA_HF_CLIENT_SCO_DATA_SEND_EVT; + p_buf->offset = p_data - (UINT8 *)(p_buf + 1); + p_buf->len = data_len; + bta_sys_sendmsg(p_buf); +} + #endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */ +/******************************************************************************* +** +** Function BTA_HfClientGetCbDataSize +** +** Description Get callback data size of specific event +** +** +** Returns void +** +*******************************************************************************/ int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event) { return bta_hf_client_cb_data_size[event]; diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c index 9fdefa97f5..b87c4869c3 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c @@ -24,6 +24,7 @@ #include "bta/bta_sys.h" #include "bta/bta_hf_client_api.h" #include "bta_hf_client_int.h" +#include "osi/allocator.h" #if BT_HF_CLIENT_BQB_INCLUDED static BOOLEAN s_bta_hf_client_bqb_clip_flag = TRUE; @@ -79,6 +80,8 @@ enum { BTA_HF_CLIENT_SEND_AT_CMD, #if (BTM_SCO_HCI_INCLUDED == TRUE) BTA_HF_CLIENT_CI_SCO_DATA, + BTA_HF_CLIENT_SCO_DATA_SEND, + BTA_HF_CLIENT_SCO_DATA_FREE, BTA_HF_CLIENT_PKT_STAT_NUMS, #endif BTA_HF_CLIENT_NUM_ACTIONS, @@ -118,6 +121,8 @@ const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = { /* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd, #if (BTM_SCO_HCI_INCLUDED == TRUE) /* BTA_HF_CLIENT_CI_SCO_DATA */ bta_hf_client_ci_sco_data, + /* BTA_HF_CLIENT_SCO_DATA_SEND */ bta_hf_client_sco_data_send, + /* BTA_HF_CLIENT_SCO_DATA_FREE */ bta_hf_client_sco_data_free, /* BTA_HF_CLIENT_PKT_STAT_NUMS */ bta_hf_client_pkt_stat_nums, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; @@ -149,6 +154,7 @@ const UINT8 bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = { /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, + /* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_FREE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, /* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_INIT_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; @@ -175,6 +181,7 @@ const UINT8 bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = { /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, + /* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_FREE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, /* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPENING_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; @@ -201,6 +208,7 @@ const UINT8 bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = { /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_SEND_AT_CMD, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_CI_SCO_DATA, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, + /* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_SEND, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, /* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_OPEN_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; @@ -227,6 +235,7 @@ const UINT8 bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = { /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, #if (BTM_SCO_HCI_INCLUDED == TRUE ) /* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, + /* SCO_DATA_SEND_EVT */ {BTA_HF_CLIENT_SCO_DATA_FREE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, /* PKT_STAT_NUMS_GET_EVT */ {BTA_HF_CLIENT_PKT_STAT_NUMS, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST}, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ }; @@ -284,6 +293,7 @@ void bta_hf_client_scb_init(void) memset(&bta_hf_client_cb.scb, 0, sizeof(tBTA_HF_CLIENT_SCB)); bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX; bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD; + bta_hf_client_cb.scb.p_sco_data = NULL; } /******************************************************************************* @@ -299,6 +309,10 @@ void bta_hf_client_scb_init(void) void bta_hf_client_scb_disable(void) { APPL_TRACE_DEBUG("%s", __FUNCTION__); + if (bta_hf_client_cb.scb.p_sco_data != NULL) { + osi_free(bta_hf_client_cb.scb.p_sco_data); + bta_hf_client_cb.scb.p_sco_data = NULL; + } bta_hf_client_scb_init(); @@ -470,6 +484,7 @@ static void bta_hf_client_api_disable(tBTA_HF_CLIENT_DATA *p_data) *******************************************************************************/ BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg) { + BOOLEAN free_msg = TRUE; #if BTA_HF_CLIENT_DEBUG == TRUE APPL_TRACE_DEBUG("bta_hf_client_hdl_event %s (0x%x)", bta_hf_client_evt_str(p_msg->event), p_msg->event); #endif @@ -484,12 +499,16 @@ BOOLEAN bta_hf_client_hdl_event(BT_HDR *p_msg) case BTA_HF_CLIENT_API_DISABLE_EVT: bta_hf_client_api_disable((tBTA_HF_CLIENT_DATA *) p_msg); break; - +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + case BTA_HF_CLIENT_SCO_DATA_SEND_EVT: + free_msg = false; + /* fall through */ +#endif default: bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA *) p_msg); break; } - return TRUE; + return free_msg; } /******************************************************************************* diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c index d464a88925..11437fb92a 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c @@ -177,6 +177,36 @@ static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active) return removed_started; } +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + +/******************************************************************************* +** +** Function bta_hf_client_sco_get_frame_size +** +** Description Get SCO frame size +** +** Returns frame size +** +*******************************************************************************/ +static UINT16 bta_hf_client_sco_get_frame_size(void) +{ + UINT16 frame_size = 0; + switch (bta_hf_client_cb.scb.air_mode) + { + case BTM_SCO_AIR_MODE_CVSD: + frame_size = bta_hf_client_cb.scb.out_pkt_len; + break; + case BTM_SCO_AIR_MODE_TRANSPNT: + frame_size = BTA_HF_CLIENT_MSBC_FRAME_SIZE; + break; + default: + break; + } + return frame_size; +} + +#endif + /******************************************************************************* ** ** Function bta_hf_client_cback_sco @@ -189,13 +219,17 @@ static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active) *******************************************************************************/ void bta_hf_client_cback_sco(UINT8 event) { - tBTA_HF_CLIENT_HDR evt; - - memset(&evt, 0, sizeof(evt)); - evt.sync_conn_handle = BTM_ReadScoHandle(bta_hf_client_cb.scb.sco_idx); + tBTA_HF_CLIENT_AUDIO_STAT audio_stat; + memset(&audio_stat, 0, sizeof(audio_stat)); + audio_stat.hdr.sync_conn_handle = BTM_ReadScoHandle(bta_hf_client_cb.scb.sco_idx); +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + if (event != BTA_HF_CLIENT_AUDIO_CLOSE_EVT) { + audio_stat.preferred_frame_size = bta_hf_client_sco_get_frame_size(); + } +#endif /* call app cback */ - (*bta_hf_client_cb.p_cback)(event, (tBTA_HF_CLIENT_HDR *) &evt); + (*bta_hf_client_cb.p_cback)(event, &audio_stat); } #if (BTM_SCO_HCI_INCLUDED == TRUE ) @@ -217,7 +251,6 @@ static void bta_hf_client_sco_read_cback (UINT16 sco_idx, BT_HDR *p_data, tBTM_S } bta_hf_client_sco_co_in_data (p_data, status); - osi_free(p_data); } #endif /* BTM_SCO_HCI_INCLUDED */ @@ -307,7 +340,7 @@ void bta_hf_client_pkt_stat_nums(tBTA_HF_CLIENT_DATA *p_data) ** ** Function bta_hf_client_ci_sco_data ** -** Description Process the SCO data ready callin event +** Description Process the SCO data ready call in event ** ** ** Returns void @@ -318,6 +351,281 @@ void bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA *p_data) UNUSED(p_data); bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CI_DATA_E); } + +/******************************************************************************* +** +** Function bta_hf_client_write_sco_data +** +** Description Write two SCO data buffers to specified instance +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_write_sco_data(BT_HDR *p_buf1, BT_HDR *p_buf2) +{ + BTM_WriteScoData(bta_hf_client_cb.scb.sco_idx, p_buf1); + if (p_buf2 != NULL) { + BTM_WriteScoData(bta_hf_client_cb.scb.sco_idx, p_buf2); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_data_send_cvsd +** +** Description Process SCO data of CVSD air mode +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_sco_data_send_cvsd(BT_HDR *p_buf, UINT8 out_pkt_len) +{ + if (bta_hf_client_cb.scb.p_sco_data != NULL) { + /* the remaining data of last sending operation */ + BT_HDR *p_buf_last = bta_hf_client_cb.scb.p_sco_data; + /* remaining data len should small than out_pkt_len */ + assert(p_buf_last->len < out_pkt_len); + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + out_pkt_len); + if (p_buf2 == NULL) { + osi_free(p_buf); + osi_free(p_buf_last); + bta_hf_client_cb.scb.p_sco_data = NULL; + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + return; + } + p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN; + + UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + memcpy(p_data, (UINT8 *)(p_buf_last + 1) + p_buf_last->offset, p_buf_last->len); + + if (p_buf->len + p_buf_last->len < out_pkt_len) { + memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len); + p_buf2->len = p_buf->len + p_buf_last->len; + osi_free(p_buf); + osi_free(p_buf_last); + bta_hf_client_cb.scb.p_sco_data = p_buf2; + } + else { + UINT16 copy_len = out_pkt_len - p_buf_last->len; + memcpy(p_data + p_buf_last->len, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len); + p_buf2->len = out_pkt_len; + p_buf->offset += copy_len; + p_buf->len -= copy_len; + osi_free(p_buf_last); + bta_hf_client_cb.scb.p_sco_data = NULL; + bta_hf_client_write_sco_data(p_buf2, NULL); + if (p_buf->len == 0) { + osi_free(p_buf); + } + else { + /* Recursive call, this will only called once */ + bta_hf_client_sco_data_send_cvsd(p_buf, out_pkt_len); + } + } + } + else if (p_buf->len < out_pkt_len) { + bta_hf_client_cb.scb.p_sco_data = p_buf; + } + else { + /* bta_hf_client_cb.scb.p_sco_data == NULL && p_buf->len >= out_pkt_len */ + while (1) { + if (p_buf->len == out_pkt_len) { + bta_hf_client_write_sco_data(p_buf, NULL); + break; + } + else { + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + out_pkt_len); + if (p_buf2 == NULL) { + osi_free(p_buf); + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + return; + } + p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN; + UINT8 *p_data = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + memcpy(p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, out_pkt_len); + p_buf2->len = out_pkt_len; + p_buf->offset += out_pkt_len; + p_buf->len -= out_pkt_len; + bta_hf_client_write_sco_data(p_buf2, NULL); + } + if (p_buf->len < out_pkt_len) { + bta_hf_client_cb.scb.p_sco_data = p_buf; + break; + } + } + } +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_data_send_msbc +** +** Description Process SCO data of mSBC air mode +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hf_client_sco_data_send_msbc(BT_HDR *p_buf, UINT8 out_pkt_len) +{ + if (p_buf->len == BTA_HF_CLIENT_MSBC_FRAME_SIZE && p_buf->offset >= BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_H2_HEADER_LEN) { + /* add H2 header */ + p_buf->offset -= BTA_HF_CLIENT_H2_HEADER_LEN; + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + bta_hf_client_h2_header((UINT16 *)p_data); + /* add header len, add addition one bytes, the len is BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3 now */ + p_buf->len += BTA_HF_CLIENT_H2_HEADER_LEN + 1; + + if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3) { + /* mSBC frame can be send directly */ + bta_hf_client_write_sco_data(p_buf, NULL); + } + else if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3) { + /* need to split into 2 sco packages for sending */ + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3); + if (p_buf2 == NULL) { + /* free the first buff too */ + osi_free(p_buf); + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + return; + } + p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN; + p_buf2->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3; + UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + memcpy(p_data2, p_data + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3, BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3); + /* update the first packet len */ + p_buf->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3; + bta_hf_client_write_sco_data(p_buf, p_buf2); + } + else { + osi_free(p_buf); + APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len); + } + } + else if (p_buf->len != 0 && p_buf->len % BTA_HF_CLIENT_MSBC_FRAME_SIZE == 0) { + /* multiple mSBC frame in the buffer, or just one but offset is too small */ + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT16 total_len = p_buf->len; + if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3) { + while (total_len != 0) { + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3); + if (p_buf2 == NULL) { + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + break; + } + p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN; + p_buf2->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3; + UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + bta_hf_client_h2_header((UINT16 *)p_data2); + p_data2 += BTA_HF_CLIENT_H2_HEADER_LEN; + memcpy(p_data2, p_data, BTA_HF_CLIENT_MSBC_FRAME_SIZE); + p_data += BTA_HF_CLIENT_MSBC_FRAME_SIZE; + total_len -= BTA_HF_CLIENT_MSBC_FRAME_SIZE; + bta_hf_client_write_sco_data(p_buf2, NULL); + } + } + else if (out_pkt_len == BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3) { + while (total_len != 0) { + BT_HDR *p_buf2 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3); + if (p_buf2 == NULL) { + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + break; + } + BT_HDR *p_buf3 = osi_calloc(sizeof(BT_HDR) + BTA_HF_CLIENT_BUFF_OFFSET_MIN + BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3); + if (p_buf3 == NULL) { + /* free the first buff too */ + osi_free(p_buf2); + APPL_TRACE_WARNING("%s, no memory", __FUNCTION__); + break; + } + + /* build first packet, include H2 header */ + p_buf2->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN; + p_buf2->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3; + UINT8 *p_data2 = (UINT8 *)(p_buf2 + 1) + p_buf2->offset; + bta_hf_client_h2_header((UINT16 *)p_data2); + p_data2 += BTA_HF_CLIENT_H2_HEADER_LEN; + memcpy(p_data2, p_data, BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 - BTA_HF_CLIENT_H2_HEADER_LEN); + p_data += BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 - BTA_HF_CLIENT_H2_HEADER_LEN; + total_len -= BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 - BTA_HF_CLIENT_H2_HEADER_LEN; + + /* build second packet, not include header */ + p_buf3->offset = BTA_HF_CLIENT_BUFF_OFFSET_MIN; + p_buf3->len = BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3; + UINT8 *p_data3 = (UINT8 *)(p_buf3 + 1) + p_buf3->offset; + memcpy(p_data3, p_data, BTA_HF_CLIENT_MSBC_FRAME_SIZE - BTA_HF_CLIENT_H2_HEADER_LEN - BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3); + p_data += BTA_HF_CLIENT_MSBC_FRAME_SIZE - BTA_HF_CLIENT_H2_HEADER_LEN - BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3; + total_len -= BTA_HF_CLIENT_MSBC_FRAME_SIZE - BTA_HF_CLIENT_H2_HEADER_LEN - BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3; + bta_hf_client_write_sco_data(p_buf2, p_buf3); + } + } + else { + APPL_TRACE_WARNING("%s, invalid out pkt len: %d", __FUNCTION__, out_pkt_len); + } + osi_free(p_buf); + } + else { + APPL_TRACE_WARNING("%s, unaccepted data len: %d", __FUNCTION__, p_buf->len); + osi_free(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_data_send +** +** Description Route SCO data to specific processing function based on air mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sco_data_send(tBTA_HF_CLIENT_DATA *p_data) +{ + BT_HDR *p_buf = (BT_HDR *) p_data; + + if (bta_hf_client_cb.scb.sco_state != BTA_HF_CLIENT_SCO_OPEN_ST) { + osi_free(p_data); + APPL_TRACE_WARNING("%s: SCO not open", __FUNCTION__); + return; + } + + UINT8 out_pkt_len = bta_hf_client_cb.scb.out_pkt_len; + UINT8 air_mode = bta_hf_client_cb.scb.air_mode; + + switch (air_mode) + { + case BTM_SCO_AIR_MODE_CVSD: + bta_hf_client_sco_data_send_cvsd(p_buf, out_pkt_len); + break; + case BTM_SCO_AIR_MODE_TRANSPNT: + bta_hf_client_sco_data_send_msbc(p_buf, out_pkt_len); + break; + default: + osi_free(p_buf); + APPL_TRACE_WARNING("%s: unsupported air mode: %d", __FUNCTION__, air_mode); + break; + } +} + +/******************************************************************************* +** +** Function bta_hf_client_sco_data_free +** +** Description Free SCO data buffer +** +** +** Returns void +** +*******************************************************************************/ +void bta_hf_client_sco_data_free(tBTA_HF_CLIENT_DATA *p_data) +{ + /* just free the sco data buffer */ + osi_free(p_data); +} + #endif /******************************************************************************* @@ -539,12 +847,9 @@ static void bta_hf_client_sco_event(UINT8 event) APPL_TRACE_DEBUG("%s state: %d event: %d", __FUNCTION__, bta_hf_client_cb.scb.sco_state, event); -#if (BTM_SCO_HCI_INCLUDED == TRUE ) - tBTA_HF_CLIENT_SCB *p_scb = &bta_hf_client_cb.scb; +#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTA_HFP_EXT_CODEC == FALSE) BT_HDR *p_buf; -#endif - -#if (BTM_SCO_HCI_INCLUDED == TRUE ) + tBTA_HF_CLIENT_SCB *p_scb = &bta_hf_client_cb.scb; if (event == BTA_HF_CLIENT_SCO_CI_DATA_E) { UINT16 pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE; UINT16 len_to_send = 0; @@ -890,6 +1195,11 @@ void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data) bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr); + if (bta_hf_client_cb.scb.p_sco_data != NULL) { + osi_free(bta_hf_client_cb.scb.p_sco_data); + bta_hf_client_cb.scb.p_sco_data = NULL; + } + /* call app callback */ bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT); diff --git a/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h index 0732a96c52..d2b34518f1 100644 --- a/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h +++ b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h @@ -44,6 +44,19 @@ #define BTA_HF_CLIENT_COLLISION_TIMER 2411 #endif +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +/* 1 (offset can not be 0) + HCI_SCO_PREAMBLE */ +#define BTA_HF_CLIENT_BUFF_OFFSET_MIN (1 + HCI_SCO_PREAMBLE_SIZE) +/* mSBC H2 header length */ +#define BTA_HF_CLIENT_H2_HEADER_LEN 2 +/* mSBC frame size not include H1/H2 header */ +#define BTA_HF_CLIENT_MSBC_FRAME_SIZE 57 +/* max user data len of sco packet type EV3 */ +#define BTA_HF_CLIENT_SCO_OUT_PKT_LEN_EV3 30 +/* max user data len of sco packet type 2-EV3 */ +#define BTA_HF_CLIENT_SCO_OUT_PKT_LEN_2EV3 60 +#endif + enum { /* these events are handled by the state machine */ BTA_HF_CLIENT_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_HS), @@ -65,6 +78,7 @@ enum { BTA_HF_CLIENT_SEND_AT_CMD_EVT, #if (BTM_SCO_HCI_INCLUDED == TRUE ) BTA_HF_CLIENT_CI_SCO_DATA_EVT, + BTA_HF_CLIENT_SCO_DATA_SEND_EVT, BTA_HF_CLIENT_PKT_NUMS_GET_EVT, #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ BTA_HF_CLIENT_MAX_EVT, @@ -138,7 +152,6 @@ typedef union { tBTA_HF_CLIENT_RFC rfc; tBTA_HF_CLIENT_DATA_VAL val; tBTA_HF_CLIENT_PKT_STAT_GET pkt_stat; - } tBTA_HF_CLIENT_DATA; /* type for each service control block */ @@ -158,6 +171,7 @@ typedef struct { UINT16 sco_idx; /* SCO handle */ UINT8 sco_state; /* SCO state variable */ BOOLEAN sco_close_rfc; /* TRUE if also close RFCOMM after SCO */ + BT_HDR *p_sco_data; /* remaining SCO data of last sending operation */ BOOLEAN retry_with_sco_only; BOOLEAN deregister; /* TRUE if service shutting down */ BOOLEAN svc_conn; /* set to TRUE when service level connection is up */ @@ -312,5 +326,8 @@ extern void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA *p_data); #if (BTM_SCO_HCI_INCLUDED == TRUE ) extern void bta_hf_client_pkt_stat_nums(tBTA_HF_CLIENT_DATA *p_data); extern void bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_h2_header(UINT16 *p_buf); +extern void bta_hf_client_sco_data_send(tBTA_HF_CLIENT_DATA *p_data); +extern void bta_hf_client_sco_data_free(tBTA_HF_CLIENT_DATA *p_data); #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */ #endif /* #if (BTA_HF_INCLUDED == TRUE) */ diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_ag_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_ag_api.h index 35bb6ab5e6..ac714d8595 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_ag_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_ag_api.h @@ -112,7 +112,7 @@ typedef UINT8 tBTA_AG_STATUS; /* It is safe to use the same value as BTA_AG_HANDLE_ALL * HANDLE_ALL is used for delivering indication * SCO_NO_CHANGE is used for changing sco behavior - * They donot interfere with each other + * They do not interfere with each other */ #define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF @@ -363,6 +363,13 @@ typedef struct tBTA_AG_CHLD_FEAT chld_feat; } tBTA_AG_CONN; +/* data associated with BTA_AG_AUDIO_OPEN_EVT, BTA_AG_AUDIO_CLOSE_EVT or BTA_AG_AUDIO_MSBC_OPEN_EVT */ +typedef struct +{ + tBTA_AG_HDR hdr; + UINT16 preferred_frame_size; +} tBTA_AG_AUDIO_STAT; + /* data associated with AT command event */ typedef struct { @@ -427,6 +434,7 @@ typedef union tBTA_AG_OPEN open; tBTA_AG_CLOSE close; tBTA_AG_CONN conn; + tBTA_AG_AUDIO_STAT audio_stat; tBTA_AG_IND ind; tBTA_AG_VAL val; //add @@ -619,6 +627,45 @@ void BTA_AgPktStatsNumsGet(UINT16 handle, UINT16 sync_conn_handle); ** *******************************************************************************/ void BTA_AgCiData(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_AgAudioBuffAlloc +** +** Description Allocate an audio buffer with specific size, reserve enough +** space and offset for lower layer to send the buffer directly. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data); + +/******************************************************************************* +** +** Function BTA_AgAudioBuffFree +** +** Description Free an audio buffer. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioBuffFree(UINT8 *p_buf); + +/******************************************************************************* +** +** Function BTA_AgAudioDataSend +** +** Description Send audio data to lower layer, whether success or not, buffer +** is consumed. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioDataSend(UINT16 handle, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len); + #endif /*#if (BTM_SCO_HCI_INCLUDED == TRUE ) */ #ifdef __cplusplus diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_hf_client_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_hf_client_api.h index ac834c7b6f..d2731d2877 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_hf_client_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_hf_client_api.h @@ -188,6 +188,12 @@ typedef struct { tBTA_HF_CLIENT_CHLD_FEAT chld_feat; } tBTA_HF_CLIENT_CONN; +/* data associated with BTA_HF_CLIENT_AUDIO_XXX_EVT */ +typedef struct { + tBTA_HF_CLIENT_HDR hdr; + UINT16 preferred_frame_size; +} tBTA_HF_CLIENT_AUDIO_STAT; + /* data associated with BTA_HF_CLIENT_IND_EVT event */ typedef struct { tBTA_HF_CLIENT_HDR hdr; @@ -251,6 +257,7 @@ typedef union { tBTA_HF_CLIENT_REGISTER reg; tBTA_HF_CLIENT_OPEN open; tBTA_HF_CLIENT_CONN conn; + tBTA_HF_CLIENT_AUDIO_STAT audio_stat; tBTA_HF_CLIENT_IND ind; tBTA_HF_CLIENT_VAL val; tBTA_HF_CLIENT_OPERATOR_NAME operator; @@ -406,9 +413,68 @@ void BTA_HfClientSendAT(UINT16 handle, tBTA_HF_CLIENT_AT_CMD_TYPE at, UINT32 val *******************************************************************************/ void BTA_HfClientPktStatsNumsGet(UINT16 sync_conn_handle); +/******************************************************************************* +** +** Function BTA_HfClientCiData +** +** Description Send SCO outgoing data ready event +** +** +** Returns void +** +*******************************************************************************/ void BTA_HfClientCiData(void); + +/******************************************************************************* +** +** Function BTA_HfClientAudioBuffAlloc +** +** Description Allocate an audio buffer with specific size, reserve enough +** space and offset for lower layer to send the buffer directly. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioBuffAlloc(UINT16 size, UINT8 **pp_buff, UINT8 **pp_data); + +/******************************************************************************* +** +** Function BTA_HfClientAudioBuffFree +** +** Description Free an audio buffer. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioBuffFree(UINT8 *p_buf); + +/******************************************************************************* +** +** Function BTA_HfClientAudioDataSend +** +** Description Send audio data to lower layer, whether success or not, buffer +** is consumed. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HfClientAudioDataSend(UINT16 sync_conn_hdl, UINT8 *p_buff_start, UINT8 *p_data, UINT16 data_len); + #endif /*#if (BTM_SCO_HCI_INCLUDED == TRUE ) */ +/******************************************************************************* +** +** Function BTA_HfClientGetCbDataSize +** +** Description Get callback data size of specific event +** +** +** Returns void +** +*******************************************************************************/ int BTA_HfClientGetCbDataSize(tBTA_HF_CLIENT_EVT event); #ifdef __cplusplus diff --git a/components/bt/host/bluedroid/btc/profile/std/hf_ag/bta_ag_co.c b/components/bt/host/bluedroid/btc/profile/std/hf_ag/bta_ag_co.c index 6000f8324c..2f095ab351 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hf_ag/bta_ag_co.c +++ b/components/bt/host/bluedroid/btc/profile/std/hf_ag/bta_ag_co.c @@ -35,9 +35,11 @@ * CONST ********************************************************************************/ #if (BTM_SCO_HCI_INCLUDED == TRUE) +#if (BTC_HFP_EXT_CODEC == FALSE) #include "oi_codec_sbc.h" #include "oi_status.h" #include "sbc_encoder.h" +#endif #if (PLC_INCLUDED == TRUE) #include "sbc_plc.h" @@ -58,21 +60,39 @@ static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr; #define HF_SBC_DEC_RAW_DATA_SIZE 240 #define HF_SBC_ENC_RAW_DATA_SIZE 240 +// H2: Header with synchronization word and sequence number +#define BTA_HF_H2_HEADER_SYNC_WORD 0x0801 +#define BTA_HF_H2_HEADER_SYNC_WORD_MASK 0x0FFF +#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0) +#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1) +#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12 +#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13 +#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14 +#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15 + +#define BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p) ((*((uint16_t *)p) & BTA_HF_H2_HEADER_SYNC_WORD_MASK) == BTA_HF_H2_HEADER_SYNC_WORD) + /* BTA-AG-CO control block to map bdaddr to BTA handle */ typedef struct { +#if (BTC_HFP_EXT_CODEC == FALSE) OI_CODEC_SBC_DECODER_CONTEXT decoder_context; OI_UINT32 decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN]; OI_INT16 decode_raw_data[HF_SBC_DEC_RAW_DATA_SIZE]; SBC_ENC_PARAMS encoder; - UINT8 sequence_number; bool is_bad_frame; bool decode_first_pkt; - OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE]; bool encode_first_pkt; + OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE]; OI_BYTE encode_msbc_data[BTM_MSBC_FRAME_SIZE]; +#else + UINT8 sequence_number; + BOOLEAN rx_first_pkt; + BOOLEAN is_bad_frame; + UINT8 rx_half_msbc_data[BTM_MSBC_FRAME_SIZE/2]; +#endif } bta_ag_co_cb_t; #if HFP_DYNAMIC_MEMORY == FALSE @@ -151,7 +171,7 @@ void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len) ** Function bta_ag_ci_slc_ready ** ** Description This function is called to notify AG that SLC is up at -** the application. This funcion is only used when the app +** the application. This function is only used when the app ** is running in pass-through mode. ** ** Returns void @@ -179,18 +199,9 @@ void bta_ag_ci_slc_ready(UINT16 handle) ** Returns void ** *******************************************************************************/ -static void bta_ag_h2_header(UINT16 *p_buf) +void bta_ag_h2_header(UINT16 *p_buf) { - // H2: Header with synchronization word and sequence number -#define BTA_HF_H2_HEADER 0x0801 -#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0) -#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1) -#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12 -#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13 -#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14 -#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15 - - UINT16 h2_header = BTA_HF_H2_HEADER; + UINT16 h2_header = BTA_HF_H2_HEADER_SYNC_WORD; UINT8 h2_header_sn0 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT0_MASK; UINT8 h2_header_sn1 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT1_MASK; h2_header |= (h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 @@ -202,6 +213,19 @@ static void bta_ag_h2_header(UINT16 *p_buf) *p_buf = h2_header; } +#if (BTC_HFP_EXT_CODEC == TRUE) + +static void bta_ag_pkt_state_reset(void) +{ + bta_ag_co_cb.sequence_number = 0; + bta_ag_co_cb.rx_first_pkt = TRUE; + bta_ag_co_cb.is_bad_frame = FALSE; +} + +#endif + +#if (BTC_HFP_EXT_CODEC == FALSE) + /******************************************************************************* ** ** Function bta_hf_dec_init @@ -217,6 +241,7 @@ static void bta_hf_dec_init(void) sbc_plc_init(&(bta_hf_ct_plc.plc_state)); #endif ///(PLC_INCLUDED == TRUE) + OI_STATUS status = OI_CODEC_SBC_DecoderReset(&bta_ag_co_cb.decoder_context, bta_ag_co_cb.decoder_context_data, HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE); if (!OI_SUCCESS(status)) { @@ -326,15 +351,21 @@ static void bta_ag_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN is_bad APPL_TRACE_ERROR("Frame decode error: %d", status); break; } -#endif ///(PLC_INCLUDED == TRUE) if (OI_SUCCESS(status)) { btc_hf_incoming_data_cb_to_app((const uint8_t *)(bta_hf_ct_plc.sbc_plc_out), sbc_raw_data_size); } +#else + if (OI_SUCCESS(status)) { + btc_hf_incoming_data_cb_to_app((const uint8_t *)(bta_ag_co_cb.decode_raw_data), sbc_raw_data_size); + } +#endif } +#endif + /******************************************************************************* - * BTA AG SCO CO FUNCITONS + * BTA AG SCO CO FUNCTIONS ********************************************************************************/ /******************************************************************************* ** @@ -418,8 +449,12 @@ void bta_ag_sco_co_open(UINT16 handle, tBTM_SCO_AIR_MODE_TYPE air_mode, UINT8 in } #endif ///(PLC_INCLUDED == TRUE) #endif /// (HFP_DYNAMIC_MEMORY == TRUE) +#if (BTC_HFP_EXT_CODEC == TRUE) + bta_ag_pkt_state_reset(); +#else bta_hf_dec_init(); bta_hf_enc_init(); +#endif return; } else { return; // Nothing to do @@ -476,6 +511,8 @@ void bta_ag_sco_co_close(void) hf_inout_pkt_size = 0; } +#if (BTC_HFP_EXT_CODEC == FALSE) + /******************************************************************************* ** ** Function bta_ag_sco_co_out_data @@ -525,7 +562,7 @@ uint32_t bta_ag_sco_co_out_data(UINT8 *p_buf) //Never run to here. } } else { - APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode); + APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode); } return 0; } @@ -546,6 +583,65 @@ void bta_ag_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status) STREAM_SKIP_UINT16(p); STREAM_TO_UINT8(pkt_size, p); +#if (BTC_HFP_EXT_CODEC == TRUE) + if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) { + btc_hf_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, status != BTM_SCO_DATA_CORRECT); + } + else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) { + if (pkt_size != hf_inout_pkt_size) { + bta_ag_co_cb.is_bad_frame = true; + } + if (status != BTM_SCO_DATA_CORRECT) { + bta_ag_co_cb.is_bad_frame = true; + } + if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) { + if (pkt_size > BTM_MSBC_FRAME_SIZE / 2) { + pkt_size = BTM_MSBC_FRAME_SIZE / 2; + } + if (bta_ag_co_cb.rx_first_pkt){ + memcpy(bta_ag_co_cb.rx_half_msbc_data, p, pkt_size); + osi_free(p_buf); + } else { + BT_HDR *p_new_buf = osi_calloc(sizeof(BT_HDR) + BTM_MSBC_FRAME_SIZE); + p_new_buf->offset = 0; + UINT8 *p_data = (UINT8 *)(p_new_buf + 1) + p_new_buf->offset; + memcpy(p_data, bta_ag_co_cb.rx_half_msbc_data, BTM_MSBC_FRAME_SIZE / 2); + memcpy(p_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size); + osi_free(p_buf); + if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p_data)) { + /* H2 header sync word found, skip */ + p_data += 2; + } + else if (!bta_ag_co_cb.is_bad_frame){ + /* not a bad frame, assume as H1 header */ + p_data += 1; + } + btc_hf_audio_data_cb_to_app((uint8_t *)p_new_buf, (uint8_t *)p_data, BTM_MSBC_FRAME_SIZE, bta_ag_co_cb.is_bad_frame); + bta_ag_co_cb.is_bad_frame = false; + memset(bta_ag_co_cb.decode_msbc_data, 0, BTM_MSBC_FRAME_SIZE); + } + bta_ag_co_cb.rx_first_pkt = !bta_ag_co_cb.rx_first_pkt; + } + else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) { + if (pkt_size > BTM_MSBC_FRAME_SIZE) { + pkt_size = BTM_MSBC_FRAME_SIZE; + } + if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p)) { + /* H2 header sync word found, skip */ + p += 2; + } + else if (!bta_ag_co_cb.is_bad_frame){ + /* not a bad frame, assume as H1 header */ + p += 1; + } + btc_hf_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, bta_ag_co_cb.is_bad_frame); + bta_ag_co_cb.is_bad_frame = false; + } + else { + osi_free(p_buf); + } + } +#else if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) { // CVSD if(status != BTM_SCO_DATA_CORRECT) { @@ -583,8 +679,12 @@ void bta_ag_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status) //Never run to here. } } else { - APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode); + APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode); } + osi_free(p_buf); +#endif } +#endif + #endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */ #endif /* #if (BTA_AG_INCLUDED == TRUE) */ diff --git a/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c b/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c index d4d597dfdd..04fd0298ad 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c +++ b/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -236,12 +236,15 @@ static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *param) else if (BTA_AG_OPEN_EVT == event) { param_len = sizeof(tBTA_AG_OPEN); } - else if ((BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event)) { + else if ((BTA_AG_CLOSE_EVT == event)) { param_len = sizeof(tBTA_AG_HDR); } else if (BTA_AG_CONN_EVT == event) { param_len = sizeof(tBTA_AG_CONN); } + else if ((BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event) || (BTA_AG_AUDIO_MSBC_OPEN_EVT == event)) { + param_len = sizeof(tBTA_AG_AUDIO_STAT); + } else if (param) { param_len = sizeof(tBTA_AG_VAL); } @@ -265,6 +268,26 @@ void btc_hf_reg_data_cb(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_ hf_local_param[0].btc_hf_outgoing_data_cb = send; } +void btc_hf_reg_audio_data_cb(esp_hf_ag_audio_data_cb_t callback) +{ + hf_local_param[0].btc_hf_audio_data_cb = callback; +} + +void btc_hf_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame) +{ + if (hf_local_param[0].btc_hf_audio_data_cb) { + /* we always have sizeof(BT_HDR) bytes free space before data, it is enough for esp_hf_audio_buff_t */ + esp_hf_audio_buff_t *audio_buff = (esp_hf_audio_buff_t *)buf; + audio_buff->buff_size = len; + audio_buff->data_len = len; + audio_buff->data = data; + hf_local_param[0].btc_hf_audio_data_cb(hf_local_param[0].btc_hf_cb.sync_conn_hdl, audio_buff, is_bad_frame); + } + else { + osi_free(buf); + } +} + void btc_hf_incoming_data_cb_to_app(const uint8_t *data, uint32_t len) { int idx = 0; @@ -949,6 +972,20 @@ bt_status_t btc_hf_ci_sco_data(void) return status; } +bool btc_hf_ag_audio_data_send(uint16_t sync_conn_hdl, uint8_t *p_buff_start, uint8_t *p_data, uint8_t data_len) +{ +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTA_HFP_EXT_CODEC == TRUE) + /* currently, sync_conn_hdl is not used */ + int idx = btc_hf_latest_connected_idx(); + CHECK_HF_SLC_CONNECTED(idx); + if (idx != BTC_HF_INVALID_IDX) { + BTA_AgAudioDataSend(hf_local_param[idx].btc_hf_cb.handle, p_buff_start, p_data, data_len); + return true; + } +#endif + return false; +} + /************************************************************************************ ** Memory malloc and release ************************************************************************************/ @@ -1266,6 +1303,13 @@ void btc_hf_call_handler(btc_msg_t *msg) btc_hf_reg_data_cb(arg->reg_data_cb.recv, arg->reg_data_cb.send); break; } + + case BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT: + { + btc_hf_reg_audio_data_cb(arg->reg_audio_data_cb.callback); + break; + } + case BTC_HF_REQUEST_PKT_STAT_EVT: { btc_hf_pkt_stat_nums_get(arg->pkt_sync_hd.sync_conn_handle); @@ -1411,7 +1455,9 @@ void btc_hf_cb_handler(btc_msg_t *msg) do { param.audio_stat.state = ESP_HF_AUDIO_STATE_CONNECTED; memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda,sizeof(esp_bd_addr_t)); + hf_local_param[idx].btc_hf_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle; param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle; + param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size; btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m); } while(0); break; @@ -1424,7 +1470,9 @@ void btc_hf_cb_handler(btc_msg_t *msg) do { param.audio_stat.state = ESP_HF_AUDIO_STATE_CONNECTED_MSBC; memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda,sizeof(esp_bd_addr_t)); + hf_local_param[idx].btc_hf_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle; param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle; + param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size; btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m); } while (0); break; @@ -1435,6 +1483,7 @@ void btc_hf_cb_handler(btc_msg_t *msg) CHECK_HF_IDX(idx); do { param.audio_stat.state = ESP_HF_AUDIO_STATE_DISCONNECTED; + hf_local_param[idx].btc_hf_cb.sync_conn_hdl = 0; memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda, sizeof(esp_bd_addr_t)); param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle; btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m); diff --git a/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c b/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c index 555e7137db..c785c73907 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c +++ b/components/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,9 +14,23 @@ #if (BTM_SCO_HCI_INCLUDED == TRUE) +#if (BTC_HFP_EXT_CODEC == FALSE) #include "oi_codec_sbc.h" #include "oi_status.h" #include "sbc_encoder.h" +#endif + +// H2: Header with synchronization word and sequence number +#define BTA_HF_H2_HEADER_SYNC_WORD 0x0801 +#define BTA_HF_H2_HEADER_SYNC_WORD_MASK 0x0FFF +#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0) +#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1) +#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12 +#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13 +#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14 +#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15 + +#define BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p) ((*((uint16_t *)p) & BTA_HF_H2_HEADER_SYNC_WORD_MASK) == BTA_HF_H2_HEADER_SYNC_WORD) #if (PLC_INCLUDED == TRUE) #include "sbc_plc.h" @@ -44,18 +58,23 @@ static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr; /* BTA-HF-CO control block to map bdaddr to BTA handle */ typedef struct { +#if (BTC_HFP_EXT_CODEC == FALSE) OI_CODEC_SBC_DECODER_CONTEXT decoder_context; OI_UINT32 decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN]; OI_INT16 decode_raw_data[HF_SBC_DEC_RAW_DATA_SIZE]; - SBC_ENC_PARAMS encoder; - UINT8 sequence_number; bool is_bad_frame; bool decode_first_pkt; - OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE]; bool encode_first_pkt; + OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE]; OI_BYTE encode_msbc_data[BTM_MSBC_FRAME_SIZE]; +#else + UINT8 sequence_number; + BOOLEAN rx_first_pkt; + BOOLEAN is_bad_frame; + UINT8 rx_half_msbc_data[BTM_MSBC_FRAME_SIZE/2]; +#endif } bta_hf_client_co_cb_t; #if HFP_DYNAMIC_MEMORY == FALSE @@ -118,6 +137,8 @@ tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, return BTA_HFP_SCO_ROUTE_HCI; } +#if (BTC_HFP_EXT_CODEC == FALSE) + /******************************************************************************* ** ** Function bta_hf_dec_init @@ -168,6 +189,19 @@ static void bta_hf_enc_init(void) { SBC_Encoder_Init(&(bta_hf_client_co_cb.encoder)); } +#endif + +#if (BTC_HFP_EXT_CODEC == TRUE) + +void bta_hf_pkt_state_reset(void) +{ + bta_hf_client_co_cb.sequence_number = 0; + bta_hf_client_co_cb.rx_first_pkt = TRUE; + bta_hf_client_co_cb.is_bad_frame = FALSE; +} + +#endif + /******************************************************************************* ** ** Function bta_hf_client_sco_co_open @@ -204,8 +238,12 @@ void bta_hf_client_sco_co_open(UINT16 handle, UINT8 air_mode, UINT8 inout_pkt_si #endif /// (HFP_DYNAMIC_MEMORY == TRUE) +#if (BTC_HFP_EXT_CODEC == TRUE) + bta_hf_pkt_state_reset(); +#else bta_hf_dec_init(); bta_hf_enc_init(); +#endif return; } else { @@ -280,18 +318,9 @@ void bta_hf_client_sco_co_close(void) ** Returns void ** *******************************************************************************/ -static void bta_hf_client_h2_header(UINT16 *p_buf) +void bta_hf_client_h2_header(UINT16 *p_buf) { - // H2: Header with synchronization word and sequence number -#define BTA_HF_H2_HEADER 0x0801 -#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0) -#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1) -#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12 -#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13 -#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14 -#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15 - - UINT16 h2_header = BTA_HF_H2_HEADER; + UINT16 h2_header = BTA_HF_H2_HEADER_SYNC_WORD; UINT8 h2_header_sn0 = bta_hf_client_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT0_MASK; UINT8 h2_header_sn1 = bta_hf_client_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT1_MASK; h2_header |= (h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 @@ -304,6 +333,8 @@ static void bta_hf_client_h2_header(UINT16 *p_buf) *p_buf = h2_header; } +#if (BTC_HFP_EXT_CODEC == FALSE) + /******************************************************************************* ** ** Function bta_hf_client_sco_co_out_data @@ -364,7 +395,7 @@ uint32_t bta_hf_client_sco_co_out_data(UINT8 *p_buf) } else { - APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode); + APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode); } return 0; } @@ -439,6 +470,8 @@ static void bta_hf_client_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN } } +#endif + /******************************************************************************* ** ** Function bta_hf_client_sco_co_in_data @@ -450,12 +483,77 @@ static void bta_hf_client_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN *******************************************************************************/ void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status) { + if (hf_air_mode != BTM_SCO_AIR_MODE_CVSD && hf_air_mode != BTM_SCO_AIR_MODE_TRANSPNT) { + APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode); + osi_free(p_buf); + return; + } + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; UINT8 pkt_size = 0; STREAM_SKIP_UINT16(p); STREAM_TO_UINT8 (pkt_size, p); +#if (BTC_HFP_EXT_CODEC == TRUE) + if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) { + btc_hf_client_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, status != BTM_SCO_DATA_CORRECT); + } + else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) { + if (pkt_size != hf_inout_pkt_size) { + bta_hf_client_co_cb.is_bad_frame = true; + } + if (status != BTM_SCO_DATA_CORRECT) { + bta_hf_client_co_cb.is_bad_frame = true; + } + if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) { + if (pkt_size > BTM_MSBC_FRAME_SIZE / 2) { + pkt_size = BTM_MSBC_FRAME_SIZE / 2; + } + if (bta_hf_client_co_cb.rx_first_pkt){ + memcpy(bta_hf_client_co_cb.rx_half_msbc_data, p, pkt_size); + osi_free(p_buf); + } else { + BT_HDR *p_new_buf = osi_calloc(sizeof(BT_HDR) + BTM_MSBC_FRAME_SIZE); + p_new_buf->offset = 0; + UINT8 *p_data = (UINT8 *)(p_new_buf + 1) + p_new_buf->offset; + memcpy(p_data, bta_hf_client_co_cb.rx_half_msbc_data, BTM_MSBC_FRAME_SIZE / 2); + memcpy(p_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size); + osi_free(p_buf); + if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p_data)) { + /* H2 header sync word found, skip */ + p_data += 2; + } + else if (!bta_hf_client_co_cb.is_bad_frame){ + /* not a bad frame, assume as H1 header */ + p_data += 1; + } + btc_hf_client_audio_data_cb_to_app((uint8_t *)p_new_buf, (uint8_t *)p_data, BTM_MSBC_FRAME_SIZE, bta_hf_client_co_cb.is_bad_frame); + bta_hf_client_co_cb.is_bad_frame = false; + memset(bta_hf_client_co_cb.rx_half_msbc_data, 0, BTM_MSBC_FRAME_SIZE); + } + bta_hf_client_co_cb.rx_first_pkt = !bta_hf_client_co_cb.rx_first_pkt; + } + else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) { + if (pkt_size > BTM_MSBC_FRAME_SIZE) { + pkt_size = BTM_MSBC_FRAME_SIZE; + } + if (BTA_HF_H2_HEADER_SYNC_WORD_CHECK(p)) { + /* H2 header sync word found, skip */ + p += 2; + } + else if (!bta_hf_client_co_cb.is_bad_frame){ + /* not a bad frame, assume as H1 header */ + p += 1; + } + btc_hf_client_audio_data_cb_to_app((uint8_t *)p_buf, (uint8_t *)p, pkt_size, bta_hf_client_co_cb.is_bad_frame); + bta_hf_client_co_cb.is_bad_frame = false; + } + else { + osi_free(p_buf); + } + } +#else if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) { // CVSD if(status != BTM_SCO_DATA_CORRECT){ @@ -496,8 +594,10 @@ void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status) //Never run to here. } } else { - APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode); + APPL_TRACE_ERROR("%s invalid air mode: %d", __FUNCTION__, hf_air_mode); } + osi_free(p_buf); +#endif } #endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */ diff --git a/components/bt/host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c b/components/bt/host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c index ea12a6928a..a1a6144c8d 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c +++ b/components/bt/host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -132,6 +132,26 @@ void btc_hf_client_reg_data_cb(esp_hf_client_incoming_data_cb_t recv, hf_client_local_param.btc_hf_client_outgoing_data_cb = send; } +static void btc_hf_client_reg_audio_data_cb(esp_hf_client_audio_data_cb_t callback) +{ + hf_client_local_param.btc_hf_client_audio_data_cb = callback; +} + +void btc_hf_client_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame) +{ + if (hf_client_local_param.btc_hf_client_audio_data_cb) { + /* we always have sizeof(BT_HDR) bytes free space before data, it is enough for esp_hf_audio_buff_t */ + esp_hf_audio_buff_t *audio_buff = (esp_hf_audio_buff_t *)buf; + audio_buff->buff_size = len; + audio_buff->data_len = len; + audio_buff->data = data; + hf_client_local_param.btc_hf_client_audio_data_cb(hf_client_local_param.btc_hf_client_cb.sync_conn_hdl, audio_buff, is_bad_frame); + } + else { + osi_free(buf); + } +} + void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len) { // todo: critical section protection @@ -1076,7 +1096,9 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED; memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); + hf_client_local_param.btc_hf_client_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle; param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle; + param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size; btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m); } while (0); break; @@ -1085,7 +1107,9 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC; memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); + hf_client_local_param.btc_hf_client_cb.sync_conn_hdl = p_data->hdr.sync_conn_handle; param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle; + param.audio_stat.preferred_frame_size = p_data->audio_stat.preferred_frame_size; btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m); } while (0); break; @@ -1094,7 +1118,9 @@ void btc_hf_client_cb_handler(btc_msg_t *msg) param.audio_stat.state = ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED; memcpy(param.audio_stat.remote_bda, &hf_client_local_param.btc_hf_client_cb.connected_bda, sizeof(esp_bd_addr_t)); + hf_client_local_param.btc_hf_client_cb.sync_conn_hdl = 0; param.audio_stat.sync_conn_handle = p_data->hdr.sync_conn_handle; + param.audio_stat.preferred_frame_size = 0; btc_hf_client_cb_to_app(ESP_HF_CLIENT_AUDIO_STATE_EVT, ¶m); } while (0); break; @@ -1183,6 +1209,9 @@ void btc_hf_client_call_handler(btc_msg_t *msg) case BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT: btc_hf_client_reg_data_cb(arg->reg_data_cb.recv, arg->reg_data_cb.send); break; + case BTC_HF_CLIENT_REGISTER_AUDIO_DATA_CALLBACK_EVT: + btc_hf_client_reg_audio_data_cb(arg->reg_audio_data_cb.callback); + break; case BTC_HF_CLIENT_SEND_NREC_EVT: btc_hf_client_send_nrec(); break; diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h index 5cecdd9951..669a12fa59 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_ag.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -57,6 +57,7 @@ typedef enum BTC_HF_END_CALL_EVT, //REG BTC_HF_REGISTER_DATA_CALLBACK_EVT, + BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT, BTC_HF_REQUEST_PKT_STAT_EVT } btc_hf_act_t; @@ -189,6 +190,11 @@ typedef union esp_hf_outgoing_data_cb_t send; } reg_data_cb; + // BTC_HF_REGISTER_AUDIO_DATA_CALLBACK_EVT + struct ag_reg_audio_data_callback { + esp_hf_ag_audio_data_cb_t callback; + } reg_audio_data_cb; + // BTC_HF_REQUEST_PKT_STAT_EVT struct ag_req_pkt_stat_sync_handle { UINT16 sync_conn_handle; @@ -211,6 +217,7 @@ typedef struct { bool initialized; UINT16 handle; + UINT16 sync_conn_hdl; bt_bdaddr_t connected_bda; tBTA_AG_PEER_FEAT peer_feat; tBTA_AG_CHLD_FEAT chld_feat; @@ -231,6 +238,7 @@ typedef struct btc_hf_cb_t btc_hf_cb; esp_hf_incoming_data_cb_t btc_hf_incoming_data_cb; esp_hf_outgoing_data_cb_t btc_hf_outgoing_data_cb; + esp_hf_ag_audio_data_cb_t btc_hf_audio_data_cb; } hf_local_param_t; #if HFP_DYNAMIC_MEMORY == TRUE @@ -247,6 +255,8 @@ void btc_hf_cb_handler(btc_msg_t *msg); //handle the event from bta void btc_hf_incoming_data_cb_to_app(const uint8_t *data, uint32_t len); +void btc_hf_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame); + uint32_t btc_hf_outgoing_data_cb_to_app(uint8_t *data, uint32_t len); void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); @@ -255,6 +265,8 @@ void btc_hf_arg_deep_free(btc_msg_t *msg); bt_status_t btc_hf_ci_sco_data(void); +bool btc_hf_ag_audio_data_send(uint16_t sync_conn_hdl, uint8_t *p_buff_start, uint8_t *p_data, uint8_t data_len); + #endif // BTC_HF_INCLUDED == TRUE #endif /* __BTC_HF_AG_H__ */ diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_client.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_client.h index 4f10371bd0..31f9454ef0 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_client.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_hf_client.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,7 @@ typedef enum { BTC_HF_CLIENT_SEND_DTMF_EVT, BTC_HF_CLIENT_REQUEST_LAST_VOICE_TAG_NUMBER_EVT, BTC_HF_CLIENT_REGISTER_DATA_CALLBACK_EVT, + BTC_HF_CLIENT_REGISTER_AUDIO_DATA_CALLBACK_EVT, BTC_HF_CLIENT_SEND_NREC_EVT, BTC_HF_CLIENT_SEND_XAPL_EVT, BTC_HF_CLIENT_SEND_IPHONEACCEV_EVT, @@ -107,6 +108,11 @@ typedef union { esp_hf_client_outgoing_data_cb_t send; } reg_data_cb; + // BTC_HF_CLIENT_REGISTER_AUDIO_DATA_CALLBACK_EVT + struct hf_client_reg_audio_data_callback { + esp_hf_client_audio_data_cb_t callback; + } reg_audio_data_cb; + //BTC_HF_CLIENT_SEND_XAPL_EVT struct send_xapl_args { char information[ESP_BT_HF_AT_SEND_XAPL_LEN + 1]; @@ -134,6 +140,7 @@ typedef struct { bool initialized; UINT16 handle; + UINT16 sync_conn_hdl; bt_bdaddr_t connected_bda; esp_hf_client_connection_state_t state; esp_hf_vr_state_t vr_state; @@ -147,6 +154,7 @@ typedef struct btc_hf_client_cb_t btc_hf_client_cb; esp_hf_client_incoming_data_cb_t btc_hf_client_incoming_data_cb; esp_hf_client_outgoing_data_cb_t btc_hf_client_outgoing_data_cb; + esp_hf_client_audio_data_cb_t btc_hf_client_audio_data_cb; }hf_client_local_param_t; #if HFP_DYNAMIC_MEMORY == TRUE @@ -162,6 +170,8 @@ void btc_hf_client_call_handler(btc_msg_t *msg); void btc_hf_client_cb_handler(btc_msg_t *msg); +void btc_hf_client_audio_data_cb_to_app(uint8_t *buf, uint8_t *data, uint16_t len, bool is_bad_frame); + void btc_hf_client_incoming_data_cb_to_app(const uint8_t *data, uint32_t len); uint32_t btc_hf_client_outgoing_data_cb_to_app(uint8_t *data, uint32_t len); diff --git a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h index 73675973d7..c15f9d0cde 100644 --- a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h +++ b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h @@ -39,6 +39,12 @@ #define UC_BT_A2DP_ENABLED FALSE #endif +#ifdef CONFIG_BT_A2DP_USE_EXTERNAL_CODEC +#define UC_BT_A2DP_USE_EXTERNAL_CODEC CONFIG_BT_A2DP_USE_EXTERNAL_CODEC +#else +#define UC_BT_A2DP_USE_EXTERNAL_CODEC FALSE +#endif + //AVRCP #ifdef CONFIG_BT_AVRCP_ENABLED #define UC_BT_AVRCP_ENABLED TRUE @@ -101,6 +107,12 @@ #define UC_BT_HFP_CLIENT_ENABLED FALSE #endif +#ifdef CONFIG_BT_HFP_USE_EXTERNAL_CODEC +#define UC_BT_HFP_USE_EXTERNAL_CODEC CONFIG_BT_HFP_USE_EXTERNAL_CODEC +#else +#define UC_BT_HFP_USE_EXTERNAL_CODEC FALSE +#endif + //HID #ifdef CONFIG_BT_HID_ENABLED #define UC_BT_HID_ENABLED CONFIG_BT_HID_ENABLED diff --git a/components/bt/host/bluedroid/common/include/common/bt_target.h b/components/bt/host/bluedroid/common/include/common/bt_target.h index 9dbc24e46d..443775657e 100644 --- a/components/bt/host/bluedroid/common/include/common/bt_target.h +++ b/components/bt/host/bluedroid/common/include/common/bt_target.h @@ -88,9 +88,13 @@ #define BTC_AV_INCLUDED TRUE #define BTA_AV_SINK_INCLUDED TRUE #define BTC_AV_SINK_INCLUDED TRUE -#define SBC_DEC_INCLUDED TRUE #define BTC_AV_SRC_INCLUDED TRUE +#if (UC_BT_A2DP_USE_EXTERNAL_CODEC == TRUE) +#define BTC_AV_EXT_CODEC TRUE +#else +#define SBC_DEC_INCLUDED TRUE #define SBC_ENC_INCLUDED TRUE +#endif #if UC_BT_AVRCP_CT_COVER_ART_ENABLED #define BTA_AV_CA_INCLUDED TRUE #define BTC_AV_CA_INCLUDED TRUE @@ -122,14 +126,22 @@ #ifndef BTM_SCO_INCLUDED #define BTM_SCO_INCLUDED TRUE #endif +#if (UC_BT_HFP_AUDIO_DATA_PATH_HCI == TRUE) +#if (UC_BT_HFP_USE_EXTERNAL_CODEC == TRUE) +#define BTC_HFP_EXT_CODEC TRUE +#define BTA_HFP_EXT_CODEC TRUE +#define PLC_INCLUDED FALSE +#else #ifndef SBC_DEC_INCLUDED #define SBC_DEC_INCLUDED TRUE #endif #ifndef SBC_ENC_INCLUDED #define SBC_ENC_INCLUDED TRUE #endif -#ifndef PLC_INCLUDED #define PLC_INCLUDED TRUE +#endif /* (UC_BT_HFP_USE_EXTERNAL_CODEC == TRUE) */ +#else +#define PLC_INCLUDED FALSE #endif #if (UC_BT_HFP_AG_ENABLED == TRUE) @@ -593,6 +605,10 @@ #define SBC_ENC_INCLUDED FALSE #endif +#ifndef BTC_HFP_EXT_CODEC +#define BTC_HFP_EXT_CODEC FALSE +#endif + /****************************************************************************** ** ** BTA-layer components @@ -642,6 +658,10 @@ #define BTA_AV_CA_INCLUDED FALSE #endif +#ifndef BTC_AV_EXT_CODEC +#define BTC_AV_EXT_CODEC FALSE +#endif + #ifndef BTA_AV_SINK_INCLUDED #define BTA_AV_SINK_INCLUDED FALSE #endif @@ -654,6 +674,10 @@ #define BTA_SDP_INCLUDED FALSE #endif +#ifndef BTA_HFP_EXT_CODEC +#define BTA_HFP_EXT_CODEC FALSE +#endif + /* This is set to enable use of GAP L2CAP connections. */ #ifndef VND_BT_JV_BTA_L2CAP #define VND_BT_JV_BTA_L2CAP FALSE