javascriptaudioaudiocontextwebkitaudiocontext

Javascript webkitAudioContext has no playback in Safari


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


Solution

  • 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.