写在前面

时隔一年没有写博客了,最近的一篇博客是2017年4月17日,怎么说呢,一个字,懒。哈哈,当然实际上是从去年四月开始接到做语音识别的项目去了,一直到现在也没什么空(其实有空,但是还是懒)。被各种bug折磨了一整年之后,终于也算是熬出头了,这里就写一个关于语音框架构建的博客,不过因为公司项目,肯定不能说得太详细了,说个大概吧,具体代码之类的可以去看看百度的那个duros,虽然我觉得它写得很烂。

关于语音识别

语音识别是一个很庞大的东西,当然对于我们这样的客户端选手来说,需要了解的也不多,这里简单的说一下,因为很庞大,所以篇幅原因,我就不说太详细(其实还是因为懒)。

云端识别

语音识别因为需要很大的数据量作为支持,所以要得到很好的体验,只能通过服务器跑神经网络来实现,所以大部分的识别是放在云端的,这里本地只需要做好网络和录放音即可。然后语音识别分两种,一种叫做听写机,还有一种叫做JSGF。他们两个的区别就在于听写机是你随便说什么,他都能给你识别出来,对错就不知道,也没有一个固定的值,JSGF就只能够识别固定的词语,你设置了他就能识别,没有设置他就不能识别。这里你就可以看看Siri的实现,当你对Siri说打电话给张三的时候,“打电话给”这四个字就是云端听写机实现的识别,“张三”这两个字就是JSGF识别的,因为张三在当前情况下一定是一个人名,那么它就会拿这个语音到你的通讯录,通过JSGF来识别。JSGF简单的说就是在一个固定的结果集里面,一定会识别出一个结果给你。如果这里我没解释清楚的,自己去百度看看,记住,就是两种东西:听写机和JSGF。

本地识别

由于刚才说了识别就分两种,一种是听写机,还有一种是JSGF,因为听写机需要很庞大的数据支撑,所以本地只能使用JSGF,当然这也至少有二三十兆。JSGF放在本地一般用作唤醒,比如类似hey Siri这种操作,当然Siri还做了声纹识别。还用作识别第一个、第二个这种类似选择的命令词。

端点检测

这个用作检测当前是否有人说话。

回声消除

回声消除主要用在当设备在播放音频的同时还要录音识别的时候,因为这种时候mic会把播放出来的音频一起录制回去,所以需要做一个消除的算法,由于android手机的AudioTrack和AudioRecord中都存在一个环形缓冲区,而每一个厂家的缓冲区大小不同,所以会造成录制的音频和当前播放的音频不一致,音频起点无法对齐,而出现消除效果很差的情况,所以这个功能在Android手机上是一个难以突破的瓶颈,不过可以勉强使用系统自带的communication来实现,不过很多厂家可能是由于技术原因吧,这个communication的参数根本没用,这里点名小米,小米垃圾,哈哈哈。

TTS

TTS就是把文字生成为音频的一个东西,也分为云端和本地,当然是云端效果好,不过本地也有它的作用,比如说没有网络的时候。

SILK

这是一个音频压缩库,主要用于本地和服务器通信的时候对数据做压缩处理。

正文开始咯

思路

怎么说呢,这个东西是一个很庞大的,一时半儿说不清楚,这里涉及太多东西了,我先挨个说怎么做,至于为什么这样做,能解释的就解释,不能解释的,就先挨个去了解这些知识,最后就知道为什么了。

分包

一共分4个包:

  1. SILK音频压缩
  2. TTS+音频播放
  3. 本地识别+端点检测+回声消除+音频录制
  4. 云端识别

本地识别包的实现

一个录音数据同步队列
一个识别结果同步队列
一个录音线程
一个识别线程
内部流程:录音线程录制音频放入录音队列,识别线程从录音线程取出数据识别后放入结果队列
外部调用:从结果队列取出结果进行操作
结果数据包括:识别内容、音频原始数据、端点数据

TTS包的实现

一个生成同步队列
一个结果同步队列
一个生成线程
一个播放线程
内部流程:生成线程从生成队列中取出文字进行生成,生成的音频放进结果队列,播放线程从结果队列中取出音频进行播放
外部调用:需要传入interface从内部回调播放状态

云端识别的实现

云端识别需要依赖本地识别库,然后从本地识别库中取数据往云端发,这里需要一个网络队列即可。

具体业务实现

架构

采用MVP架构,能够做到多个子流程解耦,比如说在Siri中,播放音乐和拨打电话,这能够分为两个子流程,他们和主流程(对话流程)是毫不相干的,但是他们却是操作的同一个页面,那么这里我们能够联想到MVP架构,我只需要在切换流程的时候切换不同的presenter即可,页面不用进行其他操作,而且每个presenter中的业务也毫不相干,可以多人共同协助开发。这里的业务分发根据云端识别后进行语义分析返回的业务标签来判断,这里我们可以考虑做成注解的方式,子流程在类名上注解自己处理的业务标签,主流程在得到业务标签后进行遍历,反射调用子流程,这样的话完完全全能够模仿Spring的操作了。

然后我感觉好像也没什么可说的了,因为涉及到太多不能说的东西,而且还有很多单独拿出来都很庞大的东西,不是三言两语能说清楚的,比如说JSGF,这里只是提供一个思路,提供一个方向,按照这个放下往下走,是可以构建出一个语音识别的开发框架的。你们可以找一下各种语音开放平台,下载这些库,来根据我这个大概的思路进行实现。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐