接上篇,說到第一步獲取本地音頻流,咱們都知道,H5有一個新增的接口專門來處理音頻流相關方法,他就是大名鼎鼎的AudioContext
,至於這個對象具體能作什麼,各位看官自行百度。我這邊主要用到的是createMediaStreamSource
方法createScriptProcessor
方法,createMediaStreamDestination
方法。此三個方法最終能夠獲取到咱們想要的本地設備拉出來的音頻流,代碼以下 :瀏覽器
let ac =new AudioContext(); let source = this.ac.createMediaStreamSource(stream); let scriptNode =ac.createScriptProcessor(2048, 1, 1); let dest = this.ac.createMediaStreamDestination();
//當你想觸發音頻採集時候,就執行下面兩行代碼 source.connect(scriptNode); scriptNode.connect(dest);
而後scriptNode有一個方法onaudioprocess
能夠監聽到音頻流採樣函數
scriptNode.onaudioprocess = (audioProcessingEvent) => { const { inputBuffer } = audioProcessingEvent; const inputData = inputBuffer.getChannelData(0); }
這裏咱們能夠獲得inputData.sampleRate
這個是音頻流的採樣率,通常默認是44000,而後到這裏咱們基本就完成了第一步,拿到音頻流以及音頻流的採樣率。知識點不足的各位自行百度惡補。this
接着第二步驟,由於瀏覽器拉出來的音頻流的採樣率過高,會給傳輸帶來壓力,再說也不須要那麼高的採樣率,和後臺商定採樣率定爲8K,那接下來就是壓縮採樣率編碼
function compress(sampleRate, data) { if (sampleRate < outSampleRate) return data; const compressRatio = Math.floor(sampleRate / outSampleRate); const compressLen = data.length / compressRatio; const result = new Float32Array(compressLen); let index = 0; let k = 0; while (index < compressLen) { result[index] = data[k]; k += compressRatio; index++; } return result; }
以上代碼相信你們都看得懂,sampleRate就是咱們獲得的 44000的音頻採樣率,data就是咱們前面獲得的inputData,這個函數方法return的東西就是咱們壓縮後的8K的採樣率code
接下來就是最重要的一步,封裝FLV格式,FLV格式比較簡單,前面都有一個flv的頭佔9位,而後4位默認都是0的previouSize(默認第一個都是0)。接下來都是tag數據,tag數據氛圍兩個部分tagheader,封裝了一些tagdata信息 佔11位,tagData第一位爲解碼數據,剩下的就是音頻數據,最後四位爲previouseSize,爲data數據的大小。
以上就是基本的概念,接下來就是封裝了上代碼:對象
const payloadLen = data.length * 1; const buffer = (tagCount == 0)? new ArrayBuffer(9 + 4 + 11 + 1 + payloadLen + 4): new ArrayBuffer(11 + 1 + payloadLen + 4); const output = new DataView(buffer); setFlvHeader(output, payloadLen, tagCount); //flv 流 tagCount默認爲0
以上就是壓縮代碼了,經過setFlvHeader的方法,能夠把咱們的音頻流進行flv的片斷封裝。接口
接下來也是重要的一步,進行g711a編碼封裝,上代碼 :ip
let offset = tagCount == 0 ? 25 : 12; for (let i = 0; i < data.length; i++, offset += 1) { const s = Math.max(-1, Math.min(1, data[i])); const int16 = s < 0 ? s * 0x8000 : s * 0x7FFF; const alawUint8 = encodeALawSample(int16); output.setUint8(offset, alawUint8); }
由於咱們是先封裝格式,再進行編碼壓縮,因此根據tagCount,咱們有一個offset的變量來記錄編碼位置。咱們先把32位浮點類型轉成16位int型,再而後經過方法encodeAlowSample方法進行編碼操做。
最後咱們獲得的就是 g711a編碼 而且有flv格式封裝的音頻流了get