forked from espressif/esp-idf
refactor(bt/bluedroid): Refactor hfp audio data path
- Refactor audio APIs, optimize audio data path, reduce memory copy operations - Support using external codec in application layer
This commit is contained 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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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)*/
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user