]> granicus.if.org Git - esp-idf/commitdiff
components/bt: Enable mSBC and add decoder and encoder
authorbaohongde <baohongde@espressif.com>
Tue, 14 May 2019 07:19:07 +0000 (15:19 +0800)
committerbaohongde <baohongde@espressif.com>
Fri, 24 May 2019 09:36:10 +0000 (17:36 +0800)
14 files changed:
components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c
components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c
components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h
components/bt/bluedroid/bta/include/bta/bta_hf_client_co.h
components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c
components/bt/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c
components/bt/bluedroid/common/include/common/bt_target.h
components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h
components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h
components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c
components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c
components/bt/bluedroid/external/sbc/plc/sbc_plc.c
components/bt/bluedroid/stack/btm/include/btm_int.h
components/bt/bluedroid/stack/include/stack/btm_api.h

index 16e67cf7313d9e83c0993a6bcdb58a989d1c1363..dcaf665dbcb31922763a2c3e630a3a52141f1027 100644 (file)
@@ -232,6 +232,8 @@ const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = {
     bta_hf_client_st_closing
 };
 
+const char *bta_hf_client_version = "1.6";
+
 /* HF Client control block */
 #if BTA_DYNAMIC_MEMORY == FALSE
 tBTA_HF_CLIENT_CB  bta_hf_client_cb;
@@ -385,15 +387,11 @@ static void bta_hf_client_api_enable(tBTA_HF_CLIENT_DATA *p_data)
     bta_hf_client_cb.p_cback = p_data->api_enable.p_cback;
 
     /* check if mSBC support enabled */
-#if 0 // todo
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.bluetooth.hfp.ver", value, "0");
-    if (strcmp(value, "1.6") == 0) {
+    if (strcmp(bta_hf_client_version, "1.6") == 0) {
         bta_hf_client_cb.msbc_enabled = TRUE;
+    } else{
+        bta_hf_client_cb.msbc_enabled = FALSE;
     }
-#else
-    bta_hf_client_cb.msbc_enabled = FALSE;
-#endif
 
     bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
 
index 16efd66736c7df96a818f66c52e671042e082b58..e9396f14a33c08e369c60faf0ff911e1d4d2c93f 100644 (file)
@@ -268,13 +268,28 @@ static void bta_hf_client_sco_conn_cback(UINT16 sco_idx)
 {
     BT_HDR  *p_buf;
     UINT8 *rem_bd;
+    tBTM_ESCO_DATA sco_data;
 
     APPL_TRACE_DEBUG("%s %d", __FUNCTION__, sco_idx);
 
     rem_bd = BTM_ReadScoBdAddr(sco_idx);
+    BTM_ReadEScoLinkParms (sco_idx, &sco_data);
 
     if (rem_bd && bdcmp(bta_hf_client_cb.scb.peer_addr, rem_bd) == 0 &&
             bta_hf_client_cb.scb.svc_conn && bta_hf_client_cb.scb.sco_idx == sco_idx) {
+
+        bta_hf_client_cb.scb.link_type = sco_data.link_type;
+        bta_hf_client_cb.scb.tx_interval = sco_data.tx_interval;
+        bta_hf_client_cb.scb.retrans_window = sco_data.retrans_window;
+        bta_hf_client_cb.scb.air_mode = sco_data.air_mode;
+        if (sco_data.air_mode == BTM_SCO_AIR_MODE_CVSD) {
+            bta_hf_client_cb.scb.tx_pkt_len = sco_data.tx_pkt_len * 2;
+            bta_hf_client_cb.scb.rx_pkt_len = sco_data.rx_pkt_len * 2;
+        } else {
+            bta_hf_client_cb.scb.tx_pkt_len = sco_data.tx_pkt_len;
+            bta_hf_client_cb.scb.rx_pkt_len = sco_data.rx_pkt_len;
+        }
+
         if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
             p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
             p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;
@@ -428,20 +443,20 @@ static void bta_hf_client_sco_event(UINT8 event)
 
 #if (BTM_SCO_HCI_INCLUDED == TRUE )
     if (event == BTA_HF_CLIENT_SCO_CI_DATA_E) {
-        uint16_t pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
-        uint16_t len_to_send = 0;
+        UINT16 pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
+        UINT16 len_to_send = 0;
         while (true)
         {
-            p_buf = osi_malloc(sizeof(BT_HDR) + pkt_offset + BTM_SCO_DATA_SIZE_MAX);
+            p_buf = osi_calloc(sizeof(BT_HDR) + pkt_offset + p_scb->tx_pkt_len);
             if (!p_buf) {
                 APPL_TRACE_WARNING("%s, no mem", __FUNCTION__);
                 break;
             }
 
             p_buf->offset = pkt_offset;
-            p_buf->len = BTM_SCO_DATA_SIZE_MAX;
-            len_to_send = bta_hf_client_sco_co_out_data(p_buf->data + pkt_offset, BTM_SCO_DATA_SIZE_MAX);
-            if (len_to_send == BTM_SCO_DATA_SIZE_MAX) {
+            len_to_send = bta_hf_client_sco_co_out_data(p_buf->data + pkt_offset);
+            p_buf->len = len_to_send;
+            if (len_to_send == p_scb->tx_pkt_len) {
                 // expect to get the exact size of data from upper layer
                 if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_OPEN_ST) {
                     tBTM_STATUS write_stat = BTM_WriteScoData(p_scb->sco_idx, p_buf);
@@ -731,7 +746,8 @@ void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA *p_data)
 #if (BTM_SCO_HCI_INCLUDED == TRUE)
     bta_hf_client_co_audio_state(bta_hf_client_cb.scb.sco_idx, SCO_STATE_ON, 0);
     /* open SCO codec if SCO is routed through transport */
-    bta_hf_client_sco_co_open(bta_hf_client_cb.scb.sco_idx, BTA_HFP_SCO_OUT_PKT_SIZE, BTA_HF_CLIENT_CI_SCO_DATA_EVT);
+    bta_hf_client_sco_co_open(bta_hf_client_cb.scb.sco_idx, bta_hf_client_cb.scb.air_mode,
+                                bta_hf_client_cb.scb.tx_pkt_len, BTA_HF_CLIENT_CI_SCO_DATA_EVT);
 #endif
 
     if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC) {
index 2e3fab9c1b9094878700d52f9dc418ee2123c361..b5b07b9c591a9002029fbe6840fe97c40b346668 100644 (file)
@@ -157,6 +157,13 @@ typedef struct {
     tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */
     TIMER_LIST_ENT      colli_timer;    /* Collision timer */
     BOOLEAN             colli_tmr_on;   /* TRUE if collision timer is active */
+
+    UINT16              rx_pkt_len;
+    UINT16              tx_pkt_len;
+    UINT8               link_type;      /* BTM_LINK_TYPE_SCO or BTM_LINK_TYPE_ESCO */
+    UINT8               tx_interval;
+    UINT8               retrans_window;
+    UINT8               air_mode;
 } tBTA_HF_CLIENT_SCB;
 
 /* sco states */
index af53e6e318d55c69457fd7c82eb795bf50e0a911..eef1c6668cac5f25ab30974824d29763ba6fdbd5 100644 (file)
@@ -73,7 +73,7 @@ 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 pkt_size, UINT16 event);
 
 /*******************************************************************************
 **
@@ -96,7 +96,7 @@ 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);
 
 /*******************************************************************************
 **
index 619e0143a2736e55a1010f8f4d6faa012b0934d8..a5d09b2ca1c8009a0e667669013b9508eda0038e 100644 (file)
@@ -516,7 +516,7 @@ static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg
     btc_aa_snk_cb.rx_flush = FALSE;
     APPL_TRACE_EVENT("Reset to sink role");
     status = OI_CODEC_SBC_DecoderReset(&btc_sbc_decoder_context, btc_sbc_decoder_context_data,
-                                       BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 2, 2, FALSE);
+                                       BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 2, 2, FALSE, FALSE);
     if (!OI_SUCCESS(status)) {
         APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
     }
index a0e003872bcd244b07b63852c18e4e8e17bf4927..6b3830b5e78be448dd72129ad25071aaafced755 100644 (file)
 
 #if (BTM_SCO_HCI_INCLUDED == TRUE)
 
+#include "btm_int.h"
+#include "stack/btm_api.h"
+#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;
@@ -39,6 +46,31 @@ static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr;
 
 #endif  ///(PLC_INCLUDED == TRUE)
 
+
+#define HF_SBC_DEC_CONTEXT_DATA_LEN     (CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS))
+#define HF_SBC_DEC_PCM_DATA_LEN         240
+#define HF_SBC_ENC_PCM_DATA_LEN         240
+
+#if HFP_DYNAMIC_MEMORY == FALSE
+static OI_CODEC_SBC_DECODER_CONTEXT hf_sbc_decoder_context;
+static OI_UINT32 hf_sbc_decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN];
+static OI_INT16 hf_sbc_decode_pcm_data[HF_SBC_DEC_PCM_DATA_LEN];
+
+static SBC_ENC_PARAMS hf_sbc_encoder;
+#else
+static OI_CODEC_SBC_DECODER_CONTEXT *hf_sbc_decoder_context_ptr;
+static OI_UINT32 *hf_sbc_decoder_context_data;
+static OI_INT16 *hf_sbc_decode_pcm_data;
+#define hf_sbc_decoder_context (*hf_sbc_decoder_context_ptr)
+
+static SBC_ENC_PARAMS *hf_sbc_encoder_ptr;
+#define hf_sbc_encoder (*hf_sbc_encoder_ptr)
+#endif /* HFP_DYNAMIC_MEMORY == FALSE */
+
+static UINT8 hf_sequence_number = 0;
+static UINT8 hf_air_mode;
+static UINT8 hf_pkt_size;
+
 /*******************************************************************************
 **
 ** Function         bta_hf_client_co_audio_state
@@ -86,10 +118,56 @@ tBTA_HFP_SCO_ROUTE_TYPE bta_hf_client_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
 {
     APPL_TRACE_EVENT("%s rx_bw %d, tx_bw %d, codec %d", __FUNCTION__, rx_bw, tx_bw,
                      p_codec_info->codec_type);
-
     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(&hf_sbc_decoder_context, hf_sbc_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) {
+    hf_sequence_number = 0;
+
+    hf_sbc_encoder.sbc_mode = SBC_MODE_MSBC;
+    hf_sbc_encoder.s16NumOfBlocks    = 15;
+    hf_sbc_encoder.s16NumOfSubBands  = 8;
+    hf_sbc_encoder.s16AllocationMethod = SBC_LOUDNESS;
+    hf_sbc_encoder.s16BitPool   = 26;
+    hf_sbc_encoder.s16ChannelMode = SBC_MONO;
+    hf_sbc_encoder.s16NumOfChannels = 1;
+    hf_sbc_encoder.s16SamplingFreq = SBC_sf16000;
+
+    SBC_Encoder_Init(&(hf_sbc_encoder));
+}
+
 /*******************************************************************************
 **
 ** Function         bta_hf_client_sco_co_open
@@ -100,23 +178,78 @@ 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 pkt_size, UINT16 event)
 {
     APPL_TRACE_EVENT("%s hdl %x, pkt_sz %u, event %u", __FUNCTION__, handle,
                      pkt_size, event);
 
-#if (PLC_INCLUDED == TRUE)
+    hf_air_mode = air_mode;
+    hf_pkt_size = pkt_size;
 
+    if (air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
 #if (HFP_DYNAMIC_MEMORY == TRUE)
-    if ((bta_hf_ct_plc_ptr = (bta_hf_ct_plc_t *)osi_malloc(sizeof(bta_hf_ct_plc_t))) == NULL) {
-        APPL_TRACE_ERROR("%s malloc fail.", __FUNCTION__);
-        return;
-    }
-    memset((void *)bta_hf_ct_plc_ptr, 0, sizeof(bta_hf_ct_plc_t));
+        hf_sbc_decoder_context_ptr = osi_calloc(sizeof(OI_CODEC_SBC_DECODER_CONTEXT));
+        hf_sbc_decoder_context_data = osi_calloc(HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32));
+        hf_sbc_decode_pcm_data = osi_calloc(HF_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16));
+        if (!hf_sbc_decoder_context_ptr || !hf_sbc_decoder_context_data || !hf_sbc_decode_pcm_data) {
+            APPL_TRACE_ERROR("%s failed to allocate SBC decoder", __FUNCTION__);
+            goto error_exit;
+        }
+
+        hf_sbc_encoder_ptr = osi_calloc(sizeof(SBC_ENC_PARAMS));
+
+        if (!hf_sbc_encoder_ptr) {
+            APPL_TRACE_ERROR("%s failed to allocate SBC encoder", __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)
 
-    sbc_plc_init(&(bta_hf_ct_plc.plc_state));
+    bta_hf_dec_init();
+    bta_hf_enc_init();
+
+    return;
+
+error_exit:;
+#if (HFP_DYNAMIC_MEMORY == TRUE)
+        if (hf_sbc_decoder_context_ptr) {
+            osi_free(hf_sbc_decoder_context_ptr);
+            hf_sbc_decoder_context_ptr = NULL;
+        }
+        if (hf_sbc_decoder_context_data) {
+            osi_free(hf_sbc_decoder_context_data);
+            hf_sbc_decoder_context_data = NULL;
+        }
+        if (hf_sbc_decode_pcm_data) {
+            osi_free(hf_sbc_decode_pcm_data);
+            hf_sbc_decode_pcm_data = NULL;
+        }
+        if (hf_sbc_encoder_ptr) {
+            osi_free(hf_sbc_encoder_ptr);
+            hf_sbc_encoder_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;
 }
 
 /*******************************************************************************
@@ -133,14 +266,66 @@ 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));
+        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);
+        osi_free(bta_hf_ct_plc_ptr);
 #endif  /// (HFP_DYNAMIC_MEMORY == TRUE)
 
 #endif  ///(PLC_INCLUDED == TRUE)
+
+#if (HFP_DYNAMIC_MEMORY == TRUE)
+        osi_free(hf_sbc_decoder_context_ptr);
+        hf_sbc_decoder_context_ptr = NULL;
+
+        osi_free(hf_sbc_decoder_context_data);
+        hf_sbc_decoder_context_data = NULL;
+
+        osi_free(hf_sbc_decode_pcm_data);
+        hf_sbc_decode_pcm_data = NULL;
+
+        osi_free(hf_sbc_encoder_ptr);
+        hf_sbc_encoder_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 = hf_sequence_number & BTA_HF_H2_HEADER_BIT0_MASK;
+    UINT8 h2_header_sn1 = hf_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)
+                );
+
+    hf_sequence_number++;
+    *p_buf = h2_header;
 }
 
 /*******************************************************************************
@@ -152,9 +337,101 @@ 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
+        return btc_hf_client_outgoing_data_cb_to_app(p_buf, hf_pkt_size);
+    } else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
+        // mSBC
+        UINT32 size = btc_hf_client_outgoing_data_cb_to_app((UINT8 *)hf_sbc_encoder.as16PcmBuffer, HF_SBC_ENC_PCM_DATA_LEN);
+        if (size != HF_SBC_ENC_PCM_DATA_LEN){
+            return 0;
+        }
+
+        bta_hf_client_h2_header((UINT16 *)p_buf);
+        hf_sbc_encoder.pu8Packet = p_buf + 2;
+
+        SBC_Encoder(&hf_sbc_encoder);
+        if (hf_sbc_encoder.u16PacketLength == BTM_ESCO_DATA_SIZE) {
+            return BTM_ESCO_DATA_SIZE_MAX;
+        } else {
+            return 0;
+        }
+    } 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_ESCO_DATA_SIZE;
+    UINT32 sbc_frame_len = HF_SBC_DEC_PCM_DATA_LEN;
+
+    if (is_bad_frame){
+        status = OI_CODEC_SBC_CHECKSUM_MISMATCH;
+    } else {
+        status = OI_CODEC_SBC_DecodeFrame(&hf_sbc_decoder_context, (const OI_BYTE **)data,
+                                          (OI_UINT32 *)length,
+                                          (OI_INT16 *)hf_sbc_decode_pcm_data,
+                                          (OI_UINT32 *)&sbc_frame_len);
+    }
+
+// 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 *)hf_sbc_decode_pcm_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_frame_len = HF_SBC_DEC_PCM_DATA_LEN;
+            status = OI_CODEC_SBC_DecodeFrame(&hf_sbc_decoder_context, &zero_signal_frame_data,
+                                                (OI_UINT32 *)&zero_signal_frame_len,
+                                                (OI_INT16 *)hf_sbc_decode_pcm_data,
+                                                (OI_UINT32 *)&sbc_frame_len);
+
+            sbc_plc_bad_frame(&(bta_hf_ct_plc.plc_state), hf_sbc_decode_pcm_data, bta_hf_ct_plc.sbc_plc_out);
+            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(&hf_sbc_decoder_context, hf_sbc_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_frame_len);
+    }
 }
 
 /*******************************************************************************
@@ -168,18 +445,40 @@ 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;
+    UINT16 handle, sco_index;
 
-    STREAM_SKIP_UINT16(p);
+    STREAM_TO_UINT16 (handle, p);
     STREAM_TO_UINT8 (pkt_size, p);
 
-    if(status != BTM_SCO_DATA_CORRECT){
-        APPL_TRACE_DEBUG("%s: not a correct frame(%d).", __func__, status);
+    handle = BTMD_GET_HANDLE (handle);
+    sco_index = btm_find_scb_by_handle(handle);
+    tSCO_CONN *sco_p = &btm_cb.sco_cb.sco_db[sco_index];
+
+    if (sco_p->esco.data.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 (sco_p->esco.data.air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
+        // mSBC
+        BOOLEAN is_bad_frame = false;
+        UINT8 msbc_frame_size = BTM_ESCO_DATA_SIZE;
+        if (pkt_size < msbc_frame_size) {
+            is_bad_frame = true;
+        }
+        if (status != BTM_SCO_DATA_CORRECT) {
+            is_bad_frame = true;
+        }
+        UINT8 *data = p;
+        bta_hf_client_decode_msbc_frame(&data, &pkt_size, is_bad_frame);
+    } else {
+        APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, sco_p->esco.data.air_mode);
     }
-    btc_hf_client_incoming_data_cb_to_app(p, pkt_size);
 }
 
 #endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
 
-#endif /* #if (BTA_HF_INCLUDED == TRUE) */
+#endif /* #if (BTA_HF_INCLUDED == TRUE) */
\ No newline at end of file
index 258c13d2d1d3f55d6ec73da10ab516f2bb3a176e..0c57d0e16fb803f83428cab4b18b2ac048512d53 100644 (file)
 #ifndef BTM_MAX_SCO_LINKS
 #define BTM_MAX_SCO_LINKS           (1)
 #endif
+#ifndef SBC_DEC_INCLUDED
+#define SBC_DEC_INCLUDED            TRUE
+#endif
+#ifndef SBC_ENC_INCLUDED
+#define SBC_ENC_INCLUDED            TRUE
+#endif
 #endif  /* CONFIG_HFP_HF_ENABLE */
 
 #if CONFIG_BT_SSP_ENABLED
 
 #ifndef CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM
 #define BLE_ADV_REPORT_FLOW_CONTROL_NUM   100
-#else 
+#else
 #define BLE_ADV_REPORT_FLOW_CONTROL_NUM     CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM
 #endif /* CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM */
 
 #ifndef CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD
 #define BLE_ADV_REPORT_DISCARD_THRSHOLD  20
-#else 
+#else
 #define BLE_ADV_REPORT_DISCARD_THRSHOLD  CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD
 #endif /* CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD */
 
 #define BTM_SCO_DATA_SIZE_MAX       120 //240
 #endif
 
+/* max TX eSCO data packet size */
+#ifndef BTM_ESCO_DATA_SIZE_MAX
+#define BTM_ESCO_DATA_SIZE_MAX      60
+#endif
+
+/* TX eSCO data packet size */
+#ifndef BTM_ESCO_DATA_SIZE
+#define BTM_ESCO_DATA_SIZE          57
+#endif
+
 /* The size in bytes of the BTM inquiry database. 5 As Default */
 #ifndef BTM_INQ_DB_SIZE
 #define BTM_INQ_DB_SIZE             5
index 6f31348957dc8dcc81f1bdd9d9d2f73ec8e41387..643bd82cc53798f0670960f6292489769f59ba85 100644 (file)
@@ -78,6 +78,9 @@ Declarations of codec functions, data types, and macros.
 #define OI_SBC_ENHANCED_SYNCWORD 0x9d
 #define OI_mSBC_SYNCWORD 0xad
 
+#define OI_SBC_MODE_STD      0
+#define OI_SBC_MODE_MSBC     1
+
 /**@name Sampling frequencies */
 /**@{*/
 #define SBC_FREQ_16000 0 /**< The sampling frequency is 16 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */
@@ -200,6 +203,7 @@ typedef struct {
     OI_UINT8 restrictSubbands;
     OI_UINT8 enhancedEnabled;
     OI_UINT8 bufferedBlocks;
+    OI_UINT8 sbc_mode;                      /* OI_SBC_MODE_STD or OI_SBC_MODE_MSBC */
 } OI_CODEC_SBC_DECODER_CONTEXT;
 
 typedef struct {
@@ -236,7 +240,8 @@ OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
                                     OI_UINT32 decoderDataBytes,
                                     OI_UINT8 maxChannels,
                                     OI_UINT8 pcmStride,
-                                    OI_BOOL enhanced);
+                                    OI_BOOL enhanced,
+                                    OI_BOOL msbc_enable);
 
 /**
  * This function restricts the kind of SBC frames that the Decoder will
index 4e3897614ff8e7f65e3cf7a6aa15d853b0d9b890..092d26f9af9206974145c8b0ca67156baee8f08c 100644 (file)
@@ -170,7 +170,8 @@ INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
                                        OI_UINT32 decoderDataBytes,
                                        OI_BYTE maxChannels,
                                        OI_BYTE pcmStride,
-                                       OI_BOOL enhanced);
+                                       OI_BOOL enhanced,
+                                       OI_BOOL msbc_enable);
 
 INLINE OI_UINT16 OI_SBC_CalculateFrameAndHeaderlen(OI_CODEC_SBC_FRAME_INFO *frame, OI_UINT *headerLen_);
 
index 1e4d73995eb7d1b521ddf81128f9398e653b5582..f198f57933927d1614e2cbb7fa0e66c779178531 100644 (file)
@@ -47,7 +47,8 @@ INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
                                        OI_UINT32 decoderDataBytes,
                                        OI_BYTE maxChannels,
                                        OI_BYTE pcmStride,
-                                       OI_BOOL enhanced)
+                                       OI_BOOL enhanced,
+                                       OI_BOOL msbc_enable)
 {
     OI_UINT i;
     OI_STATUS status;
@@ -65,6 +66,12 @@ INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
     }
 #endif
 
+    if (msbc_enable) {
+        context->sbc_mode = OI_SBC_MODE_MSBC;
+    } else {
+        context->sbc_mode = OI_SBC_MODE_STD;
+    }
+
     status = OI_CODEC_SBC_Alloc(&context->common, decoderData, decoderDataBytes, maxChannels, pcmStride);
 
     if (!OI_SUCCESS(status)) {
index b2cd75cec926fb53f8129c4bcecbcc67f797cbe2..553b4eddd495dc9f1f61ca13a980d2ac5c1fc5bc 100644 (file)
@@ -79,9 +79,9 @@ PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT *context,
         return OI_CODEC_SBC_NO_SYNCWORD;
     }
 #else  // SBC_ENHANCED
-
-    while (*frameBytes && (**frameData != OI_SBC_SYNCWORD)
-            && (**frameData != OI_mSBC_SYNCWORD)) {
+    while (*frameBytes
+        && (!(context->sbc_mode == OI_SBC_MODE_STD && **frameData == OI_SBC_SYNCWORD))
+        && (!(context->sbc_mode == OI_SBC_MODE_MSBC && **frameData == OI_mSBC_SYNCWORD))) {
         (*frameBytes)--;
         (*frameData)++;
     }
@@ -230,9 +230,10 @@ OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
                                     OI_UINT32 decoderDataBytes,
                                     OI_UINT8 maxChannels,
                                     OI_UINT8 pcmStride,
-                                    OI_BOOL enhanced)
+                                    OI_BOOL enhanced,
+                                    OI_BOOL msbc_enable)
 {
-    return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced);
+    return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced, msbc_enable);
 }
 
 OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
index b44593082e35d7faf476e12f58b69dde7b9f0707..dceae9a84979d5ffb75d3e8ce6be85ed478f7753 100644 (file)
@@ -50,21 +50,25 @@ static float rcos[SBC_OLAL] = {
 //     0.96984631f,0.88302222f,      0.75f,0.58682409f,
 //     0.41317591f,      0.25f,0.11697778f,0.09015369f};
 
+
 static float SqrtByCarmack(const float x){
-    int i;
-    float x2, y;
+    union {
+        int i;
+        float y;
+    } float_int;
+
+    float x2;
     const float threehalfs = 1.5f;
 
     x2 = x * 0.5f;
-    y = x;
-    i = *(int *)&y;
-    i = 0x5f375a86 - (i >> 1);
-    y = *(float *)&i;
-    y = y * (threehalfs - (x2 * y *y));
-    // y = y * (threehalfs - (x2 * y *y));
-    // y = y * (threehalfs - (x2 * y *y));
-
-    return (x * y);
+    float_int.y = x;
+
+    float_int.i = 0x5f375a86 - (float_int.i >> 1);
+    float_int.y = float_int.y * (threehalfs - (x2 * float_int.y * float_int.y));
+    // float_int.y = float_int.y * (threehalfs - (x2 * float_int.y * float_int.y));
+    // float_int.y = float_int.y * (threehalfs - (x2 * float_int.y * float_int.y));
+
+    return (x * float_int.y);
 }
 
 static float absolute(float x){
index 79c3eff72731144d04b3026bccc134035db8d48a..455ce7ca363b12f2f02b139a36ae0c019631a82d 100644 (file)
@@ -320,6 +320,10 @@ typedef UINT8 *BTM_BD_NAME_PTR;                        /* Pointer to Device name
 */
 typedef tBTM_SEC_CBACK tBTM_SEC_CALLBACK;
 
+#define BTM_DATA_HANDLE_MASK 0x0FFF
+
+#define BTMD_GET_HANDLE(u16) (UINT16)((u16) & BTM_DATA_HANDLE_MASK)
+
 typedef void (tBTM_SCO_IND_CBACK) (UINT16 sco_inx) ;
 
 /* MACROs to convert from SCO packet types mask to ESCO and back */
index 6aa833c036ebddc8786de9a5ecc97e76c6d87e5b..03a0e79d4d0cd4018ab63ca76a4f6342917e6565 100644 (file)
@@ -992,7 +992,7 @@ typedef UINT8 tBTM_SCO_AIR_MODE_TYPE;
 
 #define BTM_VOICE_SETTING_TRANS ((UINT16)  (HCI_INP_CODING_LINEAR          |   \
                                             HCI_INP_DATA_FMT_2S_COMPLEMENT |   \
-                                            HCI_INP_SAMPLE_SIZE_16BIT      |   \
+                                            HCI_INP_SAMPLE_SIZE_8BIT      |   \
                                             HCI_AIR_CODING_FORMAT_TRANSPNT))
 
 /*******************