Henrik Hollósi
Henrik Hollósi

Reputation: 223

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?

Upvotes: 7

Views: 23010

Answers (4)

Parag Rudani
Parag Rudani

Reputation: 1

It is Very Straightforward Indeed

const [, setMuted] = useState(true)

useEffect(() => {
  const player = new Audio(./sound.mp3);
  const playPromise = player.play();
  if (playPromise !== undefined) 
      return playPromise.then(() => setMuted(false)).catch(() => setMuted(false));
}, [])

I hope It works now :)

Upvotes: 0

Ben in CA
Ben in CA

Reputation: 851

Simple error tone

If you want something as simple as playing a simple error tone (for non-visual feedback in a barcode scanner environment, for instance), and don't want to install dependencies, etc. - it can be pretty simple. Just link to your audio file:

import ErrorAudio from './error.mp3'

And in the code, reference it, and play it:

var AudioPlay = new Audio (ErrorAudio);
AudioPlay.play();

Only discovered this after messing around with more complicated options.

Upvotes: 1

marsheth
marsheth

Reputation: 960

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" />
     ...
   </>
)

Upvotes: 7

Kirill Novikov
Kirill Novikov

Reputation: 3087

I think it would be better to use this component (https://github.com/justinmc/react-audio-player) instead of a direct dom manipulation

Upvotes: 0

Related Questions