I'm having troubles creating an AudioContext with Safari (desktop and mobile). It seems that even with creation upon user interaction, it is still suspended.
My code:
<button onclick="test()">Test</button>
const test = () => {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
audioContext = new AudioContext();
console.log(audioContext.state); // Suspended
}
This should be a minimum working example, right? What's wrong here?
I think Safari is actually behaving correctly (at least partially) in this case. The Web Audio Spec says that ...
A newly-created AudioContext will always begin in the suspended state, and a state change event will be fired whenever the state changes to a different state.
https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
Unfortunately Safari doesn't do the transition to the running
state on its own. You have to explicitly ask it to do so.
audioContext.resume();
audioContext.onstatechange = () => console.log(audioContext.state);
The statechange
event should fire almost immediately. If you execute this inside the click handler.
The function above would then look like this:
const test = () => {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
audioContext = new AudioContext();
console.log(audioContext.state); //suspended
audioContext.resume();
audioContext.onstatechange = () => console.log(audioContext.state); // running
}
Interestingly Safari only fires the statechange
event if you keep the console.log
statement before calling resume()
.
However there is another hack that you can try to kick of the AudioContext
. Just create a simple GainNode
.
const test = () => {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
audioContext = new AudioContext();
audioContext.createGain();
console.log(audioContext.state); // running
}
You can also give standardized-audio-context a try which makes all browsers behave the same in that regard.