mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/btdm_msbc_codec' into 'master'
Wide Band Speech for HFP See merge request idf/esp-idf!4854
This commit is contained in:
commit
da13efc17a
@ -21,6 +21,7 @@ if(CONFIG_BT_ENABLED)
|
||||
bluedroid/osi/include
|
||||
bluedroid/external/sbc/decoder/include
|
||||
bluedroid/external/sbc/encoder/include
|
||||
bluedroid/external/sbc/plc/include
|
||||
bluedroid/btc/profile/esp/blufi/include
|
||||
bluedroid/btc/profile/esp/include
|
||||
bluedroid/btc/profile/std/a2dp/include
|
||||
@ -156,6 +157,7 @@ if(CONFIG_BT_ENABLED)
|
||||
"bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c"
|
||||
"bluedroid/external/sbc/encoder/srce/sbc_encoder.c"
|
||||
"bluedroid/external/sbc/encoder/srce/sbc_packing.c"
|
||||
"bluedroid/external/sbc/plc/sbc_plc.c"
|
||||
"bluedroid/hci/hci_audio.c"
|
||||
"bluedroid/hci/hci_hal_h4.c"
|
||||
"bluedroid/hci/hci_layer.c"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.out_pkt_len = sco_data.tx_pkt_len * 2;
|
||||
bta_hf_client_cb.scb.in_pkt_len = sco_data.rx_pkt_len * 2;
|
||||
} else {
|
||||
bta_hf_client_cb.scb.out_pkt_len = sco_data.tx_pkt_len;
|
||||
bta_hf_client_cb.scb.in_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->out_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->out_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.out_pkt_len, BTA_HF_CLIENT_CI_SCO_DATA_EVT);
|
||||
#endif
|
||||
|
||||
if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC) {
|
||||
|
@ -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 in_pkt_len;
|
||||
UINT16 out_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 */
|
||||
|
@ -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 inout_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);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -820,7 +820,7 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
|
||||
btc_aa_src_cb.timestamp = 0;
|
||||
|
||||
/* SBC encoder config (enforced even if not used) */
|
||||
|
||||
btc_sbc_encoder.sbc_mode = SBC_MODE_STD;
|
||||
btc_sbc_encoder.s16ChannelMode = pInitAudio->ChannelMode;
|
||||
btc_sbc_encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
|
||||
btc_sbc_encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
|
||||
@ -879,7 +879,6 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
|
||||
BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
|
||||
< pUpdateAudio->MinMtuSize) ? (BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET
|
||||
- sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
|
||||
|
||||
/* Set the initial target bit rate */
|
||||
pstrEncParams->u16BitRate = btc_a2dp_source_get_sbc_rate();
|
||||
|
||||
@ -1375,8 +1374,7 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
|
||||
if (btc_media_aa_read_feeding()) {
|
||||
/* SBC encode and descramble frame */
|
||||
SBC_Encoder(&(btc_sbc_encoder));
|
||||
A2D_SbcChkFrInit(btc_sbc_encoder.pu8Packet);
|
||||
A2D_SbcDescramble(btc_sbc_encoder.pu8Packet, btc_sbc_encoder.u16PacketLength);
|
||||
|
||||
/* Update SBC frame length */
|
||||
p_buf->len += btc_sbc_encoder.u16PacketLength;
|
||||
nb_frame--;
|
||||
|
@ -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,12 +449,54 @@ 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) */
|
||||
|
@ -77,6 +77,7 @@
|
||||
#if CONFIG_BT_HFP_CLIENT_ENABLE
|
||||
#define BTC_HF_CLIENT_INCLUDED TRUE
|
||||
#define BTA_HF_INCLUDED TRUE
|
||||
#define PLC_INCLUDED TRUE
|
||||
#ifndef RFCOMM_INCLUDED
|
||||
#define RFCOMM_INCLUDED TRUE
|
||||
#endif
|
||||
@ -86,6 +87,12 @@
|
||||
#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
|
||||
@ -609,6 +616,16 @@
|
||||
#define BTM_SCO_DATA_SIZE_MAX 120 //240
|
||||
#endif
|
||||
|
||||
/* max TX eSCO data packet size */
|
||||
#ifndef BTM_MSBC_FRAME_SIZE
|
||||
#define BTM_MSBC_FRAME_SIZE 60
|
||||
#endif
|
||||
|
||||
/* TX eSCO data packet size */
|
||||
#ifndef BTM_MSBC_FRAME_DATA_SIZE
|
||||
#define BTM_MSBC_FRAME_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
|
||||
|
@ -76,6 +76,10 @@ Declarations of codec functions, data types, and macros.
|
||||
|
||||
#define OI_SBC_SYNCWORD 0x9c
|
||||
#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 */
|
||||
/**@{*/
|
||||
@ -199,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 {
|
||||
@ -235,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
|
||||
|
@ -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_);
|
||||
|
||||
|
@ -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)) {
|
||||
@ -81,9 +88,6 @@ INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
|
||||
return OI_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Read the SBC header up to but not including the joint stereo mask. The syncword has already been
|
||||
* examined, and the enhanced mode flag set, by FindSyncword.
|
||||
@ -94,7 +98,33 @@ INLINE void OI_SBC_ReadHeader(OI_CODEC_SBC_COMMON_CONTEXT *common, const OI_BYTE
|
||||
OI_UINT8 d1;
|
||||
|
||||
|
||||
OI_ASSERT(data[0] == OI_SBC_SYNCWORD || data[0] == OI_SBC_ENHANCED_SYNCWORD);
|
||||
OI_ASSERT(data[0] == OI_SBC_SYNCWORD || data[0] == OI_SBC_ENHANCED_SYNCWORD
|
||||
|| data[0] == OI_mSBC_SYNCWORD);
|
||||
|
||||
/**
|
||||
* For mSBC, just set those parameters
|
||||
*/
|
||||
if (data[0] == OI_mSBC_SYNCWORD){
|
||||
frame->freqIndex = 0;
|
||||
frame->frequency = 16000;
|
||||
|
||||
frame->blocks = 4;
|
||||
frame->nrof_blocks = 15;
|
||||
|
||||
frame->mode = 0;
|
||||
frame->nrof_channels = 1;
|
||||
|
||||
frame->alloc = SBC_LOUDNESS;
|
||||
|
||||
frame->subbands = 1;
|
||||
frame->nrof_subbands = 8;
|
||||
|
||||
frame->cachedInfo = 0;
|
||||
|
||||
frame->bitpool = 26;
|
||||
frame->crc = data[3];
|
||||
return;
|
||||
}
|
||||
|
||||
/* Avoid filling out all these strucutures if we already remember the values
|
||||
* from last time. Just in case we get a stream corresponding to data[1] ==
|
||||
|
@ -79,7 +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)) {
|
||||
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)++;
|
||||
}
|
||||
@ -228,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,
|
||||
|
@ -67,6 +67,12 @@
|
||||
|
||||
#define SBC_NULL 0
|
||||
|
||||
#define SBC_MODE_STD 0
|
||||
#define SBC_MODE_MSBC 1
|
||||
|
||||
#define SBC_SYNC_WORD_STD (0x9C)
|
||||
#define SBC_SYNC_WORD_MSBC (0xAD)
|
||||
|
||||
#ifndef SBC_MAX_NUM_FRAME
|
||||
#define SBC_MAX_NUM_FRAME 1
|
||||
#endif
|
||||
@ -161,6 +167,7 @@ typedef struct SBC_ENC_PARAMS_TAG {
|
||||
SINT16 s16BitPool; /* 16*numOfSb for mono & dual;
|
||||
32*numOfSb for stereo & joint stereo */
|
||||
UINT16 u16BitRate;
|
||||
UINT8 sbc_mode; /* SBC_MODE_STD or SBC_MODE_MSBC */
|
||||
UINT8 u8NumPacketToEncode; /* number of sbc frame to encode. Default is 1 */
|
||||
#if (SBC_JOINT_STE_INCLUDED == TRUE)
|
||||
SINT16 as16Join[SBC_MAX_NUM_OF_SUBBANDS]; /*1 if JS, 0 otherwise*/
|
||||
|
@ -31,84 +31,6 @@
|
||||
|
||||
SINT16 EncMaxShiftCounter;
|
||||
|
||||
/*************************************************************************************************
|
||||
* SBC encoder scramble code
|
||||
* Purpose: to tie the SBC code with BTE/mobile stack code,
|
||||
* especially for the case when the SBC is ported into a third-party Multimedia chip
|
||||
*
|
||||
* Algorithm:
|
||||
* init process: all counters reset to 0,
|
||||
* calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2)
|
||||
* scramble side: the init process happens every time SBC_Encoder_Init() is called.
|
||||
* descramble side: it would be nice to know if he "init" process has happened.
|
||||
* alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100).
|
||||
*
|
||||
* scramble process:
|
||||
* The CRC byte:
|
||||
* Every SBC frame has a frame header.
|
||||
* The 1st byte is the sync word and the following 2 bytes are about the stream format.
|
||||
* They are supposed to be "constant" within a "song"
|
||||
* The 4th byte is the CRC byte. The CRC byte is bound to be random.
|
||||
* Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index".
|
||||
*
|
||||
* SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame.
|
||||
*
|
||||
* The "use" bit is any bit in SBC_PRTC_USE_MASK is set.
|
||||
* If set, SBC uses the "index" from the current frame.
|
||||
* If not set, SBC uses the "index" from the previous frame or 0.
|
||||
*
|
||||
* index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index
|
||||
*
|
||||
* if(index > 0)
|
||||
* {
|
||||
* p = &u8frame[base_index];
|
||||
* if((index&1)&&(u16PacketLength > (base_index+index*2)))
|
||||
* {
|
||||
* // odd index: swap 2 bytes
|
||||
* tmp = p[index];
|
||||
* p[index] = p[index*2];
|
||||
* p[index*2] = tmp;
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // even index: shift by 3
|
||||
* tmp = (p[index] >> 5) + (p[index] << 3);
|
||||
* p[index] = tmp;
|
||||
* }
|
||||
* }
|
||||
* //else index is 0. The frame stays unaltered
|
||||
*
|
||||
*/
|
||||
|
||||
#define SBC_PRTC_CRC_IDX 3
|
||||
#define SBC_PRTC_USE_MASK 0x64
|
||||
#define SBC_PRTC_SYNC_MASK 0x10
|
||||
#define SBC_PRTC_CIDX 0
|
||||
#define SBC_PRTC_LIDX 1
|
||||
typedef struct {
|
||||
UINT8 use;
|
||||
UINT8 idx;
|
||||
} tSBC_FR_CB;
|
||||
|
||||
typedef struct {
|
||||
tSBC_FR_CB fr[2];
|
||||
UINT8 init;
|
||||
UINT8 index;
|
||||
UINT8 base;
|
||||
} tSBC_PRTC_CB;
|
||||
tSBC_PRTC_CB sbc_prtc_cb;
|
||||
|
||||
#define SBC_PRTC_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2))
|
||||
#define SBC_PRTC_CHK_INIT(ar) {if(sbc_prtc_cb.init == 0){sbc_prtc_cb.init=1; ar[0] &= ~SBC_PRTC_SYNC_MASK;}}
|
||||
#define SBC_PRTC_C2L() {p_last=&sbc_prtc_cb.fr[SBC_PRTC_LIDX]; p_cur=&sbc_prtc_cb.fr[SBC_PRTC_CIDX]; \
|
||||
p_last->idx = p_cur->idx; p_last->use = p_cur->use;}
|
||||
#define SBC_PRTC_GETC(ar) {p_cur->use = ar[SBC_PRTC_CRC_IDX] & SBC_PRTC_USE_MASK; \
|
||||
p_cur->idx = SBC_PRTC_IDX(ar[SBC_PRTC_CRC_IDX]);}
|
||||
#define SBC_PRTC_CHK_CRC(ar) {SBC_PRTC_C2L();SBC_PRTC_GETC(ar);sbc_prtc_cb.index = (p_cur->use)?SBC_PRTC_CIDX:SBC_PRTC_LIDX;}
|
||||
#define SBC_PRTC_SCRMB(ar) {idx = sbc_prtc_cb.fr[sbc_prtc_cb.index].idx; \
|
||||
if(idx > 0){if((idx&1)&&(pstrEncParams->u16PacketLength > (sbc_prtc_cb.base+(idx<<1)))) {tmp2=idx<<1; tmp=ar[idx];ar[idx]=ar[tmp2];ar[tmp2]=tmp;} \
|
||||
else{tmp2=ar[idx]; tmp=(tmp2>>5)+(tmp2<<3);ar[idx]=(UINT8)tmp;}}}
|
||||
|
||||
#if (SBC_JOINT_STE_INCLUDED == TRUE)
|
||||
SINT32 s32LRDiff[SBC_MAX_NUM_OF_BLOCKS] = {0};
|
||||
SINT32 s32LRSum[SBC_MAX_NUM_OF_BLOCKS] = {0};
|
||||
@ -130,9 +52,6 @@ void SBC_Encoder(SBC_ENC_PARAMS *pstrEncParams)
|
||||
UINT32 u32CountSum, u32CountDiff;
|
||||
SINT32 *pSum, *pDiff;
|
||||
#endif
|
||||
UINT8 *pu8;
|
||||
tSBC_FR_CB *p_cur, *p_last;
|
||||
UINT32 idx, tmp, tmp2;
|
||||
register SINT32 s32NumOfSubBands = pstrEncParams->s16NumOfSubBands;
|
||||
|
||||
pstrEncParams->pu8NextPacket = pstrEncParams->pu8Packet;
|
||||
@ -263,22 +182,8 @@ void SBC_Encoder(SBC_ENC_PARAMS *pstrEncParams)
|
||||
sbc_enc_bit_alloc_mono(pstrEncParams);
|
||||
}
|
||||
|
||||
/* save the beginning of the frame. pu8NextPacket is modified in EncPacking() */
|
||||
pu8 = pstrEncParams->pu8NextPacket;
|
||||
/* Quantize the encoded audio */
|
||||
EncPacking(pstrEncParams);
|
||||
|
||||
/* scramble the code */
|
||||
SBC_PRTC_CHK_INIT(pu8);
|
||||
SBC_PRTC_CHK_CRC(pu8);
|
||||
#if 0
|
||||
if (pstrEncParams->u16PacketLength > ((sbc_prtc_cb.fr[sbc_prtc_cb.index].idx * 2) + sbc_prtc_cb.base)) {
|
||||
printf("len: %d, idx: %d\n", pstrEncParams->u16PacketLength, sbc_prtc_cb.fr[sbc_prtc_cb.index].idx);
|
||||
} else {
|
||||
printf("len: %d, idx: %d!!!!\n", pstrEncParams->u16PacketLength, sbc_prtc_cb.fr[sbc_prtc_cb.index].idx);
|
||||
}
|
||||
#endif
|
||||
SBC_PRTC_SCRMB((&pu8[sbc_prtc_cb.base]));
|
||||
} while (--(pstrEncParams->u8NumPacketToEncode));
|
||||
|
||||
pstrEncParams->u8NumPacketToEncode = 1; /* default is one for retrocompatibility purpose */
|
||||
@ -300,83 +205,111 @@ void SBC_Encoder_Init(SBC_ENC_PARAMS *pstrEncParams)
|
||||
|
||||
pstrEncParams->u8NumPacketToEncode = 1; /* default is one for retrocompatibility purpose */
|
||||
|
||||
/* Required number of channels */
|
||||
if (pstrEncParams->s16ChannelMode == SBC_MONO) {
|
||||
pstrEncParams->s16NumOfChannels = 1;
|
||||
} else {
|
||||
pstrEncParams->s16NumOfChannels = 2;
|
||||
}
|
||||
|
||||
/* Bit pool calculation */
|
||||
if (pstrEncParams->s16SamplingFreq == SBC_sf16000) {
|
||||
s16SamplingFreq = 16000;
|
||||
} else if (pstrEncParams->s16SamplingFreq == SBC_sf32000) {
|
||||
s16SamplingFreq = 32000;
|
||||
} else if (pstrEncParams->s16SamplingFreq == SBC_sf44100) {
|
||||
s16SamplingFreq = 44100;
|
||||
} else {
|
||||
s16SamplingFreq = 48000;
|
||||
}
|
||||
|
||||
if ( (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO)
|
||||
|| (pstrEncParams->s16ChannelMode == SBC_STEREO) ) {
|
||||
s16Bitpool = (SINT16)( (pstrEncParams->u16BitRate *
|
||||
pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
|
||||
- ( (32 + (4 * pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->s16NumOfChannels)
|
||||
+ ( (pstrEncParams->s16ChannelMode - 2) *
|
||||
pstrEncParams->s16NumOfSubBands ) )
|
||||
/ pstrEncParams->s16NumOfBlocks) );
|
||||
|
||||
s16FrameLen = 4 + (4 * pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->s16NumOfChannels) / 8
|
||||
+ ( ((pstrEncParams->s16ChannelMode - 2) *
|
||||
pstrEncParams->s16NumOfSubBands)
|
||||
+ (pstrEncParams->s16NumOfBlocks * s16Bitpool) ) / 8;
|
||||
|
||||
s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
|
||||
/ (pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->s16NumOfBlocks * 1000);
|
||||
|
||||
if (s16BitRate > pstrEncParams->u16BitRate) {
|
||||
s16Bitpool--;
|
||||
}
|
||||
|
||||
if (pstrEncParams->s16NumOfSubBands == 8) {
|
||||
pstrEncParams->s16BitPool = (s16Bitpool > 255) ? 255 : s16Bitpool;
|
||||
if (pstrEncParams->sbc_mode != SBC_MODE_MSBC) {
|
||||
/* Required number of channels */
|
||||
if (pstrEncParams->s16ChannelMode == SBC_MONO) {
|
||||
pstrEncParams->s16NumOfChannels = 1;
|
||||
} else {
|
||||
pstrEncParams->s16BitPool = (s16Bitpool > 128) ? 128 : s16Bitpool;
|
||||
pstrEncParams->s16NumOfChannels = 2;
|
||||
}
|
||||
|
||||
/* Bit pool calculation */
|
||||
if (pstrEncParams->s16SamplingFreq == SBC_sf16000) {
|
||||
s16SamplingFreq = 16000;
|
||||
} else if (pstrEncParams->s16SamplingFreq == SBC_sf32000) {
|
||||
s16SamplingFreq = 32000;
|
||||
} else if (pstrEncParams->s16SamplingFreq == SBC_sf44100) {
|
||||
s16SamplingFreq = 44100;
|
||||
} else {
|
||||
s16SamplingFreq = 48000;
|
||||
}
|
||||
|
||||
if ( (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO)
|
||||
|| (pstrEncParams->s16ChannelMode == SBC_STEREO) ) {
|
||||
s16Bitpool = (SINT16)( (pstrEncParams->u16BitRate *
|
||||
pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
|
||||
- ( (32 + (4 * pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->s16NumOfChannels)
|
||||
+ ( (pstrEncParams->s16ChannelMode - 2) *
|
||||
pstrEncParams->s16NumOfSubBands ) )
|
||||
/ pstrEncParams->s16NumOfBlocks) );
|
||||
|
||||
s16FrameLen = 4 + (4 * pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->s16NumOfChannels) / 8
|
||||
+ ( ((pstrEncParams->s16ChannelMode - 2) *
|
||||
pstrEncParams->s16NumOfSubBands)
|
||||
+ (pstrEncParams->s16NumOfBlocks * s16Bitpool) ) / 8;
|
||||
|
||||
s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
|
||||
/ (pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->s16NumOfBlocks * 1000);
|
||||
|
||||
if (s16BitRate > pstrEncParams->u16BitRate) {
|
||||
s16Bitpool--;
|
||||
}
|
||||
|
||||
if (pstrEncParams->s16NumOfSubBands == 8) {
|
||||
pstrEncParams->s16BitPool = (s16Bitpool > 255) ? 255 : s16Bitpool;
|
||||
} else {
|
||||
pstrEncParams->s16BitPool = (s16Bitpool > 128) ? 128 : s16Bitpool;
|
||||
}
|
||||
} else {
|
||||
s16Bitpool = (SINT16)( ((pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->u16BitRate * 1000)
|
||||
/ (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
|
||||
- ( ( (32 / pstrEncParams->s16NumOfChannels) +
|
||||
(4 * pstrEncParams->s16NumOfSubBands) )
|
||||
/ pstrEncParams->s16NumOfBlocks ) );
|
||||
|
||||
pstrEncParams->s16BitPool = (s16Bitpool >
|
||||
(16 * pstrEncParams->s16NumOfSubBands))
|
||||
? (16 * pstrEncParams->s16NumOfSubBands) : s16Bitpool;
|
||||
}
|
||||
|
||||
if (pstrEncParams->s16BitPool < 0) {
|
||||
pstrEncParams->s16BitPool = 0;
|
||||
}
|
||||
/* sampling freq */
|
||||
HeaderParams = ((pstrEncParams->s16SamplingFreq & 3) << 6);
|
||||
|
||||
/* number of blocks*/
|
||||
HeaderParams |= (((pstrEncParams->s16NumOfBlocks - 4) & 12) << 2);
|
||||
|
||||
/* channel mode: mono, dual...*/
|
||||
HeaderParams |= ((pstrEncParams->s16ChannelMode & 3) << 2);
|
||||
|
||||
/* Loudness or SNR */
|
||||
HeaderParams |= ((pstrEncParams->s16AllocationMethod & 1) << 1);
|
||||
HeaderParams |= ((pstrEncParams->s16NumOfSubBands >> 3) & 1); /*4 or 8*/
|
||||
|
||||
pstrEncParams->FrameHeader = HeaderParams;
|
||||
} else {
|
||||
s16Bitpool = (SINT16)( ((pstrEncParams->s16NumOfSubBands *
|
||||
pstrEncParams->u16BitRate * 1000)
|
||||
/ (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
|
||||
- ( ( (32 / pstrEncParams->s16NumOfChannels) +
|
||||
(4 * pstrEncParams->s16NumOfSubBands) )
|
||||
/ pstrEncParams->s16NumOfBlocks ) );
|
||||
// mSBC
|
||||
|
||||
pstrEncParams->s16BitPool = (s16Bitpool >
|
||||
(16 * pstrEncParams->s16NumOfSubBands))
|
||||
? (16 * pstrEncParams->s16NumOfSubBands) : s16Bitpool;
|
||||
// Use mSBC encoding parameters to reset the control field
|
||||
/* Required number of channels: 1 */
|
||||
pstrEncParams->s16ChannelMode = SBC_MONO;
|
||||
pstrEncParams->s16NumOfChannels = 1;
|
||||
|
||||
/* Required Sampling frequency : 16KHz */
|
||||
pstrEncParams->s16SamplingFreq = SBC_sf16000;
|
||||
|
||||
/* Bit pool value: 26 */
|
||||
pstrEncParams->s16BitPool = 26;
|
||||
|
||||
/* number of subbands: 8 */
|
||||
pstrEncParams->s16NumOfSubBands = 8;
|
||||
|
||||
/* number of blocks: 15 */
|
||||
pstrEncParams->s16NumOfBlocks = 15;
|
||||
|
||||
/* allocation method: loudness */
|
||||
pstrEncParams->s16AllocationMethod = SBC_LOUDNESS;
|
||||
|
||||
/* set the header paramers, unused for mSBC */
|
||||
pstrEncParams->FrameHeader = 0;
|
||||
}
|
||||
|
||||
if (pstrEncParams->s16BitPool < 0) {
|
||||
pstrEncParams->s16BitPool = 0;
|
||||
}
|
||||
/* sampling freq */
|
||||
HeaderParams = ((pstrEncParams->s16SamplingFreq & 3) << 6);
|
||||
|
||||
/* number of blocks*/
|
||||
HeaderParams |= (((pstrEncParams->s16NumOfBlocks - 4) & 12) << 2);
|
||||
|
||||
/* channel mode: mono, dual...*/
|
||||
HeaderParams |= ((pstrEncParams->s16ChannelMode & 3) << 2);
|
||||
|
||||
/* Loudness or SNR */
|
||||
HeaderParams |= ((pstrEncParams->s16AllocationMethod & 1) << 1);
|
||||
HeaderParams |= ((pstrEncParams->s16NumOfSubBands >> 3) & 1); /*4 or 8*/
|
||||
pstrEncParams->FrameHeader = HeaderParams;
|
||||
|
||||
if (pstrEncParams->s16NumOfSubBands == 4) {
|
||||
if (pstrEncParams->s16NumOfChannels == 1) {
|
||||
EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 4 * 10) >> 2) << 2;
|
||||
@ -395,9 +328,6 @@ void SBC_Encoder_Init(SBC_ENC_PARAMS *pstrEncParams)
|
||||
pstrEncParams->u16BitRate, pstrEncParams->s16BitPool);
|
||||
|
||||
SbcAnalysisInit();
|
||||
|
||||
memset(&sbc_prtc_cb, 0, sizeof(tSBC_PRTC_CB));
|
||||
sbc_prtc_cb.base = 6 + pstrEncParams->s16NumOfChannels * pstrEncParams->s16NumOfSubBands / 2;
|
||||
}
|
||||
|
||||
#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */
|
||||
|
@ -84,10 +84,17 @@ void EncPacking(SBC_ENC_PARAMS *pstrEncParams)
|
||||
#endif
|
||||
|
||||
pu8PacketPtr = pstrEncParams->pu8NextPacket; /*Initialize the ptr*/
|
||||
*pu8PacketPtr++ = (UINT8)0x9C; /*Sync word*/
|
||||
*pu8PacketPtr++ = (UINT8)(pstrEncParams->FrameHeader);
|
||||
if (pstrEncParams->sbc_mode != SBC_MODE_MSBC) {
|
||||
*pu8PacketPtr++ = (UINT8)SBC_SYNC_WORD_STD; /*Sync word*/
|
||||
*pu8PacketPtr++ = (UINT8)(pstrEncParams->FrameHeader);
|
||||
|
||||
*pu8PacketPtr = (UINT8)(pstrEncParams->s16BitPool & 0x00FF);
|
||||
*pu8PacketPtr = (UINT8)(pstrEncParams->s16BitPool & 0x00FF);
|
||||
} else {
|
||||
*pu8PacketPtr++ = (UINT8)SBC_SYNC_WORD_MSBC; /*Sync word*/
|
||||
// two reserved bytes
|
||||
*pu8PacketPtr++ = 0;
|
||||
*pu8PacketPtr = 0;
|
||||
}
|
||||
pu8PacketPtr += 2; /*skip for CRC*/
|
||||
|
||||
/*here it indicate if it is byte boundary or nibble boundary*/
|
||||
|
91
components/bt/bluedroid/external/sbc/plc/include/sbc_plc.h
vendored
Normal file
91
components/bt/bluedroid/external/sbc/plc/include/sbc_plc.h
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _SBC_PLC_H
|
||||
#define _SBC_PLC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Paramter for PLC (16 kHZ)*/
|
||||
#define SBC_FS 120 /* SBC Frame Size */
|
||||
#define SBC_N 256 /* 16ms - Window Length for pattern matching */
|
||||
#define SBC_M 64 /* 4ms - Template for matching */
|
||||
#define SBC_LHIST (SBC_N + SBC_FS - 1) /* Length of history buffer required */
|
||||
#define SBC_RT 36 /* SBC Reconvergence Time (samples) */
|
||||
#define SBC_OLAL 16 /* OverLap-Add Length (samples) */
|
||||
|
||||
/* PLC State Information */
|
||||
typedef struct sbc_plc_state {
|
||||
int16_t hist[SBC_LHIST + SBC_FS + SBC_RT + SBC_OLAL];
|
||||
int16_t bestlag;
|
||||
int nbf;
|
||||
} sbc_plc_state_t;
|
||||
|
||||
/* Prototypes */
|
||||
/**
|
||||
* Perform PLC initialization of memory vectors.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
*/
|
||||
void sbc_plc_init(sbc_plc_state_t *plc_state);
|
||||
|
||||
/**
|
||||
* Perform PLC deinitialization of memory vectors.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
*/
|
||||
void sbc_plc_deinit(sbc_plc_state_t *plc_state);
|
||||
|
||||
/**
|
||||
* Perform bad frame processing.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
* @param ZIRbuf pointer to the ZIR response of the SBC decoder
|
||||
* @param out pointer to the output samples
|
||||
*/
|
||||
void sbc_plc_bad_frame(sbc_plc_state_t *plc_state, int16_t *ZIRbuf, int16_t *out);
|
||||
|
||||
/**
|
||||
* Perform good frame processing. Most of the time, this function
|
||||
* just updates history buffers and passes the input to the output,
|
||||
* but in the first good frame after frame loss, it must conceal the
|
||||
* received signal as it reconverges with the true output.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
* @param in pointer to the input vector
|
||||
* @param out pointer to the output samples
|
||||
*/
|
||||
void sbc_plc_good_frame(sbc_plc_state_t *plc_state, int16_t *in, int16_t *out);
|
||||
|
||||
/**
|
||||
* Get a zero signal eSCO frame
|
||||
* @return pointer to data buffer
|
||||
*/
|
||||
uint8_t * sbc_plc_zero_signal_frame(void);
|
||||
|
||||
/**
|
||||
* Get a zero signal eSCO pcm frame
|
||||
* @return pointer to data buffer
|
||||
*/
|
||||
int16_t * sbc_plc_zero_signal_frame_pcm(void);
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /// _SBC_PLC_H
|
306
components/bt/bluedroid/external/sbc/plc/sbc_plc.c
vendored
Normal file
306
components/bt/bluedroid/external/sbc/plc/sbc_plc.c
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common/bt_target.h"
|
||||
#include "sbc_plc.h"
|
||||
|
||||
#if (PLC_INCLUDED == TRUE)
|
||||
/* msbc */
|
||||
static const uint8_t indices0[] = { 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d,
|
||||
0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
|
||||
0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
|
||||
0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
|
||||
0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c};
|
||||
|
||||
|
||||
/* 8 kHZ */
|
||||
static const int16_t indices0_pcm[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
/* Raised COSine table for OLA */
|
||||
/* 16 kHZ */
|
||||
static float rcos[SBC_OLAL] = {
|
||||
0.99148655f,0.96623611f,0.92510857f,0.86950446f,
|
||||
0.80131732f,0.72286918f,0.63683150f,0.54613418f,
|
||||
0.45386582f,0.36316850f,0.27713082f,0.19868268f,
|
||||
0.13049554f,0.07489143f,0.03376389f,0.00851345f};
|
||||
|
||||
// /* 8 kHZ */
|
||||
// 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){
|
||||
union {
|
||||
int i;
|
||||
float y;
|
||||
} float_int;
|
||||
|
||||
float x2;
|
||||
const float threehalfs = 1.5f;
|
||||
|
||||
x2 = x * 0.5f;
|
||||
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){
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the cross correlation according to Eq. (4) of Goodman
|
||||
* paper, except that the true correlation is used. His formula
|
||||
* seems to be incorrect.
|
||||
*
|
||||
* @param x pointer to x input vector
|
||||
* @param y pointer to y input vector
|
||||
*
|
||||
* @return value containing the cross-correlation of x and y
|
||||
*/
|
||||
static float CrossCorrelation(int16_t *x, int16_t *y){
|
||||
int m;
|
||||
float num = 0;
|
||||
float den = 0;
|
||||
float x2 = 0;
|
||||
float y2 = 0;
|
||||
|
||||
for (m = 0; m < SBC_M; m++) {
|
||||
num += ((float)x[m]) * y[m];
|
||||
x2 += ((float)x[m]) * x[m];
|
||||
y2 += ((float)y[m]) * y[m];
|
||||
}
|
||||
den = (float)SqrtByCarmack(x2 * y2);
|
||||
return num / den;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform pattern matching to find the match of template with the
|
||||
* history buffer according to Section B of Goodman paper.
|
||||
*
|
||||
* @param y pointer to history buffer
|
||||
*
|
||||
* @return the lag corresponding to the best match. The lag is
|
||||
* with respect to the beginning of the history buffer.
|
||||
*
|
||||
*/
|
||||
static int PatternMatch(int16_t *y){
|
||||
int n;
|
||||
float maxCn = -999999.0; // large negative number
|
||||
float Cn;
|
||||
int bestmatch = 0;
|
||||
|
||||
for (n = 0; n < SBC_N; n++){
|
||||
Cn = CrossCorrelation(&y[SBC_LHIST-SBC_M], &y[n]);
|
||||
if (Cn > maxCn){
|
||||
bestmatch = n;
|
||||
maxCn = Cn;
|
||||
}
|
||||
}
|
||||
return bestmatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform amplitude matching using mean-absolute-value according
|
||||
* to Goodman paper.
|
||||
*
|
||||
* @param y pointer to history buffer
|
||||
* @param bestmatch value of the lag to the best match
|
||||
*
|
||||
* @return scale factor
|
||||
*/
|
||||
static float AmplitudeMatch(int16_t *y, int16_t bestmatch) {
|
||||
int i;
|
||||
float sumx = 0;
|
||||
float sumy = 0.000001f;
|
||||
float sf;
|
||||
|
||||
for (i = 0; i < SBC_FS; i++){
|
||||
sumx += absolute(y[SBC_LHIST - SBC_FS + i]);
|
||||
sumy += absolute(y[bestmatch + i]);
|
||||
}
|
||||
sf = sumx / sumy;
|
||||
// This is not in the paper, but limit the scaling factor to something reasonable to avoid creating artifacts
|
||||
if (sf < 0.75f) {
|
||||
sf = 0.75f;
|
||||
}
|
||||
if (sf > 1.2f) {
|
||||
sf = 1.2f;
|
||||
}
|
||||
return sf;
|
||||
}
|
||||
|
||||
static int16_t crop_sample(float val){
|
||||
float croped_val = val;
|
||||
if (croped_val > 32767.0) croped_val= 32767.0;
|
||||
if (croped_val < -32768.0) croped_val=-32768.0;
|
||||
return (int16_t) croped_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a zero signal eSCO frame
|
||||
* @return pointer to data buffer
|
||||
*/
|
||||
uint8_t * sbc_plc_zero_signal_frame(void){
|
||||
return (uint8_t *)&indices0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a zero signal eSCO pcm frame
|
||||
* @return pointer to data buffer
|
||||
*/
|
||||
int16_t * sbc_plc_zero_signal_frame_pcm(void){
|
||||
return (int16_t *)&indices0_pcm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform PLC initialization of memory vectors.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
*/
|
||||
void sbc_plc_init(sbc_plc_state_t *plc_state){
|
||||
plc_state->nbf=0;
|
||||
plc_state->bestlag=0;
|
||||
memset(plc_state->hist, 0, sizeof(plc_state->hist));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform PLC deinitialization of memory vectors.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
*/
|
||||
void sbc_plc_deinit(sbc_plc_state_t *plc_state){
|
||||
plc_state->nbf=0;
|
||||
plc_state->bestlag=0;
|
||||
memset(plc_state->hist, 0, sizeof(plc_state->hist));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform bad frame processing.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
* @param ZIRbuf pointer to the ZIR response of the SBC decoder
|
||||
* @param out pointer to the output samples
|
||||
*/
|
||||
void sbc_plc_bad_frame(sbc_plc_state_t *plc_state, int16_t *ZIRbuf, int16_t *out){
|
||||
int i = 0;
|
||||
float val;
|
||||
float sf = 1;
|
||||
|
||||
plc_state->nbf++;
|
||||
|
||||
if (plc_state->nbf == 1){
|
||||
// Perform pattern matching to find where to replicate
|
||||
plc_state->bestlag = PatternMatch(plc_state->hist);
|
||||
// the replication begins after the template match
|
||||
plc_state->bestlag += SBC_M;
|
||||
|
||||
// Compute Scale Factor to Match Amplitude of Substitution Packet to that of Preceding Packet
|
||||
sf = AmplitudeMatch(plc_state->hist, plc_state->bestlag);
|
||||
|
||||
for (i = 0; i < SBC_OLAL; i++){
|
||||
val = ZIRbuf[i] * rcos[i]
|
||||
+ sf * plc_state->hist[plc_state->bestlag + i] * rcos[SBC_OLAL - i - 1];
|
||||
plc_state->hist[SBC_LHIST + i] = crop_sample(val);
|
||||
}
|
||||
|
||||
for (; i < SBC_FS; i++){
|
||||
val = sf*plc_state->hist[plc_state->bestlag + i];
|
||||
plc_state->hist[SBC_LHIST + i] = crop_sample(val);
|
||||
}
|
||||
|
||||
for (; i < SBC_FS + SBC_OLAL; i++){
|
||||
val = sf * plc_state->hist[plc_state->bestlag + i] * rcos[i-SBC_FS]
|
||||
+ plc_state->hist[plc_state->bestlag + i] * rcos[SBC_OLAL - 1 - i + SBC_FS];
|
||||
plc_state->hist[SBC_LHIST + i] = crop_sample(val);
|
||||
}
|
||||
|
||||
for (; i < SBC_FS + SBC_RT + SBC_OLAL; i++){
|
||||
plc_state->hist[SBC_LHIST + i] = plc_state->hist[plc_state->bestlag + i];
|
||||
}
|
||||
} else {
|
||||
for ( ;i < SBC_FS + SBC_RT + SBC_OLAL; i++){
|
||||
plc_state->hist[SBC_LHIST + i] = plc_state->hist[plc_state->bestlag + i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < SBC_FS; i++){
|
||||
out[i] = plc_state->hist[SBC_LHIST + i];
|
||||
}
|
||||
|
||||
// shift the history buffer
|
||||
for (i = 0; i < SBC_LHIST + SBC_RT + SBC_OLAL; i++){
|
||||
plc_state->hist[i] = plc_state->hist[i + SBC_FS];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform good frame processing. Most of the time, this function
|
||||
* just updates history buffers and passes the input to the output,
|
||||
* but in the first good frame after frame loss, it must conceal the
|
||||
* received signal as it reconverges with the true output.
|
||||
*
|
||||
* @param plc_state pointer to PLC state memory
|
||||
* @param in pointer to the input vector
|
||||
* @param out pointer to the output samples
|
||||
*/
|
||||
void sbc_plc_good_frame(sbc_plc_state_t *plc_state, int16_t *in, int16_t *out){
|
||||
int i = 0;
|
||||
|
||||
if (plc_state->nbf > 0){
|
||||
for (i = 0; i < SBC_RT; i++){
|
||||
out[i] = plc_state->hist[SBC_LHIST + i];
|
||||
}
|
||||
|
||||
for (i = SBC_RT; i < SBC_RT + SBC_OLAL; i++){
|
||||
out[i] = (int16_t)(plc_state->hist[SBC_LHIST + i] * rcos[i - SBC_RT] + in[i] * rcos[SBC_OLAL - 1 - i + SBC_RT]);
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < SBC_FS; i++){
|
||||
out[i] = in[i];
|
||||
}
|
||||
// Copy the output to the history buffer
|
||||
for (i = 0; i < SBC_FS; i++){
|
||||
plc_state->hist[SBC_LHIST + i] = out[i];
|
||||
}
|
||||
// shift the history buffer
|
||||
for (i = 0; i < SBC_LHIST; i++){
|
||||
plc_state->hist[i] = plc_state->hist[i + SBC_FS];
|
||||
}
|
||||
|
||||
plc_state->nbf = 0;
|
||||
}
|
||||
|
||||
#endif ///(PLC_INCLUDED == TRUE)
|
@ -33,171 +33,6 @@
|
||||
|
||||
#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE)
|
||||
|
||||
/*************************************************************************************************
|
||||
* SBC descramble code
|
||||
* Purpose: to tie the SBC code with BTE/mobile stack code,
|
||||
* especially for the case when the SBC is ported into a third-party Multimedia chip
|
||||
*
|
||||
* Algorithm:
|
||||
* init process: all counters reset to 0,
|
||||
* calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2)
|
||||
* scramble side: the init process happens every time SBC_Encoder_Init() is called.
|
||||
* descramble side: it would be nice to know if he "init" process has happened.
|
||||
* alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100).
|
||||
*
|
||||
* scramble process:
|
||||
* The CRC byte:
|
||||
* Every SBC frame has a frame header.
|
||||
* The 1st byte is the sync word and the following 2 bytes are about the stream format.
|
||||
* They are supposed to be "constant" within a "song"
|
||||
* The 4th byte is the CRC byte. The CRC byte is bound to be random.
|
||||
* Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index".
|
||||
*
|
||||
* SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame.
|
||||
*
|
||||
* The "use" bit is any bit in SBC_PRTC_USE_MASK is set.
|
||||
* If set, SBC uses the "index" from the current frame.
|
||||
* If not set, SBC uses the "index" from the previous frame or 0.
|
||||
*
|
||||
* index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index
|
||||
*
|
||||
* if(index > 0)
|
||||
* {
|
||||
* p = &u8frame[base_index];
|
||||
* if((index&1)&&(u16PacketLength > (base_index+index*2)))
|
||||
* {
|
||||
* // odd index: swap 2 bytes
|
||||
* tmp = p[index];
|
||||
* p[index] = p[index*2];
|
||||
* p[index*2] = tmp;
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // even index: shift by 3
|
||||
* tmp = (p[index] >> 3) + (p[index] << 5);
|
||||
* p[index] = tmp;
|
||||
* }
|
||||
* }
|
||||
* //else index is 0. The frame stays unaltered
|
||||
*
|
||||
*/
|
||||
#define A2D_SBC_SYNC_WORD 0x9C
|
||||
#define A2D_SBC_CRC_IDX 3
|
||||
#define A2D_SBC_USE_MASK 0x64
|
||||
#define A2D_SBC_SYNC_MASK 0x10
|
||||
#define A2D_SBC_CIDX 0
|
||||
#define A2D_SBC_LIDX 1
|
||||
#define A2D_SBC_CH_M_BITS 0xC /* channel mode bits: 0: mono; 1 ch */
|
||||
#define A2D_SBC_SUBBAND_BIT 0x1 /* num of subband bit: 0:4; 1: 8 */
|
||||
|
||||
#define A2D_SBC_GET_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2))
|
||||
|
||||
typedef struct {
|
||||
UINT8 use;
|
||||
UINT8 idx;
|
||||
} tA2D_SBC_FR_CB;
|
||||
|
||||
typedef struct {
|
||||
tA2D_SBC_FR_CB fr[2];
|
||||
UINT8 index;
|
||||
UINT8 base;
|
||||
} tA2D_SBC_DS_CB;
|
||||
|
||||
static tA2D_SBC_DS_CB a2d_sbc_ds_cb;
|
||||
/*int a2d_count = 0;*/
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function A2D_SbcChkFrInit
|
||||
**
|
||||
** Description check if need to init the descramble control block.
|
||||
**
|
||||
** Returns nothing.
|
||||
******************************************************************************/
|
||||
void A2D_SbcChkFrInit(UINT8 *p_pkt)
|
||||
{
|
||||
UINT8 fmt;
|
||||
UINT8 num_chnl = 1;
|
||||
UINT8 num_subband = 4;
|
||||
|
||||
if ((p_pkt[0] & A2D_SBC_SYNC_MASK) == 0) {
|
||||
a2d_cb.use_desc = TRUE;
|
||||
fmt = p_pkt[1];
|
||||
p_pkt[0] |= A2D_SBC_SYNC_MASK;
|
||||
memset(&a2d_sbc_ds_cb, 0, sizeof(tA2D_SBC_DS_CB));
|
||||
if (fmt & A2D_SBC_CH_M_BITS) {
|
||||
num_chnl = 2;
|
||||
}
|
||||
if (fmt & A2D_SBC_SUBBAND_BIT) {
|
||||
num_subband = 8;
|
||||
}
|
||||
a2d_sbc_ds_cb.base = 6 + num_chnl * num_subband / 2;
|
||||
/*printf("base: %d\n", a2d_sbc_ds_cb.base);
|
||||
a2d_count = 0;*/
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function A2D_SbcDescramble
|
||||
**
|
||||
** Description descramble the packet.
|
||||
**
|
||||
** Returns nothing.
|
||||
******************************************************************************/
|
||||
void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len)
|
||||
{
|
||||
tA2D_SBC_FR_CB *p_cur, *p_last;
|
||||
UINT32 idx, tmp, tmp2;
|
||||
|
||||
if (a2d_cb.use_desc) {
|
||||
/* c2l */
|
||||
p_last = &a2d_sbc_ds_cb.fr[A2D_SBC_LIDX];
|
||||
p_cur = &a2d_sbc_ds_cb.fr[A2D_SBC_CIDX];
|
||||
p_last->idx = p_cur->idx;
|
||||
p_last->use = p_cur->use;
|
||||
/* getc */
|
||||
p_cur->use = p_pkt[A2D_SBC_CRC_IDX] & A2D_SBC_USE_MASK;
|
||||
p_cur->idx = A2D_SBC_GET_IDX(p_pkt[A2D_SBC_CRC_IDX]);
|
||||
a2d_sbc_ds_cb.index = (p_cur->use) ? A2D_SBC_CIDX : A2D_SBC_LIDX;
|
||||
/*
|
||||
printf("%05d: ar[%02d]: x%02x, msk: x%02x, use: %s, idx: %02d, ",
|
||||
a2d_count++,
|
||||
A2D_SBC_CRC_IDX, p_pkt[A2D_SBC_CRC_IDX], A2D_SBC_USE_MASK,
|
||||
(p_cur->use)?"cur":"lst", p_cur->idx);
|
||||
*/
|
||||
/* descramble */
|
||||
idx = a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx;
|
||||
if (idx > 0) {
|
||||
p_pkt = &p_pkt[a2d_sbc_ds_cb.base];
|
||||
if ((idx & 1) && (len > (a2d_sbc_ds_cb.base + (idx << 1)))) {
|
||||
tmp2 = (idx << 1);
|
||||
tmp = p_pkt[idx];
|
||||
p_pkt[idx] = p_pkt[tmp2];
|
||||
p_pkt[tmp2] = tmp;
|
||||
/*
|
||||
printf("tmp2: %02d, len: %d, idx: %d\n",
|
||||
tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx);
|
||||
*/
|
||||
} else {
|
||||
tmp2 = p_pkt[idx];
|
||||
tmp = (tmp2 >> 3) + (tmp2 << 5);
|
||||
p_pkt[idx] = (UINT8)tmp;
|
||||
/*
|
||||
printf("tmp: x%02x, len: %d, idx: %d(cmp:%d)\n",
|
||||
(UINT8)tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx,
|
||||
(a2d_sbc_ds_cb.base+(idx<<1)));
|
||||
*/
|
||||
}
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
printf("!!!!\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function A2D_BldSbcInfo
|
||||
|
@ -51,7 +51,6 @@ typedef struct {
|
||||
typedef struct {
|
||||
tA2D_FIND_CB find; /* find service control block */
|
||||
UINT8 trace_level;
|
||||
BOOLEAN use_desc;
|
||||
UINT16 avdt_sdp_ver; /* AVDTP version */
|
||||
} tA2D_CB;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -92,26 +92,6 @@ typedef struct {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function A2D_SbcChkFrInit
|
||||
**
|
||||
** Description check if need to init the descramble control block.
|
||||
**
|
||||
** Returns nothing.
|
||||
******************************************************************************/
|
||||
extern void A2D_SbcChkFrInit(UINT8 *p_pkt);
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function A2D_SbcDescramble
|
||||
**
|
||||
** Description descramble the packet.
|
||||
**
|
||||
** Returns nothing.
|
||||
******************************************************************************/
|
||||
extern void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len);
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function A2D_BldSbcInfo
|
||||
|
@ -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))
|
||||
|
||||
/*******************
|
||||
|
@ -45,6 +45,7 @@ COMPONENT_PRIV_INCLUDEDIRS += bluedroid/bta/include \
|
||||
bluedroid/utils/include \
|
||||
bluedroid/external/sbc/decoder/include \
|
||||
bluedroid/external/sbc/encoder/include \
|
||||
bluedroid/external/sbc/plc/include \
|
||||
bluedroid/btc/core/include \
|
||||
bluedroid/btc/profile/esp/blufi/include \
|
||||
bluedroid/btc/profile/esp/include \
|
||||
@ -92,6 +93,7 @@ COMPONENT_SRCDIRS += bluedroid/bta/dm \
|
||||
bluedroid/osi \
|
||||
bluedroid/external/sbc/decoder/srce \
|
||||
bluedroid/external/sbc/encoder/srce \
|
||||
bluedroid/external/sbc/plc \
|
||||
bluedroid/btc/core \
|
||||
bluedroid/btc/profile/esp/blufi \
|
||||
bluedroid/btc/profile/std/gap \
|
||||
|
Loading…
x
Reference in New Issue
Block a user