Skip to content

探讨浏览器音频是如何播放的

Updated: at 09:22 AM

前言

因为在项目中涉及到了浏览器音频处理的功能,发现以前没了解过,这次就来梳理下是怎么运行的

浏览器内置音频处理器 Web Audio API

根据我画的图例,从输入到输出 我们可以把每个音源都当作是一个 audioChunks 并非一次性发送,而是切割成每个 audioBufferSourceNode (虚线)一段一段的,包装成一个数组。

audioBufferSourceNode?

它就是表示一个音频源,包含存储在内存中的音频数据,存储在 ArrayBuffer 对象中,没有输入只有输出,需要指定一个buffer 若为null,将输出一个无声的单通道。

注意!!!

一个 audioBufferSourceNode 只能播放一次,每次调用 start() 后都行重新再创建一个 audioBufferSourceNode 但是 AudioBuffer 可以重用,GC 会在合适的时间自动进行回收

AudioCOntext.destination

音频源-a/b:可以看作就是一个音频文件,而音频文件本身就是音频采样数据,一秒钟可以采样几万个片段 通过顶端多个节点进行连接,最后连接到一个目的地 AudioCOntext.destination 通过他 来负责把声音传输出去(扬声器/耳机)等设备

zjh01.png

代码示例

//讲音频源多个片段以字节码的形式合并
const totalLength = this.audioChunks.reduce(
  (acc, chunk) => acc + chunk.byteLength,
  0
);
//通过unit8Array编码
const combineBuffer = new Uint8Array(totalLength);

let offset = 0;
for (const chunk of this.audioChunks) {
  //转换为类型化数组
  combineBuffer.set(new Uint8Array(chunk), offset);
  offset += chunk.byteLength;
}
//创建音频上下文
this.audioContext = new (window.AudioContext ||
  (window as any).webkitAudioContext)();
//构建出一个完整的音频文件
const audioBuffer = await this.audioContext.decodeAudioData(
  combineBuffer.buffer
);

//创建能够播放的音频源环境
this.audioSource = this.audioContext.createBufferSource();
//这里是标记 audioBuffer需要播放的音频 为0时,表示是一个静默单通道
this.audioSource.buffer = audioBuffer;
//连接音频,最后通过 destination播放
this.audioSource.connect(this.audioContext.destination);

流程图

zjh02.png