【Recorder.js+百度语音识别】全栈方案技术细节 (2)

要利用recorder.js实现上述需求,需要对源码进行一些功能扩展。编码转换可以在服务端进行,而recorder.js中的floatTo16BitPCM( )方法看名字应该是为了满足16bit位深这个条件的,那么我们只需要考虑单声道和16000采样率这两个条件了。

【Recorder.js+百度语音识别】全栈方案技术细节

源码中Recorder构造函数是可以接受参数的,而这个参数会被合入实例的config属性,其中numChannles就是声道数,所以我们只需要在实例化是传入自定义的声道数目即可:

new Recorder({ numChannels:1//单声道 })

再来看16000采样率这个条件,查看源码可以知道,源码中对于sampleRate的使用,一律使用了音频流数据源上下文的sampleRate,也就是对应着电脑声卡的采样率(48000Hz或44100Hz),那如何得到16000Hz采样率的数据呢?比如一个48000Hz采样率的声卡采集的信号点,1秒采集了48000次,那么这48000个数据要变成16000个数据,最简单的办法就是每4个点取1个然后组成新的数据,也就是说实际上声音采集设备传过来的采样率是固定的,我们需要多少的采样率,只需要自己拿一个比例系数去换算一下,然后丢弃掉一部分数据点(当然也可以求平均值)就可以了,封装后的调用方式为:

new Recorder({ numChannels:1, sampleRate:16000 });

那么在源码中需要做一些功能的扩展,关键的部分在下面这段代码:

//recorder.js部分源码 function exportWAV(type) { var buffers = []; for (var channel = 0; channel < numChannels; channel++) { buffers.push(mergeBuffers(recBuffers[channel], recLength)); } var interleaved = undefined; if (numChannels === 2) { interleaved = interleave(buffers[0], buffers[1]); } else { interleaved = buffers[0]; //此处是重点,可以看到对于单声道的情况是没有进行处理的,那么仿照双声道的处理方式来添加采样函数,此处改为interleaved = extractSingleChannel(buffers[0]); } var dataview = encodeWAV(interleaved); var audioBlob = new Blob([dataview], { type: type }); self.postMessage({ command: 'exportWAV', data: audioBlob }); }

extractSingleChannel( )的具体实现参考interleave( )方法

/** *sampleStep是系统的context.sampleRate/自定义sampleRate后取整的结果,这个方法实现了对单声道的*采样数据处理。 */ function extractSingleChannel(input) { //如果此处不按比例缩短,实际输出的文件会包含sampleStep倍长度的空录音 var length = Math.ceil(input.length / sampleStep); var result = new Float32Array(length); var index = 0, inputIndex = 0; while (index < length) { //此处是处理关键,算法就是输入的数据点每隔sampleStep距离取一个点放入result result[index++] = input[inputIndex]; inputIndex += sampleStep; } return result; }

这样处理后exportWAV( )方法输出的Blob对象中存放的数据就满足了百度语音的识别要求。

四. 服务端开发细节

在服务端我们使用Express框架来部署一个消息中转服务,这里涉及的知识点相对较少,可以使用百度AI的nodejs-sdk来实现,也可以自行封装,权限验证的方法几乎都是通用的,按照官方文档来做就可以了。

通过multipart/form-data方式提交的表单无法直接通过req.body或req.params进行处理,这里使用官方推荐的Multer中间件来处理,此处较为简单,直接附上笔者的参考代码:

【Recorder.js+百度语音识别】全栈方案技术细节

此处有一点需要注意的是:在实例化Multer时,传参和不传参时得到的转换对象是不一样的,如果涉及到相关场景可以直接在控制台打印出来确保使用了正确的属性。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsjjw.html