mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-03 03:31:41 +03:00
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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user