KT25-0812_82A-UART/cpu/br25/audio_dec/audio_dec_fm.c
2025-08-12 18:09:23 +08:00

668 lines
18 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
****************************************************************
*File : audio_dec_fm.c
*Note :
*
****************************************************************
*/
#include "asm/includes.h"
#include "media/includes.h"
#include "media/pcm_decoder.h"
#include "system/includes.h"
#include "effectrs_sync.h"
#include "application/audio_eq_drc_apply.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "app_config.h"
#include "app_main.h"
#include "audio_enc.h"
#include "audio_dec.h"
#include "clock_cfg.h"
#include "dev_manager.h"
#if TCFG_FM_ENABLE
//////////////////////////////////////////////////////////////////////////////
struct fm_dec_hdl {
struct audio_stream *stream; // 音频流
struct pcm_decoder pcm_dec; // pcm解码句柄
struct audio_res_wait wait; // 资源等待句柄
struct audio_mixer_ch mix_ch; // 叠加句柄
#if (RECORDER_MIX_EN)
struct audio_mixer_ch rec_mix_ch; // 叠加句柄
#endif/*RECORDER_MIX_EN*/
struct audio_eq_drc *eq_drc;//eq drc句柄
u32 id; // 唯一标识符,随机值
u32 start : 1; // 正在解码
u32 source : 8; // fm音频源
void *fm; // 底层驱动句柄
};
//////////////////////////////////////////////////////////////////////////////
struct fm_dec_hdl *fm_dec = NULL; // fm解码句柄
#if TCFG_FM_REC_EN
static u32 fm_enc_magic = 0; // fm录音id标记
#endif
//////////////////////////////////////////////////////////////////////////////
void *fm_eq_drc_open(u16 sample_rate, u8 ch_num);
void fm_eq_drc_close(struct audio_eq_drc *eq_drc);
int linein_sample_size(void *hdl);
int linein_sample_total(void *hdl);
//////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
/**@brief fm数据填充
@param *data: 数据
@param len: 数据长度
@return
@note
*/
/*----------------------------------------------------------------------------*/
void fm_sample_output_handler(s16 *data, int len)
{
struct fm_dec_hdl *dec = fm_dec;
if ((dec) && (dec->fm) && (dec->start)) {
fm_inside_output_handler(dec->fm, data, len);
}
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码释放
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void fm_dec_relaese(void)
{
if (fm_dec) {
audio_decoder_task_del_wait(&decode_task, &fm_dec->wait);
clock_remove(DEC_FM_CLK);
local_irq_disable();
free(fm_dec);
fm_dec = NULL;
local_irq_enable();
}
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码事件处理
@param *decoder: 解码器句柄
@param argc: 参数个数
@param *argv: 参数
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void fm_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
if (!fm_dec) {
log_i("fm_dec handle err ");
break;
}
if (fm_dec->id != argv[1]) {
log_w("fm_dec id err : 0x%x, 0x%x \n", fm_dec->id, argv[1]);
break;
}
fm_dec_close();
break;
}
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码数据输出
@param *entry: 音频流句柄
@param *in: 输入信息
@param *out: 输出信息
@return 输出长度
@note *out未使用
*/
/*----------------------------------------------------------------------------*/
static int fm_dec_data_handler(struct audio_stream_entry *entry,
struct audio_data_frame *in,
struct audio_data_frame *out)
{
struct audio_decoder *decoder = container_of(entry, struct audio_decoder, entry);
struct pcm_decoder *pcm_dec = container_of(decoder, struct pcm_decoder, decoder);
struct fm_dec_hdl *dec = container_of(pcm_dec, struct fm_dec_hdl, pcm_dec);
if (!dec->start) {
return 0;
}
audio_stream_run(&decoder->entry, in);
#if TCFG_FM_REC_EN
pcm2file_enc_write_pcm(dec->enc, in->data, decoder->process_len);
#endif
return decoder->process_len;
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码数据流激活
@param *p: 私有句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void fm_dec_out_stream_resume(void *p)
{
struct fm_dec_hdl *dec = p;
audio_decoder_resume(&dec->pcm_dec.decoder);
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码激活
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void fm_dec_resume(void)
{
if (fm_dec) {
audio_decoder_resume(&fm_dec->pcm_dec.decoder);
}
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码开始
@param
@return 0成功
@return 非0失败
@note
*/
/*----------------------------------------------------------------------------*/
int fm_dec_start(void)
{
int err;
struct fm_dec_hdl *dec = fm_dec;
struct audio_mixer *p_mixer = &mixer;
if (!fm_dec) {
return -EINVAL;
}
err = pcm_decoder_open(&dec->pcm_dec, &decode_task);
if (err) {
goto __err1;
}
// 打开fm驱动
dec->fm = fm_sample_open(dec->source, dec->pcm_dec.sample_rate);
linein_sample_set_resume_handler(dec->fm, fm_dec_resume);
pcm_decoder_set_event_handler(&dec->pcm_dec, fm_dec_event_handler, dec->id);
pcm_decoder_set_read_data(&dec->pcm_dec, linein_sample_read, dec->fm);
pcm_decoder_set_data_handler(&dec->pcm_dec, fm_dec_data_handler);
#if TCFG_PCM_ENC2TWS_ENABLE
{
// localtws
struct audio_fmt enc_f;
memcpy(&enc_f, &dec->pcm_dec.decoder.fmt, sizeof(struct audio_fmt));
enc_f.coding_type = AUDIO_CODING_SBC;
int ret = localtws_enc_api_open(&enc_f, LOCALTWS_ENC_FLAG_STREAM);
if (ret == true) {
dec->pcm_dec.dec_no_out_sound = 1;
// 重定向mixer
p_mixer = &g_localtws.mixer;
// 关闭资源等待。最终会在localtws解码处等待
audio_decoder_task_del_wait(&decode_task, &dec->wait);
}
}
#endif
if (!dec->pcm_dec.dec_no_out_sound) {
audio_mode_main_dec_open(AUDIO_MODE_MAIN_STATE_DEC_FM);
}
// 设置叠加功能
audio_mixer_ch_open_head(&dec->mix_ch, p_mixer);
audio_mixer_ch_set_no_wait(&dec->mix_ch, 1, 10); // 超时自动丢数
#if (RECORDER_MIX_EN)
audio_mixer_ch_open_head(&dec->rec_mix_ch, &recorder_mixer);
audio_mixer_ch_set_no_wait(&dec->rec_mix_ch, 1, 10); // 超时自动丢数
#endif/*RECORDER_MIX_EN*/
if (dec->pcm_dec.dec_no_out_sound) {
audio_mixer_ch_set_src(&dec->mix_ch, 1, 0);
#if (RECORDER_MIX_EN)
audio_mixer_ch_set_src(&dec->rec_mix_ch, 1, 0);
#endif/*RECORDER_MIX_EN*/
} else {
struct audio_mixer_ch_sync_info info = {0};
info.priv = dec->fm;
info.get_total = linein_sample_total;
info.get_size = linein_sample_size;
info.max_step = 200;
info.inc_step = 10;
info.dec_step = 10;
info.begin_per = 45;
info.top_per = 60;
info.bottom_per = 30;
audio_mixer_ch_set_sync(&dec->mix_ch, &info, 1, 1);
#if (RECORDER_MIX_EN)
audio_mixer_ch_set_sync(&dec->rec_mix_ch, &info, 1, 1);
#endif/*RECORDER_MIX_EN*/
}
dec->eq_drc = fm_eq_drc_open(dec->pcm_dec.sample_rate, dec->pcm_dec.output_ch_num);
// 数据流串联
struct audio_stream_entry *entries[8] = {NULL};
u8 entry_cnt = 0;
entries[entry_cnt++] = &dec->pcm_dec.decoder.entry;
#if TCFG_EQ_ENABLE && TCFG_FM_MODE_EQ_ENABLE
if (dec->eq_drc) {
entries[entry_cnt++] = &dec->eq_drc->entry;
}
#endif
entries[entry_cnt++] = &dec->mix_ch.entry;
dec->stream = audio_stream_open(dec, fm_dec_out_stream_resume);
audio_stream_add_list(dec->stream, entries, entry_cnt);
#if (RECORDER_MIX_EN)
audio_stream_add_entry(entries[entry_cnt - 2], &dec->rec_mix_ch.entry);
#endif/*RECORDER_MIX_EN*/
audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC);
dec->start = 1;
err = audio_decoder_start(&dec->pcm_dec.decoder);
if (err) {
goto __err3;
}
clock_set_cur();
return 0;
__err3:
dec->start = 0;
fm_eq_drc_close(dec->eq_drc);
if (dec->fm) {
local_irq_disable();
fm_sample_close(dec->fm, dec->source);
dec->fm = NULL;
local_irq_enable();
}
audio_mixer_ch_close(&dec->mix_ch);
#if (RECORDER_MIX_EN)
audio_mixer_ch_close(&dec->rec_mix_ch);
#endif/*RECORDER_MIX_EN*/
#if TCFG_PCM_ENC2TWS_ENABLE
if (dec->pcm_dec.dec_no_out_sound) {
dec->pcm_dec.dec_no_out_sound = 0;
localtws_enc_api_close();
}
#endif
if (dec->stream) {
audio_stream_close(dec->stream);
dec->stream = NULL;
}
pcm_decoder_close(&dec->pcm_dec);
__err1:
fm_dec_relaese();
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码关闭
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void __fm_dec_close(void)
{
if (fm_dec && fm_dec->start) {
fm_dec->start = 0;
#if TCFG_FM_REC_EN
fm_pcm_enc_stop();
#endif
pcm_decoder_close(&fm_dec->pcm_dec);
local_irq_disable();
fm_sample_close(fm_dec->fm, fm_dec->source);
fm_dec->fm = NULL;
local_irq_enable();
fm_eq_drc_close(fm_dec->eq_drc);
audio_mixer_ch_close(&fm_dec->mix_ch);
#if (RECORDER_MIX_EN)
audio_mixer_ch_close(&fm_dec->rec_mix_ch);
#endif/*RECORDER_MIX_EN*/
#if TCFG_PCM_ENC2TWS_ENABLE
if (fm_dec->pcm_dec.dec_no_out_sound) {
fm_dec->pcm_dec.dec_no_out_sound = 0;
localtws_enc_api_close();
}
#endif
if (fm_dec->stream) {
audio_stream_close(fm_dec->stream);
fm_dec->stream = NULL;
}
}
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码资源等待
@param *wait: 句柄
@param event: 事件
@return 0成功
@note 用于多解码打断处理
*/
/*----------------------------------------------------------------------------*/
static int fm_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
log_i("fm_wait_res_handler, event:%d\n", event);
if (event == AUDIO_RES_GET) {
// 启动解码
err = fm_dec_start();
} else if (event == AUDIO_RES_PUT) {
// 被打断
__fm_dec_close();
}
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 暂停/启动 fm解码mix ch输出
@param pause : 1:暂停 0启动
@return NULL
@note
*/
/*----------------------------------------------------------------------------*/
void fm_dec_pause_out(u8 pause)
{
if (!fm_dec) {
return;
}
audio_mixer_ch_pause(&fm_dec->mix_ch, pause);
#if (RECORDER_MIX_EN)
audio_mixer_ch_pause(&fm_dec->rec_mix_ch, pause);
#endif/*RECORDER_MIX_EN*/
audio_decoder_resume_all(&decode_task);
}
/*----------------------------------------------------------------------------*/
/**@brief 打开fm解码
@param source: 音频源
@param sample_rate: 采样率
@return 0成功
@return 非0失败
@note
*/
/*----------------------------------------------------------------------------*/
int fm_dec_open(u8 source, u32 sample_rate)
{
int err;
struct fm_dec_hdl *dec;
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
fm_dec = dec;
dec->id = rand32();
dec->source = source;
dec->pcm_dec.ch_num = 2;
dec->pcm_dec.output_ch_num = audio_output_channel_num();
dec->pcm_dec.output_ch_type = audio_output_channel_type();
dec->pcm_dec.sample_rate = sample_rate;
dec->wait.priority = 2;
dec->wait.preemption = 0;
dec->wait.snatch_same_prio = 1;
dec->wait.handler = fm_wait_res_handler;
clock_add(DEC_FM_CLK);
#if TCFG_DEC2TWS_ENABLE
// 设置localtws重播接口
localtws_globle_set_dec_restart(fm_dec_push_restart);
#endif
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭fm解码
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void fm_dec_close(void)
{
if (!fm_dec) {
return;
}
__fm_dec_close();
fm_dec_relaese();
clock_set_cur();
log_i("fm dec close \n\n ");
}
/*----------------------------------------------------------------------------*/
/**@brief fm解码重新开始
@param id: 文件解码id
@return 0成功
@return 非0失败
@note
*/
/*----------------------------------------------------------------------------*/
int fm_dec_restart(int id)
{
if ((!fm_dec) || (id != fm_dec->id)) {
return -1;
}
u8 source = fm_dec->source;
u32 sample_rate = fm_dec->pcm_dec.sample_rate;
fm_dec_close();
int err = fm_dec_open(source, sample_rate);
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 推送fm解码重新开始命令
@param
@return true成功
@return false失败
@note
*/
/*----------------------------------------------------------------------------*/
int fm_dec_push_restart(void)
{
if (!fm_dec) {
return false;
}
int argv[3];
argv[0] = (int)fm_dec_restart;
argv[1] = 1;
argv[2] = (int)fm_dec->id;
os_taskq_post_type(os_current_task(), Q_CALLBACK, ARRAY_SIZE(argv), argv);
return true;
}
/***********************inein pcm enc******************************/
#if TCFG_FM_REC_EN
/*----------------------------------------------------------------------------*/
/**@brief fm录音事件处理
@param *decoder: 编码器句柄
@param argc: 参数个数
@param *argv: 参数
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void fm_pcm_enc_event_handler(struct audio_encoder *encoder, int argc, int *argv)
{
log_i("fm_pcm_enc_event_handler, argv[]:%d, %d ", argv[0], argv[1]);
fm_pcm_enc_stop();
}
/*----------------------------------------------------------------------------*/
/**@brief fm录音停止
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void fm_pcm_enc_stop(void)
{
void *ptr;
if (fm_dec && fm_dec->enc) {
ptr = fm_dec->enc;
fm_dec->enc = NULL;
fm_enc_magic++;
pcm2file_enc_close(ptr);
}
}
/*----------------------------------------------------------------------------*/
/**@brief fm录音开始
@param
@return 0成功
@return 非0失败
@note
*/
/*----------------------------------------------------------------------------*/
int fm_pcm_enc_start(void)
{
void *ptr;
if (!fm_dec) {
return -1;
}
fm_pcm_enc_stop();
struct audio_fmt fmt = {0};
fmt.coding_type = AUDIO_CODING_MP3;
/* fmt.coding_type = AUDIO_CODING_WAV; */
fmt.bit_rate = 128;
fmt.channel = fm_dec->fmt.channel;
fmt.sample_rate = fm_dec->fmt.sample_rate;
fm_dec->enc = pcm2file_enc_open(&fmt, dev_manager_find_active(0));
if (!fm_dec->enc) {
return -1;
}
pcm2file_enc_set_evt_handler(fm_dec->enc, fm_pcm_enc_event_handler, fm_enc_magic);
pcm2file_enc_start(fm_dec->enc);
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 检测fm是否在录音
@param
@return true正录音
@return false不在
@note
*/
/*----------------------------------------------------------------------------*/
bool fm_pcm_enc_check()
{
if (fm_dec && fm_dec->enc) {
return true;
}
return false;
}
#endif /*TCFG_FM_REC_EN*/
/*----------------------------------------------------------------------------*/
/**@brief FM模式 eq drc 打开
@param sample_rate:采样率
@param ch_num:通道个数
@return 句柄
@note
*/
/*----------------------------------------------------------------------------*/
void *fm_eq_drc_open(u16 sample_rate, u8 ch_num)
{
#if TCFG_EQ_ENABLE
struct audio_eq_drc *eq_drc = NULL;
struct audio_eq_drc_parm effect_parm = {0};
#if TCFG_FM_MODE_EQ_ENABLE
effect_parm.eq_en = 1;
#if TCFG_DRC_ENABLE
#if TCFG_FM_MODE_DRC_ENABLE
effect_parm.drc_en = 1;
effect_parm.drc_cb = drc_get_filter_info;
#endif
#endif
if (effect_parm.eq_en) {
effect_parm.async_en = 1;
effect_parm.out_32bit = 1;
effect_parm.online_en = 1;
effect_parm.mode_en = 1;
}
effect_parm.eq_name = song_eq_mode;
#if TCFG_EQ_DIVIDE_ENABLE
effect_parm.divide_en = 1;
#endif
effect_parm.ch_num = ch_num;
effect_parm.sr = sample_rate;
effect_parm.eq_cb = eq_get_filter_info;
eq_drc = audio_eq_drc_open(&effect_parm);
clock_add(EQ_CLK);
if (effect_parm.drc_en) {
clock_add(EQ_DRC_CLK);
}
#endif
return eq_drc;
#endif
return NULL;
}
/*----------------------------------------------------------------------------*/
/**@brief FM模式 eq drc 关闭
@param 句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
void fm_eq_drc_close(struct audio_eq_drc *eq_drc)
{
#if TCFG_EQ_ENABLE
#if TCFG_FM_MODE_EQ_ENABLE
if (eq_drc) {
audio_eq_drc_close(eq_drc);
eq_drc = NULL;
clock_remove(EQ_CLK);
#if TCFG_DRC_ENABLE
#if TCFG_FM_MODE_DRC_ENABLE
clock_remove(EQ_DRC_CLK);
#endif
#endif
}
#endif
#endif
return;
}
#endif