Skip to content

Replace threshold-based latency calibration with MLS/cross-correlation#86

Open
fan-droide wants to merge 3 commits into
Brotherta:mainfrom
fan-droide:feature/latency-test
Open

Replace threshold-based latency calibration with MLS/cross-correlation#86
fan-droide wants to merge 3 commits into
Brotherta:mainfrom
fan-droide:feature/latency-test

Conversation

@fan-droide

@fan-droide fan-droide commented Jun 26, 2026

Copy link
Copy Markdown

What this PR does

Replaces LatencyProcessor.js (threshold/peak-based AudioWorklet detector) with <latency-test> — a maintained Web Component that measures browser round-trip audio latency using an MLS signal and cross-correlation.

Primary changes

  • LatencyController.ts rewritten to use the <latency-test> element in audioworklet mode, using the main audioCtx — closer to WAM Studio's recording path than the original fresh-context approach
  • LatencyProcessor.js deleted — replaced by the component
  • @adasp/latency-test@1.2.1 added to package.json (MIT licence)

Behaviour improvements

  • 3-run MLS/cross-correlation measurement vs. threshold/peak-based detection — more reliable and repeatable
  • Reliability gate: prior calibration is left untouched if any run is unreliable or the user stops early
  • Race-safe: stale-element guards prevent a rejected async operation from clobbering a newer calibration run
  • Fixes compensation semantics: the measured full round-trip value is used directly, instead of roundtrip - outputLatency

Manual verification

cd public && npm ci && npm run build

Tested calibration flow (mic permission, stop/retry, repeated calibrations, reload persistence) in Firefox and Chrome. self.crossOriginIsolated === true confirmed in both browsers on the live demo.

Live demo (fork)

https://charming-paletas-c95a3f.netlify.app

Background notes

Full investigation: demos/wam-studio/NOTES.md in idsinge/latency-test-examples

gilpanal and others added 2 commits June 26, 2026 14:51
Replaces the threshold-based AudioWorklet peak-detector with the
MLS/cross-correlation <latency-test> component. Key changes:
- Delete LatencyProcessor.js (old threshold detector)
- Rewrite LatencyController.ts: getUserMedia -> set audioContext +
  inputStream on the element -> listen for latency-result / latency-complete
- Use main audioCtx (not a fresh context) -- same sink, sample rate,
  outputLatency as the recording pipeline
- Fix formula bug: use event.detail.mean (full round-trip) instead of
  roundtrip - outputLatency * 1000
- Race-safe: _calibrating = true set before first await; stale-element
  guards in all event handlers; cleanup scoped to el to prevent a
  rejected async operation from clobbering a newer calibration run
- Reliability gate: only commit calibration if all 3 runs are reliable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fan-droide pushed a commit to idsinge/latency-test-examples that referenced this pull request Jun 26, 2026
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add if (this._latencyEl !== el) return guard in el.start() catch block —
  same pattern as all other async paths, prevents a late rejection from
  clobbering a newer calibration run
- Remove unused _hostView field and its HostView import
- Simplify _cleanupLatencyTest with optional chain
- Rename catch (err) to catch (_err) in startCalibrate — error already
  logged upstream before rethrow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant