这事情急不得

讯飞语音识别

2019-04-09  本文已影响136人  这事情急不得

语音识别,科大讯飞提供了sdk和web api,相比于sdk还要下载安装,web api显然clean很多,只要直接通过http调用它的api就可以了。

但web api有明显的的限制,比如上传的语音不能超过60秒,只支持8k和16k的采样率,只支持单声道。

所以,目前网上的示例代码基本上都是先弄好了一个语音文件,这个语音文件满足上面的所有要求,然后load这个语音文件发给讯飞语音识别api。这么做的原因是我们一般从麦克风中采样的音频通常都是立体声双声道44100hz采样率,要满足讯飞web api的苛刻条件,必须把采样的音频先存到磁盘上然后再用专业的音频处理软件处理成能满足讯飞web api要求的音频文件。

显然,要先弄出一个语音文件,这些个步骤太麻烦了,理想情况是我能有个网页,网页上点击“start”,然后我开始说话,说完点击“stop”,然后我说的话就被自动处理成讯飞web api支持的格式,自动发给web api进行语音识别并得到结果。

显然,这里面的难点在于如何在网页前端就能自动化处理从麦克风取得的音频并且自动处理成讯飞web api支持的格式。这就需要用到浏览器的web audio api。

首先,要从麦克风采集音频,仍然像webrtc一样,需要调用getUserMedia,指定audio:true,video: false,这样就会打开麦克风得到本地的音频流。

接下来就是要用web audio api来create AudioContext和自定义的音频处理节点:JavaScriptNode。

接下来当stream流过我们的自定义的处理函数onAudioProcess时,我们要把采集的音频数据存储到buffer里。

最后,当点击“stop“的时候,我们要停止记录buffer并且完成音频格式的转换,然后发送给科大讯飞,或者发送给我们服务器,我们的服务器可以存储音频成wav文件,然后再发送给科大讯飞。

这里首先把之前创建的AudioContext和各个节点给disconnect,close掉,这样就不会再接收音频stream了,然后调用mergeBuffer来把刚才采集的buffer数组的集合merge成一个buffer,注意这里的merge使用了JS的TypedArray技术。

然后调用audioContext.createBuffer来create我们最终需要的buffer,这个buffer的参数里面numChannels=1表示单声道,sampleRate=16000。

然后调用audioBuffer.copyToChannel来把我们采集到的buffer里的数据拷贝到我们最终需要的单声道16000采样率的buffer里面去,但此时copy进去的数据是双声道44100采样率,显然不符合这个buffer的定义,因此最后就需要调用resampleAudioBuffer来调整数据使其match这个buffer的定义。

剩下的所有代码如下。

resampleAudioBuffer里首先根据44100和16000采样率的不同计算出总共需要多少音频帧,然后创建OfflineAudioContext以对buffer进行重采样处理,在offlineContext的oncomplete回调中,我们获得重采样之后的buffer,但此时该buffer仍然还是双声道,我们需要把它变成单声道,因此需要调用interleave函数,interleave函数简单的把左右声道的buffer合并成一个声道的buffer。

最后,科大讯飞的语音识别web api只能接受PCM/WAV编码格式的音频,这里我们需要把转换完的buffer变成PCM编码并且还要加上wav文件格式头,代码就如encodeWAV函数所示。

注意这里最后返回的是一个DataView数据结构,这是一个可以封装各种不同Typed数值类型的视图。最后为了把数据发送到server,server可以使用multer或者websocket来接收这段数据,我们把数据封装成blob格式,这样一旦server接收到了这段数据,就可以直接把这段数据以二进制方式写入本地磁盘的新的.wav文件,以multer为例,server是nodejs,那么类似下面这样。

最后,如何crack出这些code,实际上是参考了网上的文章和几个不同的open source的代码的结果,可惜的是没有任何一个open source能够完全满足我们的要求,所以不得不去阅读open source源代码并且抽取出适合我们的需求的代码并加以改造才行。在以open source为基础的企业中,碰到这样的情况是很常见的,通常能正好满足需求的open source基本上找不到,因为你会发现要么open source解决的问题和你要解决的问题间虽然相似但不是完全match,要么open source的代码质量比较差毫无错误处理,只是为了demo能work就传到github上去了。当然,没有open source里面的代码和网上的文章也弄不出这样的code。

参考资料:

https://subvisual.co/blog/posts/39-tutorial-html-audio-capture-streaming-to-node-js-no-browser-extensions/

http://www.jingpingji.com/blog/2015/8/4/transferring-sound-data-with-binaryjs-and-buffering-for-smooth-playbac

https://stackoverflow.com/questions/43903963/post-html5-audio-data-to-server

https://stackoverflow.com/questions/6182315/how-to-do-base64-encoding-in-node-js

https://stackoverflow.com/questions/30031561/change-sample-rate-of-audiocontext-getusermedia

https://github.com/andreasgal/node-wav

https://github.com/TooTallNate/node-wav

http://typedarray.org/from-microphone-to-wav-with-getusermedia-and-web-audio/

https://github.com/mattdiamond/Recorderjs

上一篇下一篇

猜你喜欢

热点阅读