如何将MediaRecorder采集的音频数据适配到lamejs进行MP3编码?
解决MediaRecorder采集数据转lamejs所需Int16Array的问题
核心原理
MediaRecorder采集的chunks是压缩后的音频Blob(默认是WebM/Opus格式),而lamejs要求输入的是原始PCM音频样本(16位有符号整数,对应Int16Array)。必须先把Blob解码为原始音频数据,再转换为符合要求的格式。
分步实现
1. 解码Blob为AudioBuffer
先把收集到的chunks合并成完整Blob,再用AudioContext解码成存储原始PCM数据的AudioBuffer:
// 假设chunks是MediaRecorder收集到的数组 async function decodeChunksToAudioBuffer(chunks) { const blob = new Blob(chunks, { type: 'audio/webm' }); // 对应MediaRecorder的MIME类型 const arrayBuffer = await blob.arrayBuffer(); const audioContext = new AudioContext(); return audioContext.decodeAudioData(arrayBuffer); }
2. 转换AudioBuffer为Int16Array
AudioBuffer的getChannelData()返回范围[-1, 1]的Float32Array,需转成16位有符号整数(范围[-32768, 32767]):
function audioBufferToInt16Array(audioBuffer, isMono = true) { const channelData = audioBuffer.getChannelData(0); // 取第一声道(单声道场景) const int16Array = new Int16Array(channelData.length); // Float32转Int16:乘以对应极值,限制范围防止溢出 for (let i = 0; i < channelData.length; i++) { const sample = Math.max(-1, Math.min(1, channelData[i])); int16Array[i] = sample < 0 ? sample * 32768 : sample * 32767; } // 立体声场景需分别提取左右声道的Int16Array,后续传给lamejs时分开传入 return int16Array; }
3. 整合到lamejs编码逻辑
替换原示例中的静音样本,用处理后的真实音频数据编码:
// 先处理chunks得到可用的Int16Array样本 const audioBuffer = await decodeChunksToAudioBuffer(chunks); const samples = audioBufferToInt16Array(audioBuffer); // 沿用lamejs编码逻辑,注意匹配声道数和采样率 let channels = 1; // 对应AudioBuffer的实际声道数 let sampleRate = audioBuffer.sampleRate; // 用解码后的真实采样率,避免格式不匹配 let kbps = 128; let mp3encoder = new lamejs.Mp3Encoder(channels, sampleRate, kbps); let mp3Data = []; let sampleBlockSize = 1152; let mp3buf; for (let i = 0; i < samples.length; i += sampleBlockSize) { let sampleChunk = samples.subarray(i, i + sampleBlockSize); mp3buf = mp3encoder.encodeBuffer(sampleChunk); if (mp3buf.length > 0) { mp3Data.push(mp3buf); } } mp3buf = mp3encoder.flush(); if (mp3buf.length > 0) { mp3Data.push(new Int8Array(mp3buf)); } let audioBlob = new Blob(mp3Data, { type: "audio/mp3" });
注意事项
- 确保MediaRecorder的采样率与lamejs编码时的采样率一致,否则会出现播放速度异常
- 立体声场景下,lamejs的
encodeBuffer需传入左、右声道两个独立的Int16Array,需分别提取对应声道数据 - 转换浮点样本到整数时必须做范围限制,避免溢出导致音频杂音
内容的提问来源于stack exchange,提问作者Leon Segal
相关产品推荐
相关产品推荐

