Skip to content

API Reference — @hi-audio/latency-test

Draft. This document describes the planned API for the <latency-test> web component. The component is not yet published.


Element

html
<latency-test></latency-test>

Register the element by importing the package:

js
import '@hi-audio/latency-test'

Attributes

Attributes are reflected as properties and can be set either in HTML or via JavaScript.

AttributePropertyTypeDefaultDescription
number-of-testsnumberOfTestsnumber1How many consecutive measurements to run. When > 1, a latency-complete event is fired after the last run with aggregate statistics.
recording-moderecordingModestring"mediarecorder"Capture backend. v1 default: "mediarecorder" — uses MediaRecorder + Blob decode (implemented). v2 default: "audioworklet" — raw Float32 PCM directly from the audio graph (planned). Both values are accepted in both versions. See ScriptProcessor note below.
signal-typesignalTypestring"mls"Test signal used for the round-trip measurement. See signal types table below.
input-gaininputGainnumber0Gain multiplier applied to the input stream before capture. 0 means no gain applied. Use 50 to replicate the automatic Safari microphone compensation if needed.
mls-bitsmlsBitsnumber15Order of the MLS sequence. Sequence length = 2^n − 1. Valid range: 2–16. Only applies when signal-type="mls".
max-lag-msmaxLagMsnumber600Cross-correlation search window in milliseconds. Determines the maximum measurable round-trip latency.

Example

html
<latency-test
  number-of-tests="5"
  recording-mode="mediarecorder"
  signal-type="mls"
  mls-bits="15"
  max-lag-ms="600"
  input-gain="0">
</latency-test>

Signal types

ValueDescriptionStatus
"mls"Maximum Length Sequence — binary pseudorandom signal generated by a Linear Feedback Shift Register. Optimal for cross-correlation. Default.Available
"chirp"Logarithmic sine sweep — sweeps across a frequency range over a fixed duration. Cross-correlated with a matched filter (time-reversed chirp) to estimate the impulse response.Planned
"golay"Golay complementary sequence pair — two sequences (A and B) whose autocorrelations sum to a perfect impulse. Requires two measurement passes. Best SNR in reverberant or noisy environments.Planned

ScriptProcessor (older browsers)

ScriptProcessor is deprecated and removed from the Web Audio spec, but is documented here as a reference for very old browser environments. It is not exposed as a recording-mode value. Implementations should detect support and fall back to "mediarecorder" in environments where AudioWorklet is unavailable.

Reference: superpoweredSDK/WebBrowserAudioLatencyMeasurement


Properties (JS only)

These are set via JavaScript, not HTML attributes.

PropertyTypeDescription
audioContextAudioContextOptional. Pass an existing AudioContext from the host. If not set, the component creates one lazily on the first start() call and exposes it via this getter so the host can reuse it. The component never calls .close() — the host always owns cleanup.
inputStreamMediaStreamOptional. Pass an existing mic stream. If not set, the component calls getUserMedia lazily on the first start() call and stops the tracks when the test ends. When host-provided, the component never stops the tracks.

Example

js
const element = document.querySelector('latency-test')
element.audioContext = existingAudioContext

Methods

start()

Begins a latency measurement. If number-of-tests > 1, runs that many consecutive measurements automatically.

Requests microphone access (getUserMedia) on the first call if a stream has not already been acquired.

js
element.start()

stop()

Aborts an in-progress measurement. The component returns to its idle state. No latency-result or latency-complete events are fired for the aborted run.

js
element.stop()

Events

All events bubble and are composed (they cross shadow DOM boundaries).

latency-result

Fired once per completed test run with the measurement result.

js
element.addEventListener('latency-result', (e) => {
  const { latency, ratio, timestamp } = e.detail
  // latency   — round-trip latency in milliseconds (number)
  // ratio     — correlation reliability in dB (number); values > 18 dB are considered reliable
  // timestamp — Unix timestamp of the measurement (number)
})

latency-complete

Fired after all runs finish when number-of-tests > 1. Contains aggregate statistics over the full set.

js
element.addEventListener('latency-complete', (e) => {
  const { results, mean, std, min, max } = e.detail
  // results — array of { latency, ratio, timestamp } objects
  // mean    — mean latency in ms
  // std     — standard deviation of latency in ms
  // min     — minimum latency in ms
  // max     — maximum latency in ms
})

latency-error

Fired when the measurement cannot proceed (e.g. microphone access denied, AudioContext creation failed).

js
element.addEventListener('latency-error', (e) => {
  const { message } = e.detail
  console.error('Latency test failed:', message)
})

Lifecycle events

These fire with no payload (e.detail is null). Use them to update host UI state — disable buttons, show spinners, etc.

EventWhen fired
latency-startPermission granted; test is about to begin
latency-recordingSignal playback started; capture is running
latency-processingRecording stopped; cross-correlation worker is running

Algorithm constants

These values are fixed by the research methodology and are not configurable:

ConstantValueDescription
Reliability threshold18 dBMinimum correlation ratio for a trustworthy measurement — empirically chosen in the WAC 2025 experiments
MLS amplitude±1.0Binary MLS sequence mapped to +1.0 / −1.0 float samples
Chirp frequency range1500–8000 HzBandlimited to avoid input aliasing above 12 kHz present on some iOS devices
Mic constraintsechoCancellation: false, noiseSuppression: false, autoGainControl: falseEssential for accurate measurement; these are always forced

Browser requirements

  • getUserMedia (microphone access)
  • Web Audio API (AudioContext, AudioWorklet)
  • Web Workers
  • HTTPS or localhost

Safari may require manual gain compensation — set input-gain="50" if microphone levels are too low (common on Safari > v16 with echoCancellation disabled). The component does not apply any gain automatically.

MIT License