Web Audio合成器在Chromium正常但Firefox仅播放首音问题排查
检查OfflineAudioContext的启动时机
Firefox对startRendering()的调用时机要求更严格,得确保所有AudioNode的连接、参数设置全在调用这个方法之前完成,别在渲染过程中动态改节点参数或者加新节点。Chromium可能允许启动后还做部分操作,但Firefox是严格按规范来的,只认启动前的配置。排查音符调度的时间精度问题
Firefox对音频时间戳的处理更严谨,要保证每个音符的start()和stop()时间是基于OfflineAudioContext的currentTime或者正确的相对时间,别用绝对时间或者不同步的时间值。比如别拿Date.now()算偏移,改用context.currentTime + delay这种方式调度。检查AudioBufferSourceNode的复用问题
规范里每个AudioBufferSourceNode只能调用一次start(),要是你代码里复用同一个节点播多个音符,Firefox会严格执行这个限制,但Chromium可能允许重复调用(这是非标准行为)。得确保每个音符都新建AudioBufferSourceNode实例,播完可以调用disconnect()释放资源。验证OfflineAudioContext的渲染完成回调逻辑
Firefox里startRendering()返回的Promise完成时,要确认你正确处理了生成的AudioBuffer,而且创建AudioBufferSourceNode播放时,没漏设正确的播放参数(比如loop、playbackRate)。还要检查回调里是不是正确把AudioBufferSourceNode连到了AudioDestinationNode,并且调用了start()。测试最小复现案例
把代码简化,只留生成两个音符的核心逻辑,排除无关代码干扰。比如:const context = new OfflineAudioContext(2, 44100 * 2, 44100); // 第一个音符 const osc1 = context.createOscillator(); osc1.frequency.value = 440; osc1.connect(context.destination); osc1.start(0); osc1.stop(0.5); // 第二个音符 const osc2 = context.createOscillator(); osc2.frequency.value = 523; osc2.connect(context.destination); osc2.start(0.5); osc2.stop(1); context.startRendering().then(buffer => { const playbackCtx = new AudioContext(); const source = playbackCtx.createBufferSource(); source.buffer = buffer; source.connect(playbackCtx.destination); source.start(); });如果这个最小案例在Firefox里能正常播放两个音符,说明问题出在你代码的其他部分,逐步加代码排查就行。
内容的提问来源于stack exchange,提问作者andrew907

