0

I'm trying to setup audio playback which I cannot get working on Safari 14.0.3, but works fine in Chrome 88.0.4324.146. I have a function that returns a AudioContext or webkitAudioContext. I followed this answer: https://stackoverflow.com/a/29373891/586006

var sounds;
var audioContext

window.onload = function() {
    audioContext = returnAudioContext()
    sounds = {
        drop : new Audio('sounds/drop.mp3'),
        slide : new Audio('sounds/slide.mp3'),
        win : new Audio('sounds/win.mp3'),
        lose : new Audio('sounds/lose.mp3'),
    }
    
    playSound(sounds.drop)

}
    
function returnAudioContext(){
    var AudioContext = window.AudioContext // Default
        || window.webkitAudioContext // Safari and old versions of Chrome
        || false; 

    if (AudioContext) {
        return new AudioContext;
    }
}

function playSound(sound){
    audioContext.resume().then(() => {
        console.log("playing sound")
        sound.play();
    });
}

Live example: http://www.mysterysystem.com/stuff/test.html

Chewie The Chorkie
  • 4,896
  • 9
  • 46
  • 90
  • You forgot to invoke a new instance at `return new AudioContext;` That should be `return new AudioContext();` – Emiel Zuurbier Feb 09 '21 at 20:16
  • That change still does not work on Safari. – Chewie The Chorkie Feb 09 '21 at 20:21
  • Can you make an example which we can run in Safari as well? That might give us some more insights in what the problem might be. – Emiel Zuurbier Feb 09 '21 at 20:29
  • Surely. Edited post with live example. Note this example does not have `return new AudioContext();`, but I've also tried it with that and it still does not work. – Chewie The Chorkie Feb 09 '21 at 20:38
  • Nice thanks, that helps. Could you explain what `audioContext.resume()` does and why it is there. Also note that you're combining the `HTMLAudioElement` (`new Audio()`) with the Web Audio API, which are separate things, though they can work together. – Emiel Zuurbier Feb 09 '21 at 20:43
  • I have not found an explanation for it really, just a work around that is found on this answer: https://stackoverflow.com/a/53058870/586006 Removing that and just keeping sound.play() makes no difference on Safari. – Chewie The Chorkie Feb 09 '21 at 20:51
  • The comments under that post also indicate that it doesn't work in Safari. That is due to `audioContext.resume()`. Are you trying to play audio without user interaction? If so, that would require using a hack (if there is one) that is supported in Safari. If not, then just call `sound.play();` without the audio context, because that `sounds` is an `HTMLAudioElement` (or ` – Emiel Zuurbier Feb 09 '21 at 20:59
  • Please provide an answer. I've commented out `audioContext.resume().then(() => {` and left sound.play(), and it is giving me the unhandled promise rejection notice. In another version that is integrated into a web app, I'm interacting with the page. Still, all future sound events give this error. Creating a sound element sounds pointless, and I should be able to use an audio context in `webkitAudioContext` in Safari. – Chewie The Chorkie Feb 09 '21 at 21:14

1 Answers1

1

I've done my very best to make an example that uses solely the Web Audio API, but alas, Safari is not very compatible with this API. Though it is possible to use it in conjuction with the HTMLAudioElement, but unless you want to manipulate the audio; you won't need it.

The example below will play the drop sounds whenever you click anywhere in the document. It might need 2 clicks as audio in the browser can be very strict on when to play or not.

The playSound function checks if the play() method returns a promise. If it does then that promise should have a .catch() block. Otherwise it will throw the Unhandled Promise Rejection error in Safari.

const sounds = {
  drop: new Audio('sounds/drop.mp3'),
  slide: new Audio('sounds/slide.mp3'),
  win: new Audio('sounds/win.mp3'),
  lose: new Audio('sounds/lose.mp3'),
};

function playSound(audio) {
  let promise = audio.play();
  if (promise !== undefined) {
    promise.catch(error => {
    console.log(error);
    });
  }
}

document.addEventListener('click', () => {
  playSound(sounds.drop);
});

If you do need to use the Web Audio API to do some stuff, please let me know.

Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32