KT25-0812_82A-UART/cpu/br25/audio_dec/audio_dec_file.c

1183 lines
34 KiB
C
Raw Normal View History

2025-08-12 10:09:23 +00:00
/*
****************************************************************
*File : audio_dec_file.c
*Note :
*
****************************************************************
*/
//////////////////////////////////////////////////////////////////////////////
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "effectrs_sync.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "app_config.h"
#include "app_main.h"
#include "classic/tws_api.h"
#include "music/music_decrypt.h"
#include "music/music_id3.h"
#include "pitchshifter/pitchshifter_api.h"
#include "mono2stereo/reverb_mono2stero_api.h"
#include "audio_enc.h"
#include "clock_cfg.h"
#include "application/audio_pitch.h"
#include "application/audio_eq_drc_apply.h"
#if TCFG_APP_MUSIC_EN
#define FILE_DEC_PICK_EN 1 // 本地解码拆包转发
#if (!TCFG_DEC2TWS_ENABLE)
#undef FILE_DEC_PICK_EN
#define FILE_DEC_PICK_EN 0
#endif
#ifndef BREAKPOINT_DATA_LEN
#define BREAKPOINT_DATA_LEN 32
#endif
const int FILE_DEC_ONCE_OUT_NUM = ((512 * 4) * 2); // 一次最多输出长度。避免多解码叠加时卡住其他解码太长时间
#define CHECK_SR_WHEN_DECODING 0 //每次run都检测采样率
//////////////////////////////////////////////////////////////////////////////
struct dec_type {
u32 type; // 解码类型
u32 clk; // 解码时钟
};
const struct dec_type dec_clk_tb[] = {
{AUDIO_CODING_MP3, DEC_MP3_CLK},
{AUDIO_CODING_WAV, DEC_WAV_CLK},
{AUDIO_CODING_G729, DEC_G729_CLK},
{AUDIO_CODING_G726, DEC_G726_CLK},
{AUDIO_CODING_PCM, DEC_PCM_CLK},
{AUDIO_CODING_MTY, DEC_MTY_CLK},
{AUDIO_CODING_WMA, DEC_WMA_CLK},
{AUDIO_CODING_APE, DEC_APE_CLK},
{AUDIO_CODING_FLAC, DEC_FLAC_CLK},
{AUDIO_CODING_DTS, DEC_DTS_CLK},
{AUDIO_CODING_M4A, DEC_M4A_CLK},
{AUDIO_CODING_ALAC, DEC_ALAC_CLK},
{AUDIO_CODING_MIDI, DEC_MIDI_CLK},
{AUDIO_CODING_MP3 | AUDIO_CODING_STU_PICK, DEC_MP3PICK_CLK},
{AUDIO_CODING_WMA | AUDIO_CODING_STU_PICK, DEC_WMAPICK_CLK},
{AUDIO_CODING_M4A | AUDIO_CODING_STU_PICK, DEC_M4APICK_CLK},
};
//////////////////////////////////////////////////////////////////////////////
struct file_dec_hdl *file_dec = NULL; // 文件解码句柄
u8 file_dec_start_pause = 0; // 启动解码后但不马上开始播放
//////////////////////////////////////////////////////////////////////////////
void *file_eq_drc_open(u16 sample_rate, u8 ch_num);
void file_eq_drc_close(struct audio_eq_drc *eq_drc);
extern void put_u16hex(u16 dat);
extern int tws_api_get_tws_state();
extern void local_tws_sync_no_check_data_buf(u8 no_check);
int file_dec_repeat_set(u8 repeat_num);
//////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
/**@brief 获取文件解码hdl
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void *get_file_dec_hdl()
{
return file_dec;
}
/*----------------------------------------------------------------------------*/
/**@brief 解码时钟添加
@param type:
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void dec_clock_add(u32 type)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(dec_clk_tb); i++) {
if (type == dec_clk_tb[i].type) {
clock_add(dec_clk_tb[i].clk);
return;
}
}
}
/*----------------------------------------------------------------------------*/
/**@brief 解码时钟移除
@param type:
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void dec_clock_remove(u32 type)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(dec_clk_tb); i++) {
if (type == dec_clk_tb[i].type) {
clock_remove(dec_clk_tb[i].clk);
return;
}
}
}
/*----------------------------------------------------------------------------*/
/**@brief 读取文件数据
@param *decoder:
@param *buf:
@param len:
@return >=0
@return <0
@note
*/
/*----------------------------------------------------------------------------*/
static int file_fread(struct audio_decoder *decoder, void *buf, u32 len)
{
struct file_decoder *file_dec = container_of(decoder, struct file_decoder, decoder);
struct file_dec_hdl *dec = container_of(file_dec, struct file_dec_hdl, file_dec);
int rlen;
#if TCFG_DEC_DECRYPT_ENABLE
u32 addr;
addr = fpos(dec->file);
rlen = fread(dec->file, buf, len);
if (rlen && (rlen <= len)) {
cryptanalysis_buff(&dec->mply_cipher, buf, addr, rlen);
}
#else
rlen = fread(dec->file, buf, len);
#endif
if (rlen > len) {
// putchar('r');
rlen = 0;
dec->read_err = 1;
} else {
// putchar('R');
dec->read_err = 0;
}
return rlen;
}
/*----------------------------------------------------------------------------*/
/**@brief 文件指针定位
@param *decoder:
@param offset:
@param seek_mode:
@return 0
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
static int file_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
{
struct file_decoder *file_dec = container_of(decoder, struct file_decoder, decoder);
struct file_dec_hdl *dec = container_of(file_dec, struct file_dec_hdl, file_dec);
return fseek(dec->file, offset, seek_mode);
}
/*----------------------------------------------------------------------------*/
/**@brief 读取文件长度
@param *decoder:
@return
@note
*/
/*----------------------------------------------------------------------------*/
static int file_flen(struct audio_decoder *decoder)
{
struct file_decoder *file_dec = container_of(decoder, struct file_decoder, decoder);
struct file_dec_hdl *dec = container_of(file_dec, struct file_dec_hdl, file_dec);
int len = 0;
len = flen(dec->file);
return len;
}
static const u32 file_input_coding_more[] = {
#if TCFG_DEC_MP3_ENABLE
AUDIO_CODING_MP3,
#endif
0,
};
static const struct audio_dec_input file_input = {
.coding_type = 0
#if TCFG_DEC_WMA_ENABLE
| AUDIO_CODING_WMA
#endif
#if TCFG_DEC_WAV_ENABLE
| AUDIO_CODING_WAV
#endif
#if TCFG_DEC_FLAC_ENABLE
| AUDIO_CODING_FLAC
#endif
#if TCFG_DEC_APE_ENABLE
| AUDIO_CODING_APE
#endif
#if TCFG_DEC_M4A_ENABLE
| AUDIO_CODING_M4A
#endif
#if TCFG_DEC_ALAC_ENABLE
| AUDIO_CODING_ALAC
#endif
#if TCFG_DEC_AMR_ENABLE
| AUDIO_CODING_AMR
#endif
#if TCFG_DEC_DTS_ENABLE
| AUDIO_CODING_DTS
#endif
#if TCFG_DEC_G726_ENABLE
| AUDIO_CODING_G726
#endif
#if TCFG_DEC_MIDI_ENABLE
| AUDIO_CODING_MIDI
#endif
,
.p_more_coding_type = (u32 *)file_input_coding_more,
.data_type = AUDIO_INPUT_FILE,
.ops = {
.file = {
.fread = file_fread,
.fseek = file_fseek,
.flen = file_flen,
}
}
};
/*----------------------------------------------------------------------------*/
/**@brief 文件解码释放
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void file_dec_release(void)
{
struct file_dec_hdl *dec = file_dec;
#if TCFG_DEC_ID3_V1_ENABLE
if (dec->p_mp3_id3_v1) {
id3_obj_post(&dec->p_mp3_id3_v1);
}
#endif
#if TCFG_DEC_ID3_V2_ENABLE
if (dec->p_mp3_id3_v2) {
id3_obj_post(&dec->p_mp3_id3_v2);
}
#endif
audio_decoder_task_del_wait(&decode_task, &dec->wait);
if (dec->file_dec.decoder.fmt.coding_type) {
dec_clock_remove(dec->file_dec.decoder.fmt.coding_type);
}
local_irq_disable();
if (file_dec->dec_bp) {
free(file_dec->dec_bp);
file_dec->dec_bp = NULL;
}
free(file_dec);
file_dec = NULL;
local_irq_enable();
}
/*----------------------------------------------------------------------------*/
/**@brief 文件解码事件处理
@param *decoder:
@param argc:
@param *argv:
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void file_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
log_i("AUDIO_DEC_EVENT_END\n");
if (!file_dec) {
log_i("file_dec handle err ");
break;
}
if (file_dec->id != argv[1]) {
log_w("file_dec id err : 0x%x, 0x%x \n", file_dec->id, argv[1]);
break;
}
// 有回调让上层close避免close后上层读不到断点等
if (file_dec->evt_cb) {
/* file_dec->evt_cb(file_dec->evt_priv, argc, argv); */
int msg[2];
msg[0] = argv[0];
msg[1] = file_dec->read_err;
/* log_i("read err0:%d ", file_dec->read_err); */
file_dec->evt_cb(file_dec->evt_priv, 2, msg);
} else {
file_dec_close();
}
//audio_decoder_resume_all(&decode_task);
break;
}
}
/*----------------------------------------------------------------------------*/
/**@brief 文件解码数据流激活
@param *p:
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void file_dec_out_stream_resume(void *p)
{
struct file_dec_hdl *dec = p;
audio_decoder_resume(&dec->file_dec.decoder);
}
#if CHECK_SR_WHEN_DECODING
/*----------------------------------------------------------------------------*/
/**@brief 文件解码预处理
@param *decoder:
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
static int file_decoder_probe_handler_app(struct audio_decoder *decoder)
{
struct file_decoder *dec = container_of(decoder, struct file_decoder, decoder);
dec->once_out_cnt = 0;
audio_decoder_get_fmt_info(&dec->decoder, &dec->decoder.fmt);
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 文件解码后处理
@param *decoder:
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
static int file_decoder_post_handler_app(struct audio_decoder *decoder)
{
struct file_decoder *dec = container_of(decoder, struct file_decoder, decoder);
if (dec->status) {
dec->dec_cur_time = audio_decoder_get_play_time(&dec->decoder);
}
if (FILE_DEC_ONCE_OUT_NUM && (dec->once_out_cnt >= FILE_DEC_ONCE_OUT_NUM)) {
audio_decoder_resume(&dec->decoder);
return 0;
}
return 0;
}
//mp3特殊处理
static const struct audio_dec_handler file_decoder_handler_app = {
.dec_probe = file_decoder_probe_handler_app,
.dec_post = file_decoder_post_handler_app,
};
#endif
/*----------------------------------------------------------------------------*/
/**@brief 文件解码开始
@param
@return 0
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
static int file_dec_start(void)
{
int err;
struct file_dec_hdl *dec = file_dec;
struct audio_mixer *p_mixer = &mixer;
u8 pcm_enc_flag = 0;
if (!dec) {
return -EINVAL;
}
log_i("file_dec_start: in\n");
#if FILE_DEC_PICK_EN
if (localtws_check_enable() == true) {
// 使用拆包方式传输
err = file_decoder_open(&dec->file_dec, &file_input, &decode_task,
dec->bp, 1);
if (err == 0) {
dec->pick_flag = 1;
dec->file_dec.dec_no_out_sound = 1;
// 同步不需要检查buf变化
local_tws_sync_no_check_data_buf(1);
// 打开localtws推送
localtws_push_open();
// 启动localtws功能
localtws_start(&dec->file_dec.decoder.fmt);
// 关闭资源等待。最终会在localtws解码处等待
audio_decoder_task_del_wait(&decode_task, &dec->wait);
goto __open_ok;
}
}
#endif
// 打开file解码器
err = file_decoder_open(&dec->file_dec, &file_input, &decode_task,
dec->bp, 0);
if (err) {
goto __err1;
}
__open_ok:
#if CHECK_SR_WHEN_DECODING
if (dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_MP3) {
audio_decoder_set_handler(&dec->file_dec.decoder, &file_decoder_handler_app); //注册解码时检测采样率
}
#endif
file_decoder_set_event_handler(&dec->file_dec, file_dec_event_handler, dec->id);
// 获取id3
if (dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_MP3) {
#if TCFG_DEC_ID3_V1_ENABLE
if (dec->p_mp3_id3_v1) {
id3_obj_post(&dec->p_mp3_id3_v1);
}
dec->p_mp3_id3_v1 = id3_v1_obj_get(dec->file);
#endif
#if TCFG_DEC_ID3_V2_ENABLE
if (dec->p_mp3_id3_v2) {
id3_obj_post(&dec->p_mp3_id3_v2);
}
dec->p_mp3_id3_v2 = id3_v2_obj_get(dec->file);
#endif
}
#if TCFG_PCM_ENC2TWS_ENABLE
if (dec->file_dec.dec_no_out_sound == 0) {
// localtws
struct audio_fmt enc_f;
memcpy(&enc_f, &dec->file_dec.decoder.fmt, sizeof(struct audio_fmt));
enc_f.coding_type = AUDIO_CODING_SBC;
enc_f.channel = dec->file_dec.output_ch_num;
int ret = localtws_enc_api_open(&enc_f, 0);
if (ret == true) {
dec->file_dec.dec_no_out_sound = 1;
// 重定向mixer
p_mixer = &g_localtws.mixer;
// 关闭资源等待。最终会在localtws解码处等待
audio_decoder_task_del_wait(&decode_task, &dec->wait);
// 重新设置解码输出声道
file_decoder_set_output_channel(&dec->file_dec);
}
}
#endif
#if TCFG_SPEED_PITCH_ENABLE
static PS69_CONTEXT_CONF pitch_param;
pitch_param.pitchV = 32768;//32767 是原始音调 >32768是音调变高《32768 音调变低建议范围20000 - 50000
pitch_param.speedV = 40;//>80变快,<80 变慢建议范围30-130
pitch_param.sr = dec->file_dec.sample_rate ;
pitch_param.chn = dec->file_dec.output_ch_num ;
dec->p_pitchspeed_hdl = open_pitchspeed(&pitch_param, NULL);
#endif
if (!dec->file_dec.dec_no_out_sound) {
audio_mode_main_dec_open(AUDIO_MODE_MAIN_STATE_DEC_FILE);
}
// 设置叠加功能
audio_mixer_ch_open_head(&dec->mix_ch, p_mixer);
audio_mixer_ch_set_src(&dec->mix_ch, 1, 0);
dec_clock_add(dec->file_dec.decoder.dec_ops->coding_type);
/* #if TCFG_DEC_MIDI_ENABLE */
/* // midi功能设置 */
/* if (dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_MIDI) { */
/* extern int midi_init(void *info); */
/* memset(&dec->midi_init_info_val, 0, sizeof(MIDI_INIT_STRUCT)); */
/* int ret = midi_init(&dec->midi_init_info_val); */
/* if (ret) { */
/* goto __err3; */
/* } */
/* audio_decoder_ioctrl(&dec->file_dec.decoder, CMD_INIT_CONFIG, &dec->midi_init_info_val); */
/* } */
/* #endif */
if (dec->stream_handler && (dec->pick_flag == 0)) {
dec->stream_handler(dec->stream_priv, FILE_DEC_STREAM_OPEN, dec);
goto __stream_set_end;
}
dec->eq_drc = file_eq_drc_open(dec->file_dec.sample_rate, dec->file_dec.output_ch_num);
// 数据流串联
struct audio_stream_entry *entries[8] = {NULL};
u8 entry_cnt = 0;
entries[entry_cnt++] = &dec->file_dec.decoder.entry;
#if FILE_DEC_PICK_EN
if (dec->pick_flag) {
// 拆包直接输出到localtws推送中间不经过任何处理
entries[entry_cnt++] = &g_localtws.push.entry;
} else
#endif
{
#if TCFG_SPEED_PITCH_ENABLE
if (dec->p_pitchspeed_hdl) {
entries[entry_cnt++] = &dec->p_pitchspeed_hdl->entry;
}
#endif
#if TCFG_EQ_ENABLE && TCFG_MUSIC_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, file_dec_out_stream_resume);
audio_stream_add_list(dec->stream, entries, entry_cnt);
__stream_set_end:
log_i("total_time : %d \n", dec->file_dec.dec_total_time);
#if FILE_DEC_REPEAT_EN
file_dec_repeat_set(3);
#endif
audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC);
// 文件打开就暂停
if (file_dec_start_pause) {
log_i("file_dec_start_pause\n");
file_dec_start_pause = 0;
dec->file_dec.status = FILE_DEC_STATUS_PAUSE;
return 0;
}
// 设置时钟
clock_set_cur();
dec->file_dec.status = FILE_DEC_STATUS_PLAY;
err = audio_decoder_start(&dec->file_dec.decoder);
if (err) {
goto __err3;
}
return 0;
__err3:
dec->file_dec.status = 0;
if (dec->p_pitchspeed_hdl) {
close_pitchspeed(dec->p_pitchspeed_hdl);
}
file_eq_drc_close(dec->eq_drc);
audio_mixer_ch_close(&dec->mix_ch);
#if TCFG_PCM_ENC2TWS_ENABLE
if (file_dec->file_dec.dec_no_out_sound) {
file_dec->file_dec.dec_no_out_sound = 0;
localtws_enc_api_close();
}
#endif
if (dec->stream_handler) {
dec->stream_handler(dec->stream_priv, FILE_DEC_STREAM_CLOSE, dec);
}
if (dec->stream) {
audio_stream_close(dec->stream);
dec->stream = NULL;
}
file_decoder_close(&dec->file_dec);
__err1:
file_dec_release();
clock_set_cur();
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 文件解码资源等待
@param *wait:
@param event:
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
static int file_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
log_i("file_wait_res_handler, event:%d, status:%d ", event, file_dec->file_dec.status);
if (event == AUDIO_RES_GET) {
// 启动解码
if (file_dec->file_dec.status == 0) {
err = file_dec_start();
} else if (file_dec->file_dec.tmp_pause) {
file_dec->file_dec.tmp_pause = 0;
audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC);
if (file_dec->file_dec.status == FILE_DEC_STATUS_PLAY) {
err = audio_decoder_start(&file_dec->file_dec.decoder);
if (!file_dec->pick_flag) {
audio_mixer_ch_pause(&file_dec->mix_ch, 0);
}
}
}
} else if (event == AUDIO_RES_PUT) {
// 被打断
if (file_dec->file_dec.status) {
if (file_dec->file_dec.status == FILE_DEC_STATUS_PLAY || \
file_dec->file_dec.status == FILE_DEC_STATUS_PAUSE) {
if (!file_dec->pick_flag) {
audio_mixer_ch_pause(&file_dec->mix_ch, 1);
}
err = audio_decoder_pause(&file_dec->file_dec.decoder);
/* os_time_dly(2); */
/* audio_output_stop(); */
}
file_dec->file_dec.tmp_pause = 1;
}
}
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief file解码pp处理
@param play: 1-0-
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void file_dec_pp_ctrl(u8 play)
{
if (!file_dec) {
return ;
}
if (play) {
// 播放前处理
clock_pause_play(0);
if (!file_dec->pick_flag) {
audio_mixer_ch_pause(&file_dec->mix_ch, 0);
}
} else {
// 暂停后处理
#if TCFG_DEC2TWS_ENABLE
if (file_dec->file_dec.dec_no_out_sound) {
// 发送一个暂停命令避免从机收数超时进入stop
localtws_dec_pause();
}
#endif
if (!file_dec->pick_flag) {
audio_mixer_ch_pause(&file_dec->mix_ch, 1);
//audio_decoder_resume_all(&decode_task);
}
if (audio_mixer_get_active_ch_num(&mixer) == 0) {
clock_pause_play(1);
}
}
}
/*----------------------------------------------------------------------------*/
/**@brief 创建一个文件解码
@param *priv:
@param *handler:
@return 0
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_create(void *priv, void (*handler)(void *, int argc, int *argv))
{
struct file_dec_hdl *dec;
if (file_dec) {
file_dec_close();
}
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
file_dec = dec;
file_dec->evt_cb = handler;
file_dec->evt_priv = priv;
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 设置解码数据流设置回调接口
@param *dec:
@param *stream_handler:
@param *stream_priv:
@return
@note
*/
/*----------------------------------------------------------------------------*/
void file_dec_set_stream_set_hdl(struct file_dec_hdl *dec,
void (*stream_handler)(void *priv, int event, struct file_dec_hdl *),
void *stream_priv)
{
if (dec) {
dec->stream_handler = stream_handler;
dec->stream_priv = stream_priv;
}
}
/*----------------------------------------------------------------------------*/
/**@brief 打开文件解码
@param *file:
@param *bp:
@return 0
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_open(void *file, struct audio_dec_breakpoint *bp)
{
int err;
struct file_dec_hdl *dec = file_dec;
log_i("file_dec_open: in, 0x%x, bp:0x%x \n", file, bp);
if ((!dec) || (!file)) {
return -EPERM;
}
dec->file = file;
dec->bp = bp;
dec->id = rand32();
dec->file_dec.ch_type = AUDIO_CH_MAX;
dec->file_dec.output_ch_num = audio_output_channel_num();
dec->file_dec.output_ch_type = audio_output_channel_type();
#if TCFG_DEC_DECRYPT_ENABLE
cipher_init(&dec->mply_cipher, TCFG_DEC_DECRYPT_KEY);
cipher_check_decode_file(&dec->mply_cipher, file);
#endif
#if TCFG_DEC2TWS_ENABLE
// 设置localtws重播接口
localtws_globle_set_dec_restart(file_dec_push_restart);
#endif
dec->wait.priority = 1;
dec->wait.preemption = 0;
dec->wait.snatch_same_prio = 1;
dec->wait.handler = file_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭文件解码
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void file_dec_close(void)
{
if (!file_dec) {
return;
}
if (file_dec->file_dec.status) {
file_dec->file_dec.status = 0;
audio_mixer_ch_pause(&file_dec->mix_ch, 1);
file_decoder_close(&file_dec->file_dec);
if (file_dec->p_pitchspeed_hdl) {
close_pitchspeed(file_dec->p_pitchspeed_hdl);
}
file_eq_drc_close(file_dec->eq_drc);
audio_mixer_ch_close(&file_dec->mix_ch);
#if TCFG_PCM_ENC2TWS_ENABLE
if (file_dec->file_dec.dec_no_out_sound) {
file_dec->file_dec.dec_no_out_sound = 0;
localtws_enc_api_close();
}
#endif
if (file_dec->stream_handler) {
file_dec->stream_handler(file_dec->stream_priv, FILE_DEC_STREAM_CLOSE, file_dec);
}
if (file_dec->stream) {
audio_stream_close(file_dec->stream);
file_dec->stream = NULL;
}
}
file_dec_release();
clock_set_cur();
log_i("file_dec_close: exit\n");
}
/*----------------------------------------------------------------------------*/
/**@brief 获取file_dec句柄
@param
@return file_dec句柄
@note
*/
/*----------------------------------------------------------------------------*/
struct file_decoder *file_dec_get_file_decoder_hdl(void)
{
if (file_dec) {
return &file_dec->file_dec;
}
return NULL;
}
/*----------------------------------------------------------------------------*/
/**@brief 获取file_dec状态
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_get_status(void)
{
struct file_decoder *dec = file_dec_get_file_decoder_hdl();
if (dec) {
return dec->status;
}
return FILE_DEC_STATUS_STOP;
}
/*----------------------------------------------------------------------------*/
/**@brief 文件解码重新开始
@param id: id
@return 0
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_restart(int id)
{
if ((!file_dec) || (id != file_dec->id)) {
return -1;
}
if (file_dec->bp == NULL) {
if (file_dec->dec_bp == NULL) {
file_dec->dec_bp = zalloc(sizeof(struct audio_dec_breakpoint) + BREAKPOINT_DATA_LEN);
ASSERT(file_dec->dec_bp);
file_dec->dec_bp->data_len = BREAKPOINT_DATA_LEN;
}
file_dec->bp = file_dec->dec_bp;
}
if (file_dec->file_dec.status && file_dec->bp) {
audio_decoder_get_breakpoint(&file_dec->file_dec.decoder, file_dec->bp);
}
void *file = file_dec->file;
void *bp = file_dec->bp;
void *evt_cb = file_dec->evt_cb;
void *evt_priv = file_dec->evt_priv;
int err;
void *dec_bp = file_dec->dec_bp; // 先保存一下避免close被释放
file_dec->dec_bp = NULL;
file_dec_close();
err = file_dec_create(evt_priv, evt_cb);
if (!err) {
file_dec->dec_bp = dec_bp; // 还原回去
err = file_dec_open(file, bp);
} else {
if (dec_bp) {
free(dec_bp); // 失败,释放
}
}
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 推送文件解码重新开始命令
@param
@return true
@return false
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_push_restart(void)
{
if (!file_dec) {
return false;
}
int argv[3];
argv[0] = (int)file_dec_restart;
argv[1] = 1;
argv[2] = (int)file_dec->id;
os_taskq_post_type(os_current_task(), Q_CALLBACK, ARRAY_SIZE(argv), argv);
return true;
}
#if FILE_DEC_REPEAT_EN
/*----------------------------------------------------------------------------*/
/**@brief 循环播放回调接口
@param *priv:
@return 0
@return 0
@note
*/
/*----------------------------------------------------------------------------*/
static int file_dec_repeat_cb(void *priv)
{
struct file_dec_hdl *dec = priv;
y_printf("file_dec_repeat_cb\n");
if (dec->repeat_num) {
dec->repeat_num--;
} else {
y_printf("file_dec_repeat_cb end\n");
return -1;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 设置循环播放次数
@param repeat_num:
@return true
@return false
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_repeat_set(u8 repeat_num)
{
struct file_dec_hdl *dec = file_dec;
if (!dec || !dec->file_dec.decoder.dec_ops) {
return false;
}
switch (dec->file_dec.decoder.dec_ops->coding_type) {
case AUDIO_CODING_MP3:
case AUDIO_CODING_WAV: {
dec->repeat_num = repeat_num;
struct audio_repeat_mode_param rep = {0};
rep.flag = 1; //使能
rep.headcut_frame = 2; //依据需求砍掉前面几帧仅mp3格式有效
rep.tailcut_frame = 2; //依据需求砍掉后面几帧仅mp3格式有效
rep.repeat_callback = file_dec_repeat_cb;
rep.callback_priv = dec;
rep.repair_buf = &dec->repair_buf;
audio_decoder_ioctrl(&dec->file_dec.decoder, AUDIO_IOCTRL_CMD_REPEAT_PLAY, &rep);
}
return true;
}
return false;
}
#endif
#if FILE_DEC_AB_REPEAT_EN
#define AUDIO_AB_REPEAT_CODING_TYPE (AUDIO_CODING_MP3 | AUDIO_CODING_WMA | AUDIO_CODING_WAV | AUDIO_CODING_FLAC | AUDIO_CODING_APE | AUDIO_CODING_DTS)
enum {
AB_REPEAT_STA_NON = 0,
AB_REPEAT_STA_ASTA,
AB_REPEAT_STA_BSTA,
};
static int file_dec_ab_repeat_set(int ab_cmd, int ab_mode)
{
struct file_dec_hdl *dec = file_dec;
if (!dec || !dec->file_dec.decoder.dec_ops) {
return false;
}
y_printf("ab repat, cmd:0x%x, mode:%d \n", ab_cmd, ab_mode);
struct audio_ab_repeat_mode_param rpt = {0};
rpt.value = ab_mode;
audio_decoder_ioctrl(&dec->file_dec.decoder, ab_cmd, &rpt);
return true;
}
static int file_dec_ab_probe_check(void)
{
struct file_dec_hdl *dec = file_dec;
if (!dec || !dec->file_dec.decoder.dec_ops) {
return false;
}
if (false == file_decoder_is_play(&dec->file_dec)) {
return false;
}
if (dec->file_dec.decoder.dec_ops->coding_type & AUDIO_CODING_STU_PICK) {
return false;
}
if (!(dec->file_dec.decoder.dec_ops->coding_type & AUDIO_AB_REPEAT_CODING_TYPE)) {
return false;
}
return true;
}
int file_dec_ab_repeat_switch(void)
{
struct file_dec_hdl *dec = file_dec;
if (false == file_dec_ab_probe_check()) {
return false;
}
switch (dec->ab_repeat_status) {
case AB_REPEAT_STA_NON:
if (file_dec_ab_repeat_set(AUDIO_IOCTRL_CMD_SET_BREAKPOINT_A, 0)) {
dec->ab_repeat_status = AB_REPEAT_STA_ASTA;
}
break;
case AB_REPEAT_STA_ASTA:
if (file_dec_ab_repeat_set(AUDIO_IOCTRL_CMD_SET_BREAKPOINT_B, 0)) {
dec->ab_repeat_status = AB_REPEAT_STA_BSTA;
}
break;
case AB_REPEAT_STA_BSTA:
if (file_dec_ab_repeat_set(AUDIO_IOCTRL_CMD_SET_BREAKPOINT_MODE, AB_REPEAT_MODE_CUR)) {
dec->ab_repeat_status = AB_REPEAT_STA_NON;
}
break;
}
return true;
}
int file_dec_ab_repeat_close(void)
{
struct file_dec_hdl *dec = file_dec;
if (false == file_dec_ab_probe_check()) {
return false;
}
if (dec->ab_repeat_status == AB_REPEAT_STA_NON) {
return true;
}
if (dec->ab_repeat_status == AB_REPEAT_STA_ASTA) {
switch (dec->file_dec.decoder.dec_ops->coding_type) {
case AUDIO_CODING_FLAC:
case AUDIO_CODING_DTS:
case AUDIO_CODING_APE:
file_dec_ab_repeat_set(AUDIO_IOCTRL_CMD_SET_BREAKPOINT_B, 0);
break;
}
}
file_dec_ab_repeat_set(AUDIO_IOCTRL_CMD_SET_BREAKPOINT_MODE, AB_REPEAT_MODE_CUR);
dec->ab_repeat_status = AB_REPEAT_STA_NON;
return true;
}
#endif /*FILE_DEC_AB_REPEAT_EN*/
#endif /*TCFG_APP_MUSIC_EN*/
/*----------------------------------------------------------------------------*/
/**@brief file decoder pp处理
@param *dec: file解码句柄
@param play: 1-0-
@return
@note
*/
/*----------------------------------------------------------------------------*/
void file_decoder_pp_ctrl(struct file_decoder *dec, u8 play)
{
#if TCFG_APP_MUSIC_EN
if (file_dec && (&file_dec->file_dec == dec)) {
file_dec_pp_ctrl(play);
}
#endif /*TCFG_APP_MUSIC_EN*/
}
/*----------------------------------------------------------------------------*/
/**@brief 音乐模式 eq drc 打开
@param sample_rate:
@param ch_num:
@return
@note
*/
/*----------------------------------------------------------------------------*/
void *file_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_MUSIC_MODE_EQ_ENABLE
effect_parm.eq_en = 1;
#if TCFG_DRC_ENABLE
#if TCFG_MUSIC_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;
if (effect_parm.drc_en) {
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;
printf("ch_num %d\n,sr %d\n", ch_num, sample_rate);
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 音乐模式 eq drc 关闭
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void file_eq_drc_close(struct audio_eq_drc *eq_drc)
{
#if TCFG_EQ_ENABLE
#if TCFG_MUSIC_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_MUSIC_MODE_DRC_ENABLE
clock_remove(EQ_DRC_CLK);
#endif
#endif
}
#endif
#endif
return;
}