1

So I have a button which calls function playAudio that fetches an MP3 and plays it, that looks like this:

playAudio(e) {
    try{
      fetch(ip_address, {
          method: 'POST',
          //headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(
            {"text":message}
          ),
        }).then(response => {
          var reader = response.body.getReader();
          reader.read().then( async (response) => {
            // response.value for fetch streams is a Uint8Array
            var blob = new Blob([response.value], { type: 'audio/mp3' });
            var url = window.URL.createObjectURL(blob)
            window.audio = new Audio(); 
            window.audio.src = url;
            window.audio.play();
          })
        })
      }  catch(err) {
        console.log("Caught Error in sendHandler(): "+ err.message);
      }
  } 

And this code works fine in Chrome and Firefox, but on Safari it doesn't play the audio. From my googling I figured out that it has to do with the autoplay policies, that the sound has to start from a user interaction. I'm guessing because I am fetching the audio file onClick and then trying to play it this happens asynchronously and so this protection gets triggered. But is there a way to avoid it without either a) pre-fetching all of the sounds (which I tried, it works but there might be a lot of files so I'd rather not do that), or b) having the person do 2 clicks one to fetch the audio and one to actually play it.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
  • 2
    By the time your request is done, your user-gesture is long dead. You need to call `MediaElement.play()` from the event itself, not asynchronously. The good news is that the browser will remember this, so you can call it a first time even if no sources is defined, and you'll still be allowed to control it when your request is done. – Kaiido Dec 16 '19 at 05:38

0 Answers0