你猜猜JS 如何進行音頻流的編碼封裝?下

接上篇,說到第一步獲取本地音頻流,咱們都知道,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

相關文章
相關標籤/搜索