7

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?

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Henrik Hollósi
  • 223
  • 1
  • 5
  • 16
  • Does the file “sounds/beep.wav” exists on the server? Are you sure that the relative path is correct? – Alexander Elgin Jun 14 '19 at 16:39
  • Does the error message remain if you put the statements from the first three lines to the beginning of the event handler? Does it remain if you remove the event handler putting audio.play() at the end of componentDidMount? – Alexander Elgin Jun 14 '19 at 16:44
  • Possible duplicated from https://stackoverflow.com/questions/40276718/how-to-handle-uncaught-in-promise-domexception-the-play-request-was-interru – Nico Diz Jun 14 '19 at 16:44
  • The file exists on the "server". That is my own computer, I have it inside /src/sounds folder and App.js in /src. I don't know if it's a duplicate. I'm not trying to autoplay, it should play after user clicked. Although I tried that too, I could catch the error but what should I do with that? – Henrik Hollósi Jun 14 '19 at 16:55
  • The error remains with `componentDidMount() { document.addEventListener("click", () => { let audio = new Audio("sounds/beep.wav"); audio.load(); audio.play(); }) }` – Henrik Hollósi Jun 14 '19 at 17:02
  • By the way I'm trying to do this: https://learn.freecodecamp.org/front-end-libraries/front-end-libraries-projects/build-a-pomodoro-clock. I took a look at the solution but I can't seem to make it work according to that either... I tried using refs, no success. – Henrik Hollósi Jun 14 '19 at 17:08

4 Answers4

7

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" />
     ...
   </>
)
marsheth
  • 822
  • 6
  • 9
  • Yes, I already tried it, I could catch the error and console.log said "DOMException." Sometimes I had to click twice to make the console.log appear. If I console.logged in then branch nothing appeared. The audio never started. I tried to render it in another component too. – Henrik Hollósi Jun 14 '19 at 17:36
  • @HenrikHollósi Ok so you have an element (let's call it a button), and when you click it, it should play a local/static sound without showing any error. Is that correct? Or any other functionality? Going to make an update. – marsheth Jun 14 '19 at 17:44
  • Yep, basically that's all. It also has a logic so that the button should start a timer counting to zero and when the timer reaches zero the audio is played. – Henrik Hollósi Jun 14 '19 at 17:47
  • @HenrikHollósi [Codesandbox Sample](https://codesandbox.io/embed/audio-4ucqm?fontsize=14). You probably knew how to do that already, but just wanted to see if I could replicate your errors. I got the same console.log errors at first but looking at them showed they were either "NotAllowed" (meaning browser settings were blocking audio), or "NotSupported" (meaning incompatible file type or an issue with CORS trying to get a file). Try applying to your code and logging out the audio promise to see what kind of error is being thrown and that should help you target a more exact solution. – marsheth Jun 14 '19 at 19:20
  • So, I applied your solution and it has to do something with the link. If I provide my own file, I get "DOMException", "message: The element has no supported sources." logging the promise. If I use a sound from outside source like your link it works just fine. I'm absolutely sure I use a valid url for my own file, I double, triple checked that. Maybe I can't use a downloaded sound from soundbible. – Henrik Hollósi Jun 15 '19 at 04:08
  • @HenrikHollósi That seems like a CORS issue. How about if we import so we're sure it can read it? This was working for me with uploaded file (sorry beep is short and somewhat annoying lol): [Play audio with uploaded file Sandbox](https://codesandbox.io/s/audio-4ucqm?fontsize=14) – marsheth Jun 15 '19 at 17:32
  • Thank you! It's work for me to create another component with an audio file. – Boris Civcic Feb 23 '20 at 08:52
1

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.

Ben in CA
  • 688
  • 8
  • 22
0

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

Kirill Novikov
  • 2,576
  • 4
  • 20
  • 33
  • Still the same. My code looks something like this with that component: `function() { this.refs.audioEl.pause(); this.refs.audioEl.currentTime = 0; this.refs.audioEl.play(); } render(){ return( { this.refs = element; }} autoPlay /> ) }` – Henrik Hollósi Jun 14 '19 at 16:43
  • probably you should use `controls` property like an example (https://github.com/justinmc/react-audio-player/blob/master/example/js/main.jsx) to control music? instead of using a reference? – Kirill Novikov Jun 14 '19 at 16:50
  • Added controls, but it's still the same. The audio player appears in grey. I didn't want to show controls, the audio should play on clicks on other components of the site. – Henrik Hollósi Jun 14 '19 at 16:57
  • what if I have to assign new url how can I ? – K.S May 24 '20 at 12:43
0

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 :)