基于平头哥RSIC-V RVB2601的网络收音机设计(2)
[复制链接]
1、概述
一般收音机主要使用过天线接收到电磁波,然后对电磁波进行放大à滤波à混频à中频à解调à播放这样的流程。整个收音机的数据来源主要来自于空气中的电磁波,电磁波信号质量的强弱直接决定了音质的好坏。
而网络收音机则是通过网络向特定的服务器下载音乐,然后播放,相比于普通收音机具有音质好,易操作的特点等。
图1 网络收音机原理
通过对图1的分析可以发现,网络收音机最重要的地方是数据的来源。作为网络收音机主主流的数据来源是蜻蜓FM,但是在实际操作过程中发现蜻蜓FM的接口比较麻烦,最后选择网易云音乐的接口作为网络收音机的数据来源。
网易云音乐接口的API地址为:https://neteasecloudmusicapi.vercel.app/#/?id=neteasecloudmusicapi
通过接口可以实现几乎所有的音乐播放器功能,介于RVB2601的资源比较紧张,在实现网络连接的同时还需要实现对mp3的解码,OLED显示和按键操作等功能,因此本文主要实现根据音乐名称查找音乐,当然也可以根据歌手名称来查找音乐。
网易云音乐查找功能主要通过搜索标签里面的GET请求实现。
图2 网易云音乐查找接口
通过接口的描述可以知道,如果我们要搜索刘德华的音乐,同时每次只返回3条结果(网易云音乐接口默认每次返回30条结果,这样的数据量大概是400k,单片机的内存受不了),另外RVB内部没有中文字库,因此所有的字符都需要使用英文来表示,而刘德华可以用拼音liudehua来表示,最终GET请求的url为
http://cloud-music.pl-fe.cn/search?limit=3&keywords=liudehua&offset=10
使用单片机通过对上面的url完成GET请求后,会返回一个JSON,下面是浏览器的测试结果
图3 通过接口返回的音乐id和详情的json
在返回的json数据里面,json的头是result,每一首音乐后面都会有一个id,然后通过这个id就可以在网易云音乐的曲库中查找到一个音乐的mp3链接,而通过id查找音乐的url为
http://music.163.com/api/song/enhance/player/url?id=554191989&ids=%5B554191989%5D&br=3200000
其中ids后面的%5B与%5D是固定的,br也是固定的。这样在获取每一首音乐的时候就转化为通过search接口查找曲目的id,再通过上面的url结合id通过GET请求得到一个包含真实音乐链接的json,json内容如下
图4 通过get请求包含真实音乐信息的json
然后这个json里面的url就是真实的音乐,再把这个url通过mp3播放即可,下面就是如何通过单片机来完成这一过程。
2、在单片机中完成GET请求和JSON解析
由于单片机的资源比较紧张,对于资源能省则省。通过跟踪例程中通过命令行播放音乐的函数调用发现例程中已经有一部分GET请求的功能,因此准备复用其中的一部分功能。
原来的请求是通过下面的流程完成的
图5 原来的get请求过程
通过分析可以发现,原始的请求通过层层调用,最终在_read_resp_hdr(,,)中接收到数据,由于_read_resp_hdr中只接收了响应头,因此没有办法接收到完整的json段,需要对此进行改进修改。
根据上述的流程,下面开始构建get请求json的函数。
首先由于响应的json比较大,返回3个搜索结果都需要将近3k的空间,本身给函数的堆空间又比较小,因此在.c中定义一个全局数组char dbuf[3*1024]
这个数组就是json的缓存数组,第一步对其空间进行清零,然后再使用strcat拼接url链接,然后调用自己编写的wjson_get(wsession_t *, const char *, int,char *)函数,wsession_t *类型的指针通过调用wsession_create()为其分配内存,不过这里有一个疑问,CH2601应该没有MMU单元,如果这样重复分配几次内存估计后面出现许多问题。
在wjson_get(,,,)中再调用rc = resp_json_menu(session, 3000,dbuf);获取json,整个原理和前面的过程大同小异,resp_json_menu(,,,)再调用 rc = _read_resp_player_menu(session, dbuf, timeout_ms);然后在_read_resp_player_menu(,,)里面完成对json的接收。
与原始接收响应头有所区别的地方是,这里判断响应中有{就表示JSON数据开始了,尽管有许多问题和隐患,但是通过对多次网易云接口响应的数据来看,这样设计是可以的,同时也符合能省则省的原则。
这样收到json数据之后需要从里面解析出歌曲名称和id,最简单的思路是使用cjson来完成,实际发现一旦使用cjson整个程序的内存就爆掉了,本身资源就比较紧张,决定还是自己手动拆解json,从里面拿到曲目名称和id。
通过分析可以发现,曲目的id和名称都是在[{"id"或者},{"id"后面,因此重点比对这段字符,具体的比对过程是通过一个指针ch,ch每次只移动1位,然后再一次抓取ch后面7位字符进行比对,如果发现是上面的两个固定字符串那么铁定就是歌曲的id和名称了
这样拿到id和名称之后,再通过向http://music.163.com/api/song/enhance/player/url?id=id&ids=%5Bid%5D&br=3200000请求就可以得到歌曲的播放链接
json解析过程如下
最后就完成了对网易云音乐的数据请求,网络收音机的核心部分就完成了,整个函数调用可以概括为
图6 get请求id和曲目名称过程概括
3、总结
json一般都使用cjson进行处理,但是网易响应过来的json太长了,没办法用专门的软件处理,使用这样非正常的手段实属无奈之举。
另外响应过来的数据中还有相当的一部分没有使用,如果屏幕能够显示完成是可以使用那一部分数据的。同时也发现播放音乐的核心就是id,拿到id之后再请求数据即可。
|