265 lines
8.1 KiB
C
265 lines
8.1 KiB
C
|
|
#include "asm/includes.h"
|
||
|
|
#include "media/includes.h"
|
||
|
|
#include "system/includes.h"
|
||
|
|
#include "app_config.h"
|
||
|
|
#include "circular_buf.h"
|
||
|
|
#include "audio_fmtx.h"
|
||
|
|
#include "fm_emitter/fm_emitter_manage.h"
|
||
|
|
|
||
|
|
#if (TCFG_APP_FM_EMITTER_EN)
|
||
|
|
|
||
|
|
#define FMTX_DEBUG_ENABLE 1
|
||
|
|
#if FMTX_DEBUG_ENABLE
|
||
|
|
#define fmtx_debug printf
|
||
|
|
#else
|
||
|
|
#define fmtx_debug(...)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define FMTX_TX_BUF_LEN (4*1024)
|
||
|
|
struct _fmtx_output {
|
||
|
|
u32 in_sample_rate;
|
||
|
|
u32 out_sample_rate;
|
||
|
|
cbuffer_t cbuf;
|
||
|
|
u8 buf[FMTX_TX_BUF_LEN];
|
||
|
|
struct audio_src_handle *hw_src;
|
||
|
|
struct audio_stream_entry entry;
|
||
|
|
int sr_cal_timer;
|
||
|
|
u32 points_total;
|
||
|
|
u32 cnt_total;
|
||
|
|
u8 ch : 4;
|
||
|
|
u8 flag : 1;
|
||
|
|
u8 need_resume : 1;
|
||
|
|
} *fmtx_output_hdl = NULL;
|
||
|
|
|
||
|
|
static u32 fmtx_srI_last = 0;
|
||
|
|
|
||
|
|
|
||
|
|
static int audio_stream_fmtx_data_handler(struct audio_stream_entry *entry, struct audio_data_frame *in, struct audio_data_frame *out)
|
||
|
|
|
||
|
|
{
|
||
|
|
|
||
|
|
if (fmtx_srI_last != in->sample_rate) {
|
||
|
|
fmtx_debug("in:%d ---%d\n", fmtx_srI_last, in->sample_rate);
|
||
|
|
audio_fmtx_output_set_srI(in->sample_rate);
|
||
|
|
}
|
||
|
|
|
||
|
|
u32 len = audio_fmtx_output_write(in->data, in->data_len);
|
||
|
|
if (len != in->data_len) {
|
||
|
|
local_irq_disable();
|
||
|
|
fmtx_output_hdl->need_resume = 1;
|
||
|
|
local_irq_enable();
|
||
|
|
}
|
||
|
|
return len;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void audio_stream_fmtx_data_clear(struct audio_stream_entry *entry)
|
||
|
|
{
|
||
|
|
cbuf_clear(&(fmtx_output_hdl->cbuf));
|
||
|
|
fmtx_debug("fmtx clear\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
static void audio_fmtx_src_irq_cb(void *hdl)
|
||
|
|
{
|
||
|
|
if (fmtx_output_hdl) {
|
||
|
|
audio_stream_resume(&(fmtx_output_hdl->entry));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int audio_fmtx_src_output_handler(void *parm, s16 *data, int len)
|
||
|
|
{
|
||
|
|
int wlen = fmtx_output_hdl->cbuf.total_len - fmtx_output_hdl->cbuf.data_len;
|
||
|
|
if (wlen > len) {
|
||
|
|
wlen = len;
|
||
|
|
}
|
||
|
|
wlen = cbuf_write(&(fmtx_output_hdl->cbuf), data, wlen);
|
||
|
|
if (wlen != len) {
|
||
|
|
local_irq_disable();
|
||
|
|
fmtx_output_hdl->need_resume = 1;
|
||
|
|
local_irq_enable();
|
||
|
|
}
|
||
|
|
return wlen;
|
||
|
|
}
|
||
|
|
|
||
|
|
s16 ref_temp_buf[256];
|
||
|
|
int audio_fmtx_output_write(s16 *data, u32 len)
|
||
|
|
{
|
||
|
|
u32 wlen = 0;
|
||
|
|
if (fmtx_output_hdl) {
|
||
|
|
if (fmtx_output_hdl->hw_src) {
|
||
|
|
wlen = audio_src_resample_write(fmtx_output_hdl->hw_src, data, len);
|
||
|
|
if (bt_phone_dec_is_running()) {
|
||
|
|
for (int i = 0; i < (len >> 2); i++) {
|
||
|
|
ref_temp_buf[i] = data[2 * i] / 2 + data[2 * i + 1] / 2;
|
||
|
|
}
|
||
|
|
if (wlen) {
|
||
|
|
audio_aec_refbuf(ref_temp_buf, wlen / 2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} else {
|
||
|
|
wlen = fmtx_output_hdl->cbuf.total_len - fmtx_output_hdl->cbuf.data_len;
|
||
|
|
if (wlen > len) {
|
||
|
|
wlen = len;
|
||
|
|
}
|
||
|
|
wlen = cbuf_write(&(fmtx_output_hdl->cbuf), data, len);
|
||
|
|
}
|
||
|
|
if (wlen != len) {
|
||
|
|
local_irq_disable();
|
||
|
|
fmtx_output_hdl->need_resume = 1;
|
||
|
|
local_irq_enable();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return wlen;
|
||
|
|
}
|
||
|
|
void audio_fmtx_tx_isr(s16 *data, u32 len)
|
||
|
|
{
|
||
|
|
u32 wlen = 0;
|
||
|
|
u32 rlen = 0;
|
||
|
|
if (fmtx_output_hdl) {
|
||
|
|
local_irq_disable();
|
||
|
|
if (fmtx_output_hdl->need_resume) {
|
||
|
|
fmtx_output_hdl->need_resume = 0;
|
||
|
|
local_irq_enable();
|
||
|
|
audio_stream_resume(&(fmtx_output_hdl->entry));
|
||
|
|
} else {
|
||
|
|
local_irq_enable();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
fmtx_output_hdl->points_total += len >> 2;
|
||
|
|
|
||
|
|
rlen = cbuf_get_data_len(&(fmtx_output_hdl->cbuf));
|
||
|
|
if ((fmtx_output_hdl->flag == 0) && (rlen < (FMTX_TX_BUF_LEN / 2))) {
|
||
|
|
memset(data, 0x00, len);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
fmtx_output_hdl->flag = 1;
|
||
|
|
|
||
|
|
if (rlen >= len) {
|
||
|
|
wlen = cbuf_read(&(fmtx_output_hdl->cbuf), data, len);
|
||
|
|
} else {
|
||
|
|
fmtx_debug("fmtx end\n");
|
||
|
|
wlen = cbuf_read(&(fmtx_output_hdl->cbuf), data, rlen);
|
||
|
|
memset((u8 *)data + rlen, 0x00, len - rlen);
|
||
|
|
fmtx_output_hdl->flag = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void audio_fmtx_sr_cal_timer(void *param)
|
||
|
|
{
|
||
|
|
if (fmtx_output_hdl) {
|
||
|
|
if (fmtx_output_hdl->cnt_total == 0) {
|
||
|
|
fmtx_output_hdl->points_total = fmtx_output_hdl->out_sample_rate * 1000;
|
||
|
|
fmtx_output_hdl->cnt_total = 999;
|
||
|
|
}
|
||
|
|
fmtx_output_hdl->cnt_total++;
|
||
|
|
fmtx_output_hdl->out_sample_rate = fmtx_output_hdl->points_total / fmtx_output_hdl->cnt_total;
|
||
|
|
|
||
|
|
if ((fmtx_output_hdl->points_total > 0xFFF00000) \
|
||
|
|
&& ((fmtx_output_hdl->cnt_total % 2) == 0)) {
|
||
|
|
fmtx_output_hdl->points_total >>= 1;
|
||
|
|
fmtx_output_hdl->cnt_total >>= 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if (fmtx_output_hdl->hw_src && fmtx_output_hdl->out_sample_rate) {
|
||
|
|
/* fmtx_debug("fmtx cal:%d > %d\n", \ */
|
||
|
|
/* fmtx_output_hdl->in_sample_rate, \ */
|
||
|
|
/* fmtx_output_hdl->out_sample_rate); */
|
||
|
|
audio_hw_src_set_rate(fmtx_output_hdl->hw_src, \
|
||
|
|
fmtx_output_hdl->in_sample_rate, \
|
||
|
|
fmtx_output_hdl->out_sample_rate);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void audio_fmtx_output_set_srI(u32 sample_rate)
|
||
|
|
{
|
||
|
|
fmtx_debug("audio_fmtx_output_set_srI %d\n", sample_rate);
|
||
|
|
fmtx_srI_last = sample_rate;
|
||
|
|
if (fmtx_output_hdl) {
|
||
|
|
fmtx_output_hdl->points_total = 0;
|
||
|
|
fmtx_output_hdl->cnt_total = 0;
|
||
|
|
fmtx_output_hdl->in_sample_rate = sample_rate;
|
||
|
|
if (fmtx_output_hdl->hw_src) {
|
||
|
|
fmtx_debug("fmtx set:%d > %d\n", \
|
||
|
|
fmtx_output_hdl->in_sample_rate, \
|
||
|
|
fmtx_output_hdl->out_sample_rate);
|
||
|
|
audio_hw_src_set_rate(fmtx_output_hdl->hw_src, \
|
||
|
|
fmtx_output_hdl->in_sample_rate, \
|
||
|
|
fmtx_output_hdl->out_sample_rate);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void *audio_fmtx_output_start(u16 fre)
|
||
|
|
{
|
||
|
|
if (fmtx_output_hdl == NULL) {
|
||
|
|
fmtx_debug("audio_fmtx_output_start\n");
|
||
|
|
mem_stats();
|
||
|
|
fmtx_output_hdl = zalloc(sizeof(struct _fmtx_output));
|
||
|
|
if (fmtx_output_hdl == NULL) {
|
||
|
|
fmtx_debug("audio_fmtx_output_start malloc err !\n");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
/* clk_set("sys", 96 * 1000000L); */
|
||
|
|
/* clk_set_en(0); */
|
||
|
|
cbuf_init(&(fmtx_output_hdl->cbuf), fmtx_output_hdl->buf, FMTX_TX_BUF_LEN);
|
||
|
|
|
||
|
|
fm_emitter_manage_init(fre, audio_fmtx_tx_isr);
|
||
|
|
fm_emitter_manage_start();
|
||
|
|
|
||
|
|
fmtx_output_hdl->in_sample_rate = fmtx_srI_last;
|
||
|
|
fmtx_output_hdl->out_sample_rate = 41667;
|
||
|
|
fmtx_output_hdl->sr_cal_timer = sys_s_hi_timer_add(NULL, audio_fmtx_sr_cal_timer, 1000);
|
||
|
|
|
||
|
|
fmtx_output_hdl->hw_src = zalloc(sizeof(struct audio_src_handle));
|
||
|
|
if (fmtx_output_hdl->hw_src) {
|
||
|
|
audio_hw_src_open(fmtx_output_hdl->hw_src, 2, SRC_TYPE_RESAMPLE);
|
||
|
|
audio_hw_src_set_rate(fmtx_output_hdl->hw_src, \
|
||
|
|
fmtx_output_hdl->in_sample_rate, \
|
||
|
|
fmtx_output_hdl->out_sample_rate);
|
||
|
|
fmtx_debug("audio fmtx rate:%d -> %d\n", \
|
||
|
|
fmtx_output_hdl->in_sample_rate, \
|
||
|
|
fmtx_output_hdl->out_sample_rate);
|
||
|
|
audio_src_set_output_handler(fmtx_output_hdl->hw_src, NULL, audio_fmtx_src_output_handler);
|
||
|
|
audio_src_set_rise_irq_handler(fmtx_output_hdl->hw_src, NULL, audio_fmtx_src_irq_cb);
|
||
|
|
} else {
|
||
|
|
fmtx_debug("hw_src malloc err ==============\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
fmtx_output_hdl->entry.data_handler = audio_stream_fmtx_data_handler;
|
||
|
|
fmtx_output_hdl->entry.data_clear = audio_stream_fmtx_data_clear;
|
||
|
|
/* mem_stats(); */
|
||
|
|
return (&(fmtx_output_hdl->entry));
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
void audio_fmtx_output_stop()
|
||
|
|
{
|
||
|
|
fmtx_debug("audio_fmtx_output_stop\n");
|
||
|
|
if (fmtx_output_hdl) {
|
||
|
|
fm_emitter_manage_stop();
|
||
|
|
|
||
|
|
if (fmtx_output_hdl->sr_cal_timer) {
|
||
|
|
sys_s_hi_timer_del(fmtx_output_hdl->sr_cal_timer);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fmtx_output_hdl->hw_src) {
|
||
|
|
audio_hw_src_stop(fmtx_output_hdl->hw_src);
|
||
|
|
audio_hw_src_close(fmtx_output_hdl->hw_src);
|
||
|
|
free(fmtx_output_hdl->hw_src);
|
||
|
|
fmtx_output_hdl->hw_src = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
free(fmtx_output_hdl);
|
||
|
|
fmtx_output_hdl = NULL;
|
||
|
|
/* clk_set_en(1); */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|