I use an audioContext = new AudioContext()
of the Web Audio API for scheduling beep sounds for every beat (relative to a user-defined bpm and time signature) – let’s call this stack of beeps “track”.
Simultaneously I would like to visualize this track on a canvas which get’s re-rendered each animationFrame:
The task is to synchronize audio and visuals – there are 2 issues with this:
- time → the clock of the audio API is sth different than the time of the JS main thread. This issue is already taken care of using the approach described in this article.
- latency → even though you can schedule a sound very precisely using sth. like
audioContext.createOscillator().start(audioContext.currentTime + 1)
this doesn’t mean that the user hears the sound immediately, since there is some latencies which delay the actual sound output in the user’s audio device.
I was trying a lot of things and reading many articles about this but am still puzzled on how to properly deal with these latencies:
- I know already that when using sourceBuffers I’d have to load them first
- I believe that I should take
audioContext.baseLatency
into consideration(?) → maybe after having created the audioContext I should delay starting both audio and visuals byaudioContext.baseLatency
seconds? audioContext.outputLatency
seems to be the crucial aspect as it seems to tell sth about the time between a) the scheduled start time and b) the audio device starting to process the received buffer?
But: Even though on my machine the outputLatency is ~0.04s the actual sound delay seems much higher – more like tripled.*
I read here that there are some catches with outputLatency, from drivers just lying about its value to all sorts of uncertainties..
I would like to know if there is a solid way of either retrieving the actual time descrepancy between a)** scheduled start time and b) the time the user will hear the beep, or if there is a different approach I could take in order to synchronize audio and visuals.
*) Tested in 3 ways:
- simply by hearing and watching
- recording the screen, then playing it back in slomo to see where the red line is when hearing a beep
- By listening to the “ended” event of the oscillator and checking
audioContext.currentTime
against the expected/calculated end time of the scheduled beep
I don’t know if this is a good approach for testing latency(?)
**) Maybe there is a way to detect when sound is played from the user’s audio device? Then match that time against the expected start time?
Thanks a lot in advance for any hints into the right direction!