@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.
- package/dist/cjs/index.js +19493 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +19398 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/player.css +2140 -0
- package/dist/types/core/ABRController.d.ts +164 -0
- package/dist/types/core/CodecUtils.d.ts +54 -0
- package/dist/types/core/Disposable.d.ts +61 -0
- package/dist/types/core/EventEmitter.d.ts +73 -0
- package/dist/types/core/GatewayClient.d.ts +144 -0
- package/dist/types/core/InteractionController.d.ts +121 -0
- package/dist/types/core/LiveDurationProxy.d.ts +102 -0
- package/dist/types/core/MetaTrackManager.d.ts +220 -0
- package/dist/types/core/MistReporter.d.ts +163 -0
- package/dist/types/core/MistSignaling.d.ts +148 -0
- package/dist/types/core/PlayerController.d.ts +665 -0
- package/dist/types/core/PlayerInterface.d.ts +230 -0
- package/dist/types/core/PlayerManager.d.ts +182 -0
- package/dist/types/core/PlayerRegistry.d.ts +27 -0
- package/dist/types/core/QualityMonitor.d.ts +184 -0
- package/dist/types/core/ScreenWakeLockManager.d.ts +70 -0
- package/dist/types/core/SeekingUtils.d.ts +142 -0
- package/dist/types/core/StreamStateClient.d.ts +108 -0
- package/dist/types/core/SubtitleManager.d.ts +111 -0
- package/dist/types/core/TelemetryReporter.d.ts +79 -0
- package/dist/types/core/TimeFormat.d.ts +97 -0
- package/dist/types/core/TimerManager.d.ts +83 -0
- package/dist/types/core/UrlUtils.d.ts +81 -0
- package/dist/types/core/detector.d.ts +149 -0
- package/dist/types/core/index.d.ts +49 -0
- package/dist/types/core/scorer.d.ts +167 -0
- package/dist/types/core/selector.d.ts +9 -0
- package/dist/types/index.d.ts +45 -0
- package/dist/types/lib/utils.d.ts +2 -0
- package/dist/types/players/DashJsPlayer.d.ts +102 -0
- package/dist/types/players/HlsJsPlayer.d.ts +70 -0
- package/dist/types/players/MewsWsPlayer/SourceBufferManager.d.ts +119 -0
- package/dist/types/players/MewsWsPlayer/WebSocketManager.d.ts +60 -0
- package/dist/types/players/MewsWsPlayer/index.d.ts +220 -0
- package/dist/types/players/MewsWsPlayer/types.d.ts +89 -0
- package/dist/types/players/MistPlayer.d.ts +25 -0
- package/dist/types/players/MistWebRTCPlayer/index.d.ts +133 -0
- package/dist/types/players/NativePlayer.d.ts +143 -0
- package/dist/types/players/VideoJsPlayer.d.ts +59 -0
- package/dist/types/players/WebCodecsPlayer/JitterBuffer.d.ts +118 -0
- package/dist/types/players/WebCodecsPlayer/LatencyProfiles.d.ts +64 -0
- package/dist/types/players/WebCodecsPlayer/RawChunkParser.d.ts +63 -0
- package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +174 -0
- package/dist/types/players/WebCodecsPlayer/WebSocketController.d.ts +164 -0
- package/dist/types/players/WebCodecsPlayer/index.d.ts +149 -0
- package/dist/types/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.d.ts +105 -0
- package/dist/types/players/WebCodecsPlayer/types.d.ts +395 -0
- package/dist/types/players/WebCodecsPlayer/worker/decoder.worker.d.ts +13 -0
- package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +197 -0
- package/dist/types/players/index.d.ts +14 -0
- package/dist/types/styles/index.d.ts +11 -0
- package/dist/types/types.d.ts +363 -0
- package/dist/types/vanilla/FrameWorksPlayer.d.ts +143 -0
- package/dist/types/vanilla/index.d.ts +19 -0
- package/dist/workers/decoder.worker.js +989 -0
- package/dist/workers/decoder.worker.js.map +1 -0
- package/package.json +80 -0
- package/src/core/ABRController.ts +550 -0
- package/src/core/CodecUtils.ts +257 -0
- package/src/core/Disposable.ts +120 -0
- package/src/core/EventEmitter.ts +113 -0
- package/src/core/GatewayClient.ts +439 -0
- package/src/core/InteractionController.ts +712 -0
- package/src/core/LiveDurationProxy.ts +270 -0
- package/src/core/MetaTrackManager.ts +753 -0
- package/src/core/MistReporter.ts +543 -0
- package/src/core/MistSignaling.ts +346 -0
- package/src/core/PlayerController.ts +2829 -0
- package/src/core/PlayerInterface.ts +432 -0
- package/src/core/PlayerManager.ts +900 -0
- package/src/core/PlayerRegistry.ts +149 -0
- package/src/core/QualityMonitor.ts +597 -0
- package/src/core/ScreenWakeLockManager.ts +163 -0
- package/src/core/SeekingUtils.ts +364 -0
- package/src/core/StreamStateClient.ts +457 -0
- package/src/core/SubtitleManager.ts +297 -0
- package/src/core/TelemetryReporter.ts +308 -0
- package/src/core/TimeFormat.ts +205 -0
- package/src/core/TimerManager.ts +209 -0
- package/src/core/UrlUtils.ts +179 -0
- package/src/core/detector.ts +382 -0
- package/src/core/index.ts +140 -0
- package/src/core/scorer.ts +553 -0
- package/src/core/selector.ts +16 -0
- package/src/global.d.ts +11 -0
- package/src/index.ts +75 -0
- package/src/lib/utils.ts +6 -0
- package/src/players/DashJsPlayer.ts +642 -0
- package/src/players/HlsJsPlayer.ts +483 -0
- package/src/players/MewsWsPlayer/SourceBufferManager.ts +572 -0
- package/src/players/MewsWsPlayer/WebSocketManager.ts +241 -0
- package/src/players/MewsWsPlayer/index.ts +1065 -0
- package/src/players/MewsWsPlayer/types.ts +106 -0
- package/src/players/MistPlayer.ts +188 -0
- package/src/players/MistWebRTCPlayer/index.ts +703 -0
- package/src/players/NativePlayer.ts +820 -0
- package/src/players/VideoJsPlayer.ts +643 -0
- package/src/players/WebCodecsPlayer/JitterBuffer.ts +299 -0
- package/src/players/WebCodecsPlayer/LatencyProfiles.ts +151 -0
- package/src/players/WebCodecsPlayer/RawChunkParser.ts +151 -0
- package/src/players/WebCodecsPlayer/SyncController.ts +456 -0
- package/src/players/WebCodecsPlayer/WebSocketController.ts +564 -0
- package/src/players/WebCodecsPlayer/index.ts +1650 -0
- package/src/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.ts +379 -0
- package/src/players/WebCodecsPlayer/types.ts +542 -0
- package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +1360 -0
- package/src/players/WebCodecsPlayer/worker/types.ts +276 -0
- package/src/players/index.ts +22 -0
- package/src/styles/animations.css +21 -0
- package/src/styles/index.ts +52 -0
- package/src/styles/player.css +2126 -0
- package/src/styles/tailwind.css +1015 -0
- package/src/types.ts +421 -0
- package/src/vanilla/FrameWorksPlayer.ts +367 -0
- 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;
|