2217 lines
71 KiB
C++
2217 lines
71 KiB
C++
/***************************************************************************
|
|
*
|
|
* Copyright 2015-2019 BES.
|
|
* All rights reserved. All unpublished rights reserved.
|
|
*
|
|
* No part of this work may be used or reproduced in any form or by any
|
|
* means, or stored in a database or retrieval system, without prior written
|
|
* permission of BES.
|
|
*
|
|
* Use of this work is governed by a license granted by BES.
|
|
* This work contains confidential and proprietary information of
|
|
* BES. which is protected by copyright, trade secret,
|
|
* trademark and other intellectual property rights.
|
|
*
|
|
****************************************************************************/
|
|
// Standard C Included Files
|
|
#include "app_audio.h"
|
|
#include "app_overlay.h"
|
|
#include "app_ring_merge.h"
|
|
#include "audio_prompt_sbc.h"
|
|
#include "bt_sco_chain.h"
|
|
#include "cmsis_os.h"
|
|
#include "cqueue.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_trace.h"
|
|
#include "hal_uart.h"
|
|
#include "hfp_api.h"
|
|
#include "iir_resample.h"
|
|
#include "plat_types.h"
|
|
#include "tgt_hardware.h"
|
|
#include <math.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef TX_RX_PCM_MASK
|
|
#include "bt_drv_interface.h"
|
|
#endif
|
|
|
|
#define ENABLE_LPC_PLC
|
|
|
|
#define ENABLE_PLC_ENCODER
|
|
|
|
// BT
|
|
#include "a2dp_api.h"
|
|
#ifdef TX_RX_PCM_MASK
|
|
#include "bt_drv_interface.h"
|
|
#include "hal_chipid.h"
|
|
|
|
#endif
|
|
|
|
#include "plc_utils.h"
|
|
extern "C" {
|
|
|
|
#include "plc_8000.h"
|
|
#include "speech_utils.h"
|
|
|
|
#if defined(HFP_1_6_ENABLE)
|
|
#include "codec_sbc.h"
|
|
#if defined(ENABLE_LPC_PLC)
|
|
#include "lpc_plc_api.h"
|
|
#else
|
|
#include "plc_16000.h"
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(CVSD_BYPASS)
|
|
#include "Pcm8k_Cvsd.h"
|
|
#endif
|
|
|
|
#if defined(SPEECH_TX_24BIT)
|
|
extern int32_t *aec_echo_buf;
|
|
#else
|
|
extern short *aec_echo_buf;
|
|
#endif
|
|
|
|
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \
|
|
defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT)
|
|
#if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE)
|
|
static uint8_t *echo_buf_queue;
|
|
static uint16_t echo_buf_q_size;
|
|
static uint16_t echo_buf_q_wpos;
|
|
static uint16_t echo_buf_q_rpos;
|
|
static bool echo_buf_q_full;
|
|
#endif
|
|
#endif
|
|
static void *speech_plc;
|
|
}
|
|
|
|
// #define PENDING_MSBC_DECODER_ALG
|
|
|
|
// #define SPEECH_RX_PLC_DUMP_DATA
|
|
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
#include "audio_dump.h"
|
|
int16_t *audio_dump_temp_buf = NULL;
|
|
#endif
|
|
|
|
// app_bt_stream.cpp::bt_sco_player(), used buffer size
|
|
#define APP_BT_STREAM_USE_BUF_SIZE (1024 * 2)
|
|
#if defined(SCO_OPTIMIZE_FOR_RAM)
|
|
uint8_t *sco_overlay_ram_buf = NULL;
|
|
int sco_overlay_ram_buf_len = 0;
|
|
#endif
|
|
|
|
static bool resample_needed_flag = false;
|
|
static int sco_frame_length;
|
|
static int codec_frame_length;
|
|
static int16_t *upsample_buf_for_msbc = NULL;
|
|
static int16_t *downsample_buf_for_msbc = NULL;
|
|
static IirResampleState *upsample_st = NULL;
|
|
static IirResampleState *downsample_st = NULL;
|
|
|
|
#define VOICEBTPCM_TRACE(s, ...)
|
|
// TRACE(s, ##__VA_ARGS__)
|
|
|
|
/* voicebtpcm_pcm queue */
|
|
#define FRAME_NUM (4)
|
|
|
|
#define VOICEBTPCM_PCM_16k_FRAME_LENGTH \
|
|
(SPEECH_FRAME_MS_TO_LEN(16000, SPEECH_SCO_FRAME_MS))
|
|
#define VOICEBTPCM_PCM_16K_QUEUE_SIZE \
|
|
(VOICEBTPCM_PCM_16k_FRAME_LENGTH * FRAME_NUM)
|
|
|
|
#define VOICEBTPCM_PCM_8k_FRAME_LENGTH \
|
|
(SPEECH_FRAME_MS_TO_LEN(8000, SPEECH_SCO_FRAME_MS))
|
|
#define VOICEBTPCM_PCM_8K_QUEUE_SIZE \
|
|
(VOICEBTPCM_PCM_8k_FRAME_LENGTH * FRAME_NUM)
|
|
|
|
// #endif
|
|
CQueue voicebtpcm_p2m_pcm_queue;
|
|
CQueue voicebtpcm_m2p_pcm_queue;
|
|
|
|
static int32_t voicebtpcm_p2m_cache_threshold;
|
|
static int32_t voicebtpcm_m2p_cache_threshold;
|
|
|
|
static int32_t voicebtpcm_p2m_pcm_cache_size;
|
|
static int32_t voicebtpcm_m2p_pcm_cache_size;
|
|
|
|
static enum APP_AUDIO_CACHE_T voicebtpcm_cache_m2p_status = APP_AUDIO_CACHE_QTY;
|
|
static enum APP_AUDIO_CACHE_T voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_QTY;
|
|
|
|
extern bool bt_sco_codec_is_msbc(void);
|
|
#define ENCODE_TEMP_PCM_LEN (120)
|
|
|
|
#define MSBC_FRAME_SIZE (60)
|
|
#if defined(HFP_1_6_ENABLE)
|
|
static btif_sbc_decoder_t msbc_decoder;
|
|
static float msbc_eq_band_gain[CFG_HW_AUD_EQ_NUM_BANDS] = {0, 0, 0, 0,
|
|
0, 0, 0, 0};
|
|
|
|
#define MSBC_ENCODE_PCM_LEN (240)
|
|
|
|
unsigned char *temp_msbc_buf;
|
|
unsigned char *temp_msbc_buf1;
|
|
|
|
#if defined(ENABLE_LPC_PLC)
|
|
LpcPlcState *msbc_plc_state = NULL;
|
|
#else
|
|
struct PLC_State msbc_plc_state;
|
|
#endif
|
|
|
|
#ifdef ENABLE_PLC_ENCODER
|
|
static btif_sbc_encoder_t *msbc_plc_encoder;
|
|
static int16_t *msbc_plc_encoder_buffer = NULL;
|
|
#define MSBC_CODEC_DELAY (73)
|
|
static uint8_t enc_tmp_buf[MSBC_FRAME_SIZE - 3];
|
|
static uint8_t dec_tmp_buf[MSBC_ENCODE_PCM_LEN];
|
|
#endif
|
|
|
|
// static sbc_encoder_t sbc_Encoder1;
|
|
// static btif_sbc_pcm_data_t PcmEncData1;
|
|
static btif_sbc_encoder_t *msbc_encoder;
|
|
static btif_sbc_pcm_data_t msbc_encoder_pcmdata;
|
|
static unsigned char msbc_counter = 0x08;
|
|
#endif
|
|
|
|
int decode_msbc_frame(unsigned char *pcm_buffer, unsigned int pcm_len);
|
|
int decode_cvsd_frame(unsigned char *pcm_buffer, unsigned int pcm_len);
|
|
|
|
// playback flow
|
|
// bt-->store_voicebtpcm_m2p_buffer-->decode_voicebtpcm_m2p_frame-->audioflinger
|
|
// playback-->speaker used by playback, store data from bt to memory
|
|
int store_voicebtpcm_m2p_buffer(unsigned char *buf, unsigned int len) {
|
|
// TRACE(2,"[%s]: %d", __FUNCTION__,
|
|
// FAST_TICKS_TO_US(hal_fast_sys_timer_get()));
|
|
int size;
|
|
#if defined(HFP_1_6_ENABLE)
|
|
if (bt_sco_codec_is_msbc()) {
|
|
decode_msbc_frame(buf, len);
|
|
} else
|
|
#endif
|
|
{
|
|
#if defined(CVSD_BYPASS)
|
|
decode_cvsd_frame(buf, len);
|
|
#endif
|
|
if (speech_plc) {
|
|
speech_plc_8000((PlcSt_8000 *)speech_plc, (short *)buf, len);
|
|
}
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue, (unsigned char *)buf, len);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
}
|
|
|
|
size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_m2p_pcm_queue);
|
|
|
|
if (size >= voicebtpcm_m2p_cache_threshold) {
|
|
voicebtpcm_cache_m2p_status = APP_AUDIO_CACHE_OK;
|
|
}
|
|
|
|
// TRACE(2,"m2p :%d/%d", len, size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CVSD_BYPASS)
|
|
#define VOICECVSD_TEMP_BUFFER_SIZE 120
|
|
#define VOICECVSD_ENC_SIZE 60
|
|
static short cvsd_decode_buff[VOICECVSD_TEMP_BUFFER_SIZE * 2];
|
|
|
|
int decode_cvsd_frame(unsigned char *pcm_buffer, unsigned int pcm_len) {
|
|
uint32_t r = 0, decode_len = 0;
|
|
unsigned char *e1 = NULL, *e2 = NULL;
|
|
unsigned int len1 = 0, len2 = 0;
|
|
|
|
while (decode_len < pcm_len) {
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
len1 = len2 = 0;
|
|
e1 = e2 = 0;
|
|
r = APP_AUDIO_PeekCQueue(&voicebtpcm_m2p_pcm_queue,
|
|
VOICECVSD_TEMP_BUFFER_SIZE, &e1, &len1, &e2,
|
|
&len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
if (r == CQ_ERR) {
|
|
memset(pcm_buffer, 0, pcm_len);
|
|
TRACE(0, "cvsd spk buff underflow");
|
|
return 0;
|
|
}
|
|
|
|
if (len1 != 0) {
|
|
CvsdToPcm8k(e1, (short *)(cvsd_decode_buff), len1, 0);
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, len1);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
decode_len += len1 * 2;
|
|
}
|
|
|
|
if (len2 != 0) {
|
|
CvsdToPcm8k(e2, (short *)(cvsd_decode_buff), len2, 0);
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
decode_len += len2 * 2;
|
|
}
|
|
}
|
|
|
|
memcpy(pcm_buffer, cvsd_decode_buff, decode_len);
|
|
|
|
return decode_len;
|
|
}
|
|
|
|
int encode_cvsd_frame(unsigned char *pcm_buffer, unsigned int pcm_len) {
|
|
uint32_t r = 0;
|
|
unsigned char *e1 = NULL, *e2 = NULL;
|
|
unsigned int len1 = 0, len2 = 0;
|
|
uint32_t processed_len = 0;
|
|
uint32_t remain_len = 0, enc_len = 0;
|
|
|
|
while (processed_len < pcm_len) {
|
|
remain_len = pcm_len - processed_len;
|
|
|
|
if (remain_len >= (VOICECVSD_ENC_SIZE * 2)) {
|
|
enc_len = VOICECVSD_ENC_SIZE * 2;
|
|
} else {
|
|
enc_len = remain_len;
|
|
}
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
len1 = len2 = 0;
|
|
e1 = e2 = 0;
|
|
r = APP_AUDIO_PeekCQueue(&voicebtpcm_p2m_pcm_queue, enc_len, &e1, &len1,
|
|
&e2, &len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
if (r == CQ_ERR) {
|
|
memset(pcm_buffer, 0x55, pcm_len);
|
|
TRACE(0, "cvsd spk buff underflow");
|
|
return 0;
|
|
}
|
|
|
|
if (e1) {
|
|
Pcm8kToCvsd((short *)e1, (unsigned char *)(pcm_buffer + processed_len),
|
|
len1 / 2);
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
DeCQueue(&voicebtpcm_p2m_pcm_queue, NULL, len1);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
processed_len += len1;
|
|
}
|
|
if (e2) {
|
|
Pcm8kToCvsd((short *)e2, (unsigned char *)(pcm_buffer + processed_len),
|
|
len2 / 2);
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
DeCQueue(&voicebtpcm_p2m_pcm_queue, NULL, len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
processed_len += len2;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
for (int cc = 0; cc < 32; ++cc)
|
|
{
|
|
TRACE(1,"%x-", e1[cc]);
|
|
}
|
|
#endif
|
|
|
|
TRACE(3, "%s: processed_len %d, pcm_len %d", __func__, processed_len,
|
|
pcm_len);
|
|
|
|
return processed_len;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HFP_1_6_ENABLE)
|
|
inline int sco_parse_synchronization_header(uint8_t *buf, uint8_t *sn) {
|
|
uint8_t sn1, sn2;
|
|
*sn = 0xff;
|
|
if ((buf[0] != 0x01) || ((buf[1] & 0x0f) != 0x08) || (buf[2] != 0xad)) {
|
|
return -1;
|
|
}
|
|
|
|
sn1 = (buf[1] & 0x30) >> 4;
|
|
sn2 = (buf[1] & 0xc0) >> 6;
|
|
if ((sn1 != 0) && (sn1 != 0x3)) {
|
|
return -2;
|
|
}
|
|
if ((sn2 != 0) && (sn2 != 0x3)) {
|
|
return -3;
|
|
}
|
|
|
|
*sn = (sn1 & 0x01) | (sn2 & 0x02);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if 1
|
|
#define MSBC_LEN_FORMBT_PER_FRAME (120) // Bytes; only for BES platform.
|
|
#define SAMPLES_LEN_PER_FRAME (120)
|
|
#define MSBC_LEN_PER_FRAME (57 + 3)
|
|
|
|
#if defined(CHIP_BEST1400) || defined(CHIP_BEST1402) || \
|
|
defined(CHIP_BEST2300P) || defined(CHIP_BEST2300A) || \
|
|
defined(CHIP_BEST2001)
|
|
#define MSBC_MUTE_PATTERN (0x5555)
|
|
#else
|
|
#define MSBC_MUTE_PATTERN (0x0000)
|
|
#endif
|
|
|
|
#if !defined(PENDING_MSBC_DECODER_ALG)
|
|
short DecPcmBuf[SAMPLES_LEN_PER_FRAME];
|
|
unsigned char DecMsbcBuf[MSBC_LEN_PER_FRAME];
|
|
unsigned short DecMsbcBufAll[MSBC_LEN_FORMBT_PER_FRAME * 5];
|
|
unsigned int next_frame_flag = 0;
|
|
static int msbc_find_first_sync = 0;
|
|
static unsigned int msbc_offset = 0;
|
|
|
|
static PacketLossState pld;
|
|
|
|
int decode_msbc_frame(unsigned char *msbc_btpcm_buffer, unsigned int msbc_len) {
|
|
|
|
btif_sbc_pcm_data_t pcm_data;
|
|
unsigned int msbc_offset_lowdelay = 0;
|
|
unsigned int i, j;
|
|
unsigned short *msbc_buffer = (unsigned short *)msbc_btpcm_buffer;
|
|
int frame_flag[6]; // 1: good frame; 0:bad frame;
|
|
bt_status_t ret;
|
|
unsigned int frame_counter = 0;
|
|
unsigned short byte_decode = 0;
|
|
unsigned int msbc_offset_total = 0;
|
|
int msbc_offset_drift[6] = {
|
|
0,
|
|
};
|
|
|
|
// unsigned int timer_begin=hal_sys_timer_get();
|
|
|
|
// TRACE(1,"decode_msbc_frame,msbc_len:%d",msbc_len);
|
|
#ifdef TX_RX_PCM_MASK
|
|
if (btdrv_is_pcm_mask_enable() == 1) {
|
|
memcpy((uint8_t *)DecMsbcBufAll, msbc_buffer, msbc_len);
|
|
} else
|
|
#endif
|
|
{
|
|
for (i = 0; i < msbc_len / 2; i++) {
|
|
DecMsbcBufAll[i + (MSBC_LEN_FORMBT_PER_FRAME / 2)] = msbc_buffer[i];
|
|
}
|
|
}
|
|
|
|
/*
|
|
for(i =0; i<msbc_len/2; i=i+10)
|
|
{
|
|
TRACE(10,"0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,",
|
|
DecMsbcBufAll[i],DecMsbcBufAll[i+1],DecMsbcBufAll[i+2],DecMsbcBufAll[i+3],DecMsbcBufAll[i+4],
|
|
DecMsbcBufAll[i+5],DecMsbcBufAll[i+6],DecMsbcBufAll[i+7],DecMsbcBufAll[i+8],DecMsbcBufAll[i+9]);
|
|
}
|
|
*/
|
|
|
|
for (j = 0; j < msbc_len / MSBC_LEN_FORMBT_PER_FRAME; j++) {
|
|
frame_flag[j] = 0;
|
|
}
|
|
|
|
if (msbc_find_first_sync == 0) {
|
|
for (i = 0; i < (msbc_len / 2); i++) {
|
|
if ((DecMsbcBufAll[i] == 0x0100) &&
|
|
((DecMsbcBufAll[i + 1] & 0x0f00) == 0x0800) &&
|
|
(DecMsbcBufAll[i + 2] == 0xad00))
|
|
break;
|
|
}
|
|
|
|
TRACE(1, "sync......:%d", i);
|
|
DUMP16("0x%04x, ", &DecMsbcBufAll[0], msbc_len / 2);
|
|
|
|
if (i < (msbc_len / 2)) {
|
|
msbc_find_first_sync = 1;
|
|
msbc_offset = i % (MSBC_LEN_FORMBT_PER_FRAME / 2);
|
|
#ifdef TX_RX_PCM_MASK
|
|
if (btdrv_is_pcm_mask_enable() == 0)
|
|
#endif
|
|
{
|
|
msbc_offset_total = i;
|
|
}
|
|
TRACE(2, "[%s] msbc header found, offset %d", __FUNCTION__, msbc_offset);
|
|
} else {
|
|
for (j = 0; j < msbc_len / MSBC_LEN_FORMBT_PER_FRAME; j++) {
|
|
frame_flag[j] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (msbc_find_first_sync == 1) {
|
|
#if 1 // def TX_RX_PCM_MASK
|
|
|
|
int value = 0;
|
|
unsigned short headerm1 = 0;
|
|
unsigned short header0 = 0;
|
|
unsigned short header1 = 0;
|
|
unsigned short header2 = 0;
|
|
unsigned short header3 = 0;
|
|
// unsigned short tail0 = 0;
|
|
#endif
|
|
|
|
if (msbc_offset == 0 || msbc_offset == 1) {
|
|
msbc_offset_lowdelay = msbc_offset + 60;
|
|
// msbc_offset_lowdelay=msbc_offset;
|
|
} else {
|
|
msbc_offset_lowdelay = msbc_offset;
|
|
}
|
|
|
|
// check again
|
|
for (j = 0; j < (msbc_len / MSBC_LEN_FORMBT_PER_FRAME); j++) {
|
|
|
|
#ifdef TX_RX_PCM_MASK
|
|
if (btdrv_is_pcm_mask_enable() == 1) {
|
|
if ((DecMsbcBufAll[j * 60] == 0x0100) &&
|
|
((DecMsbcBufAll[j * 60 + 1] & 0x0f00) == 0x0800) &&
|
|
(DecMsbcBufAll[j * 60 + 2] == 0xad00)) {
|
|
frame_flag[j] = 0;
|
|
} else {
|
|
frame_flag[j] = 1;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
|
|
if (next_frame_flag == 1) {
|
|
next_frame_flag = 0;
|
|
frame_flag[j] = 1;
|
|
continue;
|
|
}
|
|
if (msbc_offset_lowdelay == 0 && j == 0) {
|
|
headerm1 = 0x0100;
|
|
} else {
|
|
headerm1 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j * (MSBC_LEN_FORMBT_PER_FRAME / 2) - 1];
|
|
}
|
|
|
|
header0 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j * (MSBC_LEN_FORMBT_PER_FRAME / 2)];
|
|
header1 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j * (MSBC_LEN_FORMBT_PER_FRAME / 2) + 1];
|
|
header2 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j * (MSBC_LEN_FORMBT_PER_FRAME / 2) + 2];
|
|
header3 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j * (MSBC_LEN_FORMBT_PER_FRAME / 2) + 3];
|
|
|
|
/*if ((headerm1 == 0x0100) && ((header0 & 0x0f00) == 0x0800) && (header1
|
|
== 0xad00) || (header0 == 0x0100) && ((header1 & 0x0f00) == 0x0800) &&
|
|
(header2 == 0xad00) || (header1 == 0x0100) && ((header2 & 0x0f00) ==
|
|
0x0800) && (header3 == 0xad00))
|
|
{
|
|
frame_flag[j] = 0;
|
|
}*/
|
|
|
|
if ((headerm1 == 0x0100) && ((header0 & 0x0f00) == 0x0800) &&
|
|
(header1 == 0xad00)) {
|
|
frame_flag[j] = 0;
|
|
// It seems that offset is reduced by 1
|
|
msbc_offset_drift[j] = -1;
|
|
TRACE(1, "[%s] msbc_offset is reduced by 1", __FUNCTION__);
|
|
/* tail0 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j*(MSBC_LEN_FORMBT_PER_FRAME / 2) + 59 - 1]; if (tail0 == 0x0000 ||
|
|
tail0 == 0x0100|| tail0==0xff00)
|
|
{
|
|
frame_flag[j] = 0;
|
|
}
|
|
else
|
|
{
|
|
frame_flag[j] = 1;
|
|
next_frame_flag = 1;
|
|
}*/
|
|
} else if ((header0 == 0x0100) && ((header1 & 0x0f00) == 0x0800) &&
|
|
(header2 == 0xad00)) {
|
|
frame_flag[j] = 0;
|
|
/* tail0 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j*(MSBC_LEN_FORMBT_PER_FRAME / 2) + 59]; if (tail0 == 0x0000 ||
|
|
tail0 == 0x0100|| tail0==0xff00)
|
|
{
|
|
frame_flag[j] = 0;
|
|
}
|
|
else
|
|
{
|
|
frame_flag[j] = 1;
|
|
next_frame_flag = 1;
|
|
}
|
|
*/
|
|
} else if ((header1 == 0x0100) && ((header2 & 0x0f00) == 0x0800) &&
|
|
(header3 == 0xad00)) {
|
|
frame_flag[j] = 0;
|
|
msbc_offset_drift[j] = 1;
|
|
TRACE(1, "[%s] msbc_offset is increased by 1", __FUNCTION__);
|
|
/* tail0 = DecMsbcBufAll[msbc_offset_lowdelay +
|
|
j*(MSBC_LEN_FORMBT_PER_FRAME / 2) + 59 + 1]; if (tail0 == 0x0000 ||
|
|
tail0==0x0100|| tail0==0xff00)
|
|
{
|
|
frame_flag[j] = 0;
|
|
}
|
|
else
|
|
{
|
|
frame_flag[j] = 1;
|
|
next_frame_flag = 1;
|
|
}*/
|
|
} else {
|
|
if ((header0 == MSBC_MUTE_PATTERN) &&
|
|
((header1 & 0x0f00) == MSBC_MUTE_PATTERN) &&
|
|
(header2 == MSBC_MUTE_PATTERN)) {
|
|
frame_flag[j] = 1;
|
|
} else {
|
|
if ((msbc_offset_lowdelay + j * (MSBC_LEN_FORMBT_PER_FRAME / 2)) >=
|
|
msbc_offset_total)
|
|
frame_flag[j] = 3;
|
|
else
|
|
frame_flag[j] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef TX_RX_PCM_MASK
|
|
if (btdrv_is_pcm_mask_enable() == 0)
|
|
#endif
|
|
{
|
|
for (j = 0; j < msbc_len / MSBC_LEN_FORMBT_PER_FRAME; j++) {
|
|
value = value | frame_flag[j];
|
|
}
|
|
// abnormal msbc packet.
|
|
if (value > 1)
|
|
msbc_find_first_sync = 0;
|
|
}
|
|
}
|
|
|
|
while (frame_counter < msbc_len / MSBC_LEN_FORMBT_PER_FRAME) {
|
|
// TRACE(3,"[%s] decoding, offset %d, offset drift %d", __FUNCTION__,
|
|
// msbc_offset, msbc_offset_drift[frame_counter]);
|
|
// skip first byte when msbc_offset == 0 and msbc_offset_drift == -1
|
|
unsigned int start_idx = 0;
|
|
if (msbc_offset_lowdelay == 0 && msbc_offset_drift[frame_counter] == -1) {
|
|
start_idx = 1;
|
|
DecMsbcBuf[0] = 0x01;
|
|
}
|
|
for (i = start_idx; i < MSBC_LEN_PER_FRAME; i++) {
|
|
// DecMsbcBuf[i]=DecMsbcBufAll[i+msbc_offset_lowdelay+frame_counter*(MSBC_LEN_FORMBT_PER_FRAME/2)+2]>>8;
|
|
DecMsbcBuf[i] =
|
|
DecMsbcBufAll[i + msbc_offset_lowdelay +
|
|
msbc_offset_drift[frame_counter] +
|
|
frame_counter * (MSBC_LEN_FORMBT_PER_FRAME / 2)] >>
|
|
8;
|
|
}
|
|
|
|
// TRACE(1,"msbc header:0x%x",DecMsbcBuf[0]);
|
|
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
audio_dump_add_channel_data(2, (short *)DecMsbcBuf, MSBC_LEN_PER_FRAME / 2);
|
|
#endif
|
|
|
|
plc_type_t plc_type = packet_loss_detection_process(&pld, DecMsbcBuf);
|
|
|
|
if (plc_type != PLC_TYPE_PASS) {
|
|
memset(DecPcmBuf, 0, sizeof(DecPcmBuf));
|
|
goto do_plc;
|
|
}
|
|
|
|
pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
pcm_data.numChannels = 1;
|
|
pcm_data.dataLen = 0;
|
|
pcm_data.data = (uint8_t *)DecPcmBuf;
|
|
|
|
ret = btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)DecMsbcBuf,
|
|
MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data,
|
|
SAMPLES_LEN_PER_FRAME * 2, msbc_eq_band_gain);
|
|
|
|
// ASSERT(ret == BT_STS_SUCCESS, "[%s] msbc decoder should never fail",
|
|
// __FUNCTION__);
|
|
if (ret != BT_STS_SUCCESS) {
|
|
plc_type = PLC_TYPE_DECODER_ERROR;
|
|
packet_loss_detection_update_histogram(&pld, plc_type);
|
|
}
|
|
|
|
do_plc:
|
|
if (plc_type == PLC_TYPE_PASS) {
|
|
#if defined(ENABLE_LPC_PLC)
|
|
lpc_plc_save(msbc_plc_state, DecPcmBuf);
|
|
#else
|
|
PLC_good_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf);
|
|
#endif
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
audio_dump_add_channel_data(0, (short *)DecPcmBuf,
|
|
MSBC_ENCODE_PCM_LEN / 2);
|
|
#endif
|
|
} else {
|
|
TRACE(1, "PLC bad frame, plc_type: %d", plc_type);
|
|
#if defined(PLC_DEBUG_PRINT_DATA)
|
|
DUMP8("0x%02x, ", DecMsbcBuf, 60);
|
|
#endif
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
for (uint32_t i = 0; i < MSBC_ENCODE_PCM_LEN / 2; i++) {
|
|
audio_dump_temp_buf[i] = (plc_type - 1) * 5000;
|
|
}
|
|
audio_dump_add_channel_data(0, audio_dump_temp_buf,
|
|
MSBC_ENCODE_PCM_LEN / 2);
|
|
#endif
|
|
#if defined(ENABLE_LPC_PLC)
|
|
lpc_plc_generate(msbc_plc_state, DecPcmBuf,
|
|
#if defined(ENABLE_PLC_ENCODER)
|
|
msbc_plc_encoder_buffer
|
|
#else
|
|
NULL
|
|
#endif
|
|
);
|
|
|
|
#if defined(ENABLE_PLC_ENCODER)
|
|
pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
pcm_data.numChannels = 1;
|
|
pcm_data.dataLen = MSBC_ENCODE_PCM_LEN;
|
|
pcm_data.data = (uint8_t *)(msbc_plc_encoder_buffer + MSBC_CODEC_DELAY);
|
|
|
|
uint16_t encoded_bytes = 0, buf_len = MSBC_FRAME_SIZE - 3;
|
|
ret = btif_sbc_encode_frames(msbc_plc_encoder, &pcm_data, &encoded_bytes,
|
|
enc_tmp_buf, &buf_len, 0xFFFF);
|
|
ASSERT(ret == BT_STS_SUCCESS, "[%s] plc encoder must success",
|
|
__FUNCTION__);
|
|
ASSERT(encoded_bytes == MSBC_ENCODE_PCM_LEN,
|
|
"[%s] plc encoder encoded bytes error", __FUNCTION__);
|
|
ASSERT(buf_len == MSBC_FRAME_SIZE - 3,
|
|
"[%s] plc encoder encoded stream length error", __FUNCTION__);
|
|
|
|
pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
pcm_data.numChannels = 1;
|
|
pcm_data.dataLen = 0;
|
|
pcm_data.data = dec_tmp_buf;
|
|
ret = btif_sbc_decode_frames(&msbc_decoder, enc_tmp_buf,
|
|
MSBC_FRAME_SIZE - 3, &byte_decode, &pcm_data,
|
|
MSBC_ENCODE_PCM_LEN, msbc_eq_band_gain);
|
|
ASSERT(ret == BT_STS_SUCCESS, "[%s] plc decoder must success",
|
|
__FUNCTION__);
|
|
ASSERT(byte_decode == MSBC_FRAME_SIZE - 3,
|
|
"[%s] plc decoder decoded bytes error", __FUNCTION__);
|
|
#endif
|
|
|
|
#else
|
|
pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
pcm_data.numChannels = 1;
|
|
pcm_data.dataLen = 0;
|
|
pcm_data.data = (uint8_t *)DecPcmBuf;
|
|
|
|
ret =
|
|
btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)indices0,
|
|
MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data,
|
|
SAMPLES_LEN_PER_FRAME * 2, msbc_eq_band_gain);
|
|
|
|
PLC_bad_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf);
|
|
|
|
ASSERT(ret == BT_STS_SUCCESS, "[%s] msbc decoder should never fail",
|
|
__FUNCTION__);
|
|
#endif
|
|
}
|
|
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
audio_dump_add_channel_data(1, (short *)DecPcmBuf, MSBC_ENCODE_PCM_LEN / 2);
|
|
audio_dump_run();
|
|
#endif
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue, (unsigned char *)DecPcmBuf,
|
|
(unsigned int)(SAMPLES_LEN_PER_FRAME * 2));
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
frame_counter++;
|
|
}
|
|
#ifdef TX_RX_PCM_MASK
|
|
if (btdrv_is_pcm_mask_enable() == 0)
|
|
#endif
|
|
{
|
|
for (i = 0; i < MSBC_LEN_FORMBT_PER_FRAME / 2; i++) {
|
|
DecMsbcBufAll[i] = DecMsbcBufAll[i + (msbc_len / 2)];
|
|
}
|
|
}
|
|
// TRACE(1,"msbc + plc:%d", (hal_sys_timer_get()-timer_begin));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
static uint8_t *msbc_buf_before_decode;
|
|
|
|
short DecPcmBuf[SAMPLES_LEN_PER_FRAME];
|
|
unsigned char DecMsbcBuf[MSBC_LEN_PER_FRAME];
|
|
unsigned short DecMsbcBufAll[MSBC_LEN_FORMBT_PER_FRAME * 5];
|
|
unsigned char DecVerifyMsbcBuf[MSBC_LEN_PER_FRAME * 2];
|
|
unsigned int next_frame_flag = 0;
|
|
uint8_t last_msbc_sync_num = 0;
|
|
CQueue msbc_temp_queue;
|
|
|
|
__attribute__((section(".fast_text_sram"))) int
|
|
decode_msbc_frame(unsigned char *msbc_btpcm_buffer, unsigned int msbc_len) {
|
|
btif_sbc_pcm_data_t pcm_data;
|
|
uint16_t msbc_queue_len = 0, msbc_sync_offset = 0;
|
|
unsigned char *e1 = NULL, *e2 = NULL;
|
|
unsigned int len1 = 0, len2 = 0;
|
|
int r = 0;
|
|
uint8_t sync_num = 0, verify_result = 0;
|
|
uint8_t frame_decode_num = 0;
|
|
int plc_num = 0;
|
|
bt_status_t ret;
|
|
unsigned short byte_decode = 0;
|
|
|
|
pcm_data.data = (unsigned char *)DecPcmBuf;
|
|
pcm_data.dataLen = 0;
|
|
|
|
// put msbc in queue
|
|
for (int j = 0; j < (int)msbc_len; j += MSBC_LEN_PER_FRAME * 2) {
|
|
for (int i = 0; i < MSBC_LEN_PER_FRAME; i++) {
|
|
DecMsbcBuf[i] = msbc_btpcm_buffer[2 * i + 1 + j];
|
|
}
|
|
APP_AUDIO_EnCQueue(&msbc_temp_queue, DecMsbcBuf, MSBC_LEN_PER_FRAME);
|
|
}
|
|
|
|
msbc_find_sync_again:
|
|
msbc_queue_len = APP_AUDIO_LengthOfCQueue(&msbc_temp_queue);
|
|
TRACE(1, "length = %d", msbc_queue_len);
|
|
if (msbc_queue_len > MSBC_LEN_PER_FRAME * 2)
|
|
msbc_queue_len = MSBC_LEN_PER_FRAME * 2;
|
|
else if (msbc_queue_len < MSBC_LEN_PER_FRAME)
|
|
return 0;
|
|
|
|
r = APP_AUDIO_PeekCQueue(&msbc_temp_queue, msbc_queue_len, &e1, &len1, &e2,
|
|
&len2);
|
|
if (r == CQ_OK) {
|
|
if (len1) {
|
|
memcpy(DecVerifyMsbcBuf, e1, len1);
|
|
}
|
|
if (len2 != 0) {
|
|
memcpy(DecVerifyMsbcBuf + len1, e2, len2);
|
|
}
|
|
} else {
|
|
// can't happen
|
|
}
|
|
|
|
// DUMP8("%02x", DecVerifyMsbcBuf, msbc_queue_len);
|
|
// find sync head
|
|
for (int i = 0; i < (msbc_queue_len - 3); i++) {
|
|
// verify sync success
|
|
if (sco_parse_synchronization_header(DecVerifyMsbcBuf + i, &sync_num) >=
|
|
0) {
|
|
verify_result = 1;
|
|
msbc_sync_offset = i;
|
|
break;
|
|
}
|
|
}
|
|
TRACE(3, "%02x %02x %02x", (DecVerifyMsbcBuf + msbc_sync_offset)[0],
|
|
(DecVerifyMsbcBuf + msbc_sync_offset)[1],
|
|
(DecVerifyMsbcBuf + msbc_sync_offset)[2]);
|
|
TRACE(5, "msbc:%d %d %d %d %d\n", verify_result, msbc_queue_len,
|
|
msbc_sync_offset, last_msbc_sync_num, sync_num);
|
|
|
|
if (!verify_result) {
|
|
// remove msbc frame remain 3 byted as it may include syn head
|
|
APP_AUDIO_DeCQueue(&msbc_temp_queue, 0, msbc_queue_len - 3);
|
|
goto msbc_find_sync_again;
|
|
} else {
|
|
// remove invalid msbc frame space
|
|
APP_AUDIO_DeCQueue(&msbc_temp_queue, 0, msbc_sync_offset);
|
|
if (msbc_sync_offset >= MSBC_LEN_PER_FRAME)
|
|
goto msbc_find_sync_again;
|
|
}
|
|
|
|
// cal plc number
|
|
if ((last_msbc_sync_num + 1) % 4 == sync_num) {
|
|
plc_num = 0;
|
|
} else {
|
|
for (int i = 0; i < 4; i++) {
|
|
if ((last_msbc_sync_num + i) % 4 == sync_num) {
|
|
break;
|
|
}
|
|
plc_num++;
|
|
}
|
|
}
|
|
last_msbc_sync_num = sync_num;
|
|
|
|
// failed check sync should do plc
|
|
if (plc_num > 0) {
|
|
for (int i = 0; i < plc_num; i++) {
|
|
ret =
|
|
btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)indices0,
|
|
MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data,
|
|
SAMPLES_LEN_PER_FRAME * 2, msbc_eq_band_gain);
|
|
|
|
if (ret == BT_STS_SUCCESS) {
|
|
TRACE(1, "PLC bad frame:%d\n", ret);
|
|
// timer_begin=hal_sys_timer_get();
|
|
PLC_bad_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf);
|
|
// TRACE(1,"msbc + plc:%d", (hal_sys_timer_get()-timer_begin));
|
|
pcm_data.data = (unsigned char *)DecPcmBuf;
|
|
pcm_data.dataLen = 0;
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue,
|
|
(unsigned char *)DecPcmBuf,
|
|
(unsigned int)(SAMPLES_LEN_PER_FRAME * 2));
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
} else {
|
|
ASSERT(0, "ERROR inices0", __func__);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
ret = btif_sbc_decode_frames(
|
|
&msbc_decoder, (unsigned char *)DecVerifyMsbcBuf + msbc_sync_offset + 2,
|
|
MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data, SAMPLES_LEN_PER_FRAME * 2,
|
|
msbc_eq_band_gain);
|
|
|
|
if (ret == BT_STS_SUCCESS) {
|
|
PLC_good_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf);
|
|
pcm_data.data = (unsigned char *)DecPcmBuf;
|
|
pcm_data.dataLen = 0;
|
|
} else {
|
|
TRACE(1, "PLC bad frame:%d\n");
|
|
PLC_bad_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf);
|
|
pcm_data.data = (unsigned char *)DecPcmBuf;
|
|
pcm_data.dataLen = 0;
|
|
TRACE(1, "ERROR msbc frame!ret:%d\n", ret);
|
|
}
|
|
// remove msbc frame
|
|
APP_AUDIO_DeCQueue(&msbc_temp_queue, 0, MSBC_LEN_PER_FRAME);
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue, (unsigned char *)DecPcmBuf,
|
|
(unsigned int)(SAMPLES_LEN_PER_FRAME * 2));
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
frame_decode_num++;
|
|
if (frame_decode_num <= (msbc_len / (MSBC_LEN_PER_FRAME * 2) - 1))
|
|
goto msbc_find_sync_again;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // #if !defined(PENDING_MSBC_DECODER_ALG)
|
|
|
|
#else
|
|
int decode_msbc_frame(unsigned char *pcm_buffer, unsigned int pcm_len) {
|
|
int ttt = 0;
|
|
// int t = 0;
|
|
uint8_t underflow = 0;
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
uint8_t plc_type = 0;
|
|
uint8_t need_check_pkt = 1;
|
|
uint8_t msbc_raw_sn = 0xff;
|
|
static uint8_t msbc_raw_sn_pre;
|
|
static uint8_t msbc_raw_sn_pre2;
|
|
static bool msbc_find_first_sync = 0;
|
|
#endif
|
|
int r = 0;
|
|
unsigned char *e1 = NULL, *e2 = NULL, *msbc_buff = NULL;
|
|
unsigned int len1 = 0, len2 = 0;
|
|
static btif_sbc_pcm_data_t pcm_data;
|
|
static unsigned int msbc_next_frame_size;
|
|
bt_status_t ret = BT_STS_SUCCESS;
|
|
unsigned short byte_decode = 0;
|
|
|
|
unsigned int pcm_offset = 0;
|
|
unsigned int pcm_processed = 0;
|
|
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
pcm_data.data = (unsigned char *)msbc_buf_before_plc;
|
|
#else
|
|
pcm_data.data = (unsigned char *)pcm_buffer;
|
|
#endif
|
|
if (!msbc_next_frame_size) {
|
|
msbc_next_frame_size = MSBC_FRAME_SIZE;
|
|
}
|
|
|
|
// reinit:
|
|
if (need_init_decoder) {
|
|
TRACE(0, "init msbc decoder\n");
|
|
pcm_data.data = (unsigned char *)(pcm_buffer + pcm_offset);
|
|
pcm_data.dataLen = 0;
|
|
|
|
btif_sbc_init_decoder(&msbc_decoder);
|
|
|
|
msbc_decoder.streamInfo.mSbcFlag = 1;
|
|
msbc_decoder.streamInfo.bitPool = 26;
|
|
msbc_decoder.streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
msbc_decoder.streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
|
|
msbc_decoder.streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
|
|
/* Number of blocks used to encode the stream (4, 8, 12, or 16) */
|
|
msbc_decoder.streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
|
|
/* The number of subbands in the stream (4 or 8) */
|
|
msbc_decoder.streamInfo.numSubBands = 8;
|
|
msbc_decoder.streamInfo.numChannels = 1;
|
|
#if defined(MSBC_PLC_ENCODER)
|
|
btif_sbc_init_encoder(&sbc_Encoder1);
|
|
sbc_Encoder1.streamInfo.mSbcFlag = 1;
|
|
sbc_Encoder1.streamInfo.numChannels = 1;
|
|
sbc_Encoder1.streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
|
|
|
|
sbc_Encoder1.streamInfo.bitPool = 26;
|
|
sbc_Encoder1.streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
sbc_Encoder1.streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
|
|
sbc_Encoder1.streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
|
|
sbc_Encoder1.streamInfo.numSubBands = 8;
|
|
|
|
#endif
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
InitPLC(&msbc_plc_state);
|
|
msbc_need_check_sync_header = 0;
|
|
msbc_raw_sn_pre = 0xff;
|
|
msbc_raw_sn_pre2 = 0xff;
|
|
msbc_find_first_sync = true;
|
|
#endif
|
|
}
|
|
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
need_check_pkt = 1;
|
|
#endif
|
|
msbc_buff = msbc_buf_before_decode;
|
|
|
|
get_again:
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
len1 = len2 = 0;
|
|
e1 = e2 = 0;
|
|
r = APP_AUDIO_PeekCQueue(&voicebtpcm_m2p_pcm_queue, msbc_next_frame_size, &e1,
|
|
&len1, &e2, &len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
if (r == CQ_ERR) {
|
|
pcm_processed = pcm_len;
|
|
memset(pcm_buffer, 0, pcm_len);
|
|
TRACE(0, "msbc spk buff underflow");
|
|
goto exit;
|
|
}
|
|
|
|
if (!len1) {
|
|
TRACE(2, "len1 underflow %d/%d\n", len1, len2);
|
|
goto get_again;
|
|
}
|
|
|
|
if (len1 > 0 && e1) {
|
|
memcpy(msbc_buff, e1, len1);
|
|
}
|
|
if (len2 > 0 && e2) {
|
|
memcpy(msbc_buff + len1, e2, len2);
|
|
}
|
|
|
|
if (msbc_find_first_sync) {
|
|
|
|
for (uint8_t i = 0; i < MSBC_FRAME_SIZE - 3; i++) {
|
|
if (!sco_parse_synchronization_header(&msbc_buff[i], &msbc_raw_sn)) {
|
|
TRACE(2, "1 msbc find sync sn:%d offset:%d", msbc_raw_sn, i);
|
|
msbc_find_first_sync = false;
|
|
goto start_decoder;
|
|
}
|
|
}
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, MSBC_FRAME_SIZE - 3);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
memset(pcm_buffer, 0, pcm_len);
|
|
pcm_processed = pcm_len;
|
|
goto exit;
|
|
}
|
|
start_decoder:
|
|
|
|
// DUMP8("%02x ", msbc_buf_before_decode, 8);
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
// [0]-1,msbc sync byte
|
|
// [1]-seqno
|
|
// code_frame(57 bytes)
|
|
// padding(1 byte)
|
|
if (need_check_pkt) {
|
|
|
|
#if 1
|
|
if (!sco_parse_synchronization_header(msbc_buf_before_decode,
|
|
&msbc_raw_sn)) {
|
|
if (msbc_raw_sn_pre2 == 0xff) {
|
|
// do nothing
|
|
msbc_raw_sn_pre2 = msbc_raw_sn;
|
|
} else {
|
|
if (((msbc_raw_sn_pre2 + 1) % 4) == msbc_raw_sn) {
|
|
// do nothing
|
|
msbc_raw_sn_pre2 = msbc_raw_sn;
|
|
} else if (msbc_raw_sn == 0xff) {
|
|
TRACE(1, "xxxxxx: sbchd err:%d", MSBC_FRAME_SIZE - 3);
|
|
} else {
|
|
TRACE(2, "xxxxxx: seq err:%d/%d", msbc_raw_sn, msbc_raw_sn_pre2);
|
|
msbc_raw_sn_pre2 = (msbc_raw_sn_pre2 + 1) % 4;
|
|
#if 1
|
|
memset(msbc_buf_before_decode, 0, MSBC_FRAME_SIZE);
|
|
#else
|
|
if (msbc_raw_sn_pre2 == 0) {
|
|
msbc_buf_before_decode[1] = 0x08;
|
|
} else if (msbc_raw_sn_pre2 == 1) {
|
|
msbc_buf_before_decode[1] = 0x38;
|
|
} else if (msbc_raw_sn_pre2 == 2) {
|
|
msbc_buf_before_decode[1] = 0xc8;
|
|
} else if (msbc_raw_sn_pre2 == 3) {
|
|
msbc_buf_before_decode[1] = 0xf8;
|
|
} else {
|
|
ASSERT(0, "msbc_raw_sn_pre2(%d) error", __func__);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
unsigned int sync_offset = 0;
|
|
if (msbc_need_check_sync_header) {
|
|
do {
|
|
if (!sco_parse_synchronization_header(&msbc_buff[sync_offset],
|
|
&msbc_raw_sn)) {
|
|
break;
|
|
}
|
|
sync_offset++;
|
|
} while (sync_offset < (MSBC_FRAME_SIZE - 3));
|
|
|
|
msbc_need_check_sync_header = 0;
|
|
if (sync_offset > 0 && sync_offset != (MSBC_FRAME_SIZE - 3)) {
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, sync_offset);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
TRACE(1, "fix sync:%d", sync_offset);
|
|
msbc_raw_sn_pre = (msbc_raw_sn + 3) % 4; // Find pre sn
|
|
msbc_raw_sn_pre2 = msbc_raw_sn_pre;
|
|
goto get_again;
|
|
// TRACE(4,"***msbc_need_check_sync %d :%x %x %x\n", sync_offset,
|
|
// msbc_buf_before_decode[0],
|
|
// msbc_buf_before_decode[1],
|
|
// msbc_buf_before_decode[2]);
|
|
} else if (sync_offset == (MSBC_FRAME_SIZE - 3)) {
|
|
// APP_AUDIO_DeCQueue(&voicebtpcm_m2p_queue, 0, sync_offset);
|
|
// just jump sync length + padding length(1byte)
|
|
// will in plc again, so can check sync again
|
|
// TRACE(4,"***msbc_need_check_sync %d :%x %x %x\n", sync_offset,
|
|
// msbc_buf_before_decode[0],
|
|
// msbc_buf_before_decode[1],
|
|
// msbc_buf_before_decode[2]);
|
|
msbc_next_frame_size = (MSBC_FRAME_SIZE - 3) - 1;
|
|
} else if (!sync_offset) {
|
|
|
|
} else {
|
|
TRACE(1, "3 msbc_need_check_sync %d\n", sync_offset);
|
|
}
|
|
}
|
|
// 0 - normal decode without plc proc, 1 - normal decode with plc proc, 2 -
|
|
// special decode with plc proc
|
|
plc_type = 0;
|
|
|
|
if (msbc_can_plc) {
|
|
if (sco_parse_synchronization_header(msbc_buf_before_decode,
|
|
&msbc_raw_sn)) {
|
|
plc_type = 2;
|
|
msbc_need_check_sync_header = 1;
|
|
} else {
|
|
plc_type = 1;
|
|
}
|
|
} else {
|
|
plc_type = 0;
|
|
}
|
|
|
|
if (msbc_raw_sn_pre == 0xff) {
|
|
// do nothing
|
|
msbc_raw_sn_pre = msbc_raw_sn;
|
|
} else {
|
|
if (((msbc_raw_sn_pre + 1) % 4) == msbc_raw_sn) {
|
|
// do nothing
|
|
msbc_raw_sn_pre = msbc_raw_sn;
|
|
} else if (msbc_raw_sn == 0xff) {
|
|
TRACE(1, "sbchd err:%d", MSBC_FRAME_SIZE - 3);
|
|
msbc_need_check_sync_header = 1;
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, MSBC_FRAME_SIZE - 3);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
msbc_raw_sn_pre = (msbc_raw_sn_pre + 1) % 4;
|
|
plc_type = 2;
|
|
} else {
|
|
TRACE(2, "seq err:%d/%d", msbc_raw_sn, msbc_raw_sn_pre);
|
|
msbc_need_check_sync_header = 1;
|
|
plc_type = 2;
|
|
msbc_raw_sn_pre = (msbc_raw_sn_pre + 1) % 4;
|
|
}
|
|
}
|
|
|
|
need_check_pkt = 0;
|
|
}
|
|
// TRACE(3,"type %d, seqno 0x%x, q_space %d\n", plc_type, cur_pkt_seqno,
|
|
// APP_AUDIO_AvailableOfCQueue(&voicebtpcm_m2p_queue));
|
|
#endif
|
|
|
|
// DUMP8("%02x ", msbc_buf_before_decode, msbc_next_frame_size);
|
|
// TRACE(0,"\n");
|
|
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
if (plc_type == 1) {
|
|
ret = btif_sbc_decode_frames(&msbc_decoder,
|
|
(unsigned char *)msbc_buf_before_decode,
|
|
msbc_next_frame_size, &byte_decode, &pcm_data,
|
|
pcm_len - pcm_offset, msbc_eq_band_gain);
|
|
|
|
ttt = hal_sys_timer_get();
|
|
#if defined(MSBC_PCM_PLC_ENABLE)
|
|
speech_plc_16000_AddToHistory((PlcSt_16000 *)speech_plc,
|
|
(short *)pcm_data.data, pcm_len / 2);
|
|
memcpy(pcm_buffer, pcm_data.data, pcm_len);
|
|
#else
|
|
PLC_good_frame(&msbc_plc_state, (short *)pcm_data.data,
|
|
(short *)pcm_buffer);
|
|
#endif
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
audio_dump_add_channel_data(0, (short *)pcm_buffer, pcm_len / 2);
|
|
#endif
|
|
} else if (plc_type == 2) {
|
|
#if defined(MSBC_PCM_PLC_ENABLE)
|
|
ret = BT_STS_SUCCESS;
|
|
ttt = hal_sys_timer_get();
|
|
#if defined(MSBC_PLC_ENCODER)
|
|
speech_plc_16000_Dofe((PlcSt_16000 *)speech_plc, (short *)pcm_buffer,
|
|
EncInBuf, pcm_len / 2);
|
|
#else
|
|
speech_plc_16000_Dofe((PlcSt_16000 *)speech_plc, (short *)pcm_buffer, NULL,
|
|
pcm_len / 2);
|
|
#endif
|
|
#else
|
|
PLC_bad_frame(&msbc_plc_state, (short *)pcm_data.data, (short *)pcm_buffer);
|
|
#endif
|
|
#if defined(MSBC_PLC_ENCODER)
|
|
{
|
|
uint16_t bytes_encoded = 0, buf_len = MSBC_ENCODE_PCM_LEN;
|
|
PcmEncData1.data = (uint8_t *)(EncInBuf + MSBC_ENC_BUFFER_OFFSET);
|
|
PcmEncData1.dataLen = pcm_len;
|
|
PcmEncData1.numChannels = 1;
|
|
PcmEncData1.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
btif_sbc_encode_frames(&sbc_Encoder1, &PcmEncData1, &bytes_encoded,
|
|
Encodedbuf1, &buf_len, 0xFFFF);
|
|
#ifdef __SBC_FUNC_IN_ROM__
|
|
ret = SBC_ROM_FUNC.sbc_frames_decode(
|
|
&msbc_decoder, Encodedbuf1, MSBC_FRAME_SIZE - 3, &byte_decode,
|
|
&pcm_data, pcm_len - pcm_offset, msbc_eq_band_gain);
|
|
#else
|
|
ret = btif_sbc_decode_frames(&msbc_decoder, Encodedbuf1,
|
|
MSBC_FRAME_SIZE - 3, &byte_decode, &pcm_data,
|
|
pcm_len - pcm_offset, msbc_eq_band_gain);
|
|
#endif
|
|
}
|
|
#endif
|
|
TRACE(2, "b t:%d ret:%d\n", (hal_sys_timer_get() - ttt), ret);
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
for (uint32_t i = 0; i < pcm_len / 2; i++) {
|
|
audio_dump_temp_buf[i] = 32767;
|
|
}
|
|
audio_dump_add_channel_data(0, audio_dump_temp_buf, pcm_len / 2);
|
|
#endif
|
|
} else
|
|
#endif
|
|
{
|
|
ret = btif_sbc_decode_frames(&msbc_decoder,
|
|
(unsigned char *)msbc_buf_before_decode,
|
|
msbc_next_frame_size, &byte_decode, &pcm_data,
|
|
pcm_len - pcm_offset, msbc_eq_band_gain);
|
|
#if defined(MSBC_PCM_PLC_ENABLE)
|
|
speech_plc_16000_AddToHistory((PlcSt_16000 *)speech_plc,
|
|
(short *)pcm_data.data, pcm_len / 2);
|
|
memcpy(pcm_buffer, pcm_data.data, pcm_len);
|
|
#endif
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
for (uint32_t i = 0; i < pcm_len / 2; i++) {
|
|
audio_dump_temp_buf[i] = -32767;
|
|
}
|
|
audio_dump_add_channel_data(0, audio_dump_temp_buf, pcm_len / 2);
|
|
#endif
|
|
}
|
|
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
audio_dump_add_channel_data(1, (short *)pcm_buffer, pcm_len / 2);
|
|
audio_dump_run();
|
|
#endif
|
|
|
|
#if 0
|
|
TRACE(1,"[0] %x", msbc_buf_before_decode[0]);
|
|
TRACE(1,"[1] %x", msbc_buf_before_decode[1]);
|
|
TRACE(1,"[2] %x", msbc_buf_before_decode[2]);
|
|
TRACE(1,"[3] %x", msbc_buf_before_decode[3]);
|
|
TRACE(1,"[4] %x", msbc_buf_before_decode[4]);
|
|
#endif
|
|
|
|
// TRACE(2,"sbcd ret %d %d\n", ret, byte_decode);
|
|
|
|
if (ret == BT_STS_CONTINUE) {
|
|
need_init_decoder = false;
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
VOICEBTPCM_TRACE(2, "000000 byte_decode =%d, current_len1 =%d", byte_decode,
|
|
msbc_next_frame_size);
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
msbc_next_frame_size = (MSBC_FRAME_SIZE - byte_decode) > 0
|
|
? (MSBC_FRAME_SIZE - byte_decode)
|
|
: MSBC_FRAME_SIZE;
|
|
goto get_again;
|
|
}
|
|
|
|
else if (ret == BT_STS_SUCCESS) {
|
|
need_init_decoder = false;
|
|
pcm_processed = pcm_data.dataLen;
|
|
pcm_data.dataLen = 0;
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
if (plc_type == 0) {
|
|
byte_decode += 1; // padding
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode);
|
|
} else {
|
|
#if defined(MSBC_PCM_PLC_ENABLE)
|
|
if (plc_type == 2) {
|
|
pcm_processed = pcm_len;
|
|
} else {
|
|
if (msbc_next_frame_size < MSBC_FRAME_SIZE)
|
|
msbc_next_frame_size += 1; // padding
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, msbc_next_frame_size);
|
|
}
|
|
#else
|
|
if (msbc_next_frame_size < MSBC_FRAME_SIZE)
|
|
msbc_next_frame_size += 1; // padding
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, msbc_next_frame_size);
|
|
#endif
|
|
}
|
|
#else
|
|
if (msbc_next_frame_size < MSBC_FRAME_SIZE)
|
|
msbc_next_frame_size += 1; // padding
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, msbc_next_frame_size);
|
|
#endif
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
msbc_next_frame_size = MSBC_FRAME_SIZE;
|
|
|
|
#if defined(MSBC_PLC_ENABLE)
|
|
// plc after a good frame
|
|
if (!msbc_can_plc) {
|
|
msbc_can_plc = true;
|
|
}
|
|
#endif
|
|
} else if (ret == BT_STS_FAILED) {
|
|
need_init_decoder = true;
|
|
pcm_processed = pcm_len;
|
|
pcm_data.dataLen = 0;
|
|
|
|
memset(pcm_buffer, 0, pcm_len);
|
|
TRACE(1, "err mutelen:%d\n", pcm_processed);
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
msbc_next_frame_size = MSBC_FRAME_SIZE;
|
|
|
|
/* leave */
|
|
} else if (ret == BT_STS_NO_RESOURCES) {
|
|
need_init_decoder = true;
|
|
pcm_processed = pcm_len;
|
|
pcm_data.dataLen = 0;
|
|
|
|
memset(pcm_buffer, 0, pcm_len);
|
|
TRACE(1, "no_res mutelen:%d\n", pcm_processed);
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
msbc_next_frame_size = MSBC_FRAME_SIZE;
|
|
}
|
|
|
|
exit:
|
|
if (underflow || need_init_decoder) {
|
|
TRACE(2, "media_msbc_decoder underflow len:%d,need_init_decoder=%d\n ",
|
|
pcm_len, need_init_decoder);
|
|
}
|
|
|
|
// TRACE(1,"pcm_processed %d", pcm_processed);
|
|
|
|
return pcm_processed;
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
// capture flow
|
|
// mic-->audioflinger
|
|
// capture-->store_voicebtpcm_p2m_buffer-->get_voicebtpcm_p2m_frame-->bt used by
|
|
// capture, store data from mic to memory
|
|
int store_voicebtpcm_p2m_buffer(unsigned char *buf, unsigned int len) {
|
|
int POSSIBLY_UNUSED size;
|
|
unsigned int avail_size = 0;
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
// merge_two_trace_to_one_track_16bits(0, (uint16_t *)buf, (uint16_t *)buf,
|
|
// len>>1); r = APP_AUDIO_EnCQueue(&voicebtpcm_p2m_queue, buf, len>>1);
|
|
avail_size = APP_AUDIO_AvailableOfCQueue(&voicebtpcm_p2m_pcm_queue);
|
|
if (len <= avail_size) {
|
|
APP_AUDIO_EnCQueue(&voicebtpcm_p2m_pcm_queue, buf, len);
|
|
} else {
|
|
VOICEBTPCM_TRACE(2, "mic buff overflow %d/%d", len, avail_size);
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len - avail_size);
|
|
APP_AUDIO_EnCQueue(&voicebtpcm_p2m_pcm_queue, buf, len);
|
|
}
|
|
size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_pcm_queue);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
VOICEBTPCM_TRACE(2, "p2m :%d/%d", len, size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(HFP_1_6_ENABLE)
|
|
unsigned char get_msbc_counter(void) {
|
|
if (msbc_counter == 0x08) {
|
|
msbc_counter = 0x38;
|
|
} else if (msbc_counter == 0x38) {
|
|
msbc_counter = 0xC8;
|
|
} else if (msbc_counter == 0xC8) {
|
|
msbc_counter = 0xF8;
|
|
} else if (msbc_counter == 0xF8) {
|
|
msbc_counter = 0x08;
|
|
}
|
|
|
|
return msbc_counter;
|
|
}
|
|
#endif
|
|
|
|
#if defined(TX_RX_PCM_MASK)
|
|
CQueue Tx_esco_queue;
|
|
CQueue Rx_esco_queue;
|
|
CQueue *get_tx_esco_queue_ptr() { return &Tx_esco_queue; }
|
|
CQueue *get_rx_esco_queue_ptr() { return &Rx_esco_queue; }
|
|
|
|
#endif
|
|
|
|
// used by capture, get the memory data which has be stored by
|
|
// store_voicebtpcm_p2m_buffer()
|
|
int get_voicebtpcm_p2m_frame(unsigned char *buf, unsigned int len) {
|
|
int got_len = 0;
|
|
|
|
// TRACE(2,"[%s] pcm_len = %d", __func__, len / 2);
|
|
if (voicebtpcm_cache_p2m_status == APP_AUDIO_CACHE_CACHEING) {
|
|
app_audio_memset_16bit((short *)buf, 0, len / 2);
|
|
TRACE(1, "[%s] APP_AUDIO_CACHE_CACHEING", __func__);
|
|
return len;
|
|
}
|
|
|
|
int msbc_encode_temp_len = MSBC_FRAME_SIZE * 2;
|
|
|
|
ASSERT(len % msbc_encode_temp_len == 0, "[%s] len(%d) is invalid", __func__,
|
|
len);
|
|
|
|
int loop_cnt = len / msbc_encode_temp_len;
|
|
len = msbc_encode_temp_len;
|
|
|
|
for (int cnt = 0; cnt < loop_cnt; cnt++) {
|
|
if (bt_sco_codec_is_msbc()) {
|
|
#ifdef HFP_1_6_ENABLE
|
|
uint16_t bytes_encoded = 0, buf_len = len;
|
|
uint16_t *dest_buf = 0, offset = 0;
|
|
int r = 0;
|
|
unsigned char *e1 = NULL, *e2 = NULL;
|
|
unsigned int len1 = 0, len2 = 0;
|
|
|
|
got_len = 0;
|
|
|
|
dest_buf = (uint16_t *)buf;
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
r = APP_AUDIO_PeekCQueue(&voicebtpcm_p2m_pcm_queue, MSBC_ENCODE_PCM_LEN,
|
|
&e1, &len1, &e2, &len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
if (r == CQ_OK) {
|
|
if (len1) {
|
|
memcpy(temp_msbc_buf, e1, len1);
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len1);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
got_len += len1;
|
|
}
|
|
if (len2 != 0) {
|
|
memcpy(temp_msbc_buf + got_len, e2, len2);
|
|
got_len += len2;
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
}
|
|
|
|
// int t = 0;
|
|
// t = hal_sys_timer_get();
|
|
msbc_encoder_pcmdata.data = temp_msbc_buf;
|
|
msbc_encoder_pcmdata.dataLen = MSBC_ENCODE_PCM_LEN;
|
|
memset(temp_msbc_buf1, 0, MSBC_FRAME_SIZE);
|
|
btif_sbc_encode_frames(msbc_encoder, &msbc_encoder_pcmdata,
|
|
&bytes_encoded, temp_msbc_buf1,
|
|
(uint16_t *)&buf_len, 0xFFFF);
|
|
// TRACE(1,"enc msbc %d t\n", hal_sys_timer_get()-t);
|
|
// TRACE(2,"encode len %d, out len %d\n", bytes_encoded, buf_len);
|
|
|
|
dest_buf[offset++] = 1 << 8;
|
|
dest_buf[offset++] = get_msbc_counter() << 8;
|
|
|
|
for (int i = 0; i < buf_len; ++i) {
|
|
dest_buf[offset++] = temp_msbc_buf1[i] << 8;
|
|
}
|
|
|
|
dest_buf[offset++] = 0; // padding
|
|
|
|
got_len = len;
|
|
}
|
|
|
|
#if defined(TX_RX_PCM_MASK)
|
|
if (btdrv_is_pcm_mask_enable() == 1) {
|
|
int status;
|
|
uint8_t len = 120;
|
|
uint8_t temp_mic_buff[len];
|
|
for (uint8_t j = 0; j < len; j++) {
|
|
temp_mic_buff[j] = buf[2 * j + 1];
|
|
}
|
|
status = APP_AUDIO_EnCQueue(&Tx_esco_queue, temp_mic_buff, len);
|
|
if (status) {
|
|
// TRACE(0,"Tx EnC Fail");
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
} else {
|
|
#if defined(CVSD_BYPASS)
|
|
got_len = encode_cvsd_frame(buf, len);
|
|
#else
|
|
int r = 0;
|
|
unsigned char *e1 = NULL, *e2 = NULL;
|
|
unsigned int len1 = 0, len2 = 0;
|
|
got_len = 0;
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
// size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_queue);
|
|
r = APP_AUDIO_PeekCQueue(&voicebtpcm_p2m_pcm_queue, len - got_len, &e1,
|
|
&len1, &e2, &len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
// VOICEBTPCM_TRACE(2,"p2m :%d/%d", len,
|
|
// APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_queue));
|
|
|
|
if (r == CQ_OK) {
|
|
if (len1) {
|
|
app_audio_memcpy_16bit((short *)buf, (short *)e1, len1 / 2);
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len1);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
got_len += len1;
|
|
}
|
|
if (len2 != 0) {
|
|
app_audio_memcpy_16bit((short *)(buf + got_len), (short *)e2,
|
|
len2 / 2);
|
|
got_len += len2;
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
}
|
|
} else {
|
|
VOICEBTPCM_TRACE(0, "mic buff underflow");
|
|
app_audio_memset_16bit((short *)buf, 0, len / 2);
|
|
got_len = len;
|
|
voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_CACHEING;
|
|
}
|
|
#endif
|
|
}
|
|
buf += msbc_encode_temp_len;
|
|
}
|
|
|
|
return got_len;
|
|
}
|
|
|
|
#if 0
|
|
void get_mic_data_max(short *buf, uint32_t len)
|
|
{
|
|
int max0 = -32768, min0 = 32767, diff0 = 0;
|
|
int max1 = -32768, min1 = 32767, diff1 = 0;
|
|
|
|
for(uint32_t i=0; i<len/2; i+=2)
|
|
{
|
|
if(buf[i+0]>max0)
|
|
{
|
|
max0 = buf[i+0];
|
|
}
|
|
|
|
if(buf[i+0]<min0)
|
|
{
|
|
min0 = buf[i+0];
|
|
}
|
|
|
|
if(buf[i+1]>max1)
|
|
{
|
|
max1 = buf[i+1];
|
|
}
|
|
|
|
if(buf[i+1]<min1)
|
|
{
|
|
min1 = buf[i+1];
|
|
}
|
|
}
|
|
TRACE(6,"min0 = %d, max0 = %d, diff0 = %d, min1 = %d, max1 = %d, diff1 = %d", min0, max0, max0 - min0, min1, max1, max1 - min1);
|
|
}
|
|
#endif
|
|
|
|
#ifdef __BT_ANC__
|
|
extern uint8_t bt_sco_samplerate_ratio;
|
|
#define US_COEF_NUM (24)
|
|
|
|
/*
|
|
8K -->48K
|
|
single phase coef Number:=24, upsample factor:=6,
|
|
64, -311, 210, -320, 363, -407, 410, -356, 196, 191,-1369,30721,
|
|
3861,-2265, 1680,-1321, 1049, -823, 625, -471, 297, -327, 34, 19, 72,
|
|
-254, 75, -117, 46, 58, -256, 583,-1141, 2197,-4866,28131,10285,-4611,
|
|
2935,-2061, 1489,-1075, 755, -523, 310, -291, -19, 31, 65, -175, -73, 84,
|
|
-245, 457, -786, 1276,-2040, 3377,-6428,23348,17094,-6200, 3592,-2347,
|
|
1588,-1073, 703, -447, 236, -203, -92, 49, 49, -92, -203, 236, -447,
|
|
703,-1073, 1588,-2347, 3592,-6200,17094,23348,-6428, 3377,-2040, 1276, -786,
|
|
457, -245, 84, -73, -175, 65, 31, -19, -291, 310, -523, 755,-1075,
|
|
1489,-2061, 2935,-4611,10285,28131,-4866, 2197,-1141, 583, -256, 58, 46,
|
|
-117, 75, -254, 72, 19, 34, -327, 297, -471, 625, -823, 1049,-1321,
|
|
1680,-2265, 3861,30721,-1369, 191, 196, -356, 410, -407, 363, -320, 210,
|
|
-311, 64,
|
|
*/
|
|
|
|
const static short coef_8k_upto_48k[6][US_COEF_NUM] __attribute__((
|
|
section(".sram_data"))) = {
|
|
{64, -311, 210, -320, 363, -407, 410, -356, 196, 191, -1369, 30721,
|
|
3861, -2265, 1680, -1321, 1049, -823, 625, -471, 297, -327, 34, 19},
|
|
{72, -254, 75, -117, 46, 58, -256, 583,
|
|
-1141, 2197, -4866, 28131, 10285, -4611, 2935, -2061,
|
|
1489, -1075, 755, -523, 310, -291, -19, 31},
|
|
{65, -175, -73, 84, -245, 457, -786, 1276,
|
|
-2040, 3377, -6428, 23348, 17094, -6200, 3592, -2347,
|
|
1588, -1073, 703, -447, 236, -203, -92, 49},
|
|
{49, -92, -203, 236, -447, 703, -1073, 1588,
|
|
-2347, 3592, -6200, 17094, 23348, -6428, 3377, -2040,
|
|
1276, -786, 457, -245, 84, -73, -175, 65},
|
|
{31, -19, -291, 310, -523, 755, -1075, 1489,
|
|
-2061, 2935, -4611, 10285, 28131, -4866, 2197, -1141,
|
|
583, -256, 58, 46, -117, 75, -254, 72},
|
|
{19, 34, -327, 297, -471, 625, -823, 1049, -1321, 1680, -2265, 3861,
|
|
30721, -1369, 191, 196, -356, 410, -407, 363, -320, 210, -311, 64}};
|
|
|
|
/*
|
|
16K -->48K
|
|
|
|
single phase coef Number:=24, upsample factor:=3,
|
|
1, -291, 248, -327, 383, -405, 362, -212, -129, 875,-2948,29344,
|
|
7324,-3795, 2603,-1913, 1418,-1031, 722, -478, 292, -220, -86, 16, 26,
|
|
-212, 6, 45, -185, 414, -764, 1290,-2099, 3470,-6431,20320,20320,-6431,
|
|
3470,-2099, 1290, -764, 414, -185, 45, 6, -212, 26, 16, -86, -220, 292,
|
|
-478, 722,-1031, 1418,-1913, 2603,-3795, 7324,29344,-2948, 875, -129, -212,
|
|
362, -405, 383, -327, 248, -291, 1,
|
|
*/
|
|
|
|
const static short coef_16k_upto_48k[3][US_COEF_NUM] __attribute__((
|
|
section(".sram_data"))) = {
|
|
{1, -291, 248, -327, 383, -405, 362, -212, -129, 875, -2948, 29344,
|
|
7324, -3795, 2603, -1913, 1418, -1031, 722, -478, 292, -220, -86, 16},
|
|
{26, -212, 6, 45, -185, 414, -764, 1290,
|
|
-2099, 3470, -6431, 20320, 20320, -6431, 3470, -2099,
|
|
1290, -764, 414, -185, 45, 6, -212, 26},
|
|
{16, -86, -220, 292, -478, 722, -1031, 1418, -1913, 2603, -3795, 7324,
|
|
29344, -2948, 875, -129, -212, 362, -405, 383, -327, 248, -291, 1}};
|
|
|
|
static short us_para_lst[US_COEF_NUM - 1];
|
|
|
|
static inline short us_get_coef_para(U32 samp_idx, U32 coef_idx) {
|
|
if (bt_sco_samplerate_ratio == 6)
|
|
return coef_8k_upto_48k[samp_idx][coef_idx];
|
|
else
|
|
return coef_16k_upto_48k[samp_idx][coef_idx];
|
|
}
|
|
|
|
void us_fir_init(void) {
|
|
app_audio_memset_16bit(us_para_lst, 0, sizeof(us_para_lst) / sizeof(short));
|
|
}
|
|
|
|
__attribute__((section(".fast_text_sram"))) U32
|
|
us_fir_run(short *src_buf, short *dst_buf, U32 in_samp_num) {
|
|
U32 in_idx, samp_idx, coef_idx, real_idx, out_idx;
|
|
int para, out;
|
|
|
|
for (in_idx = 0, out_idx = 0; in_idx < in_samp_num; in_idx++) {
|
|
for (samp_idx = 0; samp_idx < bt_sco_samplerate_ratio; samp_idx++) {
|
|
out = 0;
|
|
for (coef_idx = 0; coef_idx < US_COEF_NUM; coef_idx++) {
|
|
real_idx = coef_idx + in_idx;
|
|
para = (real_idx < (US_COEF_NUM - 1))
|
|
? us_para_lst[real_idx]
|
|
: src_buf[real_idx - (US_COEF_NUM - 1)];
|
|
out += para * us_get_coef_para(samp_idx, coef_idx);
|
|
}
|
|
|
|
dst_buf[out_idx] = (short)(out >> 16);
|
|
out_idx++;
|
|
}
|
|
}
|
|
|
|
if (in_samp_num >= (US_COEF_NUM - 1)) {
|
|
app_audio_memcpy_16bit(us_para_lst,
|
|
(src_buf + in_samp_num - US_COEF_NUM + 1),
|
|
(US_COEF_NUM - 1));
|
|
} else {
|
|
U32 start_idx = (US_COEF_NUM - 1 - in_samp_num);
|
|
|
|
app_audio_memcpy_16bit(us_para_lst, (us_para_lst + in_samp_num), start_idx);
|
|
|
|
app_audio_memcpy_16bit((us_para_lst + start_idx), src_buf, in_samp_num);
|
|
}
|
|
return out_idx;
|
|
}
|
|
|
|
uint32_t voicebtpcm_pcm_resample(short *src_samp_buf, uint32_t src_smpl_cnt,
|
|
short *dst_samp_buf) {
|
|
return us_fir_run(src_samp_buf, dst_samp_buf, src_smpl_cnt);
|
|
}
|
|
|
|
#endif
|
|
|
|
static int speech_tx_aec_frame_len = 0;
|
|
|
|
int speech_tx_aec_get_frame_len(void) { return speech_tx_aec_frame_len; }
|
|
|
|
void speech_tx_aec_set_frame_len(int len) {
|
|
TRACE(2, "[%s] len = %d", __func__, len);
|
|
speech_tx_aec_frame_len = len;
|
|
}
|
|
|
|
#if 1
|
|
// used by capture, store data from mic to memory
|
|
uint32_t voicebtpcm_pcm_audio_data_come(uint8_t *buf, uint32_t len) {
|
|
int16_t POSSIBLY_UNUSED ret = 0;
|
|
bool POSSIBLY_UNUSED vdt = false;
|
|
int size = 0;
|
|
|
|
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \
|
|
defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT)
|
|
#if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE)
|
|
uint32_t queue_len;
|
|
|
|
uint32_t len_per_channel = len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM;
|
|
|
|
ASSERT(len_per_channel == speech_tx_aec_get_frame_len() * sizeof(short),
|
|
"%s: Unmatched len: %u != %u", __func__, len_per_channel,
|
|
speech_tx_aec_get_frame_len() * sizeof(short));
|
|
ASSERT(echo_buf_q_rpos + len_per_channel <= echo_buf_q_size,
|
|
"%s: rpos (%u) overflow: len=%u size=%u", __func__, echo_buf_q_rpos,
|
|
len_per_channel, echo_buf_q_size);
|
|
|
|
if (echo_buf_q_rpos == echo_buf_q_wpos) {
|
|
queue_len = echo_buf_q_full ? echo_buf_q_size : 0;
|
|
echo_buf_q_full = false;
|
|
} else if (echo_buf_q_rpos < echo_buf_q_wpos) {
|
|
queue_len = echo_buf_q_wpos - echo_buf_q_rpos;
|
|
} else {
|
|
queue_len = echo_buf_q_size + echo_buf_q_wpos - echo_buf_q_rpos;
|
|
}
|
|
ASSERT(queue_len >= len_per_channel,
|
|
"%s: queue underflow: q_len=%u len=%u rpos=%u wpos=%u size=%u",
|
|
__func__, queue_len, len_per_channel, echo_buf_q_rpos, echo_buf_q_wpos,
|
|
echo_buf_q_size);
|
|
|
|
aec_echo_buf = (int16_t *)(echo_buf_queue + echo_buf_q_rpos);
|
|
echo_buf_q_rpos += len_per_channel;
|
|
if (echo_buf_q_rpos >= echo_buf_q_size) {
|
|
echo_buf_q_rpos = 0;
|
|
}
|
|
#endif
|
|
#endif
|
|
short *pcm_buf = (short *)buf;
|
|
#if defined(SPEECH_TX_24BIT)
|
|
int pcm_len = len / sizeof(int32_t);
|
|
#else
|
|
int pcm_len = len / sizeof(int16_t);
|
|
#endif
|
|
|
|
if (app_get_current_overlay() == APP_OVERLAY_HFP) {
|
|
speech_tx_process(pcm_buf, aec_echo_buf, &pcm_len);
|
|
|
|
#if defined(SPEECH_TX_24BIT)
|
|
int32_t *buf24 = (int32_t *)pcm_buf;
|
|
int16_t *buf16 = (int16_t *)pcm_buf;
|
|
for (int i = 0; i < pcm_len; i++)
|
|
buf16[i] = (buf24[i] >> 8);
|
|
#endif
|
|
|
|
if (resample_needed_flag == true) {
|
|
iir_resample_process(upsample_st, pcm_buf, upsample_buf_for_msbc,
|
|
pcm_len);
|
|
pcm_buf = upsample_buf_for_msbc;
|
|
pcm_len = sco_frame_length;
|
|
}
|
|
} else {
|
|
memset(buf, 0, len);
|
|
}
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
store_voicebtpcm_p2m_buffer((uint8_t *)pcm_buf, pcm_len * sizeof(short));
|
|
size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_pcm_queue);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
if (size >= voicebtpcm_p2m_cache_threshold) {
|
|
voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_OK;
|
|
}
|
|
|
|
return pcm_len * 2;
|
|
}
|
|
#else
|
|
// used by capture, store data from mic to memory
|
|
uint32_t voicebtpcm_pcm_audio_data_come(uint8_t *buf, uint32_t len) {
|
|
int16_t POSSIBLY_UNUSED ret = 0;
|
|
bool POSSIBLY_UNUSED vdt = false;
|
|
int size = 0;
|
|
|
|
short *pcm_buf = (short *)buf;
|
|
uint32_t pcm_len = len / 2;
|
|
|
|
// TRACE(2,"[%s] pcm_len = %d", __func__, pcm_len);
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
store_voicebtpcm_p2m_buffer((uint8_t *)pcm_buf, pcm_len * 2);
|
|
size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_queue);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
if (size > VOICEBTPCM_PCM_TEMP_BUFFER_SIZE) {
|
|
voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_OK;
|
|
}
|
|
|
|
return pcm_len * 2;
|
|
}
|
|
#endif
|
|
|
|
// used by playback, play data from memory to speaker
|
|
uint32_t voicebtpcm_pcm_audio_more_data(uint8_t *buf, uint32_t len) {
|
|
uint32_t l = 0;
|
|
// TRACE(3,"[%s]: pcm_len = %d, %d", __FUNCTION__, len / 2,
|
|
// FAST_TICKS_TO_US(hal_fast_sys_timer_get()));
|
|
if ((voicebtpcm_cache_m2p_status == APP_AUDIO_CACHE_CACHEING) ||
|
|
(app_get_current_overlay() != APP_OVERLAY_HFP)) {
|
|
app_audio_memset_16bit((short *)buf, 0, len / 2);
|
|
l = len;
|
|
} else {
|
|
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \
|
|
defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) || \
|
|
defined(SPEECH_TX_THIRDPARTY)
|
|
#if !(defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE))
|
|
#if defined(SPEECH_TX_24BIT) && defined(SPEECH_RX_24BIT)
|
|
memcpy(aec_echo_buf, buf, len / sizeof(int16_t) * sizeof(int32_t));
|
|
#elif defined(SPEECH_TX_24BIT) && !defined(SPEECH_RX_24BIT)
|
|
short *buf_p = (short *)buf;
|
|
for (uint32_t i = 0; i < len / sizeof(int16_t); i++) {
|
|
aec_echo_buf[i] = ((int32_t)buf_p[i] << 8);
|
|
}
|
|
#elif !defined(SPEECH_TX_24BIT) && defined(SPEECH_RX_24BIT)
|
|
int32_t *buf32_p = (int32_t *)buf;
|
|
for (uint32_t i = 0; i < len / sizeof(int16_t); i++) {
|
|
aec_echo_buf[i] = (buf32_p[i] >> 8);
|
|
}
|
|
#else
|
|
app_audio_memcpy_16bit((int16_t *)aec_echo_buf, (int16_t *)buf, len / 2);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
int decode_len = len;
|
|
uint8_t *decode_buf = buf;
|
|
|
|
if (resample_needed_flag == true) {
|
|
decode_len = sco_frame_length * 2;
|
|
decode_buf = (uint8_t *)downsample_buf_for_msbc;
|
|
}
|
|
|
|
unsigned int len1 = 0, len2 = 0;
|
|
unsigned char *e1 = NULL, *e2 = NULL;
|
|
int r = 0;
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
len1 = len2 = 0;
|
|
e1 = e2 = 0;
|
|
r = APP_AUDIO_PeekCQueue(&voicebtpcm_m2p_pcm_queue, decode_len, &e1, &len1,
|
|
&e2, &len2);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
if (r == CQ_ERR) {
|
|
TRACE(0, "pcm buff underflow");
|
|
memset(decode_buf, 0, decode_len);
|
|
l = len;
|
|
goto fail;
|
|
}
|
|
|
|
if (!len1) {
|
|
TRACE(2, "pcm len1 underflow %d/%d\n", len1, len2);
|
|
memset(decode_buf, 0, decode_len);
|
|
l = len;
|
|
goto fail;
|
|
}
|
|
|
|
if (len1 > 0 && e1) {
|
|
memcpy(decode_buf, e1, len1);
|
|
}
|
|
if (len2 > 0 && e2) {
|
|
memcpy(decode_buf + len1, e2, len2);
|
|
}
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, decode_len);
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
} // if (voicebtpcm_cache_m2p_status == APP_AUDIO_CACHE_CACHEING)
|
|
|
|
// downsample_buf_for_msbc size is len * 2
|
|
if (resample_needed_flag == true) {
|
|
iir_resample_process(downsample_st, downsample_buf_for_msbc, (int16_t *)buf,
|
|
sco_frame_length);
|
|
}
|
|
|
|
fail:
|
|
short *POSSIBLY_UNUSED pcm_buf = (short *)buf;
|
|
int POSSIBLY_UNUSED pcm_len = len / 2;
|
|
|
|
#if defined(SPEECH_RX_24BIT)
|
|
int32_t *buf32 = (int32_t *)buf;
|
|
for (int i = pcm_len - 1; i >= 0; i--) {
|
|
buf32[i] = ((int32_t)pcm_buf[i] << 8);
|
|
}
|
|
#endif
|
|
|
|
speech_rx_process(pcm_buf, &pcm_len);
|
|
|
|
buf = (uint8_t *)pcm_buf;
|
|
len = pcm_len * sizeof(short);
|
|
|
|
#if defined(SPEECH_RX_24BIT)
|
|
len = len / sizeof(int16_t) * sizeof(int32_t);
|
|
#endif
|
|
|
|
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \
|
|
defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT)
|
|
#if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE)
|
|
uint32_t queue_len;
|
|
|
|
ASSERT(len == speech_tx_aec_get_frame_len() * sizeof(short),
|
|
"%s: Unmatched len: %u != %u", __func__, len,
|
|
speech_tx_aec_get_frame_len() * sizeof(short));
|
|
ASSERT(echo_buf_q_wpos + len <= echo_buf_q_size,
|
|
"%s: wpos (%u) overflow: len=%u size=%u", __func__, echo_buf_q_wpos,
|
|
len, echo_buf_q_size);
|
|
|
|
if (echo_buf_q_rpos == echo_buf_q_wpos) {
|
|
queue_len = echo_buf_q_full ? echo_buf_q_size : 0;
|
|
} else if (echo_buf_q_rpos < echo_buf_q_wpos) {
|
|
queue_len = echo_buf_q_wpos - echo_buf_q_rpos;
|
|
} else {
|
|
queue_len = echo_buf_q_size + echo_buf_q_wpos - echo_buf_q_rpos;
|
|
}
|
|
ASSERT(queue_len + len <= echo_buf_q_size,
|
|
"%s: queue overflow: q_len=%u len=%u rpos=%u wpos=%u size=%u",
|
|
__func__, queue_len, len, echo_buf_q_rpos, echo_buf_q_wpos,
|
|
echo_buf_q_size);
|
|
|
|
app_audio_memcpy_16bit((int16_t *)(echo_buf_queue + echo_buf_q_wpos),
|
|
(int16_t *)buf, len / 2);
|
|
echo_buf_q_wpos += len;
|
|
if (echo_buf_q_wpos >= echo_buf_q_size) {
|
|
echo_buf_q_wpos = 0;
|
|
}
|
|
if (echo_buf_q_rpos == echo_buf_q_wpos) {
|
|
echo_buf_q_full = true;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return l;
|
|
}
|
|
|
|
void *voicebtpcm_get_ext_buff(int size) {
|
|
uint8_t *pBuff = NULL;
|
|
if (size % 4) {
|
|
size = size + (4 - size % 4);
|
|
}
|
|
app_audio_mempool_get_buff(&pBuff, size);
|
|
VOICEBTPCM_TRACE(2, "[%s] len:%d", __func__, size);
|
|
return (void *)pBuff;
|
|
}
|
|
|
|
int voicebtpcm_pcm_echo_buf_queue_init(uint32_t size) {
|
|
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \
|
|
defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT)
|
|
#if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE)
|
|
echo_buf_queue = (uint8_t *)voicebtpcm_get_ext_buff(size);
|
|
echo_buf_q_size = size;
|
|
echo_buf_q_wpos = 0;
|
|
echo_buf_q_rpos = 0;
|
|
echo_buf_q_full = false;
|
|
#endif
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void voicebtpcm_pcm_echo_buf_queue_reset(void) {
|
|
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \
|
|
defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT)
|
|
#if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE)
|
|
echo_buf_q_wpos = 0;
|
|
echo_buf_q_rpos = 0;
|
|
echo_buf_q_full = false;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void voicebtpcm_pcm_echo_buf_queue_deinit(void) {
|
|
#if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \
|
|
defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT)
|
|
#if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE)
|
|
echo_buf_queue = NULL;
|
|
echo_buf_q_size = 0;
|
|
echo_buf_q_wpos = 0;
|
|
echo_buf_q_rpos = 0;
|
|
echo_buf_q_full = false;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
extern enum AUD_SAMPRATE_T speech_codec_get_sample_rate(void);
|
|
|
|
// sco sample rate: encoder/decoder sample rate
|
|
// codec sample rate: hardware sample rate
|
|
int voicebtpcm_pcm_audio_init(int sco_sample_rate, int codec_sample_rate) {
|
|
uint8_t POSSIBLY_UNUSED *speech_buf = NULL;
|
|
int POSSIBLY_UNUSED speech_len = 0;
|
|
|
|
sco_frame_length =
|
|
SPEECH_FRAME_MS_TO_LEN(sco_sample_rate, SPEECH_SCO_FRAME_MS);
|
|
codec_frame_length =
|
|
SPEECH_FRAME_MS_TO_LEN(codec_sample_rate, SPEECH_SCO_FRAME_MS);
|
|
|
|
TRACE(3, "[%s] TX: sample rate = %d, frame len = %d", __func__,
|
|
codec_sample_rate, codec_frame_length);
|
|
TRACE(3, "[%s] RX: sample rate = %d, frame len = %d", __func__,
|
|
codec_sample_rate, codec_frame_length);
|
|
|
|
// init cqueue
|
|
uint8_t *p2m_pcm_buff = NULL;
|
|
uint8_t *m2p_pcm_buff = NULL;
|
|
#if defined(TX_RX_PCM_MASK)
|
|
uint8_t *Mic_frame_buff = NULL;
|
|
uint8_t *Rx_esco_buff = NULL;
|
|
uint32_t pcm_buf_size = 240 * sizeof(uint8_t);
|
|
#endif
|
|
if (bt_sco_codec_is_msbc()) {
|
|
voicebtpcm_p2m_pcm_cache_size = VOICEBTPCM_PCM_16K_QUEUE_SIZE;
|
|
voicebtpcm_m2p_pcm_cache_size = VOICEBTPCM_PCM_16K_QUEUE_SIZE;
|
|
} else {
|
|
voicebtpcm_p2m_pcm_cache_size = VOICEBTPCM_PCM_8K_QUEUE_SIZE;
|
|
voicebtpcm_m2p_pcm_cache_size = VOICEBTPCM_PCM_8K_QUEUE_SIZE;
|
|
}
|
|
|
|
voicebtpcm_p2m_cache_threshold = voicebtpcm_p2m_pcm_cache_size / 2;
|
|
voicebtpcm_m2p_cache_threshold = voicebtpcm_m2p_pcm_cache_size / 2;
|
|
|
|
app_audio_mempool_get_buff(&p2m_pcm_buff, voicebtpcm_p2m_pcm_cache_size);
|
|
app_audio_mempool_get_buff(&m2p_pcm_buff, voicebtpcm_m2p_pcm_cache_size);
|
|
#if defined(TX_RX_PCM_MASK)
|
|
app_audio_mempool_get_buff(&Mic_frame_buff, pcm_buf_size);
|
|
app_audio_mempool_get_buff(&Rx_esco_buff, pcm_buf_size);
|
|
#endif
|
|
|
|
LOCK_APP_AUDIO_QUEUE();
|
|
APP_AUDIO_InitCQueue(&voicebtpcm_p2m_pcm_queue, voicebtpcm_p2m_pcm_cache_size,
|
|
p2m_pcm_buff);
|
|
APP_AUDIO_InitCQueue(&voicebtpcm_m2p_pcm_queue, voicebtpcm_m2p_pcm_cache_size,
|
|
m2p_pcm_buff);
|
|
|
|
#if defined(TX_RX_PCM_MASK)
|
|
APP_AUDIO_InitCQueue(&Tx_esco_queue, pcm_buf_size, Mic_frame_buff);
|
|
APP_AUDIO_InitCQueue(&Rx_esco_queue, pcm_buf_size, Rx_esco_buff);
|
|
#endif
|
|
UNLOCK_APP_AUDIO_QUEUE();
|
|
|
|
voicebtpcm_cache_m2p_status = APP_AUDIO_CACHE_CACHEING;
|
|
voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_CACHEING;
|
|
|
|
#if defined(HFP_1_6_ENABLE)
|
|
|
|
memset(DecPcmBuf, 0, SAMPLES_LEN_PER_FRAME * sizeof(short));
|
|
memset(DecMsbcBuf, 0, MSBC_LEN_PER_FRAME * sizeof(unsigned char));
|
|
memset(DecMsbcBufAll, 0, sizeof(DecMsbcBufAll));
|
|
|
|
if (bt_sco_codec_is_msbc()) {
|
|
app_audio_mempool_get_buff((uint8_t **)&msbc_encoder,
|
|
sizeof(btif_sbc_encoder_t));
|
|
#if !defined(PENDING_MSBC_DECODER_ALG)
|
|
app_audio_mempool_get_buff(&temp_msbc_buf, MSBC_ENCODE_PCM_LEN);
|
|
app_audio_mempool_get_buff(&temp_msbc_buf1, MSBC_FRAME_SIZE);
|
|
#else
|
|
app_audio_mempool_get_buff(&msbc_buf_before_decode,
|
|
MSBC_FRAME_SIZE * sizeof(short));
|
|
app_audio_mempool_get_buff(&temp_msbc_buf,
|
|
MSBC_ENCODE_PCM_LEN * sizeof(short));
|
|
app_audio_mempool_get_buff(&temp_msbc_buf1,
|
|
MSBC_ENCODE_PCM_LEN * sizeof(short));
|
|
#endif
|
|
// init msbc encoder
|
|
btif_sbc_init_encoder(msbc_encoder);
|
|
msbc_encoder->streamInfo.mSbcFlag = 1;
|
|
msbc_encoder->streamInfo.numChannels = 1;
|
|
msbc_encoder->streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
|
|
|
|
msbc_encoder->streamInfo.bitPool = 26;
|
|
msbc_encoder->streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
msbc_encoder->streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
|
|
msbc_encoder->streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
|
|
msbc_encoder->streamInfo.numSubBands = 8;
|
|
|
|
msbc_counter = 0x08;
|
|
|
|
// init msbc decoder
|
|
const float EQLevel[25] = {
|
|
0.0630957, 0.0794328, 0.1, 0.1258925, 0.1584893,
|
|
0.1995262, 0.2511886, 0.3162278, 0.398107, 0.5011872,
|
|
0.6309573, 0.794328, 1, 1.258925, 1.584893,
|
|
1.995262, 2.5118864, 3.1622776, 3.9810717, 5.011872,
|
|
6.309573, 7.943282, 10, 12.589254, 15.848932}; //-12~12
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < sizeof(msbc_eq_band_gain) / sizeof(float); i++) {
|
|
msbc_eq_band_gain[i] = EQLevel[cfg_aud_eq_sbc_band_settings[i] + 12];
|
|
}
|
|
|
|
btif_sbc_init_decoder(&msbc_decoder);
|
|
|
|
msbc_decoder.streamInfo.mSbcFlag = 1;
|
|
msbc_decoder.streamInfo.bitPool = 26;
|
|
msbc_decoder.streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
msbc_decoder.streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
|
|
msbc_decoder.streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
|
|
/* Number of blocks used to encode the stream (4, 8, 12, or 16) */
|
|
msbc_decoder.streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
|
|
/* The number of subbands in the stream (4 or 8) */
|
|
msbc_decoder.streamInfo.numSubBands = 8;
|
|
msbc_decoder.streamInfo.numChannels = 1;
|
|
#if defined(PENDING_MSBC_DECODER_ALG)
|
|
last_msbc_sync_num = 0;
|
|
APP_AUDIO_InitCQueue(&msbc_temp_queue, sizeof(DecMsbcBufAll),
|
|
(uint8_t *)DecMsbcBufAll);
|
|
#endif
|
|
// init msbc plc
|
|
|
|
#ifndef ENABLE_LPC_PLC
|
|
InitPLC(&msbc_plc_state);
|
|
#endif
|
|
|
|
next_frame_flag = 0;
|
|
msbc_find_first_sync = 0;
|
|
|
|
packet_loss_detection_init(&pld);
|
|
|
|
#if defined(ENABLE_PLC_ENCODER)
|
|
app_audio_mempool_get_buff((uint8_t **)&msbc_plc_encoder,
|
|
sizeof(btif_sbc_encoder_t));
|
|
btif_sbc_init_encoder(msbc_plc_encoder);
|
|
msbc_plc_encoder->streamInfo.mSbcFlag = 1;
|
|
msbc_plc_encoder->streamInfo.bitPool = 26;
|
|
msbc_plc_encoder->streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
|
|
msbc_plc_encoder->streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO;
|
|
msbc_plc_encoder->streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS;
|
|
/* Number of blocks used to encode the stream (4, 8, 12, or 16) */
|
|
msbc_plc_encoder->streamInfo.numBlocks = BTIF_MSBC_BLOCKS;
|
|
/* The number of subbands in the stream (4 or 8) */
|
|
msbc_plc_encoder->streamInfo.numSubBands = 8;
|
|
msbc_plc_encoder->streamInfo.numChannels = 1;
|
|
app_audio_mempool_get_buff((uint8_t **)&msbc_plc_encoder_buffer,
|
|
sizeof(int16_t) *
|
|
(SAMPLES_LEN_PER_FRAME + MSBC_CODEC_DELAY));
|
|
#endif
|
|
} else
|
|
#endif
|
|
{
|
|
speech_plc = (PlcSt_8000 *)speech_plc_8000_init(voicebtpcm_get_ext_buff);
|
|
}
|
|
|
|
#if defined(CVSD_BYPASS)
|
|
Pcm8k_CvsdInit();
|
|
#endif
|
|
|
|
#ifdef SPEECH_RX_PLC_DUMP_DATA
|
|
audio_dump_temp_buf =
|
|
(int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * 120);
|
|
audio_dump_init(120, sizeof(short), 3);
|
|
#endif
|
|
|
|
resample_needed_flag = (sco_sample_rate == codec_sample_rate) ? 0 : 1;
|
|
|
|
if (resample_needed_flag == true) {
|
|
// upsample_buf_for_msbc -> uplink resampler
|
|
// downsample_buf_for_msbc -> downlink resampler
|
|
// store msbc pcm buffer
|
|
upsample_buf_for_msbc =
|
|
(int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * sco_frame_length);
|
|
downsample_buf_for_msbc =
|
|
(int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * sco_frame_length);
|
|
}
|
|
|
|
#if defined(SCO_OPTIMIZE_FOR_RAM)
|
|
sco_overlay_ram_buf_len =
|
|
hal_overlay_get_text_free_size((enum HAL_OVERLAY_ID_T)APP_OVERLAY_HFP);
|
|
sco_overlay_ram_buf = (uint8_t *)hal_overlay_get_text_free_addr(
|
|
(enum HAL_OVERLAY_ID_T)APP_OVERLAY_HFP);
|
|
#endif
|
|
|
|
speech_len = app_audio_mempool_free_buff_size() - APP_BT_STREAM_USE_BUF_SIZE;
|
|
speech_buf = (uint8_t *)voicebtpcm_get_ext_buff(speech_len);
|
|
|
|
int tx_frame_ms = SPEECH_PROCESS_FRAME_MS;
|
|
int rx_frame_ms = SPEECH_PROCESS_FRAME_MS;
|
|
#if !defined(SPEECH_RX_NS2FLOAT)
|
|
rx_frame_ms = SPEECH_SCO_FRAME_MS;
|
|
#endif
|
|
speech_init(codec_sample_rate, codec_sample_rate, tx_frame_ms, rx_frame_ms,
|
|
SPEECH_SCO_FRAME_MS, speech_buf, speech_len);
|
|
|
|
if (resample_needed_flag == true) {
|
|
// Resample state must be created after speech init, as it uses speech heap
|
|
upsample_st = iir_resample_init(
|
|
codec_frame_length,
|
|
iir_resample_choose_mode(codec_sample_rate, sco_sample_rate));
|
|
downsample_st = iir_resample_init(
|
|
sco_frame_length,
|
|
iir_resample_choose_mode(sco_sample_rate, codec_sample_rate));
|
|
}
|
|
|
|
#if defined(HFP_1_6_ENABLE) && defined(ENABLE_LPC_PLC)
|
|
msbc_plc_state = lpc_plc_create(sco_sample_rate);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int voicebtpcm_pcm_audio_deinit(void) {
|
|
TRACE(1, "[%s] Close...", __func__);
|
|
// TRACE(2,"[%s] app audio buffer free = %d", __func__,
|
|
// app_audio_mempool_free_buff_size());
|
|
|
|
#if defined(HFP_1_6_ENABLE) && defined(ENABLE_LPC_PLC)
|
|
lpc_plc_destroy(msbc_plc_state);
|
|
#endif
|
|
|
|
if (resample_needed_flag == true) {
|
|
iir_resample_destroy(upsample_st);
|
|
iir_resample_destroy(downsample_st);
|
|
}
|
|
|
|
speech_deinit();
|
|
|
|
#if defined(HFP_1_6_ENABLE)
|
|
#if !defined(PENDING_MSBC_DECODER_ALG)
|
|
packet_loss_detection_report(&pld);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(SCO_OPTIMIZE_FOR_RAM)
|
|
sco_overlay_ram_buf = NULL;
|
|
sco_overlay_ram_buf_len = 0;
|
|
#endif
|
|
|
|
voicebtpcm_pcm_echo_buf_queue_deinit();
|
|
|
|
// TRACE(1,"Free buf = %d", app_audio_mempool_free_buff_size());
|
|
|
|
return 0;
|
|
} |