KT24-1110_65E-HA-651B/cpu/br25/audio_dec/audio_dec_file.c
2024-11-10 18:44:17 +08:00

1520 lines
45 KiB
C
Raw 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_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 "media/audio_voice_changer.h"
#include "media/audio_eq_drc_apply.h"
#include "audio_base.h"
#include "channel_switch.h"
#include "media/convert_data.h"
#include "audio_effect/audio_dynamic_eq_demo.h"
#include "media/effects_adj.h"
#include "audio_effect/audio_eff_default_parm.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); // 一次最多输出长度。避免多解码叠加时卡住其他解码太长时间
const int FILE_DEC_PP_FADE_MS = 50; // pp淡入淡出时长。0-不使用淡入淡出
// 文件解码输出使用单独任务
#if TCFG_AUDIO_DEC_OUT_TASK
#define FILE_DEC_USE_OUT_TASK 1
#else
#define FILE_DEC_USE_OUT_TASK 0
#endif
#define CHECK_SR_WHEN_DECODING 1 //每次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; // 启动解码后但不马上开始播放
//////////////////////////////////////////////////////////////////////////////
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);
extern int sd_active_status_control(u8 en);
extern void sd_active_ctl_by_coding_type(u8 en);
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)) {
// read后进行解密
cryptanalysis_buff(&dec->mply_cipher, buf, addr, rlen);
}
#else
rlen = fread(dec->file, buf, len);
#endif
if (rlen > len) {
// putchar('r');
if (rlen == (-1)) {
//file err
dec->read_err = 1;
} else {
//dis err
dec->read_err = 2;
}
rlen = 0;
} 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;
}
// 先检查完file_input中定义的类型最后检查file_input_coding_more定义的数据类型
static const u32 file_input_coding_more[] = {
#if TCFG_DEC_WAV_ENABLE
AUDIO_CODING_WAV,
#endif
#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;
}
#if FILE_DEC_SAVE_FAT_TABLE_EN
if (file_dec->fat_table) {
free(file_dec->fat_table);
}
#endif//FILE_DEC_SAVE_FAT_TABLE_EN
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;
#if FILE_DEC_USE_OUT_TASK
if (dec->file_dec.dec_no_out_sound == 0) {
audio_decoder_resume_out_task(&dec->file_dec.decoder);
return ;
}
#endif
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;
struct audio_fmt fmt = {0};
audio_decoder_get_fmt_info(&dec->decoder, &fmt);
if (fmt.sample_rate) {
dec->decoder.fmt.sample_rate = fmt.sample_rate;
}
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) {
// 没有拆包的情况下尝试使用sbc等编码转发
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 = 2;//dec->file_dec.output_ch_num; // 使用双声道输出localtws在解码时才变成对应声道
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);
if (dec->file_dec.output_ch_num != enc_f.channel) {
dec->file_dec.output_ch_num = dec->file_dec.decoder.fmt.channel = enc_f.channel;
if (enc_f.channel == 2) {
dec->file_dec.output_ch_type = AUDIO_CH_LR;
} else {
dec->file_dec.output_ch_type = AUDIO_CH_DIFF;
}
}
// 重新设置解码输出声道
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);
#if FILE_DEC_USE_OUT_TASK
if (dec->file_dec.dec_no_out_sound == 0) {
audio_decoder_out_task_ch_enable(&dec->file_dec.decoder, 1024);
}
#endif
dec_clock_add(dec->file_dec.decoder.dec_ops->coding_type);
if (dec->stream_handler && (dec->pick_flag == 0)) {
dec->stream_handler(dec->stream_priv, FILE_DEC_STREAM_OPEN, dec);
goto __stream_set_end;
}
#if AUDIO_SURROUND_CONFIG
dec->surround = surround_open_demo(AEID_MUSIC_SURROUND, dec->file_dec.output_ch_type);
#endif
#if AUDIO_VBASS_CONFIG
dec->vbass_prev_gain = audio_gain_open_demo(AEID_MUSIC_VBASS_PREV_GAIN, dec->file_dec.output_ch_num);
dec->ns_gate = audio_noisegate_open_demo(AEID_MUSIC_NS_GATE, dec->file_dec.sample_rate, dec->file_dec.output_ch_num);
//虚拟低音
dec->vbass = audio_vbass_open_demo(AEID_MUSIC_VBASS, dec->file_dec.sample_rate, dec->file_dec.output_ch_num);
#endif
#if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE
dec->high_bass = high_bass_eq_open(dec->file_dec.sample_rate, dec->file_dec.output_ch_num);
dec->hb_drc = high_bass_drc_open(dec->file_dec.sample_rate, dec->file_dec.output_ch_num);
if (dec->hb_drc && dec->hb_drc->run32bit) {
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
dec->hb_convert = convet_data_open(0, 512);
#endif
}
#endif
#if TCFG_EQ_ENABLE && TCFG_MUSIC_MODE_EQ_ENABLE
dec->eq = music_eq_open(dec->file_dec.sample_rate, dec->file_dec.output_ch_num);// eq
#if TCFG_DRC_ENABLE && TCFG_MUSIC_MODE_DRC_ENABLE
dec->drc = music_drc_open(dec->file_dec.sample_rate, dec->file_dec.output_ch_num);//drc
#endif/*TCFG_MUSIC_MODE_DRC_ENABLE*/
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
if (dec->eq && dec->eq->out_32bit) {
dec->convert = convet_data_open(0, 512);
}
#endif
#if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC
dec->ext_eq = music_ext_eq_open(dec->file_dec.sample_rate, dec->file_dec.output_ch_num);
#endif
#if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE
dec->eq2 = music_eq2_open(dec->file_dec.sample_rate, dec->file_dec.output_ch_num);// eq
dec->dy_eq = audio_dynamic_eq_ctrl_open(AEID_MUSIC_DYNAMIC_EQ, dec->file_dec.sample_rate, dec->file_dec.output_ch_num);//动态eq
dec->convert2 = convet_data_open(0, 512);
#endif/*TCFG_DYNAMIC_EQ_ENABLE*/
#if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE
dec->gain = audio_gain_open_demo(AEID_MUSIC_GAIN, dec->file_dec.output_ch_num);
#endif
#endif/*TCFG_MUSIC_MODE_EQ_ENABLE*/
// 数据流串联
struct audio_stream_entry *entries[16] = {NULL};
u8 entry_cnt = 0;
u8 rl_rr_entry_start = 0;
entries[entry_cnt++] = &dec->file_dec.decoder.entry;
#if SYS_DIGVOL_GROUP_EN
void *dvol_entry = sys_digvol_group_ch_open("music_file", -1, NULL);
entries[entry_cnt++] = dvol_entry;
#endif // SYS_DIGVOL_GROUP_EN
#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 AUDIO_VBASS_CONFIG
if (dec->vbass_prev_gain) {
entries[entry_cnt++] = &dec->vbass_prev_gain->entry;
}
if (dec->ns_gate) {
entries[entry_cnt++] = &dec->ns_gate->entry;
}
if (dec->vbass) {
entries[entry_cnt++] = &dec->vbass->entry;
}
#endif
#if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE
if (dec->high_bass) { //高低音
entries[entry_cnt++] = &dec->high_bass->entry;
}
if (dec->hb_drc) { //高低音后drc
entries[entry_cnt++] = &dec->hb_drc->entry;
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
if (dec->hb_convert) {
entries[entry_cnt++] = &dec->hb_convert->entry;
}
#endif
}
#endif
rl_rr_entry_start = entry_cnt - 1;//记录eq的上一个节点
#if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE
if (dec->gain) {
entries[entry_cnt++] = &dec->gain->entry;
}
#endif
#if AUDIO_SURROUND_CONFIG
if (dec->surround) {
entries[entry_cnt++] = &dec->surround->entry;
}
#endif
#if TCFG_EQ_ENABLE && TCFG_MUSIC_MODE_EQ_ENABLE
if (dec->eq) {
entries[entry_cnt++] = &dec->eq->entry;
if (dec->drc) {
entries[entry_cnt++] = &dec->drc->entry;
}
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
if (dec->convert) {
entries[entry_cnt++] = &dec->convert->entry;
}
#endif
#if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC
if (dec->ext_eq) {
entries[entry_cnt++] = &dec->ext_eq->entry;
}
#endif
#if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE
if (dec->eq2) {
entries[entry_cnt++] = &dec->eq2->entry;
}
if (dec->dy_eq && dec->dy_eq->dy_eq) {
entries[entry_cnt++] = &dec->dy_eq->dy_eq->entry;
}
if (dec->convert2) {
entries[entry_cnt++] = &dec->convert2->entry;
}
#endif
}
#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
#if FILE_DEC_DEST_PLAY
// 跳到指定位置播放
file_dec_set_start_play(3 * 1000);
/* u32 file_dec_dest_test_cb(void *priv); */
/* file_dec_set_start_dest_play(2000, 4000, file_dec_dest_test_cb, dec); */
#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;
if (dec->evt_cb) {
int msg[2];
msg[0] = AUDIO_DEC_EVENT_START;
dec->evt_cb(dec->evt_priv, 2, msg);
}
#if FILE_DEC_SAVE_FAT_TABLE_EN
if (dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_APE
|| dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_M4A
|| dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_AAC
|| dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_ALAC
) {
//针对m4a、ape优化因为解码频繁seek导致卡音问题
if (dec->fat_table == NULL) {
dec->fat_table = zalloc(FILE_DEC_SAVE_FAT_TABLE_SIZE);
} else {
printf("warning !!! fat_table malloc ready\n");
}
if (dec->fat_table) {
fsave_fat_table(dec->file, FILE_DEC_SAVE_FAT_TABLE_SIZE, dec->fat_table);
}
}
#endif//FILE_DEC_SAVE_FAT_TABLE_EN
err = audio_decoder_start(&dec->file_dec.decoder);
if (err) {
goto __err3;
}
sd_active_ctl_by_coding_type(1);
return 0;
__err3:
dec->file_dec.status = 0;
#if TCFG_SPEED_PITCH_ENABLE
if (dec->p_pitchspeed_hdl) {
close_pitchspeed(dec->p_pitchspeed_hdl);
}
#endif
#if AUDIO_SURROUND_CONFIG
surround_close_demo(dec->surround);
#endif
#if AUDIO_VBASS_CONFIG
audio_gain_close_demo(dec->vbass_prev_gain);
audio_noisegate_close_demo(dec->ns_gate);
audio_vbass_close_demo(dec->vbass);
#endif
#if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE
high_bass_eq_close(dec->high_bass);
high_bass_drc_close(dec->hb_drc);
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
convet_data_close(dec->hb_convert);
#endif
#endif
#if TCFG_EQ_ENABLE && TCFG_MUSIC_MODE_EQ_ENABLE
music_eq_close(dec->eq);
#if TCFG_DRC_ENABLE && TCFG_MUSIC_MODE_DRC_ENABLE
music_drc_close(dec->drc);
#endif
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
convet_data_close(dec->convert);
#endif
#if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC
music_ext_eq_close(dec->ext_eq);
#endif
#if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE
music_eq2_close(dec->eq2);
audio_dynamic_eq_ctrl_close(dec->dy_eq);
convet_data_close(dec->convert2);
#endif
#if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE
audio_gain_close_demo(dec->gain);
#endif
#endif
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 SYS_DIGVOL_GROUP_EN
sys_digvol_group_ch_close("music_file");
#endif // SYS_DIGVOL_GROUP_EN
if (dec->stream) {
audio_stream_close(dec->stream);
dec->stream = NULL;
}
file_decoder_close(&dec->file_dec);
__err1:
if (dec->evt_cb && (dec->wait_add == 0)) {
int msg[2];
msg[0] = AUDIO_DEC_EVENT_ERR;
dec->evt_cb(dec->evt_priv, 2, msg);
}
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) {
// 播放前处理
#if (!TCFG_MIC_EFFECT_ENABLE)
clock_pause_play(0);
#endif/*TCFG_MIC_EFFECT_ENABLE*/
if (!file_dec->pick_flag) {
audio_mixer_ch_pause(&file_dec->mix_ch, 0);
}
#if TCFG_DEC2TWS_ENABLE
if (file_dec->file_dec.dec_no_out_sound) {
localtws_decoder_pause(0);
}
#endif
} else {
// 暂停后处理
#if TCFG_DEC2TWS_ENABLE
if (file_dec->file_dec.dec_no_out_sound) {
localtws_decoder_pause(1);
}
#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) {
#if (!TCFG_MIC_EFFECT_ENABLE)
clock_pause_play(1);
#endif/*TCFG_MIC_EFFECT_ENABLE*/
}
}
}
/*----------------------------------------------------------------------------*/
/**@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);
vddiom_set_dynamic(TCFG_VDDIO_DEV_ACCESS_LEVEL);
if ((!dec) || (!file)) {
vddiom_set_dynamic(TCFG_LOWPOWER_VDDIOM_LEVEL);
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;
dec->wait_add = 1;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
if (file_dec) {
file_dec->wait_add = 0;
}
return err;
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭文件解码
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void file_dec_close(void)
{
if (!file_dec) {
vddiom_set_dynamic(TCFG_LOWPOWER_VDDIOM_LEVEL);
return;
}
if (file_dec->file_dec.status) {
if (file_dec->file_dec.dec_no_out_sound == 0) {
audio_mixer_ch_try_fadeout(&file_dec->mix_ch, 50);
}
file_dec->file_dec.status = 0;
audio_mixer_ch_pause(&file_dec->mix_ch, 1);
file_decoder_close(&file_dec->file_dec);
#if TCFG_SPEED_PITCH_ENABLE
if (file_dec->p_pitchspeed_hdl) {
close_pitchspeed(file_dec->p_pitchspeed_hdl);
}
#endif
#if AUDIO_SURROUND_CONFIG
surround_close_demo(file_dec->surround);
#endif
#if AUDIO_VBASS_CONFIG
audio_gain_close_demo(file_dec->vbass_prev_gain);
audio_noisegate_close_demo(file_dec->ns_gate);
audio_vbass_close_demo(file_dec->vbass);
#endif
#if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE
high_bass_eq_close(file_dec->high_bass);
high_bass_drc_close(file_dec->hb_drc);
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
convet_data_close(file_dec->hb_convert);
#endif
#endif
#if TCFG_EQ_ENABLE && TCFG_MUSIC_MODE_EQ_ENABLE
music_eq_close(file_dec->eq);
#if TCFG_DRC_ENABLE && TCFG_MUSIC_MODE_DRC_ENABLE
music_drc_close(file_dec->drc);
#endif
#if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE
convet_data_close(file_dec->convert);
#endif
#if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC
music_ext_eq_close(file_dec->ext_eq);
#endif
#if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE
music_eq2_close(file_dec->eq2);
audio_dynamic_eq_ctrl_close(file_dec->dy_eq);
convet_data_close(file_dec->convert2);
#endif
#if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE
audio_gain_close_demo(file_dec->gain);
#endif
#endif
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 SYS_DIGVOL_GROUP_EN
sys_digvol_group_ch_close("music_file");
#endif // SYS_DIGVOL_GROUP_EN
// 先关闭各个节点最后才close数据流
if (file_dec->stream) {
audio_stream_close(file_dec->stream);
file_dec->stream = NULL;
}
}
file_dec_release();
sd_active_status_control(0);
clock_set_cur();
log_i("file_dec_close: exit\n");
vddiom_set_dynamic(TCFG_LOWPOWER_VDDIOM_LEVEL);
}
/*----------------------------------------------------------------------------*/
/**@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_DEST_PLAY
static u32 file_dec_dest_test_cb(void *priv)
{
struct file_dec_hdl *dec = priv;
static u8 cnt = 0;
if (cnt < 3) {
cnt ++;
printf("file_dec_dest_test_cb");
struct audio_dest_time_play_param param = {0};
param.start_time = 20 * 1000;
param.dest_time = 30 * 1000;
param.callback_func = file_dec_dest_test_cb;
param.callback_priv = dec;
audio_decoder_ioctrl(&dec->file_dec.decoder, AUDIO_IOCTRL_CMD_SET_DEST_PLAYPOS, &param);
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 跳到指定位置开始播放,播放到目标时间后回调
@param start_time: 要跳转过去播放的起始时间
@param dest_time: 要跳转过去播放的目标时间
@param *cb: 到达目标时间后回调
@param *cb_priv: 回调参数
@return true成功
@return false失败
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_set_start_dest_play(u32 start_time, u32 dest_time, u32(*cb)(void *), void *cb_priv)
{
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: {
struct audio_dest_time_play_param param = {0};
param.start_time = start_time;
param.dest_time = dest_time;
param.callback_func = cb;
param.callback_priv = cb_priv;
audio_decoder_ioctrl(&dec->file_dec.decoder, AUDIO_IOCTRL_CMD_SET_DEST_PLAYPOS, &param);
}
return true;
}
return false;
}
/*----------------------------------------------------------------------------*/
/**@brief 跳到指定位置开始播放
@param start_time: 要跳转过去播放的起始时间
@return true成功
@return false失败
@note
*/
/*----------------------------------------------------------------------------*/
int file_dec_set_start_play(u32 start_time)
{
return file_dec_set_start_dest_play(start_time, 0x7fffffff, NULL, NULL);
}
#endif
#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,
};
/*----------------------------------------------------------------------------*/
/**@brief 设置AB点复读命令
@param ab_cmd: 命令
@param ab_mode: 参数
@return true:成功
@note
*/
/*----------------------------------------------------------------------------*/
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;
}
/*----------------------------------------------------------------------------*/
/**@brief 检查是否可以AB点复读
@param
@return true:成功
@note
*/
/*----------------------------------------------------------------------------*/
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;
}
/*----------------------------------------------------------------------------*/
/**@brief 切换AB点复读状态
@param
@return true:成功
@note
*/
/*----------------------------------------------------------------------------*/
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;
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭AB点复读
@param
@return true:成功
@note
*/
/*----------------------------------------------------------------------------*/
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*/
/*----------------------------------------------------------------------------*/
/**@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*/
}
#endif /*TCFG_APP_MUSIC_EN*/