AudioContext 启动需用户手势触发,跨域资源需 CORS 头,decodeAudioData 前须确保 ArrayBuffer 有效且只调用一次,BufferSource 播放后不可复用,音量调节应使用 setTargetAtTime 避免跳变。

AudioContext 创建失败:跨域或自动播放策略拦住了
现代浏览器默认禁止未交互触发的音频上下文启动,new AudioContext() 可能创建成功但后续调用 resume() 报错 DOMException: The audio context was not allowed to start。
- 必须在用户手势(如
click、touchstart)回调中调用audioContext.resume() - 不能在
DOMContentLoaded或setTimeout里直接 resume - 如果音频资源来自跨域服务器,需确保响应头包含
Access-Control-Allow-Origin: *,否则decodeAudioData()会静默失败
decodeAudioData 后没声音?检查 ArrayBuffer 是否被释放
fetch() + arrayBuffer() 获取音频二进制后,传给 audioContext.decodeAudioData(),常见错误是把 response.arrayBuffer() 直接 await 两次——第二次返回空 ArrayBuffer,导致解码失败且无报错。
- 只调用一次
arrayBuffer(),并缓存结果 - 解码前确认
ArrayBuffer.byteLength > 0 - 解码失败时,
catch中打印err.message,常见提示是Failed to decode audio data,大概率是格式不支持(如 Safari 不支持 MP3 解码)或数据损坏
fetch('sound.mp3')
.then(r => r.arrayBuffer())
.then(buffer => audioContext.decodeAudioData(buffer))
.then(audioBuffer => {
const source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioContext.destination);
source.start(); // 必须在 resume() 之后调用
})
.catch(err => console.error('Decode failed:', err.message));
createBufferSource 播放一次就失效?别重复 use buffer
AudioBufferSourceNode 是一次性节点:调用 start() 后,再次 start() 会抛出 InvalidStateError。不能复用同一个 source 节点反复播放。
- 每次播放都要新建
audioContext.createBufferSource() - 若需循环播放,设置
source.loop = true,但注意手动stop()避免内存泄漏 - 长期运行的音效系统建议封装成工厂函数,避免意外复用已开始的 source
音量忽大忽小?别直接改 gain.value,用 setTargetAtTime
直接赋值 gainNode.gain.value = 0.5 会导致跳变,尤其在实时调节(如拖拽音量条)时明显咔哒声。
立即学习“Java免费学习笔记(深入)”;
- 用
gainNode.gain.setTargetAtTime(target, audioContext.currentTime, timeConstant) -
timeConstant通常取0.01~0.1,越小过渡越快,但太小仍可能有瞬态失真 - 需要精确包络控制(如 ADSR)时,改用
exponentialRampToValueAtTime()或setValueCurveAtTime()
resume() 必须由用户操作触发,这个约束在桌面端测试容易忽略,一到移动端就全崩。










