Skip to content

Commit d5b1e61

Browse files
authored
Expand on limitations of existing speech recognition events in Alternatives and refactor Timestamps to use Seconds (#205)
* Expand on limitations of existing speech recognition events Added detailed explanations regarding the limitations of existing API surfaces for tracking latency in speech recognition in the Alternatives Considered section, including issues with `speechstart` and `speechend` events and the implications of modifying `event.timeStamp`. * Refactor speech recognition timestamps to use seconds Updated the speech recognition result timestamps to use seconds instead of milliseconds, improving consistency with other Web APIs. Added detailed explanations for the choice of time representation, proposed behavior, and security considerations. Based off of comments from #205
1 parent f711e7a commit d5b1e61

1 file changed

Lines changed: 88 additions & 35 deletions

File tree

explainers/speech-recognition-result-timestamps.md

Lines changed: 88 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,70 +6,103 @@
66

77
The Web Speech API currently does not expose the start and end timestamps of the source audio corresponding to a given transcription result (`SpeechRecognitionResult`). This limitation creates two major challenges for API clients and end users:
88

9-
- **Timeline Association:** Developers cannot readily associate transcribed text with specific segments of the audio source, making it difficult to map generated captions to media timelines or audio tracks.
9+
- **Timeline Association:** Developers cannot readily associate transcribed text with specific segments of the audio source, making it difficult to map generated captions to media timelines, audio tracks, or video frames.
1010
- **Latency Tracking & Backend Failover:** With the adoption of on-device Automatic Speech Recognition (ASR) to improve privacy and reduce server costs, processing performance becomes heavily dependent on local client hardware resources. The Web Speech API acts as a "black box" regarding local processing delays. Developers cannot programmatically calculate transcription latency or detect when on-device models fall behind real-time. This leads to poor user experiences (e.g. caption lag during live video conferencing) and deprives applications of the signal needed to seamlessly fail over to high-performance cloud backends.
1111

1212
### Proposed Solution
1313

14-
We propose extending the `SpeechRecognitionResult` interface to include optional (nullable) `audioStartTime` and `audioEndTime` attributes.
14+
We propose extending the `SpeechRecognitionResult` interface to include `audioStartTime` and `audioEndTime` attributes.
1515

1616
#### Web IDL Definition
1717

1818
```webidl
1919
partial interface SpeechRecognitionResult {
20-
// Start timestamp of the audio segment in milliseconds (relative to the start of the audio stream)
21-
readonly attribute DOMHighResTimeStamp? audioStartTime;
20+
// Start timestamp of the audio segment in seconds relative to the start of the audio stream (0.0s).
21+
readonly attribute double audioStartTime;
2222
23-
// End timestamp of the audio segment in milliseconds (relative to the start of the audio stream)
24-
readonly attribute DOMHighResTimeStamp? audioEndTime;
23+
// End timestamp of the audio segment in seconds relative to the start of the audio stream.
24+
readonly attribute double audioEndTime;
2525
};
2626
```
2727

28+
### Choice of Time Representation: Seconds as `double`
29+
30+
The timestamps `audioStartTime` and `audioEndTime` are defined as `double` representing **seconds**, rather than `DOMHighResTimeStamp` (milliseconds). This design choice is based on the following considerations:
31+
32+
1. **Consistency with Adjacent Web Audio & Media APIs:**
33+
* In adjacent W3C media specifications, media-local stream timelines are universally represented in **seconds** as a `double`:
34+
* **Web Audio API:** [`BaseAudioContext.currentTime`](https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime) (seconds)
35+
* **HTML Media Elements:** [`HTMLMediaElement.currentTime`](https://html.spec.whatwg.org/multipage/media.html#dom-media-currenttime) (seconds)
36+
* **AudioParam Scheduling:** [`AudioParam.setValueAtTime()`](https://webaudio.github.io/web-audio-api/#dom-audioparam-setvalueattime) (seconds)
37+
* Using seconds ensures seamless interoperability when developers route audio between `<audio>`/`<video>` elements, Web Audio graphs, and `SpeechRecognition`, avoiding repetitive and error-prone unit conversions ($1000\times / \div 1000$).
38+
39+
2. **Semantic Inaccuracy of `DOMHighResTimeStamp` for Media Streams:**
40+
* Under the [W3C High Resolution Time Level 3](https://www.w3.org/TR/hr-time-3/#sec-domhighrestimestamp) specification, `DOMHighResTimeStamp` is strictly defined as a time coordinate in **milliseconds** measured relative to the global execution context's time origin (`performance.timeOrigin`).
41+
* Because `audioStartTime` and `audioEndTime` represent a **media-local timeline** (elapsed time starting at $0.0\text{s}$ at the beginning of the audio stream) rather than document uptime, using `DOMHighResTimeStamp` would be semantically incorrect.
42+
43+
3. **Numerical Precision:**
44+
* A standard 64-bit IEEE 754 floating-point number (`double`) in seconds provides sub-nanosecond resolution across hours of continuous audio streaming, ensuring sample-accurate precision at any audio sample rate (e.g. 16 kHz to 96 kHz).
45+
46+
4. **W3C TAG Design Principles Alignment:**
47+
* This design adheres to the [W3C TAG Design Principles on Times and Dates](https://w3ctag.github.io/design-principles/#times-and-dates), ensuring consistency across media stream APIs on the web platform.
48+
49+
---
50+
2851
### Proposed Behavior & Example Usage
2952

30-
The `audioStartTime` and `audioEndTime` properties represent the audio duration bounds (in milliseconds) corresponding to the transcribed segment. If the underlying recognition engine backend does not support segment timestamps, these attributes return `null`.
53+
The `audioStartTime` and `audioEndTime` properties represent the audio duration bounds (in seconds) corresponding to the transcribed segment.
3154

32-
Developers can programmatically compute processing latency by comparing `audioEndTime` against the standard DOM event generation timestamp (`Event.timeStamp`):
55+
Developers can programmatically compute processing latency by converting the stream timestamp to the document timeline and comparing against `Event.timeStamp`:
3356

3457
```javascript
3558
const recognition = new SpeechRecognition();
3659
recognition.continuous = true;
3760
recognition.interimResults = true;
3861

62+
let audioOriginMs = 0;
63+
64+
// 1. Capture the audio stream's start timestamp on the document timeline
65+
recognition.onaudiostart = (event) => {
66+
audioOriginMs = event.timeStamp;
67+
};
68+
3969
recognition.onresult = (event) => {
4070
const result = event.results[event.resultIndex];
4171

42-
if (result.audioEndTime !== null && result.audioEndTime !== undefined) {
43-
// Calculate on-device processing latency
44-
const processingLatencyMs = event.timeStamp - result.audioEndTime;
72+
// 2. Convert stream-relative seconds to document timeline milliseconds
73+
const absoluteAudioEndMs = audioOriginMs + (result.audioEndTime * 1000);
74+
75+
// 3. Calculate on-device processing latency
76+
const processingLatencyMs = event.timeStamp - absoluteAudioEndMs;
4577

46-
// Trigger seamless failover to cloud backend if latency breaches acceptable threshold
47-
if (processingLatencyMs > 1500) {
48-
console.warn(`ASR processing lag detected (${processingLatencyMs}ms). Transitioning to cloud provider.`);
49-
switchToCloudBackend();
50-
}
78+
// 4. Trigger seamless failover to cloud backend if latency breaches acceptable threshold
79+
if (processingLatencyMs > 1500) {
80+
console.warn(`ASR processing lag detected (${processingLatencyMs.toFixed(0)}ms). Transitioning to cloud provider.`);
81+
switchToCloudBackend();
5182
}
5283
};
5384

5485
recognition.start();
5586
```
5687

57-
## Converting Stream Timestamps to Document Time Origin
88+
---
5889

59-
`audioStartTime` and `audioEndTime` are defined as media-local offsets in milliseconds relative to the start of the audio stream ($t = 0.0\text{ms}$).
90+
### Converting Stream Timestamps to Document Time Origin
6091

61-
For real-time applications such as **live translation**, **subtitling overlays**, and **audio-visual sync**, developers often need to map these stream offsets to the document's global timeline (`DOMHighResTimeStamp` / `performance.now()`).
92+
`audioStartTime` and `audioEndTime` are defined as media-local offsets in seconds relative to the start of the audio stream ($t = 0.0\text{s}$).
6293

63-
### Pattern: Capturing the Audio Timeline Origin
94+
For real-time applications such as **live translation**, **subtitling overlays**, and **audio-visual sync**, developers often need to map these stream offsets to the document's global timeline (`performance.timeOrigin` / `performance.now()`).
95+
96+
#### Pattern: Capturing the Audio Timeline Origin
6497

6598
To convert stream-relative timestamps to document time coordinates:
66-
1. Record the baseline timestamp when the `audiostart` event fires (`event.timeStamp` is a `DOMHighResTimeStamp` relative to `timeOrigin`).
67-
2. Add the result's `audioStartTime` and `audioEndTime` offsets to that baseline.
99+
1. Record the baseline timestamp when the `audiostart` event fires (`event.timeStamp` is in milliseconds relative to `timeOrigin`).
100+
2. Add the result's `audioStartTime` and `audioEndTime` offsets (converted to milliseconds) to that baseline:
68101

69-
$$\text{absoluteStartTime} = \text{audioOrigin} + \text{result.audioStartTime}$$
70-
$$\text{absoluteEndTime} = \text{audioOrigin} + \text{result.audioEndTime}$$
102+
$$\text{absoluteStartTimeMs} = \text{audioOriginMs} + (\text{result.audioStartTime} \times 1000)$$
103+
$$\text{absoluteEndTimeMs} = \text{audioOriginMs} + (\text{result.audioEndTime} \times 1000)$$
71104

72-
### Measuring Live Translation Latency Example
105+
#### Measuring Live Translation Latency Example
73106

74107
In live speech translation workflows, measuring both **Speech-to-Text (STT) latency** and **Machine Translation (MT) end-to-end latency** is essential:
75108

@@ -78,23 +111,22 @@ const recognition = new SpeechRecognition();
78111
recognition.continuous = true;
79112
recognition.interimResults = true;
80113

81-
let audioOriginTime = 0;
114+
let audioOriginTimeMs = 0;
82115

83116
// 1. Capture the audio stream's time origin on the document timeline
84117
recognition.onaudiostart = (event) => {
85-
audioOriginTime = event.timeStamp;
118+
audioOriginTimeMs = event.timeStamp;
86119
};
87120

88121
recognition.onresult = async (event) => {
89122
const result = event.results[event.resultIndex];
90-
if (result.audioEndTime === null || result.audioEndTime === undefined) return;
91123

92-
// 2. Convert stream offsets to document time origin coordinates
93-
const absoluteAudioStart = audioOriginTime + result.audioStartTime;
94-
const absoluteAudioEnd = audioOriginTime + result.audioEndTime;
124+
// 2. Convert stream offsets (seconds) to document timeline (milliseconds)
125+
const absoluteAudioStartMs = audioOriginTimeMs + (result.audioStartTime * 1000);
126+
const absoluteAudioEndMs = audioOriginTimeMs + (result.audioEndTime * 1000);
95127

96128
// 3. Compute ASR recognition latency
97-
const asrLatencyMs = event.timeStamp - absoluteAudioEnd;
129+
const asrLatencyMs = event.timeStamp - absoluteAudioEndMs;
98130

99131
// 4. Perform live translation
100132
const text = result[0].transcript;
@@ -103,23 +135,44 @@ recognition.onresult = async (event) => {
103135
const translationEndTime = performance.now();
104136

105137
// 5. Total end-to-end latency from speaker utterance to translated subtitle
106-
const totalE2ELatencyMs = translationEndTime - absoluteAudioEnd;
138+
const totalE2ELatencyMs = translationEndTime - absoluteAudioEndMs;
107139

108140
console.log(`ASR Processing Time: ${asrLatencyMs.toFixed(1)}ms`);
109141
console.log(`Total Live Translation Delay: ${totalE2ELatencyMs.toFixed(1)}ms`);
110142
};
143+
144+
recognition.start();
111145
```
146+
112147
---
148+
113149
### Security and Privacy Considerations
114150

115151
#### Fingerprinting Risk
116-
Exposing sub-millisecond or precise micro-architectural timing information enables hardware profiling (measuring CPU execution speed, thermal throttling, and system load), creating a tracking vector for cross-origin user fingerprinting.
152+
Exposing sub-millisecond or precise micro-architectural timing information enables hardware profiling (measuring CPU execution speed, thermal throttling, and system load), creating a potential tracking vector for cross-origin user fingerprinting.
117153

118154
#### Mitigation Strategy
119-
To mitigate fingerprinting vectors, browser implementations MUST apply timestamp fuzzing and precision reduction before exposing timing attributes to web scripts. We propose mirroring the precision capping strategy used in [`HTMLMediaElement.currentTime`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime), rounding exposed timestamps to **2ms** precision (or matching the site-wide timer resolution policy).
155+
To mitigate potential side-channel and fingerprinting vectors:
156+
* **Precedent:** Implementations (such as Chromium) follow the security posture established by [`HTMLMediaElement.currentTime`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime), coarsening raw engine timestamps to discrete resolution buckets (e.g. 2ms resolution) in non-isolated execution contexts.
157+
* **Specification Precedent:** In accordance with [W3C High Resolution Time Level 3](https://www.w3.org/TR/hr-time-3/#privacy-security), the specification does not mandate a hardcoded quantization value, allowing user agents to adjust timer resolution or introduce jitter according to their security and cross-origin isolation policies.
158+
159+
---
120160

121161
### Alternatives Considered
122162

123163
- **Browser-Generated Warning Events (`onprocessinglag`):** Simple for web applications to catch, but fails to accommodate varying latency thresholds across different use cases (e.g. real-time meeting captioning requires <200ms latency, while dictation tools tolerate multi-second delays).
124164
- **Internal Processing Queue Metric (`queueDepth`):** Directly exposes engine backlogs, but is difficult to standardize across fragmented engine architectures, model types, and buffering strategies.
125165
- **Binary Status Flag (`isRealTime`):** Simple boolean check, but lacks numerical precision for applications seeking to track progressive latency degradation trendlines.
166+
- **Existing API Surfaces (Events):** Existing events were deemed insufficient because:
167+
1. **`speechstart` and `speechend` Events:**
168+
The Web Speech API specification defines `speechstart` and `speechend` events on the `SpeechRecognition` interface. However, these events cannot solve the continuous latency tracking problem:
169+
* **Session-level vs. Result-level Granularity:** In continuous recognition mode, `speechstart` and `soundstart` fire once when voice activity is first detected at the beginning of the session. They do not fire for every individual phrase or sentence returned in subsequent `SpeechRecognitionResult` events.
170+
* **Inequality with Result Audio Boundaries:** Because `speechstart` only marks initial voice activity, `speechstart.timeStamp` is not equal to `result.audioStartTime` for any subsequent utterance emitted throughout a session.
171+
* **Fragile Event Correlation:** Even if engines fired `speechstart`/`speechend` around each phrase, associating separate asynchronous DOM events with streaming interim and final `SpeechRecognitionResult` objects requires complex, error-prone client-side state tracking (poor ergonomics).
172+
2. **Overloading `event.timeStamp` on Result Events:**
173+
Another alternative considered was modifying `event.timeStamp` on the `result` event to match the speech timing:
174+
* **Eliminates Latency Calculation:** `event.timeStamp` indicates when the browser dispatched the DOM event on the document timeline. Keeping `event.timeStamp` intact while providing `result.audioEndTime` allows web applications to measure processing delay:
175+
$$\text{latencyMs} = \text{event.timeStamp} - (\text{audioOriginMs} + \text{result.audioEndTime} \times 1000)$$
176+
* Overwriting `event.timeStamp` would conflate acoustic timing with main-thread dispatch time, eliminating the ability to detect processing lag.
177+
178+
Attaching `audioStartTime` and `audioEndTime` directly to `SpeechRecognitionResult` provides a 1:1 association between the recognized transcript text and its corresponding acoustic timeline.

0 commit comments

Comments
 (0)