Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
网络学习营
Webclient
【网络编程学习】+清石+第四周挑战任务+百度语音识别
发布于 2018-08-26 23:50:43 浏览:1775
订阅该版
[tocm] ## 挑战: (通过麦克风)或者事先录制好一段语音,通过百度语义识别功能,获取语音识别结果,根据结果来控制 IO, 或者是 LED 灯;开发环境说明: 1. qemu 虚拟机环境问题总结: 2. 如何发送HTTP body 内容,直接读取文件,4k 4k 发送。 3. 暂未实现,思路是主要参考webclient_post_file 例子。 后面的代码就是改的,但还没有收到正确的响应。主要是熟悉一下JSON 和webclient_post 的实现方式。 ```c /* * File : httpclient.c * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Change Logs: * Date Author Notes * 2018-07-20 flybreak first version */ #include
/* 使用 HTTP 协议与服务器通信需要包含此头文件 */ #include
/* 使用BSD socket,需要包含socket.h头文件 */ #include
#include
#include "webclient_internal.h" #define BUF_SZ 1024//4096 //缓冲区大小 #define URL_LEN_MAX 256 //网址最大长度 #define AREA_ID "101021300" //上海浦东地区 ID /* 天气数据解析 */ void vop_data_parse(rt_uint8_t *data) { cJSON *root = RT_NULL, *object = RT_NULL, *item = RT_NULL; //root = cJSON_Parse((const char *)data); object = cJSON_Parse((const char *)data); // if (!root) if(!object) { rt_kprintf("No memory for cJSON root!
"); return; } //object = cJSON_GetObjectItem(root, "sk_info"); item = cJSON_GetObjectItem(object, "error_no"); rt_kprintf("
error_no:%d", item->valuestring); item = cJSON_GetObjectItem(object, "error_msg"); rt_kprintf("
error_msg :%s ", item->valuestring); item = cJSON_GetObjectItem(object, "result"); rt_kprintf("
result :%s ", item->valuestring); /* item = cJSON_GetObjectItem(object, "ws"); rt_kprintf("
ws :%s ", item->valuestring); item = cJSON_GetObjectItem(object, "sd"); rt_kprintf("
sd :%s ", item->valuestring); item = cJSON_GetObjectItem(object, "date"); rt_kprintf("
date :%s", item->valuestring); item = cJSON_GetObjectItem(object, "time"); rt_kprintf("
time :%s
", item->valuestring);*/ // if (root != RT_NULL) // cJSON_Delete(root); if (object != RT_NULL) cJSON_Delete(object); } int webclient_post_pcm_file(struct webclient_session *session , const char* filename) { size_t length; char boundary[60]; int fd = -1, rc = WEBCLIENT_OK; char *header = NULL, *header_ptr; unsigned char *buffer = NULL, *buffer_ptr; // struct webclient_session* session = session; fd = open(filename, O_RDONLY, 0); if (fd < 0) { rc = -WEBCLIENT_FILE_ERROR; goto __exit; } /* get the size of file */ length = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); buffer = web_malloc(WEBCLIENT_RESPONSE_BUFSZ); if (buffer == NULL) { rc = -WEBCLIENT_NOMEM; goto __exit; } /* send file data */ while (1) { length = read(fd, buffer, WEBCLIENT_RESPONSE_BUFSZ); if (length <= 0) break; webclient_write(session, buffer, length); } __exit: if (fd >= 0) close(fd); // if (session != NULL) webclient_close(session); if (buffer != NULL) web_free(buffer); if (header != NULL) web_free(header); return 0; } void vop(int argc, char **argv) { rt_uint8_t *ptr = RT_NULL; int length = 0, result; struct webclient_session *session = RT_NULL; char *weather_url = RT_NULL; /* 为 weather_url 分配空间 */ weather_url = rt_calloc(1, URL_LEN_MAX); if (!weather_url) { rt_kprintf("No memory for weather_url!
"); goto __exit; } /* 拼接 GET 网址 */ //rt_snprintf(weather_url, URL_LEN_MAX, "http://mobile.weather.com.cn/data/sk/%s.html", AREA_ID);//http://mobile.weather.com.cn/data/sk/101021300.html rt_snprintf(weather_url, URL_LEN_MAX, "http://vop.baidu.com/server_api?dev_pid=1536&cuid=7470fdac1cd8&token=24.6ea3239ec36ac3a20429bf7e1f58c682.2592000.1536986633.282335-11684396"); /* 为结构体 webclient_session 分配空间 */ session = (struct webclient_session *)rt_calloc(1, sizeof(struct webclient_session)); if (!session) { rt_kprintf("No memory for session structure!
"); goto __exit; } /* 连接百度语音识别网站 */ result = webclient_connect(session, weather_url); if (result < 0) { rt_kprintf("Webclient connect URI(%s) failed!
", weather_url); goto __exit; } /* 发送官方标准 header */ char content_type_str[]="Content-Type: audio/pcm;rate=16000"; result = webclient_send_header(session, WEBCLIENT_POST,content_type_str,strlen(content_type_str));//WEBCLIENT_GET if (result < 0) { rt_kprintf("Webclient send header buffer failed return %d!", result); goto __exit; } webclient_post_pcm_file(session,"/:16k.pcm"); /* 检查响应 */ if (webclient_handle_response(session)) { if (session->response != 200)//200 { rt_kprintf("webclient handle response(%d) error!", session->response); // goto __exit; } } /* 分配用于存放接收数据的缓冲 */ ptr = rt_calloc(1, BUF_SZ); if(!ptr) { rt_kprintf("No memory for data receive buffer!
"); goto __exit; } length = webclient_read(session, ptr, BUF_SZ); ptr[length] = '\0'; /* 天气数据解析 */ rt_kprintf("respon date is %s
",ptr); vop_data_parse(ptr); __exit: /* 释放网址空间 */ if (weather_url != RT_NULL) rt_free(weather_url); /* 关闭会话 */ if (session != RT_NULL) webclient_close(session); /* 释放缓冲区空间 */ if (ptr != RT_NULL) rt_free(ptr); } #ifdef FINSH_USING_MSH #include
MSH_CMD_EXPORT(vop, Get weather by webclient); #endif ``` - [第四周 挑战 任务 百度语音识别.pdf"](https://club.rt-thread.org/uploads/201808/26/235025lyy882wyddisiltw.attach)
查看更多
3
个回答
默认排序
按发布时间排序
小住住
认证专家
2018-08-28
这家伙很懒,什么也没写!
## 步骤三: 理解post 上传文件的原理。 - [Multipart/form-data POST文件上传详解](https://blog.csdn.net/xiaojianpitt/article/details/6856536) 最早的HTTP POST是不支持文件上传的,给编程开发带来很多问题。 但是在1995年,ietf出台了rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上传。 所以Content-Type的类型扩充了`multipart/form-data`用以支持向服务器发送二进制数据。 因此发送post请求时候,表单`
`属性`enctype`共有二个值可选,这个属性管理的是表单的MIME编码: ``` ① application/x-www-form-urlencoded(默认值) ② multipart/form-data ``` 浏览器将会发送以下数据: ``` POST /t2/upload.do HTTP/1.1 User-Agent: SOHUWapRebot Accept-Language: zh-cn,zh;q=0.5 Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Content-Length: 60408 Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Host: w.sohu.com --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="desc" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` 我们来分析下数据,第一个空行之前自然还是HTTP header,之后则是Entity,而此时的Entity也比之前要复杂一些。根据RFC 1867定义,我们需要选择一段数据作为“分割边界”( boundary属性),这个“边界数据”不能在内容其他地方出现,一般来说使用一段从概率上说“几乎不可能”的数据即可。 不同浏览器的实现不同,例如火狐某次post的 ``` boundary=---------------------------32404670520626 , ``` opera为 ``` boundary=----------E4SgDZXhJMgNE8jpwNdOAX ``` 每次post浏览器都会生成一个随机的30-40位长度的随机字符串,浏览器一般不会遍历这次post的所有数据找到一个不可能出现在数据中的字符串,这样代价太大了。 一般都是随机生成,如果你遇见boundary值和post的内容一样,那样的话这次上传肯定失败,不过我建议你去买彩票,你太幸运了。 Rfc1867这样说明{A boundary is selected that does not occur in any of the data. (This selection is sometimes done probabilisticly.)}。 ``` --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="pic"; filename="photo.jpg" Content-Type: application/octet-stream Content-Transfer-Encoding: binary ``` [图片二进制数据] ``` --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC— ``` 选择了这个边界之后,浏览器便把它放在Content-Type 里面传递给服务器,服务器根据此边界解析数据。下面的数据便根据boundary划分段,每一段便是一项数据。(每个field被分成小部分,而且包含一个value是`"form-data"`的`"Content-Disposition"`的头部;一个"name"属性对应field的ID,等等,文件的话包括一个filename) • IE和Chrome在filename的选择策略上有所不同,前者是文件的完整路径,而后者则仅仅是文件名。 • 数据内容以两条横线结尾,并同样以一个换行结束。在网络协议中一般都以连续的CR、LF(即\r、\n,或0x0D、Ox0A)字符作为换行,这与Windows的标准一致。如果您使用其他操作系统,则需要考虑它们的换行符。 另外Content-length 指的是所用数据的长度。 ## 步骤四:代码实现 流程是:先发送`head` 再 发送 ``` /* send mime_multipart */ /* send file data */ /* send last boundary */ ``` 具体格式参见源码。
小住住
认证专家
2018-08-29
这家伙很懒,什么也没写!
最后就两个问题: 命令行输入 文件名字 打开文件失败 还有就是 `16k.pcm` 文件格式质量不高 `error_no:3301.`
小住住
认证专家
2018-08-29
这家伙很懒,什么也没写!
- [【网络编程学习】+ zppsky + 百度语音识别控制LED](https://www.rt-thread.org/qa/thread-7868-1-1.html) 感谢赵盼盼网友的悉心指导,总算可以实现了。就是使用的这个帖子的。 总结两点: 1.`voice_ctrl 16k.pcm` 打开失败的原因 是因为 `void voice_ctrl_my(int argc, char *argv[])`少了`argv`后面的`[]` ; 2.总是响应 3301,语音质量差,可能是因为tftp 传的时候,没又传正确导致。
撰写答案
登录
注册新账号
关注者
0
被浏览
1.8k
关于作者
小住住
这家伙很懒,什么也没写!
提问
129
回答
126
被采纳
2
关注TA
发私信
相关问题
1
【LWIP学习营】第一关开发环境搭建
2
LWIP学习营第一周入门移植问题汇总贴
3
【LWIP学习营】f407+lan8720A小结
4
【LwIP学习营】【第一周】仅零散记录,无主题
5
【LWIP学习营】正点原子探索者F407+LAN8720第一周小结
6
【LwIP学习营】【第一周】网络通信基础及实现TCP 聊天客户端
7
【LwIP学习营】【第一周】LWIP移植
8
【LwIP学习营】【第一周】LWIP移植
9
【LwIP学习营】【第一周】开发板适配
10
【LwIP学习营】【第一周】环境搭建和配置验证
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
7
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
3
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部