Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
网络学习营
【网络编程学习】+ A Byte of China + 百度语音识别
发布于 2018-08-26 16:28:38 浏览:2597
订阅该版
* 本帖最后由 ianhom 于 2018-8-26 17:38 编辑 * 最后一周的最后的挑战:百度语音识别 **_开发环境_** RT-Thread+ LwIP + 野火RT1052mini **_过程说明_** To be continue首先我们需要将[百度语音](https://console.bce.baidu.com/ai/#/ai/speech/overview/index)侧进行配置,进行应用的创建 ![TIM截图20180826164859.png](/uploads/201808/26/171158seh4dp5f55fhqtfh.png) 因为百度语音识别对语音源文件有格式要求,我们选择PCM格式,使用百度提供的工具对音频文件进行转码,工具为[ffmpeg](http://ffmpeg.zeranoe.com/builds/)(点击下载),在cmd中输入下列命令可以进行转码操作(详细操作请参考百度官网[工具说明](https://cloud.baidu.com/doc/SPEECH/ASR-Tool.html))。本帖最后的附件是我转换后音频文件,可以用于测试。 ```ffmpeg -y -i test.mp3 -acodec pcm_s16le -f s16le -ac 1 -ar 16000 test.pcm``` 有了语音源文件之后,看一下调用方式。 首先我们需要获得token,这个在之前[语音合成](https://club.rt-thread.org/ask/question/7775.html)中讲到过,这里复习一下,记录下应用中的API key和APP SECRET,如下图组装获取token的网址,复制到游览器中,获得token。 ![TIM截图20180826165320.png](/uploads/201808/26/171159lv775x23zv3h5uvr.png) ![TIM截图20180826170802.png](/uploads/201808/26/171159l2n8dhtd82rxt2et.png) 获取的到token之后,我们就可以获得我们调用的API连接,*****可以随意起名,@@@@@@@@@替换完上文的token即可 ```http://vop.baidu.com/server_api?dev_pid=1536&cuid=******&token=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ``` 有了API链接之后,我们需要修改POST内的参数。百度通过HTTP POST的方法来实现语音上传,其中有JSON和raw两种,我们采用比较合适嵌入式的raw方式。 raw的要求是:1、pcm音频文件二进制放在body中(翻译一下,就是调用http中post方法把文件上传);2、在header中Content-Type: audio/pcm;rate=16000(翻译一下,就是在POST函数中修改Content-type的值)。 至此,我们就完成了百度语音侧的配置 ----------------------------------------------华丽的分界线---------------------------------------------------------- 配置我们的RTT工程,menuconfig中打开webclient GET/POST samples的应用,如图: ![TIM截图20180826171740.png](/uploads/201808/26/171817tppsux1zzrdiroks.png) 经过pkgs --update和scons命令后,我们就可以在IDE中根据我们的需求来开发应用了。 这里思路如下,我们参考之前weather的应用,在post完之后,立即获取响应,并进行处理(分段/提取)、判断(开关灯识别)即可。这里需要注意的,就是填写**正确的API地址**和**Content-type**, 详情请参考帖子最后的参考代码。 最后效果验证,将音频文件传入到开发板中(TFTP或SD卡拷贝),启动RTT,输入asr_led on1.pcm,即可对on1.pcm音频文件进行语音识别、转换成文字并进行LED控制,效果如图 ![TIM截图20180826153430.png](/uploads/201808/26/172658i86dnd8regj8dsmj.png) **_总结_** 1、遇到一个坑,本想通过RTT中POST/GET例程的webclient_get_file和webclient_post_file来直接实现,将音频文件post上去后,再get响应信息,但是发现不行,初步分析是在webclient_post_file完成之后,就关闭了session,再次webclient_get_file的状态就不对了,所以获取失败。所以调整成现在的形式。 2、IDE中对比中文文字时(比如对比“关灯”)需要输入中文字符,最好将IDE配置成UTF-8的编码格式,否则比对会一直失败。但在我的IDE中还是会遇到奇葩的情况,如“开灯”会被“吃”掉一个双引号,导致编译失败。这个问题后续我好好研究一下。 **_开发资源_** 语音文件: ![on1.pcm](/uploads/201808/26/162728bjxs704fjj1xifz1.attach) ![on2.pcm](/uploads/201808/26/162728h8f711fee71971z8.attach) ![off1.pcm](/uploads/201808/26/162727y4u4j85yucrjcc05.attach) ![off2.pcm](/uploads/201808/26/162727qexe9ebwb8wibagv.attach) 参考代码: ``` static char *TurnOn1 = "开"; static char *TurnOn2 = "回来"; static char *TurnOff1 = "关"; static char *TurnOff2 = "睡觉"; static char *my_url = "http://vop.baidu.com/server_api?dev_pid=1536&cuid=asr&token=*******************************"; /* 请将******的部分更换成token */ static char *my_type = "audio/pcm;rate=16000"; int asr_led(int argc, char** argv) { 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 = NULL; if (argc != 2) { rt_kprintf("baidu_asr filename
"); return 0; } 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; } session = (struct webclient_session*) web_malloc(sizeof(struct webclient_session)); if (!session) { rc = -WEBCLIENT_NOMEM; goto __exit; } memset(session, 0x0, sizeof(struct webclient_session)); rc = webclient_connect(session, my_url); if (rc < 0) goto __exit; header = (char*) web_malloc(WEBCLIENT_HEADER_BUFSZ); if (header == NULL) { rc = -WEBCLIENT_NOMEM; goto __exit; } header_ptr = header; /* build boundary */ rt_snprintf(boundary, sizeof(boundary), "----------------------------%012d", rt_tick_get()); /* build encapsulated mime_multipart information*/ buffer_ptr = buffer; /* first boundary */ buffer_ptr += rt_snprintf((char*) buffer_ptr, WEBCLIENT_RESPONSE_BUFSZ - (buffer_ptr - buffer), "--%s
", boundary); buffer_ptr += rt_snprintf((char*) buffer_ptr, WEBCLIENT_RESPONSE_BUFSZ - (buffer_ptr - buffer), "Content-Disposition: form-data; %s
", my_type); buffer_ptr += rt_snprintf((char*) buffer_ptr, WEBCLIENT_RESPONSE_BUFSZ - (buffer_ptr - buffer), "Content-Type: application/octet-stream
"); /* calculate content-length */ length += buffer_ptr - buffer; length += strlen(boundary) + 6; /* add the last boundary */ /* build header for upload */ header_ptr += rt_snprintf(header_ptr, WEBCLIENT_HEADER_BUFSZ - (header_ptr - header), "Content-Length: %d
", length); header_ptr += rt_snprintf(header_ptr, WEBCLIENT_HEADER_BUFSZ - (header_ptr - header), "Content-Type: %s
", my_type); /* send header */ rc = webclient_send_header(session, WEBCLIENT_POST, header, header_ptr - header); if (rc < 0) goto __exit; /* send mime_multipart */ webclient_write(session, buffer, buffer_ptr - buffer); /* send file data */ while (1) { length = read(fd, buffer, WEBCLIENT_RESPONSE_BUFSZ); if (length <= 0) break; webclient_write(session, buffer, length); } /* send last boundary */ rt_snprintf((char*) buffer, WEBCLIENT_RESPONSE_BUFSZ, "
--%s--
", boundary); webclient_write(session, buffer, strlen(boundary) + 6); if (webclient_handle_response(session)) { if (session->response != 200) { rt_kprintf("webclient handle response(%d) error!", session->response); goto __exit; } } length = webclient_read(session, buffer, WEBCLIENT_RESPONSE_BUFSZ); buffer_ptr = buffer; buffer_ptr[length] = '\0'; buffer_ptr = strstr(buffer_ptr, "result")+strlen("result\":[\""); buffer_ptr[strstr(buffer_ptr, "\"") - buffer_ptr] = '\0'; rt_kprintf("We get the result: %s
", buffer_ptr); if((strstr(buffer_ptr, TurnOn1))||(strstr(buffer_ptr, TurnOn2))) { rt_kprintf("We get the command, I will turn it on
"); LED_Ctrl_On(); } else if((strstr(buffer_ptr, TurnOff1))||(strstr(buffer_ptr, TurnOff2))) { rt_kprintf("We get the command, I will turn it off
"); LED_Ctrl_Off(); } else { rt_kprintf("We do not get any valid command, I will do nothing
"); } __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; } MSH_CMD_EXPORT(asr_led, Baidu ASR services); ```
查看更多
0
个回答
默认排序
按发布时间排序
暂无答案,快来添加答案吧
撰写答案
登录
注册新账号
关注者
0
被浏览
2.6k
关于作者
ianhom
这家伙很懒,什么也没写!
提问
17
回答
16
被采纳
0
关注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
ota在线升级
UART
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
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
a1012112796
13
个答案
1
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部