小程序——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解碼和上傳時間

六、收穫
 完成了小程序社區沒人敢去嘗試的一條路
 辦法總比問題多
 沉着冷靜逐一擊破
 後面再優化

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