Files
99_7018_lmx/cpu/br28/audio_dec/audio_dec_file.c
2025-10-29 13:10:02 +08:00

1306 lines
35 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 "media/file_decoder.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 "audio_dec/audio_dec_file.h"
#include "media/audio_stream.h"
#include "music/music_decrypt.h"
#include "music/music_id3.h"
#include "application/eq_config.h"
#include "audio_dec_eff.h"
#include "bt_tws.h"
#include "media/bt_audio_timestamp.h"
#include "media/audio_syncts.h"
#include "audio_codec_clock.h"
#include "sound_device.h"
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
#include "audio_dvol.h"
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
#if TCFG_APP_MUSIC_EN
#define FILE_DEC_PICK_EN 0 // 本地解码拆包转发
#define FILE_DEC_ALIGN 0
#define FILE_DEC_START 1
#define FILE_DEC_INVITE 2
#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-不使用淡入淡出
struct file_dec_hdl *file_dec = NULL; // 文件解码句柄
u8 file_dec_start_pause = 0; // 启动解码后但不马上开始播放
extern struct audio_dac_hdl dac_hdl;
//////////////////////////////////////////////////////////////////////////////
void file_eq_drc_open(struct file_dec_hdl *hdl, u16 sample_rate, u8 ch_num);
void file_eq_drc_close(struct file_dec_hdl *hdl);
extern void *local_tws_dec_sync_open(u8 channel, u16 sample_rate, u16 output_rate);
extern void local_tws_sync_no_check_data_buf(u8 no_check);
extern void audio_mix_ch_event_handler(void *priv, int event);
extern void bt_audio_sync_nettime_select(u8 base);
int file_dec_repeat_set(u8 repeat_num);
//////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
/**@brief 获取文件解码hdl
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void *get_file_dec_hdl()
{
return file_dec;
}
static enum audio_channel file_dec_get_output_channel()
{
enum audio_channel channel;
#if TCFG_USER_TWS_ENABLE
int state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {
channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
} else {
u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
if (dac_connect_mode == DAC_OUTPUT_LR) {
channel = AUDIO_CH_LR;
} else {
channel = AUDIO_CH_DIFF;
}
}
#else
u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
if (dac_connect_mode == DAC_OUTPUT_LR) {
channel = AUDIO_CH_LR;
} else {
channel = AUDIO_CH_DIFF;
}
#endif
return channel;
}
static u8 file_dec_output_channel_num(void)
{
u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
if (dac_connect_mode == AUDIO_CH_LR) {
return 2;
}
return 1;
}
/*----------------------------------------------------------------------------*/
/**@brief 读取文件数据
@param *decoder: 解码器句柄
@param *buf: 数据
@param len: 数据长度
@return >=0读到的数据长度
@return <0错误
@note
*/
/*----------------------------------------------------------------------------*/
static int file_fread(struct audio_decoder *decoder, void *buf, u32 len)
{
int rlen;
struct file_dec_hdl *dec = file_dec;
#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');
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_dec_hdl *dec = file_dec;
return fseek(dec->file, offset, seek_mode);
}
/*----------------------------------------------------------------------------*/
/**@brief 读取文件长度
@param *decoder: 解码器句柄
@return 文件长度
@note
*/
/*----------------------------------------------------------------------------*/
static int file_flen(struct audio_decoder *decoder)
{
int len = 0;
struct file_dec_hdl *dec = file_dec;
len = flen(dec->file);
return len;
}
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_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
,
.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,
}
}
};
#if TCFG_DEC2TWS_ENABLE
static inline u16 local_tws_audio_seqn(void *buf)
{
u16 seqn;
/*Get local tws audio sequence.*/
if (!buf) {
return 0;
}
memcpy(&seqn, buf, sizeof(seqn));
return seqn;
}
static inline u16 local_tws_audio_timestamp(void *buf)
{
u32 timestamp;
/*Get local tws audio sequence.*/
if (!buf) {
return 0;
}
memcpy(&timestamp, buf, sizeof(timestamp));
return timestamp;
}
/*static int frame_fread(struct audio_decoder *decoder, u8 **frame)*/
static int frame_fread(struct audio_decoder *decoder, void *buf, u32 len)
{
int offset = 0;
int frame_len;
struct file_dec_hdl *dec = file_dec;
while (len) {
int clen = MIN(dec->frame_remain_len, len);
if (clen) {
memcpy((u8 *)buf + offset,
dec->frame + dec->frame_len - dec->frame_remain_len, clen);
len -= clen;
offset += clen;
dec->frame_remain_len -= clen;
break;
} else {
if (dec->frame) {
tws_api_data_trans_free(dec->tws_channel, dec->frame);
}
dec->frame = tws_api_data_trans_pop(dec->tws_channel, &frame_len);
if (!dec->frame) {
dec->frame_remain_len = 0;
break;
}
#if 0
u16 seqn = local_tws_audio_seqn(dec->frame);
if ((u16)(seqn - dec->seqn) > 1) {
log_w("Local tws audio sequence error : %d, %d.\n", seqn, dec->seqn);
}
dec->seqn = seqn;
#else
u32 timestamp = local_tws_audio_timestamp(dec->frame);
audio_syncts_next_pts(dec->syncts, timestamp);
dec->mix_ch_event_params[2] = timestamp;
#endif
dec->frame_len = frame_len;
dec->frame_remain_len = frame_len - sizeof(dec->seqn);
}
}
if (offset == 0) {
// r_printf("no_data\n");
if (dec->trans_dec_end) {
return -EINVAL;
}
}
return offset;
}
static int frame_fseek(struct audio_decoder *decoder, u32 offset, int seek_mode)
{
return 0;
}
static int frame_flen(struct audio_decoder *decoder)
{
return 0x7fffffff;
}
static const struct audio_dec_input frame_input = {
.coding_type = 0,
.data_type = AUDIO_INPUT_FILE,
.ops = {
.file = {
.fread = frame_fread,
.fseek = frame_fseek,
.flen = frame_flen,
}
}
};
#endif
/*----------------------------------------------------------------------------*/
/**@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);
audio_codec_clock_del(AUDIO_FILE_MODE);
#if TCFG_DEC2TWS_ENABLE
if (dec->tws_channel) {
tws_api_data_trans_close(dec->tws_channel);
}
#endif
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(MUSIC_DVOL);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
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)
{
printf("file_dec_event_handler: %d\n", argv[0]);
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 TCFG_DEC2TWS_ENABLE
if (decoder == &file_dec->trans_dec.decoder) {
file_dec->trans_dec_end = 1;
break;
}
#endif
if (decoder != &file_dec->file_dec.decoder) {
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();
}
break;
default:
break;
}
}
static int file_decoder_output_after_syncts(void *priv, void *data, int len)
{
struct file_dec_hdl *dec = (struct file_dec_hdl *)priv;
#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
if (dec->eq_drc && dec->eq_drc->async) {
return eq_drc_run(dec->eq_drc, data, len);//异步eq
}
#endif//TCFG_MUSIC_MODE_EQ_ENABLE
int wlen = audio_mixer_ch_write(&dec->mix_ch, data, len);
return wlen;
}
static int file_decoder_output_hander(struct file_decoder *decoder, s16 *data, int len)
{
int wlen = 0;
struct file_dec_hdl *dec = container_of(decoder, struct file_dec_hdl, file_dec);
if (!dec->remain) {
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run(MUSIC_DVOL, data, len);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
if (dec->eq_drc && !dec->eq_drc->async) {
eq_drc_run(dec->eq_drc, data, len);//同步eq
}
#endif
}
#if TCFG_DEC2TWS_ENABLE
if (dec->syncts) {
int wlen = audio_syncts_frame_filter(dec->syncts, data, len);
if (wlen < len) {
audio_syncts_trigger_resume(dec->syncts, (void *)decoder, (void (*)(void *))audio_decoder_resume);
}
dec->remain = wlen < len ? 1 : 0;
return wlen;
}
#endif
wlen = file_decoder_output_after_syncts(dec, data, len);
dec->remain = wlen < len ? 1 : 0;
return wlen;
}
static int tws_local_media_trans_handler(struct file_decoder *decoder, s16 *data, int len)
{
/*int wlen = tws_api_local_media_trans_bulk_push((u8 *)data, len);*/
struct file_dec_hdl *dec = container_of(decoder, struct file_dec_hdl, file_dec);
int wlen = 0;
#if TCFG_DEC2TWS_ENABLE
/*wlen = tws_api_local_media_push_with_sequence((u8 *)data, len, file_dec->tx_seqn);*/
u32 timestamp = 0;
if (dec->ts_handle) {
timestamp = file_audio_timestamp_update(dec->ts_handle, dec->pcm_num);
}
wlen = tws_api_local_media_push_with_timestamp((u8 *)data, len, timestamp);
if (wlen) {
u16 pcm_num = 0;
memcpy(&pcm_num, data, sizeof(pcm_num));
/*printf("Num : %d x 32\n", pcm_num);*/
dec->pcm_num += (pcm_num * 32);
/*file_dec->tx_seqn++;*/
}
#endif
/*printf("trans: %d, %d\n", wlen, len);*/
return wlen;
}
static int tws_file_decoder_syncts_setup(struct file_dec_hdl *dec)
{
int err = 0;
#if TCFG_DEC2TWS_ENABLE
struct audio_syncts_params params = {0};
params.nch = file_dec_output_channel_num();
params.pcm_device = PCM_INSIDE_DAC;
params.network = AUDIO_NETWORK_BT2_1;
params.rin_sample_rate = dec->file_dec.sample_rate;
params.rout_sample_rate = dec->file_dec.sample_rate;
params.priv = dec;
params.factor = TIME_US_FACTOR;
params.output = file_decoder_output_after_syncts;
bt_audio_sync_nettime_select(1);
err = audio_syncts_open(&dec->syncts, &params);
if (!err) {
dec->mix_ch_event_params[0] = (u32)&dec->mix_ch;
dec->mix_ch_event_params[1] = (u32)dec->syncts;
audio_mixer_ch_set_event_handler(&dec->mix_ch, (void *)dec->mix_ch_event_params, audio_mix_ch_event_handler);
}
#endif
return err;
}
static void tws_file_decoder_syncts_free(struct file_dec_hdl *dec)
{
#if TCFG_DEC2TWS_ENABLE
if (dec->syncts) {
audio_syncts_close(dec->syncts);
dec->syncts = NULL;
}
#endif
}
static int tws_data_trans_handler(struct file_decoder *dec, s16 *data, int len)
{
int wlen = 0;
#if TCFG_DEC2TWS_ENABLE
u8 *buf = tws_api_data_trans_buf_alloc(file_dec->tws_channel, len + 2);
if (!buf) {
return 0;
}
memcpy(buf, &file_dec->tx_seqn, 2);
memcpy(buf + 2, data, len);
tws_api_data_trans_push(file_dec->tws_channel, buf, len + 2);
file_dec->tx_seqn++;
#endif
/*printf("trans: %d, %d\n", wlen, len);*/
return len;
}
/*----------------------------------------------------------------------------*/
/**@brief 文件解码开始
@param
@return 0成功
@return 非0失败
@note
*/
/*----------------------------------------------------------------------------*/
static int file_dec_start()
{
int err;
enum audio_channel channel;
struct file_dec_hdl *dec = file_dec;
struct audio_mixer *p_mixer = &mixer;
if (!dec) {
return -EINVAL;
}
log_i("file_dec_start: in\n");
// 打开file解码器
#if TCFG_DEC2TWS_ENABLE
err = frame_decoder_open(&dec->file_dec, &frame_input, &decode_task);
#else
err = file_decoder_open(&dec->file_dec, &file_input, &decode_task, dec->bp, 0);
#endif
if (err) {
goto __err1;
}
dec->file_dec.output_handler = file_decoder_output_hander;
file_decoder_set_event_handler(&dec->file_dec, file_dec_event_handler, dec->id);
channel = file_dec_get_output_channel();
audio_decoder_set_output_channel(&dec->file_dec.decoder, channel);
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
// 设置叠加功能
audio_mixer_ch_open(&dec->mix_ch, p_mixer);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, dec->file_dec.sample_rate);
int ch_num = 1;
if (channel == AUDIO_CH_LR) {
ch_num = 2;
}
file_eq_drc_open(dec, dec->file_dec.sample_rate, ch_num);
sound_pcm_dev_channel_mapping(ch_num);
#if TCFG_DEC2TWS_ENABLE
tws_file_decoder_syncts_setup(dec);
#endif
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
// 设置时钟
/*clk_set("sys", 120000000);*/
audio_codec_clock_set(AUDIO_FILE_MODE, dec->file_dec.coding_type, dec->wait.preemption);
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);
}
err = audio_decoder_start(&dec->file_dec.decoder);
if (err) {
goto __err2;
}
return 0;
__err2:
dec->file_dec.status = 0;
audio_mixer_ch_close(&dec->mix_ch);
file_eq_drc_close(dec);
file_decoder_close(&dec->file_dec);
__err1:
if (dec->evt_cb && (dec->wait_add)) {
int msg[2];
msg[0] = AUDIO_DEC_EVENT_ERR;
dec->evt_cb(dec->evt_priv, 2, msg);
}
file_dec_release();
/*clk_set("sys", 24000000);*/
audio_codec_clock_del(AUDIO_FILE_MODE);
return err;
}
#if TCFG_DEC2TWS_ENABLE
static void tws_file_trans_timestamp_free(struct file_dec_hdl *dec)
{
if (dec->ts_handle) {
file_audio_timestamp_close(dec->ts_handle);
dec->ts_handle = NULL;
}
}
static void tws_file_trans_timestamp_create(struct file_dec_hdl *dec)
{
tws_file_trans_timestamp_free(dec);
bt_audio_sync_nettime_select(1);
dec->ts_handle = file_audio_timestamp_create(0, dec->trans_dec.sample_rate, bt_audio_sync_lat_time(), 250, TIME_US_FACTOR);
dec->pcm_num = 0;
}
static void send_data_trans_dec_start_cmd();
static int tws_file_dec_trans_start(void)
{
int err;
u8 channel = AUDIO_CH_LR;
struct file_dec_hdl *dec = file_dec;
if (!dec) {
return -EINVAL;
}
log_i("file_dec_trans_start: in\n");
// 打开file解码器
err = file_decoder_open(&dec->trans_dec, &file_input, &decode_task, dec->bp, 1);
if (err) {
goto __err1;
}
dec->tx_seqn = 1;
dec->trans_dec.output_handler = tws_data_trans_handler;
file_decoder_set_event_handler(&dec->trans_dec, file_dec_event_handler, dec->id);
audio_decoder_set_output_channel(&dec->trans_dec.decoder, channel);
audio_decoder_set_run_max(&dec->trans_dec.decoder, 5);
dec->file_dec.sample_rate = dec->trans_dec.sample_rate;
dec->file_dec.coding_type = dec->trans_dec.coding_type & 0x0fffffff;
log_i("total_time : %d\n", dec->trans_dec.dec_total_time);
// 设置时钟
/*clk_set("sys", 120000000);*/
audio_codec_clock_set(AUDIO_FILE_MODE, dec->file_dec.coding_type, dec->wait.preemption);
dec->tws_channel = tws_api_data_trans_open(dec->tws_channel,
TWS_DTC_LOCAL_MEDIA, 10 * 1024);
send_data_trans_dec_start_cmd();
int ch_num = 1;
if (channel == AUDIO_CH_LR) {
ch_num = 2;
}
/* file_eq_drc_open(dec, dec->file_dec.sample_rate, ch_num); */
tws_file_trans_timestamp_create(dec);
dec->trans_dec_end = 0;
dec->trans_dec.status = FILE_DEC_STATUS_PLAY;
err = audio_decoder_start(&dec->trans_dec.decoder);
if (err) {
goto __err2;
}
return 0;
__err2:
dec->file_dec.status = 0;
file_decoder_close(&dec->file_dec);
tws_file_trans_timestamp_free(dec);
tws_api_data_trans_stop(dec->tws_channel);
file_eq_drc_close(dec);
__err1:
file_dec_release();
/*clk_set("sys", 24000000);*/
audio_codec_clock_del(AUDIO_FILE_MODE);
return err;
}
#endif
/*----------------------------------------------------------------------------*/
/**@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;
if (file_dec->file_dec.status == FILE_DEC_STATUS_PLAY) {
audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
#if TCFG_DEC2TWS_ENABLE
tws_api_auto_drop_frame_enable(0);
tws_file_decoder_syncts_setup(file_dec);
#endif
err = audio_decoder_start(&file_dec->file_dec.decoder);
audio_decoder_resume_all(&decode_task);
} else if (file_dec->file_dec.status == FILE_DEC_STATUS_PAUSE) {
audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
}
}
} 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) {
audio_decoder_resume_all(&decode_task);
err = audio_decoder_pause(&file_dec->file_dec.decoder);
audio_mixer_ch_close(&file_dec->mix_ch);
#if TCFG_DEC2TWS_ENABLE
tws_file_decoder_syncts_free(file_dec);
tws_api_auto_drop_frame_enable(1);
#endif
}
file_dec->file_dec.tmp_pause = 1;
}
}
return err;
}
#if TCFG_DEC2TWS_ENABLE
static void send_data_trans_dec_start_cmd()
{
u8 args[8];
if (file_dec->file_dec.status) {
u32 data[1];
data[0] = FILE_DEC_INVITE;
tws_api_send_data_to_sibling(data, sizeof(data), TWS_FUNC_ID_FILE_DEC);
}
if (file_dec->file_dec.coding_type == AUDIO_CODING_MP3) {
args[0] = 1;
} else if (file_dec->file_dec.coding_type == AUDIO_CODING_WMA) {
args[0] = 2;
}
args[1] = file_dec->file_dec.sample_rate;
args[2] = file_dec->file_dec.sample_rate >> 8;
args[3] = file_dec->id & 0xff;
tws_api_data_trans_start(file_dec->tws_channel, args, 4);
}
static int tws_file_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
log_i("tws_file_wait_res_handler, event:%d, status:%d ", event,
file_dec->trans_dec.status);
if (event == AUDIO_RES_GET) {
// 启动解码
if (file_dec->trans_dec.status == 0) {
err = tws_file_dec_trans_start();
if (err) {
return err;
}
} else if (file_dec->trans_dec.tmp_pause) {
file_dec->trans_dec.tmp_pause = 0;
if (file_dec->trans_dec.status == FILE_DEC_STATUS_PLAY) {
err = audio_decoder_start(&file_dec->trans_dec.decoder);
}
}
} else if (event == AUDIO_RES_PUT) {
// 被打断
if (file_dec->trans_dec.status) {
if (file_dec->trans_dec.status == FILE_DEC_STATUS_PLAY || \
file_dec->trans_dec.status == FILE_DEC_STATUS_PAUSE) {
err = audio_decoder_pause(&file_dec->trans_dec.decoder);
}
file_dec->trans_dec.tmp_pause = 1;
}
}
file_wait_res_handler(wait, event);
return err;
}
void send_local_media_dec_open_cmd()
{
puts("send_local_media_dec_open_cmd\n");
if (!file_dec) {
return;
}
if (file_dec->trans_dec.status) {
puts("---trans_open\n");
file_dec->tws_channel = tws_api_data_trans_open(file_dec->tws_channel,
TWS_DTC_LOCAL_MEDIA, 10 * 1024);
}
if (file_dec->file_dec.status) {
puts("---dec_open\n");
send_data_trans_dec_start_cmd();
}
}
#endif
/*----------------------------------------------------------------------------*/
/**@brief file解码pp处理
@param play: 1-播放。0-暂停
@return
@note 弱函数重定义
*/
/*----------------------------------------------------------------------------*/
static void file_dec_pp_ctrl(u8 play)
{
if (!file_dec) {
return ;
}
#if TCFG_DEC2TWS_ENABLE
if (play) {
// 播放前处理
if (!file_dec->pick_flag) {
audio_mixer_ch_pause(&file_dec->mix_ch, 0);
}
} else {
// 暂停后处理
if (!file_dec->pick_flag) {
audio_mixer_ch_pause(&file_dec->mix_ch, 1);
}
audio_decoder_resume_all_by_sem(&decode_task, 2); // 超时等待解码task运行一轮
}
#else
if (play) {
// 播放前处理
if (!file_dec->pick_flag) {
audio_mixer_ch_open(&file_dec->mix_ch, &mixer);
}
} else {
// 暂停后处理
if (!file_dec->pick_flag) {
audio_mixer_ch_close(&file_dec->mix_ch);
}
audio_decoder_resume_all_by_sem(&decode_task, 2); // 超时等待解码task运行一轮
}
#endif
}
/*----------------------------------------------------------------------------*/
/**@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 = 2;//audio_output_channel_num();
#if TCFG_DEC_DECRYPT_ENABLE
cipher_init(&dec->mply_cipher, TCFG_DEC_DECRYPT_KEY);
cipher_check_decode_file(&dec->mply_cipher, file);
#endif
dec->wait_add = 1;
#if TCFG_DEC2TWS_ENABLE
dec->wait.priority = 1;
dec->wait.preemption = 1;
dec->wait.handler = tws_file_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
#else
dec->wait.priority = 1;
dec->wait.preemption = 1;
dec->wait.handler = file_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
#endif
if (file_dec) {
file_dec->wait_add = 0;
}
return err;
}
int tws_local_media_dec_open(u8 channel, u8 *arg)
{
int err;
struct file_dec_hdl *dec = file_dec;
log_i("tws_local_media_dec_open\n");
if (!dec) {
dec = zalloc(sizeof(*dec));
if (!dec) {
return -EPERM;
}
file_dec = dec;
}
if (arg[0] == 1) {
dec->file_dec.coding_type = AUDIO_CODING_MP3;
} else if (arg[0] == 2) {
dec->file_dec.coding_type = AUDIO_CODING_WMA;
}
dec->file_dec.sample_rate = (arg[2] << 8) | arg[1];
dec->id = arg[3];
#if TCFG_USER_TWS_ENABLE
dec->tws_channel = channel;
#endif
dec->wait.priority = 1;
dec->wait.preemption = 1;
dec->wait.handler = file_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
return err;
}
int tws_local_media_dec_state()
{
if (!file_dec) {
return 0;
}
if (file_dec->file_dec.status == FILE_DEC_STATUS_PLAY) {
return 1;
}
return 0;
}
static 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);
file_eq_drc_close(file_dec);
tws_file_decoder_syncts_free(file_dec);
audio_mixer_ch_close(&file_dec->mix_ch);
if (file_dec->stream_handler) {
file_dec->stream_handler(file_dec->stream_priv, FILE_DEC_STREAM_CLOSE,
file_dec);
}
#if TCFG_DEC2TWS_ENABLE
if (file_dec->frame) {
tws_api_data_trans_free(file_dec->tws_channel, file_dec->frame);
file_dec->frame = NULL;
}
#endif
}
file_dec_release();
log_i("file_dec_close: exit\n");
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭文件解码
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void file_dec_close(void)
{
#if TCFG_DEC2TWS_ENABLE
if (!file_dec) {
return;
}
if (file_dec->trans_dec.status) {
file_dec->trans_dec.status = 0;
file_decoder_close(&file_dec->trans_dec);
tws_api_data_trans_stop(file_dec->tws_channel);
file_eq_drc_close(file_dec);
}
tws_file_trans_timestamp_free(file_dec);
tws_api_data_trans_clear(file_dec->tws_channel);
#endif
__file_dec_close();
}
#if TCFG_DEC2TWS_ENABLE
void tws_local_media_dec_close()
{
file_dec_close();
}
#endif
/*----------------------------------------------------------------------------*/
/**@brief 获取file_dec句柄
@param
@return file_dec句柄
@note
*/
/*----------------------------------------------------------------------------*/
struct file_decoder *file_dec_get_file_decoder_hdl(void)
{
if (!file_dec) {
return NULL;
}
#if TCFG_DEC2TWS_ENABLE
return &file_dec->trans_dec;
#else
return &file_dec->file_dec;
#endif
}
/*----------------------------------------------------------------------------*/
/**@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;
}
int file_dec_get_source()
{
if (!file_dec) {
return -EINVAL;
}
#if TCFG_DEC2TWS_ENABLE
if (file_dec->trans_dec.status) {
return FILE_FROM_LOCAL;
}
if (file_dec->file_dec.status) {
return FILE_FROM_TWS;
}
#else
if (file_dec->file_dec.status) {
return FILE_FROM_LOCAL;
}
#endif
return -EINVAL;
}
/*----------------------------------------------------------------------------*/
/**@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;
}
/*----------------------------------------------------------------------------*/
/**@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 (file_dec && (&file_dec->file_dec == dec)) {
file_dec_pp_ctrl(play);
}
}
/*----------------------------------------------------------------------------*/
/**@brief 音乐模式 eq drc 打开
@param sample_rate:采样率
@param ch_num:通道个数
@return 句柄
@note
*/
/*----------------------------------------------------------------------------*/
void file_eq_drc_open(struct file_dec_hdl *hdl, u16 sample_rate, u8 ch_num)
{
#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
u8 drc_en = 0;
#if TCFG_DRC_ENABLE&&TCFG_MUSIC_MODE_DRC_ENABLE
drc_en = 1;
#endif//TCFG_MUSIC_MODE_DRC_ENABLE
hdl->eq_drc = dec_eq_drc_setup(&hdl->mix_ch, (eq_output_cb)audio_mixer_ch_write, sample_rate, ch_num, 1, drc_en);
#endif//TCFG_MUSIC_MODE_EQ_ENABLE
}
/*----------------------------------------------------------------------------*/
/**@brief 音乐模式 eq drc 关闭
@param 句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
void file_eq_drc_close(struct file_dec_hdl *hdl)
{
#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
if (hdl->eq_drc) {
dec_eq_drc_free(hdl->eq_drc);
hdl->eq_drc = NULL;
}
#endif//TCFG_MUSIC_MODE_EQ_ENABLE
}
#endif /*TCFG_APP_MUSIC_EN*/