KT25-0812_82A-UART/cpu/br25/audio_common/audio_iis.c

261 lines
7.7 KiB
C
Raw Normal View History

2025-08-12 10:09:23 +00:00
#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