6

接上篇,说到第一步获取本地音频流,我们都知道,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,然后到这里我们基本就完成了第一步,拿到音频流以及音频流的采样率。知识点不足的各位自行百度恶补。

接着第二步骤,因为浏览器拉出来的音频流的采样率太高,会给传输带来压力,再说也不需要那么高的采样率,和后台商定采样率定为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的采样率

接下来就是最重要的一步,封装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编码封装,上代码 :

    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格式封装的音频流了


罗鼎
57 声望4 粉丝