Audio context hell

OK friends; so, I’ve just gone through all of the audio documentation (Audio | Babylon.js Documentation)

All of these examples are in the playground; so, maybe it avoids audio context hell?

I’m now trying to port this very fancy demo (Babylon.js - Web Audio Analyser demo) into VR and hack on it, the problem is I can’t find the full code anywhere, so I had to go into the inspector and start ripping things out, but for the life of me, I cannot figure out how to fire the script from that button that starts the audio engine (and so I’m losing it, lol).

Can you clarify exactly what you mean by “audio context hell”? It’s unclear to me.

“babylon.js:16 The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
e._initializeAudioContext @ babylon.js:16” ← that’s the error message

Somehow, I think I’m supposed to connect the button below to some process that tells engine to start playing the song; and, I have no idea how to do that :<

Yes, I think there’s a cross-browser constraint where you can’t automatically play audio or video on page load - it has to be done on user click or some other event.

That icon I think BJS just overlays to indicate audio engine state. In the past I’ve had to hide it using CSS as I didn’t know any other way.

Word; but how do I get my music to play? I can’t figure out how to get it to play… and I don’t see in the demo where I’m taking this from, how the developer got the music to start when you click that icon?

In the playground, stuff just starts playing automatically Babylon.js Playground

I think Engine.audioEngine.audioContext?.resume();

where in the code would you put this? after you create the music? I don’t see this in his code… (thanks for giving this a shot btw)

well the error message goes away, but I don’t hear anything lol; never mind sorry, it’s there, it’s just there twice now.

you need a user interaction to hear the music, but I don’t know how to code that, and I don’t see where else that is coded

I can’t comment on how the PG works or the demo code, but assume there’s a bunch of setup going on behind the scenes in both cases.

In my own projects I’ve just ensured I call Engine.audioEngine.audioContext?.resume(); on some user event, like clicking a play button.

You might also need to check Engine.audioEngine.setGlobalVolume(1);

And of course play your music with myMusic.play()

I think I need to see a full example of audio working not on the playground.

I just tried to implement the simplest playground example of audio from the documentation and I couldn’t get it to play on glitch.com

So, somewhere somebody has a simple example that starts the audio context. e.g. this doesn’t work for me:

window.addEventListener("keydown", function(evt) {
          // Press space key to fire
          if (evt.keyCode === 32) {
            music.play();
            BABYLON.Engine.audioEngine.audioContext?.resume();
          }
        });
         BABYLON.Engine.audioEngine.setGlobalVolume(1);

I made a codepen. It seems to work OK for me.

Click the sphere to play/pause the music.

Note that this also hides the default BJS unmute icon.

2 Likes

I did an implementation of what you did; fixed a quick in glitch, and now everything works! THANK YOU!

1 Like

take a look at your work: https://www.instagram.com/p/COW9w3JlViq/

audio is a little choppy, I’ll post about that tomorrow

1 Like

This thread was helpful for me and I’ll just add my own react-based solution here:

  // Set up and enable the audio element component
  useEffect(() => {
    //@ts-ignore
    const audioEl: HTMLAudioElement = document.getElementById('musicAudioElement')
    setMusicAudioElement(audioEl)

    const listenForActivity = (): void => {
      console.log('trying to play after user activiy')
      audioEl?.play().catch(waitForUserActivity)
      document.removeEventListener('click', listenForActivity)
      Engine.audioEngine.audioContext?.resume()
      Engine.audioEngine.useCustomUnlockedButton = true
    }

    const waitForUserActivity = (e: any): void => {
      console.error('audioEl.play().catch', e)
      document.addEventListener('click', listenForActivity)
    }

    audioEl.play().catch(waitForUserActivity)
    //@ts-ignore
    audioEl.muted = false
  }, [])