RVB2601应用开发实战系列六:网络播放器设计(二)

简介: 本文是基于RVB2601开发板实现网络播放器设计的下篇,主要介绍基于YoC软件平台av组件采用http协议播放一首网络mp3歌曲。

本文作者:少川

本文转自:芯片开放社区(OCC)

一、前言

本例程基于YoC软件平台av组件采用http协议播放一首网络mp3歌曲。当开发板成功通过sal(底层通过at指令连接内置的网卡芯片)连接网络后,可输入相应串口命令行从web服务器上拉取mp3歌曲实现边拉取音频源数据边播放的功能。开发者可基于该例程实现更为丰富的网络播放功能。 本例程名为ch2601_webplayer_demo,可以通过CDK直接从OCC拉取。


二、如何使用

1.下载代码并编译运行

  • 通过cdk搜索ch2601_webplayer_demo并下载工程代码打开后,会有如下界面。其中框1为解决方案组件,框2中是该解决方案依赖的子功能组件。
  • 在本例程中,主要依赖av(音视频软件框架)、pvmp3dec(mp3解码器)、drv_wifi_at_w800(wifi驱动)等组件。

1.png


  • 在IDE上编译通过后,点击下载进行烧录。烧录成功后,复位运行。成功运行后,串口会有如何打印输出:

2.png


2.网络连接

通过ifconfig命令可配置需要连接的热点。具体命令为:

ifconfig ap wifi_ssid wifi_psk

热点配置成功后,会有下图如下打印:

3.png


3.命令行播放控制

可通过在串口下输入如下命令来控制歌曲的播放

# player help        player play welcom/url[http://]  #播放内置开机音频或网络歌曲        player pause                     #暂停播放        player resume                    #恢复播放        player stop#停止播放        player help                      #播放器帮助命令


播放http歌曲player play http://yocbook.oss-cn-hangzhou.aliyuncs.com/av_repo/alibaba.mp3,示例如下:

ayer play http://yocbook.oss-cn-hangzhou.aliyuncs.com/av_repo/alibaba.mp3
# [  13.620]<E>w800_api domain to ip: 47.110.23.146[  13.630]<D>sals remote_port -- : 80[  13.710]<D>WEB http request: 
GET /av_repo/alibaba.mp3 HTTP/1.0
Host: yocbook.oss-cn-hangzhou.aliyuncs.com
User-Agent: CSKY/YOC
[  15.000]<D>stream upto cache threshold2, pos =553, cache_pos =809, diff=256[  15.420]<D>avparser find a parser, name = mp3, id =1[  15.440]<D>ad find a decode, name = pvmp3dec, id =1[  15.450]<D>filter_swr open a avfilter, name = swr
[  15.470]<D>filter_vol open a avfilter, name = vol
[  15.470]<D>ao_alsa  ao open
[  15.490]<D>ao ao ref: openref =1, startref =0, fun = __ao_open
[  15.510]<D>ao ori sf ==> sf =90317074, rate =44100, ch =2, bits =16, siged =1, float =0, endian =0[  15.540]<D>ao ao  sf ==> sf =90316946, rate =44100, ch =1, bits =16, siged =1, float =0, endian =0[  15.810]<D>ao ao ref: openref =1, startref =1, fun = __ao_start
[  15.820]<D>player_demo =====_player_event, 24, type =2[  15.820]<D>player player_get_media_info, 809 enter. player = 20009E00
[  15.830]<D>player player_get_media_info, 821 leave. player = 20009E00
[  15.830]<D>player_demo =====rc =0, duration = 415807ms, bps =64000, size =3326462


三、例程开发

1.主要代码解析

1.1 主函数流程

主函数位于ch2601_webplayer_demo/app/src/app_main.c中。详细的解释如下:

staticvoidnetwork_event(uint32_tevent_id, constvoid*param, void*context)
{
switch(event_id) {
caseEVENT_NETMGR_GOT_IP:
LOGD(TAG, "net got ip");
break;
caseEVENT_NETMGR_NET_DISCON:
LOGD(TAG, "net disconnect");
break;
    }
/*do exception process */app_exception_event(event_id);
}
intmain(void)
{
board_yoc_init();     // 板级配置、kv文件系统、声卡驱动、网卡驱动等初始化player_init();        // 播放器模块初始化cli_reg_cmd_player(); // 播放器命令行注册/* Subscribe */event_subscribe(EVENT_NETMGR_GOT_IP, network_event, NULL);     // 订阅网络连接事件event_subscribe(EVENT_NETMGR_NET_DISCON, network_event, NULL); // 订阅网络断开事件}

1.2 声卡、网卡驱动注册等

代码位于ch2601_webplayer_demo/app/src/init.c中。

staticvoidnetwork_init()
{
w800_wifi_param_tw800_param;
/* init wifi driver and network */w800_param.reset_pin=PA21;
w800_param.baud=1*1000000;
w800_param.cs_pin=PA15;
w800_param.wakeup_pin=PA25;
w800_param.int_pin=PA22;
w800_param.channel_id=0;
w800_param.buffer_size=4*1024;
wifi_w800_register(NULL, &w800_param);
app_netmgr_hdl=netmgr_dev_wifi_init();
if (app_netmgr_hdl) {
utask_t*task=utask_new("netmgr", 2*1024, QUEUE_MSG_COUNT, AOS_DEFAULT_APP_PRI);
netmgr_service_init(task);
netmgr_start(app_netmgr_hdl);
    }
}
voidboard_yoc_init(void)
{
board_init();                                 // 板级初始化event_service_init(NULL);                     // 发布订阅服务初始化console_init(CONSOLE_UART_IDX, 115200, 512);  // 串口初始化ulog_init();                                  // 日志初始化aos_set_log_level(AOS_LL_DEBUG);              // 配置默认日志打印级别intret=partition_init();                   // 分区初始化if (ret<=0) {
LOGE(TAG, "partition init failed");
    } else {
LOGI(TAG, "find %d partitions", ret);
    }
aos_kv_init("kv");                            // kv文件系统初始化,可用于保存网络ssid&psksnd_card_alkaid_register(NULL);               // 声卡初始化,可用于播放&采集network_init();                               // 网络初始化board_cli_init();                             // 命令行初始化并注册默认的命令}


1.3 网络底层通信

2601主芯片是通过spi与无线网卡芯片w800通信的。w800中运行有完整的lwip网络协议栈。 drv_wifi_at_w800组件将底层spi收到的网络数据(采用at协议封装)处理后递交到sal(socket abstract layer)组件中。2601通过sal来屏蔽底层网卡驱动的差异,向上提供标准的BSD网络套接字接口。 此部分代码位于components/drv_wifi_at_w800/w800_at_port.c中。

staticintspi_resp_len(void)
{
uint16_ttemp=0;
uint8_ta,b;
uint8_tcmd=SPI_REG_INT_STTS;
intrecv_len=0;
while (1) {
CS_LOW;
csi_spi_send(&spi_handle, &cmd, 1, AOS_WAIT_FOREVER);       // 检查是否存在有效数据csi_spi_receive(&spi_handle, &a, 1, AOS_WAIT_FOREVER);
csi_spi_receive(&spi_handle, &b, 1, AOS_WAIT_FOREVER);
CS_HIGH;
temp=a| (b<<8);
if((temp!=0xffff) && (temp&0x01)) {
cmd=SPI_REG_RX_DAT_LEN;
CS_LOW;
csi_spi_send(&spi_handle, &cmd, 1, AOS_WAIT_FOREVER);   // 获取接收数据长度 csi_spi_receive(&spi_handle, &a, 1, AOS_WAIT_FOREVER);
csi_spi_receive(&spi_handle, &b, 1, AOS_WAIT_FOREVER);
CS_HIGH;
recv_len=a| (b<<8);
// printf("recv len:%d\r\n", recv_len);break;
        }
aos_msleep(100);
    }
returnrecv_len;
}
staticvoidat_spi_recv_task(void*priv)
{
intlen=0;
uint8_t*recv=NULL;
while(1) {
aos_sem_wait(&spi_recv_sem, AOS_WAIT_FOREVER); // 是否有中断过来,通过GIIO来触发中断len=spi_resp_len();               // 获取对端发送过来的数据长度if (len)
recv=aos_malloc_check(len);
elsecontinue;
spi_recv(recv, len);                // 获取实际有效数据while (ringbuffer_available_write_space(&spi_ringbuffer) < (len-1)) {
aos_msleep(100);
        }
intw_len=ringbuffer_write(&spi_ringbuffer, recv, len-1); // 写入到环形缓冲中if (w_len!= (len-1)) {
LOGD(TAG, "spi buffer is full\r\n");
        } else {
spi_channel_cb(AT_CHANNEL_EVENT_READ, spi_channel_priv);
        }
if (recv) {
aos_free(recv);
recv=NULL;
        }
    }
}
staticvoid*at_spi_init(constchar*name, void*config)
{
intret=0;
csi_pin_set_mux(PA16, PA16_SPI0_SCK);                            // 配置管脚复用csi_pin_set_mux(PA17, PA17_SPI0_MOSI);
csi_pin_set_mux(PA18, PA18_SPI0_MISO);
// csi_pin_set_mux(PA15, PA15_SPI0_CS); // CScsi_pin_set_mux(PA15, PIN_FUNC_GPIO); // CScsi_pin_set_mux(PA22, PIN_FUNC_GPIO); // INTcsi_gpio_pin_init(&spi_int_pin, PA22);                           // gpio配置csi_gpio_pin_dir(&spi_int_pin,GPIO_DIRECTION_INPUT);
csi_gpio_pin_mode(&spi_int_pin,GPIO_MODE_PULLNONE);
csi_gpio_pin_debounce(&spi_int_pin, true);
csi_gpio_pin_attach_callback(&spi_int_pin, spi_in_int_cb, NULL); // 根据gpio来通知是否存在网络数据csi_gpio_pin_irq_mode(&spi_int_pin,GPIO_IRQ_MODE_FALLING_EDGE);
csi_gpio_pin_irq_enable(&spi_int_pin, 1);
csi_gpio_pin_init(&spi_cs_pin, PA15);
csi_gpio_pin_mode(&spi_cs_pin,GPIO_MODE_PULLUP);
csi_gpio_pin_dir(&spi_cs_pin,GPIO_DIRECTION_OUTPUT);
CS_HIGH;
csi_gpio_pin_init(&spi_wakeup_pin, PA25);
csi_gpio_pin_mode(&spi_wakeup_pin,GPIO_MODE_PULLUP);
csi_gpio_pin_dir(&spi_wakeup_pin,GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_write(&spi_wakeup_pin, GPIO_PIN_HIGH);
ret=csi_spi_init(&spi_handle, 0);
if (ret<0) {
printf("csi spi init failed\r\n");
returnNULL;
    }
csi_spi_mode(&spi_handle, SPI_MASTER);        // 2601侧作为masterret=csi_spi_baud(&spi_handle, 1*1000000);   // 波特率配置默认1MLOGD(TAG, "#######################spi speed:%d\r\n", ret);
csi_spi_cp_format(&spi_handle, SPI_FORMAT_CPOL0_CPHA0);
csi_spi_frame_len(&spi_handle, SPI_FRAME_LEN_8);
csi_spi_select_slave(&spi_handle, 0);         // 建立与w800间的spi通信,w800网卡作为slave 0aos_task_ttask;
ret=aos_sem_new(&spi_recv_sem, 0);          // 用于gpio中断通知// aos_check(ret, NULL);ret=aos_task_new_ext(&task, "spi_recv", at_spi_recv_task, NULL, 1536, 9);
// aos_check(ret, NULL);spi_recv_buffer= (char*)aos_malloc_check(SPI_RX_BUFFER_LEN); // 创建环形buffer,用于接收网络数据ringbuffer_create(&spi_ringbuffer, spi_recv_buffer, SPI_RX_BUFFER_LEN);
return (void*)1;
}
at_channel_tspi_channel= {
    .init=at_spi_init,
    .set_event=at_spi_set_event,
    .send=at_spi_send,
    .recv=at_spi_recv,
};


2.网络播放器使用及配置

YoC平台中的播放器可以支持wav、mp3、m4a、amrnb、amrwb、flac、adts等多种音频格式的播放。同时也支持sd卡、http(s)、fifo、mem等多种取流方式。url格式的详细定义如下:

流类型 URL前缀 URL格式
网络流 http(s):// http(s)://ip:port/xx.mp3
文件流(SD卡) file:// file:///fatfs0/xx.mp3?avformat=%s&avcodec=%s&channel=%u&rate=%u
内存流 mem:// mem://addr=%u&size=%u&avformat=%s&avcodec=%s&channel=%u&rate=%u
fifo流 fifo:// fifo://tts/1?avformat=%s&avcodec=%s&channel=%u&rate=%u
加密流 crypto:// crypto://http://ip:port/xx.mp3?key=%s&iv=%s
hls流 http(s):// http(s)://ip:port/xx.m3u8

播放器相关组件详细的设计和使用方法请访问以下链接: https://yoc.docs.t-head.cn/yocbook/Chapter5-%E7%BB%84%E4%BB%B6/%E5%A4%9A%E5%AA%92%E4%BD%93%E6%92%AD%E6%94%BE%E5%99%A8/av.html


2.1 网络播放器在2601芯片上的应用

网络播放器典型代码解析如下:

staticplayer_t*g_player;
staticvoid_player_event(player_t*player, uint8_ttype, constvoid*data, uint32_tlen)
{
intrc;
UNUSED(len);
UNUSED(data);
UNUSED(handle);
LOGD(TAG, "=====%s, %d, type = %d", __FUNCTION__, __LINE__, type);
switch (type) {
casePLAYER_EVENT_ERROR:      // 播放出错事件rc=player_stop(player);
break;
casePLAYER_EVENT_START: {    // 开始播放事件media_info_tminfo;
memset(&minfo, 0, sizeof(media_info_t));
rc=player_get_media_info(player, &minfo);  // 获取媒体时长、大小等信息LOGD(TAG, "=====rc = %d, duration = %llums, bps = %llu, size = %u", rc, minfo.duration, minfo.bps, minfo.size);
break;
    }
casePLAYER_EVENT_FINISH:     // 播放结束事件player_stop(player);      // 停止播放break;
default:
break;
    }
}
player_t*get_player_demo()
{
if (!g_player) {
ply_conf_tply_cnf;
player_conf_init(&ply_cnf);               // 初始化播放器默认配置ply_cnf.vol_en=1;               // 使能数字音量功能ply_cnf.vol_index=160;             // 0~255ply_cnf.event_cb=_player_event;   // 播放事件回调函数ply_cnf.period_num=12;              // 底层音频输出缓冲周期,用于控制音频输出缓冲大小ply_cnf.cache_size=32*1024;       // 网络时的播放缓冲大小g_player=player_new(&ply_cnf);          // 创建播放器    }
returng_player;
}


2.2 网络播放器相关宏配置

鉴于2601的硬件资源比较受限,而网络播放器又提供了很多的功能。所以不太可能将播放器提供的所有功能都能够包含进去。此时就需要开发根据具体产品需要开启或配置相关功能。 例程中典型宏定义配置如下:

CONFIG_AEFXER_IPC=0#音效处理,2601不涉及CONFIG_AEFXER_SONA=0#音效处理,2601不涉及CONFIG_AO_MIXER_SUPPORT=0#混音播放,默认关闭CONFIG_ATEMPOER_IPC=0#核间变速播放,2601不涉及CONFIG_ATEMPOER_SONIC=1#变速播放CONFIG_AV_AO_CHANNEL_NUM=1#单声道音频输出CONFIG_AV_PROBE_SIZE_MAX=1024#音频格式探测最大长度CONFIG_AV_SAMPLE_NUM_PER_FRAME_MAX=80#控制wav音频帧的最大采样数CONFIG_AV_STREAM_INNER_BUF_SIZE=256#stream内部buf大小,用于性能优化CONFIG_DECODER_ADPCM_MS=0#adpcm_ms解码CONFIG_DECODER_ALAW=0#alaw解码CONFIG_DECODER_AMRNB=0#amrnb解码CONFIG_DECODER_AMRWB=0#amrwb解码CONFIG_DECODER_FLAC=0#flac解码CONFIG_DECODER_IPC=0#核间解码,2601不涉及CONFIG_DECODER_MULAW=0#ulaw解码CONFIG_DECODER_OPUS=0#opus解码CONFIG_DECODER_PCM=1#pcm裸流解码CONFIG_DECODER_PVMP3=1#mp3解码CONFIG_DECODER_SPEEX=0#speex解码CONFIG_DEMUXER_ADTS=0#adts解复用CONFIG_DEMUXER_AMR=0#amr解复用CONFIG_DEMUXER_ASF=0#asf解复用CONFIG_DEMUXER_FLAC=0#flac解复用CONFIG_DEMUXER_MP3=1#mp3解复用CONFIG_DEMUXER_MP4=0#mp4解复用CONFIG_DEMUXER_OGG=0#ogg解复用CONFIG_DEMUXER_RAWAUDIO=0#rawaudio解复用CONFIG_DEMUXER_TS=0#ts解复用CONFIG_DEMUXER_WAV=0#wav解复用CONFIG_EQXER_IPC=0#量化器,2601不涉及CONFIG_EQXER_SILAN=0#量化器,2601不涉及CONFIG_FFTXER_IPC=0#fft变换,2601不涉及CONFIG_FFTXER_SPEEX=0#fft变换,2601不涉及CONFIG_PLAYER_TASK_STACK_SIZE=2048#播放器任务栈大小CONFIG_RESAMPLER_IPC=0#核间音频重采样CONFIG_RESAMPLER_SPEEX=0#speex重采样CONFIG_STREAMER_CRYPTO=0#加密流CONFIG_STREAMER_FIFO=0#队列流CONFIG_STREAMER_FILE=0#文件流CONFIG_STREAMER_HLS=0#httplivestreamCONFIG_STREAMER_HTTP=1#http网络流CONFIG_STREAMER_MEM=1#内存流CONFIG_WEB_CACHE_TASK_STACK_SIZE=2048#网络流缓冲任务栈大小


AV组件中宏配置的具体说明请参考此链接中的功能配置与裁剪小节。该链接中同时会介绍典型音频播放场景的相关配置。


2.3 在CDK中如何配置宏

  • 在解决方案名称上右击,选择弹出框中第一项,如下图所示:

4.png


  • 在弹出框中选中Compile选项卡,单击下图中的红色框可配置相关宏

5.png


  • 在弹出框中,根据功能需要配置对应的宏,保存后重新编译

6.png


注意事项:

  • Package中的子功能组件在Options选项中会有默认的配置项(如果存在)
  • 解决方案在依赖子功能组件时,可通过Options选项自行重新配置相关的宏。其在编译时会覆盖子功能组件的默认配置


四、参考资料

  1. YoC软件平台:https://yoc.docs.t-head.cn/yocbook/


  1. 多媒体播放器组件:https://yoc.docs.t-head.cn/yocbook/Chapter5-%E7%BB%84%E4%BB%B6/%E5%A4%9A%E5%AA%92%E4%BD%93%E6%92%AD%E6%94%BE%E5%99%A8/


  1. SAL组件:https://yoc.docs.t-head.cn/yocbook/Chapter4-%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9D%97/%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5/%E5%A5%97%E6%8E%A5%E5%AD%97%E9%80%82%E9%85%8D%E5%B1%82SAL.html


  1. AT组件:https://yoc.docs.t-head.cn/yocbook/Chapter4-%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9D%97/AT%E5%91%BD%E4%BB%A4/


  1. 网络管理器组件:https://yoc.docs.t-head.cn/yocbook/Chapter4-%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9D%97/%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5/%E7%BD%91%E7%BB%9C%E7%AE%A1%E7%90%86%E5%99%A8.html
相关文章
|
11天前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
36 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
25天前
|
存储 监控 物联网
计算机网络的应用
计算机网络已深入现代生活的多个方面,包括通信与交流(电子邮件、即时通讯、社交媒体)、媒体与娱乐(在线媒体、在线游戏)、商务与经济(电子商务、远程办公)、教育与学习(在线教育平台)、物联网与智能家居、远程服务(远程医疗、智能交通系统)及数据存储与处理(云计算、数据共享与分析)。这些应用极大地方便了人们的生活,促进了社会的发展。
48 2
计算机网络的应用
|
29天前
|
机器学习/深度学习 运维 安全
图神经网络在欺诈检测与蛋白质功能预测中的应用概述
金融交易网络与蛋白质结构的共同特点是它们无法通过简单的欧几里得空间模型来准确描述,而是需要复杂的图结构来捕捉实体间的交互模式。传统深度学习方法在处理这类数据时效果不佳,图神经网络(GNNs)因此成为解决此类问题的关键技术。GNNs通过消息传递机制,能有效提取图结构中的深层特征,适用于欺诈检测和蛋白质功能预测等复杂网络建模任务。
63 2
图神经网络在欺诈检测与蛋白质功能预测中的应用概述
|
18天前
|
存储 安全 网络安全
网络安全的盾与剑:漏洞防御与加密技术的实战应用
在数字化浪潮中,网络安全成为保护信息资产的重中之重。本文将深入探讨网络安全的两个关键领域——安全漏洞的防御策略和加密技术的应用,通过具体案例分析常见的安全威胁,并提供实用的防护措施。同时,我们将展示如何利用Python编程语言实现简单的加密算法,增强读者的安全意识和技术能力。文章旨在为非专业读者提供一扇了解网络安全复杂世界的窗口,以及为专业人士提供可立即投入使用的技术参考。
|
21天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
54 7
|
25天前
|
机器学习/深度学习 自然语言处理 语音技术
Python在深度学习领域的应用,重点讲解了神经网络的基础概念、基本结构、训练过程及优化技巧
本文介绍了Python在深度学习领域的应用,重点讲解了神经网络的基础概念、基本结构、训练过程及优化技巧,并通过TensorFlow和PyTorch等库展示了实现神经网络的具体示例,涵盖图像识别、语音识别等多个应用场景。
48 8
|
23天前
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
35 2
|
27天前
|
安全 网络安全 数据安全/隐私保护
利用Docker的网络安全功能来保护容器化应用
通过综合运用这些 Docker 网络安全功能和策略,可以有效地保护容器化应用,降低安全风险,确保应用在安全的环境中运行。同时,随着安全威胁的不断变化,还需要持续关注和研究新的网络安全技术和方法,不断完善和强化网络安全保护措施,以适应日益复杂的安全挑战。
42 5
|
29天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
本文旨在通过深入浅出的方式,为读者揭示卷积神经网络(CNN)的神秘面纱,并展示其在图像识别领域的实际应用。我们将从CNN的基本概念出发,逐步深入到网络结构、工作原理以及训练过程,最后通过一个实际的代码示例,带领读者体验CNN的强大功能。无论你是深度学习的初学者,还是希望进一步了解CNN的专业人士,这篇文章都将为你提供有价值的信息和启发。
|
25天前
|
机器学习/深度学习 人工智能 自然语言处理
探索深度学习中的卷积神经网络(CNN)及其在现代应用中的革新
探索深度学习中的卷积神经网络(CNN)及其在现代应用中的革新
下一篇
DataWorks