最近开发的一个工程中需要用到云上传功能,我是用来上传音频到云端进行识别的,目前开放的语音识别平台有很多家,科大讯飞、百度语音、阿里云等,但是这些商家对于安卓应用端和linux嵌入式开发的支持都是不错的,我的工程暂时用不到linux系统,所以先尝试用裸板进行音频上传识别,百度语音和阿里云都是支持restful的http请求进行识别的,那么裸板能够完成POST请求的就只能加ESP8266了,所以这里采用这个模块。平台我这里用的是百度语音,因为百度的技术文档支持写的还是比较详细的,所以研究一段时间也就差不多能够勉强使用了,但是受限于ESP8266这个模块的传输速度,这个识别过程不是很稳定,一旦网络不好很容易失败,而且这个识别过程很慢很慢。下面记录一下这个开发过程。
首先ESP8266这个模块基本上就相当于一个无线网卡,既可以作为热点,也可以通过路由器连接互联网,用的比较多的是用这个模块与手机进行无线连接然后用手机对程序做一些控制或者进行信息交互。这次拓展一下,直接用这个模块的STA模式连接互联网,然后与互联网进行数据交互。模块与单片机使用串口进行通信,模块集成了一些命令可以很方便的对其进行控制。其中用到的一些命令会在程序中进行介绍。
稍微介绍一下百度语音识别的过程,首先必须要有百度账号,然后到语音识别平台去注册一个应用,注册好之后会提供一个秘钥,之后会在程序中通过秘钥去获取一个token,只有在发送音频时加上这个token才能被识别。也就是说我们的识别过程分为两步,第一步是获取token,第二步是打包音频数据上传,当然其实还有第三步就是将返回的结果(json格式)进行解析,其实返回的token也是需要解析出来的。具体的细节性的内容请参看以下网址http://ai.baidu.com/docs#/ASR-API/top点击打开链接。
初始化就不多说了,直接用原子家的初始化就好,然后设置为STA模式,命令是AT+CWMODE=1,这个命令之后需要重启一下模块,命令是AT+RST。之后第一步要先连接路由器,这里的命令是AT+CWJAP="wifista_ssid",wifista_password"。接下来设置为单链接模式:AT+CIPMUX=0。接下来就要开始进行联网上传数据了,第一步是要连接到目标服务器(这个是获取token的服务器):
sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s","openapi.baidu.com","80");
atk_8266_send_cmd(p,"OK",200);
然后设置为透传模式,也就是说下面这一条命令执行完之后,之后所有用串口发出的东西都不再认为是命令,而是直接转发到刚刚连接到的服务器上:
atk_8266_send_cmd("AT+CIPMODE=1","OK",200);
之后涉及到的就是如何进行一个POST的请求了,这个稍微上网学一下就行,主要知道格式就成,这里有一篇不错的诶帖子可以进行了解:https://www.cnblogs.com/ranyonsue/p/5984001.html点击打开链接。
下面是我的进行POST请求的程序段:
u3_printf("POST https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=xxxxxxxxxxxx&client_secret=xxxxxxxxxxx& HTTP/1.1\r\n");
u3_printf("Host: openapi.baidu.com\r\n");
u3_printf("Content-Length: 0\r\n");
u3_printf("Connection: close\r\n");
u3_printf("\r\n");
u3_printf("0\r\n");
这个命令其实没有发送数据,只是要接收数据,但作为一个POST请求后面总觉得应该有点东西,所以我在空行之后直接发送了一个0字符。然后就可以检测是否接收到数据了。是否接收到数据同样直接看串口接收标志是否置位即可。然后最重要的就是一定要记得退出透传模式再进行其他操作!退出就是串口接收到连续的三个+就会退出,但是这个退出在这个程序中有时候会失败。
之后同样的操作之后连接到语音上传的服务器:
sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s","vop.baidu.com","80");
atk_8266_send_cmd(p,"OK",200)
之后进入透传模式后如下发送语音数据:
u3_printf("POST http://vop.baidu.com/server_api?dev_pid=1537&cuid=C89CDCE7B0F4&token=%s HTTP/1.1\r\n",access_token);
u3_printf("Content-Type: audio/wav;rate=16000\r\n");
u3_printf("Host: vop.baidu.com\r\n");
u3_printf("Content-Length: %lu\r\n",file_byte);
u3_printf("Connection: Keep Alive\r\n");
u3_printf("\r\n");
fillnum=wav_buffill(USART3_TX_BUF,USART3_MAX_SEND_LEN);
第一行都是一些配置参数,在之前发的那个百度的技术文档中有描述,最后在空行之后我是直接将数据分批读出然后用串口发送出去,我觉得发送过程服务器认为发送完成有两种可能,一种是上面发送的数据长度,另外一种是发送的间隔,间隔超过某一阈值就认为发送完成,总之无论怎样,我的这种发送方式都是可以完成音频的上传的。这样基本就完成了数据的上传,这个过程中还有一个非常重要的事就是检测到返回数据后一定要对数据进行解析,返回的数据时json格式的,要把自己需要用的东西分离出来,另外最后识别到的结果是UTF-8格式的,如果要显示的话注意文字格式转换的问题。