#ifdef SUPPORT_MS_EXTENSIONS #pragma bss_seg(".audio_cvp_ref_task.data.bss") #pragma data_seg(".audio_cvp_ref_task.data") #pragma const_seg(".audio_cvp_ref_task.text.const") #pragma code_seg(".audio_cvp_ref_task.text") #endif /* **************************************************************** * AUDIO CVP REF SRC * File : audio_cvp_ref_src.c * By : * Notes : CVP回音消除的外部参考数变采样 * **************************************************************** */ #include "audio_cvp.h" #include "system/includes.h" #include "media/includes.h" #include "circular_buf.h" #include "Resample_api.h" #include "media/audio_general.h" #include "effects/convert_data.h" #include "jlstream.h" #include "esco_player.h" #include "pc_spk_player.h" #define CVP_REF_SRC_TASK_NAME "CVP_RefTask" #define ALINK_CH_IDX 0 //iis输出使用的通道 #define CVP_REF_SRC_FRAME_SIZE (480 * 2)//512 typedef struct { volatile u8 state; volatile u8 busy; RS_STUCT_API *sw_src_api; u32 *sw_src_buf; u16 input_rate; u16 output_rate; u8 channel; s16 *ref_tmp_buf; cbuffer_t cbuf; u8 ref_buf[2048 * 10];//和输入的数据大小有关系 u8 align_flag; u8 bit_width; u8 data_multiple;//输入输出数据倍数 } cvp_ref_src_t; static cvp_ref_src_t *cvp_ref_src = NULL; extern void iis_node_write_callback_add(const char *name, u8 is_after_write_over, u8 scene, void (*cb)(void *, int)); extern void iis_node_write_callback_del(const char *name); #define IIS_READ_MAGIC 0x55AA static int iis_read_pos = IIS_READ_MAGIC; /*获取iis dma里面还有多少数据没有播放*/ static u32 get_alink_data_len(u8 ch_idx) { u32 len = 0; switch (ch_idx) { case 0: len = (JL_ALNK0->LEN - JL_ALNK0->SHN0) * 4; break; case 1: len = (JL_ALNK0->LEN - JL_ALNK0->SHN1) * 4; break; case 2: len = (JL_ALNK0->LEN - JL_ALNK0->SHN2) * 4; break; case 3: len = (JL_ALNK0->LEN - JL_ALNK0->SHN3) * 4; break; } return len; } /*iis硬件写指针位置*/ static u32 get_alink_hwptr(u8 ch_idx) { u32 val = 0; switch (ch_idx) { case 0: val = JL_ALNK0->HWPTR0; break; case 1: val = JL_ALNK0->HWPTR1; break; case 2: val = JL_ALNK0->HWPTR2; break; case 3: val = JL_ALNK0->HWPTR3; break; } return val; } /*重新对齐iis延时*/ int audio_cvp_ref_data_align_reset(void) { iis_read_pos = IIS_READ_MAGIC; cvp_ref_src_t *hdl = cvp_ref_src; if (hdl) { hdl->align_flag = 0; cbuf_clear(&hdl->cbuf); } return 0; } /*对齐iis的数据延时,在第一次mic数据来时调用对齐*/ void audio_cvp_ref_data_align() { cvp_ref_src_t *hdl = cvp_ref_src; /* !iis_read_pos : iis有数据了才么开始对齐 !hdl->align_flag : 表示还没有做对齐*/ if (hdl && !hdl->align_flag && !iis_read_pos) { int iis_data_len = get_alink_data_len(ALINK_CH_IDX); int cbuf_total_len = cbuf_get_data_len(&hdl->cbuf); printf("hdl->cbuf len %d ", cbuf_total_len); int need_read_len = cbuf_total_len - iis_data_len; printf("adc_iis_data_align: %d %d", iis_data_len, need_read_len); if (need_read_len >= 0) { cbuf_read_updata(&hdl->cbuf, need_read_len); } else { cbuf_write_updata(&hdl->cbuf, need_read_len * (-1)); } hdl->align_flag = 1; //有参考数据进来,并且对齐后,取消忽略参考数据 audio_cvp_ioctl(CVP_OUTWAY_REF_IGNORE, 0, NULL); } } static void audio_cvp_ref_src_run(s16 *data, int len) { cvp_ref_src_t *hdl = cvp_ref_src; u16 ref_len = len; if (hdl) { if (hdl->bit_width) { audio_convert_data_32bit_to_16bit_round((s32 *)data, (s16 *)data, ref_len >> 2); ref_len >>= 1; } if (hdl->channel == 2) { /* putchar('2'); */ /*双变单*/ for (int i = 0; i < (ref_len >> 2); i++) { data[i] = ((int)data[2 * i] + (int)data[2 * i + 1]) / 2; } ref_len >>= 1; } if (hdl->sw_src_api) { /* putchar('s'); */ ref_len = hdl->sw_src_api->run(hdl->sw_src_buf, data, ref_len >> 1, data); ref_len <<= 1; } /* printf("ref_len %d : %d", ref_len, len); */ audio_aec_refbuf(data, NULL, ref_len); } } static void audio_cvp_ref_src_task(void *p) { int msg[16]; cvp_ref_src_t *hdl = NULL; while (1) { os_taskq_pend("taskq", msg, ARRAY_SIZE(msg)); hdl = cvp_ref_src; if (hdl && hdl->state) { s16 *data = (s16 *)msg[1]; int len = msg[2]; /* putchar('r'); */ hdl->busy = 1; int cbuf_data_len = cbuf_get_data_len(&hdl->cbuf); /*判断cbuf的缓存够一帧数据,并且参考数据可写长度大于1帧时*/ while (cbuf_data_len >= CVP_REF_SRC_FRAME_SIZE && (get_audio_cvp_output_way_writable_len() * hdl->data_multiple) >= CVP_REF_SRC_FRAME_SIZE) { cbuf_data_len -= CVP_REF_SRC_FRAME_SIZE; cbuf_read(&hdl->cbuf, hdl->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE); audio_cvp_ref_src_run((s16 *)hdl->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE); } hdl->busy = 0; } } } int audio_cvp_ref_src_data_fill(void *p, s16 *data, int len) { cvp_ref_src_t *hdl = cvp_ref_src; int ret = 0; if ((!esco_player_runing() #if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE && !pc_spk_player_runing() #endif ) || (len == 0)) { return 0; } if (hdl && hdl->state) { if (0 == cbuf_write(&hdl->cbuf, data, len) && hdl->align_flag) { cbuf_clear(&hdl->cbuf); hdl->align_flag = 0; printf("ref src cbuf wfail!!"); } if (hdl->align_flag) { if (cbuf_get_data_len(&hdl->cbuf) >= CVP_REF_SRC_FRAME_SIZE) { ret = os_taskq_post_msg(CVP_REF_SRC_TASK_NAME, 2, (int)data, len); } } } return ret; } static void iis_write_callback(void *data, int len) { cvp_ref_src_t *hdl = cvp_ref_src; if (hdl) { if (iis_read_pos == IIS_READ_MAGIC) { u32 iis_hwptr = get_alink_hwptr(ALINK_CH_IDX); if (iis_hwptr) { iis_read_pos = 0; printf("JL_ALNK HWPTR %d, data_len %d", iis_hwptr, len); } } if (iis_read_pos == 0) { if (esco_player_runing() #if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE || pc_spk_player_runing() #endif ) { audio_cvp_ref_start(1); } } audio_cvp_ref_src_data_fill(NULL, data, len); } } /* ********************************************************************* * Audio CVP Ref Src * Description: 打开外部参考数据变采样 * Arguments : scene 场景 * insr 输入采样率 * outsr 输出采样率 * nch 输入数据的通道数 * Return : None. * Note(s) : 声卡设备是DAC,默认不用外部提供参考数据 ********************************************************************* */ int audio_cvp_ref_src_open(u8 scene, u32 insr, u32 outsr, u8 nch) { printf("audio_cvp_ref_src_open"); if (cvp_ref_src) { printf("aec_ref_src alreadly open !!!"); return -1; } cvp_ref_src_t *hdl = zalloc(sizeof(cvp_ref_src_t)); if (hdl == NULL) { printf("aec_ref_src malloc fail !!!"); return -1; } cbuf_init(&hdl->cbuf, hdl->ref_buf, sizeof(hdl->ref_buf)); int err = task_create(audio_cvp_ref_src_task, NULL, CVP_REF_SRC_TASK_NAME); if (err != OS_NO_ERR) { printf("task create error!"); free(hdl); hdl = NULL; return -1; } audio_cvp_set_output_way(1); iis_node_write_callback_add(CVP_REF_SRC_TASK_NAME, 1, scene, iis_write_callback); hdl->input_rate = insr; hdl->output_rate = outsr; hdl->channel = nch; hdl->bit_width = audio_general_out_dev_bit_width(); hdl->sw_src_api = get_rs16_context(); printf("sw_src_api:0x%x\n", (int)(hdl->sw_src_api)); ASSERT(hdl->sw_src_api); int sw_src_need_buf = hdl->sw_src_api->need_buf(); printf("sw_src_buf:%d\n", sw_src_need_buf); hdl->sw_src_buf = zalloc(sw_src_need_buf); ASSERT(hdl->sw_src_buf, "sw_src_buf zalloc fail"); RS_PARA_STRUCT rs_para_obj; rs_para_obj.nch = 1; rs_para_obj.dataTypeobj.IndataBit = 0; rs_para_obj.dataTypeobj.OutdataBit = 0; rs_para_obj.dataTypeobj.IndataInc = 1; rs_para_obj.dataTypeobj.OutdataInc = 1; rs_para_obj.dataTypeobj.Qval = 15; int multiple_cnt;//倍数 if ((insr % 8000) == 0) { multiple_cnt = insr / 8000; rs_para_obj.new_insample = 6250; if (outsr == 16000) { //48k->16k rs_para_obj.new_outsample = 2080 * (6 / multiple_cnt); } else { //48k->8k rs_para_obj.new_outsample = (2080 / 2) * (6 / multiple_cnt); } } else { multiple_cnt = insr / 11025; rs_para_obj.new_insample = 12000; if (outsr == 16000) { //44.1k->16k rs_para_obj.new_outsample = (17 * 256) * (4 / multiple_cnt); } else { //44.1k->8k rs_para_obj.new_outsample = (17 * 256 / 2) * (4 / multiple_cnt); } } printf("sw src,ch = %d, in = %d,out = %d\n", rs_para_obj.nch, rs_para_obj.new_insample, rs_para_obj.new_outsample); hdl->sw_src_api->open(hdl->sw_src_buf, &rs_para_obj); hdl->data_multiple = (insr / outsr) * nch * (1 << hdl->bit_width); printf("indata nch %d, bitw %d, data_multiple %d", hdl->channel, hdl->bit_width, hdl->data_multiple); hdl->ref_tmp_buf = zalloc(CVP_REF_SRC_FRAME_SIZE); audio_cvp_ref_data_align_reset(); hdl->state = 1; cvp_ref_src = hdl; return 0; } void audio_cvp_ref_src_close() { cvp_ref_src_t *hdl = cvp_ref_src; if (hdl) { hdl->state = 0; while (hdl->busy) { putchar('w'); os_time_dly(2); } int err = task_kill(CVP_REF_SRC_TASK_NAME); if (err) { printf("kill task %s: err=%d\n", CVP_REF_SRC_TASK_NAME, err); } iis_node_write_callback_del(CVP_REF_SRC_TASK_NAME); if (hdl->sw_src_api) { hdl->sw_src_api = NULL; } if (hdl->sw_src_buf) { free(hdl->sw_src_buf); hdl->sw_src_buf = NULL; } if (hdl->ref_tmp_buf) { free(hdl->ref_tmp_buf); hdl->ref_tmp_buf = NULL; } free(hdl); hdl = NULL; cvp_ref_src = NULL; } }