Every voice-AI vendor publishes a latency number. All measured differently, none including the phone network. dialtone records what it sent and what came back and recovers the timing from the audio itself.
An SDK will tell you it emitted its first audio chunk 340ms after it decided the caller stopped talking. That is real, and it excludes the inbound jitter buffer, the endpointer's own decision delay — usually the largest term — loss concealment, carrier codec delay, and the playout buffer.
So do not ask. Recovering true end-of-speech to first-audio latency means normalised cross-correlation on the recorded audio, normalised per window rather than globally — otherwise a loud unrelated burst outscores a quiet true match and the alignment lands on whatever was loudest.
FFT numerator, prefix-sum denominator. O(n log n) rather than O(n·m).
A periodic signal matches at every multiple of its period. Peak sharpness catches it instead of reporting confident nonsense.
"Hello?… hello?", a phone number in chunks, an address over a compressor, an answering machine.
A codec conceals one lost packet well and five in a row not at all. Independent loss at the same rate is far too forgiving.
Silence-filling would make every dropout look like end-of-turn, and the harness would measure its own naivety.
Inject a known latency, assert the harness recovers it. Without that, nothing it reports means anything.
The control tests — the harness measuring a latency it injected on purpose:
No real telephony leg yet — everything here is a simulated media path. The timing recovery is designed for real recordings, but placing actual PSTN calls costs money per minute and is not wired up. That is the obvious next piece. No ASR scoring either: this measures timing and turn-taking, not comprehension.
The README goes deeper, and the tests are the honest documentation. Happy to walk through the trade-offs.