Search code examples
javascriptioshtml5-audio

Is there a way to get OscillatorNode to produce a sound on an iOS device?


I'm working on a music web app that has a piano keyboard. When a user presses a piano key, I'm using OscillatorNode to play a brief tone corresponding to the key:

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

function playNote(note) {
    let oscillator;
    let freq = notes[note];
    console.debug(note + " (" + freq + " Hz)");
    oscillator = audioCtx.createOscillator(); // create Oscillator node
    oscillator.type = wavetypeEl.val(); // triangle wave by default
    oscillator.frequency.setValueAtTime(freq, audioCtx.currentTime); // freq = value in hertz
    oscillator.connect(audioCtx.destination);
    oscillator.start();
    oscillator.stop(audioCtx.currentTime + 0.5);
}

$('#keyboard button').on('click', (e) => {
        playNote(e.target.dataset.note);
});

This works on all the desktop and Android browsers I've tried, but iOS stubbornly refuses to play any sound. I see that I need a user interaction to "unlock" an AudioContext on iOS, but I would have thought calling playNote() from my click function would have done the trick.

According to Apple, I should be able to use noteOn() on my oscillator object, instead of oscillator.start() the way I've got it in my example. But that doesn't seem to be a valid method.

I must be missing something simple here. Anybody know?


Solution

  • If everything seems to be working fine it could be that the device itself is on mute. For some reason (or for no reason at all) Safari doesn't play any sound coming from the Web Audio API when the device is muted. But it plays everything else.

    There are some hacky ways to circumvent this bug which basically work by playing something with an audio element first before using the Web Audio API.

    unmute-ios-audio is for example a library which implements the hack mentioned above.