接上篇,说到第一步获取本地音频流,我们都知道,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格式封装的音频流了
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。