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
<latency-test></latency-test>Register the element by importing the package:
import '@hi-audio/latency-test'Attributes
Attributes are reflected as properties and can be set either in HTML or via JavaScript.
| Attribute | Property | Type | Default | Description |
|---|---|---|---|---|
number-of-tests | numberOfTests | number | 1 | How many consecutive measurements to run. When > 1, a latency-complete event is fired after the last run with aggregate statistics. |
recording-mode | recordingMode | string | "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-type | signalType | string | "mls" | Test signal used for the round-trip measurement. See signal types table below. |
input-gain | inputGain | number | 0 | Gain 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-bits | mlsBits | number | 15 | Order of the MLS sequence. Sequence length = 2^n − 1. Valid range: 2–16. Only applies when signal-type="mls". |
max-lag-ms | maxLagMs | number | 600 | Cross-correlation search window in milliseconds. Determines the maximum measurable round-trip latency. |
Example
<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
| Value | Description | Status |
|---|---|---|
"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.
| Property | Type | Description |
|---|---|---|
audioContext | AudioContext | Optional. 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. |
inputStream | MediaStream | Optional. 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
const element = document.querySelector('latency-test')
element.audioContext = existingAudioContextMethods
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.
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.
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.
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.
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).
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.
| Event | When fired |
|---|---|
latency-start | Permission granted; test is about to begin |
latency-recording | Signal playback started; capture is running |
latency-processing | Recording stopped; cross-correlation worker is running |
Algorithm constants
These values are fixed by the research methodology and are not configurable:
| Constant | Value | Description |
|---|---|---|
| Reliability threshold | 18 dB | Minimum correlation ratio for a trustworthy measurement — empirically chosen in the WAC 2025 experiments |
| MLS amplitude | ±1.0 | Binary MLS sequence mapped to +1.0 / −1.0 float samples |
| Chirp frequency range | 1500–8000 Hz | Bandlimited to avoid input aliasing above 12 kHz present on some iOS devices |
| Mic constraints | echoCancellation: false, noiseSuppression: false, autoGainControl: false | Essential 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.