doubao_chat/apps/common/example/audio/audio_demo/local_music.c

683 lines
18 KiB
C
Raw Permalink 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 "server/audio_server.h"
#include "server/server_core.h"
#include "app_config.h"
#include "storage_device.h"
#include "reverb_deal.h"
#include "event/key_event.h"
#include "event/device_event.h"
#include "syscfg/syscfg_id.h"
#include "system/wait.h"
#include "system/app_core.h"
#ifdef USE_AUDIO_DEMO
#ifdef CONFIG_LOCAL_MUSIC_MODE_ENABLE
#define CONFIG_STORE_VOLUME
#define VOLUME_STEP 5
#define MIN_VOLUME_VALUE 5
#define MAX_VOLUME_VALUE 100
#define INIT_VOLUME_VALUE 50
struct local_music_hdl {
u8 local_play_all; //1:全盘播放 0:播放目录
char volume;
u8 reverb_enable;
u16 wait_sd;
u16 wait_udisk;
int play_time;
int total_time;
FILE *file;
struct vfscan *fscan;
struct vfscan *dir_list;
struct server *dec_server;
struct audio_dec_breakpoint local_bp;
const char *local_path;
};
static struct local_music_hdl local_music_handler;
#define __this (&local_music_handler)
//获取断点数据
static int local_music_get_dec_breakpoint(struct audio_dec_breakpoint *bp)
{
int err;
union audio_req r = {0};
bp->len = 0;
r.dec.bp = bp;
r.dec.cmd = AUDIO_DEC_GET_BREAKPOINT;
if (bp->data) {
free(bp->data);
bp->data = NULL;
}
err = server_request(__this->dec_server, AUDIO_REQ_DEC, &r);
if (err) {
return err;
}
if (r.dec.status == AUDIO_DEC_STOP) {
bp->len = 0;
free(bp->data);
bp->data = NULL;
return -1;
}
/* put_buf(bp->data, bp->len); */
return 0;
}
//设置音量大小
static int local_music_set_dec_volume(int step)
{
union audio_req req = {0};
int volume = __this->volume + step;
if (volume < MIN_VOLUME_VALUE) {
volume = MIN_VOLUME_VALUE;
} else if (volume > MAX_VOLUME_VALUE) {
volume = MAX_VOLUME_VALUE;
}
if (volume == __this->volume) {
return -1;
}
__this->volume = volume;
log_d("set_dec_volume: %d\n", volume);
req.dec.cmd = AUDIO_DEC_SET_VOLUME;
req.dec.volume = volume;
server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
#ifdef CONFIG_STORE_VOLUME
syscfg_write(CFG_MUSIC_VOL, &__this->volume, sizeof(__this->volume));
#endif
return 0;
}
//获取解码器状态
static int local_music_get_dec_status(void)
{
union audio_req req = {0};
req.dec.cmd = AUDIO_DEC_GET_STATUS;
server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
return req.dec.status;
}
//暂停/继续播放
static int local_music_dec_play_pause(void)
{
union audio_req r = {0};
#ifdef CONFIG_DEC_ANALOG_VOLUME_ENABLE
r.dec.attr = AUDIO_ATTR_FADE_INOUT;
#endif
r.dec.cmd = AUDIO_DEC_PP;
return server_request(__this->dec_server, AUDIO_REQ_DEC, &r);
}
//停止播放
static int local_music_dec_stop(void)
{
int err = 0;
union audio_req req = {0};
if (!__this->file) {
return 0;
}
log_i("local_music_dec_stop\n");
req.dec.cmd = AUDIO_DEC_STOP;
server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
int argv[2];
argv[0] = AUDIO_SERVER_EVENT_END;
argv[1] = (int)__this->file;
server_event_handler_del(__this->dec_server, 2, argv);
fclose(__this->file);
__this->file = NULL;
return 0;
}
//解码文件
static int local_music_dec_file(FILE *file)
{
int err;
union audio_req req = {0};
log_i("local_music_dec_local_file\n");
if (!file) {
return -1;
}
local_music_dec_stop();
req.dec.cmd = AUDIO_DEC_OPEN;
req.dec.volume = __this->volume;
req.dec.output_buf_len = 6 * 1024;
req.dec.file = file;
req.dec.channel = 0;
req.dec.sample_rate = 0;
req.dec.priority = 1;
req.dec.sample_source = CONFIG_AUDIO_DEC_PLAY_SOURCE;
#if 0 //变声变调功能
req.dec.speedV = 80; // >80是变快,<80是变慢,建议范围:30到130
req.dec.pitchV = 32768; // >32768是音调变高,<32768音调变低,建议范围20000到50000
req.dec.attr = AUDIO_ATTR_PS_EN;
#endif
#if TCFG_EQ_ENABLE && defined EQ_CORE_V1
req.dec.attr |= AUDIO_ATTR_EQ_EN;
#if TCFG_LIMITER_ENABLE
req.dec.attr |= AUDIO_ATTR_EQ32BIT_EN;
#endif
#if TCFG_DRC_ENABLE
req.dec.attr |= AUDIO_ATTR_DRC_EN;
#endif
#endif
#if CONFIG_DEC_DECRYPT_ENABLE
//播放加密文件
extern const struct audio_vfs_ops *get_decrypt_vfs_ops(void);
req.dec.vfs_ops = get_decrypt_vfs_ops();
req.dec.attr |= AUDIO_ATTR_DECRYPT_DEC;
#endif
err = server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
if (err) {
log_e("audio_dec_open: err = %d\n", err);
fclose(file);
return err;
}
__this->play_time = req.dec.play_time;
__this->total_time = req.dec.total_time; //获取播放总时长
req.dec.cmd = AUDIO_DEC_START;
err = server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
if (err) {
log_e("audio_dec_start: err = %d\n", err);
fclose(file);
return err;
}
__this->file = file;
log_i("play_music_file: suss\n");
return 0;
}
//切换上一首或下一首
static int local_music_dec_switch_file(int fsel_mode)
{
int i = 0;
FILE *file = NULL;
int len = 0;
char name[16] = {0};
log_i("local_music_dec_switch_file\n");
if (!__this->fscan || !__this->fscan->file_number) {
return -1;
}
__retry:
do {
file = fselect(__this->fscan, fsel_mode, fsel_mode == FSEL_BY_NUMBER ? (CPU_RAND() % __this->fscan->file_number) + 1 : 0);
if (file) {
memset(name, 0, sizeof(name));
len = fget_name(file, (u8 *)name, sizeof(name) - 1);
if (len > 0) {
log_i("play file name : %s\n", name);
}
++i;
break;
}
if (fsel_mode == FSEL_NEXT_FILE) {
fsel_mode = FSEL_FIRST_FILE;
} else if (fsel_mode == FSEL_PREV_FILE) {
fsel_mode = FSEL_LAST_FILE;
} else {
break;
}
} while (i++ < __this->fscan->file_number);
if (!file) {
return -1;
}
if (0 != local_music_dec_file(file)) {
if (fsel_mode == FSEL_FIRST_FILE) {
fsel_mode = FSEL_NEXT_FILE;
} else if (fsel_mode == FSEL_LAST_FILE) {
fsel_mode = FSEL_PREV_FILE;
}
goto __retry;
}
return 0;
}
//切换文件夹
static int local_music_dec_switch_dir(int fsel_mode)
{
int len = 0;
int i = 0;
char name[16] = {0};
char path[128] = {0};
FILE *dir = NULL;
FILE *file = NULL;
log_i("local_music_dec_switch_dir\n");
if (!__this->local_path) {
return -1;
}
if (__this->local_play_all && __this->local_path != CONFIG_MUSIC_PATH_FLASH) {
//全盘搜索
if (__this->fscan) {
fscan_release(__this->fscan);
}
#if CONFIG_DEC_DECRYPT_ENABLE
__this->fscan = fscan(__this->local_path, "-r -tMP3WMAWAVM4AAMRAPEFLAAACSPXOPUDTSADPSMP -sn", 2);
#else
__this->fscan = fscan(__this->local_path, "-r -tMP3WMAWAVM4AAMRAPEFLAAACSPXOPUDTSADP -sn", 2);
#endif
if (!__this->fscan) {
return -1;
}
return local_music_dec_switch_file(FSEL_FIRST_FILE);
}
//搜索文件夹
if (!__this->dir_list) {
__this->dir_list = fscan(__this->local_path, "-d -sn", 2);
if (!__this->dir_list || __this->dir_list->file_number == 0) {
log_w("no_music_dir_find\n");
return -1;
}
}
//选择文件夹
__again:
do {
dir = fselect(__this->dir_list, fsel_mode, 0);
if (dir) {
i++;
break;
}
if (fsel_mode == FSEL_NEXT_FILE) {
fsel_mode = FSEL_FIRST_FILE;
} else if (fsel_mode == FSEL_PREV_FILE) {
fsel_mode = FSEL_LAST_FILE;
} else {
log_w("fselect_dir_faild, create dir\n");
return -1;
}
} while (i++ < __this->dir_list->file_number);
if (!dir) {
return -1;
}
len = fget_name(dir, (u8 *)name, sizeof(name) - 1);
if (0 == len) {
fclose(dir);
if (fsel_mode == FSEL_FIRST_FILE) {
fsel_mode = FSEL_NEXT_FILE;
} else if (fsel_mode == FSEL_LAST_FILE) {
fsel_mode = FSEL_PREV_FILE;
}
goto __again;
}
fclose(dir);
if (__this->fscan) {
fscan_release(__this->fscan);
}
fname_to_path(path, __this->local_path, name, len, 1, 0);
#if 0 //此处播放指定目录,用户填写的目录路径要注意中文编码问题,看不懂就直接用16进制把路径打印出来
const char *user_dir = "";
if (!file && strcmp(path, user_dir)) {
log_i("dir name : %s\n", path);
if (fsel_mode == FSEL_FIRST_FILE) {
fsel_mode = FSEL_NEXT_FILE;
} else if (fsel_mode == FSEL_LAST_FILE) {
fsel_mode = FSEL_PREV_FILE;
}
goto __again;
}
#endif
log_i("fscan path : %s\n", path);
/*搜索文件夹下的音频文件,按序号排序*/
#if CONFIG_DEC_DECRYPT_ENABLE
__this->fscan = fscan(path, "-tMP3WMAWAVM4AAMRAPEFLAAACSPXOPUDTSADPSMP -sn", 2);
#else
__this->fscan = fscan(path, "-tMP3WMAWAVM4AAMRAPEFLAAACSPXOPUDTSADP -sn", 2);
#endif
if (!file) {
if (!__this->fscan || !__this->fscan->file_number) {
if (fsel_mode == FSEL_FIRST_FILE) {
fsel_mode = FSEL_NEXT_FILE;
} else if (fsel_mode == FSEL_LAST_FILE) {
fsel_mode = FSEL_PREV_FILE;
}
goto __again;
}
local_music_dec_switch_file(FSEL_FIRST_FILE);
}
return 0;
}
//快进快退,单位是秒,暂时只支持MP3格式
static int local_music_dec_seek(int seek_step)
{
union audio_req r = {0};
if (0 == seek_step) {
return 0;
}
if (__this->total_time != 0 && __this->total_time != -1) {
if (__this->play_time + seek_step <= 0 || __this->play_time + seek_step >= __this->total_time) {
log_e("local music seek out of range\n");
return -1;
}
}
if (seek_step > 0) {
r.dec.cmd = AUDIO_DEC_FF;
r.dec.ff_fr_step = seek_step;
} else {
r.dec.cmd = AUDIO_DEC_FR;
r.dec.ff_fr_step = -seek_step;
}
log_i("local music seek step : %d\n", seek_step);
return server_request(__this->dec_server, AUDIO_REQ_DEC, &r);
}
//释放资源,切换播放源设备
static int local_music_switch_local_device(const char *path)
{
log_i("local_music_switch_local_device\n");
if (__this->dir_list) {
fscan_release(__this->dir_list);
__this->dir_list = NULL;
}
if (__this->fscan) {
fscan_release(__this->fscan);
__this->fscan = NULL;
}
if (__this->wait_sd) {
wait_completion_del(__this->wait_sd);
__this->wait_sd = 0;
}
if (__this->wait_udisk) {
wait_completion_del(__this->wait_udisk);
__this->wait_udisk = 0;
}
local_music_dec_stop();
if (path == NULL) {
return -1;
}
__this->local_path = path;
local_music_dec_switch_dir(FSEL_FIRST_FILE);
return 0;
}
static void dec_server_event_handler(void *priv, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_SERVER_EVENT_ERR:
log_i("local_music: AUDIO_SERVER_EVENT_ERR\n");
case AUDIO_SERVER_EVENT_END:
log_i("local_music: AUDIO_SERVER_EVENT_END\n");
local_music_dec_stop();
local_music_dec_switch_file(FSEL_NEXT_FILE);
break;
case AUDIO_SERVER_EVENT_CURR_TIME:
log_d("play_time: %d\n", argv[1]);
__this->play_time = argv[1];
break;
}
}
static int local_music_mode_init(void)
{
log_i("local_music_play_main\n");
memset(__this, 0, sizeof(struct local_music_hdl));
#ifdef CONFIG_STORE_VOLUME
if (syscfg_read(CFG_MUSIC_VOL, &__this->volume, sizeof(__this->volume)) < 0 ||
__this->volume < MIN_VOLUME_VALUE || __this->volume > MAX_VOLUME_VALUE) {
__this->volume = INIT_VOLUME_VALUE;
}
#else
__this->volume = INIT_VOLUME_VALUE;
#endif
if (__this->volume < 0 || __this->volume > MAX_VOLUME_VALUE) {
__this->volume = INIT_VOLUME_VALUE;
}
__this->local_play_all = 1;
__this->dec_server = server_open("audio_server", "dec");
if (!__this->dec_server) {
return -1;
}
server_register_event_handler_to_task(__this->dec_server, NULL, dec_server_event_handler, "app_core");
if (storage_device_ready()) {
return local_music_switch_local_device(CONFIG_MUSIC_PATH_SD);
} else {
return local_music_switch_local_device(CONFIG_MUSIC_PATH_FLASH);
}
}
static void local_music_mode_exit(void)
{
#if defined CONFIG_REVERB_MODE_ENABLE && defined CONFIG_AUDIO_MIX_ENABLE
if (__this->reverb_enable) {
echo_reverb_uninit();
}
#endif
local_music_switch_local_device(NULL);
server_close(__this->dec_server);
__this->dec_server = NULL;
}
static int local_music_key_click(struct key_event *key)
{
int ret = true;
switch (key->value) {
case KEY_OK:
local_music_dec_play_pause();
break;
case KEY_VOLUME_DEC:
local_music_set_dec_volume(-VOLUME_STEP);
break;
case KEY_VOLUME_INC:
local_music_set_dec_volume(VOLUME_STEP);
break;
default:
ret = false;
break;
}
return ret;
}
static int local_music_key_long(struct key_event *key)
{
switch (key->value) {
case KEY_OK:
local_music_dec_switch_dir(FSEL_NEXT_FILE);
break;
case KEY_VOLUME_DEC:
local_music_dec_switch_file(FSEL_PREV_FILE);
break;
case KEY_VOLUME_INC:
local_music_dec_switch_file(FSEL_NEXT_FILE);
break;
case KEY_MODE:
#if defined CONFIG_REVERB_MODE_ENABLE && defined CONFIG_AUDIO_MIX_ENABLE
if (__this->reverb_enable) {
//关闭混响
echo_reverb_uninit();
__this->reverb_enable = 0;
} else {
//配置混响参数
const struct __HOWLING_PARM_ howling_parm = {13, 20, 20, 300, 5, -50000/*-25000*/, 0, 16000, 1};
#if CONFIG_AUDIO_ENC_SAMPLE_SOURCE != AUDIO_ENC_SAMPLE_SOURCE_MIC
echo_reverb_init(48000, 16000, BIT(CONFIG_AUDIO_ENC_SAMPLE_SOURCE + 3), 100, __this->volume, NULL, NULL, (void *)&howling_parm, NULL);
#else
echo_reverb_init(48000, 16000, BIT(CONFIG_REVERB_ADC_CHANNEL), 100, __this->volume, NULL, NULL, (void *)&howling_parm, NULL);
#endif
__this->reverb_enable = 1;
}
#else
if (storage_device_ready()) {
local_music_switch_local_device(CONFIG_MUSIC_PATH_SD);
}
#endif
break;
default:
break;
}
return true;
}
static int local_music_key_event_handler(struct key_event *key)
{
switch (key->action) {
case KEY_EVENT_CLICK:
return local_music_key_click(key);
case KEY_EVENT_LONG:
return local_music_key_long(key);
default:
break;
}
return true;
}
/*
*设备响应函数
*/
static int local_music_device_event_handler(struct sys_event *sys_eve)
{
struct device_event *device_eve = (struct device_event *)sys_eve->payload;
/* SD卡插拔处理 */
if (sys_eve->from == DEVICE_EVENT_FROM_SD) {
switch (device_eve->event) {
case DEVICE_EVENT_IN:
//等待SD卡挂载完成才开始搜索文件
__this->wait_sd = wait_completion(sdcard_storage_device_ready,
(int (*)(void *))local_music_switch_local_device,
CONFIG_MUSIC_PATH_SD, device_eve->arg);
break;
case DEVICE_EVENT_OUT:
//SD卡拔出,释放资源
local_music_switch_local_device(NULL);
break;
}
#if TCFG_UDISK_ENABLE
/* U盘插拔处理 */
} else if (sys_eve->from == DEVICE_EVENT_FROM_USB_HOST && !strncmp((const char *)device_eve->value, "udisk", 5)) {
switch (device_eve->event) {
case DEVICE_EVENT_IN:
//等待U盘挂载完成才开始搜索文件
__this->wait_udisk = wait_completion(udisk_storage_device_ready,
(int (*)(void *))local_music_switch_local_device,
CONFIG_MUSIC_PATH_UDISK, ((const char *)device_eve->value)[5] - '0');
break;
case DEVICE_EVENT_OUT:
//U盘拔出,释放资源
local_music_switch_local_device(NULL);
break;
}
#endif
}
return true;
}
static int local_music_event_handler(struct application *app, struct sys_event *event)
{
switch (event->type) {
case SYS_KEY_EVENT:
return local_music_key_event_handler((struct key_event *)event->payload);
case SYS_DEVICE_EVENT:
return local_music_device_event_handler(event);
default:
return false;
}
}
static int local_music_state_machine(struct application *app, enum app_state state, struct intent *it)
{
switch (state) {
case APP_STA_CREATE:
break;
case APP_STA_START:
local_music_mode_init();
break;
case APP_STA_PAUSE:
break;
case APP_STA_RESUME:
break;
case APP_STA_STOP:
local_music_mode_exit();
break;
case APP_STA_DESTROY:
break;
}
return 0;
}
static const struct application_operation local_music_ops = {
.state_machine = local_music_state_machine,
.event_handler = local_music_event_handler,
};
REGISTER_APPLICATION(local_music) = {
.name = "local_music",
.ops = &local_music_ops,
.state = APP_STA_DESTROY,
};
#endif
#endif//USE_AUDIO_DEMO