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

678 lines
17 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 "event/key_event.h"
#include "event/device_event.h"
#include "event/net_event.h"
#include "syscfg/syscfg_id.h"
#include "system/wait.h"
#include "system/app_core.h"
#include "lwip.h"
#ifdef USE_AUDIO_DEMO
#ifdef CONFIG_NET_MUSIC_MODE_ENABLE
#include "server/ai_server.h"
#include "network_download/net_download.h"
#define CONFIG_STORE_VOLUME
#define VOLUME_STEP 5
#define MIN_VOLUME_VALUE 5
#define MAX_VOLUME_VALUE 100
#define INIT_VOLUME_VALUE 50
struct net_music_hdl {
char volume;
u16 wait_download;
int download_ready;
int play_time;
int total_time;
void *net_file;
const char *ai_name;
struct server *dec_server;
struct server *ai_server;
char *url; //保存断点歌曲的链接
struct audio_dec_breakpoint dec_bp;
};
static struct net_music_hdl net_music_handler;
#define __this (&net_music_handler)
//网络解码需要的数据访问句柄
static const struct audio_vfs_ops net_audio_dec_vfs_ops = {
.fread = net_download_read,
.fseek = net_download_seek,
.flen = net_download_get_file_len,
};
int get_app_music_volume(void)
{
return __this->volume;
}
int get_app_music_playtime(void)
{
return __this->play_time;
}
int get_app_music_total_time(void)
{
return __this->total_time;
}
//检查音频需要的格式检查数据头部是否下载缓冲完成
static int __net_download_ready(void *p)
{
__this->download_ready = net_download_check_ready(__this->net_file);
if (__this->download_ready) {
return 1;
}
return 0;
}
//暂停/继续播放
static int net_music_dec_play_pause(u8 notify)
{
union audio_req r = {0};
union ai_req req = {0};
#ifdef CONFIG_DEC_ANALOG_VOLUME_ENABLE
r.dec.attr = AUDIO_ATTR_FADE_INOUT;
#endif
r.dec.cmd = AUDIO_DEC_PP;
server_request(__this->dec_server, AUDIO_REQ_DEC, &r);
if (r.dec.status == AUDIO_DEC_START) {
/* 播放状态 */
net_download_set_pp(__this->net_file, 0);
} else if (r.dec.status == AUDIO_DEC_PAUSE) {
/* 暂停状态 */
net_download_set_pp(__this->net_file, 1);
}
if (notify && __this->ai_server && r.dec.status != AUDIO_DEC_STOP) {
//notify : 是否需要通知云端暂停
req.evt.event = AI_EVENT_PLAY_PAUSE;
req.evt.ai_name = __this->ai_name;
if (r.dec.status == AUDIO_DEC_PAUSE) {
req.evt.arg = 1;
}
ai_server_request(__this->ai_server, AI_REQ_EVENT, &req);
}
return 0;
}
//停止播放
static int net_music_dec_stop(void)
{
union audio_req r = {0};
union ai_req req = {0};
if (!__this->net_file) {
return 0;
}
log_i("net_music_dec_stop\n");
net_download_buf_inactive(__this->net_file);
if (__this->wait_download) {
/*
* 歌曲还未开始播放,删除wait
*/
/* sys_timer_del(__this->wait_download); */
wait_completion_del(__this->wait_download);
__this->wait_download = 0;
} else {
r.dec.cmd = AUDIO_DEC_STOP;
server_request(__this->dec_server, AUDIO_REQ_DEC, &r);
int argv[2];
argv[0] = AUDIO_SERVER_EVENT_END;
argv[1] = (int)__this->net_file;
server_event_handler_del(__this->dec_server, 2, argv);
}
extern int lwip_canceladdrinfo(void);
lwip_canceladdrinfo();
//释放网络下载资源
net_download_close(__this->net_file);
__this->net_file = NULL;
return 0;
}
//播放结束
static int net_music_dec_end(void)
{
union ai_req req = {0};
log_i("net_music_dec_end\n");
net_music_dec_stop();
if (!__this->ai_server) {
return 0;
}
/* 歌曲播放完成,发送此命令后ai平台会发送新的URL */
req.evt.event = AI_EVENT_MEDIA_END;
req.evt.ai_name = __this->ai_name;
return ai_server_request(__this->ai_server, AI_REQ_EVENT, &req);
}
//数据缓冲已完成,开始解码
static int __net_music_dec_file(void *file)
{
int err;
union ai_req r = {0};
union audio_req req = {0};
__this->wait_download = 0;
if (__this->download_ready < 0) {
/* 网络下载失败 */
goto __err;
}
//获取网络资源的格式
req.dec.dec_type = net_download_get_media_type(file);
if (req.dec.dec_type == NULL) {
goto __err;
}
log_i("url_file_type: %s\n", req.dec.dec_type);
net_download_set_read_timeout(file, 5000);
req.dec.cmd = AUDIO_DEC_OPEN;
req.dec.volume = __this->volume;
req.dec.output_buf_len = 6 * 1024;
req.dec.file = (FILE *)file;
req.dec.channel = 0;
req.dec.sample_rate = 0;
req.dec.priority = 1;
req.dec.vfs_ops = &net_audio_dec_vfs_ops;
req.dec.sample_source = CONFIG_AUDIO_DEC_PLAY_SOURCE;
/* req.dec.bp = &__this->dec_bp; //恢复断点 */
#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
err = server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
if (err) {
goto __err;
}
__this->play_time = req.dec.play_time;
__this->total_time = req.dec.total_time;
net_download_set_read_timeout(file, 0);
req.dec.cmd = AUDIO_DEC_START;
server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
net_download_set_pp(file, 0);
return 0;
__err:
log_e("play_net_music_faild\n");
net_download_buf_inactive(file);
req.dec.cmd = AUDIO_DEC_STOP;
server_request(__this->dec_server, AUDIO_REQ_DEC, &req);
net_download_close(file);
__this->net_file = NULL;
if (__this->ai_server) {
r.evt.event = AI_EVENT_MEDIA_END;
r.evt.ai_name = __this->ai_name;
ai_server_request(__this->ai_server, AI_REQ_EVENT, &r);
}
return -1;
}
static int net_music_dec_file(const char *url)
{
int err;
struct net_download_parm parm = {0};
net_music_dec_stop();
if (!url) {
return -1;
}
log_i("net_download_open\n");
parm.url = url;
//网络缓冲buf大小
#ifdef CONFIG_NO_SDRAM_ENABLE
parm.cbuf_size = 150 * 1024;
#else
parm.cbuf_size = 500 * 1024;
#endif
//设置网络下载超时
parm.timeout_millsec = 10000;
#ifdef CONFIG_DOWNLOAD_SAVE_FILE
if (storage_device_ready()) {
parm.save_file = 1;
parm.file_dir = NULL;
}
#endif
parm.seek_threshold = 1024 * 200; //用户可适当调整
/* parm.seek_low_range = __this->dec_bp.fptr; //恢复断点时设置网络的开始下载地址 */
err = net_download_open(&__this->net_file, &parm);
if (err) {
log_e("net_download_open: err = %d\n", err);
return err;
}
/*异步等待网络下载ready,防止网络阻塞导致app_core卡住 */
__this->wait_download = wait_completion(__net_download_ready,
(int (*)(void *))__net_music_dec_file, __this->net_file, NULL);
return 0;
}
//切换上一首或下一首
static int net_music_dec_switch_file(int fsel_mode)
{
union ai_req req = {0};
if (!__this->ai_server) {
return 0;
}
log_i("net_music_dec_switch_file\n");
if (!strcmp(__this->ai_name, "dlna")) {
return 0;
}
net_music_dec_stop();
if (fsel_mode == FSEL_NEXT_FILE) {
req.evt.event = AI_EVENT_NEXT_SONG;
} else if (fsel_mode == FSEL_PREV_FILE) {
req.evt.event = AI_EVENT_PREVIOUS_SONG;
} else {
return 0;
}
req.evt.ai_name = __this->ai_name;
return ai_server_request(__this->ai_server, AI_REQ_EVENT, &req);
}
//获取断点数据
static int net_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 net_music_set_dec_volume(int step)
{
union audio_req req = {0};
union ai_req ai = {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
if (__this->ai_server) {
ai.evt.event = AI_EVENT_VOLUME_CHANGE;
ai.evt.arg = __this->volume;
ai.evt.ai_name = __this->ai_name;
return ai_server_request(__this->ai_server, AI_REQ_EVENT, &ai);
}
return 0;
}
//获取解码器状态
static int net_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;
}
//快进快退,单位是秒,暂时只支持MP3格式
static int net_music_dec_seek(int seek_step)
{
int err;
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("net music seek step : %d\n", seek_step);
return server_request(__this->dec_server, AUDIO_REQ_DEC, &r);
}
static void dec_server_event_handler(void *priv, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_SERVER_EVENT_ERR:
log_i("net_music: AUDIO_SERVER_EVENT_ERR\n");
case AUDIO_SERVER_EVENT_END:
log_i("net_music: AUDIO_SERVER_EVENT_END\n");
net_music_dec_end();
break;
case AUDIO_SERVER_EVENT_CURR_TIME:
log_d("play_time: %d\n", argv[1]);
__this->play_time = argv[1];
break;
}
}
//第三方平台的事件通知回调
static void ai_server_event_handler(void *priv, int argc, int *argv)
{
if (!__this->ai_server) {
switch (argv[0]) {
case AI_SERVER_EVENT_URL:
free((void *)argv[1]);
break;
}
return;
}
switch (argv[0]) {
case AI_SERVER_EVENT_CONNECTED:
break;
case AI_SERVER_EVENT_DISCONNECTED:
break;
case AI_SERVER_EVENT_URL:
case AI_SERVER_EVENT_URL_TTS:
case AI_SERVER_EVENT_URL_MEDIA:
__this->total_time = 0; //清空上一首歌的信息
__this->ai_name = (const char *)argv[2];
const char *url = (const char *)argv[1];
free(__this->url);
__this->url = malloc(strlen(url) + 1);
if (__this->url) {
strcpy(__this->url, url);
}
net_music_dec_file(url);
break;
case AI_SERVER_EVENT_CONTINUE:
if (AUDIO_DEC_PAUSE == net_music_get_dec_status()) {
net_music_dec_play_pause(0);
}
break;
case AI_SERVER_EVENT_PAUSE:
if (AUDIO_DEC_START == net_music_get_dec_status()) {
net_music_dec_play_pause(0);
}
break;
case AI_SERVER_EVENT_STOP:
net_music_dec_stop();
break;
case AI_SERVER_EVENT_RESUME_PLAY:
break;
case AI_SERVER_EVENT_SEEK:
net_music_dec_seek(argv[1] - __this->play_time);
break;
case AI_SERVER_EVENT_VOLUME_CHANGE:
net_music_set_dec_volume(argv[1] - __this->volume);
break;
case AI_SERVER_EVENT_SET_PLAY_TIME:
__this->play_time = argv[1];
break;
default:
break;
}
}
static int net_music_mode_init(void)
{
log_i("net_music_play_main\n");
memset(__this, 0, sizeof(struct net_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->ai_name = "unknown";
__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 (lwip_dhcp_bound()) {
__this->ai_server = server_open("ai_server", NULL);
if (__this->ai_server) {
union ai_req req = {0};
server_register_event_handler_to_task(__this->ai_server, NULL, ai_server_event_handler, "app_core");
ai_server_request(__this->ai_server, AI_REQ_CONNECT, &req);
}
}
return 0;
}
static void net_music_mode_exit(void)
{
net_music_dec_stop();
server_close(__this->dec_server);
__this->dec_server = NULL;
if (__this->ai_server) {
server_close(__this->ai_server);
__this->ai_server = NULL;
}
free(__this->url);
__this->url = NULL;
}
static int net_music_key_click(struct key_event *key)
{
int ret = true;
switch (key->value) {
case KEY_OK:
net_music_dec_play_pause(1);
break;
case KEY_VOLUME_DEC:
net_music_set_dec_volume(-VOLUME_STEP);
break;
case KEY_VOLUME_INC:
net_music_set_dec_volume(VOLUME_STEP);
break;
default:
ret = false;
break;
}
return ret;
}
static int net_music_key_long(struct key_event *key)
{
switch (key->value) {
case KEY_OK:
/* net_music_dec_file(""); */
break;
case KEY_VOLUME_DEC:
net_music_dec_switch_file(FSEL_PREV_FILE);
break;
case KEY_VOLUME_INC:
net_music_dec_switch_file(FSEL_NEXT_FILE);
break;
case KEY_MODE:
net_music_get_dec_breakpoint(&__this->dec_bp);
break;
default:
break;
}
return true;
}
static int net_music_key_event_handler(struct key_event *key)
{
switch (key->action) {
case KEY_EVENT_CLICK:
return net_music_key_click(key);
case KEY_EVENT_LONG:
return net_music_key_long(key);
default:
break;
}
return true;
}
static int net_music_net_event_handler(struct net_event *event)
{
switch (event->event) {
case NET_EVENT_CONNECTED:
if (!__this->ai_server) {
__this->ai_server = server_open("ai_server", NULL);
if (__this->ai_server) {
union ai_req req = {0};
server_register_event_handler_to_task(__this->ai_server, NULL, ai_server_event_handler, "app_core");
ai_server_request(__this->ai_server, AI_REQ_CONNECT, &req);
}
}
break;
default:
break;
}
return false;
}
static int net_music_event_handler(struct application *app, struct sys_event *event)
{
switch (event->type) {
case SYS_KEY_EVENT:
return net_music_key_event_handler((struct key_event *)event->payload);
case SYS_NET_EVENT:
return net_music_net_event_handler((struct net_event *)event->payload);
default:
return false;
}
}
static int net_music_state_machine(struct application *app, enum app_state state, struct intent *it)
{
switch (state) {
case APP_STA_CREATE:
break;
case APP_STA_START:
net_music_mode_init();
break;
case APP_STA_PAUSE:
break;
case APP_STA_RESUME:
break;
case APP_STA_STOP:
net_music_mode_exit();
break;
case APP_STA_DESTROY:
break;
}
return 0;
}
static const struct application_operation net_music_ops = {
.state_machine = net_music_state_machine,
.event_handler = net_music_event_handler,
};
REGISTER_APPLICATION(net_music) = {
.name = "net_music",
.ops = &net_music_ops,
.state = APP_STA_DESTROY,
};
#endif
#endif//USE_AUDIO_DEMO