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 chunk
、Format chunk
和Data chunk
。另外,文件中还可能包含一些可选的区块,如:Fact chunk
、Cue points chunk
、Playlist chunk
、Associated data list chunk
等。
FORMAT区块
- 以
'fmt '
为标识
Size
表示该区块数据的长度(不包含ID
和Size
的长度)
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区块
- 以
'data'
为标识
Size
表示音频数据的长度,N = ByteRate * seconds
Data
音频数据
4. 清理缓冲期
记得要在每次不需要音频 Buffer 数据的时候清理缓冲区,避免内存持续堆积。