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

如何使用js-mp3解码MP3并在AudioContext中播放以解决Safari15解码问题

问题核心原因

你代码里有个非常隐蔽的低级错误:拼接右声道数据时,concatTypedArrays的第一个参数错误传成了已经累积了左声道采样的left数组,导致右声道数据混入了全部左声道的内容,最终左右声道数据错乱引发失真。
另外你当前的实现逻辑存在冗余:调用decoder.decode()之后已经拿到了完整的PCM数据,不需要再重置指针循环读帧,直接从返回的pcmArrayBuffer里拆分左右声道即可,效率更高也能避免逐帧拼接的性能问题。


修正后实现代码

// responseData 是MP3文件的ArrayBuffer
const decoder = Mp3.newDecoder(responseData);
// 直接获取完整的PCM数据
const pcmBuffer = decoder.decode();
const channels = decoder.numberOfChannels ?? 2;
const sampleRate = decoder.sampleRate;
// 按32位浮点数格式读取PCM
const pcmData = new Float32Array(pcmBuffer);
const frameCount = pcmData.length / channels;

// 初始化AudioBuffer
const audioContext = new AudioContext();
const audioBuffer = audioContext.createBuffer(channels, frameCount, sampleRate);

// 拆分交错存储的PCM:js-mp3返回的PCM是左、右、左、右...交错排列的
for (let i = 0; i < frameCount; i++) {
  for (let ch = 0; ch < channels; ch++) {
    audioBuffer.getChannelData(ch)[i] = pcmData[i * channels + ch];
  }
}

// 播放逻辑
const source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioContext.destination);
source.start(0);

如果你非要保留原来的循环读帧写法,仅需要修改右声道拼接的一行代码即可:
把right = concatTypedArrays(left, decoder.frame.v_vec[1])修改为right = concatTypedArrays(right, decoder.frame.v_vec[1])就能解决失真问题,但该方案逐帧拼接的性能较差,处理长音频时容易出现卡顿,更推荐上方直接解析完整PCM的方案。

内容的提问来源于stack exchange,提问作者Einar Egilsson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 13:36:05