Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Local variable audio in object method not playing

I'm making a game, and I want sounds to play on events occurring. I have currently got an object that looks like below:

var soundObject = {
    invaderShoot: function() {
        var audio = new Audio("laser.wav");
        audio.play();
    },
    //Many more of the same method
};

And then I'm playing the sounds like this:

soundObject.invaderShoot();

However, when I try to do this, it comes up with the following error:

Unhandled Promise Rejection: NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

And it comes up highlighting this line in the method:

audio.play();

What is the problem? I have searched through GitHub threads and Stack Overflow questions, but I cannot find a definition of what the error is, let alone how to fix it.

How should I fix this?

I am only permitted to use .wav files, because that is the only file format that my code hosting service allows.

like image 485
Jack Bashford Avatar asked Oct 30 '18 06:10

Jack Bashford


2 Answers

Audio.play() returns a Promise which is resolved when playback has been successfully started. Failure to begin playback for any reason, such as permission issues, result in the promise being rejected.

const playedPromise = audio.play();
if (playedPromise) {
        playedPromise.catch((e) => {
            if (e.name === 'NotAllowedError' ||
                e.name === 'NotSupportedError') {
                //console.log(e.name);
            }
        });
    }

In your case, looks like your browser/os does not allow automatic playing of audio. The user agent (browser) or operating system doesn't allow playback of media in the current context or situation. This may happen, for example, if the browser requires the user to explicitly start media playback by clicking a "play" button. Here is the reference.

As far as AutoPlay is concerned, you might need to add AudoContext in your HTML as per new browser policy. https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio

EDIT

window.onload = function() {
  var context = new AudioContext();
  // Setup all nodes
  ...
}
context.resume().then(() => {
    audio.play();
    console.log('Playback resumed successfully');
  });
like image 161
Narendra Avatar answered Nov 15 '22 13:11

Narendra


From the attached bug, it seems that the issue is due to audio/ video auto play being disabled by default. This of course has practical for the user as it reduces the amount of abuse though adds. For your situation however it means that you can't create the audio object on the fly.

Instead you should create it beforehand and simply switch the URL/ resume the audio when you need it. The following snippet from the attached ticket seems promising.

// sm2 attaches the audio element as sound._a
let audio = sound._a;
audio.crossOrigin = 'anonymous';
sound._sourceNode = audioContext.createMediaElementSource(audio);
sound._sourceNode.connect(inputNode);

function play() {
  /**
   * If an AudioContext is created prior to the document receiving a
   * user gesture, it will be created in the "suspended" state, and
   * you will need to call resume() after a user gesture is
   * received.
   */
    audioContext.resume().then(() => {
        sound.play();
    });
}

https://github.com/scottschiller/SoundManager2/issues/178

like image 3
Ish Avatar answered Nov 15 '22 13:11

Ish