KT24-1110_65E-HA-651B/cpu/br25/audio_enc/audio_cvp.c
2024-11-10 18:44:17 +08:00

597 lines
18 KiB
C
Raw Permalink 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 CVP APIs
* Description:CVP用户调用接口
* 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 "circular_buf.h"
#include "clock_cfg.h"
#include "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 CVP_USER_MALLOC_ENABLE 1
/*CVP_TOGGLE:CVP模块使能开关Disable则数据完全不经过处理CVP模块不占用资源*/
#define CVP_TOGGLE 1
#if (TCFG_EQ_ENABLE == 1)
#include "media/audio_eq.h"
#define CVP_DCCS_EN 1 /*mic去直流滤波eq*/
#define CVP_UL_EQ_EN 1 /*mic 普通eq*/
#else
#define CVP_DCCS_EN 0
#define CVP_UL_EQ_EN 0
#endif/*TCFG_EQ_ENABLE*/
/*使能即可跟踪通话过程的内存情况*/
#define CVP_MEM_TRACE_ENABLE 0
/*
*ANS等级:0~2,
*等级1比等级0多6k左右的ram
*等级2比等级1多3k左右的ram
*/
static const u8 CONST_ANS_MODE = 1;
/*
*AEC复杂等级等级越高ram和mips越大适应性越好
*回音路径不定/回音失真等情况才需要比较高的等级
*音箱建议使用等级:4
*耳机建议使用等级:2
*/
#define AEC_TAIL_LENGTH 4 /*range:2~10,default:4*/
/*单工连续清0的帧数*/
#define AEC_SIMPLEX_TAIL 15
/*
*远端数据大于CONST_AEC_SIMPLEX_THR,即清零近端数据
*越小,回音限制得越好,同时也就越容易卡
*/
#define AEC_SIMPLEX_THR 100000 /*default:260000*/
/*aec mode select:AEC_MODE_REDUCE or AEC_MODE_ADVANCE */
#define AEC_MODULE_BIT AEC_MODE_ADVANCE
//////////////////////////= EDN =//////////////////////////////////////
/*数据输出开头丢掉的数据包数*/
#define CVP_OUT_DUMP_PACKET 10
/**数据输出开头丢掉的数据包数*/
#define CVP_IN_DUMP_PACKET 1
extern struct adc_platform_data adc_data;
static void cvp_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_cvp_hdl {
u8 start; //cvp模块状态
u8 inbuf_clear_cnt; //cvp输入数据丢掉
u8 output_fade_in; //cvp输出淡入使能
u8 output_fade_in_gain; //cvp输出淡入增益
#if CVP_UL_EQ_EN
struct audio_eq *ul_eq; //上行数据eq处理
#endif/*CVP_UL_EQ_EN*/
#if CVP_DCCS_EN
struct audio_eq *dccs_eq; //省电容mic去直流滤波
#endif/*CVP_DCCS_EN*/
u16 dump_packet; //前面如果有杂音,丢掉几包
u8 output_buf[1000]; //cvp数据输出缓存
cbuffer_t output_cbuf;
struct aec_s_attr attr; //cvp模块参数属性
};
#if CVP_USER_MALLOC_ENABLE
struct audio_cvp_hdl *cvp_hdl = NULL;
#else
struct audio_cvp_hdl cvp_handle;
#endif/*CVP_USER_MALLOC_ENABLE*/
void audio_cvp_ref_start(u8 en)
{
if (cvp_hdl) {
if (en != cvp_hdl->attr.fm_tx_start) {
cvp_hdl->attr.fm_tx_start = en;
y_printf("fm_tx_start:%d\n", en);
}
}
}
#if CVP_DCCS_EN
static const int DCCS_8k_Coeff[5] = {
(943718 << 2), -(856687 << 2), (1048576 << 2), (1887437 << 2), -(2097152 << 2)
};
static const int DCCS_16k_Coeff[5] = {
(1006633 << 2), -(967542 << 2), (1048576 << 2), (2013266 << 2), -(2097152 << 2)
};
static int cvp_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/*CVP_DCCS_EN*/
#if CVP_UL_EQ_EN
static int ul_eq_output(void *priv, void *data, u32 len)
{
return 0;
}
#endif/*CVP_UL_EQ_EN*/
/*
*********************************************************************
* Audio CVP Process_Probe
* Description: CVP模块数据前处理回调
* Arguments : data 数据地址
* len 数据长度
* Return : 0 成功 其他 失败
* Note(s) : 在源数据经过AEC模块前可以增加自定义处理
*********************************************************************
*/
static int audio_cvp_probe(s16 *data, u16 len)
{
#if CVP_DCCS_EN
if (cvp_hdl->dccs_eq) {
audio_eq_run(cvp_hdl->dccs_eq, data, len);
}
#endif/*CVP_DCCS_EN*/
return 0;
}
/*
*********************************************************************
* Audio CVP Process_Post
* Description: CVP模块数据后处理回调
* Arguments : data 数据地址
* len 数据长度
* Return : 0 成功 其他 失败
* Note(s) : 在数据处理完毕,可以增加自定义后处理
*********************************************************************
*/
static int audio_cvp_post(s16 *data, u16 len)
{
#if CVP_UL_EQ_EN
if (cvp_hdl->ul_eq) {
audio_eq_run(cvp_hdl->ul_eq, data, len);
}
#endif/*CVP_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 CVP Output Handle
* Description: CVP模块数据输出回调
* Arguments : data 输出数据地址
* len 输出数据长度
* Return : 数据输出消耗长度
* Note(s) : None.
*********************************************************************
*/
extern void esco_enc_resume(void);
static int audio_cvp_output(s16 *data, u16 len)
{
#if CVP_MEM_TRACE_ENABLE
sys_memory_trace();
#endif/*CVP_MEM_TRACE_ENABLE*/
if (cvp_hdl->dump_packet) {
cvp_hdl->dump_packet--;
memset(data, 0, len);
} else {
if (cvp_hdl->output_fade_in) {
s32 tmp_data;
//printf("fade:%d\n",cvp_hdl->output_fade_in_gain);
for (int i = 0; i < len / 2; i++) {
tmp_data = data[i];
data[i] = tmp_data * cvp_hdl->output_fade_in_gain >> 7;
}
cvp_hdl->output_fade_in_gain += 12;
if (cvp_hdl->output_fade_in_gain >= 128) {
cvp_hdl->output_fade_in = 0;
}
}
}
u16 wlen = cbuf_write(&cvp_hdl->output_cbuf, data, len);
//printf("wlen:%d-%d\n",len,cvp_hdl.output_cbuf.data_len);
/* esco_enc_resume(); */
#if 1
static u32 aec_output_max = 0;
if (aec_output_max < cvp_hdl->output_cbuf.data_len) {
aec_output_max = cvp_hdl->output_cbuf.data_len;
y_printf("o_max:%d", aec_output_max);
}
#endif
if (wlen != len) {
putchar('F');
}
return wlen;
}
/*
*********************************************************************
* Audio CVP Output Read
* Description: 读取cvp模块的输出数据
* Arguments : buf 读取数据存放地址
* len 读取数据长度
* Return : 数据读取长度
* Note(s) : None.
*********************************************************************
*/
int audio_cvp_output_read(s16 *buf, u16 len)
{
//printf("rlen:%d-%d\n",len,cvp_hdl.output_cbuf.data_len);
local_irq_disable();
if (!cvp_hdl || !cvp_hdl->start) {
printf("audio_a2dp_aec close now");
local_irq_enable();
return -EINVAL;
}
u16 rlen = cbuf_read(&cvp_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 CVP Open
* Description: 初始化CVP模块
* Arguments : sr 采样率(8000/16000)
* enablebit 使能模块(AEC/NLP/AGC/ANS...)
* out_hdl 自定义回调函数NULL则用默认的回调
* param_hdl 自定义参数回调函数NULL则用默认的参数
* Return : 0 成功 其他 失败
* Note(s) : null
*********************************************************************
*/
int audio_cvp_open(u16 sample_rate, s16 enablebit, int (*out_hdl)(s16 *data, u16 len), void (*param_hdl)(struct aec_s_attr *p))
{
struct aec_s_attr *cvp_param;
printf("audio_aec_open\n");
mem_stats();
#if CVP_USER_MALLOC_ENABLE
cvp_hdl = zalloc(sizeof(struct audio_cvp_hdl));
if (cvp_hdl == NULL) {
log_error("cvp_hdl malloc failed");
return -ENOMEM;
}
#else
cvp_hdl = &cvp_handle;
#endif/*CVP_USER_MALLOC_ENABLE*/
cbuf_init(&cvp_hdl->output_cbuf, cvp_hdl->output_buf, sizeof(cvp_hdl->output_buf));
cvp_hdl->start = 1;
cvp_hdl->dump_packet = CVP_OUT_DUMP_PACKET;
cvp_hdl->inbuf_clear_cnt = CVP_IN_DUMP_PACKET;
cvp_hdl->output_fade_in = 1;
cvp_hdl->output_fade_in_gain = 0;
cvp_param = &cvp_hdl->attr;
cvp_param->output_way = 0;
cvp_param->toggle = 1;
cvp_param->EnableBit = AEC_MODULE_BIT;
cvp_param->agc_en = 0;
cvp_param->wideband = 0;
cvp_param->ul_eq_en = 1;
cvp_param->packet_dump = 50;/*0~255(u8)*/
/*AGC*/
cvp_param->AGC_NDT_fade_in_step = 1.3f;
cvp_param->AGC_NDT_fade_out_step = 0.9f;
cvp_param->AGC_DT_fade_in_step = 1.3f;
cvp_param->AGC_DT_fade_out_step = 0.9f;
cvp_param->AGC_NDT_max_gain = 12.f;
cvp_param->AGC_NDT_min_gain = 0.f;
cvp_param->AGC_NDT_speech_thr = -50.f;
cvp_param->AGC_DT_max_gain = 12.f;
cvp_param->AGC_DT_min_gain = 0.f;
cvp_param->AGC_DT_speech_thr = -40.f;
cvp_param->AGC_echo_look_ahead = 0;
cvp_param->AGC_echo_present_thr = -70.f;
cvp_param->AGC_echo_hold = 400;
/*AEC*/
cvp_param->AEC_DT_AggressiveFactor = 1.f; /*范围1~5越大追踪越好但会不稳定,如破音*/
cvp_param->AEC_RefEngThr = -70.f; /*范围:-90 ~ -60 dB*/
/*ES*/
cvp_param->ES_AggressFactor = -3.0f; /*范围:-1 ~ -5*/
cvp_param->ES_MinSuppress = 4.f; /*范围0 ~ 10*/
cvp_param->ES_Unconverge_OverDrive = cvp_param->ES_MinSuppress;
/*ANS*/
cvp_param->ANS_mode = CONST_ANS_MODE;
cvp_param->ANS_AggressFactor = 1.25f; /*范围1~2,动态调整,越大越强(1.25f)*/
cvp_param->ANS_MinSuppress = 0.04f; /*范围0~1,静态定死最小调整,越小越强(0.09f)*/
cvp_param->ANS_NoiseLevel = 2.2e4f;
cvp_param->wn_en = 0;
cvp_param->aec_tail_length = AEC_TAIL_LENGTH;
cvp_param->wn_gain = 331;
cvp_param->SimplexTail = AEC_SIMPLEX_TAIL;
cvp_param->SimplexThr = AEC_SIMPLEX_THR;
cvp_param->dly_est = 0;
cvp_param->dst_delay = 50;
cvp_param->aec_probe = audio_cvp_probe;
cvp_param->aec_post = audio_cvp_post;
cvp_param->output_handle = audio_cvp_output;
cvp_param->output_handle = out_hdl;
cvp_param->ref_sr = audio_output_nor_rate();
if (cvp_param->ref_sr == 0) {
cvp_param->ref_sr = sample_rate;
}
if (enablebit >= 0) {
cvp_param->EnableBit = enablebit;
}
if (out_hdl) {
cvp_param->output_handle = out_hdl;
}
if (param_hdl) {
param_hdl(cvp_param);
}
if (sample_rate == 16000) {
cvp_param->wideband = 1;
cvp_param->hw_delay_offset = 50;
if (cvp_param->EnableBit == AEC_MODE_ADVANCE) {
clock_add(AEC16K_ADV_CLK);
} else {
clock_add(AEC16K_CLK);
}
} else {
cvp_param->wideband = 0;
cvp_param->hw_delay_offset = 75;
if (cvp_param->EnableBit == AEC_MODE_ADVANCE) {
clock_add(AEC8K_ADV_CLK);
} else {
clock_add(AEC8K_CLK);
}
}
#if CVP_UL_EQ_EN
if (cvp_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;
cvp_hdl->ul_eq = audio_dec_eq_open(&ul_eq_param);
}
#endif/*CVP_UL_EQ_EN*/
#if CVP_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 = cvp_dccs_eq_filter;
cvp_hdl->dccs_eq = audio_dec_eq_open(&dccs_eq_param);
}
#endif/*CVP_DCCS_EN*/
//cvp_param_dump(cvp_param);
#if CVP_TOGGLE
aec_open(cvp_param);
#endif
mem_stats();
printf("audio_a2dp_aec_open succ\n");
return 0;
}
/*
*********************************************************************
* Audio CVP Close
* Description: 关闭CVP模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_cvp_close(void)
{
printf("audio_a2dp_aec_close\n");
struct aec_s_attr *cvp_param;
if (cvp_hdl) {
cvp_hdl->start = 0;
cvp_param = &cvp_hdl->attr;
if (cvp_param->wideband) {
if (cvp_param->EnableBit == AEC_MODE_ADVANCE) {
clock_remove(AEC16K_ADV_CLK);
} else {
clock_remove(AEC16K_CLK);
}
} else {
if (cvp_param->EnableBit == AEC_MODE_ADVANCE) {
clock_remove(AEC8K_ADV_CLK);
} else {
clock_remove(AEC8K_CLK);
}
}
#if CVP_TOGGLE
aec_close();
#endif/*CVP_TOGGLE*/
#if CVP_DCCS_EN
if (cvp_hdl->dccs_eq) {
audio_dec_eq_close(cvp_hdl->dccs_eq);
}
#endif/*CVP_DCCS_EN*/
#if CVP_UL_EQ_EN
if (cvp_hdl->ul_eq) {
audio_dec_eq_close(cvp_hdl->ul_eq);
}
#endif/*CVP_UL_EQ_EN*/
local_irq_disable();
#if CVP_USER_MALLOC_ENABLE
free(cvp_hdl);
#endif/*CVP_USER_MALLOC_ENABLE*/
cvp_hdl = NULL;
local_irq_enable();
}
printf("audio_a2dp_aec_close ok\n");
}
/*
*********************************************************************
* Audio CVP Input
* Description: CVP源数据输入
* Arguments : buf 输入源数据地址
* len 输入源数据长度
* Return : None.
* Note(s) : 输入一帧数据唤醒一次运行任务处理数据默认帧长256点
*********************************************************************
*/
void audio_cvp_inbuf(s16 *buf, u16 len)
{
if (cvp_hdl && cvp_hdl->start) {
#if CVP_TOGGLE
if (cvp_hdl->inbuf_clear_cnt) {
cvp_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("a2dp aec inbuf full\n");
}
#else
cvp_hdl->attr.output_handle(buf, len);
#endif/*CVP_TOGGLE*/
}
}
/*
*********************************************************************
* Audio CVP Reference
* Description: CVP模块参考数据输入
* Arguments : buf 输入参考数据地址
* len 输入参考数据长度
* Return : None.
* Note(s) : 声卡设备是DAC默认不用外部提供参考数据
*********************************************************************
*/
void audio_cvp_refbuf(s16 *buf, u16 len)
{
if (cvp_hdl && cvp_hdl->start) {
#if CVP_TOGGLE
aec_ref_data(buf, len);
#endif/*CVP_TOGGLE*/
}
}
/* void aec_estimate_dump(int DlyEst)
{
printf("DlyEst:%d\n",DlyEst);
} */