You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 09:20:12