# AudioContext baseLatency: a figure every profile shares

> AudioContext baseLatency and outputLatency come from the real output device, so every browser profile on one computer reports the same pair.

Source: https://mosaicbrowser.com/blog/audio-baselatency-headphones

## baseLatency is shared by every profile and moves with your headphones

AudioContext baseLatency and outputLatency come from the real output device, so every browser profile on one computer reports the same pair.

![Two latency figures that belong to the computer](https://mosaicbrowser.com/covers/audio-baselatency-headphones.webp)

`AudioContext.baseLatency` is the processing latency, in seconds, that a Web Audio context adds before its output reaches the operating system's audio subsystem. Chrome works it out from the audio callback's buffer size and the sample rate. Both belong to the computer's audio hardware, not to the browser profile. So every profile on one machine reports the same `baseLatency`, and when the output device changes the figure can change for all of them at once.

Its sibling, `outputLatency`, behaves the same way and has one more twist. We claim both per profile in our engine, in patch `0112`, and getting the second one right took two attempts.

## What baseLatency and outputLatency measure

The Web Audio specification splits the delay between a page scheduling a sound and the sound coming out of a speaker into two parts.

| Property | Covers | In Chrome |
| --- | --- | --- |
| `baseLatency` | the context's own processing, up to the audio subsystem | buffer size divided by sample rate, known when the context is created |
| `outputLatency` | from the audio subsystem to the device playing the first sample | 0 until the audio callback has run, then the hardware's estimate |

The figure is a short division. A callback of 256 frames at 48,000 Hz gives `0.005333333333333333`. Reading it costs a page three lines:

```
const ctx = new AudioContext()
ctx.baseLatency     // a figure straight away
ctx.outputLatency   // 0 until something has played

```

There is no permission prompt and no user gesture involved. The context can stay `suspended` and the read still works.

Mosaic is a desktop app

Email yourself the link and open it on your computer.

[How it works: Machines that exist](https://mosaicbrowser.com/features/real-fingerprints)

## Why the figure tracks the computer, not the profile

Most fingerprint values a profile can claim are about the machine it pretends to be. These two are about the machine it runs on. The buffer size and the sample rate come from the output device and its driver. Any number of profiles opened on one computer read the same pair of floats.

That makes the pair a join key rather than a weak signal. A site that sees two supposedly unrelated visitors with identical audio latencies has one more reason to think they sit at the same desk. And because the figures follow the output device, they change when it does: plug in headphones or switch to a different output and every profile on the machine can move together.

The audio noise our engine adds doesn't help here. Patch `0007` perturbs the samples a page renders and reads back, which is what an [OfflineAudioContext fingerprint](https://mosaicbrowser.com/blog/offlineaudiocontext-explained) hashes. Timing is a different surface. Without its own claim, a page could read a per-profile audio hash beside the computer's honest latency, which is a mismatch of its own.

## How we draw a latency per profile

Each profile gets its pair from its own seed when it launches. The draw picks a buffer of 128, 256 or 512 frames and a sample rate of 44,100 or 48,000 Hz, and sends the quotients as launch switches. The pair doesn't change between launches, and it doesn't change when you plug in headphones.

The first version of that draw printed the figure with `toFixed(6)`. That produced `0.005333`, where branded Chrome on the same machine said `0.005333333333333333`. No division of whole frames by a real sample rate produces a number that stops at six decimals, so the rounded value was one a real browser could never report. It was the one audio value where we disagreed with Chrome in kind rather than in noise. We now send the whole quotient, printed the shortest way that round-trips to the same double, which is how the engine would print it.

## outputLatency has a value and a moment

`outputLatency` caught us a second way. Chrome computes it from a position the audio callback writes. On a context that has not rendered anything, it answers 0. Our patch returned the profile's figure from the first line of the function, before any of that work. Same flags, same page, one launch each:

```
branded Chrome 153, suspended          outputLatency 0
our engine,         suspended          outputLatency 0.010666666666666666
branded Chrome 153, after rendering    outputLatency 0.024

```

A number where every Chrome we measured has a 0 is a positive identification. The patch now lets the real state decide when there is a latency to report, and the switch decides only what it is. On the rebuilt engine a suspended context reads 0, and a context that has rendered reads `0.021333`, the profile's claim rather than the hardware's `0.024`. `baseLatency` needs no such gate, because Chrome knows the buffer size when the context is built and reports a non-zero figure from the first read.

## How to check your own

Open the same page in two browser profiles on one computer and log both properties. Do it once with the context suspended and once after an oscillator has played for a second at a gain nobody can hear. Then switch the output device and repeat. If both profiles print the same figures, and both change when the device changes, the pair is identifying the computer.

It is the same class of fault as a [value pinned across every profile](https://mosaicbrowser.com/blog/notification-permission-denied): nothing leaks in, but one figure is shared by everything on the machine, and a site can read that as well as a leak. The rest of each profile's hardware, from the GPU to the fonts, is drawn from [real devices](https://mosaicbrowser.com/features/real-fingerprints).

## Questions

### What is AudioContext baseLatency?

It is the number of seconds of processing latency the AudioContext adds while passing audio from its destination node to the operating system's audio subsystem. In Chrome it follows from the audio callback's buffer size and the sample rate, so it is known as soon as the context exists.

### What is the difference between baseLatency and outputLatency?

baseLatency covers the browser's own side, up to the audio subsystem. outputLatency estimates the rest, from the audio subsystem to the device playing the first sample. In Chrome, outputLatency reads 0 until the context has actually rendered audio.

### Can a website read baseLatency without permission?

Yes. A page creates an AudioContext and reads the property on the next line. No user gesture is needed, and the context can still be suspended.

### Does audio fingerprint noise change baseLatency?

Not on its own. Audio noise perturbs the samples a page renders and reads back, and the latency figures are timing, not samples. They need their own claim.

## Related

[How the OfflineAudioContext fingerprint is computed](https://mosaicbrowser.com/blog/offlineaudiocontext-explained): An oscillator through a compressor, rendered silently and summed: the OfflineAudioContext fingerprint reads your machine's floating-point audio path.

[An audio spoof that changed the sound every time it was read](https://mosaicbrowser.com/blog/getchanneldata-compounding): getChannelData returns the buffer's own memory, so our audio noise multiplied samples on every read: v·f, then v·f². A seeded byte fixed it.

[344 profiles said "denied": one value, everywhere](https://mosaicbrowser.com/blog/notification-permission-denied): Notification permission became a fingerprint: Notification.permission read denied on all 344 of our profiles, where an unconfigured Chrome says default.

[Machines that exist: fingerprints drawn from real hardware](https://mosaicbrowser.com/features/real-fingerprints): Mosaic draws each profile's GPU, screen, CPU, memory and fonts from one real device, so the parts of a fingerprint agree with each other and with the host.

[Browser fingerprint: what a site can read about your machine](https://mosaicbrowser.com/glossary/browser-fingerprint): A browser fingerprint is the set of values a site reads about your browser and computer, which together recognize you without cookies. What goes into one.







## Mosaic, on your own computer

The browser this blog is about: its own Chromium, fingerprints from real machines and a proxy exit per profile. Free holds 3 profiles. Pro is $49 a month for any number.

Mosaic is a desktop app

Email yourself the link and open it on your computer.
