1520 lines
45 KiB
C
1520 lines
45 KiB
C
|
/*
|
|||
|
****************************************************************
|
|||
|
*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, ¶m);
|
|||
|
}
|
|||
|
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, ¶m);
|
|||
|
}
|
|||
|
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*/
|