|
|
@@ -15,9 +15,67 @@
|
|
|
#include "bta/bta_hf_client_co.h"
|
|
|
#include "hci/hci_audio.h"
|
|
|
#include "btc_hf_client.h"
|
|
|
+#include "osi/allocator.h"
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
#if (BTA_HF_INCLUDED == TRUE)
|
|
|
|
|
|
#if (BTM_SCO_HCI_INCLUDED == TRUE)
|
|
|
+
|
|
|
+#include "oi_codec_sbc.h"
|
|
|
+#include "oi_status.h"
|
|
|
+#include "sbc_encoder.h"
|
|
|
+
|
|
|
+#if (PLC_INCLUDED == TRUE)
|
|
|
+#include "sbc_plc.h"
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ bool first_good_frame_found;
|
|
|
+ sbc_plc_state_t plc_state;
|
|
|
+ int16_t sbc_plc_out[SBC_FS];
|
|
|
+} bta_hf_ct_plc_t;
|
|
|
+
|
|
|
+#if HFP_DYNAMIC_MEMORY == FALSE
|
|
|
+static bta_hf_ct_plc_t bta_hf_ct_plc;
|
|
|
+#else
|
|
|
+static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr;
|
|
|
+#define bta_hf_ct_plc (*bta_hf_ct_plc_ptr)
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif ///(PLC_INCLUDED == TRUE)
|
|
|
+
|
|
|
+
|
|
|
+#define HF_SBC_DEC_CONTEXT_DATA_LEN (CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS))
|
|
|
+#define HF_SBC_DEC_RAW_DATA_SIZE 240
|
|
|
+#define HF_SBC_ENC_RAW_DATA_SIZE 240
|
|
|
+
|
|
|
+/* BTA-HF-CO control block to map bdaddr to BTA handle */
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ 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 encode_msbc_data[BTM_MSBC_FRAME_SIZE];
|
|
|
+} bta_hf_client_co_cb_t;
|
|
|
+
|
|
|
+#if HFP_DYNAMIC_MEMORY == FALSE
|
|
|
+static bta_hf_client_co_cb_t bta_hf_client_co_cb;
|
|
|
+#else
|
|
|
+static bta_hf_client_co_cb_t *bta_hf_client_co_cb_ptr;
|
|
|
+#define bta_hf_client_co_cb (*bta_hf_client_co_cb_ptr)
|
|
|
+#endif /* HFP_DYNAMIC_MEMORY == FALSE */
|
|
|
+
|
|
|
+static UINT8 hf_air_mode;
|
|
|
+static UINT8 hf_inout_pkt_size;
|
|
|
+
|
|
|
/*******************************************************************************
|
|
|
**
|
|
|
** Function bta_hf_client_co_audio_state
|
|
|
@@ -68,6 +126,56 @@ tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
|
|
|
return BTA_HFP_SCO_ROUTE_HCI;
|
|
|
}
|
|
|
|
|
|
+/*******************************************************************************
|
|
|
+ **
|
|
|
+ ** Function bta_hf_dec_init
|
|
|
+ **
|
|
|
+ ** Description Initialize decoding task
|
|
|
+ **
|
|
|
+ ** Returns void
|
|
|
+ **
|
|
|
+ *******************************************************************************/
|
|
|
+static void bta_hf_dec_init(void) {
|
|
|
+#if (PLC_INCLUDED == TRUE)
|
|
|
+ sbc_plc_init(&(bta_hf_ct_plc.plc_state));
|
|
|
+#endif ///(PLC_INCLUDED == TRUE)
|
|
|
+
|
|
|
+ OI_STATUS status;
|
|
|
+
|
|
|
+ status = OI_CODEC_SBC_DecoderReset(&bta_hf_client_co_cb.decoder_context, bta_hf_client_co_cb.decoder_context_data,
|
|
|
+ HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE);
|
|
|
+ if (!OI_SUCCESS(status)) {
|
|
|
+ APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+ **
|
|
|
+ ** Function bta_hf_enc_init
|
|
|
+ **
|
|
|
+ ** Description Initialize encoding task
|
|
|
+ **
|
|
|
+ ** Returns void
|
|
|
+ **
|
|
|
+ *******************************************************************************/
|
|
|
+static void bta_hf_enc_init(void) {
|
|
|
+ bta_hf_client_co_cb.sequence_number = 0;
|
|
|
+ bta_hf_client_co_cb.decode_first_pkt = true;
|
|
|
+ bta_hf_client_co_cb.encode_first_pkt = true;
|
|
|
+ bta_hf_client_co_cb.is_bad_frame = false;
|
|
|
+
|
|
|
+ bta_hf_client_co_cb.encoder.sbc_mode = SBC_MODE_MSBC;
|
|
|
+ bta_hf_client_co_cb.encoder.s16NumOfBlocks = 15;
|
|
|
+ bta_hf_client_co_cb.encoder.s16NumOfSubBands = 8;
|
|
|
+ bta_hf_client_co_cb.encoder.s16AllocationMethod = SBC_LOUDNESS;
|
|
|
+ bta_hf_client_co_cb.encoder.s16BitPool = 26;
|
|
|
+ bta_hf_client_co_cb.encoder.s16ChannelMode = SBC_MONO;
|
|
|
+ bta_hf_client_co_cb.encoder.s16NumOfChannels = 1;
|
|
|
+ bta_hf_client_co_cb.encoder.s16SamplingFreq = SBC_sf16000;
|
|
|
+
|
|
|
+ SBC_Encoder_Init(&(bta_hf_client_co_cb.encoder));
|
|
|
+}
|
|
|
+
|
|
|
/*******************************************************************************
|
|
|
**
|
|
|
** Function bta_hf_client_sco_co_open
|
|
|
@@ -78,10 +186,57 @@ tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
|
|
|
** Returns void
|
|
|
**
|
|
|
*******************************************************************************/
|
|
|
-void bta_hf_client_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event)
|
|
|
+void bta_hf_client_sco_co_open(UINT16 handle, UINT8 air_mode, UINT8 inout_pkt_size, UINT16 event)
|
|
|
{
|
|
|
APPL_TRACE_EVENT("%s hdl %x, pkt_sz %u, event %u", __FUNCTION__, handle,
|
|
|
- pkt_size, event);
|
|
|
+ inout_pkt_size, event);
|
|
|
+
|
|
|
+ hf_air_mode = air_mode;
|
|
|
+ hf_inout_pkt_size = inout_pkt_size;
|
|
|
+
|
|
|
+ if (air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
|
|
|
+#if (HFP_DYNAMIC_MEMORY == TRUE)
|
|
|
+ bta_hf_client_co_cb_ptr = osi_calloc(sizeof(bta_hf_client_co_cb_t));
|
|
|
+ if (!bta_hf_client_co_cb_ptr) {
|
|
|
+ APPL_TRACE_ERROR("%s allocate failed", __FUNCTION__);
|
|
|
+ goto error_exit;
|
|
|
+ }
|
|
|
+
|
|
|
+#if (PLC_INCLUDED == TRUE)
|
|
|
+ bta_hf_ct_plc_ptr = (bta_hf_ct_plc_t *)osi_calloc(sizeof(bta_hf_ct_plc_t));
|
|
|
+ if (!bta_hf_ct_plc_ptr) {
|
|
|
+ APPL_TRACE_ERROR("%s malloc fail.", __FUNCTION__);
|
|
|
+ goto error_exit;
|
|
|
+ }
|
|
|
+#endif ///(PLC_INCLUDED == TRUE)
|
|
|
+
|
|
|
+#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
|
|
|
+
|
|
|
+ bta_hf_dec_init();
|
|
|
+ bta_hf_enc_init();
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+error_exit:;
|
|
|
+#if (HFP_DYNAMIC_MEMORY == TRUE)
|
|
|
+ if (bta_hf_client_co_cb_ptr) {
|
|
|
+ osi_free(bta_hf_client_co_cb_ptr);
|
|
|
+ bta_hf_client_co_cb_ptr = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+#if (PLC_INCLUDED == TRUE)
|
|
|
+ if (bta_hf_ct_plc_ptr) {
|
|
|
+ osi_free(bta_hf_ct_plc_ptr);
|
|
|
+ bta_hf_ct_plc_ptr = NULL;
|
|
|
+ }
|
|
|
+#endif ///(PLC_INCLUDED == TRUE)
|
|
|
+
|
|
|
+#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
|
|
|
+ } else {
|
|
|
+ // Nothing to do
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
|
@@ -97,6 +252,59 @@ void bta_hf_client_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event)
|
|
|
void bta_hf_client_sco_co_close(void)
|
|
|
{
|
|
|
APPL_TRACE_EVENT("%s", __FUNCTION__);
|
|
|
+
|
|
|
+ if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
|
|
|
+#if (PLC_INCLUDED == TRUE)
|
|
|
+ sbc_plc_deinit(&(bta_hf_ct_plc.plc_state));
|
|
|
+ bta_hf_ct_plc.first_good_frame_found = FALSE;
|
|
|
+
|
|
|
+#if (HFP_DYNAMIC_MEMORY == TRUE)
|
|
|
+ osi_free(bta_hf_ct_plc_ptr);
|
|
|
+ bta_hf_ct_plc_ptr = NULL;
|
|
|
+#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
|
|
|
+
|
|
|
+#endif ///(PLC_INCLUDED == TRUE)
|
|
|
+
|
|
|
+#if (HFP_DYNAMIC_MEMORY == TRUE)
|
|
|
+ osi_free(bta_hf_client_co_cb_ptr);
|
|
|
+ bta_hf_client_co_cb_ptr = NULL;
|
|
|
+#endif /* HFP_DYNAMIC_MEMORY == TRUE */
|
|
|
+ } else {
|
|
|
+ // Nothing to do
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+**
|
|
|
+** Function bta_hf_client_h2_header
|
|
|
+**
|
|
|
+** Description This function is called to fill in H2 header
|
|
|
+**
|
|
|
+** Returns void
|
|
|
+**
|
|
|
+*******************************************************************************/
|
|
|
+static 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;
|
|
|
+ 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
|
|
|
+ | h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET2
|
|
|
+ | h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 - 1)
|
|
|
+ | h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 - 1)
|
|
|
+ );
|
|
|
+
|
|
|
+ bta_hf_client_co_cb.sequence_number++;
|
|
|
+ *p_buf = h2_header;
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
|
@@ -108,9 +316,126 @@ void bta_hf_client_sco_co_close(void)
|
|
|
** Returns number of bytes got from application
|
|
|
**
|
|
|
*******************************************************************************/
|
|
|
-uint32_t bta_hf_client_sco_co_out_data(uint8_t *p_buf, uint32_t sz)
|
|
|
+uint32_t bta_hf_client_sco_co_out_data(UINT8 *p_buf)
|
|
|
{
|
|
|
- return btc_hf_client_outgoing_data_cb_to_app(p_buf, sz);
|
|
|
+ if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
|
|
|
+ // CVSD
|
|
|
+ uint32_t hf_raw_pkt_size = hf_inout_pkt_size;
|
|
|
+ return btc_hf_client_outgoing_data_cb_to_app(p_buf, hf_raw_pkt_size);
|
|
|
+ } else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
|
|
|
+ // mSBC
|
|
|
+
|
|
|
+ if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
|
|
|
+ if (bta_hf_client_co_cb.encode_first_pkt){
|
|
|
+ UINT32 size = btc_hf_client_outgoing_data_cb_to_app((UINT8 *)bta_hf_client_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
|
|
|
+ if (size != HF_SBC_ENC_RAW_DATA_SIZE){
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ bta_hf_client_h2_header((UINT16 *)bta_hf_client_co_cb.encode_msbc_data);
|
|
|
+ bta_hf_client_co_cb.encoder.pu8Packet = bta_hf_client_co_cb.encode_msbc_data + 2;
|
|
|
+
|
|
|
+ SBC_Encoder(&bta_hf_client_co_cb.encoder);
|
|
|
+ memcpy(p_buf, bta_hf_client_co_cb.encode_msbc_data, hf_inout_pkt_size);
|
|
|
+ bta_hf_client_co_cb.encode_first_pkt = !bta_hf_client_co_cb.encode_first_pkt;
|
|
|
+ return hf_inout_pkt_size;
|
|
|
+ } else {
|
|
|
+ memcpy(p_buf, bta_hf_client_co_cb.encode_msbc_data + hf_inout_pkt_size, hf_inout_pkt_size);
|
|
|
+ bta_hf_client_co_cb.encode_first_pkt = !bta_hf_client_co_cb.encode_first_pkt;
|
|
|
+ return hf_inout_pkt_size;
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
|
|
|
+ UINT32 size = btc_hf_client_outgoing_data_cb_to_app((UINT8 *)bta_hf_client_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
|
|
|
+ if (size != HF_SBC_ENC_RAW_DATA_SIZE){
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ bta_hf_client_h2_header((UINT16 *)p_buf);
|
|
|
+ bta_hf_client_co_cb.encoder.pu8Packet = p_buf + 2;
|
|
|
+
|
|
|
+ SBC_Encoder(&bta_hf_client_co_cb.encoder);
|
|
|
+ return hf_inout_pkt_size;
|
|
|
+ } else {
|
|
|
+ //Never run to here.
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ } else {
|
|
|
+ APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************
|
|
|
+**
|
|
|
+** Function bta_hf_client_decode_msbc_frame
|
|
|
+**
|
|
|
+** Description This function is called decode a mSBC frame
|
|
|
+**
|
|
|
+** Returns void
|
|
|
+**
|
|
|
+*******************************************************************************/
|
|
|
+static void bta_hf_client_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN is_bad_frame){
|
|
|
+ OI_STATUS status;
|
|
|
+ const OI_BYTE *zero_signal_frame_data;
|
|
|
+ UINT8 zero_signal_frame_len = BTM_MSBC_FRAME_DATA_SIZE;
|
|
|
+ UINT32 sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
|
|
|
+
|
|
|
+ if (is_bad_frame){
|
|
|
+ status = OI_CODEC_SBC_CHECKSUM_MISMATCH;
|
|
|
+ } else {
|
|
|
+ status = OI_CODEC_SBC_DecodeFrame(&bta_hf_client_co_cb.decoder_context, (const OI_BYTE **)data,
|
|
|
+ (OI_UINT32 *)length,
|
|
|
+ (OI_INT16 *)bta_hf_client_co_cb.decode_raw_data,
|
|
|
+ (OI_UINT32 *)&sbc_raw_data_size);
|
|
|
+ }
|
|
|
+
|
|
|
+// PLC_INCLUDED will be set to TRUE when enabling Wide Band Speech
|
|
|
+#if (PLC_INCLUDED == TRUE)
|
|
|
+ switch(status){
|
|
|
+ case OI_OK:
|
|
|
+ bta_hf_ct_plc.first_good_frame_found = TRUE;
|
|
|
+ sbc_plc_good_frame(&(bta_hf_ct_plc.plc_state), (int16_t *)bta_hf_client_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
|
|
|
+ case OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA:
|
|
|
+ case OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA:
|
|
|
+ case OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA:
|
|
|
+ break;
|
|
|
+ case OI_CODEC_SBC_NO_SYNCWORD:
|
|
|
+ case OI_CODEC_SBC_CHECKSUM_MISMATCH:
|
|
|
+ if (!bta_hf_ct_plc.first_good_frame_found) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ zero_signal_frame_data = sbc_plc_zero_signal_frame();
|
|
|
+ sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
|
|
|
+ status = OI_CODEC_SBC_DecodeFrame(&bta_hf_client_co_cb.decoder_context, &zero_signal_frame_data,
|
|
|
+ (OI_UINT32 *)&zero_signal_frame_len,
|
|
|
+ (OI_INT16 *)bta_hf_client_co_cb.decode_raw_data,
|
|
|
+ (OI_UINT32 *)&sbc_raw_data_size);
|
|
|
+ sbc_plc_bad_frame(&(bta_hf_ct_plc.plc_state), bta_hf_client_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
|
|
|
+ APPL_TRACE_DEBUG("bad frame, using PLC to fix it.");
|
|
|
+ break;
|
|
|
+ case OI_STATUS_INVALID_PARAMETERS:
|
|
|
+ // This caused by corrupt frames.
|
|
|
+ // The codec apparently does not recover from this.
|
|
|
+ // Re-initialize the codec.
|
|
|
+ APPL_TRACE_ERROR("Frame decode error: OI_STATUS_INVALID_PARAMETERS");
|
|
|
+
|
|
|
+ if (!OI_SUCCESS(OI_CODEC_SBC_DecoderReset(&bta_hf_client_co_cb.decoder_context, bta_hf_client_co_cb.decoder_context_data,
|
|
|
+ HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE))) {
|
|
|
+ APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ APPL_TRACE_ERROR("Frame decode error: %d", status);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+#endif ///(PLC_INCLUDED == TRUE)
|
|
|
+
|
|
|
+ if (OI_SUCCESS(status)){
|
|
|
+ btc_hf_client_incoming_data_cb_to_app((const uint8_t *)(bta_hf_ct_plc.sbc_plc_out), sbc_raw_data_size);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
|
@@ -124,14 +449,56 @@ uint32_t bta_hf_client_sco_co_out_data(uint8_t *p_buf, uint32_t sz)
|
|
|
*******************************************************************************/
|
|
|
void bta_hf_client_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
|
|
|
{
|
|
|
- UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
|
|
- UINT8 pkt_size = 0;
|
|
|
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
|
|
+ UINT8 pkt_size = 0;
|
|
|
|
|
|
STREAM_SKIP_UINT16(p);
|
|
|
STREAM_TO_UINT8 (pkt_size, p);
|
|
|
- btc_hf_client_incoming_data_cb_to_app(p, pkt_size);
|
|
|
+
|
|
|
+ if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
|
|
|
+ // CVSD
|
|
|
+ if(status != BTM_SCO_DATA_CORRECT){
|
|
|
+ APPL_TRACE_DEBUG("%s: not a correct frame(%d).", __func__, status);
|
|
|
+ }
|
|
|
+ btc_hf_client_incoming_data_cb_to_app(p, pkt_size);
|
|
|
+ } else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
|
|
|
+ // mSBC
|
|
|
+ UINT8 *data = NULL;
|
|
|
+
|
|
|
+ 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 (bta_hf_client_co_cb.decode_first_pkt){
|
|
|
+ if (!bta_hf_client_co_cb.is_bad_frame){
|
|
|
+ memcpy(bta_hf_client_co_cb.decode_msbc_data, p, pkt_size);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!bta_hf_client_co_cb.is_bad_frame){
|
|
|
+ memcpy(bta_hf_client_co_cb.decode_msbc_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size);
|
|
|
+ }
|
|
|
+
|
|
|
+ data = bta_hf_client_co_cb.decode_msbc_data;
|
|
|
+ bta_hf_client_decode_msbc_frame(&data, &pkt_size, bta_hf_client_co_cb.is_bad_frame);
|
|
|
+ bta_hf_client_co_cb.is_bad_frame = false;
|
|
|
+ }
|
|
|
+ bta_hf_client_co_cb.decode_first_pkt = !bta_hf_client_co_cb.decode_first_pkt;
|
|
|
+
|
|
|
+ } else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
|
|
|
+ data = p;
|
|
|
+ bta_hf_client_decode_msbc_frame(&data, &pkt_size, bta_hf_client_co_cb.is_bad_frame);
|
|
|
+ bta_hf_client_co_cb.is_bad_frame = false;
|
|
|
+ } else {
|
|
|
+ //Never run to here.
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
|
|
|
|
|
|
-#endif /* #if (BTA_HF_INCLUDED == TRUE) */
|
|
|
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
|