KT24-1110_65E-HA-651B/apps/soundbox/aec/br25/audio_aec.c

781 lines
23 KiB
C
Raw Permalink Normal View History

2024-11-10 10:44:17 +00:00
/*
*********************************************************************
* Audio AEC APIs
* Description:AEC用户调用接口
* Note(s) :ANS等级和AEC滤波器长度可根据实际需要进行配置
* (1)CONST_ANS_MODE:ANS降噪等级配置
* (2)AEC_TAIL_LENGTH:AEC滤波器长度配置
*********************************************************************
*/
#include "system/includes.h"
#include "app_config.h"
#include "audio_config.h"
#include "aec_user.h"
#include "media/includes.h"
#include "media/audio_eq_drc_apply.h"
#include "circular_buf.h"
#include "clock_cfg.h"
#include "media/effects_adj.h"
#include "audio_effect/audio_eff_default_parm.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
/*AEC_TOGGLE:AEC模块使能开关Disable则数据完全不经过处理AEC模块不占用资源*/
#if (TCFG_AEC_ENABLE)
#define AEC_TOGGLE 1
#else
#define AEC_TOGGLE 0
#endif/*TCFG_AEC_ENABLE*/
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DONGLE)
#undef AEC_TOGGLE
#define AEC_TOGGLE 0
#endif/*AUDIO_OUTPUT_WAY_DONGLE*/
#if (TCFG_EQ_ENABLE == 1)
#define AEC_DCCS_EN TCFG_AEC_DCCS_EQ_ENABLE /*mic去直流滤波eq*/
#define AEC_UL_EQ_EN TCFG_AEC_UL_EQ_ENABLE /*mic 普通eq*/
#else
#define AEC_DCCS_EN 0
#define AEC_UL_EQ_EN 0
#endif/*TCFG_EQ_ENABLE*/
/*使能即可跟踪通话过程的内存情况*/
#define CVP_MEM_TRACE_ENABLE 0
#ifdef CONFIG_FPGA_ENABLE
const u8 CONST_AEC_ENABLE = 0;
#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*/
/*
*ANS等级:0~2,
*106k左右的ram
*213k左右的ram
*/
const u8 CONST_ANS_MODE = 1;
/*参考数据变采样处理*/
#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*/
/*
*AEC复杂等级ram和mips越大
*/
*使:4
*使:2
*/
#define AEC_TAIL_LENGTH 4 /*range:2~10,default:4*/
/*
*使
*/
*
*/
#if ((AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM) || TCFG_AEC_SIMPLEX)
const u8 CONST_AEC_DLY_EST = 1;
#else
const u8 CONST_AEC_DLY_EST = 0;
#endif
//////////////////Simplex Parameters(单工调试参数)/////////////////////
#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*/
//////////////////////////= EDN =//////////////////////////////////////
//////////////////AEC Parameters(通话回声调试参数)/////////////////////
/*aec mode select:AEC_MODE_REDUCE or AEC_MODE_ADVANCE */
#define AEC_MODULE_BIT AEC_MODE_ADVANCE
//////////////////////////= EDN =//////////////////////////////////////
/*数据输出开头丢掉的数据包数*/
#define AEC_OUT_DUMP_PACKET 10
/**数据输出开头丢掉的数据包数*/
#define AEC_IN_DUMP_PACKET 1
extern struct adc_platform_data adc_data;
/*复用lmp rx buf(一般通话的时候复用)
*rx_buf概率产生碎片alloc失败0
*/
#define MALLOC_MULTIPLEX_EN 0
extern void *lmp_malloc(int);
extern void lmp_free(void *);
extern u32 usb_mic_is_running();
void *zalloc_mux(int size)
{
#if MALLOC_MULTIPLEX_EN
void *p = NULL;
void bredr_rx_bulk_state();
bredr_rx_bulk_state();
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);
}
y_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
y_printf("[free_mux]p = 0x%x\n", p);
lmp_free(p);
#else
free(p);
#endif
}
void aec_param_dump(struct aec_s_attr *param)
{
log_info("===========dump aec param==================\n");
log_info("toggle:%d\n", param->toggle);
log_info("EnableBit:%x\n", param->EnableBit);
log_info("ul_eq_en:%x\n", param->ul_eq_en);
log_info("agc_en:%x\n", param->agc_en);
//log_info("AGC_fade:%d\n", (int)(param->AGC_gain_step * 100));
log_info("AGC_NDT_max_gain:%d\n", (int)(param->AGC_NDT_max_gain * 100));
log_info("AGC_NDT_min_gain:%d\n", (int)(param->AGC_NDT_min_gain * 100));
log_info("AGC_NDT_speech_thr:%d\n", (int)(param->AGC_NDT_speech_thr * 100));
log_info("AGC_DT_max_gain:%d\n", (int)(param->AGC_DT_max_gain * 100));
log_info("AGC_DT_min_gain:%d\n", (int)(param->AGC_DT_min_gain * 100));
log_info("AGC_DT_speech_thr:%d\n", (int)(param->AGC_DT_speech_thr * 100));
log_info("AGC_echo_present_thr:%d\n", (int)(param->AGC_echo_present_thr * 100));
log_info("AEC_DT_AggressiveFactor:%d\n", (int)(param->AEC_DT_AggressiveFactor * 100));
log_info("AEC_RefEngThr:%d\n", (int)(param->AEC_RefEngThr * 100));
log_info("ES_AggressFactor:%d\n", (int)(param->ES_AggressFactor * 100));
log_info("ES_MinSuppress:%d\n", (int)(param->ES_MinSuppress * 100));
log_info("ANS_AggressFactor:%d\n", (int)(param->ANS_AggressFactor * 100));
log_info("ANS_MinSuppress:%d\n", (int)(param->ANS_MinSuppress * 100));
log_info("=================END=======================\n");
}
struct audio_aec_hdl {
u8 start; //aec模块状态
u8 inbuf_clear_cnt; //aec输入数据丢掉
u8 output_fade_in; //aec输出淡入使能
u8 output_fade_in_gain; //aec输出淡入增益
#if AEC_UL_EQ_EN
struct audio_eq *ul_eq; //上行数据eq处理
#endif/*AEC_UL_EQ_EN*/
#if AEC_DCCS_EN
struct audio_eq *dccs_eq; //省电容mic去直流滤波
#endif/*AEC_DCCS_EN*/
u16 dump_packet; //前面如果有杂音,丢掉几包
u8 output_buf[1000]; //aec数据输出缓存
cbuffer_t output_cbuf;
struct aec_s_attr attr; //aec模块参数属性
};
#if AEC_USER_MALLOC_ENABLE
struct audio_aec_hdl *aec_hdl = NULL;
#else
struct audio_aec_hdl aec_handle;
#endif/*AEC_USER_MALLOC_ENABLE*/
void audio_aec_ref_start(u8 en)
{
if (aec_hdl) {
if (en != aec_hdl->attr.fm_tx_start) {
aec_hdl->attr.fm_tx_start = en;
y_printf("fm_tx_start:%d\n", en);
}
}
}
#if AEC_DCCS_EN
const int DCCS_8k_Coeff[5] = {
(943718 << 2), -(856687 << 2), (1048576 << 2), (1887437 << 2), -(2097152 << 2)
};
const int DCCS_16k_Coeff[5] = {
(1006633 << 2), -(967542 << 2), (1048576 << 2), (2013266 << 2), -(2097152 << 2)
};
int aec_dccs_eq_filter(void *eq, int sr, struct audio_eq_filter_info *info)
{
//r_printf("dccs_eq sr:%d\n", sr);
if (sr == 16000) {
info->L_coeff = (void *)DCCS_16k_Coeff;
info->R_coeff = (void *)DCCS_16k_Coeff;
} else {
info->L_coeff = (void *)DCCS_8k_Coeff;
info->R_coeff = (void *)DCCS_8k_Coeff;
}
info->L_gain = 0;
info->R_gain = 0;
info->nsection = 1;
return 0;
}
static int dccs_eq_output(void *priv, void *data, u32 len)
{
return 0;
}
#endif/*AEC_DCCS_EN*/
#if AEC_UL_EQ_EN
static int ul_eq_output(void *priv, void *data, u32 len)
{
return 0;
}
#endif/*AEC_UL_EQ_EN*/
/*
*********************************************************************
* Audio AEC Process_Probe
* Description: AEC模块数据前处理回调
* Arguments : data
* len
* Return : 0
* Note(s) : AEC模块前
*********************************************************************
*/
static int audio_aec_probe(s16 *data, u16 len)
{
#if AEC_DCCS_EN
if (aec_hdl->dccs_eq) {
audio_eq_run(aec_hdl->dccs_eq, data, 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*/
return 0;
}
/*跟踪系统内存使用情况:physics memory size xxxx bytes*/
static void sys_memory_trace(void)
{
static int cnt = 0;
if (cnt++ > 200) {
cnt = 0;
mem_stats();
}
}
/*
*********************************************************************
* 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 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;
}
}
}
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_read_config(struct aec_s_attr *p)
{
AEC_CONFIG cfg;
int ret = syscfg_read(CFG_AEC_ID, &cfg, sizeof(AEC_CONFIG));
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;
//dumpModulaStatus(cfg.aec_mode);
p->EnableBit = (cfg.aec_mode & AEC_MODE_ADVANCE);
if (p->EnableBit == 0) {
p->toggle = 0;
printf("cvp toggle off\n");
}
if ((cfg.aec_mode & AGC_EN) == 0) {
p->agc_en = (cfg.aec_mode & AGC_EN) ? 1 : 0;
}
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);
}
}
/*
*********************************************************************
* 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;
}
#else
aec_hdl = &aec_handle;
#endif/*AEC_USER_MALLOC_ENABLE*/
cbuf_init(&aec_hdl->output_cbuf, aec_hdl->output_buf, sizeof(aec_hdl->output_buf));
aec_hdl->start = 1;
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;
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)
aec_param->output_way = 1;
#else
aec_param->output_way = 0;
#endif
aec_param->toggle = 1;
aec_param->EnableBit = AEC_MODULE_BIT;
aec_param->agc_en = 1;
aec_param->wideband = 0;
aec_param->ul_eq_en = 1;
aec_param->packet_dump = 50;/*0~255(u8)*/
/*AGC*/
aec_param->AGC_NDT_fade_in_step = 1.3f;
aec_param->AGC_NDT_fade_out_step = 0.9f;
aec_param->AGC_DT_fade_in_step = 1.3f;
aec_param->AGC_DT_fade_out_step = 0.9f;
aec_param->AGC_NDT_max_gain = 12.f;
aec_param->AGC_NDT_min_gain = 0.f;
aec_param->AGC_NDT_speech_thr = -50.f;
aec_param->AGC_DT_max_gain = 12.f;
aec_param->AGC_DT_min_gain = 0.f;
aec_param->AGC_DT_speech_thr = -40.f;
aec_param->AGC_echo_look_ahead = 0;
aec_param->AGC_echo_present_thr = -70.f;
aec_param->AGC_echo_hold = 400;
/*AEC*/
aec_param->AEC_DT_AggressiveFactor = 1.f; /*范围1~5越大追踪越好但会不稳定,如破音*/
aec_param->AEC_RefEngThr = -70.f; /*范围:-90 ~ -60 dB*/
/*ES*/
aec_param->ES_AggressFactor = -3.0f; /*范围:-1 ~ -5*/
aec_param->ES_MinSuppress = 4.f; /*范围0 ~ 10*/
aec_param->ES_Unconverge_OverDrive = aec_param->ES_MinSuppress;
/*ANS*/
aec_param->ANS_mode = CONST_ANS_MODE;
aec_param->ANS_AggressFactor = 1.25f; /*范围1~2,动态调整,越大越强(1.25f)*/
aec_param->ANS_MinSuppress = 0.04f; /*范围0~1,静态定死最小调整,越小越强(0.09f)*/
aec_param->ANS_NoiseLevel = 2.2e4f;
aec_param->wn_en = 0;
aec_param->aec_tail_length = AEC_TAIL_LENGTH;
aec_param->wn_gain = 331;
aec_param->SimplexTail = AEC_SIMPLEX_TAIL;
aec_param->SimplexThr = AEC_SIMPLEX_THR;
#if ((AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM) || (TCFG_AEC_SIMPLEX))
aec_param->dly_est = 1;
#else
aec_param->dly_est = 0;
#endif
aec_param->dst_delay = 50;
aec_param->aec_probe = audio_aec_probe;
aec_param->aec_post = audio_aec_post;
aec_param->output_handle = audio_aec_output;
aec_param->ref_sr = usb_mic_is_running();
if (aec_param->ref_sr == 0) {
aec_param->ref_sr = sample_rate;
}
audio_aec_param_read_config(aec_param);
if (enablebit >= 0) {
aec_param->EnableBit = enablebit;
}
if (out_hdl) {
aec_param->output_handle = out_hdl;
}
#if TCFG_AEC_SIMPLEX
aec_param->wn_en = 1;
aec_param->EnableBit = AEC_MODE_SIMPLEX;
if (sample_rate == 8000) {
aec_param->wideband = 0;
aec_param->hw_delay_offset = 75;
aec_param->SimplexTail = aec_param->SimplexTail / 2;
clock_add(AEC8K_SPX_CLK);
} else {
aec_param->wideband = 1;
aec_param->hw_delay_offset = 50;
clock_add(AEC16K_SPX_CLK);
}
if (aec_param->dly_est == 0) {
aec_param->dst_delay = 30;
}
//printf("aec SimplexMode\n");
#else
if (sample_rate == 16000) {
aec_param->wideband = 1;
aec_param->hw_delay_offset = 50;
if (aec_param->EnableBit == AEC_MODE_ADVANCE) {
clock_add(AEC16K_ADV_CLK);
} else {
clock_add(AEC16K_CLK);
}
} else {
aec_param->wideband = 0;
aec_param->hw_delay_offset = 75;
if (aec_param->EnableBit == AEC_MODE_ADVANCE) {
clock_add(AEC8K_ADV_CLK);
} else {
clock_add(AEC8K_CLK);
}
}
#endif/*TCFG_AEC_SIMPLEX*/
#if AEC_UL_EQ_EN
if (aec_param->ul_eq_en) {
u8 mode = 2;
if (sample_rate == 8000) {
mode = 3;
}
struct audio_eq_param ul_eq_param = {0};
ul_eq_param.sr = sample_rate;
ul_eq_param.channels = 1;
ul_eq_param.max_nsection = phone_mode[mode].eq_parm.seg_num;
ul_eq_param.nsection = phone_mode[mode].eq_parm.seg_num;
ul_eq_param.seg = phone_mode[mode].eq_parm.seg;
ul_eq_param.global_gain = phone_mode[mode].eq_parm.global_gain;
ul_eq_param.cb = eq_get_filter_info;
ul_eq_param.eq_name = AEID_ESCO_UL_EQ;
aec_hdl->ul_eq = audio_dec_eq_open(&ul_eq_param);
}
#endif/*AEC_UL_EQ_EN*/
#if AEC_DCCS_EN
if (adc_data.mic_capless) {
struct audio_eq_param dccs_eq_param = {0};
dccs_eq_param.sr = sample_rate;
dccs_eq_param.channels = 1;
dccs_eq_param.max_nsection = 1;
dccs_eq_param.cb = aec_dccs_eq_filter;
aec_hdl->dccs_eq = audio_dec_eq_open(&dccs_eq_param);
}
#endif/*AEC_DCCS_EN*/
//aec_param->toggle = 1;
//aec_param->EnableBit = AEC_MODULE_BIT;
//aec_param_dump(aec_param);
#if AEC_TOGGLE
aec_open(aec_param);
#endif
mem_stats();
printf("audio_aec_open succ\n");
return 0;
}
/*
*********************************************************************
* Audio AEC Init
* Description: AEC模块
* Arguments : sr (8000/16000)
* Return : 0
* Note(s) : None.
*********************************************************************
*/
int audio_aec_init(u16 sample_rate)
{
return audio_aec_open(sample_rate, -1, NULL);
}
/*
*********************************************************************
* Audio AEC Close
* Description: AEC模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_aec_close(void)
{
printf("audio_aec_close\n");
struct aec_s_attr *aec_param;
if (aec_hdl) {
aec_hdl->start = 0;
aec_param = &aec_hdl->attr;
#if TCFG_AEC_SIMPLEX
if (aec_param->wideband) {
clock_remove(AEC16K_SPX_CLK);
} else {
clock_remove(AEC8K_SPX_CLK);
}
#else
if (aec_param->wideband) {
if (aec_param->EnableBit == AEC_MODE_ADVANCE) {
clock_remove(AEC16K_ADV_CLK);
} else {
clock_remove(AEC16K_CLK);
}
} else {
if (aec_param->EnableBit == AEC_MODE_ADVANCE) {
clock_remove(AEC8K_ADV_CLK);
} else {
clock_remove(AEC8K_CLK);
}
}
#endif/*TCFG_AEC_SIMPLEX*/
#if AEC_TOGGLE
aec_close();
#endif/*AEC_TOGGLE*/
#if AEC_DCCS_EN
if (aec_hdl->dccs_eq) {
audio_dec_eq_close(aec_hdl->dccs_eq);
}
#endif/*AEC_DCCS_EN*/
#if AEC_UL_EQ_EN
if (aec_hdl->ul_eq) {
audio_dec_eq_close(aec_hdl->ul_eq);
}
#endif/*AEC_UL_EQ_EN*/
local_irq_disable();
#if AEC_USER_MALLOC_ENABLE
free(aec_hdl);
#endif/*AEC_USER_MALLOC_ENABLE*/
aec_hdl = NULL;
local_irq_enable();
}
printf("audio_aec_close ok\n");
}
/*
*********************************************************************
* 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_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) {
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_DAC)
/* log_info("fill dac data\n");
u8 tmp_buf[64] = {0};
for (u8 i = 0; i < 512 / sizeof(tmp_buf); i++) {
app_audio_output_write(tmp_buf, sizeof(tmp_buf));
} */
#endif
} else if (ret == -2) {
log_error("aec inbuf full\n");
}
#else
audio_aec_output(buf, len);
#endif/*AEC_TOGGLE*/
}
}
/*
*********************************************************************
* 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*/
}
}
/* void aec_estimate_dump(int DlyEst)
{
printf("DlyEst:%d\n",DlyEst);
} */