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

1031 lines
32 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".audio_cvp_develop.data.bss")
#pragma data_seg(".audio_cvp_develop.data")
#pragma const_seg(".audio_cvp_develop.text.const")
#pragma code_seg(".audio_cvp_develop.text")
#endif
/*
***************************************************************************
* Audio CVP Develop
*
* Brief : Third-party algorithm integration 第三方算法集成
* Notes :
* 1.demo默认将输入数据copy到输出,相关处理只需在运算函数
* audio_aec_run()实现即可
* 2.双mic ENC开发,需要在配置工具中通话第三方算法节点选择双麦算法
* 3.建议算法开发者使用宏定义将自己的代码模块包起来
* 4.开发阶段,默认使用芯片最高主频160MHz,可以通过修改AEC_CLK来修改
运行频率。
***************************************************************************
*/
#include "audio_cvp.h"
#include "aec_uart_debug.h"
#include "system/includes.h"
#include "media/includes.h"
#include "effects/eq_config.h"
#include "circular_buf.h"
#include "overlay_code.h"
#include "audio_config.h"
#include "debug.h"
#include "cvp_node.h"
#include "app_config.h"
#if TCFG_AUDIO_CVP_SYNC
#include "audio_cvp_sync.h"
#endif/*TCFG_AUDIO_CVP_SYNC*/
#if TCFG_AUDIO_DUT_ENABLE
#include "audio_dut_control.h"
#endif/*TCFG_AUDIO_DUT_ENABLE*/
#if defined(TCFG_CVP_DEVELOP_ENABLE) && (TCFG_CVP_DEVELOP_ENABLE == CVP_CFG_USER_DEFINED)
#define AEC_CLK (160 * 1000000L) /*模块运行时钟(MaxFre:160MHz)*/
#define AEC_FRAME_POINTS 256 /*AEC处理帧长,跟mic采样长度关联*/
#define AEC_FRAME_SIZE (AEC_FRAME_POINTS << 1)
#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_OUT_DUMP_PACKET 15
/*
* 参考数据变采样处理
* 0 : 关闭参考数据变采样
* 1 : 使用软件变采样
* 2 : 使用硬件变采样
*/
#if TCFG_BT_DONGLE_ENABLE || TCFG_ESCO_DL_CVSD_SR_USE_16K
const u8 CONST_REF_SRC = 1;
#else
const u8 CONST_REF_SRC = 0;
#endif
//*********************************************************************************//
// 预处理配置(Pre-process Config) //
//*********************************************************************************//
/*预增益配置*/
#define CVP_PRE_GAIN_ENABLE 0 //算法处理前预加数字增益放大使能
#define CVP_PRE_GAIN 6.f //算法前处理数字增益(Gain = 10^(dB_diff/20))
/*AEC输入buf复用mic_adc采样buf*/
#define MIC_BULK_MAX 3
struct mic_bulk {
struct list_head entry;
s16 *addr;
u16 len;
u16 used;
};
struct audio_aec_hdl {
volatile u8 start; //aec模块状态
u8 mic_num; //MIC的数量
volatile u8 busy;
volatile u8 ref_busy;
volatile u8 ref_ok; //aec模块状态
u8 output_fade_in; //aec输出淡入使能
u8 output_fade_in_gain; //aec输出淡入增益
u8 output_sel; //数据输出通道选择
u16 dump_packet; //前面如果有杂音,丢掉几包
s16 *mic; /*主mic数据地址*/
s16 *mic_ref; /*参考mic数据地址*/
s16 *mic_ref_1; /*参考mic数据地址*/
s16 *pFar; /*参考数据地址*/
s16 *free_ram; /*当前可用内存*/
/* s16 spk_ref[AEC_FRAME_POINTS]; #<{(|扬声器参考数据|)}># */
s16 *spk_ref; /*扬声器参考数据*/
s16 out[AEC_FRAME_POINTS]; /*运算输出地址*/
OS_SEM sem;
/*数据复用相关数据结构*/
struct mic_bulk in_bulk[MIC_BULK_MAX];
struct mic_bulk inref_bulk[MIC_BULK_MAX];
struct mic_bulk inref_1_bulk[MIC_BULK_MAX];
struct mic_bulk ref0_bulk[MIC_BULK_MAX];
struct list_head in_head;
struct list_head inref_head;
struct list_head inref_1_head;
struct list_head ref0_head;
u8 output_way;
u8 fm_tx_start;
u8 ref_channel;
u8 adc_ref_en;
u16 ref_size;
u32 ref_sr;
int (*output_handle)(s16 *dat, u16 len);//输出回调函数
};
struct audio_aec_hdl *aec_hdl = NULL;
struct audio_aec_hdl aec_hdl_mem AT(.aec_mem);
#define AEC_REF_CBUF_SIZE (AEC_FRAME_POINTS * 6)
#define AEC_REF_CBUF_DOOR_SIZE (AEC_REF_CBUF_SIZE / 2)
static cbuffer_t *aec_ref_cbuf = NULL;
extern void aec_code_movable_load(void);
extern void aec_code_movable_unload(void);
__attribute__((weak))u32 usb_mic_is_running()
{
return 0;
}
void audio_aec_ref_start(u8 en)
{
if (aec_hdl) {
if (en != aec_hdl->fm_tx_start) {
/* if (esco_adc_mic_en() == 0) { */
aec_hdl->fm_tx_start = en;
y_printf("fm_tx_start:%d\n", en);
/* } */
}
}
}
/*通话上行同步输出回调*/
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.
*********************************************************************
*/
static int audio_aec_output(s16 *data, u16 len)
{
u16 wlen = 0;
if (aec_hdl && aec_hdl->start) {
#if TCFG_AUDIO_CVP_SYNC
audio_cvp_sync_run(data, len);
return len;
#endif/*TCFG_AUDIO_CVP_SYNC*/
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;
}
}
}
return cvp_node_output_handle(data, len);
}
return wlen;
}
/*
*跟踪系统内存使用情况:physics memory size xxxx bytes
*正常的系统运行过程,应该至少有3k bytes的剩余空间给到系统调度开销
*/
static void sys_memory_trace(void)
{
static int cnt = 0;
if (cnt++ > 200) {
cnt = 0;
mem_stats();
}
}
#include "Resample_api.h"
static RS_STUCT_API *sw_src_api = NULL;
static unsigned int *sw_src_buf = NULL;
#include "asm/audio_src.h"
static struct audio_src_handle *ref_hw_src = NULL;;
static u16 ref_hw_src_len = 0;
static int ref_hw_src_output(void *p, s16 *data, u16 len)
{
struct audio_aec_hdl *aec = (struct audio_aec_hdl *)p;
if (aec) {
memcpy(aec->pFar + (ref_hw_src_len >> 1), data, len);
ref_hw_src_len += len;
}
return len;
}
static int sw_src_init(u8 nch, u16 insample, u16 outsample)
{
if (CONST_REF_SRC == 1) {
if (insample != outsample) {
sw_src_api = get_rs16_context();
g_printf("sw_src_api:0x%x\n", sw_src_api);
ASSERT(sw_src_api);
u32 sw_src_need_buf = sw_src_api->need_buf();
g_printf("sw_src_buf:%d\n", sw_src_need_buf);
sw_src_buf = malloc(sw_src_need_buf);
ASSERT(sw_src_buf);
RS_PARA_STRUCT rs_para_obj;
rs_para_obj.nch = nch;
rs_para_obj.new_insample = insample;//48000;
rs_para_obj.new_outsample = outsample;//16000;
rs_para_obj.dataTypeobj.IndataBit = 0;
rs_para_obj.dataTypeobj.OutdataBit = 0;
rs_para_obj.dataTypeobj.IndataInc = (nch == 1) ? 1 : 2;
rs_para_obj.dataTypeobj.OutdataInc = (nch == 1) ? 1 : 2;
rs_para_obj.dataTypeobj.Qval = 15;
printf("sw src,ch = %d, in = %d,out = %d\n", rs_para_obj.nch, rs_para_obj.new_insample, rs_para_obj.new_outsample);
sw_src_api->open(sw_src_buf, &rs_para_obj);
}
} else if (CONST_REF_SRC == 2) {
if (insample != outsample) {
printf("hw src ch %d, in %d, out %d\n", nch, insample, outsample);
ref_hw_src = zalloc(sizeof(struct audio_src_handle));
if (ref_hw_src) {
u8 channel = nch;
audio_hw_src_open(ref_hw_src, channel, AUDIO_RESAMPLE_SYNC_OUTPUT);
audio_hw_src_set_rate(ref_hw_src, insample, outsample);
audio_src_set_output_handler(ref_hw_src, aec_hdl, (int (*)(void *, void *, int))ref_hw_src_output);
printf("audio hw src open succ %x", (int)ref_hw_src);
} else {
printf("ref_hw_src malloc fail !!!\n");
}
}
}
return 0;
}
static int sw_src_run(s16 *indata, s16 *outdata, u16 len)
{
int outlen = len;
if (CONST_REF_SRC == 1) {
if (sw_src_api && sw_src_buf) {
outlen = sw_src_api->run(sw_src_buf, indata, len >> 1, outdata);
/* ASSERT(outlen <= (sizeof(outdata) >> 1)); */
outlen = outlen << 1;
/* printf("%d\n",outlen); */
}
} else if (CONST_REF_SRC == 2) {
if (ref_hw_src) {
ref_hw_src_len = 0;;
outlen = audio_src_resample_write(ref_hw_src, indata, len);
outlen = ref_hw_src_len;
}
}
return outlen;
}
static void sw_src_exit(void)
{
if (CONST_REF_SRC == 1) {
if (sw_src_buf) {
free(sw_src_buf);
sw_src_buf = NULL;
sw_src_api = NULL;
}
} else if (CONST_REF_SRC == 2) {
printf("[HW]ref_src_exit\n");
if (ref_hw_src) {
audio_hw_src_close(ref_hw_src);
free(ref_hw_src);
ref_hw_src = NULL;
}
}
}
/*
*********************************************************************
* Audio AEC RUN
* Description: AEC数据处理核心
* Arguments : in Talk Mic采样数据
* inref FF Mic采样数据
* inref1 FB Mic采样数据
* ref speaker回采参考数据
* out 数据输出
* points 数据点数,单位short
* Return : 数据运算输出长度
* Note(s) : 在这里实现AEC_core
*********************************************************************
*/
static int audio_aec_run(s16 *in, s16 *inref, s16 *inref1, s16 *ref, s16 *out, u16 points)
{
int out_size = 0;
putchar('.');
#if CVP_PRE_GAIN_ENABLE
GainProcess_16Bit(in, in, CVP_PRE_GAIN, 1, 1, 1, points);
GainProcess_16Bit(inref, inref, CVP_PRE_GAIN, 1, 1, 1, points);
// GainProcess_16Bit_test(inref1, inref1, 0.f, 1, 1, 1, points);
#endif/*CVP_PRE_GAIN_ENABLE*/
/*TODO:这里调用第三方算法处理*/
//3rd_party_algo_run();
memcpy(out, in, (points << 1));
//memcpy(out, inref, (points << 1));
out_size = points << 1;
#if TCFG_AUDIO_DUT_ENABLE
switch (aec_hdl->output_sel) {
case CVP_3MIC_OUTPUT_SEL_MASTER:
memcpy(out, in, (points << 1));
break;
case CVP_3MIC_OUTPUT_SEL_SLAVE:
if (aec_hdl->mic_num > 1) {
memcpy(out, inref, (points << 1));
}
break;
case CVP_3MIC_OUTPUT_SEL_FBMIC:
if (aec_hdl->mic_num > 2) {
memcpy(out, inref1, (points << 1));
}
break;
default:
break;
}
#endif/*TCFG_AUDIO_DUT_ENABLE*/
sys_memory_trace();
return out_size;
}
/*
*********************************************************************
* Audio AEC Task
* Description: AEC任务
* Arguments : priv 私用参数
* Return : None.
* Note(s) : None.
*********************************************************************
*/
static void audio_aec_task(void *priv)
{
printf("==Audio AEC Task==\n");
struct mic_bulk *bulk = NULL;
struct mic_bulk *bulk_ref = NULL;
struct mic_bulk *bulk_ref_1 = NULL;
struct mic_bulk *ref0_bulk = NULL;
u8 pend = 1;
while (1) {
if (aec_hdl->output_way == 1) {
if (!list_empty(&aec_hdl->in_head) && (aec_ref_cbuf->data_len >= aec_hdl->ref_size)) {
cbuf_read(aec_ref_cbuf, aec_hdl->spk_ref, aec_hdl->ref_size);
} else {
os_sem_pend(&aec_hdl->sem, 0);
continue;
}
} else {
if (pend) {
os_sem_pend(&aec_hdl->sem, 0);
}
}
pend = 1;
if (aec_hdl->start) {
if ((!list_empty(&aec_hdl->in_head)) &&
(!list_empty(&aec_hdl->ref0_head))) {
aec_hdl->busy = 1;
local_irq_disable();
/*1.获取主mic数据*/
bulk = list_first_entry(&aec_hdl->in_head, struct mic_bulk, entry);
list_del(&bulk->entry);
aec_hdl->mic = bulk->addr;
if (aec_hdl->mic_num >= 2) {
/*获取参考mic数据*/
bulk_ref = list_first_entry(&aec_hdl->inref_head, struct mic_bulk, entry);
list_del(&bulk_ref->entry);
aec_hdl->mic_ref = bulk_ref->addr;
}
if (aec_hdl->mic_num >= 3) {
/*获取参考mic数据*/
bulk_ref_1 = list_first_entry(&aec_hdl->inref_1_head, struct mic_bulk, entry);
list_del(&bulk_ref_1->entry);
aec_hdl->mic_ref_1 = bulk_ref_1->addr;
}
/*获取参考数据*/
aec_hdl->pFar = aec_hdl->spk_ref;
if (aec_hdl->output_way == 0) {
ref0_bulk = list_first_entry(&aec_hdl->ref0_head, struct mic_bulk, entry);
list_del(&ref0_bulk->entry);
aec_hdl->pFar = (s16 *)ref0_bulk->addr;
}
local_irq_enable();
int rlen = aec_hdl->ref_size;
/*dac参考数据是立体声数据时,合成一个声道*/
if (aec_hdl->ref_channel == 2) {
for (int i = 0; i < rlen / 4; i++) {
aec_hdl->pFar[i] = (short)(((int)aec_hdl->pFar[i * 2] + (int)aec_hdl->pFar[i * 2 + 1]) >> 1);
}
rlen = rlen >> 1;
}
/*参考数据变采样*/
if (CONST_REF_SRC) {
rlen = sw_src_run(aec_hdl->pFar, aec_hdl->pFar, rlen);
}
/*4.算法处理*/
int out_len = audio_aec_run(aec_hdl->mic, aec_hdl->mic_ref, aec_hdl->mic_ref_1, aec_hdl->pFar, aec_hdl->out, AEC_FRAME_POINTS);
/*5.结果输出*/
aec_hdl->output_handle(aec_hdl->out, out_len);
/*6.数据导出*/
if (CONST_AEC_EXPORT) {
aec_uart_fill(0, aec_hdl->mic, 512); //主mic数据
aec_uart_fill(1, aec_hdl->mic_ref, 512); //副mic数据
aec_uart_fill(2, aec_hdl->pFar, 512); //扬声器数据
if (aec_hdl->mic_num == 3) {
aec_uart_fill(2, aec_hdl->mic_ref_1, 512); //扬声器数据
aec_uart_fill(3, aec_hdl->pFar, 512); //扬声器数据
aec_uart_fill(4, aec_hdl->out, out_len); //算法运算结果
}
aec_uart_write();
}
bulk->used = 0;
if (aec_hdl->mic_num >= 2) {
bulk_ref->used = 0;
}
if (aec_hdl->mic_num >= 3) {
bulk_ref_1->used = 0;
}
if (aec_hdl->output_way == 0) {
ref0_bulk->used = 0;
}
aec_hdl->busy = 0;
pend = 0;
}
}
}
}
/*
*********************************************************************
* 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))
{
printf("audio_aec_init,sr = %d\n", init_param->sample_rate);
s16 sample_rate = init_param->sample_rate;
u32 ref_sr = init_param->ref_sr;
mem_stats();
if (aec_hdl) {
printf("audio aec is already open!\n");
return -1;
}
overlay_load_code(OVERLAY_AEC);
aec_code_movable_load();
/* aec_hdl = zalloc(sizeof(struct audio_aec_hdl)); */
/* if (aec_hdl == NULL) { */
/* printf("aec_hdl malloc failed"); */
/* return -ENOMEM; */
/* } */
/* audio_overlay_load_code(OVERLAY_AEC); */
memset(&aec_hdl_mem, 0, sizeof(aec_hdl_mem));
aec_hdl = &aec_hdl_mem;
printf("aec_hdl size:%ld\n", sizeof(struct audio_aec_hdl));
/* clk_set("sys", AEC_CLK); */
aec_hdl->mic_num = init_param->mic_num;
aec_hdl->dump_packet = CVP_OUT_DUMP_PACKET;
aec_hdl->output_fade_in = 1;
aec_hdl->output_fade_in_gain = 0;
#if TCFG_AUDIO_DUT_ENABLE
aec_hdl->output_sel = CVP_3MIC_OUTPUT_SEL_DEFAULT;
#endif/*TCFG_AUDIO_DUT_ENABLE*/
#if TCFG_AUDIO_CVP_SYNC
audio_cvp_sync_open(init_param->sample_rate);
#endif/*TCFG_AUDIO_CVP_SYNC*/
aec_hdl->output_way = 0;
aec_hdl->fm_tx_start = 0;
aec_hdl->ref_channel = 1;
aec_hdl->adc_ref_en = 0;
if (ref_sr) {
aec_hdl->ref_sr = ref_sr;
} else {
aec_hdl->ref_sr = usb_mic_is_running();
}
if (aec_hdl->ref_sr == 0) {
if (TCFG_ESCO_DL_CVSD_SR_USE_16K && (sample_rate == 8000)) {
aec_hdl->ref_sr = 16000; //CVSD 下行为16K
} else {
aec_hdl->ref_sr = sample_rate;
}
}
if (out_hdl) {
aec_hdl->output_handle = out_hdl;
} else {
aec_hdl->output_handle = audio_aec_output;
}
/*不支持参考数据和输入数据不成倍数关系的运算*/
if (aec_hdl->ref_sr % sample_rate) {
printf("AEC error: ref_sr:%d,in_sr:%d\n", aec_hdl->ref_sr, sample_rate);
return -ENOEXEC;
}
if (aec_hdl->ref_channel != 2) {
aec_hdl->ref_channel = 1;
}
INIT_LIST_HEAD(&aec_hdl->in_head);
INIT_LIST_HEAD(&aec_hdl->inref_head);
INIT_LIST_HEAD(&aec_hdl->inref_1_head);
if (aec_hdl->output_way == 0) {
INIT_LIST_HEAD(&aec_hdl->ref0_head);
}
/*adc回采参考数据时,复用adc的buf*/
aec_hdl->ref_size = AEC_FRAME_POINTS * sizeof(short) * (aec_hdl->ref_sr / sample_rate) * aec_hdl->ref_channel;
printf("aec ref_size:%d\n", aec_hdl->ref_size);
if (aec_hdl->adc_ref_en == 0) {
if (aec_hdl->output_way == 0) {
aec_hdl->spk_ref = zalloc(aec_hdl->ref_size * MIC_BULK_MAX);
} else {
aec_hdl->spk_ref = zalloc(aec_hdl->ref_size);
}
}
if (aec_hdl->output_way == 1) {
u16 aec_ref_buf_size = AEC_REF_CBUF_SIZE * (aec_hdl->ref_sr / sample_rate) * aec_hdl->ref_channel;
u8 *aec_ref_buf = zalloc(aec_ref_buf_size + sizeof(cbuffer_t));
aec_ref_cbuf = (cbuffer_t *)aec_ref_buf;
printf("aec ref cbuf:%d\n", aec_ref_buf_size);
if (aec_ref_cbuf) {
cbuf_init(aec_ref_cbuf, aec_ref_buf + sizeof(cbuffer_t), aec_ref_buf_size);
/* cbuf_write(aec_ref_cbuf, aec->output, 128); */
} else {
printf("aec cbuf zalloc failed\n");
}
}
os_sem_create(&aec_hdl->sem, 0);
task_create(audio_aec_task, NULL, "aec");
if (CONST_AEC_EXPORT) {
if (aec_hdl->mic_num == 3) {
aec_uart_open(5, 512);
} else {
aec_uart_open(3, 512);
}
}
audio_dac_read_reset();
if (CONST_REF_SRC) {
sw_src_init(1, aec_hdl->ref_sr, sample_rate);
}
aec_hdl->start = 1;
mem_stats();
#if 0
aec_hdl->free_ram = malloc(1024 * 63);
mem_stats();
#endif
printf("audio_aec_open succ\n");
return 0;
}
/*
*********************************************************************
* Audio AEC Init
* Description: 初始化AEC模块
* Arguments : init_param 初始化参数句柄
* 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 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;
while (aec_hdl->busy) {
os_time_dly(2);
}
task_kill("aec");
#if TCFG_AUDIO_CVP_SYNC
//在AEC关闭之后再关,否则还会跑cvp_sync_run,导致越界
audio_cvp_sync_close();
#endif/*TCFG_AUDIO_CVP_SYNC*/
if (CONST_AEC_EXPORT) {
aec_uart_close();
}
if (CONST_REF_SRC) {
sw_src_exit();
}
if (aec_ref_cbuf) {
free(aec_ref_cbuf);
aec_ref_cbuf = NULL;
}
if (aec_hdl->spk_ref) {
free(aec_hdl->spk_ref);
aec_hdl->spk_ref = NULL;
}
local_irq_disable();
if (aec_hdl->free_ram) {
free(aec_hdl->free_ram);
}
/* free(aec_hdl); */
aec_hdl = NULL;
local_irq_enable();
aec_code_movable_unload();
printf("audio_aec_close succ\n");
}
}
/*
*********************************************************************
* 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;
}
int cvp_develop_read_ref_data(void)
{
u16 rlen = -1;
u8 i;
int err = 0;
if (aec_hdl == NULL) {
return 0;
} else if (aec_hdl->start == 0) {
return 0;
}
if ((aec_hdl->output_way) || (aec_hdl->adc_ref_en)) {
return 0;
}
for (i = 0; i < MIC_BULK_MAX; i++) {
if (aec_hdl->ref0_bulk[i].used == 0) {
rlen = audio_dac_read(60,
aec_hdl->spk_ref + ((aec_hdl->ref_size >> 1) * i),
aec_hdl->ref_size / aec_hdl->ref_channel,
aec_hdl->ref_channel);
break;
}
}
if (i < MIC_BULK_MAX) {
//AEC_D("bulk:%d-%d\n",i,len);
aec_hdl->ref0_bulk[i].addr = (aec_hdl->spk_ref + ((aec_hdl->ref_size >> 1) * i));
aec_hdl->ref0_bulk[i].used = 0x55;
aec_hdl->ref0_bulk[i].len = rlen;
list_add_tail(&aec_hdl->ref0_bulk[i].entry, &aec_hdl->ref0_head);
} else {
printf(">>>far_in_full\n");
/*align reset*/
struct mic_bulk *bulk;
list_for_each_entry(bulk, &aec_hdl->ref0_head, entry) {
bulk->used = 0;
__list_del_entry(&bulk->entry);
}
return -1;
}
return rlen;
}
/*
*********************************************************************
* 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->output_way == 1) {
if ((aec_hdl->ref_ok == 0) || (aec_hdl->fm_tx_start == 0)) {
if (aec_hdl->ref_ok && !aec_hdl->fm_tx_start) {
printf("[aec]fm_tx_start == 0\n");
}
return;
}
}
int i = 0;
for (i = 0; i < MIC_BULK_MAX; i++) {
if (aec_hdl->in_bulk[i].used == 0) {
break;
}
}
if (i < MIC_BULK_MAX) {
aec_hdl->in_bulk[i].addr = buf;
aec_hdl->in_bulk[i].used = 0x55;
aec_hdl->in_bulk[i].len = len;
list_add_tail(&aec_hdl->in_bulk[i].entry, &aec_hdl->in_head);
} else {
printf(">>>aec_in_full\n");
/*align reset*/
if (aec_hdl->output_way == 0) {
audio_dac_read_reset();
}
struct mic_bulk *bulk;
list_for_each_entry(bulk, &aec_hdl->in_head, entry) {
bulk->used = 0;
__list_del_entry(&bulk->entry);
}
return;
}
os_sem_set(&aec_hdl->sem, 0);
os_sem_post(&aec_hdl->sem);
}
}
/*
*********************************************************************
* 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) {
if (aec_hdl->output_way == 1) {
if ((aec_hdl->ref_ok == 0) || (aec_hdl->fm_tx_start == 0)) {
if (aec_hdl->ref_ok && !aec_hdl->fm_tx_start) {
printf("[aec]fm_tx_start == 0\n");
}
return;
}
}
int i = 0;
for (i = 0; i < MIC_BULK_MAX; i++) {
if (aec_hdl->inref_bulk[i].used == 0) {
break;
}
}
if (i < MIC_BULK_MAX) {
aec_hdl->inref_bulk[i].addr = buf;
aec_hdl->inref_bulk[i].used = 0x55;
aec_hdl->inref_bulk[i].len = len;
list_add_tail(&aec_hdl->inref_bulk[i].entry, &aec_hdl->inref_head);
} else {
printf(">>>aec_inref_full\n");
/*align reset*/
if (aec_hdl->output_way == 0) {
audio_dac_read_reset();
}
struct mic_bulk *bulk;
list_for_each_entry(bulk, &aec_hdl->inref_head, entry) {
bulk->used = 0;
__list_del_entry(&bulk->entry);
}
return;
}
}
}
/*
*********************************************************************
* Audio AEC Input Reference
* Description: AEC源参考数据输入
* Arguments : buf 输入源数据地址
* len 输入源数据长度
* Return : None.
* Note(s) : 双mic ENC的参考mic数据输入,单mic的无须调用该接口
*********************************************************************
*/
void audio_aec_inbuf_ref_1(s16 *buf, u16 len)
{
if (aec_hdl && aec_hdl->start) {
if (aec_hdl->output_way == 1) {
if ((aec_hdl->ref_ok == 0) || (aec_hdl->fm_tx_start == 0)) {
if (aec_hdl->ref_ok && !aec_hdl->fm_tx_start) {
printf("[aec]fm_tx_start == 0\n");
}
return;
}
}
int i = 0;
for (i = 0; i < MIC_BULK_MAX; i++) {
if (aec_hdl->inref_1_bulk[i].used == 0) {
break;
}
}
if (i < MIC_BULK_MAX) {
aec_hdl->inref_1_bulk[i].addr = buf;
aec_hdl->inref_1_bulk[i].used = 0x55;
aec_hdl->inref_1_bulk[i].len = len;
list_add_tail(&aec_hdl->inref_1_bulk[i].entry, &aec_hdl->inref_1_head);
} else {
printf(">>>aec_inref_1_full\n");
/*align reset*/
struct mic_bulk *bulk;
list_for_each_entry(bulk, &aec_hdl->inref_1_head, entry) {
bulk->used = 0;
__list_del_entry(&bulk->entry);
}
return;
}
}
}
/*
*********************************************************************
* Audio AEC Reference
* Description: AEC模块参考数据输入
* Arguments : buf 输入参考数据地址
* len 输入参考数据长度
* Return : None.
* Note(s) : 声卡设备是DAC,默认不用外部提供参考数据
*********************************************************************
*/
void audio_aec_far_refbuf(s16 *buf, u16 len);
void audio_aec_refbuf(s16 *data0, s16 *data1, u16 len)
{
if (aec_hdl && aec_hdl->start) {
if ((aec_hdl != NULL) && (aec_hdl->adc_ref_en == 1) && (aec_hdl->output_way == 0)) {
/*使用adc回采时*/
if (data0) {
audio_aec_far_refbuf(data0, len);
}
return;
}
/*使用外部参考数据时*/
if (aec_hdl->output_way != 1) {
return;
}
aec_hdl->ref_busy = 1;
aec_hdl->ref_ok = 1;
if (0 == cbuf_write(aec_ref_cbuf, data0, len)) {
printf("aec wfail:%d\n", len);
}
#if 1
static u16 aec_ref_max = 0;
if (aec_ref_max < aec_ref_cbuf->data_len) {
aec_ref_max = aec_ref_cbuf->data_len;
printf("aec_ref_max:%d\n", aec_ref_max);
}
#endif
if (!list_empty(&aec_hdl->in_head) && (aec_ref_cbuf->data_len >= aec_hdl->ref_size)) {
os_sem_set(&aec_hdl->sem, 0);
os_sem_post(&aec_hdl->sem);
}
aec_hdl->ref_busy = 0;
}
}
/*adc ref0*/
void audio_aec_far_refbuf(s16 *buf, u16 len)
{
u16 wlen;
u8 i;
int err = 0;
if ((aec_hdl == NULL) || (aec_hdl->adc_ref_en == 0) || (aec_hdl->output_way == 1)) {
return;
}
#if 0
/*AEC暂时挂起,有其他功能要做,比如播题示音,这个时候不用做AEC*/
if ((aec->state & AEC_STATE_SUSPEND) || (aec->state & AEC_STATE_RESET)) {
return err;
}
#endif
//AEC_D("A:%d\n", len);
for (i = 0; i < MIC_BULK_MAX; i++) {
if (aec_hdl->ref0_bulk[i].used == 0) {
break;
}
}
if (i < MIC_BULK_MAX) {
//AEC_D("bulk:%d-%d\n",i,len);
aec_hdl->ref0_bulk[i].addr = buf;
aec_hdl->ref0_bulk[i].used = 0x55;
aec_hdl->ref0_bulk[i].len = len;
list_add_tail(&aec_hdl->ref0_bulk[i].entry, &aec_hdl->ref0_head);
} else {
printf(">>>aec_in_ref0_full\n");
/*align reset*/
struct mic_bulk *bulk;
list_for_each_entry(bulk, &aec_hdl->ref0_head, entry) {
bulk->used = 0;
__list_del_entry(&bulk->entry);
}
return;
}
}
/*
*********************************************************************
* Audio AEC Output Sel
* Description: AEC输出数据选择
* Arguments : sel 选择输出/算法输出/talk/ff/fb原始数据
* agc NULL
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_aec_output_sel(u8 sel, u8 agc)
{
if (aec_hdl) {
aec_hdl->output_sel = sel;
}
}
/*
*********************************************************************
* 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) {
aec_hdl->output_sel = (toggle) ? 0 : 1;
return 0;
}
return 1;
}
/*
*********************************************************************
* Audio CVP IOCTL
* Description: CVP功能配置
* Arguments : cmd 操作命令
* value 操作数
* priv 操作内存地址
* Return : 0 成功 其他 失败
* Note(s) : (1)比如动态开关降噪NS模块:
*********************************************************************
*/
int audio_cvp_ioctl(int cmd, int value, void *priv)
{
return -1;
}
#endif /*TCFG_CVP_DEVELOP_ENABLE*/