Web Audio API error related

I’m using BabylonJS 8.41.1 with AudioEngineV2 and a custom audio wrapper (global AudioManager + many SoundPlayer instances).

I’m not calling setValueCurveAtTime directly anywhere in my code.

From time to time I see this error in the browser console, which is already being suppressed by Babylon’s AudioInitializer:

Uncaught NotSupportedError: Failed to execute 'setValueCurveAtTime' on 'AudioParam': setValueCurveAtTime(..., 1267.800816326531, 0.01) overlaps setValueCurveAtTime(..., 1267.800816326531, 0.01)

As I understand it, this means that two setValueCurveAtTime calls for the same AudioParam overlap in time (same startTime and duration), and the browser throws NotSupportedError.

In my game I have:

  • many long looping environment sounds,
  • frequent updates of audio listener orientation (camera moves/rotates a lot),
  • and some volume fades on top of that.

Questions:

  1. Is this error expected in Babylon 8.41.1 when multiple internal curves overlap (for example for listener orientation or other spatial parameters)?

  2. Is there a recommended pattern to avoid these overlaps – e.g. cancelling previous automation, limiting update frequency, or some API I should prefer/avoid when doing fades and frequent audio updates? @docEdub

This type of error in Firefox (and the same in Chrome, but rarely):

Uncaught DOMException: AudioParam.setValueCurveAtTime: Can't add events during a curve event
    setTargetValue https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1049
    set https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1049
    _updatePosition https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20873
    _updatePosition https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:16143
    set https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:16143
    setPosition https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22973
    _onRegisterAfterWorldMatrixUpdate https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22973
    _registerFunc https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22973
    notifyObservers https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:17931
    computeWorldMatrix https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1770
    getWorldMatrix https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20873
    computeWorldMatrix https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1770
    isReady https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22966
    isReady https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:19493
    start https://game.1kit.net/assets/index-ZH9WTQJI.js:184
    _renderFrame https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20199
    _processFrame https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20199
    _renderLoop https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:18149
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20197
babylon-core-D2M0Dc4X.js:1049:2685
    setTargetValue https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1049
    set https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1049
    _updatePosition https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20873
    _updatePosition https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:16143
    set https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:16143
    setPosition https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22973
    _onRegisterAfterWorldMatrixUpdate https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22973
    _registerFunc https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22973
    notifyObservers https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:17931
    computeWorldMatrix https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1770
    getWorldMatrix https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20873
    computeWorldMatrix https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:1770
    isReady https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:22966
    isReady https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:19493
    start https://game.1kit.net/assets/index-ZH9WTQJI.js:184
    _renderFrame https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20199
    _processFrame https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20199
    _renderLoop https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:18149
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-D2M0Dc4X.js:20197

Unfortunatelly I didn’t create PlayGround yet.
I still debug my code and trying to reproduce. Maybe you know where to look next? I can’t even pinpoint exactly when this started, somewhere around version 8.40.0 or later.

Thanks. This indicates an issue in the Babylon.js audio code. I’ll investigate. What browser are you seeing this on?

Hello, Andy.

Firefox is the easiest way to reproduce:

Chrome also shown the error, but without freeze:

You can try my staging test pre-beta version :grin:

Open console in dev tools (F12).

When I open details.
setValueCurveAtTime underlined with red line.

This is my pet project, so there is no great urgency, but in our free time I think we will figure out what is breaking in the audio.

1 Like

I’m not able to reproduce the setValueCurveAtTime issue, yet, but I am seeing this error in your demo:

Did you make changes to avoid the setValueCurveAtTime issue?

Uncaught NotSupportedError: Failed to execute 'setValueCurveAtTime' on 'AudioParam': setValueCurveAtTime(..., 75.13066666666667, 0.01) overlaps setValueCurveAtTime(..., 75.13066666666667, 0.01)
    at e3.setTargetValue (chunk-MEGOPWB7.js?v=52b2ca40:4469:186)
    at e3.set (chunk-MEGOPWB7.js?v=52b2ca40:4459:18)
    at t3._updatePosition (chunk-MEGOPWB7.js?v=52b2ca40:30955:97)
    at t3._updatePosition (chunk-MEGOPWB7.js?v=52b2ca40:22107:180)
    at t3.set (chunk-MEGOPWB7.js?v=52b2ca40:22084:39)
    at e2.setPosition (chunk-MEGOPWB7.js?v=52b2ca40:38293:343)
    at e2._onRegisterAfterWorldMatrixUpdate (chunk-MEGOPWB7.js?v=52b2ca40:38347:18)
    at e3._registerFunc [as callback] (chunk-MEGOPWB7.js?v=52b2ca40:38340:23)
    at e3.notifyObservers (chunk-MEGOPWB7.js?v=52b2ca40:23216:214)
    at t3.computeWorldMatrix (chunk-MEGOPWB7.js?v=52b2ca40:4908:538)

I got it outside of my code inside of BabylonJS, however probably I’ve sent wrong values to Audio Engine.
This digits seems weird: setValueCurveAtTime(..., 75.13066666666667, 0.01) overlaps setValueCurveAtTime(..., 75.13066666666667, 0.01)

Interesting addition, in Firefox browser I see this error even when character on the way to the ground and even can’t land because of freeze whole engine.

Uncaught DOMException: AudioParam.setValueCurveAtTime: Can't add events during a curve event
    setTargetValue https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:1044
    set https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:1044
    _updatePosition https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20864
    _updatePosition https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:16141
    set https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:16141
    setPosition https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:22964
    _onRegisterAfterWorldMatrixUpdate https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:22964
    _registerFunc https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:22964
    notifyObservers https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:17929
    computeWorldMatrix https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:1765
    getWorldMatrix https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20864
    computeWorldMatrix https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:1765
    isReady https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:22957
    isReady https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:19484
    start https://game.1kit.net/assets/index-B63btvL3.js:184
    _renderFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _processFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    v https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-DwAE_9Zq.js:20190
babylon-core-DwAE_9Zq.js:1044:2685

however in the Chrome it rarely appears.

I am still in deep debug. :grin:

Firefox fixed this recently so make sure you’re using the latest version. You shouldn’t be seeing this in Chrome at all, though, so I’m looking into it, too.

Oh, I see! The Chrome error is not the same. It says “Provided float value is non-finite”. That makes more sense.

I suspect you’re using an old version of Firefox when you’re getting the setValueCurveAtTime error, which is not surprising. Update Firefox and that error should go away.

I’ll take a look at the Chrome “non-finite value” error, now.

I’m using what seems to be the latest version of Firefox,


and it’s the only browser that’s the most finicky and the slowest when it comes to WebGL. I already see supporting Firefox as a personal challenge rather than just a bug. I don’t see this issue in Chrome, and even if it occasionally pops up somewhere, unlike Firefox, Chrome doesn’t freeze the entire process or hang—it just keeps going.

I was able to avoid this error in Firefox when I removed the call to this.sound.attachToMesh(mesh) on the Sound object that I import from import { Sound } from 'babylonjs'. The error occurs exactly at the moment when the position of the spatial sound is set, apparently when the value has a very large fractional part, which Chrome seems to tolerate better than Firefox. And even if I stop using attachToMesh, which works poorly in Firefox, and switch to sound.setPosition(), I still end up hitting the error later, already at sound.setPlaybackRate(rate).

And setPlaybackRate managed to trigger the setValueCurveAtTime error in Firefox only once. So by abandoning attachToMesh in favor of a plain setPosition, I’ve mostly defeated this error. Now I just want some kind of conclusion.

Can we consider this a victory over the bug by using setPosition instead of attachToMesh in Firefox, or should we continue digging into why attachToMesh causes the setValueCurveAtTime error in Firefox?

So I use now my wrapper for Sound with:

Piece of code :grin:

attachToMesh(mesh: TransformNode): void {
    try {
      if (!this.sound || !mesh) {
        return
      }

      this.sound.spatialSound = true

      // TODO: Remove this once we have a proper solution for Firefox
      // this.sound.attachToMesh(mesh) is not working in Firefox
      this.setPosition(mesh.position)

      // Automatically apply optimal parameters for spatial sound
      this.configureSpatialSound()
    } catch (error) {
      // Silently handle audio attachment errors during disposal
      if ((import.meta as any).env.VITE_DEBUG === '1') {
        console.warn('[SoundAdapter] Error attaching sound to mesh:', error)
      }
    }
  }

Just as I started writing this post and reported that I had beaten the bug by replacing attachToMesh with setPosition, I immediately ran into the ominous setValueCurveAtTime again—this time caused by setPlaybackRate().

Error message:

Uncaught DOMException: AudioParam.setValueCurveAtTime: Can't add events during a curve event
    setTargetValue https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:1044
    set https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:22506
    set https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:19725
    setPlaybackRate https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:22964
    setPlaybackRate https://game.1kit.net/assets/index-BQJ0Ioko.js:183
    update https://game.1kit.net/assets/index-BQJ0Ioko.js:183
    applyByAnimationName https://game.1kit.net/assets/index-BQJ0Ioko.js:183
    applyMovementByAnimationType https://game.1kit.net/assets/index-BQJ0Ioko.js:183
    forwardLeft https://game.1kit.net/assets/index-BQJ0Ioko.js:183
    forwardLeft https://game.1kit.net/assets/index-BQJ0Ioko.js:183
    action https://game.1kit.net/assets/index-BQJ0Ioko.js:184
    handleRules https://game.1kit.net/assets/index-BQJ0Ioko.js:184
    handle https://game.1kit.net/assets/index-BQJ0Ioko.js:184
    update https://game.1kit.net/assets/index-BQJ0Ioko.js:184
    start https://game.1kit.net/assets/index-BQJ0Ioko.js:184
    notifyObservers https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:17929
    render https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:19484
    start https://game.1kit.net/assets/index-BQJ0Ioko.js:184
    _renderFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _processFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
    _renderLoop https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:18147
    _boundRenderFunction https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    v https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20188
    _queueNewFrame https://game.1kit.net/assets/babylon-core-CqzBUFF8.js:20190
babylon-core-CqzBUFF

At least the search for the problem has narrowed down to specific methods of the Sound class: attachToMesh and setPlaybackRate :slightly_smiling_face:

Oh my God, how fast history changes. Just a couple of minutes ago Firefox released an update (146.0.1), and although the bug is still there, it looks different now.

Ok, I’ll keep trying to repro the issue on Firefox.

The non-finite number issue should be fixed by this PR when it goes in:

2 Likes

Ah, good! This I can fix :slight_smile:

Oh, wait, no this is the old error message we used to get on Firefox. Weird. I wonder if they reverted their fix.

I’m trying to reproduce this on Firefox in many different ways, but no matter what I do it always gets fixed by calling cancelScheduledValues(0), which is what we already do right before calling setValueCurveAtTime.

I suspect there’s a timing-related bug in Firefox that only shows up when lots of calls occur in close succession. I’m going to add a try/catch around our usage of setValueCurveAtTime with a fallback so the value gets set immediately if using a curve fails.

1 Like

BTW: Right now I’ve got this error in Chrome browser.
It is hard to debug, because it unstable and can appears rarely.


Probably error when AudioParam is not changed, it trying to overlaps same value.

BTW: For temporarily awhile I’ve created dirty-hack to patch Firefox error in my app.

In the begin of scene I import patch:

// TODO: Remove this import when BabylonJS fixes the Firefox audio issue
import { applyFirefoxAudioPatch } from '@game/audio/utils/FirefoxAudioPatch'

Launch it inside of constructor:

constructor() {
    // Apply Firefox audio patch before any audio initialization
    // TODO: Remove this call when BabylonJS fixes the Firefox audio issue
    applyFirefoxAudioPatch()
  }

And patch code FirefoxAudioPatch.ts:

/**
 * Firefox AudioParam.setValueCurveAtTime Error Patch
 * 
 * This patch suppresses a known Firefox bug in BabylonJS audio system:
 * "Uncaught DOMException: AudioParam.setValueCurveAtTime: Can't add events during a curve event"
 * 
 * This is a temporary workaround until BabylonJS fixes the issue.
 * 
 * TO REMOVE THIS PATCH:
 * 1. Delete this file
 * 2. Remove the import and applyFirefoxAudioPatch() call from Arena.ts
 * 3. Test in Firefox to verify the vendor has fixed the issue
 */

/**
 * Applies a patch to suppress Firefox-specific AudioParam errors
 * This patches the AudioParam.setValueCurveAtTime method to catch and silently handle
 * the "Can't add events during a curve event" error that occurs in Firefox.
 */
export function applyFirefoxAudioPatch(): void {
  // Check if we're in a browser environment
  if (typeof window === 'undefined') {
    return
  }

  // Check if AudioParam is available (should be available in all browsers with Web Audio API)
  if (typeof AudioParam === 'undefined' || !AudioParam.prototype) {
    return
  }

  // Check if setValueCurveAtTime method exists
  if (typeof AudioParam.prototype.setValueCurveAtTime !== 'function') {
    return
  }

  // Store original method reference if not already patched
  if ((AudioParam.prototype.setValueCurveAtTime as any).__originalSetValueCurveAtTime) {
    // Already patched, skip
    return
  }

  const originalSetValueCurveAtTime = AudioParam.prototype.setValueCurveAtTime

  // Mark as patched
  ;(AudioParam.prototype.setValueCurveAtTime as any).__originalSetValueCurveAtTime = originalSetValueCurveAtTime

  // Patch AudioParam.prototype.setValueCurveAtTime
  AudioParam.prototype.setValueCurveAtTime = function (
    values: Float32Array | number[],
    startTime: number,
    duration: number
  ): AudioParam {
    try {
      return originalSetValueCurveAtTime.call(this, values, startTime, duration)
    } catch (error: unknown) {
      // Only suppress the specific Firefox error
      if (
        error instanceof DOMException &&
        error.message.includes("Can't add events during a curve event")
      ) {
        // Silently ignore this Firefox-specific error
        // This is a known issue in Firefox's Web Audio API implementation
        // The error occurs when BabylonJS tries to update audio parameters
        // while a curve animation is already in progress
        return this
      }
      // Re-throw any other errors
      throw error
    }
  }

  // Log patch application in debug mode
  console.log('[FirefoxAudioPatch] Applied Firefox AudioParam.setValueCurveAtTime error suppression')
  
}

/**
 * Removes the Firefox audio patch (for testing or when vendor fixes the issue)
 */
export function removeFirefoxAudioPatch(): void {
  // This would require storing the original method, which we don't do
  // to keep the patch simple. If you need to remove it, reload the page.
  console.warn('[FirefoxAudioPatch] Patch removal requires page reload')
}

@docEdub will be back shortly to help with this issue :slight_smile:

1 Like