Files
AC707N/SDK/audio/CVP/audio_cvp.c
T
2025-12-03 11:12:34 +08:00

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;
}