@livepeer-frameworks/player-core 0.0.3

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 (120) hide show
  1. package/dist/cjs/index.js +19493 -0
  2. package/dist/cjs/index.js.map +1 -0
  3. package/dist/esm/index.js +19398 -0
  4. package/dist/esm/index.js.map +1 -0
  5. package/dist/player.css +2140 -0
  6. package/dist/types/core/ABRController.d.ts +164 -0
  7. package/dist/types/core/CodecUtils.d.ts +54 -0
  8. package/dist/types/core/Disposable.d.ts +61 -0
  9. package/dist/types/core/EventEmitter.d.ts +73 -0
  10. package/dist/types/core/GatewayClient.d.ts +144 -0
  11. package/dist/types/core/InteractionController.d.ts +121 -0
  12. package/dist/types/core/LiveDurationProxy.d.ts +102 -0
  13. package/dist/types/core/MetaTrackManager.d.ts +220 -0
  14. package/dist/types/core/MistReporter.d.ts +163 -0
  15. package/dist/types/core/MistSignaling.d.ts +148 -0
  16. package/dist/types/core/PlayerController.d.ts +665 -0
  17. package/dist/types/core/PlayerInterface.d.ts +230 -0
  18. package/dist/types/core/PlayerManager.d.ts +182 -0
  19. package/dist/types/core/PlayerRegistry.d.ts +27 -0
  20. package/dist/types/core/QualityMonitor.d.ts +184 -0
  21. package/dist/types/core/ScreenWakeLockManager.d.ts +70 -0
  22. package/dist/types/core/SeekingUtils.d.ts +142 -0
  23. package/dist/types/core/StreamStateClient.d.ts +108 -0
  24. package/dist/types/core/SubtitleManager.d.ts +111 -0
  25. package/dist/types/core/TelemetryReporter.d.ts +79 -0
  26. package/dist/types/core/TimeFormat.d.ts +97 -0
  27. package/dist/types/core/TimerManager.d.ts +83 -0
  28. package/dist/types/core/UrlUtils.d.ts +81 -0
  29. package/dist/types/core/detector.d.ts +149 -0
  30. package/dist/types/core/index.d.ts +49 -0
  31. package/dist/types/core/scorer.d.ts +167 -0
  32. package/dist/types/core/selector.d.ts +9 -0
  33. package/dist/types/index.d.ts +45 -0
  34. package/dist/types/lib/utils.d.ts +2 -0
  35. package/dist/types/players/DashJsPlayer.d.ts +102 -0
  36. package/dist/types/players/HlsJsPlayer.d.ts +70 -0
  37. package/dist/types/players/MewsWsPlayer/SourceBufferManager.d.ts +119 -0
  38. package/dist/types/players/MewsWsPlayer/WebSocketManager.d.ts +60 -0
  39. package/dist/types/players/MewsWsPlayer/index.d.ts +220 -0
  40. package/dist/types/players/MewsWsPlayer/types.d.ts +89 -0
  41. package/dist/types/players/MistPlayer.d.ts +25 -0
  42. package/dist/types/players/MistWebRTCPlayer/index.d.ts +133 -0
  43. package/dist/types/players/NativePlayer.d.ts +143 -0
  44. package/dist/types/players/VideoJsPlayer.d.ts +59 -0
  45. package/dist/types/players/WebCodecsPlayer/JitterBuffer.d.ts +118 -0
  46. package/dist/types/players/WebCodecsPlayer/LatencyProfiles.d.ts +64 -0
  47. package/dist/types/players/WebCodecsPlayer/RawChunkParser.d.ts +63 -0
  48. package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +174 -0
  49. package/dist/types/players/WebCodecsPlayer/WebSocketController.d.ts +164 -0
  50. package/dist/types/players/WebCodecsPlayer/index.d.ts +149 -0
  51. package/dist/types/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.d.ts +105 -0
  52. package/dist/types/players/WebCodecsPlayer/types.d.ts +395 -0
  53. package/dist/types/players/WebCodecsPlayer/worker/decoder.worker.d.ts +13 -0
  54. package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +197 -0
  55. package/dist/types/players/index.d.ts +14 -0
  56. package/dist/types/styles/index.d.ts +11 -0
  57. package/dist/types/types.d.ts +363 -0
  58. package/dist/types/vanilla/FrameWorksPlayer.d.ts +143 -0
  59. package/dist/types/vanilla/index.d.ts +19 -0
  60. package/dist/workers/decoder.worker.js +989 -0
  61. package/dist/workers/decoder.worker.js.map +1 -0
  62. package/package.json +80 -0
  63. package/src/core/ABRController.ts +550 -0
  64. package/src/core/CodecUtils.ts +257 -0
  65. package/src/core/Disposable.ts +120 -0
  66. package/src/core/EventEmitter.ts +113 -0
  67. package/src/core/GatewayClient.ts +439 -0
  68. package/src/core/InteractionController.ts +712 -0
  69. package/src/core/LiveDurationProxy.ts +270 -0
  70. package/src/core/MetaTrackManager.ts +753 -0
  71. package/src/core/MistReporter.ts +543 -0
  72. package/src/core/MistSignaling.ts +346 -0
  73. package/src/core/PlayerController.ts +2829 -0
  74. package/src/core/PlayerInterface.ts +432 -0
  75. package/src/core/PlayerManager.ts +900 -0
  76. package/src/core/PlayerRegistry.ts +149 -0
  77. package/src/core/QualityMonitor.ts +597 -0
  78. package/src/core/ScreenWakeLockManager.ts +163 -0
  79. package/src/core/SeekingUtils.ts +364 -0
  80. package/src/core/StreamStateClient.ts +457 -0
  81. package/src/core/SubtitleManager.ts +297 -0
  82. package/src/core/TelemetryReporter.ts +308 -0
  83. package/src/core/TimeFormat.ts +205 -0
  84. package/src/core/TimerManager.ts +209 -0
  85. package/src/core/UrlUtils.ts +179 -0
  86. package/src/core/detector.ts +382 -0
  87. package/src/core/index.ts +140 -0
  88. package/src/core/scorer.ts +553 -0
  89. package/src/core/selector.ts +16 -0
  90. package/src/global.d.ts +11 -0
  91. package/src/index.ts +75 -0
  92. package/src/lib/utils.ts +6 -0
  93. package/src/players/DashJsPlayer.ts +642 -0
  94. package/src/players/HlsJsPlayer.ts +483 -0
  95. package/src/players/MewsWsPlayer/SourceBufferManager.ts +572 -0
  96. package/src/players/MewsWsPlayer/WebSocketManager.ts +241 -0
  97. package/src/players/MewsWsPlayer/index.ts +1065 -0
  98. package/src/players/MewsWsPlayer/types.ts +106 -0
  99. package/src/players/MistPlayer.ts +188 -0
  100. package/src/players/MistWebRTCPlayer/index.ts +703 -0
  101. package/src/players/NativePlayer.ts +820 -0
  102. package/src/players/VideoJsPlayer.ts +643 -0
  103. package/src/players/WebCodecsPlayer/JitterBuffer.ts +299 -0
  104. package/src/players/WebCodecsPlayer/LatencyProfiles.ts +151 -0
  105. package/src/players/WebCodecsPlayer/RawChunkParser.ts +151 -0
  106. package/src/players/WebCodecsPlayer/SyncController.ts +456 -0
  107. package/src/players/WebCodecsPlayer/WebSocketController.ts +564 -0
  108. package/src/players/WebCodecsPlayer/index.ts +1650 -0
  109. package/src/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.ts +379 -0
  110. package/src/players/WebCodecsPlayer/types.ts +542 -0
  111. package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +1360 -0
  112. package/src/players/WebCodecsPlayer/worker/types.ts +276 -0
  113. package/src/players/index.ts +22 -0
  114. package/src/styles/animations.css +21 -0
  115. package/src/styles/index.ts +52 -0
  116. package/src/styles/player.css +2126 -0
  117. package/src/styles/tailwind.css +1015 -0
  118. package/src/types.ts +421 -0
  119. package/src/vanilla/FrameWorksPlayer.ts +367 -0
  120. package/src/vanilla/index.ts +22 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * LiveDurationProxy - Wraps video element to provide meaningful duration for live streams
3
+ *
4
+ * Live streams report `Infinity` or `NaN` for duration, breaking seek bars and time display.
5
+ * This proxy intercepts the duration getter and returns a calculated value based on:
6
+ * - Buffer end position
7
+ * - Elapsed time since last progress event
8
+ *
9
+ * Based on MistMetaPlayer reference implementation (wrappers/html5.js, dashjs.js)
10
+ */
11
+
12
+ export interface LiveDurationProxyOptions {
13
+ /** Whether to constrain seeking to buffered range (default: true) */
14
+ constrainSeek?: boolean;
15
+ /** Live offset from buffer end in seconds (default: 0) */
16
+ liveOffset?: number;
17
+ /** Callback when duration changes */
18
+ onDurationChange?: (duration: number) => void;
19
+ }
20
+
21
+ export interface LiveDurationState {
22
+ /** Calculated duration */
23
+ duration: number;
24
+ /** Whether stream is live */
25
+ isLive: boolean;
26
+ /** Buffer end position */
27
+ bufferEnd: number;
28
+ /** Time since last progress */
29
+ elapsed: number;
30
+ }
31
+
32
+ /**
33
+ * Creates a proxy wrapper around a video element that provides meaningful
34
+ * duration values for live streams.
35
+ */
36
+ export class LiveDurationProxy {
37
+ private video: HTMLVideoElement;
38
+ private options: Required<LiveDurationProxyOptions>;
39
+ private lastProgressTime: number = 0;
40
+ private lastBufferEnd: number = 0;
41
+ private listeners: Array<() => void> = [];
42
+ private _calculatedDuration: number = 0;
43
+
44
+ constructor(video: HTMLVideoElement, options: LiveDurationProxyOptions = {}) {
45
+ this.video = video;
46
+ this.options = {
47
+ constrainSeek: options.constrainSeek ?? true,
48
+ liveOffset: options.liveOffset ?? 0,
49
+ onDurationChange: options.onDurationChange ?? (() => {}),
50
+ };
51
+
52
+ this.setupListeners();
53
+ this.updateDuration();
54
+ }
55
+
56
+ /**
57
+ * Check if the stream is live
58
+ */
59
+ isLive(): boolean {
60
+ const nativeDuration = this.video.duration;
61
+ return !isFinite(nativeDuration) || nativeDuration === Infinity;
62
+ }
63
+
64
+ /**
65
+ * Get the calculated duration
66
+ * For live: bufferEnd + elapsedSinceLastProgress
67
+ * For VOD: native duration
68
+ */
69
+ getDuration(): number {
70
+ if (!this.isLive()) {
71
+ return this.video.duration;
72
+ }
73
+ return this._calculatedDuration;
74
+ }
75
+
76
+ /**
77
+ * Get the current buffer end position
78
+ */
79
+ getBufferEnd(): number {
80
+ const buffered = this.video.buffered;
81
+ if (buffered.length === 0) return 0;
82
+
83
+ // Find the buffer range containing current time, or the last one
84
+ for (let i = 0; i < buffered.length; i++) {
85
+ if (buffered.start(i) <= this.video.currentTime && buffered.end(i) > this.video.currentTime) {
86
+ return buffered.end(i);
87
+ }
88
+ }
89
+
90
+ // Return the end of the last buffer range
91
+ return buffered.end(buffered.length - 1);
92
+ }
93
+
94
+ /**
95
+ * Get the live edge position (where live is)
96
+ */
97
+ getLiveEdge(): number {
98
+ return this.getBufferEnd() - this.options.liveOffset;
99
+ }
100
+
101
+ /**
102
+ * Get the current latency (distance from live edge)
103
+ */
104
+ getLatency(): number {
105
+ if (!this.isLive()) return 0;
106
+ return Math.max(0, this.getLiveEdge() - this.video.currentTime);
107
+ }
108
+
109
+ /**
110
+ * Seek to a position, respecting live constraints
111
+ */
112
+ seek(time: number): void {
113
+ if (!this.isLive() || !this.options.constrainSeek) {
114
+ this.video.currentTime = time;
115
+ return;
116
+ }
117
+
118
+ // Constrain to buffered range for live
119
+ const buffered = this.video.buffered;
120
+ if (buffered.length === 0) {
121
+ this.video.currentTime = time;
122
+ return;
123
+ }
124
+
125
+ // Find valid seek range
126
+ const bufferStart = buffered.start(0);
127
+ const bufferEnd = this.getBufferEnd();
128
+ const liveEdge = this.getLiveEdge();
129
+
130
+ // Clamp to valid range
131
+ const clampedTime = Math.max(bufferStart, Math.min(time, liveEdge));
132
+ this.video.currentTime = clampedTime;
133
+ }
134
+
135
+ /**
136
+ * Jump to live edge
137
+ */
138
+ jumpToLive(): void {
139
+ if (!this.isLive()) return;
140
+ this.video.currentTime = this.getLiveEdge();
141
+ }
142
+
143
+ /**
144
+ * Check if currently at live edge (within threshold)
145
+ */
146
+ isAtLiveEdge(threshold: number = 2): boolean {
147
+ if (!this.isLive()) return false;
148
+ return this.getLatency() <= threshold;
149
+ }
150
+
151
+ /**
152
+ * Get current state
153
+ */
154
+ getState(): LiveDurationState {
155
+ return {
156
+ duration: this.getDuration(),
157
+ isLive: this.isLive(),
158
+ bufferEnd: this.getBufferEnd(),
159
+ elapsed: this.lastProgressTime > 0 ? (Date.now() - this.lastProgressTime) / 1000 : 0,
160
+ };
161
+ }
162
+
163
+ /**
164
+ * Update the calculated duration
165
+ */
166
+ private updateDuration(): void {
167
+ if (!this.isLive()) {
168
+ this._calculatedDuration = this.video.duration;
169
+ return;
170
+ }
171
+
172
+ const bufferEnd = this.getBufferEnd();
173
+ const now = Date.now();
174
+ const elapsedSinceProgress = this.lastProgressTime > 0
175
+ ? (now - this.lastProgressTime) / 1000
176
+ : 0;
177
+
178
+ // MistPlayer formula: buffer_end + elapsed_since_last_progress
179
+ const newDuration = bufferEnd + elapsedSinceProgress;
180
+
181
+ // Only update if changed significantly (avoid constant updates)
182
+ if (Math.abs(newDuration - this._calculatedDuration) > 0.1) {
183
+ this._calculatedDuration = newDuration;
184
+ this.options.onDurationChange(newDuration);
185
+ }
186
+
187
+ this.lastBufferEnd = bufferEnd;
188
+ }
189
+
190
+ /**
191
+ * Setup event listeners for tracking
192
+ */
193
+ private setupListeners(): void {
194
+ const onProgress = () => {
195
+ this.lastProgressTime = Date.now();
196
+ this.updateDuration();
197
+ };
198
+
199
+ const onTimeUpdate = () => {
200
+ this.updateDuration();
201
+ };
202
+
203
+ const onDurationChange = () => {
204
+ this.updateDuration();
205
+ };
206
+
207
+ const onLoadedMetadata = () => {
208
+ this.updateDuration();
209
+ };
210
+
211
+ this.video.addEventListener('progress', onProgress);
212
+ this.video.addEventListener('timeupdate', onTimeUpdate);
213
+ this.video.addEventListener('durationchange', onDurationChange);
214
+ this.video.addEventListener('loadedmetadata', onLoadedMetadata);
215
+
216
+ this.listeners = [
217
+ () => this.video.removeEventListener('progress', onProgress),
218
+ () => this.video.removeEventListener('timeupdate', onTimeUpdate),
219
+ () => this.video.removeEventListener('durationchange', onDurationChange),
220
+ () => this.video.removeEventListener('loadedmetadata', onLoadedMetadata),
221
+ ];
222
+ }
223
+
224
+ /**
225
+ * Cleanup
226
+ */
227
+ destroy(): void {
228
+ this.listeners.forEach(cleanup => cleanup());
229
+ this.listeners = [];
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Create a Proxy wrapper for a video element that intercepts duration/currentTime
235
+ * This allows existing code to work transparently with live streams.
236
+ *
237
+ * Note: This is an advanced feature - for most cases, use LiveDurationProxy directly.
238
+ */
239
+ export function createLiveVideoProxy(
240
+ video: HTMLVideoElement,
241
+ options: LiveDurationProxyOptions = {}
242
+ ): { proxy: HTMLVideoElement; controller: LiveDurationProxy } {
243
+ const controller = new LiveDurationProxy(video, options);
244
+
245
+ const proxy = new Proxy(video, {
246
+ get(target, prop, receiver) {
247
+ if (prop === 'duration') {
248
+ return controller.getDuration();
249
+ }
250
+
251
+ const value = Reflect.get(target, prop, receiver);
252
+ if (typeof value === 'function') {
253
+ return value.bind(target);
254
+ }
255
+ return value;
256
+ },
257
+
258
+ set(target, prop, value, receiver) {
259
+ if (prop === 'currentTime' && controller.isLive()) {
260
+ controller.seek(value as number);
261
+ return true;
262
+ }
263
+ return Reflect.set(target, prop, value, receiver);
264
+ },
265
+ });
266
+
267
+ return { proxy: proxy as HTMLVideoElement, controller };
268
+ }
269
+
270
+ export default LiveDurationProxy;