Files
99_7018_lmx/apps/earphone/aec/br28/audio_aec.c
2025-10-29 13:10:02 +08:00

1357 lines
41 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
****************************************************************
* AUDIO SMS(SingleMic System)
* File : audio_aec_sms.c
* By :
* Notes : AEC回音消除 + 单mic降噪
*
****************************************************************
*/
#include "aec_user.h"
#include "system/includes.h"
#include "media/includes.h"
#include "application/eq_config.h"
#include "application/audio_drc.h"
#include "application/audio_pitch.h"
#include "circular_buf.h"
#include "overlay_code.h"
#include "audio_aec_online.h"
//#include "audio_aec_debug.c"
#include "audio_config.h"
#include "amplitude_statistic.h"
#include "audio_gain_process.h"
#if TCFG_AUDIO_CVP_SYNC
#include "audio_cvp_sync.h"
#endif/*TCFG_AUDIO_CVP_SYNC*/
#if TCFG_AUDIO_CVP_DUT_ENABLE
#include "audio_cvp_dut.h"
#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
int audio_cvp_code_load(void)
{
overlay_load_code(OVERLAY_AEC);
//printf("Audio_CVP_Code_Load succ\n");
return 0;
}
#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_AUDIO_DUAL_MIC_ENABLE == 0) && (TCFG_AUDIO_TRIPLE_MIC_ENABLE == 0)
#include "commproc.h"
#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"
#define AEC_USER_MALLOC_ENABLE 1
#define AEC_TOGGLE TCFG_AEC_ENABLE
#if TCFG_EQ_ENABLE
/*mic去直流滤波eq*/
#define AEC_DCCS_EN TCFG_AEC_DCCS_EQ_ENABLE
/*mic普通eq*/
#define AEC_UL_EQ_EN TCFG_AEC_UL_EQ_ENABLE
#else
#define AEC_DCCS_EN 0
#define AEC_UL_EQ_EN 0
#endif/*TCFG_EQ_ENABLE*/
#if TCFG_DRC_ENABLE
#define CVP_UL_DRC_EN TCFG_CVP_UL_DRC_ENABLE
#else
#define CVP_UL_DRC_EN 0
#endif/*TCFG_DRC_ENABLE*/
extern const int VC_KINDO_TVM;
/*省电容mic通过eq模块实现去直流滤波*/
#if TCFG_SUPPORT_MIC_CAPLESS
#if ((TCFG_EQ_ENABLE == 0) || (TCFG_AEC_DCCS_EQ_ENABLE == 0))
#error "MicCapless enable,Please enable TCFG_EQ_ENABLE and TCFG_AEC_DCCS_EQ_ENABLE"
#endif/*TCFG_EQ_ENABLE*/
#endif/*TCFG_SUPPORT_MIC_CAPLESS*/
extern struct adc_platform_data adc_data;
extern struct audio_dac_hdl dac_hdl;
#ifdef CONFIG_FPGA_ENABLE
const u8 CONST_AEC_ENABLE = 1;
#define FPGA_AEC_CLK (48 * 1000000L)
#else
const u8 CONST_AEC_ENABLE = 1;
#endif/*CONFIG_FPGA_ENABLE*/
#ifdef AUDIO_PCM_DEBUG
/*AEC串口数据导出*/
const u8 CONST_AEC_EXPORT = 1;
#else
const u8 CONST_AEC_EXPORT = 0;
#endif/*AUDIO_PCM_DEBUG*/
//*********************************************************************************//
// 预处理配置(Pre-process Config) //
//*********************************************************************************//
/*预增益配置*/
#define CVP_PRE_GAIN_ENABLE 0 //算法处理前预加数字增益放大
/*响度指示器*/
#define CVP_LOUDNESS_TRACE_ENABLE 0 //跟踪获取当前mic输入幅值
//*********************************************************************************//
// 调试配置(Debug Config) //
//*********************************************************************************//
/*使能即可跟踪通话过程的内存情况*/
#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**************************************//
/*参考数据变采样处理*/
#if TCFG_USB_MIC_CVP_ENABLE
const u8 CONST_REF_SRC = 1;
#else
const u8 CONST_REF_SRC = 0;
#endif /*TCFG_USB_MIC_CVP_ENABLE*/
/*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 2 /*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
__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; //前面如果有杂音,丢掉几包
u8 output_buf[1000]; //aec数据输出缓存
cbuffer_t output_cbuf;
#if AEC_UL_EQ_EN
struct audio_eq *ul_eq;
#endif/*AEC_UL_EQ_EN*/
#if AEC_DCCS_EN
struct audio_eq *dccs_eq;
#endif/*AEC_DCCS_EN*/
#if CVP_UL_DRC_EN
struct audio_drc *ul_drc;
#endif/*CVP_UL_DRC_EN*/
struct aec_s_attr attr;
#if AEC_PITCHSHIFTER_CONFIG
s_pitch_hdl *pitch ; //变声
u8 pitch_mode_L; //记录变声模式
u8 pitch_mode_R; //记录变声模式
#endif/* AEC_PITCHSHIFTER_CONFIG */
};
#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*/
extern int esco_adc_mic_en();
void audio_aec_ref_start(u8 en)
{
if (aec_hdl) {
if (en != aec_hdl->attr.fm_tx_start) {
if (esco_adc_mic_en() == 0) {
aec_hdl->attr.fm_tx_start = en;
y_printf("fm_tx_start:%d\n", en);
}
}
}
}
#if AEC_DCCS_EN
//一段高通滤波器 可调中心截止频率、带宽
// 默认 /*freq:100*/ /*quality:0.7f*/
const struct eq_seg_info dccs_eq_tab_8k[] = {
{0, EQ_IIR_TYPE_HIGH_PASS, 100, 0, 0.7f},
};
const struct eq_seg_info dccs_eq_tab_16k[] = {
{0, EQ_IIR_TYPE_HIGH_PASS, 100, 0, 0.7f},
};
static float dccs_tab[5];
int aec_dccs_eq_filter(void *eq, int sr, struct audio_eq_filter_info *info)
{
if (!sr) {
sr = 16000;
}
u8 nsection = ARRAY_SIZE(dccs_eq_tab_8k);
local_irq_disable();
if (sr == 16000) {
for (int i = 0; i < nsection; i++) {
eq_seg_design((struct eq_seg_info *)&dccs_eq_tab_16k[i], sr, &dccs_tab[5 * i]);
}
} else {
for (int i = 0; i < nsection; i++) {
eq_seg_design((struct eq_seg_info *)&dccs_eq_tab_8k[i], sr, &dccs_tab[5 * i]);
}
}
local_irq_enable();
info->L_coeff = (float *)dccs_tab;
info->R_coeff = (float *)dccs_tab;
info->L_gain = 0;
info->R_gain = 0;
info->nsection = nsection;
return 0;
}
#endif/*AEC_DCCS_EN*/
#if CVP_UL_DRC_EN
static float Gain_dB = 0;
int cvp_ul_drc_filter(struct audio_drc *drc, struct audio_drc_filter_info *info)
{
static struct drc_ch wdrc_p = {0};
struct threshold_group threshold[3] = {{0, 0}, {75.f, 75.f}, {140.f, 75.f}}; //这里减去90才是具体的db数
/*倍数对应放大的dB数
* 20lg(2) = 6dB
* 20lg(3) = 9.5dB
* 20lg(4) = 12dB
* 20lg(5) = 14dB
* 20lg(6) = 15.5dB
* 20lg(7) = 17dB
* 20lg(8) = 18dB
* 20lg(9) = 19dB
* 20lg(10) = 20dB*/
Gain_dB = 4.0f; /*drc压制后要放大的倍数*/
wdrc_p.nband = 1;
wdrc_p.type = 3;//wdrc
//left
int i = 0;
wdrc_p._p.wdrc[i][0].attacktime = 1;
wdrc_p._p.wdrc[i][0].releasetime = 200;
memcpy(wdrc_p._p.wdrc[i][0].threshold, threshold, sizeof(threshold));
wdrc_p._p.wdrc[i][0].threshold_num = ARRAY_SIZE(threshold);
wdrc_p._p.wdrc[i][0].rms_time = 25;
wdrc_p._p.wdrc[i][0].algorithm = 0;
wdrc_p._p.wdrc[i][0].mode = 1;
//right
wdrc_p._p.wdrc[i][1].attacktime = 1;
wdrc_p._p.wdrc[i][1].releasetime = 200;
memcpy(wdrc_p._p.wdrc[i][1].threshold, threshold, sizeof(threshold));
wdrc_p._p.wdrc[i][1].threshold_num = ARRAY_SIZE(threshold);
wdrc_p._p.wdrc[i][1].rms_time = 25;
wdrc_p._p.wdrc[i][1].algorithm = wdrc_p._p.wdrc[i][0].algorithm;
wdrc_p._p.wdrc[i][1].mode = wdrc_p._p.wdrc[i][0].mode;
info->R_pch = info->pch = &wdrc_p;
return 0;
}
#endif/*CVP_UL_DRC_EN*/
/*
*********************************************************************
* Audio AEC Process_Probe
* Description: AEC模块数据前处理回调(预处理)
* Arguments : talk_mic 主麦数据地址
* talk_ref_mic 单麦没有用到为NULL
* fb_mic 单麦没有用到为NULL
* ref 参考数据地址
* len 数据长度(Unit:byte)
* Return : 0 成功 其他 失败
* Note(s) : 在源数据经过CVP模块前可以增加自定义处理
*********************************************************************
*/
static LOUDNESS_M_STRUCT mic_loudness;
static int audio_aec_probe(short *talk_mic, short *talk_ref_mic, short *fb_mic, short *ref, u16 len)
{
#if CVP_PRE_GAIN_ENABLE
GainProcess_16Bit(talk_mic, talk_mic, 12.f, 1, 1, 1, len >> 1);
#endif/*CVP_PRE_GAIN_ENABLE*/
#if CVP_LOUDNESS_TRACE_ENABLE
loudness_meter_short(&mic_loudness, talk_mic, len >> 1);
#endif/*CVP_LOUDNESS_TRACE_ENABLE*/
#if AEC_DCCS_EN
if (aec_hdl->dccs_eq) {
audio_eq_run(aec_hdl->dccs_eq, talk_mic, len);
}
#endif/*AEC_DCCS_EN*/
return 0;
}
/*
*********************************************************************
* Audio AEC Process_Post
* Description: AEC模块数据后处理回调
* Arguments : data 数据地址
* len 数据长度
* Return : 0 成功 其他 失败
* Note(s) : 在数据处理完毕,可以增加自定义后处理
*********************************************************************
*/
static int audio_aec_post(s16 *data, u16 len)
{
#if AEC_UL_EQ_EN
if (aec_hdl->ul_eq) {
audio_eq_run(aec_hdl->ul_eq, data, len);
}
#endif/*AEC_UL_EQ_EN*/
#if CVP_UL_DRC_EN
if (aec_hdl->ul_drc) {
audio_drc_run(aec_hdl->ul_drc, data, len);
GainProcess_16Bit(data, data, Gain_dB, 1, 1, 1, len >> 1);
}
#endif/*CVP_UL_DRC_EN*/
#if AEC_PITCHSHIFTER_CONFIG
if (aec_hdl && aec_hdl->pitch) {
pitch_run(aec_hdl->pitch, data, data, len, 1);
}
#endif/* AEC_PITCHSHIFTER_CONFIG */
return 0;
}
int audio_aec_update(u8 EnableBit)
{
#if (TCFG_KWS_VOICE_RECOGNITION_ENABLE == 1)
extern u8 kws_is_running(void);
if (kws_is_running()) { /*当是KWS调用的使用默认参数的EnableBit恢复clk*/
EnableBit = aec_hdl->attr.EnableBit;
}
#endif /*TCFG_KWS_VOICE_RECOGNITION_ENABLE*/
printf("aec_update,wideband:%d,EnableBit:%x", aec_hdl->attr.wideband, EnableBit);
if (CONST_ANS_VERSION == ANS_V200) {
clk_set("sys", CONFIG_BT_CALL_DNS_HZ);
return 0;
}
if (aec_hdl->attr.wideband) {
if ((EnableBit & 0x7) == AEC_MODE_ADVANCE) {
clk_set("sys", BT_CALL_16k_ADVANCE_HZ);
} else {
clk_set("sys", BT_CALL_16k_HZ);
}
} else {
if ((EnableBit & 0x7) == AEC_MODE_ADVANCE) {
clk_set("sys", BT_CALL_ADVANCE_HZ);
} else {
clk_set("sys", BT_CALL_HZ);
}
}
return 0;
}
/*跟踪系统内存使用情况:physics memory size xxxx bytes*/
static void sys_memory_trace(void)
{
static int cnt = 0;
if (cnt++ > 200) {
cnt = 0;
mem_stats();
}
}
extern void esco_enc_resume(void);
#if TCFG_AUDIO_CVP_SYNC
int audio_aec_sync_buffer_set(s16 *data, int len)
{
u16 wlen = cbuf_write(&aec_hdl->output_cbuf, data, len);
/* printf("wlen:%d-%d\n",len,aec_hdl->output_cbuf.data_len); */
esco_enc_resume();
return wlen;
}
#endif/*TCFG_AUDIO_CVP_SYNC*/
/*
*********************************************************************
* Audio AEC Output Handle
* Description: AEC模块数据输出回调
* Arguments : data 输出数据地址
* len 输出数据长度
* Return : 数据输出消耗长度
* Note(s) : None.
*********************************************************************
*/
static int audio_aec_output(s16 *data, u16 len)
{
#if ((defined TCFG_KWS_VOICE_RECOGNITION_ENABLE) && TCFG_KWS_VOICE_RECOGNITION_ENABLE)
//Voice Recognition get mic data here
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*/
u16 wlen = cbuf_write(&aec_hdl->output_cbuf, data, len);
//printf("wlen:%d-%d\n",len,aec_hdl.output_cbuf.data_len);
esco_enc_resume();
#if 1
static u32 aec_output_max = 0;
if (aec_output_max < aec_hdl->output_cbuf.data_len) {
aec_output_max = aec_hdl->output_cbuf.data_len;
y_printf("o_max:%d", aec_output_max);
}
#endif
if (wlen != len) {
putchar('f');
}
return wlen;
}
/*
*********************************************************************
* Audio AEC Output Read
* Description: 读取aec模块的输出数据
* Arguments : buf 读取数据存放地址
* len 读取数据长度
* Return : 数据读取长度
* Note(s) : None.
*********************************************************************
*/
int audio_aec_output_read(s16 *buf, u16 len)
{
//printf("rlen:%d-%d\n",len,aec_hdl.output_cbuf.data_len);
local_irq_disable();
if (!aec_hdl || !aec_hdl->start) {
printf("audio_aec close now");
local_irq_enable();
return -EINVAL;
}
u16 rlen = cbuf_read(&aec_hdl->output_cbuf, buf, len);
if (rlen == 0) {
//putchar('N');
}
local_irq_enable();
return rlen;
}
static const char *CVP_ModuleName[] = {
"AEC", "NLP", "ANS", "ENC", "AGC"
};
static const char *CVP_ModuleStatus[] = {
"Disable", "Enable"
};
static void dumpModulaStatus(int EnableBit)
{
printf("EnableBitDebug = 0x%x\n", EnableBit);
for (int i = 0; i < 5; i++) {
int k = 1 << i;
printf("%s : %s\n", CVP_ModuleName[i], CVP_ModuleStatus[((EnableBit & k) != 0)]);
}
}
/*
*********************************************************************
* 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;
#if TCFG_AEC_TOOL_ONLINE_ENABLE
ret = aec_cfg_online_update_fill(&cfg, sizeof(AEC_CONFIG));
#endif/*TCFG_AEC_TOOL_ONLINE_ENABLE*/
if (ret == 0) {
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
ret = syscfg_read(CFG_AEC_ID, &cfg, sizeof(AEC_CONFIG));
#else
ret = syscfg_read(CFG_SMS_DNS_ID, &cfg, sizeof(AEC_CONFIG));
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
}
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;
// dumpModulaStatus(cfg.aec_mode);
p->EnableBit = (cfg.aec_mode & AEC_MODE_ADVANCE);
if (p->EnableBit == 0) {
p->toggle = 0;
printf("cvp toggle off\n");
} else {
p->toggle = 1;
}
#if (CVP_UL_DRC_EN == 1)/*开通话上行DRC时不开AGC*/
p->agc_en = 0;
#else
p->agc_en = (cfg.aec_mode & AGC_EN) ? 1 : 0;
#endif/*CVP_UL_DRC_EN*/
p->ul_eq_en = cfg.ul_eq_en;
printf("aec_mode:%x,agc_en:%d,ul_eq_en:%d\n", cfg.aec_mode, p->agc_en, p->ul_eq_en);
//aec_param_dump(p);
} 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;
/*AGC*/
#if (CVP_UL_DRC_EN == 1)/*开通话上行DRC时不开AGC*/
p->agc_en = 0;
#else
p->agc_en = 1;
#endif/*CVP_UL_DRC_EN*/
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_mode = 1;
p->ANS_NoiseLevel = 2.2e3f;
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;
}
#define CLEAR_FRAME 5 // 用来丢掉前几帧数据
/*
*********************************************************************
* Audio AEC Open
* Description: 初始化AEC模块
* Arguments : sr 采样率(8000/16000)
* enablebit 使能模块(AEC/NLP/AGC/ANS...)
* out_hdl 自定义回调函数NULL则用默认的回调
* Return : 0 成功 其他 失败
* Note(s) : 该接口是对audio_aec_init的扩展支持自定义使能模块以及
* 数据输出回调函数
*********************************************************************
*/
int audio_aec_open(u16 sample_rate, s16 enablebit, int (*out_hdl)(s16 *data, u16 len))
{
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*/
#if CVP_LOUDNESS_TRACE_ENABLE
loudness_meter_init(&mic_loudness, sample_rate, 50, 0);
#endif/*CVP_LOUDNESS_TRACE_ENABLE*/
cbuf_init(&aec_hdl->output_cbuf, aec_hdl->output_buf, sizeof(aec_hdl->output_buf));
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;
aec_param->ref_sr = usb_mic_is_running();
if (aec_param->ref_sr == 0) {
aec_param->ref_sr = sample_rate;
}
aec_input_clear_enable(CLEAR_FRAME);
audio_aec_param_init(aec_param);
if (enablebit >= 0) {
aec_param->EnableBit = enablebit;
}
if (out_hdl) {
aec_param->output_handle = out_hdl;
}
#if TCFG_AUDIO_OUTPUT_IIS
aec_param->output_way = 1;
#endif
#if TCFG_AEC_SIMPLEX
aec_param->wn_en = 1;
aec_param.EnableBit = AEC_MODE_SIMPLEX;
if (sr == 8000) {
aec_param.SimplexTail = aec_param.SimplexTail / 2;
}
#else
aec_param->wn_en = 0;
#endif/*TCFG_AEC_SIMPLEX*/
/*根据清晰语音处理模块配置,配置相应的系统时钟*/
int aec_clock = BT_CALL_16k_HZ;
if (sample_rate == 16000) {
/*宽带wide-band*/
aec_param->wideband = 1;
aec_param->hw_delay_offset = 60;
if (aec_param->EnableBit == AEC_MODE_ADVANCE) {
aec_clock = BT_CALL_16k_ADVANCE_HZ;
} else {
aec_clock = BT_CALL_16k_HZ;
}
} else {
/*窄带narrow-band*/
aec_param->wideband = 0;
aec_param->hw_delay_offset = 55;
if (aec_param->EnableBit == AEC_MODE_ADVANCE) {
aec_clock = BT_CALL_ADVANCE_HZ;
} else {
aec_clock = BT_CALL_HZ;
}
}
if (CONST_ANS_VERSION == ANS_V200) {
aec_clock = CONFIG_BT_CALL_DNS_HZ;
}
#ifdef CONFIG_FPGA_ENABLE
aec_clock = FPGA_AEC_CLK;
#endif/*CONFIG_FPGA_ENABLE*/
clk_set("sys", aec_clock);
#if AEC_UL_EQ_EN
if (aec_param->ul_eq_en) {
struct audio_eq_param ul_eq_param = {0};
ul_eq_param.sr = sample_rate;
ul_eq_param.channels = 1;
ul_eq_param.online_en = 1;
ul_eq_param.mode_en = 0;
ul_eq_param.remain_en = 0;
ul_eq_param.max_nsection = EQ_SECTION_MAX;
ul_eq_param.cb = aec_ul_eq_filter;
ul_eq_param.eq_name = aec_eq_mode;
aec_hdl->ul_eq = audio_dec_eq_open(&ul_eq_param);
}
#endif/*AEC_UL_EQ_EN*/
#if AEC_DCCS_EN
if (adc_data.mic_mode == AUDIO_MIC_CAPLESS_MODE) {
struct audio_eq_param dccs_eq_param = {0};
dccs_eq_param.sr = sample_rate;
dccs_eq_param.channels = 1;
dccs_eq_param.online_en = 0;
dccs_eq_param.mode_en = 0;
dccs_eq_param.remain_en = 0;
dccs_eq_param.max_nsection = EQ_SECTION_MAX;
dccs_eq_param.cb = aec_dccs_eq_filter;
aec_hdl->dccs_eq = audio_dec_eq_open(&dccs_eq_param);
}
#endif/*AEC_DCCS_EN*/
#if CVP_UL_DRC_EN
printf("audio cvp ul drc open start\n");
struct audio_drc_param ul_drc_param = {0};
ul_drc_param.channels = 1;
ul_drc_param.sr = sample_rate;
ul_drc_param.out_32bit = 0;
/* ul_drc_param.online_en = 0; */
/* ul_drc_param.remain_en = 0; */
/* ul_drc_param.stero_div = 0; */
ul_drc_param.cb = cvp_ul_drc_filter;
ul_drc_param.drc_name = 0;
u8 index = 0;
if (sample_rate == 8000) { //窄频
index = 1;
}
/* ul_drc_param.wdrc = &phone_mode[index].drc_parm; */
aec_hdl->ul_drc = audio_dec_drc_open(&ul_drc_param);
if (aec_hdl->ul_drc) {
printf("audio cvp ul drc open succ %x\n", aec_hdl->ul_drc);
} else {
printf("audio cvp ul drc open fail \n");
}
#endif/*CVP_UL_DRC_EN*/
#if AEC_PITCHSHIFTER_CONFIG
PITCH_SHIFT_PARM sparm = {0};
sparm.sr = sample_rate;
sparm.shiftv = 100;
sparm.effect_v = EFFECT_PITCH_SHIFT;
sparm.formant_shift = 100;
aec_hdl->pitch = open_pitch(&sparm);
pause_pitch(aec_hdl->pitch, 1);
aec_hdl->pitch_mode_L = 0;
aec_hdl->pitch_mode_R = 0;
#endif/* AEC_PITCHSHIFTER_CONFIG */
//aec_param_dump(aec_param);
aec_hdl->EnableBit = aec_param->EnableBit;
#if ((defined TCFG_KWS_VOICE_RECOGNITION_ENABLE) && TCFG_KWS_VOICE_RECOGNITION_ENABLE)
extern u8 kws_get_state(void);
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 AEC_TOGGLE
int ret = aec_open(aec_param);
ASSERT(ret != -EPERM, "Chip not support aec mode!!");
#endif/*AEC_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)
* Return : 0 成功 其他 失败
* Note(s) : None.
*********************************************************************
*/
int audio_aec_init(u16 sample_rate)
{
return audio_aec_open(sample_rate, -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;
aec_reboot(aec_hdl->attr.EnableBit);
} else {
if (aec_hdl->EnableBit != aec_hdl->attr.EnableBit) {
aec_hdl->attr.agc_en = 1;
aec_reboot(aec_hdl->EnableBit);
}
}
}
} else {
printf("audio_aec close now\n");
}
}
#if TCFG_SIDETONE_ENABLE
static s16 mic0_data[3][256];
static int mic0_data_offset = 0;
static int mic0_data_bulk = 0;
static s16 mic1_data[3][256];
static int mic1_data_offset = 0;
static int mic1_data_bulk = 0;
#endif/*TCFG_SIDETONE_ENABLE*/
/*
*********************************************************************
* 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 AEC_TOGGLE
aec_close();
#endif
#if TCFG_AUDIO_CVP_SYNC
//在AEC关闭之后再关否则还会跑CVP_SYNC_RUN,导致越界
audio_cvp_sync_close();
#endif/*TCFG_AUDIO_CVP_SYNC*/
#if AEC_DCCS_EN
if (aec_hdl->dccs_eq) {
audio_dec_eq_close(aec_hdl->dccs_eq);
aec_hdl->dccs_eq = NULL;
}
#endif/*AEC_DCCS_EN*/
#if AEC_UL_EQ_EN
if (aec_hdl->ul_eq) {
audio_dec_eq_close(aec_hdl->ul_eq);
aec_hdl->ul_eq = NULL;
}
#endif/*AEC_UL_EQ_EN*/
#if CVP_UL_DRC_EN
if (aec_hdl->ul_drc) {
audio_dec_drc_close(aec_hdl->ul_drc);
aec_hdl->ul_drc = NULL;
}
#endif/*CVP_UL_DRC_EN*/
#if AEC_PITCHSHIFTER_CONFIG
if (aec_hdl && aec_hdl->pitch) {
close_pitch(aec_hdl->pitch);
aec_hdl->pitch = NULL;
}
#endif/* AEC_PITCHSHIFTER_CONFIG */
local_irq_disable();
#if AEC_USER_MALLOC_ENABLE
free(aec_hdl);
#endif/*AEC_USER_MALLOC_ENABLE*/
aec_hdl = NULL;
local_irq_enable();
#if TCFG_SIDETONE_ENABLE
mic0_data_offset = 0;
mic0_data_bulk = 0;
mic1_data_offset = 0;
mic1_data_bulk = 0;
#endif/*TCFG_SIDETONE_ENABLE*/
}
}
/*
*********************************************************************
* 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)
{
u16 data_len = len;
if (aec_hdl && aec_hdl->start) {
if (aec_hdl->input_clear) {
aec_hdl->input_clear--;
memset(buf, 0, len);
}
#if TCFG_AUDIO_CVP_DUT_ENABLE
if (cvp_dut_mode_get() == CVP_DUT_MODE_BYPASS) {
audio_aec_output(buf, len);
return;
}
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
#if TCFG_SIDETONE_ENABLE
if (mic0_data_bulk > 2) {
mic0_data_bulk = 0;
}
if (mic0_data_offset > (512 - len)) {
mic0_data_offset = 0;
}
memcpy((((u32)&mic0_data[mic0_data_bulk][0]) + mic0_data_offset), buf, len);
data_len = 512;
buf = (s16 *)(&mic0_data[mic0_data_bulk]);
mic0_data_offset += len;
if (mic0_data_offset <= (512 - len)) {
return;
}
mic0_data_bulk++;
#endif/*TCFG_SIDETONE_ENABLE*/
#if AEC_TOGGLE
if (aec_hdl->inbuf_clear_cnt) {
aec_hdl->inbuf_clear_cnt--;
memset(buf, 0, data_len);
}
int ret = aec_in_data(buf, data_len);
if (ret == -1) {
} else if (ret == -2) {
log_error("aec inbuf full\n");
printf("clk : %d\n", clk_get("sys"));
}
#else /*不经算法,直通到输出*/
audio_aec_output(buf, data_len);
#endif/*AEC_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)
{
u16 data_len = len;
#if TCFG_SIDETONE_ENABLE
if (mic1_data_bulk > 2) {
mic1_data_bulk = 0;
}
if (mic1_data_offset > (512 - len)) {
mic1_data_offset = 0;
}
memcpy((((u32)&mic1_data[mic1_data_bulk][0]) + mic1_data_offset), buf, len);
data_len = 512;
buf = (s16 *)(&mic1_data[mic1_data_bulk]);
mic1_data_offset += len;
if (mic1_data_offset <= (512 - len)) {
return;
}
mic1_data_bulk++;
#endif/*TCFG_SIDETONE_ENABLE*/
if (aec_hdl && aec_hdl->start) {
aec_in_data_ref(buf, data_len);
}
}
/*
*********************************************************************
* Audio AEC Reference
* Description: AEC模块参考数据输入
* Arguments : buf 输入参考数据地址
* len 输入参考数据长度
* Return : None.
* Note(s) : 声卡设备是DAC默认不用外部提供参考数据
*********************************************************************
*/
void audio_aec_refbuf(s16 *buf, u16 len)
{
if (aec_hdl && aec_hdl->start) {
#if AEC_TOGGLE
aec_ref_data(buf, len);
#endif/*AEC_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 && aec_hdl->start) {
return aec_ioctl(cmd, value, priv);
} else {
return -1;
}
}
/*
*********************************************************************
* Audio AEC Toggle Set
* Description: AEC模块算法开关使能
* Arguments : toggle 0 关闭算法 1 打开算法
* Return : None.
* Note(s) : None.
*********************************************************************
*/
int audio_aec_toggle_set(u8 toggle)
{
if (aec_hdl) {
aec_toggle(toggle);
return 0;
}
return 1;
}
/**
* 以下为用户层扩展接口
*/
//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);
}
}
#if AEC_PITCHSHIFTER_CONFIG
/*----------------------------------------------------------------------------*/
/**@brief 变声参数直接更新
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void set_pitch_para(u32 shiftv, u32 sr, u8 effect, u32 formant_shift)
{
if (aec_hdl && aec_hdl->pitch) {
PITCH_SHIFT_PARM parm = {0};
parm.sr = sr;
parm.shiftv = shiftv;
parm.effect_v = effect;
parm.formant_shift = formant_shift;
//printf("\n\n\nshiftv[%d],sr[%d],effect[%d],formant_shift[%d] \n\n", parm.shiftv, parm.sr, parm.effect_v, parm.formant_shift);
update_picth_parm(aec_hdl->pitch, &parm);
}
}
/*----------------------------------------------------------------------------*/
/**@brief 变声效果设置
@param sound:原声SOUND_ORIGINAL,男声SOUND_UNCLE, 女声SOUND_GODDESS
@return
@note
*/
/*----------------------------------------------------------------------------*/
void audio_aec_pitch_change(u32 sound)
{
if (aec_hdl && aec_hdl->pitch) {
switch (sound) {
case SOUND_ORIGINAL:
pause_pitch(aec_hdl->pitch, 1);
log_info("pitch origin\n");
break;
case SOUND_UNCLE:
set_pitch_para(136, aec_hdl->pitch->parm.sr, EFFECT_PITCH_SHIFT, 0);
pause_pitch(aec_hdl->pitch, 0);
log_info("pitch uncle\n");
break;
case SOUND_GODDESS:
if (VC_KINDO_TVM) {
set_pitch_para(56, aec_hdl->pitch->parm.sr, EFFECT_VOICECHANGE_KIN0, 150);
} else {
set_pitch_para(46, aec_hdl->pitch->parm.sr, EFFECT_VOICECHANGE_KIN2, 80);
}
/* set_pitch_para(66, aec_hdl->pitch->parm.sr, EFFECT_VOICECHANGE_KIN0, 150); */
pause_pitch(aec_hdl->pitch, 0);
log_info("pitch goddess\n");
break;
default:
break;
}
}
}
struct _esco_eff {
u16 eff_L;
u16 eff_R;
};
struct _esco_eff esco_eff;
#define TWS_FUNC_ID_ESCO_EFF \
((int)(('E' + 'S' + 'C' + 'O') << (2 * 8)) | \
(int)(('E' + 'F' + 'F') << (1 * 8)) | \
(int)(('S' + 'Y' + 'N' + 'C') << (0 * 8)))
/*----------------------------------------------------------------------------*/
/**@brief 变声控制
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void audio_aec_pitch_change_ctrl()
{
if (!aec_hdl) {
return;
}
#if TCFG_USER_TWS_ENABLE
int state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {// tws链接时左耳触发男声 右耳触发女声
enum audio_channel channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
if (channel == AUDIO_CH_L) {
log_info("aec_hdl->pitch_mode_L %d\n", aec_hdl->pitch_mode_L);
if (aec_hdl->pitch_mode_L != SOUND_UNCLE) {
aec_hdl->pitch_mode_L = SOUND_UNCLE;
aec_hdl->pitch_mode_R = SOUND_UNCLE;
} else {
aec_hdl->pitch_mode_L = SOUND_ORIGINAL;
aec_hdl->pitch_mode_R = SOUND_ORIGINAL;
}
} else if (channel == AUDIO_CH_R) {
log_info("aec_hdl->pitch_mode_R %d\n", aec_hdl->pitch_mode_R);
if (aec_hdl->pitch_mode_R != SOUND_GODDESS) {
aec_hdl->pitch_mode_R = SOUND_GODDESS;
aec_hdl->pitch_mode_L = SOUND_GODDESS;
} else {
aec_hdl->pitch_mode_R = SOUND_ORIGINAL;
aec_hdl->pitch_mode_L = SOUND_ORIGINAL;
}
}
esco_eff.eff_L = aec_hdl->pitch_mode_L;
esco_eff.eff_R = aec_hdl->pitch_mode_R;
tws_api_send_data_to_sibling((u8 *)&esco_eff, sizeof(struct _esco_eff), TWS_FUNC_ID_ESCO_EFF);//发送左右耳的变声模式
} else
#endif/*TCFG_USER_TWS_ENABLE*/
{
//tws未连接时变声直接切换男声->女声->原声
if (aec_hdl->pitch_mode_L != SOUND_UNCLE) {
aec_hdl->pitch_mode_L = SOUND_UNCLE;
} else if (aec_hdl->pitch_mode_L == SOUND_UNCLE) {
aec_hdl->pitch_mode_L = SOUND_GODDESS;
} else {
aec_hdl->pitch_mode_L = SOUND_ORIGINAL;
}
audio_aec_pitch_change(aec_hdl->pitch_mode_L);
}
}
#if TCFG_USER_TWS_ENABLE
static void tws_esco_pitch_align(void *data, u16 len, bool rx)
{
memcpy(&esco_eff, data, sizeof(struct _esco_eff));
int state = tws_api_get_tws_state();
enum audio_channel channel;
if (state & TWS_STA_SIBLING_CONNECTED) {
channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
if (channel == AUDIO_CH_L) {//左耳设置变声
log_info("channel %d============= eff_L %d\n", channel, esco_eff.eff_L);
audio_aec_pitch_change(esco_eff.eff_L);
if (aec_hdl) {
aec_hdl->pitch_mode_L = esco_eff.eff_L;
}
} else {//右耳设置变声
log_info("channel %d============= eff_R %d\n", channel, esco_eff.eff_R);
audio_aec_pitch_change(esco_eff.eff_R);
if (aec_hdl) {
aec_hdl->pitch_mode_R = esco_eff.eff_R;
}
}
}
}
REGISTER_TWS_FUNC_STUB(esco_align_eff) = {
.func_id = TWS_FUNC_ID_ESCO_EFF,
.func = tws_esco_pitch_align,
};
#endif/*TCFG_USER_TWS_ENABLE*/
#endif/* AEC_PITCHSHIFTER_CONFIG */
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE == 0*/
#endif /*TCFG_CVP_DEVELOP_ENABLE*/