Open patternleaf opened 1 year ago
As far as I can tell the autoplay policy gets lifted in any browser as soon as you resume any AudioContext
. Once this has been done for one AudioContext
every other AudioContext
seems to resume, too. I made a little demo to verify this:
https://stackblitz.com/edit/js-vvbsjc?file=index.js,index.html
Anyway, it feels not okay to create an AudioContext
only to resume it. What do you think about a new exported function that could be used to set the AudioContext
? I think you already proposed above. Is that what you had in mind, too?
import { setContext, setTimeout } from 'audio-context-timers';
const audioContext = new AudioContext();
setContext(audioContext);
document.onclick = () => {
audioContext.resume();
setTimeout(() => console.log('yeah'), 1000);
}
@chrisguttandin Thanks. Yes a setContext
would help our use case. Maybe consider also adding a getContext
?
More info about what we were trying to do:
createTimer
and clearTimer
.createTimer
needed to be called before any user gesture.To service createTimer
calls before an audio context was running
we had to return vanilla browser timers. The trouble was that createTimer
didn't have a clean way to know when it could start using ACT timers.
// timers.ts
import { setTimeout as actSetTimeout } from 'audio-context-timers';
export const createTimer = (callback: Function, delay): TimerId => {
if (canUseActTimers) { // <----- how to know this?
return actSetTimeout(callback, delay);
}
return window.setTimeout(callback, delay);
};
To answer this question we made a local AudioContext just for the purpose of attempting to resume()
it and check its state. As you say: not great.
A setContext
exported from audio-context-timers
would let us pass our own AudioContext, which is cool, and we could query that same one. Two downsides I'm thinking of:
setContext
we might have to do some extra work. For example, let's say our AudioContext isn't initialized immediately on load. Would we need to track whether we've called setContext
? Would audio-context-timers
have already created its own default AudioContext if we don't call it right away?Alternatively, if a getContext
was provided we could just query that directly:
import { setTimeout as actSetTimeout, getContext as actGetContext } from 'audio-context-timers';
export const createTimer = (callback: Function, delay): TimerId => {
if (actGetContext().state === 'running') {
return actSetTimeout(callback, delay);
}
return window.setTimeout(callback, delay);
};
Or if we definitely wanted to use our own AudioContext for timers to avoid browser limits, etc, we could use both getContext
and setContext
, something like:
import {
setTimeout as actSetTimeout,
setContext as actSetContext,
getContext as actGetContext
} from 'audio-context-timers';
import { getGlobalAudioContext } from '../local-audio-service';
export const createTimer = (callback: Function, delay): TimerId => {
let timerContext = actGetContext();
const globalContext = getGlobalAudioContext();
if (!timerContext && globalContext) {
actSetContext(globalContext);
timerContext = globalContext;
}
if (timerContext && context.state === 'running') {
return actSetTimeout(callback, delay);
}
return window.setTimeout(callback, delay);
};
So anyway I guess I'd advocate for both a setContext
and getContext
. But either one would help clean up this use case. Thanks for the library, it's super helpful!
Thanks for telling me more about your use case. It got me thinking. Would it be an option for you to use worker-timers instead?
Per autoplay policy, an AudioContext won't be allowed to run until a user gesture of some sort happens. Calls to
audio-context-timers.setTimeout
made before this happens won't function as expected.One solution: expose the audio context used to provide the timer service. Clients can then observe that context to see when it should be safe to use its timers.
Another solution might be to allow clients to provide the AudioContext. This would also allow clients to better manage the number of AudioContexts running around and avoid possibly bumping up against browser limits.