@openmoq/playback 0.0.0-stage → 0.6.1

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.
Files changed (63) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +18 -2
  3. package/dist/adaptive-tolerance.d.ts +128 -0
  4. package/dist/adaptive-tolerance.d.ts.map +1 -0
  5. package/dist/adaptive-tolerance.js +339 -0
  6. package/dist/adaptive-tolerance.js.map +1 -0
  7. package/dist/bandwidth-estimator.d.ts +49 -0
  8. package/dist/bandwidth-estimator.d.ts.map +1 -0
  9. package/dist/bandwidth-estimator.js +77 -0
  10. package/dist/bandwidth-estimator.js.map +1 -0
  11. package/dist/browser/index.global.js +2813 -0
  12. package/dist/browser/index.global.js.map +1 -0
  13. package/dist/browser/index.js +2788 -0
  14. package/dist/browser/index.js.map +1 -0
  15. package/dist/buffer-based-controller.d.ts +87 -0
  16. package/dist/buffer-based-controller.d.ts.map +1 -0
  17. package/dist/buffer-based-controller.js +85 -0
  18. package/dist/buffer-based-controller.js.map +1 -0
  19. package/dist/decoder-state.d.ts +103 -0
  20. package/dist/decoder-state.d.ts.map +1 -0
  21. package/dist/decoder-state.js +145 -0
  22. package/dist/decoder-state.js.map +1 -0
  23. package/dist/gap-detector.d.ts +83 -0
  24. package/dist/gap-detector.d.ts.map +1 -0
  25. package/dist/gap-detector.js +129 -0
  26. package/dist/gap-detector.js.map +1 -0
  27. package/dist/index.d.ts +33 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +33 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/jitter-buffer.d.ts +73 -0
  32. package/dist/jitter-buffer.d.ts.map +1 -0
  33. package/dist/jitter-buffer.js +216 -0
  34. package/dist/jitter-buffer.js.map +1 -0
  35. package/dist/keyframe-validator.d.ts +26 -0
  36. package/dist/keyframe-validator.d.ts.map +1 -0
  37. package/dist/keyframe-validator.js +170 -0
  38. package/dist/keyframe-validator.js.map +1 -0
  39. package/dist/pipeline.d.ts +215 -0
  40. package/dist/pipeline.d.ts.map +1 -0
  41. package/dist/pipeline.js +852 -0
  42. package/dist/pipeline.js.map +1 -0
  43. package/dist/recovery.d.ts +166 -0
  44. package/dist/recovery.d.ts.map +1 -0
  45. package/dist/recovery.js +176 -0
  46. package/dist/recovery.js.map +1 -0
  47. package/dist/render-scheduler.d.ts +50 -0
  48. package/dist/render-scheduler.d.ts.map +1 -0
  49. package/dist/render-scheduler.js +84 -0
  50. package/dist/render-scheduler.js.map +1 -0
  51. package/dist/startup-buffer.d.ts +68 -0
  52. package/dist/startup-buffer.d.ts.map +1 -0
  53. package/dist/startup-buffer.js +107 -0
  54. package/dist/startup-buffer.js.map +1 -0
  55. package/dist/sync.d.ts +234 -0
  56. package/dist/sync.d.ts.map +1 -0
  57. package/dist/sync.js +343 -0
  58. package/dist/sync.js.map +1 -0
  59. package/dist/types.d.ts +229 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +12 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +56 -3
@@ -0,0 +1,339 @@
1
+ /**
2
+ * Adaptive jitter tolerance controller.
3
+ *
4
+ * Auto-calibrates gap timeout and drift threshold from observed network
5
+ * jitter. Implements graduated recovery (monitoring → extended wait → skip)
6
+ * with stall-count escalation and exponential decay.
7
+ *
8
+ * Sans-I/O: time is an explicit parameter, no browser APIs.
9
+ * All state is flat and mutable in place — zero allocations in the hot path.
10
+ *
11
+ * @see draft-ietf-moq-loc-01 §2.3.1.1 (CaptureTimestamp)
12
+ * @module
13
+ */
14
+ // ─── Recovery phases ────────────────────────────────────────────────
15
+ export const RecoveryPhase = {
16
+ /** Baseline — no active jitter issues. */
17
+ Normal: 'normal',
18
+ /** Gap detected, observing whether transient or persistent. */
19
+ Monitoring: 'monitoring',
20
+ /** Persistent gap — waiting with extended timeout before skipping. */
21
+ ExtendedWait: 'extended_wait',
22
+ };
23
+ export const DEFAULT_TOLERANCE_CONFIG = {
24
+ emaAlpha: 0.125, // 1/8 — RFC 6298 gain
25
+ varianceAlpha: 0.25, // 1/4 — RFC 6298 gain
26
+ slidingWindowSize: 128, // ~4s at 30fps
27
+ jitterMultiplier: 4.0, // μ + 4σ ≈ 99.99% of Gaussian
28
+ minGapTimeoutMs: 50, // floor: ~1.5 video frames
29
+ maxGapTimeoutMs: 2000, // ceiling
30
+ minDriftThresholdMs: 80,
31
+ driftThresholdMultiplier: 3.0,
32
+ stallIncrementMs: 33, // 1 video frame interval
33
+ maxStallIncrements: 3, // max 3 × 33ms = ~100ms added
34
+ monitorWindowMs: 500, // observe before escalating
35
+ monitorCleanFrames: 60, // 1s at 60fps tick rate
36
+ monitorCleanDurationMs: 1000,
37
+ maxExtendedWaitMs: 2000,
38
+ skipFrequencyThreshold: 3, // 3 skips in window → quality reduce
39
+ skipFrequencyWindowMs: 30000,
40
+ decayMinCleanFrames: 120, // 2s at 60fps
41
+ decayMinCleanDurationMs: 2000,
42
+ decayFactor: 0.9, // 10% reduction per decay step
43
+ };
44
+ const TICK_NO_SKIP = { shouldSkip: false };
45
+ const TICK_SKIP = { shouldSkip: true };
46
+ // ─── Sliding window max ─────────────────────────────────────────────
47
+ /**
48
+ * O(1) amortized sliding window maximum using a monotonic deque.
49
+ * Pre-allocated, zero-alloc after construction.
50
+ */
51
+ class SlidingMax {
52
+ buf;
53
+ deq;
54
+ capacity;
55
+ writePos = 0;
56
+ count = 0;
57
+ dHead = 0;
58
+ dTail = 0;
59
+ constructor(capacity) {
60
+ this.capacity = capacity;
61
+ this.buf = new Float64Array(capacity);
62
+ this.deq = new Uint32Array(capacity);
63
+ }
64
+ push(value) {
65
+ const cap = this.capacity;
66
+ const wIdx = this.writePos % cap;
67
+ // Evict expired front
68
+ if (this.count === cap && this.dHead !== this.dTail
69
+ && this.deq[this.dHead % cap] === wIdx) {
70
+ this.dHead++;
71
+ }
72
+ // Maintain monotonicity from back
73
+ while (this.dHead !== this.dTail
74
+ && this.buf[this.deq[(this.dTail - 1) % cap] % cap] <= value) {
75
+ this.dTail--;
76
+ }
77
+ this.deq[this.dTail % cap] = wIdx;
78
+ this.dTail++;
79
+ this.buf[wIdx] = value;
80
+ this.writePos++;
81
+ if (this.count < cap)
82
+ this.count++;
83
+ }
84
+ get max() {
85
+ if (this.dHead === this.dTail)
86
+ return 0;
87
+ return this.buf[this.deq[this.dHead % this.capacity] % this.capacity];
88
+ }
89
+ reset() {
90
+ this.writePos = 0;
91
+ this.count = 0;
92
+ this.dHead = 0;
93
+ this.dTail = 0;
94
+ }
95
+ }
96
+ // ─── Controller ─────────────────────────────────────────────────────
97
+ /**
98
+ * Adaptive jitter tolerance controller.
99
+ *
100
+ * Consumes frame arrival and gap events, produces auto-calibrated
101
+ * thresholds for gap timeout and drift detection.
102
+ */
103
+ export class AdaptiveToleranceController {
104
+ cfg;
105
+ // ── Jitter estimation ──
106
+ _jitterEma = 0;
107
+ _jitterVar = 0;
108
+ _lastTransitMs = 0;
109
+ _hasLastTransit = false;
110
+ _slidingMax;
111
+ // ── Phase state ──
112
+ _phase = RecoveryPhase.Normal;
113
+ _phaseEnteredMs = 0;
114
+ _monitorGapCount = 0;
115
+ _stallCount = 0;
116
+ _stallEscalationMs = 0;
117
+ // ── Skip frequency tracking ──
118
+ _skipTimestamps = [];
119
+ // ── Clean streak tracking (for monitoring exit + decay) ──
120
+ _cleanFrameCount = 0;
121
+ _cleanStreakStartMs = 0;
122
+ // ── Quality reduction ──
123
+ _shouldReduceQuality = false;
124
+ // ── Protocol signals ──
125
+ _deliveryTimeoutMs = 0;
126
+ // ── Capture timestamp jitter (for drift threshold) ──
127
+ _lastCaptureUs = 0;
128
+ _hasCaptureRef = false;
129
+ _captureJitterEma = 0;
130
+ constructor(config) {
131
+ this.cfg = config;
132
+ this._slidingMax = new SlidingMax(config.slidingWindowSize);
133
+ }
134
+ // ─── Read-only state ──────────────────────────────────────────
135
+ get phase() { return this._phase; }
136
+ get jitterEmaMs() { return this._jitterEma; }
137
+ get jitterVarMs() { return this._jitterVar; }
138
+ get slidingMaxMs() { return this._slidingMax.max; }
139
+ get stallCount() { return this._stallCount; }
140
+ get shouldReduceQuality() { return this._shouldReduceQuality; }
141
+ /**
142
+ * Auto-calibrated gap timeout in milliseconds.
143
+ *
144
+ * baseline = max(minGap, EMA + K × variance, slidingMax)
145
+ * effective = min(baseline + stallEscalation, maxGap, deliveryTimeout)
146
+ */
147
+ get effectiveGapTimeoutMs() {
148
+ const adaptive = Math.max(this.cfg.minGapTimeoutMs, this._jitterEma + this.cfg.jitterMultiplier * this._jitterVar, this._slidingMax.max);
149
+ const withStall = adaptive + this._stallEscalationMs;
150
+ let capped = Math.min(withStall, this.cfg.maxGapTimeoutMs);
151
+ if (this._deliveryTimeoutMs > 0) {
152
+ capped = Math.min(capped, this._deliveryTimeoutMs);
153
+ }
154
+ return capped;
155
+ }
156
+ /**
157
+ * Auto-calibrated drift threshold in milliseconds.
158
+ *
159
+ * Based on observed CaptureTimestamp interarrival jitter.
160
+ */
161
+ get effectiveDriftThresholdMs() {
162
+ if (!this._hasCaptureRef || this._captureJitterEma === 0) {
163
+ return this.cfg.minDriftThresholdMs;
164
+ }
165
+ return Math.max(this.cfg.minDriftThresholdMs, this._captureJitterEma * this.cfg.driftThresholdMultiplier);
166
+ }
167
+ // ─── Events IN ────────────────────────────────────────────────
168
+ /**
169
+ * Notify that a frame arrived.
170
+ *
171
+ * @param nowMs Current time in milliseconds
172
+ * @param captureUs CaptureTimestamp in microseconds
173
+ * @param arrivalMs Arrival time in milliseconds
174
+ */
175
+ onFrameArrived(nowMs, captureUs, arrivalMs) {
176
+ // Update interarrival jitter EMA (EWMA over transit deltas)
177
+ const transitMs = arrivalMs - captureUs * 0.001;
178
+ if (this._hasLastTransit) {
179
+ const d = transitMs - this._lastTransitMs;
180
+ const absD = d < 0 ? -d : d;
181
+ // EWMA update: α = 1/8, β = 1/4 (RFC 6298)
182
+ const emaErr = absD - this._jitterEma;
183
+ this._jitterEma += this.cfg.emaAlpha * emaErr;
184
+ this._jitterVar += this.cfg.varianceAlpha * (absD - this._jitterVar);
185
+ // Sliding window max
186
+ this._slidingMax.push(absD);
187
+ }
188
+ this._lastTransitMs = transitMs;
189
+ this._hasLastTransit = true;
190
+ // Capture timestamp jitter (for drift threshold)
191
+ if (this._hasCaptureRef) {
192
+ const captureIntervalUs = captureUs - this._lastCaptureUs;
193
+ // Expected ~33333 for 30fps, ~20000 for audio — we don't know, just track variance
194
+ const captureJitterMs = Math.abs(captureIntervalUs) * 0.001;
195
+ // Track the variance of capture intervals, not absolute value
196
+ if (this._captureJitterEma === 0) {
197
+ this._captureJitterEma = captureJitterMs;
198
+ }
199
+ else {
200
+ this._captureJitterEma += this.cfg.emaAlpha * (captureJitterMs - this._captureJitterEma);
201
+ }
202
+ }
203
+ this._lastCaptureUs = captureUs;
204
+ this._hasCaptureRef = true;
205
+ // Clean streak tracking
206
+ this._cleanFrameCount++;
207
+ if (this._cleanFrameCount === 1) {
208
+ this._cleanStreakStartMs = nowMs;
209
+ }
210
+ }
211
+ /**
212
+ * Notify that a gap was detected.
213
+ *
214
+ * @param nowMs Current time in milliseconds
215
+ * @param groupId The group ID where the gap was detected
216
+ */
217
+ onGapDetected(nowMs, _groupId) {
218
+ this._cleanFrameCount = 0;
219
+ switch (this._phase) {
220
+ case RecoveryPhase.Normal:
221
+ this._phase = RecoveryPhase.Monitoring;
222
+ this._phaseEnteredMs = nowMs;
223
+ this._monitorGapCount = 1;
224
+ break;
225
+ case RecoveryPhase.Monitoring:
226
+ this._monitorGapCount++;
227
+ if (this._monitorGapCount >= 2
228
+ && nowMs - this._phaseEnteredMs <= this.cfg.monitorWindowMs) {
229
+ // Persistent gap — escalate
230
+ this._phase = RecoveryPhase.ExtendedWait;
231
+ this._phaseEnteredMs = nowMs;
232
+ }
233
+ break;
234
+ case RecoveryPhase.ExtendedWait:
235
+ // Already waiting — no further escalation
236
+ break;
237
+ }
238
+ }
239
+ /**
240
+ * Periodic tick — evaluate phase transitions and decay.
241
+ *
242
+ * @param nowMs Current time in milliseconds
243
+ * @returns TickResult indicating whether caller should skip forward
244
+ */
245
+ tick(nowMs) {
246
+ switch (this._phase) {
247
+ case RecoveryPhase.Monitoring: {
248
+ // Check if monitoring window expired without 2nd gap → clean exit
249
+ if (nowMs - this._phaseEnteredMs > this.cfg.monitorWindowMs) {
250
+ // Check clean period
251
+ if (this._cleanFrameCount >= this.cfg.monitorCleanFrames
252
+ && nowMs - this._cleanStreakStartMs >= this.cfg.monitorCleanDurationMs) {
253
+ this._phase = RecoveryPhase.Normal;
254
+ return TICK_NO_SKIP;
255
+ }
256
+ }
257
+ break;
258
+ }
259
+ case RecoveryPhase.ExtendedWait: {
260
+ if (nowMs - this._phaseEnteredMs >= this.cfg.maxExtendedWaitMs) {
261
+ // Timeout — skip forward
262
+ this._stallCount++;
263
+ this._stallEscalationMs = Math.min(this._stallCount * this.cfg.stallIncrementMs, this.cfg.maxStallIncrements * this.cfg.stallIncrementMs);
264
+ // Track skip frequency for quality reduction
265
+ this._skipTimestamps.push(nowMs);
266
+ this._pruneSkipTimestamps(nowMs);
267
+ if (this._skipTimestamps.length >= this.cfg.skipFrequencyThreshold) {
268
+ this._shouldReduceQuality = true;
269
+ }
270
+ this._phase = RecoveryPhase.Normal;
271
+ this._cleanFrameCount = 0;
272
+ return TICK_SKIP;
273
+ }
274
+ break;
275
+ }
276
+ case RecoveryPhase.Normal: {
277
+ // Decay stall escalation during clean periods
278
+ if (this._stallEscalationMs > 0
279
+ && this._cleanFrameCount >= this.cfg.decayMinCleanFrames
280
+ && this._cleanStreakStartMs > 0
281
+ && nowMs - this._cleanStreakStartMs >= this.cfg.decayMinCleanDurationMs) {
282
+ this._stallEscalationMs *= this.cfg.decayFactor;
283
+ if (this._stallEscalationMs < 1) {
284
+ this._stallEscalationMs = 0;
285
+ this._stallCount = 0;
286
+ }
287
+ // Reset clean counters for next decay step
288
+ this._cleanFrameCount = 0;
289
+ this._cleanStreakStartMs = nowMs;
290
+ }
291
+ // Decay quality reduction flag
292
+ if (this._shouldReduceQuality) {
293
+ this._pruneSkipTimestamps(nowMs);
294
+ if (this._skipTimestamps.length < this.cfg.skipFrequencyThreshold) {
295
+ this._shouldReduceQuality = false;
296
+ }
297
+ }
298
+ break;
299
+ }
300
+ }
301
+ return TICK_NO_SKIP;
302
+ }
303
+ /**
304
+ * Set DELIVERY_TIMEOUT from protocol negotiation.
305
+ * Caps the effective gap timeout.
306
+ *
307
+ * @see draft-ietf-moq-transport-16 §9.2.2.2
308
+ */
309
+ setDeliveryTimeout(timeoutMs) {
310
+ this._deliveryTimeoutMs = timeoutMs;
311
+ }
312
+ /** Reset all state (seek, pause→resume). */
313
+ reset() {
314
+ this._jitterEma = 0;
315
+ this._jitterVar = 0;
316
+ this._lastTransitMs = 0;
317
+ this._hasLastTransit = false;
318
+ this._slidingMax.reset();
319
+ this._phase = RecoveryPhase.Normal;
320
+ this._phaseEnteredMs = 0;
321
+ this._monitorGapCount = 0;
322
+ this._stallCount = 0;
323
+ this._stallEscalationMs = 0;
324
+ this._skipTimestamps = [];
325
+ this._cleanFrameCount = 0;
326
+ this._cleanStreakStartMs = 0;
327
+ this._shouldReduceQuality = false;
328
+ this._deliveryTimeoutMs = 0;
329
+ this._lastCaptureUs = 0;
330
+ this._hasCaptureRef = false;
331
+ this._captureJitterEma = 0;
332
+ }
333
+ // ─── Internal ─────────────────────────────────────────────────
334
+ _pruneSkipTimestamps(nowMs) {
335
+ const windowStart = nowMs - this.cfg.skipFrequencyWindowMs;
336
+ this._skipTimestamps = this._skipTimestamps.filter(t => t >= windowStart);
337
+ }
338
+ }
339
+ //# sourceMappingURL=adaptive-tolerance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive-tolerance.js","sourceRoot":"","sources":["../src/adaptive-tolerance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * BandwidthEstimator — EWMA-smoothed bandwidth estimation from
3
+ * group arrival rate.
4
+ *
5
+ * MoQ/QUIC has no HTTP request/response cycle to time, so traditional
6
+ * ABR segment-download bandwidth estimation doesn't apply. Instead we
7
+ * measure the effective throughput from object arrival timing:
8
+ *
9
+ * instantaneous_bps = group_size_bytes * 8 / inter_arrival_seconds
10
+ *
11
+ * Smoothed with EWMA (Exponentially Weighted Moving Average) to filter
12
+ * single-sample spikes and bursty delivery patterns (conference WiFi).
13
+ *
14
+ * The estimate drives proactive quality decisions — downshift BEFORE
15
+ * stalls occur, based on arrival rate vs current track bitrate.
16
+ *
17
+ * @module
18
+ */
19
+ export declare class BandwidthEstimator {
20
+ private readonly alpha;
21
+ private readonly minSamples;
22
+ private estimateBps;
23
+ private lastTimestampUs;
24
+ private lastGroupBytes;
25
+ private sampleCount;
26
+ /**
27
+ * @param alpha EWMA smoothing factor (0-1). Higher = more responsive
28
+ * to recent samples, lower = smoother. Default 0.3.
29
+ * @param minSamples Minimum group arrivals before reporting a non-zero
30
+ * estimate. Early samples include connection latency
31
+ * and aren't representative. Default 5 (~10s at 2s GOPs).
32
+ */
33
+ constructor(alpha?: number, minSamples?: number);
34
+ /**
35
+ * Record a group arrival. Call once per complete group (GOP).
36
+ *
37
+ * @param bytes Total bytes in the group.
38
+ * @param timestampUs Arrival timestamp in microseconds.
39
+ */
40
+ recordGroup(bytes: number, timestampUs: number): void;
41
+ /**
42
+ * Current smoothed bandwidth estimate in kbps.
43
+ * Returns 0 if fewer than 2 groups have been recorded.
44
+ */
45
+ getEstimateKbps(): number;
46
+ /** Reset all state. */
47
+ reset(): void;
48
+ }
49
+ //# sourceMappingURL=bandwidth-estimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bandwidth-estimator.d.ts","sourceRoot":"","sources":["../src/bandwidth-estimator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,WAAW,CAAK;IAExB;;;;;;OAMG;gBACS,KAAK,SAAM,EAAE,UAAU,SAAI;IAKvC;;;;;OAKG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAiBrD;;;OAGG;IACH,eAAe,IAAI,MAAM;IAKzB,uBAAuB;IACvB,KAAK,IAAI,IAAI;CAMhB"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * BandwidthEstimator — EWMA-smoothed bandwidth estimation from
3
+ * group arrival rate.
4
+ *
5
+ * MoQ/QUIC has no HTTP request/response cycle to time, so traditional
6
+ * ABR segment-download bandwidth estimation doesn't apply. Instead we
7
+ * measure the effective throughput from object arrival timing:
8
+ *
9
+ * instantaneous_bps = group_size_bytes * 8 / inter_arrival_seconds
10
+ *
11
+ * Smoothed with EWMA (Exponentially Weighted Moving Average) to filter
12
+ * single-sample spikes and bursty delivery patterns (conference WiFi).
13
+ *
14
+ * The estimate drives proactive quality decisions — downshift BEFORE
15
+ * stalls occur, based on arrival rate vs current track bitrate.
16
+ *
17
+ * @module
18
+ */
19
+ export class BandwidthEstimator {
20
+ alpha;
21
+ minSamples;
22
+ estimateBps = null;
23
+ lastTimestampUs = null;
24
+ lastGroupBytes = null;
25
+ sampleCount = 0;
26
+ /**
27
+ * @param alpha EWMA smoothing factor (0-1). Higher = more responsive
28
+ * to recent samples, lower = smoother. Default 0.3.
29
+ * @param minSamples Minimum group arrivals before reporting a non-zero
30
+ * estimate. Early samples include connection latency
31
+ * and aren't representative. Default 5 (~10s at 2s GOPs).
32
+ */
33
+ constructor(alpha = 0.3, minSamples = 5) {
34
+ this.alpha = alpha;
35
+ this.minSamples = minSamples;
36
+ }
37
+ /**
38
+ * Record a group arrival. Call once per complete group (GOP).
39
+ *
40
+ * @param bytes Total bytes in the group.
41
+ * @param timestampUs Arrival timestamp in microseconds.
42
+ */
43
+ recordGroup(bytes, timestampUs) {
44
+ if (this.lastTimestampUs !== null && this.lastGroupBytes !== null) {
45
+ const deltaUs = timestampUs - this.lastTimestampUs;
46
+ if (deltaUs > 0) {
47
+ this.sampleCount++;
48
+ const instantBps = (bytes * 8) / (deltaUs / 1_000_000);
49
+ if (this.estimateBps === null) {
50
+ this.estimateBps = instantBps;
51
+ }
52
+ else {
53
+ this.estimateBps = this.alpha * instantBps + (1 - this.alpha) * this.estimateBps;
54
+ }
55
+ }
56
+ }
57
+ this.lastTimestampUs = timestampUs;
58
+ this.lastGroupBytes = bytes;
59
+ }
60
+ /**
61
+ * Current smoothed bandwidth estimate in kbps.
62
+ * Returns 0 if fewer than 2 groups have been recorded.
63
+ */
64
+ getEstimateKbps() {
65
+ if (this.estimateBps === null || this.sampleCount < this.minSamples)
66
+ return 0;
67
+ return this.estimateBps / 1000;
68
+ }
69
+ /** Reset all state. */
70
+ reset() {
71
+ this.estimateBps = null;
72
+ this.lastTimestampUs = null;
73
+ this.lastGroupBytes = null;
74
+ this.sampleCount = 0;
75
+ }
76
+ }
77
+ //# sourceMappingURL=bandwidth-estimator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bandwidth-estimator.js","sourceRoot":"","sources":["../src/bandwidth-estimator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,OAAO,kBAAkB;IACV,KAAK,CAAS;IACd,UAAU,CAAS;IAC5B,WAAW,GAAkB,IAAI,CAAC;IAClC,eAAe,GAAkB,IAAI,CAAC;IACtC,cAAc,GAAkB,IAAI,CAAC;IACrC,WAAW,GAAG,CAAC,CAAC;IAExB;;;;;;OAMG;IACH,YAAY,KAAK,GAAG,GAAG,EAAE,UAAU,GAAG,CAAC;QACnC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,KAAa,EAAE,WAAmB;QAC1C,IAAI,IAAI,CAAC,eAAe,KAAK,IAAI,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YAChE,MAAM,OAAO,GAAG,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC;YACnD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBACd,IAAI,CAAC,WAAW,EAAE,CAAC;gBACnB,MAAM,UAAU,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;gBACvD,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;oBAC5B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACJ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,GAAG,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;gBACrF,CAAC;YACL,CAAC;QACL,CAAC;QACD,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC;QACnC,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAChC,CAAC;IAED;;;OAGG;IACH,eAAe;QACX,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU;YAAE,OAAO,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IACnC,CAAC;IAED,uBAAuB;IACvB,KAAK;QACD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IACzB,CAAC;CACJ"}