Files
99_7018_lmx/apps/earphone/music/sd_music.c
2025-10-29 13:10:02 +08:00

755 lines
24 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.

#include "system/includes.h"
#include "music/music_player.h"
#include "music/breakpoint.h"
#include "app_action.h"
#include "app_main.h"
#include "earphone.h"
#include "key_event_deal.h"
#include "audio_config.h"
#include "bt_background.h"
#include "default_event_handler.h"
#include "app_online_cfg.h"
#include "user_cfg.h"
#include "tone_player.h"
#include "app_task.h"
#include "earphone.h"
#include "update.h"
#include "app_power_manage.h"
#include "app_charge.h"
#define LOG_TAG_CONST MUSIC
#define LOG_TAG "[MUSIC]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#if TCFG_APP_MUSIC_EN
#define VALUE_NULL 0
//模式idle状态
static volatile u8 is_music_active = 0;
///模式参数结构体
struct __music_task_parm {
u8 type;
int val;
};
///music模式控制结构体
struct __music {
struct __music_task_parm task_parm;
u16 file_err_counter;//错误文件统计
u8 file_play_direct;//0:下一曲, 1上一曲
u8 scandisk_break;//扫描设备打断标志
char device_tone_dev[16];
#if SD_BAUD_RATE_CHANGE_WHEN_SCAN
u32 old_speed;
#endif
};
struct __music music_hdl = {0};
#define __this (&music_hdl)
static struct __breakpoint *breakpoint = NULL;
static const u8 music_key_table[][KEY_EVENT_MAX] = {
// SHORT LONG HOLD
// UP DOUBLE TRIPLE
{
KEY_MUSIC_PP, KEY_POWEROFF, KEY_POWEROFF_HOLD,
KEY_NULL, KEY_MODE_SWITCH, KEY_NULL
},
{
KEY_MUSIC_NEXT, KEY_VOL_UP, KEY_VOL_UP,
KEY_NULL, KEY_NULL, KEY_NULL
},
{
KEY_MUSIC_PREV, KEY_VOL_DOWN, KEY_VOL_DOWN,
KEY_NULL, KEY_NULL, KEY_NULL
},
};
//*----------------------------------------------------------------------------*/
/**@brief 检测能否进入低功耗
@param 无
@return 无
@note 无
@note 放在按键事件处理后
*/
/*----------------------------------------------------------------------------*/
static void music_powerdown_enter_check(void)
{
u8 music_play_status = 0;
music_play_status = music_player_get_play_status();
if ((is_music_active == 1) && (music_play_status == FILE_DEC_STATUS_PAUSE)) {
is_music_active = 0;
}
/* log_info(">>>>>>>>>>>>>>>enter music_play_status = %d\n", music_play_status); */
}
//*----------------------------------------------------------------------------*/
/**@brief 检测能否退出低功耗
@param 无
@return 无
@note 无
@note 放在按键事件处理前
*/
/*----------------------------------------------------------------------------*/
static void music_powerdown_exit_check(void)
{
u8 music_play_status = 0;
music_play_status = music_player_get_play_status();
//非暂停的自定义按键事件, 把进低功耗的定时器删除
if (music_play_status == FILE_DEC_STATUS_PAUSE) {
if (is_music_active == 0) {
is_music_active = 1;
}
}
/* log_info(">>>>>>>>>>>>>>>exit music_play_status = %d\n", music_play_status); */
}
//*----------------------------------------------------------------------------*/
/**@brief music 解码成功回调
@param priv:私有参数, parm:暂时未用
@return
@note 此处可以做一些用户操作, 如断点保存, 显示, 获取播放信息等
*/
/*----------------------------------------------------------------------------*/
static void music_player_play_success(void *priv, int parm)
{
char *logo = music_player_get_dev_cur();
log_info("\n\n----------------music_player_play_success----------------------\n");
log_info("cur dev = %s\n", logo);
log_info("total dev = %d\n", dev_manager_get_total(1));
log_info("cur filenum = %d\n", music_player_get_file_cur());
log_info("totol filenum = %d\n", music_player_get_file_total());
log_info("totol time = %d\n", music_player_get_dec_total_time());
log_info("sclust = %d\n", music_player_get_file_sclust());
log_info("dir_cur = %d\n", music_player_get_dir_cur());
log_info("dir_total = %d\n", music_player_get_dir_total());
log_info("file indir = %d\n", music_player_get_fileindir_number());
log_info("\n");
///save breakpoint, 只保存文件信息
if (music_player_get_playing_breakpoint(breakpoint, 0) == true) {
breakpoint_vm_write(breakpoint, logo);
}
}
//*----------------------------------------------------------------------------*/
/**@brief music 发送自定义按键消息
@param msg:按键类型; value:发送的值
@return 0:发送正常 -1:发送失败
@note 虚拟按键消息
*/
/*----------------------------------------------------------------------------*/
static int app_music_task_put_key_msg(int msg, int value)
{
if (app_get_curr_task() != APP_MUSIC_TASK) {
//不在音乐模式不发自定义按键消息
log_w("custom msg invalid!");
return -1;
}
struct sys_event e;
e.type = SYS_KEY_EVENT;
e.u.key.event = msg;
e.u.key.value = value;
e.arg = (void *)DEVICE_EVENT_FROM_CUSTOM;
sys_event_notify(&e);
return 0;
}
//*----------------------------------------------------------------------------*/
/**@brief music 解码结束回调处理
@param
@return
@note 此处统一将错误通过消息的方式发出, 在key msg中统一响应
*/
/*----------------------------------------------------------------------------*/
static void music_player_play_end(void *priv, int parm)
{
log_info("music_player_play_end\n");
///这里推出消息, 目的是在music主流程switch case统一入口
app_music_task_put_key_msg(KEY_MUSIC_PLAYER_END, parm);
}
//*----------------------------------------------------------------------------*/
/**@brief music 解码错误回调
@param
@return
@note 此处统一将错误通过消息的方式发出, 在key msg中统一响应
*/
/*----------------------------------------------------------------------------*/
static void music_player_decode_err(void *priv, int parm)
{
log_info("music_player_decode_err\n");
///这里推出消息, 目的是在music主流程switch case统一入口
app_music_task_put_key_msg(KEY_MUSIC_PLAYER_DEC_ERR, parm);
}
static const struct __player_cb music_player_callback = {
.start = music_player_play_success,
.end = music_player_play_end,
.err = music_player_decode_err,
// .fsn_break = music_player_scandisk_break,
};
static const struct __scan_callback scan_cb = {
.enter = NULL,
.exit = NULL,
.scan_break = NULL,
};
//*----------------------------------------------------------------------------*/
/**@brief music 模式初始化处理
@param 无
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void music_task_start()
{
char *log = NULL;
log_info("music task start!!!!!\n");
///时钟初始化
clk_set("sys", CONFIG_MUSIC_DEC_CLOCK);
///按键使能
sys_key_event_enable();
//关闭自动关机
sys_auto_shut_down_disable();
///播放器初始化
struct __player_parm parm = {0};
parm.cb = &music_player_callback;
parm.scan_cb = &scan_cb;
music_player_creat(NULL, &parm);
music_player_set_repeat_mode(FCYCLE_ALL);
///获取断点句柄, 后面所有断点读/写都需要用到
breakpoint = breakpoint_handle_creat();
///初始化一些参数
__this->file_err_counter = 0;
__this->file_play_direct = 0;
__this->scandisk_break = 0;
is_music_active = 1;
}
//*----------------------------------------------------------------------------*/
/**@brief 开始播歌
@param 无
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void music_player_play_start(void)
{
app_music_task_put_key_msg(KEY_MUSIC_PLAYER_START, VALUE_NULL);
}
static void music_save_breakpoint(int save_dec_bp)
{
char *logo = music_player_get_dev_cur();
///save breakpoint, 只保存文件信息
if (music_player_get_playing_breakpoint(breakpoint, save_dec_bp) == true) {
breakpoint_vm_write(breakpoint, logo);
}
}
//*----------------------------------------------------------------------------*/
/**@brief music 模式退出处理
@param 无
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void music_task_close()
{
music_save_breakpoint(1);
music_player_stop(1);
breakpoint_handle_destroy(&breakpoint);
music_player_destroy();
memset(__this, 0, sizeof(struct __music));
is_music_active = 0;
}
//*----------------------------------------------------------------------------*/
/**@brief 恢复音乐模式
@param 无
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void music_task_resume(void)
{
music_task_start();
music_player_play_start();
}
//*----------------------------------------------------------------------------*/
/**@brief 清除自定义按键消息
@param 无
@return 无
@note
*/
/*----------------------------------------------------------------------------*/
static void custom_event_clr(void)
{
struct sys_event clear_key_event = {
.type = SYS_KEY_EVENT,
.arg = (void *)DEVICE_EVENT_FROM_CUSTOM,
};
sys_key_event_disable();
sys_event_clear(&clear_key_event);
}
//*----------------------------------------------------------------------------*/
/**@brief music 在线检测 切换模式判断使用
@param 无
@return 1 设备在线 0 设备不在线
@note
*/
/*----------------------------------------------------------------------------*/
int music_app_check(void)
{
log_info("music_app_check");
if (dev_manager_get_total(1)) {
return true;
}
return false;
}
//*----------------------------------------------------------------------------*/
/**@brief music 模式解码错误处理
@param err:错误码详细错误码描述请看music_player错误码表枚举
@return
@note
*/
/*----------------------------------------------------------------------------*/
void music_player_err_deal(int err)
{
u16 msg = KEY_NULL;
char *logo = NULL;
if (err != MUSIC_PLAYER_ERR_NULL && err != MUSIC_PLAYER_SUCC) {
log_e("music player err = %d\n", err);
}
switch (err) {
case MUSIC_PLAYER_SUCC:
__this->file_err_counter = 0;
break;
case MUSIC_PLAYER_ERR_NULL:
break;
case MUSIC_PLAYER_ERR_POINT:
case MUSIC_PLAYER_ERR_NO_RAM:
msg = KEY_MUSIC_PLAYER_QUIT;//退出音乐模式
break;
case MUSIC_PLAYER_ERR_DECODE_FAIL:
if (__this->file_err_counter >= music_player_get_file_total()) {
__this->file_err_counter = 0;
dev_manager_set_valid_by_logo(music_player_get_dev_cur(), 0);///将设备设置为无效设备
if (dev_manager_get_total(1) == 0) {//参数为1 :获取所有有效设备 参数0获取所有设备
msg = KEY_MUSIC_PLAYER_QUIT;//没有设备了,退出音乐模式
} else {
msg = KEY_MUSIC_AUTO_NEXT_DEV;///所有文件都是错误的, 切换到下一个设备
}
} else {
__this->file_err_counter ++;
if (__this->file_play_direct == 0) {
msg = KEY_MUSIC_NEXT;//播放下一曲
} else {
msg = KEY_MUSIC_PREV;//播放上一曲
}
}
break;
case MUSIC_PLAYER_ERR_DEV_NOFOUND:
if (dev_manager_get_total(1) == 0) {//参数为1 :获取所有有效设备 参数0获取所有设备
msg = KEY_MUSIC_PLAYER_QUIT;///没有设备在线, 退出音乐模式
} else {
msg = KEY_MUSIC_PLAYER_START;///没有找到指定设备, 播放之前的活动设备
}
break;
case MUSIC_PLAYER_ERR_FSCAN:
///需要结合music_player_scandisk_break中处理的标志位处理
if (__this->scandisk_break) {
__this->scandisk_break = 0;
///此处不做任何处理, 打断的事件已经重发, 由重发事件执行后续处理
break;
}
case MUSIC_PLAYER_ERR_DEV_READ:
case MUSIC_PLAYER_ERR_DEV_OFFLINE:
log_e("MUSIC_PLAYER_ERR_DEV_OFFLINE \n");
logo = music_player_get_dev_cur();
if (dev_manager_online_check_by_logo(logo, 1)) {
///如果错误失败在线, 并且是播放过程中产生的,先记录下断点
if (music_player_get_playing_breakpoint(breakpoint, 1) == true) {
music_player_stop(0);//先停止防止下一步操作VM卡顿
breakpoint_vm_write(breakpoint, logo);
}
if (err == MUSIC_PLAYER_ERR_FSCAN) {
dev_manager_set_valid_by_logo(logo, 0);///将设备设置为无效设备
} else {
//针对读错误, 因为时间推到应用层有延时导致下一个模式判断不正常, 此处需要将设备卸载
dev_manager_unmount(dev_manager_get_logo(dev_manager_find_active(0)));
}
}
if (dev_manager_get_total(1) == 0) {
msg = KEY_MUSIC_PLAYER_QUIT;///没有设备在线, 退出音乐模式
} else {
msg = KEY_MUSIC_AUTO_NEXT_DEV;///切换设备
}
break;
case MUSIC_PLAYER_ERR_FILE_NOFOUND:
///查找文件有扫盘的可能也需要结合music_player_scandisk_break中处理的标志位处理
if (__this->scandisk_break) {
__this->scandisk_break = 0;
///此处不做任何处理, 打断的事件已经重发, 由重发事件执行后续处理
break;
}
case MUSIC_PLAYER_ERR_PARM:
logo = music_player_get_dev_cur();
if (dev_manager_online_check_by_logo(logo, 1)) {
if (music_player_get_file_total()) {
msg = KEY_MUSIC_PLAYER_PLAY_FIRST;///有文件,播放第一个文件
break;
}
}
if (dev_manager_get_total(1) == 0) {
msg = KEY_MUSIC_PLAYER_QUIT;//没有设备了,退出音乐模式
} else {
msg = KEY_MUSIC_AUTO_NEXT_DEV;
}
break;
case MUSIC_PLAYER_ERR_FILE_READ://文件读错误
msg = KEY_MUSIC_NEXT;//播放下一曲
break;
}
if (msg != KEY_NULL) {
app_music_task_put_key_msg(msg, VALUE_NULL);
}
}
//*----------------------------------------------------------------------------*/
/**@brief music 模式按键处理
@param 按键消息
@return
@note
*/
/*----------------------------------------------------------------------------*/
static int app_music_key_event_handler(struct sys_event *event)
{
int ret = true;
int err = MUSIC_PLAYER_ERR_NULL;
u8 vol, auto_next_dev;
int mode ;
char *logo = NULL;
int key_event = 0;
struct key_event *key = &event->u.key;
if (event->arg == DEVICE_EVENT_FROM_KEY) {
key_event = music_key_table[key->value][key->event];//物理按键事件
} else {
key_event = key->event;//软件按键事件
}
log_info("music task msg = %d\n", key_event);
music_powerdown_exit_check();
switch (key_event) {
case KEY_MUSIC_PLAYER_START:
log_info("KEY_MUSIC_PLAYER_START !!\n");
///断点播放活动设备
logo = dev_manager_get_logo(dev_manager_find_active(1));
if (music_player_get_play_status() == FILE_DEC_STATUS_PLAY) {
if (music_player_get_dev_cur() && logo) {
///播放的设备跟当前活动的设备是同一个设备,不处理
if (0 == strcmp(logo, music_player_get_dev_cur())) {
log_w("the same dev!!\n");
break;
}
}
}
if (true == breakpoint_vm_read(breakpoint, logo)) {
err = music_player_play_by_breakpoint(logo, breakpoint);
} else {
err = music_player_play_first_file(logo);
}
break;
///播放器退出处理
case KEY_MUSIC_PLAYER_QUIT:
log_info("KEY_MUSIC_PLAYER_QUIT !!\n");
app_task_switch_next();
break;
///结束消息处理
case KEY_MUSIC_PLAYER_END:
log_info("KEY_MUSIC_PLAYER_END\n");
err = music_player_end_deal(key->value);
break;
//播放器解码错误处理
case KEY_MUSIC_PLAYER_DEC_ERR:
err = music_player_decode_err_deal(key->value);
break;
///播放执行类消息
case KEY_MUSIC_PP:
log_info("KEY_MUSIC_PP\n");
err = music_player_pp();
log_info("=============================================%d\n", music_player_get_play_status());
break;
case KEY_MUSIC_PLAYER_AUTO_NEXT:
log_info("KEY_MUSIC_PLAYER_AUTO_NEXT\n");
err = music_player_play_auto_next();
break;
case KEY_MUSIC_PLAYER_PLAY_FIRST:
log_info("KEY_MUSIC_PLAYER_PLAY_FIRST\n");
err = music_player_play_first_file(NULL);
break;
case KEY_MUSIC_PREV:
log_info("KEY_MUSIC_PREV\n");
__this->file_play_direct = 1;
err = music_player_play_prev();
break;
case KEY_MUSIC_NEXT:
log_info("KEY_MUSIC_NEXT\n");
__this->file_play_direct = 0;
err = music_player_play_next();
break;
case KEY_MUSIC_PLAYE_PREV_FOLDER:
log_info("KEY_MUSIC_PLAYE_PREV_FOLDER\n");
err = music_player_play_folder_prev();
break;
case KEY_MUSIC_PLAYE_NEXT_FOLDER:
log_info("KEY_MUSIC_PLAYE_NEXT_FOLDER\n");
err = music_player_play_folder_next();
break;
case KEY_MUSIC_AUTO_NEXT_DEV:
case KEY_MUSIC_CHANGE_DEV:
log_info("KEY_MUSIC_CHANGE_DEV\n");
auto_next_dev = ((key_event == KEY_MUSIC_AUTO_NEXT_DEV) ? 1 : 0);
logo = music_player_get_dev_next(auto_next_dev);
log_info("next dev = %s\n", logo);
if (logo == NULL) { ///找不到下一个设备,不响应设备切换
break;
}
///切换设备前先保存一下上一个设备的断点信息,包括文件和解码信息
if (music_player_get_playing_breakpoint(breakpoint, 1) == true) {
music_player_stop(0);//先停止防止下一步操作VM卡顿
breakpoint_vm_write(breakpoint, music_player_get_dev_cur());
}
if (true == breakpoint_vm_read(breakpoint, logo)) {
err = music_player_play_by_breakpoint(logo, breakpoint);
} else {
err = music_player_play_first_file(logo);
}
break;
case KEY_MUSIC_PLAYE_BY_DEV_FILENUM:
log_info("KEY_MUSIC_PLAYE_BY_DEV_FILENUM, file_number = %d\n", key->value);
logo = dev_manager_get_logo(dev_manager_find_active(1));
err = music_player_play_by_number(logo, key->value);
break;
case KEY_MUSIC_PLAYE_BY_DEV_SCLUST:
log_info("KEY_MUSIC_PLAYE_BY_DEV_SCLUST\n");
logo = dev_manager_get_logo(dev_manager_find_active(1));
err = music_player_play_by_sclust(logo, key->value);
break;
case KEY_MUSIC_PLAYE_BY_DEV_PATH:
log_info("KEY_MUSIC_PLAYE_BY_DEV_PATH\n");
err = music_player_play_by_path((char *)"udisk0", "/sin.wav");///this is a demo
break;
///非播放执行类消息
case KEY_MUSIC_FF:
log_info("KEY_MUSIC_FF\n");
music_player_ff(3);
break;
case KEY_MUSIC_FR:
log_info("KEY_MUSIC_FR\n");
music_player_fr(3);
break;
case KEY_MUSIC_CHANGE_REPEAT:
log_info("KEY_MUSIC_CHANGE_REPEAT\n");
mode = music_player_change_repeat_mode();
break;
case KEY_MUSIC_DELETE_FILE:
log_info("KEY_MUSIC_DELETE_FILE\n");
err = music_player_delete_playing_file();
break;
case KEY_MUSIC_PLAYER_AB_REPEAT_SWITCH:
/* file_dec_ab_repeat_switch(); */
break;
case KEY_MODE_SWITCH:
log_info("KEY_MUSIC_SWITCH\n");
app_task_switch_next();
break;
case KEY_VOL_UP:
log_info("KEY_VOL_UP\n");
if (!tone_get_status()) {
app_audio_volume_up(1);
log_info("vol+: %d", app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
}
if (app_audio_get_volume(APP_AUDIO_CURRENT_STATE) == app_audio_get_max_volume()) {
if (tone_get_status() == 0) {
#if TCFG_MAX_VOL_PROMPT
STATUS *p_tone = get_tone_config();
tone_play_index(p_tone->max_vol, 0);
#endif
}
}
break;
case KEY_VOL_DOWN:
log_info("KEY_VOL_DOWN\n");
app_audio_volume_down(1);
log_info("vol-: %d", app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
break;
case KEY_POWEROFF:
case KEY_POWEROFF_HOLD:
app_earphone_key_event_handler(event);
break;
default:
ret = false;
break;
}
music_powerdown_enter_check();
//退出模式后,不做错误处理
if (is_music_active == 0) {
return false;
}
///错误处理
log_info("music play err = %d\n", err);
music_player_err_deal(err);
return false;
}
/*
* 系统事件处理函数
*/
static int event_handler(struct application *app, struct sys_event *event)
{
switch (event->type) {
case SYS_KEY_EVENT:
/*
* 普通按键消息处理
*/
return app_music_key_event_handler(event);
case SYS_BT_EVENT:
/*
* 蓝牙事件处理
*/
break;
case SYS_DEVICE_EVENT:
/*
* 系统设备事件处理
*/
if ((u32)event->arg == DRIVER_EVENT_FROM_SD0) {
if (event->u.dev.event == DEVICE_EVENT_OUT) {
update_clear_result();
music_save_breakpoint(1);
dev_manager_del((char *)event->u.dev.value);
app_task_switch_next();
return true;
}
}
if ((u32)event->arg == DRIVER_EVENT_FROM_SD0) {
#if TCFG_ONLINE_ENABLE
} else if ((u32)event->arg == DEVICE_EVENT_FROM_CI_UART) {
ci_data_rx_handler(CI_UART);
#if TCFG_USER_TWS_ENABLE
} else if ((u32)event->arg == DEVICE_EVENT_FROM_CI_TWS) {
ci_data_rx_handler(CI_TWS);
#endif
#endif
} else if ((u32)event->arg == DEVICE_EVENT_FROM_POWER) {
app_power_event_handler(&event->u.dev);
return true;
} else if ((u32)event->arg == DEVICE_EVENT_FROM_CHARGE) {
app_charge_event_handler(&event->u.dev);
return true;
}
break;
default:
break;
}
default_event_handler(event);
return false;
}
static int state_machine(struct application *app, enum app_state state,
struct intent *it)
{
int err = 0;
int tone_play_err = 0;
switch (state) {
case APP_STA_CREATE: {
log_info("APP_STA_CREATE\n");
//播完提示音再开始播SD卡
tone_play_err = tone_play_with_callback(TONE_MUSIC_MODE, 1, music_player_play_start, NULL);
if (tone_play_err == -EINVAL) {
log_info("tone play err! music_player_play_start!\n");
music_player_play_start();
}
}
break;
case APP_STA_START:
if (!it) {
break;
}
switch (it->action) {
case ACTION_MUSIC_MAIN:
log_info("ACTION_MUSIC_MAIN\n");
music_task_start();
break;
case ACTION_MUSIC_TWS_RX:
break;
}
break;
case APP_STA_PAUSE:
log_info("APP_STA_PAUSE\n");
music_task_close();
break;
case APP_STA_RESUME:
log_info("APP_STA_RESUME\n");
music_task_resume();
break;
case APP_STA_STOP:
log_info("APP_STA_STOP\n");
music_task_close();
break;
case APP_STA_DESTROY:
log_info("APP_STA_DESTROY\n");
custom_event_clr();
break;
}
return err;
}
static const struct application_operation app_music_ops = {
.state_machine = state_machine,
.event_handler = event_handler,
};
/*
* 注册music模式
*/
REGISTER_APPLICATION(app_music) = {
.name = "music",
.action = ACTION_MUSIC_MAIN,
.ops = &app_music_ops,
.state = APP_STA_DESTROY,
};
/*
* 注册idle状态
*/
static u8 music_idle_query(void)
{
return !is_music_active;
}
REGISTER_LP_TARGET(music_lp_target) = {
.name = "music",
.is_idle = music_idle_query,
};
#endif