最近在做科大讯飞的语音解析模块,主要用于语音控制播放。采集语音输入后,送给科大讯飞语音的SDK,云服务器返回JSON的数据,再解析拿到URL地址,最后送给播放器去播放。不知是否是尚未上线的product,申请的appid,解析JSON后拿到的URL地址,歌曲播放的时间都很短,一般不到1分钟。

一番网络搜索后,据说百度有个未公开的搜歌API,只要拿到歌手和歌曲名,就可以传给这个URL,然后百度就会回你一个XML文件,解析这个文件,就可以拿到你要的MP3播放地址了,那就开始干活吧。

百度音乐搜索API实现说明

搜歌API: http://box.zhangmen.baidu.com/x?op=12&count=1&title=
在上面这个地址后面加上要搜索的歌手和歌曲名,如下图

至于这里的歌手和歌曲名,都是由科大讯飞的SDK返回的JSON数据,解析出来的,此处不需要关心。

在浏览器的地址栏上输入上面的地址,就会返回如下图的内容:

然后将红色框框的1和2拼凑在一起,就得到了mp3的地址,即
http://zhangmenshiting.baidu.com/data2/music/88329745/88329745.mp3?xcode=1c4dab84d5d0d5dc44a2e9dde28d95e5117565b2b6f412d5&mid=0.00592347543617

具体流程图如下图:

本文主要讲述实线框框内的实现

  • Decode 中文 URL
    因为URL带有中文字符,做HTTP请求的时候,需要将中文字符 decode一下,方能识别,具体方法如下
CHAR from_hex(CHAR ch)
{return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}CHAR *url_decode(CHAR *str)
{CHAR *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;while (*pstr) {if (*pstr == '%') {if (pstr[1] && pstr[2]) {*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);pstr += 2;}} else if (*pstr == '+') { *pbuf++ = ' ';} else {*pbuf++ = *pstr;}pstr++;}*pbuf = '\0';return buf;
}

拿到decode的字符后,将其拼凑成一个完整的URL即可。

  • CURL模拟HTTP请求
    拿到可以访问的URL后,接下来就是用CURL模拟HTTP请求,去抓取百度搜歌的内容,此处利用的CURL将数据写到buffer的方式,并非保存文件方式,具体实现如下:
static INT32 curl_http_download_progress_callback(void *p,double t, /* dltotal */double d, /* dlnow */double ultotal,double ulnow)
{INT32 currentPercent = 0;if(t != 0){currentPercent = (int)((double)100*(d/t));  }printf("Curl DownLoad percent : %d\n", currentPercent);if(100 == currentPercent){sem_post(&semDownLoadFinished);}return CURL_RET_OK;
}static size_t curl_http_write_memory_cb(void *contents, size_t size, size_t nmemb, void *userp)
{size_t realsize = size * nmemb;struct MemoryStruct *mem = (struct MemoryStruct *)userp;mem->memory = realloc(mem->memory, mem->size + realsize + 1);if (mem->memory == NULL) {/* out of memory! */printf("not enough memory (realloc returned NULL)\n");exit(EXIT_FAILURE);}memcpy(&(mem->memory[mem->size]), contents, realsize);mem->size += realsize;mem->memory[mem->size] = 0;return realsize;
}INT32 curl_http_get_page(const CHAR * url)
{CURL *curl;CURLcode res;chunk.memory = malloc(1);  /* will be grown as needed by the realloc above */chunk.size = 0;    /* no data at this point */res = curl_global_init(CURL_GLOBAL_ALL);if(CURLE_OK != res){return CURL_RET_FAIL;}curl = curl_easy_init();if(curl) {        curl_easy_setopt(curl, CURLOPT_URL, url);curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, curl_http_write_memory_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, curl_http_download_progress_callback);curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,curl);curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);                        // display debug msgcurl_easy_perform(curl);curl_easy_cleanup(curl);}    return CURL_RET_OK;
}

在确保网页的内容全部保存到buffer中,这里用到了CURL的CURLOPT_PROGRESSFUNCTION参数,通过它,你可以拿到下载的百分比,当下载到100%时,会post一个信号量,收到这个信号量,就可以进行下一个环节了

注意:
1.这里没有做CURL超时处理,请自行加上
2.关于CURL的使用,可以参考以下地址
curl使用小结
ubuntu 13.10下安装curl
ubuntu下运行程序提示找不到libcurl动态库

  • XML解析
    拿到网页内容后,解析来就是XML字段。这里是利用libxml2去做解析,具体实现如下
CHAR * xml_parse_file(CHAR *buf, INT32 len)
{INT32 str1Len=0, str2Len=0;CHAR *temp1URL=NULL, *temp2URL=NULL;CHAR * retURL = NULL;xmlDocPtr doc;xmlNodePtr root,node;xmlChar *value;//xml_str_replace(buf, "encoding=\"gb2312\"", "encoding=\"utf-8\"");  //此处因为在板子上跑,xml解析会出错,说不支持gb2312,而PC上的LINUX不需要转换即可解析,PC上加了也可以解析出来doc = xmlParseMemory(buf,len);    //parse xml in memoryif (NULL == doc) {  printf("Document not parsed successfully\n");return NULL; } root=xmlDocGetRootElement(doc);for(node=root->children;node;node=node->next){if(xmlStrcasecmp(node->name,BAD_CAST"url")==0)break;}if(node==NULL){TONLY_VOICE_LOG_ERR("no node = content\n");return NULL;}for(node=node->children;node;node=node->next){if(xmlStrcasecmp(node->name,BAD_CAST"encode")==0){   value=xmlNodeGetContent(node);            temp1URL = strrchr((CHAR *)value, '/');str1Len = strlen((CHAR *)value) - strlen((CHAR *)temp1URL);temp2URL = (CHAR *)malloc(sizeof(CHAR)*str1Len+1);            memset(temp2URL, 0, sizeof(CHAR)*str1Len+1);memcpy(temp2URL, value, str1Len+1);temp2URL[str1Len+1] = '\0';printf("Cut out the decode URL is %s\n",temp2URL);             xmlFree(value);}else if(xmlStrcasecmp(node->name,BAD_CAST"decode")==0){       value=xmlNodeGetContent(node);if(temp2URL){str2Len = strlen((CHAR *)value) + strlen((CHAR *)temp2URL);retURL = (CHAR *)malloc(sizeof(CHAR)*str2Len + 1);memset(retURL, 0, sizeof(CHAR)*strlen((CHAR *)value) + 1);strcpy(retURL, temp2URL);strcat(retURL, (CHAR *)value);retURL[str2Len+1] = '\0';free(temp2URL);printf("retURL is %s\n",retURL); }xmlFree(value);}}xmlFreeDoc(doc);    return retURL;
}

最后xml_parse_file返回的字符串,就是最终的mp3播放地址,将其送给播放器就可以实现播放了。

注意:
1.libxml2的安装方法如下:
(1)sudo apt-get install libxml2
(2)sudo apt-get install libxml2-dev

2.libxml2使用方法
[Linux C]利用libxml2解析xml文件
Linux环境下C使用的XML解析库:libxml2

参考资料

  1. 百度MP3音乐API接口及应用
  2. 在线音乐API的研究
  3. 抓包获取百度音乐API
  4. linux c语言字符串函数replace,indexOf,substring等的实现
  5. libxml2官网

[Linux C]百度音乐API实现在线搜歌相关推荐

  1. 基于百度音乐Api的Android高仿音乐播放App可在线试听下载歌词浏览

    基于百度音乐Api的Android高仿音乐播放App可在线试听下载歌词浏览 首先这也是学习过程中开发的一个练手项目,基于百度音乐Api,api在网上搜的,如果想看他的实现,可以下载我的项目来参考.风格 ...

  2. 百度音乐API抓取-Fiddler

    百度音乐API抓取 前段时间做了一个本地音乐的播放器 github地址,想实现在线播放的功能,于是到处寻找API,很遗憾,不是歌曲不全就是质量不高.在网上发现这么一个APIMRASONG博客,有&qu ...

  3. Vue实现仿音乐播放器11-实现访问百度音乐API实现播放音乐功能

    场景 从今日推荐页面点击某首歌曲会将这首歌曲的songid通过路由传递到播放界面, 播放界面调用百度音乐接口实现数据的获取以及音乐的播放. 效果 实现 配置路由 首先在pages目录下新建musicp ...

  4. Vue实现仿音乐播放器5-实现今日推荐访问百度音乐API获取数据

    前文 前面已经实现了音乐导航菜单的切换,现在要实现主页面的今日推荐功能. 效果 实现 实现首页重定向 当应用初始化时,默认进入主页面home页,所以在router下的index.js下配置: expo ...

  5. Vue实现访问百度音乐API实现播放音乐功能

    场景 从今日推荐页面点击某首歌曲会将这首歌曲的songid通过路由传递到播放界面, 播放界面调用百度音乐接口实现数据的获取以及音乐的播放. 效果 实现 配置路由 首先在pages目录下新建musicp ...

  6. 从实例入手学习使用vue+axios配置代理进行跨域访问百度音乐API

    场景 如果要使用axios直接进行跨域访问是不可以的,这是就需要配置代理了,为什么要配置代理呢? 原因就是因为客户端请求服务端的数据是存在跨域问题的,而服务器和服务器之间可以相互请求数据,是没有跨域的 ...

  7. 百度音乐api+c语言,百度音乐API全接口

    百度音乐API http://tingapi.ting.baidu.com/v1/restserver/ting 获取方式:GET 参数:format=json或xml&calback=&am ...

  8. 百度音乐API全接口

    百度音乐API http://tingapi.ting.baidu.com/v1/restserver/ting 获取方式:GET 参数:format=json或xml&calback=&am ...

  9. 网易云android视频播放器,网易云服务-在线搜歌-数据结构

    1.课程的初忠与目的 问题:通过上课发现,在学习完成Android基本组件后,还会迷茫于如何完成一个完整的应用. 本实践课程通过开发完成一个"畅听音乐"的小项目,实现从基本组件的学 ...

最新文章

  1. NLP通用模型诞生?一个模型搞定十大自然语言常见任务
  2. java布局工具,Java Swing:库,工具,布局管理器
  3. Java集群优化——dubbo+zookeeper构建高可用分布式集群
  4. Jenkins Job Buidler
  5. Spring Cloud构建微服务架构:服务网关(路由配置)【Dalston版】
  6. java中修饰符的说明
  7. MongoCola使用教程 1 - MongoDB的基本操作和聚合功能
  8. matlab中的运算函数,基于Matlab软件的函数运算在实践中的应用
  9. AD16修改规则加宽电源线与地线
  10. 树莓派2研究之:交叉编译小度WIFI驱动,让小派支持小度WIFI
  11. 用计算机绘制阀体各零件步骤,机械制图之零件图(四)
  12. 鸭子-策略模式(Strategy)
  13. 苹果电脑mac桌面上出现关不掉的黑框/白框 解决办法
  14. 缺省值及属性(Python)
  15. 【线上直播ING】2016互联网金融应用发展半年报
  16. android4.0.3 编译lichee 报错dhd-cdc-sdmmc-gpl-3.0.8问题
  17. 大连工业大学计算机技术,大学计算机基础-大连工业大学计算机技术试验教学中心网站.PPT...
  18. 字符设备、块设备、网络设备
  19. c罗图片带字经典语言,20条经典的唯美的图片带字-感人的情话
  20. 中盐集团:加快推进数智化转型,引领盐行业高质量发展

热门文章

  1. Springboot使用杂谈
  2. Powerpoint插入图表(转)
  3. 秦九韶多项式运算时间java,秦九韶算法的思想与解多项式算法时间比较附代码...
  4. 小米8位置服务器,超旗舰新机小米8,强大的GPS定位无人能及!
  5. Media Encoder 2020 for Mac(me 2020 大师版)
  6. Cloud Computing:云计算的简介、必要性以及安全上云与企业数字化转型(从陈坤/辛芷蕾主演电视剧《输赢》看云计算的未来)的关系
  7. 五、Redis主从同步
  8. 决策树:CART决策树剪枝算法(超详细)
  9. python输出汉字怎么对齐_Python的print输出中文对齐问题
  10. JQuery中的九大选择器及其应用(上)