#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*/