Keeping audio and visuals in sync with the Web Audio API
Audio and visuals out of sync when using the Web Audio API? There’s a property for that.
There was an issue with the animated piano keyboard I built for my website JazzKeys.fyi in that the audio and visuals were out of sync when listening on Bluetooth headphones. I had assumed that latency would be taken care of automatically by the OS — there are no such issues when viewing an embedded HTML <video>
, for example — but it seems that the Web Audio API does not handle this by default.
It turns out, however, that the Web Audio API’s AudioContext
interface has a new property that returns an estimate in seconds of the output latency. The property, outputLatency
, is currently supported in newer versions of Firefox and Chrome1, and allows us to delay starting the visuals and have them be in sync with the audio.
Testing it out permalink
You can test it by running the code below in the browser console.
First check the latency while your audio output is set to the built-in speakers or a pair of wired headphones:
var audioCtx = new AudioContext()
audioCtx.outputLatency
I get 0 (zero) when I just checked in Firefox on macOS.2
Now set the audio output to a pair of Bluetooth headphones and check the latency again:
audioCtx.outputLatency
I get 0.17780041666666666 seconds.
If I then switch back to the built-in speaker it‘s 0.02485258333333333 seconds. I can’t explain that; feel free to leave a comment if you know the reason.
You can alternatively test it on an updated version of the animated keyboard (below). Output latency will be shown beneath the controls when you press Play.
Safari and older browsers permalink
Because browser support is incomplete, when using outputLatency
we should first check that the property exists:3
const hasOutputLatency = window.AudioContext && 'outputLatency' in window.AudioContext.prototype ? true : false;
if (hasOutputLatency) {
console.log('AudioContext.outputLatency is available');
}
Regarding Safari, I see there is a fixme in the WebKit code, so hopefully the feature will be available soon on iPhones and iPads.
Further reading permalink
There is some great technical background in this post by a Paul Adenot, an engineer at Mozilla who added outputLatency
(along with baseLatency
and getOutputTimestamp
) to Firefox.
This does not include Firefox and Chrome on iOS and iPadOS: they use WebKit under the hood. ↩︎
When
outputLatency
is queried in the Codesandbox of my animated keyboard, the (non-Bluetooth headphones) value returned is 0.0154195s in Firefox and 0.024s in Chrome, so it looks like it depends on browser and maybe what else is running in the program context (the Codesandbox has a whole bunch of other JavaScript running). It can also vary by OS and device ↩︎If you want to ignore Internet Explorer, you can remove the check for
window.AudioContext
↩︎