小程序——MP3转pcm之殇

一、 需求背景

  1. 明确需求:
    微信小程序实现语音识别。
  2. 分析需求:

    目前我们科大讯飞平台目前已经支持语音识别相关业务,我们只要将小程序语音上传(对接)到科大讯飞语音处理后台,就能完成上述需求。

  3. 问题拆解:
    上述需求 => 将小程序语音按照目前接口要求的格式上传到讯飞语音接口。

二、 分析和调研问题

  1. 小程序支持的录音格式(MP3,AAC),采样率(8k-48k)

clipboard.pngclipboard.png
clipboard.pngclipboard.png

2.科大讯飞语音接口接收的参数

将语音转换为对应的文本和语义

![图片上传中...]

3.明确需求:

  • 由于小程序支持MP3和AAC两种录音格式,但是EPG的语音接口支持分片上传,所以我们只能选择mp3格式
  • EPG语音接口支持 四种编码格式(pcm、speex、speex、opus),采样率 8k或16k。
  • 思路:(目前的采样率认为是可以16k=> 16k不用变)

a) Mp3 => pcm
b) Mp3 => speex
c) Mp3 => amr
d) Mp3 => opus

  • 经过一番调研 github 或者npm包(因为小程序没有window对象,搜索资料node.js不能用浏览器下的对象)

a) 有一个工具ffmpeg(安装) 命令行转(不满足需求)
b) 【小程序社区】社区中有两种声音
(1)官方能不能增加pcm录音格式(官方给出暂时不考虑)
(2)MP3 => pcm放在服务器端做(我们的后端推不动)
(3)【很高兴】得知github js-mp3开源库可以将MP3的arraybuffer => pcm格式的arraybuffer
https://developers.weixin.qq....

  • 验证js-mp3能不能将MP3转为pcm格式

a) 网上下载 MP3
b) 在node.js中写对应的demo
c) 可以将MP3转为 pcm(很高兴,也没注意该MP3的采样率是多少)
d) 微信小程序demo, 将录音的mp3,将录音的MP3文件由临时文件保存到本地文件(此时不知道保存到哪里了,手机的根目录/tencent/MicroMsg/wxafiles/tem_XXXXXX, 文件名变了,文件管理功能不强大)
e) 将录音MP3(16k)试着用 js-mp3转码(很可惜失败了,绝望)

  • 分析js-mp3转码不成功的原因

a) MP3有几种格式

clipboard.png

b) 下载ultraEdit对MP3文件头分析
音频数据帧

         每个帧都有4 字节帧头 + 2 字节CRC校验(存在是否由帧头决定)+ 尸体数据(MAIN_DATA)
 Ø  帧头
 AAAAAAAA   AAABBCCD   EEEEFFGH    IIJJKLMM

clipboard.png
图片描述

clipboard.png

c) js-mp3支持的MP3帧数据的前几位是
(1)49 68
1001001 011 01 00 0
保留 保留
(2)49 51
1001001 010 10 00 1
Mpeg2 保留
(3)FF FA
11111111 111 11 01 0
Mpeg1 layer3
(4)FF FB
11111111 111 11 01 1
Mpeg1 layer3

        总结:这个包只支持采样率为32k以上的音频转码

http://www.mp3-tech.org/progr...
d) 微信MP3(16k,8k)所属格式(几个转码不成功的)
微信 wx.mp3
Ff f3 68 04
1111 1111 1111 0011 0110 1000 0000 0100
Mpeg2 Layer3 比特率 48 采样率 8000

Wx1.mp3
【开头16进制】49 44 33 03
【二级制】0100 1001 0100 0100 0011 0011 0000 0011
Mpeg2.5 layer2 比特率 24 采样率 12000

clipboard.png

FF F3
1111 1111 111 10 01 1
Mpeg2 layer3

图片描述

下载的MP3
Ff f3 40 c0
1111 1111 111 10 01 1 0100 0000 1100 0000
MPEG 2 layer3 比特率 32 采样率 22050

【绝望】js-mp3 好像不行了,从新调研其他包

三、 解决问题

  1. 调研从零开始,理清思路。
  2. 通过调研得知wav = pcm + 44字节(头信息),于是MP3=>pcm转为MP3=>wav

Pcm播放器播不了,wav能播

  1. audiobuffer-to-wav

图片描述

a) 【曙光】Mp3文件 buffer => arraybuffer
=> audioBuffer =>
wav的ArrayBuffer => buffer(写入文件)
b) Audiobuffer 这个对象是浏览器端的对象(绝望)
c) audio-decode 这个包在node端也支持https://github.com/audiojs/au...
d) 开始测试普通的MP3文件转码ok, 小程序录音的MP3文件又报错
断点调试:这个包引入 ‘is-mp3’

clipboard.png

经过分析得知:
wx MP3开头 Ff f3
支持的开头 (1)FF FA/FB (2)49 44/33
怀疑: 这难道不是真正的MP3

手动添加

clipboard.png

校验过去了,但是还是不支持这种采样率为(16k或者8k的),转换时候报错了

  1. 【转换思路】先用 32k以上的采样率(这样起码MP3=> pcm是成功的),然后再同一种格式下降低采样率(32k=> 16k)
  2. 在node端验证完毕(js-mp3或者audio-decode)
  3. 在小程序端实现时(audio-decode报错,暂时没解决。Js-Mp3没有报错)

得到pcm格式(32k采样率)

let Mp3 = require('js-mp3');

var mp3ArrayBuffer = ...; // prepare your mp3 decoded array buffer here

    var decoder = Mp3.newDecoder(mp3ArrayBuffer);
var pcmArrayBuffer = decoder.decode(); // now you got decoded PCM data
  1. 【新问题】pcm (采样率由32k转为16k)
  2. Pcm-util

    pcm.convert(buffer, fromFormat, toFormat)
    Convert array buffer from one format to another.
    图片描述

注意:
 采样率 32k 变为 16k
 SamplesPerFrame和采样率是对应的
 BitDepth不设置的时候,默认是16
保存pcm(pcm文件大小约为MP3文件大小的10倍)文件到本地,此时用ffmpeg将pcm转为wav
(1) 用采样率为16k转换时,时长为原MP3的两倍(严重失真)
(2) 用采样率32k转换时,时长和原mp3一致(不失真)
结论: 上述pcm 32k=> pcm16k时没有成功(toFormat有问题)。
通过排查将bitDepth设为 原来的一半 8,结果 pcm 16k文件约为原mp3大小的5倍,ffmpeg 16k 转为wav播放正常(无失真)

四、对接科大讯飞语音识别Ai

  1. 测量转码耗时

录音时长(s) 转码时间(s)
10.920 7.118
5.8 3.972
1.48 0.918
提交转码后的16k pcm,可以实现语音识别
五、分析和优化
分析

  1. 实现了从0到1到过程(不用依赖后端,自己也能玩起来)
  2. 由于现在没有利用分片上传、分片转码,分片转意的过程。耗时相对较长
  3. 现在js-mp3转码只能识别 整个MP3,而分片 不是一个MP3格式的数据,是纯数据切断(导致,这个方案不能分片解码、上传)
  4. 目前耗时 在两步 MP3(32k)=> pcm(32k)=> pcm(16k)

优化
1.变两步为一步 mp3 (16k) => pcm (16k)
2.解决audio-decode 引入错误,如果能将 ,mp3的arraybuffer 分片转为audioBuffer(不依赖整个mp3头),完成 pcm(16k) 直接转换

  1. 分片上传 10s 的时长,转码耗时只是最后一个分片的2s解码和上传时间

六、收获
 完成了小程序社区没人敢去尝试的一条路
 办法总比问题多
 沉着冷静逐一击破
 后面再优化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章