← Back to blog

记录浏览器 dump 麦克风音频数据

1. 浏览器获取麦克风数据

// 请求访问麦克风
let stream = await navigator.mediaDevices.getUserMedia({ audio: true })

// 创建一个音频上下文
let audioContext = new AudioContext();
// 创建一个媒体流源
let audioInput = audioContext.createMediaStreamSource(stream);

2. 获取当前麦克风流的音频 PCM 数据

MediaStreamSourceNode connect 到可以获取数据的 AudioNode,这里方案有很多就不展开了,可以根据自己的需要进行取舍:

  • AudioWorklet
  • ScriptProcessor
  • AnalyseNode

3. 把 PCM 数据转存成 WAV 格式后使用 Blob Url 下载

WAV文件遵循RIFF规则,其内容以区块(chunk)为最小单位进行存储。WAV文件一般由3个区块组成:RIFF chunkFormat chunkData chunk。另外,文件中还可能包含一些可选的区块,如:Fact chunkCue points chunkPlaylist chunkAssociated data list chunk等。

FORMAT区块

名称偏移地址字节数端序内容
ID0x004Byte大端’fmt ’ (0x666D7420)
Size0x044Byte小端16
AudioFormat0x082Byte小端音频格式
NumChannels0x0A2Byte小端声道数
SampleRate0x0C4Byte小端采样率
ByteRate0x104Byte小端每秒数据字节数
BlockAlign0x142Byte小端数据块对齐
BitsPerSample0x162Byte小端采样位数
  • 'fmt '为标识
  • Size表示该区块数据的长度(不包含IDSize的长度)
  • AudioFormat表示Data区块存储的音频数据的格式,PCM音频数据的值为1
  • NumChannels表示音频数据的声道数,1:单声道,2:双声道
  • SampleRate表示音频数据的采样率
  • ByteRate每秒数据字节数 = SampleRate * NumChannels * BitsPerSample / 8
  • BlockAlign每个采样所需的字节数 = NumChannels * BitsPerSample / 8
  • BitsPerSample每个采样存储的bit数,8:8bit,16:16bit,32:32bit

DATA区块

名称偏移地址字节数端序内容
ID0x004Byte大端’data’ (0x64617461)
Size0x044Byte小端N
Data0x08NByte小端音频数据
  • 'data'为标识
  • Size表示音频数据的长度,N = ByteRate * seconds
  • Data音频数据

4. 清理缓冲期

记得要在每次不需要音频 Buffer 数据的时候清理缓冲区,避免内存持续堆积。