986 lines
29 KiB
C
986 lines
29 KiB
C
#ifdef SUPPORT_MS_EXTENSIONS
|
|
#pragma bss_seg(".audio_cvp.data.bss")
|
|
#pragma data_seg(".audio_cvp.data")
|
|
#pragma const_seg(".audio_cvp.text.const")
|
|
#pragma code_seg(".audio_cvp.text")
|
|
#endif
|
|
/*
|
|
****************************************************************
|
|
* AUDIO SMS(SingleMic System)
|
|
* File : audio_aec_sms.c
|
|
* By :
|
|
* Notes : AEC回音消除 + 单mic降噪
|
|
*
|
|
****************************************************************
|
|
*/
|
|
#include "audio_cvp.h"
|
|
#include "system/includes.h"
|
|
#include "media/includes.h"
|
|
#include "effects/eq_config.h"
|
|
#include "effects/audio_pitch.h"
|
|
#include "circular_buf.h"
|
|
#include "overlay_code.h"
|
|
#include "audio_cvp_online.h"
|
|
#include "audio_config.h"
|
|
#include "cvp_node.h"
|
|
#include "app_config.h"
|
|
#include "audio_dc_offset_remove.h"
|
|
#include "adc_file.h"
|
|
#include "audio_cvp_def.h"
|
|
#include "effects/audio_gain_process.h"
|
|
|
|
#if TCFG_AUDIO_CVP_SYNC
|
|
#include "audio_cvp_sync.h"
|
|
#endif/*TCFG_AUDIO_CVP_SYNC*/
|
|
|
|
#if !defined(TCFG_CVP_DEVELOP_ENABLE) || (TCFG_CVP_DEVELOP_ENABLE == 0)
|
|
|
|
#if TCFG_USER_TWS_ENABLE
|
|
#include "bt_tws.h"
|
|
#endif/* TCFG_USER_TWS_ENABLE */
|
|
|
|
#if TCFG_SMART_VOICE_ENABLE
|
|
#include "smart_voice/smart_voice.h"
|
|
#endif
|
|
|
|
#if (TCFG_AUDIO_DUAL_MIC_ENABLE == 0) && (TCFG_AUDIO_TRIPLE_MIC_ENABLE == 0)
|
|
|
|
#define LOG_TAG_CONST AEC_USER
|
|
#define LOG_TAG "[AEC_USER]"
|
|
#define LOG_ERROR_ENABLE
|
|
#define LOG_DEBUG_ENABLE
|
|
#define LOG_INFO_ENABLE
|
|
/* #define LOG_DUMP_ENABLE */
|
|
#define LOG_CLI_ENABLE
|
|
#include "debug.h"
|
|
#include "audio_cvp_debug.c"
|
|
|
|
#define AEC_USER_MALLOC_ENABLE 1
|
|
|
|
/*CVP_TOGGLE:CVP模块(包括AEC、NLP、NS等)总开关,Disable则数据完全不经过处理,释放资源*/
|
|
#define CVP_TOGGLE TCFG_AEC_ENABLE /*CVP模块总开关*/
|
|
/*模块使能,控制代码是否链接*/
|
|
const u8 CONST_AEC_ENABLE = 1;
|
|
const u8 CONST_NLP_ENABLE = 1;
|
|
const u8 CONST_NS_ENABLE = 1;
|
|
const u8 CONST_AGC_ENABLE = 1;
|
|
|
|
/*CVP带宽配置*/
|
|
const u8 CONST_CVP_BAND_WIDTH_CFG = TCFG_AUDIO_CVP_BAND_WIDTH_CFG; //ANS
|
|
const u8 CONST_DNS_PARAM_TYPE = TCFG_AUDIO_CVP_BAND_WIDTH_CFG; //DNS
|
|
|
|
#include "asm/dac.h"
|
|
#if (AUDIO_DAC_CHANNEL_NUM == 1)
|
|
const int const_cvp_ref_2ch_enable = 0;
|
|
#else
|
|
const int const_cvp_ref_2ch_enable = 1;
|
|
#endif
|
|
|
|
/*使用输入立体声参考数据的TDE回音消除算法*/
|
|
const u8 CONST_SMS_TDE_STEREO_REF_ENABLE = 0;
|
|
|
|
|
|
#if ((defined TCFG_AUDIO_DATA_EXPORT_DEFINE) && (TCFG_AUDIO_DATA_EXPORT_DEFINE == AUDIO_DATA_EXPORT_VIA_UART))
|
|
/*AEC串口数据导出*/
|
|
const u8 CONST_AEC_EXPORT = 1;
|
|
#else
|
|
const u8 CONST_AEC_EXPORT = 0;
|
|
#endif/*TCFG_AUDIO_DATA_EXPORT_DEFINE*/
|
|
|
|
/*使能即可跟踪通话过程的内存情况*/
|
|
#define CVP_MEM_TRACE_ENABLE 0
|
|
|
|
/*
|
|
*延时估计使能
|
|
*点烟器需要做延时估计
|
|
*其他的暂时不需要做
|
|
*/
|
|
const u8 CONST_AEC_DLY_EST = 0;
|
|
|
|
/*
|
|
*ANS等级:0~2,
|
|
*等级1比等级0多6k左右的ram
|
|
*等级2比等级1多3k左右的ram:优化了连续说话变小声问题
|
|
*/
|
|
const u8 CONST_ANS_MODE = 2;
|
|
|
|
/*
|
|
*ANS版本配置
|
|
*ANS_V100:传统降噪
|
|
*ANS_V200:AI降噪,需要更多的ram和mips
|
|
**/
|
|
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
|
|
const u8 CONST_ANS_VERSION = ANS_V100;
|
|
#else
|
|
const u8 CONST_ANS_VERSION = ANS_V200;
|
|
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
|
|
|
|
//*********************************************************************************//
|
|
// DNS配置 //
|
|
//*********************************************************************************//
|
|
/* SNR估计,可以实现场景适配 */
|
|
const u8 CONST_DNS_SNR_EST = 0;
|
|
|
|
/* DNS后处理 */
|
|
const u8 CONST_DNS_POST_ENHANCE = 0;
|
|
|
|
//*******************************DNS配置 end**************************************//
|
|
|
|
/*
|
|
* 参考数据变采样处理
|
|
* 0 : 关闭参考数据变采样
|
|
* 1 : 使用软件变采样
|
|
* 2 : 使用硬件变采样
|
|
*/
|
|
#if TCFG_BT_DONGLE_ENABLE || TCFG_ESCO_DL_CVSD_SR_USE_16K || (TCFG_SMART_VOICE_ENABLE && TCFG_SMART_VOICE_USE_AEC) || TCFG_USB_SLAVE_AUDIO_MIC_ENABLE \
|
|
|| ((defined TCFG_LEA_CALL_DL_GLOBAL_SR) && (TCFG_LEA_CALL_DL_GLOBAL_SR != 0x01))
|
|
const u8 CONST_REF_SRC = 1;
|
|
#else
|
|
const u8 CONST_REF_SRC = 0;
|
|
#endif
|
|
/*Splittingfilter模式:0 or 1
|
|
*mode = 0:运算量和ram小,高频会跌下来
|
|
*mode = 1:运算量和ram大,频响正常(过认证,选择模式1)
|
|
*/
|
|
const u8 CONST_SPLIT_FILTER_MODE = 0;
|
|
|
|
/*
|
|
*AEC复杂等级,等级越高,ram和mips越大,适应性越好
|
|
*回音路径不定/回音失真等情况才需要比较高的等级
|
|
*音箱建议使用等级:5
|
|
*耳机建议使用等级:2
|
|
*/
|
|
#define AEC_TAIL_LENGTH 5 /*range:2~10,default:2*/
|
|
|
|
#if TCFG_AEC_SIMPLEX
|
|
/*限幅器-噪声门限*/
|
|
const u8 CONST_AEC_SIMPLEX = 1;
|
|
#else
|
|
const u8 CONST_AEC_SIMPLEX = 0;
|
|
#endif/*TCFG_AEC_SIMPLEX*/
|
|
/*单工连续清0的帧数*/
|
|
#define AEC_SIMPLEX_TAIL 15
|
|
/**远端数据大于CONST_AEC_SIMPLEX_THR,即清零近端数据
|
|
*越小,回音限制得越好,同时也就越容易卡*/
|
|
#define AEC_SIMPLEX_THR 100000 /*default:260000*/
|
|
|
|
/*数据输出开头丢掉的数据包数*/
|
|
#define AEC_OUT_DUMP_PACKET 15
|
|
/*数据输出开头丢掉的数据包数*/
|
|
#define AEC_IN_DUMP_PACKET 1
|
|
|
|
extern void aec_code_movable_load(void);
|
|
extern void aec_code_movable_unload(void);
|
|
extern int db2mag(int db, int dbQ, int magDQ);//10^db/20
|
|
|
|
extern int esco_player_runing();
|
|
__attribute__((weak))u32 usb_mic_is_running()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*复用lmp rx buf(一般通话的时候复用)
|
|
*rx_buf概率产生碎片,导致alloc失败,因此默认配0
|
|
*/
|
|
#define MALLOC_MULTIPLEX_EN 0
|
|
extern void *lmp_malloc(int);
|
|
extern void lmp_free(void *);
|
|
void *zalloc_mux(int size)
|
|
{
|
|
#if MALLOC_MULTIPLEX_EN
|
|
void *p = NULL;
|
|
do {
|
|
p = lmp_malloc(size);
|
|
if (p) {
|
|
break;
|
|
}
|
|
printf("aec_malloc wait...\n");
|
|
os_time_dly(2);
|
|
} while (1);
|
|
if (p) {
|
|
memset(p, 0, size);
|
|
}
|
|
printf("[malloc_mux]p = 0x%x,size = %d\n", p, size);
|
|
return p;
|
|
#else
|
|
return zalloc(size);
|
|
#endif
|
|
}
|
|
|
|
void free_mux(void *p)
|
|
{
|
|
#if MALLOC_MULTIPLEX_EN
|
|
printf("[free_mux]p = 0x%x\n", p);
|
|
lmp_free(p);
|
|
#else
|
|
free(p);
|
|
#endif
|
|
}
|
|
|
|
struct audio_aec_hdl {
|
|
u8 start; //aec模块状态
|
|
u8 inbuf_clear_cnt; //aec输入数据丢掉
|
|
u8 output_fade_in; //aec输出淡入使能
|
|
u8 output_fade_in_gain; //aec输出淡入增益
|
|
u8 EnableBit; //aec使能模块
|
|
u8 input_clear; //清0输入数据标志
|
|
u16 dump_packet; //前面如果有杂音,丢掉几包
|
|
|
|
void *dcc_hdl;
|
|
struct aec_s_attr attr;
|
|
struct audio_cvp_pre_param_t pre; //预处理配置
|
|
};
|
|
#if AEC_USER_MALLOC_ENABLE
|
|
struct audio_aec_hdl *aec_hdl = NULL;
|
|
#else
|
|
struct audio_aec_hdl aec_handle;
|
|
struct audio_aec_hdl *aec_hdl = &aec_handle;
|
|
#endif/*AEC_USER_MALLOC_ENABLE*/
|
|
static u8 global_output_way = 0;
|
|
|
|
void audio_cvp_set_output_way(u8 en)
|
|
{
|
|
global_output_way = en;
|
|
}
|
|
|
|
void audio_cvp_ref_start(u8 en)
|
|
{
|
|
if (aec_hdl && (aec_hdl->attr.fm_tx_start == 0)) {
|
|
aec_hdl->attr.fm_tx_start = en;
|
|
y_printf("fm_tx_start:%d\n", en);
|
|
}
|
|
}
|
|
|
|
int audio_cvp_probe_param_update(struct audio_cvp_pre_param_t *cfg)
|
|
{
|
|
if (aec_hdl) {
|
|
aec_hdl->pre = *cfg;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Process_Probe
|
|
* Description: AEC模块数据前处理回调
|
|
* Arguments : data 数据地址
|
|
* len 数据长度
|
|
* Return : 0 成功 其他 失败
|
|
* Note(s) : 在源数据经过AEC模块前,可以增加自定义处理
|
|
*********************************************************************
|
|
*/
|
|
static int audio_aec_probe(short *talk_mic, short *talk_ref_mic, short *mic3, short *ref, u16 len)
|
|
{
|
|
if (aec_hdl->pre.pre_gain_en) {
|
|
GainProcess_16Bit(talk_mic, talk_mic, aec_hdl->pre.talk_mic_gain, 1, 1, 1, len >> 1);
|
|
}
|
|
if (aec_hdl->dcc_hdl) {
|
|
audio_dc_offset_remove_run(aec_hdl->dcc_hdl, (void *)talk_mic, len);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Process_Post
|
|
* Description: AEC模块数据后处理回调
|
|
* Arguments : data 数据地址
|
|
* len 数据长度
|
|
* Return : 0 成功 其他 失败
|
|
* Note(s) : 在数据处理完毕,可以增加自定义后处理
|
|
*********************************************************************
|
|
*/
|
|
static int audio_aec_post(s16 *data, u16 len)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int audio_aec_update(u8 EnableBit)
|
|
{
|
|
printf("aec_update,wideband:%d,EnableBit:%x", aec_hdl->attr.wideband, EnableBit);
|
|
return 0;
|
|
}
|
|
|
|
/*跟踪系统内存使用情况:physics memory size xxxx bytes*/
|
|
static void sys_memory_trace(void)
|
|
{
|
|
static int cnt = 0;
|
|
if (cnt++ > 200) {
|
|
cnt = 0;
|
|
mem_stats();
|
|
}
|
|
}
|
|
|
|
/*通话上行同步输出回调*/
|
|
int audio_aec_sync_buffer_set(s16 *data, int len)
|
|
{
|
|
return cvp_node_output_handle(data, len);
|
|
}
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Output Handle
|
|
* Description: AEC模块数据输出回调
|
|
* Arguments : data 输出数据地址
|
|
* len 输出数据长度
|
|
* Return : 数据输出消耗长度
|
|
* Note(s) : None.
|
|
*********************************************************************
|
|
*/
|
|
extern void esco_enc_resume(void);
|
|
static int audio_aec_output(s16 *data, u16 len)
|
|
{
|
|
#if (((defined TCFG_KWS_VOICE_RECOGNITION_ENABLE) && TCFG_KWS_VOICE_RECOGNITION_ENABLE) || \
|
|
((defined TCFG_CALL_KWS_SWITCH_ENABLE) && TCFG_CALL_KWS_SWITCH_ENABLE))
|
|
//Voice Recognition get mic data here
|
|
if (esco_player_runing()) {
|
|
extern void kws_aec_data_output(void *priv, s16 * data, int len);
|
|
kws_aec_data_output(NULL, data, len);
|
|
}
|
|
#endif/*TCFG_KWS_VOICE_RECOGNITION_ENABLE*/
|
|
|
|
#if CVP_MEM_TRACE_ENABLE
|
|
sys_memory_trace();
|
|
#endif/*CVP_MEM_TRACE_ENABLE*/
|
|
|
|
if (aec_hdl->dump_packet) {
|
|
aec_hdl->dump_packet--;
|
|
memset(data, 0, len);
|
|
} else {
|
|
if (aec_hdl->output_fade_in) {
|
|
s32 tmp_data;
|
|
//printf("fade:%d\n",aec_hdl->output_fade_in_gain);
|
|
for (int i = 0; i < len / 2; i++) {
|
|
tmp_data = data[i];
|
|
data[i] = tmp_data * aec_hdl->output_fade_in_gain >> 7;
|
|
}
|
|
aec_hdl->output_fade_in_gain += 12;
|
|
if (aec_hdl->output_fade_in_gain >= 128) {
|
|
aec_hdl->output_fade_in = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if TCFG_AUDIO_CVP_SYNC
|
|
audio_cvp_sync_run(data, len);
|
|
return len;
|
|
#endif/*TCFG_AUDIO_CVP_SYNC*/
|
|
return cvp_node_output_handle(data, len);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Parameters
|
|
* Description: AEC模块配置参数
|
|
* Arguments : p 参数指针
|
|
* Return : None.
|
|
* Note(s) : 读取配置文件成功,则使用配置文件的参数配置,否则使用默
|
|
* 认参数配置
|
|
*********************************************************************
|
|
*/
|
|
static void audio_aec_param_init(struct aec_s_attr *p)
|
|
{
|
|
int ret = 0;
|
|
AEC_CONFIG cfg;
|
|
//读取工具配置参数+预处理参数
|
|
ret = cvp_node_param_cfg_read(&cfg, 0);
|
|
#if TCFG_AEC_TOOL_ONLINE_ENABLE
|
|
//APP在线调试,APP参数覆盖工具配置参数(不覆盖预处理参数)
|
|
ret = aec_cfg_online_update_fill(&cfg, sizeof(AEC_CONFIG));
|
|
#endif/*TCFG_AEC_TOOL_ONLINE_ENABLE*/
|
|
log_info("CVP_NS_MODE = %d\n", TCFG_AUDIO_CVP_NS_MODE);
|
|
if (ret == sizeof(AEC_CONFIG)) {
|
|
log_info("audio_aec read config ok\n");
|
|
p->AGC_NDT_fade_in_step = cfg.ndt_fade_in;
|
|
p->AGC_NDT_fade_out_step = cfg.ndt_fade_out;
|
|
p->AGC_DT_fade_in_step = cfg.dt_fade_in;
|
|
p->AGC_DT_fade_out_step = cfg.dt_fade_out;
|
|
p->AGC_NDT_max_gain = cfg.ndt_max_gain;
|
|
p->AGC_NDT_min_gain = cfg.ndt_min_gain;
|
|
p->AGC_NDT_speech_thr = cfg.ndt_speech_thr;
|
|
p->AGC_DT_max_gain = cfg.dt_max_gain;
|
|
p->AGC_DT_min_gain = cfg.dt_min_gain;
|
|
p->AGC_DT_speech_thr = cfg.dt_speech_thr;
|
|
p->AGC_echo_present_thr = cfg.echo_present_thr;
|
|
p->AEC_DT_AggressiveFactor = cfg.aec_dt_aggress;
|
|
p->AEC_RefEngThr = cfg.aec_refengthr;
|
|
p->ES_AggressFactor = cfg.es_aggress_factor;
|
|
p->ES_MinSuppress = cfg.es_min_suppress;
|
|
p->ES_Unconverge_OverDrive = cfg.es_min_suppress;
|
|
p->ANS_AggressFactor = cfg.ans_aggress;
|
|
p->ANS_MinSuppress = cfg.ans_suppress;
|
|
p->DNS_OverDrive = cfg.ans_aggress;
|
|
p->DNS_GainFloor = cfg.ans_suppress;
|
|
p->DNS_highGain = 2.5f;
|
|
p->DNS_rbRate = 0.3f;
|
|
|
|
p->ANS_NoiseLevel = db2mag((int)(cfg.init_noise_lvl * (1 << 8)), 8, 23);//初始噪声水平
|
|
|
|
p->adc_ref_en = cfg.adc_ref_en;
|
|
|
|
p->toggle = (cfg.aec_mode) ? 1 : 0;
|
|
p->EnableBit = (cfg.aec_mode & AEC_MODE_ADVANCE);
|
|
p->agc_en = (cfg.aec_mode & AGC_EN) ? 1 : 0;
|
|
p->ul_eq_en = 0;
|
|
g_printf("p->EnableBit %x\n", p->EnableBit);
|
|
} else {
|
|
log_error("read audio_aec param err:%x", ret);
|
|
p->toggle = 1;
|
|
p->EnableBit = AEC_MODE_REDUCE;
|
|
p->wideband = 0;
|
|
p->ul_eq_en = 1;
|
|
|
|
p->agc_en = 1;
|
|
p->AGC_NDT_fade_in_step = 1.3f;
|
|
p->AGC_NDT_fade_out_step = 0.9f;
|
|
p->AGC_DT_fade_in_step = 1.3f;
|
|
p->AGC_DT_fade_out_step = 0.9f;
|
|
p->AGC_NDT_max_gain = 12.f;
|
|
p->AGC_NDT_min_gain = 0.f;
|
|
p->AGC_NDT_speech_thr = -50.f;
|
|
p->AGC_DT_max_gain = 12.f;
|
|
p->AGC_DT_min_gain = 0.f;
|
|
p->AGC_DT_speech_thr = -40.f;
|
|
p->AGC_echo_present_thr = -70.f;
|
|
|
|
/*AEC*/
|
|
p->AEC_DT_AggressiveFactor = 1.f; /*范围:1~5,越大追踪越好,但会不稳定,如破音*/
|
|
p->AEC_RefEngThr = -70.f;
|
|
|
|
/*ES*/
|
|
p->ES_AggressFactor = -3.0f;
|
|
p->ES_MinSuppress = 4.f;
|
|
p->ES_Unconverge_OverDrive = p->ES_MinSuppress;
|
|
|
|
/*ANS*/
|
|
p->ANS_AggressFactor = 1.25f; /*范围:1~2,动态调整,越大越强(1.25f)*/
|
|
p->ANS_MinSuppress = 0.04f; /*范围:0~1,静态定死最小调整,越小越强(0.09f)*/
|
|
|
|
/*DNS*/
|
|
p->DNS_GainFloor = 0.1f; /*增益最小值控制,范围:0~1.0,越小降噪越强,默认0.1,建议值:0~0.2*/
|
|
p->DNS_OverDrive = 1.0f; /*控制降噪强度,范围:0~3.0,越大降噪越强,正常降噪时为1.0,建议调节范围:0.3~3*/
|
|
p->DNS_highGain = 2.5f; /*EQ强度, 范围:1.0f~3.5f,越大越强*/
|
|
p->DNS_rbRate = 0.3f; /*混响强度,范围:0~0.9f,越大越强*/
|
|
|
|
p->ANS_NoiseLevel = db2mag((int)(-75.0f * (1 << 8)), 8, 23);//初始噪声水平
|
|
}
|
|
p->ANS_mode = 1;
|
|
p->wn_gain = 331;
|
|
p->SimplexTail = AEC_SIMPLEX_TAIL;
|
|
p->SimplexThr = AEC_SIMPLEX_THR;
|
|
p->dly_est = 0;
|
|
p->dst_delay = 50;
|
|
p->AGC_echo_look_ahead = 0;
|
|
p->AGC_echo_hold = 0;
|
|
p->packet_dump = 50;/*0~255(u8)*/
|
|
p->aec_tail_length = AEC_TAIL_LENGTH;
|
|
p->ES_OverSuppressThr = 0.02f;
|
|
p->ES_OverSuppress = 2.f;
|
|
/* aec_param_dump(p); */
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Open
|
|
* Description: 初始化AEC模块
|
|
* Arguments : init_param sr 采样率(8000/16000)
|
|
* ref_sr 参考采样率
|
|
* enablebit 使能模块(AEC/NLP/AGC/ANS...)
|
|
* out_hdl 自定义回调函数,NULL则用默认的回调
|
|
* Return : 0 成功 其他 失败
|
|
* Note(s) : 该接口是对audio_aec_init的扩展,支持自定义使能模块以及
|
|
* 数据输出回调函数
|
|
*********************************************************************
|
|
*/
|
|
int audio_aec_open(struct audio_aec_init_param_t *init_param, s16 enablebit, int (*out_hdl)(s16 *data, u16 len))
|
|
{
|
|
s16 sample_rate = init_param->sample_rate;
|
|
u32 ref_sr = init_param->ref_sr;
|
|
u8 ref_channel = init_param->ref_channel;
|
|
struct aec_s_attr *aec_param;
|
|
printf("audio_aec_open\n");
|
|
mem_stats();
|
|
#if AEC_USER_MALLOC_ENABLE
|
|
aec_hdl = zalloc(sizeof(struct audio_aec_hdl));
|
|
if (aec_hdl == NULL) {
|
|
log_error("aec_hdl malloc failed");
|
|
return -ENOMEM;
|
|
}
|
|
#endif/*AEC_USER_MALLOC_ENABLE*/
|
|
|
|
#if TCFG_AUDIO_CVP_SYNC
|
|
audio_cvp_sync_open(sample_rate);
|
|
#endif/*TCFG_AUDIO_CVP_SYNC*/
|
|
|
|
overlay_load_code(OVERLAY_AEC);
|
|
aec_code_movable_load();
|
|
|
|
aec_hdl->dump_packet = AEC_OUT_DUMP_PACKET;
|
|
aec_hdl->inbuf_clear_cnt = AEC_IN_DUMP_PACKET;
|
|
aec_hdl->output_fade_in = 1;
|
|
aec_hdl->output_fade_in_gain = 0;
|
|
aec_param = &aec_hdl->attr;
|
|
aec_param->aec_probe = audio_aec_probe;
|
|
aec_param->aec_post = audio_aec_post;
|
|
#if TCFG_AEC_TOOL_ONLINE_ENABLE
|
|
aec_param->aec_update = audio_aec_update;
|
|
#endif/*TCFG_AEC_TOOL_ONLINE_ENABLE*/
|
|
aec_param->output_handle = audio_aec_output;
|
|
aec_param->far_noise_gate = 10;
|
|
if (ref_sr) {
|
|
aec_param->ref_sr = ref_sr;
|
|
} else {
|
|
aec_param->ref_sr = usb_mic_is_running();
|
|
}
|
|
if (aec_param->ref_sr == 0) {
|
|
if (TCFG_ESCO_DL_CVSD_SR_USE_16K && (sample_rate == 8000)) {
|
|
aec_param->ref_sr = 16000; //CVSD 下行为16K
|
|
} else {
|
|
aec_param->ref_sr = sample_rate;
|
|
}
|
|
}
|
|
if (ref_channel != 2) {
|
|
ref_channel = 1;
|
|
}
|
|
aec_param->ref_channel = ref_channel;
|
|
|
|
audio_aec_param_init(aec_param);
|
|
if (enablebit >= 0) {
|
|
aec_param->EnableBit = enablebit;
|
|
}
|
|
if (out_hdl) {
|
|
aec_param->output_handle = out_hdl;
|
|
}
|
|
|
|
aec_param->output_way = global_output_way;
|
|
|
|
if (aec_param->output_way == 0 && aec_param->adc_ref_en == 0) {
|
|
/*内部读取DAC数据做参考数据才需要做24bit转16bit*/
|
|
extern struct dac_platform_data dac_data;
|
|
aec_param->ref_bit_width = dac_data.bit_width;
|
|
} else {
|
|
aec_param->ref_bit_width = DATA_BIT_WIDE_16BIT;
|
|
}
|
|
|
|
#if (TCFG_SMART_VOICE_ENABLE && TCFG_SMART_VOICE_USE_AEC)
|
|
printf("esco_player_runing() : %d", esco_player_runing());
|
|
if (!esco_player_runing()) {
|
|
/* aec_param->ref_sr = TCFG_AUDIO_GLOBAL_SAMPLE_RATE; */
|
|
|
|
aec_param->output_way = 1;
|
|
aec_param->fm_tx_start = 1;
|
|
/*在语音识别做24bit转16bit*/
|
|
aec_param->ref_bit_width = DATA_BIT_WIDE_16BIT;
|
|
|
|
/*AGC*/
|
|
aec_param->agc_en = 0;
|
|
|
|
/*AEC*/
|
|
aec_param->EnableBit = AEC_EN;
|
|
aec_param->AEC_DT_AggressiveFactor = 4.f; /*范围:1~5,越大追踪越好,但会不稳定,如破音*/
|
|
aec_param->AEC_RefEngThr = -70.f;
|
|
}
|
|
#endif // TCFG_SMART_VOICE_USE_AEC
|
|
|
|
#if TCFG_AEC_SIMPLEX
|
|
aec_param->wn_en = 1;
|
|
aec_param->EnableBit = AEC_MODE_SIMPLEX;
|
|
if (sample_rate == 8000) {
|
|
aec_param->SimplexTail = aec_param->SimplexTail / 2;
|
|
}
|
|
#else
|
|
aec_param->wn_en = 0;
|
|
#endif/*TCFG_AEC_SIMPLEX*/
|
|
|
|
/*根据清晰语音处理模块配置,配置相应的系统时钟*/
|
|
if (sample_rate == 16000) {
|
|
/*宽带wide-band*/
|
|
aec_param->wideband = 1;
|
|
aec_param->hw_delay_offset = 60;
|
|
} else {
|
|
/*窄带narrow-band*/
|
|
aec_param->wideband = 0;
|
|
aec_param->hw_delay_offset = 55;
|
|
}
|
|
|
|
/* clk_set("sys", 0); */
|
|
|
|
if (audio_adc_file_get_mic_mode(0) == AUDIO_MIC_CAPLESS_MODE) {
|
|
aec_hdl->dcc_hdl = audio_dc_offset_remove_open(sample_rate, 1);
|
|
}
|
|
|
|
//aec_param_dump(aec_param);
|
|
aec_hdl->EnableBit = aec_param->EnableBit;
|
|
#if (((defined TCFG_KWS_VOICE_RECOGNITION_ENABLE) && TCFG_KWS_VOICE_RECOGNITION_ENABLE) || \
|
|
((defined TCFG_CALL_KWS_SWITCH_ENABLE) && TCFG_CALL_KWS_SWITCH_ENABLE))
|
|
extern u8 kws_get_state(void);
|
|
if (esco_player_runing()) {
|
|
if (kws_get_state()) {
|
|
aec_param->EnableBit = AEC_EN;
|
|
aec_param->agc_en = 0;
|
|
printf("kws open,aec_enablebit=%x", aec_param->EnableBit);
|
|
//临时关闭aec, 对比测试
|
|
//aec_param->toggle = 0;
|
|
}
|
|
}
|
|
#endif/*TCFG_KWS_VOICE_RECOGNITION_ENABLE*/
|
|
|
|
#if CVP_TOGGLE
|
|
if (aec_param->output_way && (aec_param->adc_ref_en || aec_param->ref_bit_width)) {
|
|
ASSERT(0, "output_way and adc_ref_en can not open at same time, or output_way nonsupport 24bit Width");
|
|
}
|
|
#if (TCFG_AUDIO_SMS_SEL == SMS_TDE)
|
|
if (CONST_SMS_TDE_STEREO_REF_ENABLE && aec_param->ref_channel != 2) {
|
|
ASSERT(0, "ref_channel need set 2 ch when CONST_SMS_TDE_STEREO_REF_ENABLE is 1");
|
|
}
|
|
#endif
|
|
int ret = aec_open(aec_param);
|
|
ASSERT(ret == 0, "aec_open err %d!!", ret);
|
|
#endif/*CVP_TOGGLE*/
|
|
aec_hdl->start = 1;
|
|
mem_stats();
|
|
printf("audio_aec_open succ\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Init
|
|
* Description: 初始化AEC模块
|
|
* Arguments : sample_rate 采样率(8000/16000)
|
|
* ref_sr 参考采样率
|
|
* Return : 0 成功 其他 失败
|
|
* Note(s) : None.
|
|
*********************************************************************
|
|
*/
|
|
int audio_aec_init(struct audio_aec_init_param_t *init_param)
|
|
{
|
|
return audio_aec_open(init_param, -1, NULL);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Reboot
|
|
* Description: AEC模块复位接口
|
|
* Arguments : reduce 复位/恢复标志
|
|
* Return : None.
|
|
* Note(s) : None.
|
|
*********************************************************************
|
|
*/
|
|
void audio_aec_reboot(u8 reduce)
|
|
{
|
|
if (aec_hdl) {
|
|
printf("audio_aec_reboot:%x,%x,start:%d", aec_hdl->EnableBit, aec_hdl->attr.EnableBit, aec_hdl->start);
|
|
if (aec_hdl->start) {
|
|
if (reduce) {
|
|
aec_hdl->attr.EnableBit = AEC_EN;
|
|
aec_hdl->attr.agc_en = 0;
|
|
} else {
|
|
if (aec_hdl->EnableBit != aec_hdl->attr.EnableBit) {
|
|
aec_hdl->attr.EnableBit = aec_hdl->EnableBit;
|
|
}
|
|
aec_hdl->attr.agc_en = 1;
|
|
}
|
|
#if (TCFG_AUDIO_SMS_SEL == SMS_TDE)
|
|
sms_tde_reboot(aec_hdl->attr.EnableBit);
|
|
#else
|
|
aec_reboot(aec_hdl->attr.EnableBit);
|
|
#endif
|
|
}
|
|
} else {
|
|
printf("audio_aec close now\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Close
|
|
* Description: 关闭AEC模块
|
|
* Arguments : None.
|
|
* Return : None.
|
|
* Note(s) : None.
|
|
*********************************************************************
|
|
*/
|
|
void audio_aec_close(void)
|
|
{
|
|
printf("audio_aec_close:%x", (u32)aec_hdl);
|
|
if (aec_hdl) {
|
|
aec_hdl->start = 0;
|
|
|
|
#if CVP_TOGGLE
|
|
aec_close();
|
|
#endif
|
|
|
|
#if TCFG_AUDIO_CVP_SYNC
|
|
//在AEC关闭之后再关,否则还会跑cvp_sync_run,导致越界
|
|
audio_cvp_sync_close();
|
|
#endif/*TCFG_AUDIO_CVP_SYNC*/
|
|
|
|
if (aec_hdl->dcc_hdl) {
|
|
audio_dc_offset_remove_close(aec_hdl->dcc_hdl);
|
|
aec_hdl->dcc_hdl = NULL;
|
|
}
|
|
|
|
local_irq_disable();
|
|
#if AEC_USER_MALLOC_ENABLE
|
|
free(aec_hdl);
|
|
#endif/*AEC_USER_MALLOC_ENABLE*/
|
|
aec_hdl = NULL;
|
|
local_irq_enable();
|
|
|
|
aec_code_movable_unload();
|
|
}
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Status
|
|
* Description: AEC模块当前状态
|
|
* Arguments : None.
|
|
* Return : 0 关闭 其他 打开
|
|
* Note(s) : None.
|
|
*********************************************************************
|
|
*/
|
|
u8 audio_aec_status(void)
|
|
{
|
|
if (aec_hdl) {
|
|
return aec_hdl->start;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Input
|
|
* Description: AEC源数据输入
|
|
* Arguments : buf 输入源数据地址
|
|
* len 输入源数据长度
|
|
* Return : None.
|
|
* Note(s) : 输入一帧数据,唤醒一次运行任务处理数据,默认帧长256点
|
|
*********************************************************************
|
|
*/
|
|
void audio_aec_inbuf(s16 *buf, u16 len)
|
|
{
|
|
if (aec_hdl && aec_hdl->start) {
|
|
if (aec_hdl->input_clear) {
|
|
memset(buf, 0, len);
|
|
}
|
|
#if CVP_TOGGLE
|
|
if (aec_hdl->inbuf_clear_cnt) {
|
|
aec_hdl->inbuf_clear_cnt--;
|
|
memset(buf, 0, len);
|
|
}
|
|
int ret = aec_in_data(buf, len);
|
|
if (ret == -1) {
|
|
} else if (ret == -2) {
|
|
log_error("aec inbuf full\n");
|
|
#if TCFG_SMART_VOICE_ENABLE && TCFG_SMART_VOICE_USE_AEC
|
|
audio_smart_voice_aec_cbuf_data_clear();
|
|
#endif
|
|
}
|
|
#else /*不经算法,直通到输出*/
|
|
aec_hdl->attr.output_handle(buf, len);
|
|
#endif/*CVP_TOGGLE*/
|
|
}
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Input Reference
|
|
* Description: AEC源参考数据输入
|
|
* Arguments : buf 输入源数据地址
|
|
* len 输入源数据长度
|
|
* Return : None.
|
|
* Note(s) : 双mic ENC的参考mic数据输入,单mic的无须调用该接口
|
|
*********************************************************************
|
|
*/
|
|
void audio_aec_inbuf_ref(s16 *buf, u16 len)
|
|
{
|
|
if (aec_hdl && aec_hdl->start) {
|
|
aec_in_data_ref(buf, len);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio AEC Reference
|
|
* Description: AEC模块参考数据输入
|
|
* Arguments : buf 输入参考数据地址
|
|
* len 输入参考数据长度
|
|
* Return : None.
|
|
* Note(s) : 声卡设备是DAC,默认不用外部提供参考数据
|
|
*********************************************************************
|
|
*/
|
|
void audio_aec_refbuf(s16 *data0, s16 *data1, u16 len)
|
|
{
|
|
if (aec_hdl && aec_hdl->start) {
|
|
#if CVP_TOGGLE
|
|
aec_ref_data(data0, data1, len);
|
|
#endif/*CVP_TOGGLE*/
|
|
}
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio CVP IOCTL
|
|
* Description: CVP功能配置
|
|
* Arguments : cmd 操作命令
|
|
* value 操作数
|
|
* priv 操作内存地址
|
|
* Return : 0 成功 其他 失败
|
|
* Note(s) : (1)比如动态开关降噪NS模块:
|
|
* audio_cvp_ioctl(CVP_NS_SWITCH,1,NULL); //降噪关
|
|
* audio_cvp_ioctl(CVP_NS_SWITCH,0,NULL); //降噪开
|
|
*********************************************************************
|
|
*/
|
|
int audio_cvp_ioctl(int cmd, int value, void *priv)
|
|
{
|
|
if (!aec_hdl) {
|
|
return -1;
|
|
}
|
|
#if (TCFG_AUDIO_SMS_SEL == SMS_TDE)
|
|
return sms_tde_ioctl(cmd, value, priv);
|
|
#else
|
|
return aec_ioctl(cmd, value, priv);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
*********************************************************************
|
|
* Audio CVP Toggle Set
|
|
* Description: CVP模块算法开关使能
|
|
* Arguments : toggle 0 关闭算法 1 打开算法
|
|
* Return : None.
|
|
* Note(s) : None.
|
|
*********************************************************************
|
|
*/
|
|
int audio_cvp_toggle_set(u8 toggle)
|
|
{
|
|
if (aec_hdl) {
|
|
#if (TCFG_AUDIO_SMS_SEL == SMS_TDE)
|
|
sms_tde_toggle(toggle);
|
|
#else
|
|
aec_toggle(toggle);
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*是否在重启*/
|
|
u8 get_audio_aec_rebooting()
|
|
{
|
|
if (aec_hdl && aec_hdl->start) {
|
|
#if (TCFG_AUDIO_SMS_SEL == SMS_TDE)
|
|
return get_sms_tde_rebooting();
|
|
#else
|
|
return get_aec_rebooting();
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*可写长度*/
|
|
int get_audio_cvp_output_way_writable_len()
|
|
{
|
|
if (aec_hdl && aec_hdl->start) {
|
|
#if (TCFG_AUDIO_SMS_SEL == SMS_TDE)
|
|
return get_cvp_sms_tde_output_way_writable_len();
|
|
#else
|
|
return get_cvp_sms_output_way_writable_len();
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 以下为用户层扩展接口
|
|
*/
|
|
//pbg profile use it,don't delete
|
|
void aec_input_clear_enable(u8 enable)
|
|
{
|
|
if (aec_hdl) {
|
|
aec_hdl->input_clear = enable;
|
|
log_info("aec_input_clear_enable= %d\n", enable);
|
|
}
|
|
}
|
|
|
|
int aec_get_input_clear_status(void)
|
|
{
|
|
if (aec_hdl) {
|
|
return aec_hdl->input_clear;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* void aec_estimate_dump(int DlyEst) */
|
|
/* { */
|
|
/* printf("DlyEst:%d\n", DlyEst); */
|
|
/* } */
|
|
|
|
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE == 0) && TCFG_AUDIO_TRIPLE_MIC_ENABLE == 0*/
|
|
#endif /*TCFG_CVP_DEVELOP_ENABLE*/
|
|
|
|
int audio_cvp_phase_align(void)
|
|
{
|
|
if (audio_aec_status() == 0) {
|
|
return 0;
|
|
}
|
|
#if defined(TCFG_CVP_DEVELOP_ENABLE) && (TCFG_CVP_DEVELOP_ENABLE)
|
|
return cvp_develop_read_ref_data();
|
|
#endif
|
|
|
|
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
|
|
/*3MIC*/
|
|
return cvp_tms_read_ref_data();
|
|
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
|
|
#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
|
|
/*TWS双麦*/
|
|
return cvp_dms_read_ref_data();
|
|
#elif (TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE)
|
|
/*话务耳机双麦*/
|
|
return cvp_dms_flexible_read_ref_data();
|
|
#elif (TCFG_AUDIO_DMS_SEL == DMS_HYBRID)
|
|
/*双麦hybrid*/
|
|
return cvp_dms_hybrid_read_ref_data();
|
|
#elif (TCFG_AUDIO_DMS_SEL == DMS_AWN)
|
|
/*双麦awn*/
|
|
return cvp_dms_awn_read_ref_data();
|
|
#endif
|
|
#else
|
|
/*单麦*/
|
|
#if (TCFG_AUDIO_SMS_SEL == SMS_TDE)
|
|
/*TDE*/
|
|
return cvp_sms_tde_read_ref_data();
|
|
#else
|
|
return cvp_sms_read_ref_data();
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
u16 get_cvp_node_uuid()
|
|
{
|
|
/* 设置源节点是哪个 */
|
|
u16 node_uuid = 0;
|
|
#if TCFG_AUDIO_CVP_DEVELOP_ENABLE
|
|
node_uuid = NODE_UUID_CVP_DEVELOP;
|
|
#elif TCFG_AUDIO_CVP_SMS_ANS_MODE
|
|
node_uuid = NODE_UUID_CVP_SMS_ANS;
|
|
#elif TCFG_AUDIO_CVP_SMS_DNS_MODE
|
|
node_uuid = NODE_UUID_CVP_SMS_DNS;
|
|
#elif TCFG_AUDIO_CVP_DMS_ANS_MODE
|
|
node_uuid = NODE_UUID_CVP_DMS_ANS;
|
|
#elif TCFG_AUDIO_CVP_DMS_DNS_MODE
|
|
node_uuid = NODE_UUID_CVP_DMS_DNS;
|
|
#elif TCFG_AUDIO_CVP_DMS_FLEXIBLE_ANS_MODE
|
|
node_uuid = NODE_UUID_CVP_DMS_FLEXIBLE_ANS;
|
|
#elif TCFG_AUDIO_CVP_DMS_FLEXIBLE_DNS_MODE
|
|
node_uuid = NODE_UUID_CVP_DMS_FLEXIBLE_DNS;
|
|
#elif TCFG_AUDIO_CVP_3MIC_MODE
|
|
node_uuid = NODE_UUID_CVP_3MIC;
|
|
#elif TCFG_AUDIO_CVP_DMS_HYBRID_DNS_MODE
|
|
node_uuid = NODE_UUID_CVP_DMS_HYBRID_DNS;
|
|
#elif TCFG_AUDIO_CVP_DMS_AWN_DNS_MODE
|
|
node_uuid = NODE_UUID_CVP_DMS_AWN_DNS;
|
|
#endif
|
|
return node_uuid;
|
|
}
|