515 lines
13 KiB
C
515 lines
13 KiB
C
/********************************测试例程说明************************************
|
||
* 功能说明:
|
||
* 通过HTTP协议,播放网络音频文件,并将音频文件存储至指定路径(可选)。
|
||
*
|
||
* 使用说明:
|
||
* 确保网络连接成功、存储设备就绪,指定网络音频路径URL、存储路径PATH,
|
||
* 调用 net_audio_play_test()函数播放网络音频,即可开始下载。
|
||
* ******************************************************************************/
|
||
#include "system/includes.h"
|
||
#include "http/http_cli.h"
|
||
#include "server/audio_server.h"
|
||
#include "fs/fs.h"
|
||
#include <stdlib.h>
|
||
#include "storage_device.h"
|
||
#include "device/device.h"//u8
|
||
#include "server/video_dec_server.h"//fopen
|
||
#include "system/includes.h"//GPIO
|
||
#include "asm/port_waked_up.h"
|
||
#include "asm/gpio.h"
|
||
#include "app_config.h"
|
||
#include "wifi/wifi_connect.h"
|
||
#include "ename.h"
|
||
|
||
#ifdef USE_DevKitBoard_TEST_DEMO
|
||
|
||
/*#define WIFI_MUSIC_PATH "http://music.163.com/song/media/outer/url?id=66282.mp3"*/
|
||
#define WIFI_MUSIC_PATH "https://test02.jieliapp.com/tmp/2021/12/31/music_test.mp3"
|
||
|
||
#if 1
|
||
#define log_info(x, ...) printf("\n\n[audio_test]###" x " ", ## __VA_ARGS__)
|
||
#else
|
||
#define log_info(...)
|
||
#endif
|
||
|
||
#define DATA_BUF_SIZE (50*1024)
|
||
#define RECV_BUF_SIZE (512)
|
||
#define SAVE_BUF_SIZE (5*1024)//网络卡的时候这个buf需要改大
|
||
|
||
#define SHUTDOWN_CMD (1000)
|
||
|
||
struct net_audio_hdl {
|
||
char *url; //音频链接
|
||
char *path; //文件存放路径
|
||
FILE *fp; //文件指针
|
||
struct server *dec_server; //解码服务
|
||
u8 *data_buf; //音频数据buffer
|
||
cbuffer_t data_cbuf; //音频数据cycle buffer
|
||
u32 recv_size; //已接收音频数据长度
|
||
char *recv_buf; //数据缓存buffer
|
||
u32 total_size; //音频文件总长度
|
||
u32 play_size; //当前播放进度
|
||
OS_SEM r_sem; //读音频数据信号量
|
||
OS_SEM w_sem; //写音频数据信号量
|
||
u8 run_flag; //播放标志
|
||
u8 dec_ready_flag; //解码器就绪标志位
|
||
u8 dec_status; //解码器运行标志位
|
||
u8 dec_volume; //播放音量
|
||
int recv_task_pid; //recv_task句柄
|
||
int play_task_pid; //music_task句柄
|
||
int connect_flag; //网络连接标志
|
||
httpcli_ctx *ctx; //HTTP请求参数
|
||
const struct net_download_ops *download_ops; //http操作集
|
||
};
|
||
|
||
|
||
struct play_parm {
|
||
char *url; //音频链接
|
||
char *path; //文件存放路径
|
||
u8 volume; //播放音量
|
||
};
|
||
|
||
|
||
static int net_audio_buf_write(void *priv, char *data, u32 len);
|
||
static int net_audio_vfs_fread(void *priv, void *data, u32 len);
|
||
static int net_audio_vfs_flen(void *priv);
|
||
static int net_audio_vfs_seek(void *priv, u32 offset, int orig);
|
||
static void dec_server_event_handler(void *priv, int argc, int *argv);
|
||
static int open_audio_dec(void *priv);
|
||
static int close_audio_dec(void *priv);
|
||
static void recv_net_audio_data_task(void *priv);
|
||
static s32 httpin_user_cb(void *_ctx, void *buf, u32 size, void *priv, httpin_status status);
|
||
static void net_audio_play_task(void *priv);
|
||
|
||
|
||
//将音频数据写入data_cbuf
|
||
static int net_audio_buf_write(void *priv, char *data, u32 len)
|
||
{
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
u32 wlen = 0;
|
||
|
||
while (hdl->run_flag) {
|
||
wlen = cbuf_write(&hdl->data_cbuf, data, len);
|
||
if (wlen) {
|
||
os_sem_set(&hdl->w_sem, 0);
|
||
os_sem_post(&hdl->r_sem);
|
||
/*putchar('('); */
|
||
hdl->recv_size += len;
|
||
//音频下载成功,或缓存成功,打开解码器,开始播放
|
||
if ((hdl->recv_size >= hdl->total_size || hdl->recv_size >= SAVE_BUF_SIZE) && hdl->dec_status == 0) {
|
||
log_info(">>>>>>>>>>>audio dec open!\n");
|
||
open_audio_dec(hdl);
|
||
hdl->dec_status = 1;
|
||
}
|
||
break;
|
||
}
|
||
/*log_info(">>>>>write pend......\n");*/
|
||
os_sem_pend(&hdl->w_sem, 0);
|
||
}
|
||
|
||
return wlen;
|
||
}
|
||
|
||
|
||
static int net_audio_vfs_fread(void *priv, void *data, u32 len)
|
||
{
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
u32 rlen = 0;
|
||
|
||
while (hdl->run_flag && hdl->dec_ready_flag) {
|
||
if (hdl->total_size - hdl->play_size < 512) {
|
||
len = hdl->total_size - hdl->play_size;
|
||
}
|
||
|
||
rlen = cbuf_read(&hdl->data_cbuf, data, len);
|
||
if (rlen) {
|
||
hdl->play_size += rlen;
|
||
|
||
//发送写信号
|
||
os_sem_set(&hdl->r_sem, 0);
|
||
os_sem_post(&hdl->w_sem);
|
||
/* putchar(')'); */
|
||
|
||
if (hdl->play_size >= hdl->total_size) {
|
||
hdl->run_flag = 0;
|
||
hdl->dec_ready_flag = 0;
|
||
log_info("net audio play complete.\n");
|
||
log_info("play size = %d.\n", hdl->play_size);
|
||
}
|
||
break;
|
||
}
|
||
|
||
/* log_info(">>>>>read pend......\n"); */
|
||
os_sem_pend(&hdl->r_sem, 0);
|
||
}
|
||
return ((hdl->play_size >= hdl->total_size) ? 0 : len);
|
||
}
|
||
|
||
|
||
static int net_audio_vfs_flen(void *priv)
|
||
{
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
return hdl->total_size;
|
||
}
|
||
|
||
|
||
static int net_audio_vfs_seek(void *priv, u32 offset, int orig)
|
||
{
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
|
||
if (offset > 0) {
|
||
hdl->dec_ready_flag = 1; //解码器开始偏移数据后,再开始播放,避免音频播放开端吞字
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
static const struct audio_vfs_ops net_audio_vfs_ops = {
|
||
.fread = net_audio_vfs_fread,
|
||
.flen = net_audio_vfs_flen,
|
||
.fseek = net_audio_vfs_seek,
|
||
};
|
||
|
||
|
||
static void dec_server_event_handler(void *priv, int argc, int *argv)
|
||
{
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
int msg = 0;
|
||
|
||
switch (argv[0]) {
|
||
case AUDIO_SERVER_EVENT_ERR:
|
||
log_info("AUDIO_SERVER_EVENT_ERR\n");
|
||
break;
|
||
|
||
case AUDIO_SERVER_EVENT_END:
|
||
log_info("AUDIO_SERVER_EVENT_END\n");
|
||
msg = SHUTDOWN_CMD;
|
||
os_taskq_post("net_audio_play_task", 1, msg);
|
||
|
||
break;
|
||
|
||
case AUDIO_SERVER_EVENT_CURR_TIME:
|
||
log_info("play_time: %d\n", argv[1]);
|
||
os_taskq_post("ui_main_task", 2, UI_MSG_PLEAY_TIME, argv[1]);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
static int open_audio_dec(void *priv)
|
||
{
|
||
union audio_req req = {0};
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
|
||
req.dec.cmd = AUDIO_DEC_OPEN;
|
||
req.dec.volume = hdl->dec_volume;
|
||
req.dec.output_buf = NULL;
|
||
req.dec.output_buf_len = 12 * 1024;
|
||
req.dec.channel = 0;
|
||
req.dec.sample_rate = 0;
|
||
req.dec.priority = 1;
|
||
req.dec.vfs_ops = &net_audio_vfs_ops;
|
||
req.dec.file = (FILE *)hdl;
|
||
req.dec.dec_type = "mp3";
|
||
req.dec.sample_source = "dac";
|
||
|
||
//打开解码器
|
||
if (server_request(hdl->dec_server, AUDIO_REQ_DEC, &req) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
os_taskq_post("ui_main_task", 2, UI_MSG_PLEAY_ALL_TIME, req.dec.total_time);
|
||
|
||
//开始解码
|
||
req.dec.cmd = AUDIO_DEC_START;
|
||
if (server_request(hdl->dec_server, AUDIO_REQ_DEC, &req) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
static int close_audio_dec(void *priv)
|
||
{
|
||
union audio_req req = {0};
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
|
||
req.dec.cmd = AUDIO_DEC_STOP;
|
||
if (hdl->dec_server) {
|
||
|
||
//关闭解码器
|
||
log_info("stop dec.\n");
|
||
server_request(hdl->dec_server, AUDIO_REQ_DEC, &req);
|
||
|
||
//关闭解码服务
|
||
log_info("close audio_server.\n");
|
||
server_close(hdl->dec_server);
|
||
hdl->dec_server = NULL;
|
||
}
|
||
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
static void shutdown_audio_play(void *priv)
|
||
{
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
|
||
//关闭音频
|
||
close_audio_dec(hdl);
|
||
|
||
|
||
//关闭数据接收线程
|
||
if (hdl->recv_task_pid) {
|
||
log_info("kill recv task");
|
||
thread_kill(&hdl->recv_task_pid, KILL_FORCE);
|
||
}
|
||
|
||
//关闭http
|
||
if (hdl->connect_flag) {
|
||
log_info("close http.\n");
|
||
hdl->download_ops->close(hdl->ctx);
|
||
hdl->connect_flag = 0;
|
||
}
|
||
|
||
/*//关闭播放线程*/
|
||
/*if (hdl->music_task_pid) {*/
|
||
/*thread_kill(hdl->music_task_pid, KILL_WAIT);*/
|
||
/*}*/
|
||
|
||
//释放内存
|
||
log_info("free memory start.\n");
|
||
|
||
if (hdl->ctx) {
|
||
free(hdl->ctx);
|
||
}
|
||
|
||
if (hdl->data_buf) {
|
||
free(hdl->data_buf);
|
||
}
|
||
|
||
if (hdl->recv_buf) {
|
||
free(hdl->recv_buf);
|
||
}
|
||
|
||
if (hdl->url) {
|
||
free(hdl->url);
|
||
}
|
||
|
||
if (hdl->path) {
|
||
free(hdl->path);
|
||
}
|
||
|
||
if (hdl) {
|
||
memset(hdl, 0, sizeof(struct net_audio_hdl));
|
||
free(hdl);
|
||
}
|
||
|
||
log_info("free memory stop.\n");
|
||
}
|
||
|
||
|
||
static void recv_net_audio_data_task(void *priv)
|
||
{
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
int ret = 0;
|
||
|
||
|
||
_reconnect_:
|
||
//发起连接请求,建立socket连接
|
||
ret = hdl->download_ops->init(hdl->ctx);
|
||
if (ret != HERROR_OK) {
|
||
if (hdl->ctx->req_exit_flag == 0) {
|
||
os_time_dly(50);
|
||
goto _reconnect_;
|
||
}
|
||
} else {
|
||
hdl->connect_flag = 1;
|
||
}
|
||
|
||
while (hdl->ctx->req_exit_flag == 0) {
|
||
//读取数据
|
||
ret = hdl->download_ops->read(hdl->ctx, hdl->recv_buf, sizeof(hdl->recv_buf));
|
||
if (hdl->ctx->req_exit_flag) {
|
||
goto _out_;
|
||
}
|
||
|
||
if (ret < 0) { //读取数据失败
|
||
log_info("recv fail.\n");
|
||
} else {
|
||
net_audio_buf_write(hdl, hdl->recv_buf, ret);
|
||
/*log_info(">>>>>>>>>>>>>>>>>11net_audio_buf_write\n");*/
|
||
}
|
||
|
||
if (hdl->recv_size >= hdl->total_size) {
|
||
break;
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
_out_:
|
||
//关闭网络连接
|
||
hdl->download_ops->close(hdl->ctx);
|
||
hdl->connect_flag = 0;
|
||
}
|
||
|
||
|
||
static s32 httpin_user_cb(void *_ctx, void *buf, u32 size, void *priv, httpin_status status)
|
||
{
|
||
u32 wlen = 0;
|
||
httpcli_ctx *ctx = (httpcli_ctx *)_ctx;
|
||
struct net_audio_hdl *hdl = (struct net_audio_hdl *)priv;
|
||
|
||
if (status == HTTPIN_HEADER) {
|
||
if (ctx->content_length) {
|
||
hdl->run_flag = 1;
|
||
hdl->total_size = ctx->content_length;
|
||
log_info("HTTPIN_HEADER content_length = %d\n", ctx->content_length);
|
||
}
|
||
|
||
if (ctx->content_type[0]) {
|
||
log_info("HTTPIN_HEADER content_type = %s\n", ctx->content_type);
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
static void net_audio_play_task(void *priv)
|
||
{
|
||
struct play_parm *parm = (struct play_parm *)priv;
|
||
struct net_audio_hdl *hdl = NULL;
|
||
int msg[32] = {0};
|
||
int res = 0;
|
||
|
||
//申请堆内存
|
||
hdl = (struct net_audio_hdl *)calloc(1, sizeof(struct net_audio_hdl));
|
||
if (hdl == NULL) {
|
||
return;
|
||
}
|
||
|
||
hdl->ctx = (httpcli_ctx *)calloc(1, sizeof(httpcli_ctx));
|
||
if (hdl->ctx == NULL) {
|
||
return;
|
||
}
|
||
|
||
hdl->data_buf = (char *)calloc(1, DATA_BUF_SIZE);
|
||
if (hdl->data_buf == NULL) {
|
||
return;
|
||
}
|
||
|
||
hdl->recv_buf = (char *)calloc(1, RECV_BUF_SIZE);
|
||
if (hdl->recv_buf == NULL) {
|
||
return;
|
||
}
|
||
|
||
hdl->url = (char *)calloc(1, strlen(parm->url) + 1);
|
||
if (hdl->url == NULL) {
|
||
return;
|
||
}
|
||
strcpy(hdl->url, parm->url);
|
||
|
||
//初始化cycle buffer
|
||
cbuf_init(&hdl->data_cbuf, hdl->data_buf, DATA_BUF_SIZE);
|
||
|
||
os_sem_create(&hdl->r_sem, 0);
|
||
os_sem_create(&hdl->w_sem, 0);
|
||
|
||
|
||
hdl->dec_volume = parm->volume;
|
||
hdl->download_ops = &http_ops;
|
||
|
||
//http请求参数赋值
|
||
hdl->ctx->url = hdl->url;
|
||
hdl->ctx->cb = httpin_user_cb;
|
||
hdl->ctx->priv = hdl;
|
||
hdl->ctx->connection = "close";
|
||
hdl->ctx->timeout_millsec = 10000;
|
||
|
||
hdl->dec_server = server_open("audio_server", "dec");
|
||
if (!hdl->dec_server) {
|
||
log_info("audio server open fail.\n");
|
||
return;
|
||
} else {
|
||
log_info("open success");
|
||
}
|
||
|
||
log_info(">>>>>>>>%d\n", __LINE__);
|
||
server_register_event_handler(hdl->dec_server, hdl, dec_server_event_handler);
|
||
log_info(">>>>>>>>%d\n", __LINE__);
|
||
|
||
thread_fork("recv_net_audio_data_task", 20, 1024 * 4, 0, &hdl->recv_task_pid, recv_net_audio_data_task, hdl);
|
||
|
||
for (;;) {
|
||
res = os_task_pend("taskq", msg, ARRAY_SIZE(msg));
|
||
|
||
if (msg[1] == SHUTDOWN_CMD) {
|
||
log_info("recv shutdown req.\n");
|
||
|
||
shutdown_audio_play(hdl);
|
||
log_info("kill self.\n");
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
static void shutdown_audio_play_test(void)
|
||
{
|
||
int msg = 0;
|
||
msg = SHUTDOWN_CMD;
|
||
os_taskq_post("net_audio_play_task", 1, msg);
|
||
}
|
||
|
||
|
||
void net_audio_play_test(char *url, char *path, u8 volume)
|
||
{
|
||
struct play_parm parm = {0};
|
||
|
||
if (url == NULL || url[0] == '\0') {
|
||
return;
|
||
}
|
||
|
||
parm.url = (char *)calloc(1, strlen(url) + 1);
|
||
if (parm.url == NULL) {
|
||
return;
|
||
}
|
||
|
||
strcpy(parm.url, url);
|
||
|
||
parm.volume = volume;
|
||
|
||
thread_fork("net_audio_play_task", 20, 1024, 512, NULL, net_audio_play_task, &parm);
|
||
|
||
}
|
||
|
||
static void wifi_music_stask(void *priv)
|
||
{
|
||
u8 state;
|
||
net_audio_play_test(WIFI_MUSIC_PATH, CONFIG_STORAGE_PATH, 100);
|
||
}
|
||
|
||
void wifi_music_start(void)
|
||
{
|
||
puts("wifi_music_start \n\n");
|
||
thread_fork("wifi_music_stask", 11, 1024, 0, 0, wifi_music_stask, NULL);
|
||
}
|
||
|
||
void wifi_music_end(void)
|
||
{
|
||
os_taskq_post("net_audio_play_task", 1, SHUTDOWN_CMD);
|
||
}
|
||
|
||
|
||
#endif
|
||
|
||
|