Signal · signalsVersion 5

audio

A short sound rendered offline through a compressor; the last 500 samples are reported as a digest. Nothing is played.

audio at a glance (from the library code, signalsVersion 5)
Component nameaudio
In the visitorIdyes
structuredId groupaudio
Hashingalways a digest (first 128 bits of SHA-256)
Excluded underBrave (brave_farbling)
Inner timeout1000 ms
Added insignalsVersion 1
In plain words

WhiskerJS asks the browser to compute a short test tone and pass it through a sound compressor, all in memory, without playing anything. The exact numbers that come out depend on how the browser, the operating system and the processor do floating-point maths, so they differ slightly between devices. WhiskerJS keeps only a short code (a digest) of the end of the sound.

What it reads

audio creates an OfflineAudioContext (or the older webkitOfflineAudioContext) with 1 channel, 5000 frames at 44100 Hz. Inside it:

  • an oscillator with type triangle at 10000 Hz;
  • a dynamics compressor with threshold -50, knee 40, ratio 12, attack 0 and release 0.25;
  • oscillator to compressor to the context’s destination.

It starts the oscillator, renders the buffer with startRendering(), takes channel 0 and keeps the last 500 samples as 32-bit floats. Those 2000 bytes are hashed.

How the technique works

An offline audio context computes sound as fast as it can into memory instead of sending it to speakers. The triangle wave is a simple, known input; the compressor applies non-linear gain changes that exercise the audio engine’s maths. Small differences in how engines implement these nodes, and in the CPU’s floating-point behaviour, show up in the last digits of the samples. If all 500 samples are zero, the render produced silence (a sign of blocking), and the component is reported blocked / silent instead of hashing zeros.

Why it helps

The audio stack differs between browser engines (Chromium, Gecko, WebKit), their versions, operating systems and CPU families, while the same setup usually produces exactly the same samples. It is the only member of the audio group of the structuredId, so a change in that part points straight at the audio stack.

Stability

It can change with a browser update that touches the Web Audio implementation, an operating system update, or a change of CPU architecture. WhiskerJS renders it once only: unlike canvas and webgl_image, there is no double render, so a browser or extension that randomises audio reads every time would give a new digest on every run and change the visitorId. Browsers known to do this on purpose are handled through the exclusion table instead.

Browser support and what blocks it

Privacy

The output is a computed test tone, not a recording: no microphone, no playback, no audio device. It reveals how the device computes audio and leaves only as a 32-character digest. No permission, no prompt, no request.

How WhiskerJS handles noise and failures

Status ruleId When
ok none rendered; value is a digest
unavailable no_api no OfflineAudioContext
blocked no_buffer the render gave no buffer
blocked short_buffer fewer than 5000 samples
blocked silent the last 500 samples were all zero
blocked security_error, threw creating or rendering the context threw or rejected
unavailable no_digest no Web Crypto
excluded brave_farbling, caller_excluded exclusion table or your list
timed_out timeout, aborted 1000 ms inner timeout, budget, abort

Example value

From a headless Chromium test browser in a container:

"audio": { "status": "ok", "value": "40febf1c331d3bd4c550bd46ce0e1813", "hashed": true }

Questions and answers

Does the audio signal play a sound or use the microphone?

No. The sound is rendered offline into a buffer in memory. No audio device is opened, nothing is played and the microphone is never touched.

Why is audio excluded in Brave?

Brave adds per-site, per-session noise to audio reads. Reading it would only make the id change, so the exclusion table skips it and reports brave_farbling.

Is audio checked for noise like canvas?

No. audio is rendered once and has no double render. A browser that adds random noise to every audio read would change the digest from run to run, which is why such browsers belong in the exclusion table.