Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play audio with React

Whatever I do, I get an error message while trying to playing a sound:

Uncaught (in promise) DOMException.

After searching on Google I found that it should appear if I autoplayed the audio before any action on the page from the user but it's not the case for me. I even did this:

componentDidMount() {
  let audio = new Audio('sounds/beep.wav');
  audio.load();
  audio.muted = true;
  document.addEventListener('click', () => {
    audio.muted = false;
    audio.play();
  });
}

But the message still appears and the sound doesn't play. What should I do?

like image 332
Henrik Hollósi Avatar asked Jun 14 '19 16:06

Henrik Hollósi


1 Answers

The audio is an HTMLMediaElement, and calling play() returns a Promise, so needs to be handled. Depending on the size of the file, it's usually ready to go, but if it is not loaded (e.g pending promise), it will throw the "AbortError" DOMException.

You can check to see if its loaded first, then catch the error to turn off the message. For example:

componentDidMount() {
      this.audio = new Audio('sounds/beep.wav')
      this.audio.load()
      this.playAudio()
}

playAudio() {
    const audioPromise = this.audio.play()
    if (audioPromise !== undefined) {
      audioPromise
        .then(_ => {
          // autoplay started
        })
        .catch(err => {
          // catch dom exception
          console.info(err)
        })
    }
}

Another pattern that has worked well without showing that error is creating the component as an HTML audio element with the autoPlay attribute and then rendering it as a component where needed. For example:


const Sound = ( { soundFileName, ...rest } ) => (
  <audio autoPlay src={`sounds/${soundFileName}`} {...rest} />
)

const ComponentToAutoPlaySoundIn = () => (
   <>
     ...
     <Sound soundFileName="beep.wav" />
     ...
   </>
)
like image 87
marsheth Avatar answered Oct 22 '22 05:10

marsheth