#include "asm/includes.h" #include "media/includes.h" #include "system/includes.h" #include "app_config.h" #include "circular_buf.h" #include "audio_iis.h" #include "audio_link.h" #define IIS_DEBUG_ENABLE 1 #if IIS_DEBUG_ENABLE #define iis_debug printf #else #define iis_debug(...) #endif #if (TCFG_IIS_ENABLE && TCFG_IIS_OUTPUT_EN) #define IIS_TX_BUF_LEN (4*1024) struct _iis_output { u32 in_sample_rate; u32 out_sample_rate; cbuffer_t cbuf; u8 buf[IIS_TX_BUF_LEN]; struct audio_src_handle *hw_src; struct audio_stream_entry entry; int sr_cal_timer; u32 points_total; u16 cnt_total; u8 ch : 4; u8 flag : 1; u8 need_resume : 1; } *iis_output_hdl = NULL; static u32 iis_srI_last = 0; static int audio_stream_iis_data_handler(struct audio_stream_entry *entry, struct audio_data_frame *in, struct audio_data_frame *out) { if (iis_srI_last != in->sample_rate) { iis_debug("in:%d ---%d\n", iis_srI_last, in->sample_rate); audio_iis_output_set_srI(in->sample_rate); } u32 len = audio_iis_output_write(in->data, in->data_len); if (len != in->data_len) { local_irq_disable(); iis_output_hdl->need_resume = 1; local_irq_enable(); } return len; } static void audio_stream_iis_data_clear(struct audio_stream_entry *entry) { cbuf_clear(&(iis_output_hdl->cbuf)); iis_debug("iis clear\n"); } static void audio_iis_src_irq_cb(void *hdl) { if (iis_output_hdl) { audio_stream_resume(&(iis_output_hdl->entry)); } } int audio_iis_src_output_handler(void *parm, s16 *data, int len) { int wlen = iis_output_hdl->cbuf.total_len - iis_output_hdl->cbuf.data_len; if (wlen > len) { wlen = len; } wlen = cbuf_write(&(iis_output_hdl->cbuf), data, wlen); if (wlen != len) { local_irq_disable(); iis_output_hdl->need_resume = 1; local_irq_enable(); } return wlen; } int audio_iis_output_write(s16 *data, u32 len) { u32 wlen = 0; if (iis_output_hdl) { if (iis_output_hdl->hw_src) { wlen = audio_src_resample_write(iis_output_hdl->hw_src, data, len); } else { wlen = iis_output_hdl->cbuf.total_len - iis_output_hdl->cbuf.data_len; if (wlen > len) { wlen = len; } wlen = cbuf_write(&(iis_output_hdl->cbuf), data, len); } if (wlen != len) { local_irq_disable(); iis_output_hdl->need_resume = 1; local_irq_enable(); } } return wlen; } void audio_iis_tx_isr(u8 idx, s16 *data, u32 len) { u32 wlen = 0; u32 rlen = 0; if (iis_output_hdl) { local_irq_disable(); if (iis_output_hdl->need_resume) { iis_output_hdl->need_resume = 0; local_irq_enable(); audio_stream_resume(&(iis_output_hdl->entry)); } else { local_irq_enable(); } iis_output_hdl->points_total += len >> 2; rlen = cbuf_get_data_len(&(iis_output_hdl->cbuf)); if ((iis_output_hdl->flag == 0) && (rlen < (IIS_TX_BUF_LEN / 2))) { memset(data, 0x00, len); return; } iis_output_hdl->flag = 1; if (rlen >= len) { wlen = cbuf_read(&(iis_output_hdl->cbuf), data, len); } else { iis_debug("iis end\n"); wlen = cbuf_read(&(iis_output_hdl->cbuf), data, rlen); memset((u8 *)data + rlen, 0x00, len - rlen); iis_output_hdl->flag = 0; } } } void audio_iis_sr_cal_timer(void *param) { if (iis_output_hdl) { if (iis_output_hdl->cnt_total == 0) { iis_output_hdl->points_total = iis_output_hdl->in_sample_rate; } iis_output_hdl->cnt_total++; iis_output_hdl->out_sample_rate = iis_output_hdl->points_total / iis_output_hdl->cnt_total; if ((iis_output_hdl->points_total > 0xFFF00000) \ && ((iis_output_hdl->cnt_total % 2) == 0)) { iis_output_hdl->points_total >>= 1; iis_output_hdl->cnt_total >>= 1; } if (iis_output_hdl->hw_src && iis_output_hdl->out_sample_rate) { /* iis_debug("iis cal:%d > %d\n", \ */ /* iis_output_hdl->in_sample_rate, \ */ /* iis_output_hdl->out_sample_rate); */ audio_hw_src_set_rate(iis_output_hdl->hw_src, \ iis_output_hdl->in_sample_rate, \ iis_output_hdl->out_sample_rate); } } } void audio_iis_output_set_srI(u32 sample_rate) { iis_debug("audio_iis_output_set_srI %d\n", sample_rate); iis_srI_last = sample_rate; if (iis_output_hdl) { iis_output_hdl->points_total = 0; iis_output_hdl->cnt_total = 0; iis_output_hdl->in_sample_rate = sample_rate; if (iis_output_hdl->hw_src) { iis_debug("iis set:%d > %d\n", \ iis_output_hdl->in_sample_rate, \ iis_output_hdl->out_sample_rate); audio_hw_src_set_rate(iis_output_hdl->hw_src, \ iis_output_hdl->in_sample_rate, \ iis_output_hdl->out_sample_rate); } } } void *audio_iis_output_start(u8 ch) { if (iis_output_hdl == NULL) { iis_debug("audio_iis_output_start\n"); mem_stats(); iis_output_hdl = zalloc(sizeof(struct _iis_output)); if (iis_output_hdl == NULL) { iis_debug("audio_iis_output_start malloc err !\n"); return NULL; } /* clk_set("sys", 96 * 1000000L); */ /* clk_set_en(0); */ cbuf_init(&(iis_output_hdl->cbuf), iis_output_hdl->buf, IIS_TX_BUF_LEN); iis_output_hdl->in_sample_rate = iis_srI_last; iis_output_hdl->out_sample_rate = TCFG_IIS_OUTPUT_SR; iis_output_hdl->ch = ch; iis_output_hdl->sr_cal_timer = sys_hi_timer_add(NULL, audio_iis_sr_cal_timer, 1000); iis_output_hdl->hw_src = zalloc(sizeof(struct audio_src_handle)); if (iis_output_hdl->hw_src) { audio_hw_src_open(iis_output_hdl->hw_src, 2, SRC_TYPE_RESAMPLE); audio_hw_src_set_rate(iis_output_hdl->hw_src, \ iis_output_hdl->in_sample_rate, \ iis_output_hdl->out_sample_rate); iis_debug("audio iis rate:%d -> %d\n", \ iis_output_hdl->in_sample_rate, \ iis_output_hdl->out_sample_rate); audio_src_set_output_handler(iis_output_hdl->hw_src, NULL, audio_iis_src_output_handler); audio_src_set_rise_irq_handler(iis_output_hdl->hw_src, NULL, audio_iis_src_irq_cb); } else { iis_debug("hw_src malloc err ==============\n"); } audio_link_init(); alink_channel_init(ch, ALINK_DIR_TX, audio_iis_tx_isr); iis_output_hdl->entry.data_handler = audio_stream_iis_data_handler; iis_output_hdl->entry.data_clear = audio_stream_iis_data_clear; /* mem_stats(); */ return (&(iis_output_hdl->entry)); } return NULL; } void audio_iis_output_stop() { iis_debug("audio_iis_output_stop\n"); if (iis_output_hdl) { alink_channel_close(iis_output_hdl->ch); audio_link_uninit(); if (iis_output_hdl->sr_cal_timer) { sys_hi_timer_del(iis_output_hdl->sr_cal_timer); } if (iis_output_hdl->hw_src) { audio_hw_src_stop(iis_output_hdl->hw_src); audio_hw_src_close(iis_output_hdl->hw_src); free(iis_output_hdl->hw_src); iis_output_hdl->hw_src = NULL; } free(iis_output_hdl); iis_output_hdl = NULL; /* clk_set_en(1); */ } } #endif