@openmoq/playback 0.0.0-stage → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +202 -0
- package/README.md +18 -2
- package/dist/adaptive-tolerance.d.ts +128 -0
- package/dist/adaptive-tolerance.d.ts.map +1 -0
- package/dist/adaptive-tolerance.js +339 -0
- package/dist/adaptive-tolerance.js.map +1 -0
- package/dist/bandwidth-estimator.d.ts +49 -0
- package/dist/bandwidth-estimator.d.ts.map +1 -0
- package/dist/bandwidth-estimator.js +77 -0
- package/dist/bandwidth-estimator.js.map +1 -0
- package/dist/browser/index.global.js +2813 -0
- package/dist/browser/index.global.js.map +1 -0
- package/dist/browser/index.js +2788 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/buffer-based-controller.d.ts +87 -0
- package/dist/buffer-based-controller.d.ts.map +1 -0
- package/dist/buffer-based-controller.js +85 -0
- package/dist/buffer-based-controller.js.map +1 -0
- package/dist/decoder-state.d.ts +103 -0
- package/dist/decoder-state.d.ts.map +1 -0
- package/dist/decoder-state.js +145 -0
- package/dist/decoder-state.js.map +1 -0
- package/dist/gap-detector.d.ts +83 -0
- package/dist/gap-detector.d.ts.map +1 -0
- package/dist/gap-detector.js +129 -0
- package/dist/gap-detector.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/jitter-buffer.d.ts +73 -0
- package/dist/jitter-buffer.d.ts.map +1 -0
- package/dist/jitter-buffer.js +216 -0
- package/dist/jitter-buffer.js.map +1 -0
- package/dist/keyframe-validator.d.ts +26 -0
- package/dist/keyframe-validator.d.ts.map +1 -0
- package/dist/keyframe-validator.js +170 -0
- package/dist/keyframe-validator.js.map +1 -0
- package/dist/pipeline.d.ts +215 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +852 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/recovery.d.ts +166 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +176 -0
- package/dist/recovery.js.map +1 -0
- package/dist/render-scheduler.d.ts +50 -0
- package/dist/render-scheduler.d.ts.map +1 -0
- package/dist/render-scheduler.js +84 -0
- package/dist/render-scheduler.js.map +1 -0
- package/dist/startup-buffer.d.ts +68 -0
- package/dist/startup-buffer.d.ts.map +1 -0
- package/dist/startup-buffer.js +107 -0
- package/dist/startup-buffer.js.map +1 -0
- package/dist/sync.d.ts +234 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +343 -0
- package/dist/sync.js.map +1 -0
- package/dist/types.d.ts +229 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -3
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StartupBuffer — holds frames before first drain to warm the jitter estimator.
|
|
3
|
+
*
|
|
4
|
+
* Prevents initial stutter by collecting N frames (determined by network class)
|
|
5
|
+
* before allowing the pipeline to start draining. During the hold, the adaptive
|
|
6
|
+
* tolerance controller calibrates from real arrival timing — so it's ready
|
|
7
|
+
* when playback begins.
|
|
8
|
+
*
|
|
9
|
+
* Network classification uses the QUIC handshake RTT (available before any media)
|
|
10
|
+
* to set initial parameters:
|
|
11
|
+
* - LAN (<1ms): 2 frames / 80ms max — near-zero startup delay
|
|
12
|
+
* - Near-LAN (1-5ms): 3 frames / 120ms
|
|
13
|
+
* - Metro WAN (5-50ms): 8 frames / 300ms
|
|
14
|
+
* - Long-haul WAN (>50ms): 12 frames / 500ms
|
|
15
|
+
*
|
|
16
|
+
* @see draft-ietf-moq-loc-01 §4.2 (decode order)
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Classify network conditions from QUIC handshake RTT.
|
|
21
|
+
*
|
|
22
|
+
* @param handshakeRttMs Round-trip time from the QUIC/WebTransport handshake
|
|
23
|
+
*/
|
|
24
|
+
export function classifyNetwork(handshakeRttMs) {
|
|
25
|
+
if (handshakeRttMs < 1) {
|
|
26
|
+
return { minFrames: 2, maxWaitMs: 80 };
|
|
27
|
+
}
|
|
28
|
+
else if (handshakeRttMs < 5) {
|
|
29
|
+
return { minFrames: 3, maxWaitMs: 120 };
|
|
30
|
+
}
|
|
31
|
+
else if (handshakeRttMs < 50) {
|
|
32
|
+
return { minFrames: 8, maxWaitMs: 300 };
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return { minFrames: 12, maxWaitMs: 500 };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ─── StartupBuffer ──────────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Gates pipeline draining until enough frames have arrived for smooth startup.
|
|
41
|
+
*
|
|
42
|
+
* Usage:
|
|
43
|
+
* ```ts
|
|
44
|
+
* // In pipeline.pushObject():
|
|
45
|
+
* startupBuffer.recordFrame(clock.now() / 1000);
|
|
46
|
+
*
|
|
47
|
+
* // In pipeline.tick():
|
|
48
|
+
* if (!startupBuffer.shouldDrain) return; // hold frames
|
|
49
|
+
* // ... normal drain logic
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export class StartupBuffer {
|
|
53
|
+
minFrames;
|
|
54
|
+
maxWaitMs;
|
|
55
|
+
_frameCount = 0;
|
|
56
|
+
_firstFrameMs = 0;
|
|
57
|
+
_lastFrameMs = 0;
|
|
58
|
+
_draining = false;
|
|
59
|
+
constructor(params) {
|
|
60
|
+
this.minFrames = params.minFrames;
|
|
61
|
+
this.maxWaitMs = params.maxWaitMs;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Record a frame arrival. Call from pushObject().
|
|
65
|
+
* @param nowMs Current time in milliseconds
|
|
66
|
+
*/
|
|
67
|
+
recordFrame(nowMs) {
|
|
68
|
+
this._frameCount++;
|
|
69
|
+
if (this._frameCount === 1) {
|
|
70
|
+
this._firstFrameMs = nowMs;
|
|
71
|
+
}
|
|
72
|
+
this._lastFrameMs = nowMs;
|
|
73
|
+
// Check transition
|
|
74
|
+
if (!this._draining) {
|
|
75
|
+
const elapsed = this._lastFrameMs - this._firstFrameMs;
|
|
76
|
+
if (this._frameCount >= this.minFrames || elapsed >= this.maxWaitMs) {
|
|
77
|
+
this._draining = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Whether the pipeline should start draining (buffer phase complete). */
|
|
82
|
+
get shouldDrain() {
|
|
83
|
+
return this._draining;
|
|
84
|
+
}
|
|
85
|
+
/** Number of frames recorded. */
|
|
86
|
+
get frameCount() {
|
|
87
|
+
return this._frameCount;
|
|
88
|
+
}
|
|
89
|
+
/** Time elapsed since first frame in milliseconds. */
|
|
90
|
+
get elapsedMs() {
|
|
91
|
+
if (this._frameCount === 0)
|
|
92
|
+
return 0;
|
|
93
|
+
return this._lastFrameMs - this._firstFrameMs;
|
|
94
|
+
}
|
|
95
|
+
/** Accelerated EMA alpha for warmup (4x standard 1/16). */
|
|
96
|
+
get warmupEmaAlpha() {
|
|
97
|
+
return 0.25;
|
|
98
|
+
}
|
|
99
|
+
/** Reset to buffering state (e.g., after seek or pause→resume). */
|
|
100
|
+
reset() {
|
|
101
|
+
this._frameCount = 0;
|
|
102
|
+
this._firstFrameMs = 0;
|
|
103
|
+
this._lastFrameMs = 0;
|
|
104
|
+
this._draining = false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=startup-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-buffer.js","sourceRoot":"","sources":["../src/startup-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,cAAsB;IACpD,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACzC,CAAC;SAAM,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;IAC1C,CAAC;SAAM,IAAI,cAAc,GAAG,EAAE,EAAE,CAAC;QAC/B,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,uEAAuE;AAEvE;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,aAAa;IACP,SAAS,CAAS;IAClB,SAAS,CAAS;IAE3B,WAAW,GAAG,CAAC,CAAC;IAChB,aAAa,GAAG,CAAC,CAAC;IAClB,YAAY,GAAG,CAAC,CAAC;IACjB,SAAS,GAAG,KAAK,CAAC;IAE1B,YAAY,MAAqB;QAC/B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,KAAa;QACvB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,IAAI,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAE1B,mBAAmB;QACnB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC;YACvD,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,IAAI,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,iCAAiC;IACjC,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,sDAAsD;IACtD,IAAI,SAAS;QACX,IAAI,IAAI,CAAC,WAAW,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC;IAChD,CAAC;IAED,2DAA2D;IAC3D,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mEAAmE;IACnE,KAAK;QACH,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;CACF"}
|
package/dist/sync.d.ts
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A/V sync controller with injectable clock.
|
|
3
|
+
*
|
|
4
|
+
* Audio-master model: the first audio sample establishes a sync reference
|
|
5
|
+
* mapping CaptureTimestamp (wall-clock microseconds) to local clock time.
|
|
6
|
+
* Video render times are computed relative to this reference.
|
|
7
|
+
*
|
|
8
|
+
* Drift detection: reportPresentationTiming measures VIDEO PRESENTATION SCHEDULE
|
|
9
|
+
* drift — actual presentation time minus the exact scheduled time carried with
|
|
10
|
+
* the frame. If it exceeds the adaptive threshold, presentationDriftExceeded
|
|
11
|
+
* signals and a sync_drift event is emitted — but no automatic re-anchor occurs.
|
|
12
|
+
* Actual audio/video skew is a separate metric (sync_skew).
|
|
13
|
+
* The reference is set once to avoid audio glitching from re-anchor jumps.
|
|
14
|
+
* In practice, gap recovery (skip_forward) and seek/pause naturally re-anchor.
|
|
15
|
+
*
|
|
16
|
+
* Live catch-up: measures end-to-end latency by comparing CaptureTimestamp
|
|
17
|
+
* (publisher wall-clock) to subscriber wall-clock. When latency exceeds
|
|
18
|
+
* targetLatency + threshold, activates catch-up (playback rate > 1.0).
|
|
19
|
+
* Hysteresis prevents oscillation near the threshold boundary.
|
|
20
|
+
*
|
|
21
|
+
* @see draft-ietf-moq-loc-01 §2.3.1.1 (CaptureTimestamp)
|
|
22
|
+
* @see draft-ietf-moq-msf-00 §5.1.16 (targetLatency)
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import type { ClockSource, CatchUpState } from './types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Render time calculation result.
|
|
28
|
+
*/
|
|
29
|
+
export interface RenderTiming {
|
|
30
|
+
/** When to render this frame, in local clock microseconds. */
|
|
31
|
+
readonly renderTimeUs: number;
|
|
32
|
+
/** How far ahead (+) or behind (-) this frame is relative to now. */
|
|
33
|
+
readonly offsetUs: number;
|
|
34
|
+
/** Whether this frame should be dropped (too late to render). */
|
|
35
|
+
readonly shouldDrop: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Injectable wall-clock source for latency measurement.
|
|
39
|
+
* Returns Unix epoch microseconds (same domain as CaptureTimestamp).
|
|
40
|
+
* Default: `Date.now() * 1000`.
|
|
41
|
+
*
|
|
42
|
+
* @see draft-ietf-moq-loc-01 §2.3.1.1 (CaptureTimestamp = wall-clock µs)
|
|
43
|
+
*/
|
|
44
|
+
export interface WallClockSource {
|
|
45
|
+
/** Current wall-clock time in microseconds since Unix epoch. */
|
|
46
|
+
now(): number;
|
|
47
|
+
}
|
|
48
|
+
export interface SyncControllerConfig {
|
|
49
|
+
readonly driftThresholdUs: number;
|
|
50
|
+
readonly dropThresholdUs?: number;
|
|
51
|
+
readonly clock: ClockSource;
|
|
52
|
+
/** Target end-to-end latency in ms. @see draft-ietf-moq-msf-00 §5.1.16 */
|
|
53
|
+
readonly targetLatencyMs?: number;
|
|
54
|
+
/** Max playback rate for catch-up (e.g., 1.1). Default: 1.0 (disabled). */
|
|
55
|
+
readonly maxCatchUpRate?: number;
|
|
56
|
+
/** Latency above target before catch-up activates (ms). Default: 500. */
|
|
57
|
+
readonly catchUpThresholdMs?: number;
|
|
58
|
+
/** Latency above target before catch-up deactivates (ms, hysteresis). Default: 50. */
|
|
59
|
+
readonly catchUpRecoveryMs?: number;
|
|
60
|
+
/** Injectable wall-clock for testability. Default: Date.now() * 1000. */
|
|
61
|
+
readonly wallClock?: WallClockSource;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A/V sync controller with live catch-up.
|
|
65
|
+
*
|
|
66
|
+
* @see draft-ietf-moq-loc-01 §2.3.1.1
|
|
67
|
+
* @see draft-ietf-moq-msf-00 §5.1.16
|
|
68
|
+
*/
|
|
69
|
+
export declare class SyncController {
|
|
70
|
+
private _driftThresholdUs;
|
|
71
|
+
private readonly dropThresholdUs;
|
|
72
|
+
private readonly clock;
|
|
73
|
+
/** Local clock time when audio reference was set. */
|
|
74
|
+
private localBaselineUs;
|
|
75
|
+
/** CaptureTimestamp of the audio reference sample. */
|
|
76
|
+
private captureBaselineUs;
|
|
77
|
+
/** Accumulated drift measurement. */
|
|
78
|
+
private _currentDriftUs;
|
|
79
|
+
/**
|
|
80
|
+
* Video join offset — shifts video render times forward during live join.
|
|
81
|
+
*
|
|
82
|
+
* When joining a live stream, video starts from the GOP boundary
|
|
83
|
+
* (which has an older CaptureTimestamp than the current audio).
|
|
84
|
+
* This offset shifts video render times forward so the first frames
|
|
85
|
+
* render in the future instead of the past, preventing startup stutter.
|
|
86
|
+
*
|
|
87
|
+
* Snaps to zero when the video timeline catches up to the audio live edge.
|
|
88
|
+
* Audio render times are unaffected.
|
|
89
|
+
*/
|
|
90
|
+
private _videoJoinOffsetUs;
|
|
91
|
+
private readonly wallClock;
|
|
92
|
+
private readonly targetLatencyMs;
|
|
93
|
+
private readonly maxCatchUpRate;
|
|
94
|
+
private readonly catchUpThresholdMs;
|
|
95
|
+
private readonly catchUpRecoveryMs;
|
|
96
|
+
private _catchUpActive;
|
|
97
|
+
private _currentRate;
|
|
98
|
+
private _lastLatencyUs;
|
|
99
|
+
constructor(config: SyncControllerConfig);
|
|
100
|
+
/** Whether a sync reference has been established. */
|
|
101
|
+
get hasReference(): boolean;
|
|
102
|
+
/** Current drift magnitude in microseconds. */
|
|
103
|
+
get currentDriftUs(): number;
|
|
104
|
+
/** Current drift threshold in microseconds. Mutable for adaptive tolerance. */
|
|
105
|
+
get driftThresholdUs(): number;
|
|
106
|
+
set driftThresholdUs(value: number);
|
|
107
|
+
/**
|
|
108
|
+
* Whether PRESENTATION SCHEDULE drift exceeds the threshold.
|
|
109
|
+
*
|
|
110
|
+
* Deliberately has NO live-join suppression. The exact queued schedule
|
|
111
|
+
* already contains the join offset, so missing that schedule during a join
|
|
112
|
+
* is a real miss. (The legacy PTS-era metric needed the suppression because
|
|
113
|
+
* the offset itself showed up as drift; see {@link needsResync}.)
|
|
114
|
+
*/
|
|
115
|
+
get presentationDriftExceeded(): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* @deprecated Threshold check for the legacy {@link reportActualRenderTime}
|
|
118
|
+
* metric, retaining its live-join suppression. Use
|
|
119
|
+
* {@link presentationDriftExceeded} with schedule-based measurement.
|
|
120
|
+
*/
|
|
121
|
+
get needsResync(): boolean;
|
|
122
|
+
/** Whether catch-up is currently active. */
|
|
123
|
+
get catchUpActive(): boolean;
|
|
124
|
+
/** Current playback rate (1.0 when catch-up inactive). */
|
|
125
|
+
get currentRate(): number;
|
|
126
|
+
/**
|
|
127
|
+
* Last measured latency in microseconds.
|
|
128
|
+
* 0 before first measurement.
|
|
129
|
+
* @see draft-ietf-moq-loc-01 §2.3.1.1
|
|
130
|
+
*/
|
|
131
|
+
get latencyUs(): number;
|
|
132
|
+
/**
|
|
133
|
+
* Establish sync reference from an audio sample.
|
|
134
|
+
* Maps captureTimestamp to the current local clock time.
|
|
135
|
+
* Resets drift measurement.
|
|
136
|
+
*
|
|
137
|
+
* @param captureTimestampUs CaptureTimestamp in microseconds
|
|
138
|
+
*/
|
|
139
|
+
setAudioReference(captureTimestampUs: bigint): void;
|
|
140
|
+
/**
|
|
141
|
+
* Establish sync reference from a video frame (video-only mode).
|
|
142
|
+
* No-op if a reference already exists — audio has priority.
|
|
143
|
+
*
|
|
144
|
+
* @param captureTimestampUs CaptureTimestamp of the first video frame
|
|
145
|
+
*/
|
|
146
|
+
setVideoReference(captureTimestampUs: bigint): void;
|
|
147
|
+
/** Current video join offset in microseconds. 0 = no offset active. */
|
|
148
|
+
get videoJoinOffsetUs(): number;
|
|
149
|
+
/**
|
|
150
|
+
* Apply video join re-anchor for live stream join.
|
|
151
|
+
*
|
|
152
|
+
* Called when the first video keyframe is decoded after a live join.
|
|
153
|
+
* Computes an offset that shifts video render times forward so the
|
|
154
|
+
* first frame renders at `now + cushion` instead of in the past.
|
|
155
|
+
*
|
|
156
|
+
* The offset is a constant added to all video render times. It preserves
|
|
157
|
+
* inter-frame timing (33ms spacing) while shifting the whole timeline.
|
|
158
|
+
* Snaps to zero when video catches up to the live edge.
|
|
159
|
+
*
|
|
160
|
+
* @param firstKeyframeCaptureUs CaptureTimestamp of the first keyframe
|
|
161
|
+
* @param cushionUs Extra future cushion (default: 16ms ≈ 1 rAF tick)
|
|
162
|
+
*/
|
|
163
|
+
onVideoJoin(firstKeyframeCaptureUs: bigint, cushionUs?: number): void;
|
|
164
|
+
/**
|
|
165
|
+
* Compute render timing for a video frame.
|
|
166
|
+
*
|
|
167
|
+
* @param captureTimestampUs CaptureTimestamp in microseconds
|
|
168
|
+
*/
|
|
169
|
+
computeVideoRenderTime(captureTimestampUs: bigint): RenderTiming | null;
|
|
170
|
+
/**
|
|
171
|
+
* Compute render timing for an audio sample.
|
|
172
|
+
*
|
|
173
|
+
* @param captureTimestampUs CaptureTimestamp in microseconds
|
|
174
|
+
*/
|
|
175
|
+
computeAudioRenderTime(captureTimestampUs: bigint): RenderTiming | null;
|
|
176
|
+
/**
|
|
177
|
+
* Record PRESENTATION SCHEDULE drift: did the renderer present the frame
|
|
178
|
+
* when it was told to?
|
|
179
|
+
*
|
|
180
|
+
* `scheduledUs` must be the EXACT timestamp stored with the rendered frame.
|
|
181
|
+
* It already accounts for the playout cushion actually applied to that
|
|
182
|
+
* frame, the live-join offset, decode-output recomputation and late-frame
|
|
183
|
+
* handling — none of which may be recomputed or subtracted later, because an
|
|
184
|
+
* adaptive cushion can move between enqueue and presentation.
|
|
185
|
+
*
|
|
186
|
+
* The schedule is REQUIRED here. Optionality lives at
|
|
187
|
+
* `FrameRenderedFeedback`, where the pipeline suppresses the whole
|
|
188
|
+
* measurement/event transaction cleanly: missing evidence is not drift.
|
|
189
|
+
*
|
|
190
|
+
* Actual audio/video skew is measured separately as `sync_skew`.
|
|
191
|
+
*/
|
|
192
|
+
reportPresentationTiming(scheduledUs: number, actualUs: number): void;
|
|
193
|
+
/**
|
|
194
|
+
* @deprecated Compares against the UNCUSHIONED PTS-anchored time, so a
|
|
195
|
+
* stream presenting exactly on its intended schedule reports the whole
|
|
196
|
+
* playout cushion as drift. Retained as a compatibility path only; use
|
|
197
|
+
* {@link reportPresentationTiming}.
|
|
198
|
+
*/
|
|
199
|
+
reportActualRenderTime(captureTimestampUs: bigint, actualLocalUs: number): void;
|
|
200
|
+
/**
|
|
201
|
+
* Measure end-to-end latency from a wall-clock timestamp.
|
|
202
|
+
*
|
|
203
|
+
* Compares the publisher's wall-clock timestamp to the subscriber's
|
|
204
|
+
* wall clock, both in Unix epoch microseconds. A media-time timestamp
|
|
205
|
+
* (LOC-04 with Timescale) has no wall-clock meaning, so latency is
|
|
206
|
+
* unmeasurable and this returns null.
|
|
207
|
+
*
|
|
208
|
+
* @param captureTimestampUs Timestamp in microseconds
|
|
209
|
+
* @param isWallClock False when the timestamp is media time. Undefined means wall clock.
|
|
210
|
+
* @returns Latency in microseconds, or null if unmeasurable
|
|
211
|
+
* @see draft-ietf-moq-loc-01 §2.3.1.1
|
|
212
|
+
* @see draft-ietf-moq-loc-04 §2.3.1.2
|
|
213
|
+
*/
|
|
214
|
+
measureLatency(captureTimestampUs: bigint, isWallClock?: boolean): number | null;
|
|
215
|
+
/**
|
|
216
|
+
* Evaluate catch-up state based on current latency.
|
|
217
|
+
*
|
|
218
|
+
* Hysteresis: activates when latency > target + threshold,
|
|
219
|
+
* deactivates when latency <= target + recovery.
|
|
220
|
+
*
|
|
221
|
+
* Rate is proportional to overshoot, quantized to 0.05x increments.
|
|
222
|
+
*
|
|
223
|
+
* @param captureTimestampUs CaptureTimestamp in microseconds (Unix epoch)
|
|
224
|
+
* @returns CatchUpState if evaluated, null if catch-up is disabled or no timestamp
|
|
225
|
+
* @see draft-ietf-moq-msf-00 §5.1.16 (targetLatency)
|
|
226
|
+
*/
|
|
227
|
+
evaluateCatchUp(captureTimestampUs: bigint, isWallClock?: boolean): CatchUpState | null;
|
|
228
|
+
/**
|
|
229
|
+
* Reset the sync reference (e.g., after a skip-forward).
|
|
230
|
+
*/
|
|
231
|
+
reset(): void;
|
|
232
|
+
private computeRenderTime;
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
|