@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,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common Player Interface
|
|
3
|
+
*
|
|
4
|
+
* All player implementations must implement this interface to ensure
|
|
5
|
+
* consistent behavior and enable the PlayerManager selection system
|
|
6
|
+
*/
|
|
7
|
+
export interface StreamSource {
|
|
8
|
+
url: string;
|
|
9
|
+
type: string;
|
|
10
|
+
index?: number;
|
|
11
|
+
streamName?: string;
|
|
12
|
+
mistPlayerUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface StreamTrack {
|
|
15
|
+
type: 'video' | 'audio' | 'meta';
|
|
16
|
+
codec: string;
|
|
17
|
+
codecstring?: string;
|
|
18
|
+
init?: string;
|
|
19
|
+
/** Track index from MistServer (used for binary chunk routing) */
|
|
20
|
+
idx?: number;
|
|
21
|
+
width?: number;
|
|
22
|
+
height?: number;
|
|
23
|
+
fpks?: number;
|
|
24
|
+
channels?: number;
|
|
25
|
+
rate?: number;
|
|
26
|
+
size?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface StreamInfo {
|
|
29
|
+
source: StreamSource[];
|
|
30
|
+
meta: {
|
|
31
|
+
tracks: StreamTrack[];
|
|
32
|
+
};
|
|
33
|
+
type?: 'live' | 'vod';
|
|
34
|
+
}
|
|
35
|
+
export interface PlayerOptions {
|
|
36
|
+
autoplay?: boolean;
|
|
37
|
+
muted?: boolean;
|
|
38
|
+
controls?: boolean;
|
|
39
|
+
loop?: boolean;
|
|
40
|
+
poster?: string;
|
|
41
|
+
width?: number;
|
|
42
|
+
height?: number;
|
|
43
|
+
/** Enable dev mode - for Legacy player, uses MistServer's dev skin with source selection */
|
|
44
|
+
devMode?: boolean;
|
|
45
|
+
onReady?: (element: HTMLVideoElement) => void;
|
|
46
|
+
onError?: (error: string | Error) => void;
|
|
47
|
+
onPlay?: () => void;
|
|
48
|
+
onPause?: () => void;
|
|
49
|
+
onEnded?: () => void;
|
|
50
|
+
onTimeUpdate?: (currentTime: number) => void;
|
|
51
|
+
onWaiting?: () => void;
|
|
52
|
+
onPlaying?: () => void;
|
|
53
|
+
onCanPlay?: () => void;
|
|
54
|
+
onDurationChange?: (duration: number) => void;
|
|
55
|
+
}
|
|
56
|
+
export interface PlayerCapability {
|
|
57
|
+
/** Player name for display */
|
|
58
|
+
name: string;
|
|
59
|
+
/** Unique identifier */
|
|
60
|
+
shortname: string;
|
|
61
|
+
/** Priority (lower number = higher priority) */
|
|
62
|
+
priority: number;
|
|
63
|
+
/** MIME types this player can handle */
|
|
64
|
+
mimes: string[];
|
|
65
|
+
}
|
|
66
|
+
export interface PlayerEvents {
|
|
67
|
+
ready: HTMLVideoElement;
|
|
68
|
+
error: string | Error;
|
|
69
|
+
play: void;
|
|
70
|
+
pause: void;
|
|
71
|
+
ended: void;
|
|
72
|
+
timeupdate: number;
|
|
73
|
+
/** Request to reload the player (e.g., Firefox segment error recovery) */
|
|
74
|
+
reloadrequested: {
|
|
75
|
+
reason: string;
|
|
76
|
+
};
|
|
77
|
+
/** Seekable range changed */
|
|
78
|
+
seekablechange: {
|
|
79
|
+
start: number;
|
|
80
|
+
end: number;
|
|
81
|
+
bufferWindow: number;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Base interface all players must implement
|
|
86
|
+
*/
|
|
87
|
+
export interface IPlayer {
|
|
88
|
+
/** Player metadata */
|
|
89
|
+
readonly capability: PlayerCapability;
|
|
90
|
+
/**
|
|
91
|
+
* Check if this player supports the given MIME type
|
|
92
|
+
*/
|
|
93
|
+
isMimeSupported(mimetype: string): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Check if this player can play in the current browser environment
|
|
96
|
+
* @param mimetype - MIME type to test
|
|
97
|
+
* @param source - Source information
|
|
98
|
+
* @param streamInfo - Stream metadata
|
|
99
|
+
* @returns false if not supported, true if supported (no track info),
|
|
100
|
+
* or array of supported track types
|
|
101
|
+
*/
|
|
102
|
+
isBrowserSupported(mimetype: string, source: StreamSource, streamInfo: StreamInfo): boolean | string[];
|
|
103
|
+
/**
|
|
104
|
+
* Initialize the player with given source and options
|
|
105
|
+
* @param container - Container element to render in
|
|
106
|
+
* @param source - Source to play
|
|
107
|
+
* @param options - Player options
|
|
108
|
+
* @param streamInfo - Full stream metadata (optional, for players that need track details)
|
|
109
|
+
* @returns Promise resolving to video element
|
|
110
|
+
*/
|
|
111
|
+
initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions, streamInfo?: StreamInfo): Promise<HTMLVideoElement>;
|
|
112
|
+
/**
|
|
113
|
+
* Clean up and destroy the player.
|
|
114
|
+
* May be async if cleanup requires network requests (e.g., WHEP session DELETE).
|
|
115
|
+
*/
|
|
116
|
+
destroy(): void | Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Get the underlying video element (if available)
|
|
119
|
+
*/
|
|
120
|
+
getVideoElement(): HTMLVideoElement | null;
|
|
121
|
+
/**
|
|
122
|
+
* Set video size
|
|
123
|
+
*/
|
|
124
|
+
setSize?(width: number, height: number): void;
|
|
125
|
+
/**
|
|
126
|
+
* Add event listener
|
|
127
|
+
*/
|
|
128
|
+
on<K extends keyof PlayerEvents>(event: K, listener: (data: PlayerEvents[K]) => void): void;
|
|
129
|
+
/**
|
|
130
|
+
* Remove event listener
|
|
131
|
+
*/
|
|
132
|
+
off<K extends keyof PlayerEvents>(event: K, listener: (data: PlayerEvents[K]) => void): void;
|
|
133
|
+
/**
|
|
134
|
+
* Get current playback state
|
|
135
|
+
*/
|
|
136
|
+
getCurrentTime?(): number;
|
|
137
|
+
getDuration?(): number;
|
|
138
|
+
isPaused?(): boolean;
|
|
139
|
+
isMuted?(): boolean;
|
|
140
|
+
/** Optional: provide an override seekable range (seconds) */
|
|
141
|
+
getSeekableRange?(): {
|
|
142
|
+
start: number;
|
|
143
|
+
end: number;
|
|
144
|
+
} | null;
|
|
145
|
+
/** Optional: provide buffered ranges override */
|
|
146
|
+
getBufferedRanges?(): TimeRanges | null;
|
|
147
|
+
/**
|
|
148
|
+
* Control playback
|
|
149
|
+
*/
|
|
150
|
+
play?(): Promise<void>;
|
|
151
|
+
pause?(): void;
|
|
152
|
+
seek?(time: number): void;
|
|
153
|
+
setVolume?(volume: number): void;
|
|
154
|
+
setMuted?(muted: boolean): void;
|
|
155
|
+
setPlaybackRate?(rate: number): void;
|
|
156
|
+
getTextTracks?(): Array<{
|
|
157
|
+
id: string;
|
|
158
|
+
label: string;
|
|
159
|
+
lang?: string;
|
|
160
|
+
active: boolean;
|
|
161
|
+
}>;
|
|
162
|
+
selectTextTrack?(id: string | null): void;
|
|
163
|
+
getQualities?(): Array<{
|
|
164
|
+
id: string;
|
|
165
|
+
label: string;
|
|
166
|
+
bitrate?: number;
|
|
167
|
+
width?: number;
|
|
168
|
+
height?: number;
|
|
169
|
+
isAuto?: boolean;
|
|
170
|
+
active?: boolean;
|
|
171
|
+
}>;
|
|
172
|
+
selectQuality?(id: string): void;
|
|
173
|
+
getCurrentQuality?(): string | null;
|
|
174
|
+
isLive?(): boolean;
|
|
175
|
+
jumpToLive?(): void;
|
|
176
|
+
requestPiP?(): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Optional: Retrieve player-specific stats (e.g., WebRTC inbound-rtp)
|
|
179
|
+
*/
|
|
180
|
+
getStats?(): Promise<any>;
|
|
181
|
+
/**
|
|
182
|
+
* Optional: Retrieve approximate playback latency stats
|
|
183
|
+
*/
|
|
184
|
+
getLatency?(): Promise<any>;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Base class providing common functionality
|
|
188
|
+
*/
|
|
189
|
+
export declare abstract class BasePlayer implements IPlayer {
|
|
190
|
+
abstract readonly capability: PlayerCapability;
|
|
191
|
+
protected listeners: Map<string, Set<Function>>;
|
|
192
|
+
protected videoElement: HTMLVideoElement | null;
|
|
193
|
+
abstract isMimeSupported(mimetype: string): boolean;
|
|
194
|
+
abstract isBrowserSupported(mimetype: string, source: StreamSource, streamInfo: StreamInfo): boolean | string[];
|
|
195
|
+
abstract initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions, streamInfo?: StreamInfo): Promise<HTMLVideoElement>;
|
|
196
|
+
abstract destroy(): void | Promise<void>;
|
|
197
|
+
getVideoElement(): HTMLVideoElement | null;
|
|
198
|
+
on<K extends keyof PlayerEvents>(event: K, listener: (data: PlayerEvents[K]) => void): void;
|
|
199
|
+
off<K extends keyof PlayerEvents>(event: K, listener: (data: PlayerEvents[K]) => void): void;
|
|
200
|
+
protected emit<K extends keyof PlayerEvents>(event: K, data: PlayerEvents[K]): void;
|
|
201
|
+
protected setupVideoEventListeners(video: HTMLVideoElement, options: PlayerOptions): void;
|
|
202
|
+
getCurrentTime(): number;
|
|
203
|
+
getDuration(): number;
|
|
204
|
+
getSeekableRange(): {
|
|
205
|
+
start: number;
|
|
206
|
+
end: number;
|
|
207
|
+
} | null;
|
|
208
|
+
getBufferedRanges(): TimeRanges | null;
|
|
209
|
+
isPaused(): boolean;
|
|
210
|
+
isMuted(): boolean;
|
|
211
|
+
play(): Promise<void>;
|
|
212
|
+
pause(): void;
|
|
213
|
+
seek(time: number): void;
|
|
214
|
+
setVolume(volume: number): void;
|
|
215
|
+
setMuted(muted: boolean): void;
|
|
216
|
+
setPlaybackRate(rate: number): void;
|
|
217
|
+
getTextTracks(): Array<{
|
|
218
|
+
id: string;
|
|
219
|
+
label: string;
|
|
220
|
+
lang?: string;
|
|
221
|
+
active: boolean;
|
|
222
|
+
}>;
|
|
223
|
+
selectTextTrack(id: string | null): void;
|
|
224
|
+
isLive(): boolean;
|
|
225
|
+
jumpToLive(): void;
|
|
226
|
+
requestPiP(): Promise<void>;
|
|
227
|
+
setSize(width: number, height: number): void;
|
|
228
|
+
getStats(): Promise<any>;
|
|
229
|
+
getLatency(): Promise<any>;
|
|
230
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PlayerManager
|
|
3
|
+
*
|
|
4
|
+
* Central orchestrator for player selection and lifecycle management.
|
|
5
|
+
* Single source of truth for all scoring logic.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - `getAllCombinations()` is THE single function that computes player+source scores
|
|
9
|
+
* - Results are cached by content (source types + track codecs), not object identity
|
|
10
|
+
* - Events fire only when selection actually changes (no render spam)
|
|
11
|
+
* - `selectBestPlayer()` returns cached winner without recomputation
|
|
12
|
+
*/
|
|
13
|
+
import { IPlayer, StreamSource, StreamInfo, PlayerOptions } from './PlayerInterface';
|
|
14
|
+
import type { PlaybackMode } from '../types';
|
|
15
|
+
export interface PlayerSelection {
|
|
16
|
+
score: number;
|
|
17
|
+
player: string;
|
|
18
|
+
source: StreamSource;
|
|
19
|
+
source_index: number;
|
|
20
|
+
}
|
|
21
|
+
export interface PlayerManagerOptions {
|
|
22
|
+
/** Force a specific player */
|
|
23
|
+
forcePlayer?: string;
|
|
24
|
+
/** Force a specific source index */
|
|
25
|
+
forceSource?: number;
|
|
26
|
+
/** Force a specific MIME type */
|
|
27
|
+
forceType?: string;
|
|
28
|
+
/** Enable debug logging (logs selection changes only, not every render) */
|
|
29
|
+
debug?: boolean;
|
|
30
|
+
/** Automatic fallback on player failure */
|
|
31
|
+
autoFallback?: boolean;
|
|
32
|
+
/** Maximum fallback attempts */
|
|
33
|
+
maxFallbackAttempts?: number;
|
|
34
|
+
/** Playback mode for protocol selection */
|
|
35
|
+
playbackMode?: PlaybackMode;
|
|
36
|
+
}
|
|
37
|
+
export interface PlayerManagerEvents {
|
|
38
|
+
playerSelected: {
|
|
39
|
+
player: string;
|
|
40
|
+
source: StreamSource;
|
|
41
|
+
score: number;
|
|
42
|
+
};
|
|
43
|
+
playerInitialized: {
|
|
44
|
+
player: IPlayer;
|
|
45
|
+
videoElement: HTMLVideoElement;
|
|
46
|
+
};
|
|
47
|
+
playerFailed: {
|
|
48
|
+
player: string;
|
|
49
|
+
error: string;
|
|
50
|
+
};
|
|
51
|
+
fallbackAttempted: {
|
|
52
|
+
fromPlayer: string;
|
|
53
|
+
toPlayer: string;
|
|
54
|
+
};
|
|
55
|
+
/** Fires when selection changes (different player+source than before) */
|
|
56
|
+
'selection-changed': PlayerSelection | null;
|
|
57
|
+
/** Fires when combinations are recomputed (cache miss) */
|
|
58
|
+
'combinations-updated': PlayerCombination[];
|
|
59
|
+
}
|
|
60
|
+
/** Full combination info including scoring breakdown */
|
|
61
|
+
export interface PlayerCombination {
|
|
62
|
+
player: string;
|
|
63
|
+
playerName: string;
|
|
64
|
+
source: StreamSource;
|
|
65
|
+
sourceIndex: number;
|
|
66
|
+
sourceType: string;
|
|
67
|
+
score: number;
|
|
68
|
+
compatible: boolean;
|
|
69
|
+
incompatibleReason?: string;
|
|
70
|
+
/** True when player supports MIME but codec is incompatible */
|
|
71
|
+
codecIncompatible?: boolean;
|
|
72
|
+
scoreBreakdown?: {
|
|
73
|
+
trackScore: number;
|
|
74
|
+
trackTypes: string[];
|
|
75
|
+
priorityScore: number;
|
|
76
|
+
sourceScore: number;
|
|
77
|
+
reliabilityScore?: number;
|
|
78
|
+
modeBonus?: number;
|
|
79
|
+
routingBonus?: number;
|
|
80
|
+
weights: {
|
|
81
|
+
tracks: number;
|
|
82
|
+
priority: number;
|
|
83
|
+
source: number;
|
|
84
|
+
reliability?: number;
|
|
85
|
+
mode?: number;
|
|
86
|
+
routing?: number;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export declare class PlayerManager {
|
|
91
|
+
private players;
|
|
92
|
+
private currentPlayer;
|
|
93
|
+
private listeners;
|
|
94
|
+
private fallbackAttempts;
|
|
95
|
+
private options;
|
|
96
|
+
private cachedCombinations;
|
|
97
|
+
private cachedSelection;
|
|
98
|
+
private cacheKey;
|
|
99
|
+
private lastLoggedWinner;
|
|
100
|
+
private lastContainer;
|
|
101
|
+
private lastStreamInfo;
|
|
102
|
+
private lastPlayerOptions;
|
|
103
|
+
private lastManagerOptions;
|
|
104
|
+
private excludedPlayers;
|
|
105
|
+
private opQueue;
|
|
106
|
+
constructor(options?: PlayerManagerOptions);
|
|
107
|
+
registerPlayer(player: IPlayer): void;
|
|
108
|
+
unregisterPlayer(shortname: string): void;
|
|
109
|
+
getRegisteredPlayers(): IPlayer[];
|
|
110
|
+
/**
|
|
111
|
+
* Compute cache key based on CONTENT, not object identity.
|
|
112
|
+
* Prevents recalculation when streamInfo is a new object with same data.
|
|
113
|
+
*/
|
|
114
|
+
private computeCacheKey;
|
|
115
|
+
/** Invalidate cache (called when player registrations change) */
|
|
116
|
+
invalidateCache(): void;
|
|
117
|
+
/** Get cached selection without recomputing */
|
|
118
|
+
getCurrentSelection(): PlayerSelection | null;
|
|
119
|
+
/** Get cached combinations without recomputing */
|
|
120
|
+
getCachedCombinations(): PlayerCombination[] | null;
|
|
121
|
+
/**
|
|
122
|
+
* THE single source of truth for player+source scoring.
|
|
123
|
+
* Returns ALL combinations (compatible and incompatible) with scores.
|
|
124
|
+
* Results are cached - won't recompute if source types/tracks haven't changed.
|
|
125
|
+
*/
|
|
126
|
+
getAllCombinations(streamInfo: StreamInfo, playbackMode?: PlaybackMode): PlayerCombination[];
|
|
127
|
+
/**
|
|
128
|
+
* Select the best player for given stream info.
|
|
129
|
+
* Uses cached combinations - won't recompute if data hasn't changed.
|
|
130
|
+
*/
|
|
131
|
+
selectBestPlayer(streamInfo: StreamInfo, options?: PlayerManagerOptions): PlayerSelection | false;
|
|
132
|
+
/**
|
|
133
|
+
* Internal: compute all combinations (no caching)
|
|
134
|
+
*/
|
|
135
|
+
private computeAllCombinations;
|
|
136
|
+
/**
|
|
137
|
+
* Pick best compatible combination
|
|
138
|
+
*/
|
|
139
|
+
private pickBestFromCombinations;
|
|
140
|
+
/**
|
|
141
|
+
* Check if selection changed
|
|
142
|
+
*/
|
|
143
|
+
private hasSelectionChanged;
|
|
144
|
+
private enqueueOp;
|
|
145
|
+
initializePlayer(container: HTMLElement, streamInfo: StreamInfo, playerOptions?: PlayerOptions, managerOptions?: PlayerManagerOptions): Promise<HTMLVideoElement>;
|
|
146
|
+
private tryInitializePlayer;
|
|
147
|
+
tryPlaybackFallback(): Promise<boolean>;
|
|
148
|
+
getRemainingFallbackAttempts(): number;
|
|
149
|
+
canAttemptFallback(): boolean;
|
|
150
|
+
getCurrentPlayer(): IPlayer | null;
|
|
151
|
+
getBrowserCapabilities(): {
|
|
152
|
+
browser: import("./detector").BrowserInfo;
|
|
153
|
+
compatibility: {
|
|
154
|
+
supportsNativeHLS: boolean | 0 | null;
|
|
155
|
+
supportsMSE: boolean;
|
|
156
|
+
supportsWebSocket: boolean;
|
|
157
|
+
supportsWebRTC: boolean;
|
|
158
|
+
preferVideoJs: boolean | 0 | null;
|
|
159
|
+
avoidMEWSOnMac: boolean;
|
|
160
|
+
fileProtocolLimitations: boolean;
|
|
161
|
+
};
|
|
162
|
+
supportedMimeTypes: string[];
|
|
163
|
+
availablePlayers: {
|
|
164
|
+
name: string;
|
|
165
|
+
shortname: string;
|
|
166
|
+
priority: number;
|
|
167
|
+
mimes: string[];
|
|
168
|
+
}[];
|
|
169
|
+
};
|
|
170
|
+
private getSupportedMimeTypes;
|
|
171
|
+
private getAvailablePlayerInfo;
|
|
172
|
+
destroy(): Promise<void>;
|
|
173
|
+
removeAllListeners(): void;
|
|
174
|
+
on<K extends keyof PlayerManagerEvents>(event: K, listener: (data: PlayerManagerEvents[K]) => void): () => void;
|
|
175
|
+
off<K extends keyof PlayerManagerEvents>(event: K, listener: (data: PlayerManagerEvents[K]) => void): void;
|
|
176
|
+
private emit;
|
|
177
|
+
private log;
|
|
178
|
+
testSource(source: StreamSource, streamInfo: StreamInfo): Promise<{
|
|
179
|
+
canPlay: boolean;
|
|
180
|
+
players: string[];
|
|
181
|
+
}>;
|
|
182
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Player Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registration of all available player implementations
|
|
5
|
+
*/
|
|
6
|
+
import { PlayerManager } from './PlayerManager';
|
|
7
|
+
export declare function ensurePlayersRegistered(manager?: PlayerManager): Promise<void>;
|
|
8
|
+
export declare const globalPlayerManager: PlayerManager;
|
|
9
|
+
/**
|
|
10
|
+
* Register all available players (async for backwards compatibility)
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerAllPlayers(manager?: PlayerManager): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Create a new PlayerManager instance with all players registered
|
|
15
|
+
*/
|
|
16
|
+
export declare function createPlayerManager(options?: ConstructorParameters<typeof PlayerManager>[0]): PlayerManager;
|
|
17
|
+
/**
|
|
18
|
+
* Export individual player classes for direct use
|
|
19
|
+
*/
|
|
20
|
+
export { NativePlayerImpl, DirectPlaybackPlayerImpl } from '../players/NativePlayer';
|
|
21
|
+
export { HlsJsPlayerImpl } from '../players/HlsJsPlayer';
|
|
22
|
+
export { DashJsPlayerImpl } from '../players/DashJsPlayer';
|
|
23
|
+
export { VideoJsPlayerImpl } from '../players/VideoJsPlayer';
|
|
24
|
+
export { MistPlayerImpl } from '../players/MistPlayer';
|
|
25
|
+
export { MewsWsPlayerImpl } from '../players/MewsWsPlayer';
|
|
26
|
+
export { MistWebRTCPlayerImpl } from '../players/MistWebRTCPlayer';
|
|
27
|
+
export { WebCodecsPlayerImpl } from '../players/WebCodecsPlayer';
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { PlaybackQuality, QualityThresholds } from '../types';
|
|
2
|
+
/** Protocol type for threshold selection */
|
|
3
|
+
export type PlayerProtocol = 'webrtc' | 'hls' | 'dash' | 'html5' | 'unknown';
|
|
4
|
+
/** Protocol-specific playback score thresholds (MistMetaPlayer reference) */
|
|
5
|
+
export declare const PROTOCOL_THRESHOLDS: Record<PlayerProtocol, number>;
|
|
6
|
+
export interface QualityMonitorOptions {
|
|
7
|
+
/** Sample interval in ms */
|
|
8
|
+
sampleInterval?: number;
|
|
9
|
+
/** Quality thresholds */
|
|
10
|
+
thresholds?: Partial<QualityThresholds>;
|
|
11
|
+
/** Callback when quality degrades */
|
|
12
|
+
onQualityDegraded?: (quality: PlaybackQuality) => void;
|
|
13
|
+
/** Callback on every sample */
|
|
14
|
+
onSample?: (quality: PlaybackQuality) => void;
|
|
15
|
+
/** Current player protocol for threshold selection */
|
|
16
|
+
protocol?: PlayerProtocol;
|
|
17
|
+
/** Custom playback score threshold (overrides protocol default) */
|
|
18
|
+
playbackScoreThreshold?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Callback when sustained poor quality triggers a fallback request
|
|
21
|
+
* Reference: player.js:654-665 - "nextCombo" action
|
|
22
|
+
*/
|
|
23
|
+
onFallbackRequest?: (reason: {
|
|
24
|
+
score: number;
|
|
25
|
+
consecutivePoorSamples: number;
|
|
26
|
+
}) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Number of consecutive poor samples before requesting fallback
|
|
29
|
+
* Default: 5 (2.5 seconds at 500ms sample interval)
|
|
30
|
+
*/
|
|
31
|
+
poorSamplesBeforeFallback?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface QualityMonitorState {
|
|
34
|
+
isMonitoring: boolean;
|
|
35
|
+
quality: PlaybackQuality | null;
|
|
36
|
+
history: PlaybackQuality[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* QualityMonitor - Tracks playback quality metrics
|
|
40
|
+
*
|
|
41
|
+
* Monitors:
|
|
42
|
+
* - Buffer health (seconds ahead)
|
|
43
|
+
* - Stall count (waiting events)
|
|
44
|
+
* - Frame drop rate (via video.getVideoPlaybackQuality())
|
|
45
|
+
* - Estimated bitrate
|
|
46
|
+
* - Latency (for live streams)
|
|
47
|
+
*
|
|
48
|
+
* Calculates a composite quality score (0-100) and triggers
|
|
49
|
+
* callbacks when quality degrades below thresholds.
|
|
50
|
+
*/
|
|
51
|
+
export declare class QualityMonitor {
|
|
52
|
+
private videoElement;
|
|
53
|
+
private options;
|
|
54
|
+
private thresholds;
|
|
55
|
+
private timers;
|
|
56
|
+
private stallCount;
|
|
57
|
+
private lastStallTime;
|
|
58
|
+
private totalStallMs;
|
|
59
|
+
private history;
|
|
60
|
+
private lastBytesLoaded;
|
|
61
|
+
private lastBytesTime;
|
|
62
|
+
private listeners;
|
|
63
|
+
private playbackScoreHistory;
|
|
64
|
+
private playbackScore;
|
|
65
|
+
private readonly PLAYBACK_SCORE_AVERAGING_STEPS;
|
|
66
|
+
private consecutivePoorSamples;
|
|
67
|
+
private fallbackTriggered;
|
|
68
|
+
constructor(options?: QualityMonitorOptions);
|
|
69
|
+
/**
|
|
70
|
+
* Set the current player protocol for threshold selection
|
|
71
|
+
*/
|
|
72
|
+
setProtocol(protocol: PlayerProtocol): void;
|
|
73
|
+
/**
|
|
74
|
+
* Get the current player protocol
|
|
75
|
+
*/
|
|
76
|
+
getProtocol(): PlayerProtocol;
|
|
77
|
+
/**
|
|
78
|
+
* Get the playback score threshold for the current protocol
|
|
79
|
+
*/
|
|
80
|
+
getPlaybackScoreThreshold(): number;
|
|
81
|
+
/**
|
|
82
|
+
* Set a custom playback score threshold (overrides protocol default)
|
|
83
|
+
*/
|
|
84
|
+
setPlaybackScoreThreshold(threshold: number | null): void;
|
|
85
|
+
/**
|
|
86
|
+
* Start monitoring a video element
|
|
87
|
+
*/
|
|
88
|
+
start(videoElement: HTMLVideoElement): void;
|
|
89
|
+
/**
|
|
90
|
+
* Stop monitoring
|
|
91
|
+
*/
|
|
92
|
+
stop(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Take a quality sample
|
|
95
|
+
*/
|
|
96
|
+
private sample;
|
|
97
|
+
/**
|
|
98
|
+
* Calculate current quality metrics
|
|
99
|
+
*/
|
|
100
|
+
private calculateQuality;
|
|
101
|
+
/**
|
|
102
|
+
* Calculate composite quality score
|
|
103
|
+
*
|
|
104
|
+
* D4: Duration-weighted stall tracking - stall penalty considers both
|
|
105
|
+
* count AND duration. 10x 0.1s stalls (1s total) weighs less than 1x 1s stall.
|
|
106
|
+
*/
|
|
107
|
+
private calculateScore;
|
|
108
|
+
/**
|
|
109
|
+
* Get current quality metrics
|
|
110
|
+
*/
|
|
111
|
+
getCurrentQuality(): PlaybackQuality | null;
|
|
112
|
+
/**
|
|
113
|
+
* Get rolling average quality
|
|
114
|
+
*/
|
|
115
|
+
getAverageQuality(): PlaybackQuality | null;
|
|
116
|
+
/**
|
|
117
|
+
* Get quality history
|
|
118
|
+
*/
|
|
119
|
+
getHistory(): PlaybackQuality[];
|
|
120
|
+
/**
|
|
121
|
+
* Reset stall counters
|
|
122
|
+
*/
|
|
123
|
+
resetStallCounters(): void;
|
|
124
|
+
/**
|
|
125
|
+
* Get total stall time in ms
|
|
126
|
+
*/
|
|
127
|
+
getTotalStallMs(): number;
|
|
128
|
+
/**
|
|
129
|
+
* Check if currently monitoring
|
|
130
|
+
*/
|
|
131
|
+
isMonitoring(): boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Calculate playback score entry value
|
|
134
|
+
* Compares video time progress vs wall clock time
|
|
135
|
+
*/
|
|
136
|
+
private getPlaybackScoreValue;
|
|
137
|
+
/**
|
|
138
|
+
* Calculate score between two entries
|
|
139
|
+
* Returns 1.0 for normal playback, >1.0 if faster, <1.0 if stalled, <0 if backwards
|
|
140
|
+
*/
|
|
141
|
+
private calculatePlaybackScoreFromEntries;
|
|
142
|
+
/**
|
|
143
|
+
* Calculate and update the playback score
|
|
144
|
+
* Like MistPlayer's calcScore function
|
|
145
|
+
*/
|
|
146
|
+
private updatePlaybackScore;
|
|
147
|
+
/**
|
|
148
|
+
* Get current playback score (MistPlayer-style 0-2.0 scale)
|
|
149
|
+
*
|
|
150
|
+
* - 1.0 = normal playback (video progresses at expected rate)
|
|
151
|
+
* - > 1.0 = faster than expected (catching up)
|
|
152
|
+
* - < 1.0 = slower than expected (stalling/buffering)
|
|
153
|
+
* - < 0 = video went backwards
|
|
154
|
+
*
|
|
155
|
+
* Threshold recommendations:
|
|
156
|
+
* - WebRTC: warn below 0.95
|
|
157
|
+
* - HLS/DASH: warn below 0.75
|
|
158
|
+
*/
|
|
159
|
+
getPlaybackScore(): number;
|
|
160
|
+
/**
|
|
161
|
+
* Check if playback quality is poor based on score
|
|
162
|
+
* Uses protocol-specific thresholds (MistPlayer-style)
|
|
163
|
+
* WebRTC: 0.95 (strict), HLS/DASH/HTML5: 0.75 (lenient)
|
|
164
|
+
*/
|
|
165
|
+
isPlaybackPoor(): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Reset playback score tracking
|
|
168
|
+
*/
|
|
169
|
+
resetPlaybackScore(): void;
|
|
170
|
+
/**
|
|
171
|
+
* Reset fallback state
|
|
172
|
+
* Call after a player switch to allow fallback to trigger again
|
|
173
|
+
*/
|
|
174
|
+
resetFallbackState(): void;
|
|
175
|
+
/**
|
|
176
|
+
* Get consecutive poor sample count (for debugging)
|
|
177
|
+
*/
|
|
178
|
+
getConsecutivePoorSamples(): number;
|
|
179
|
+
/**
|
|
180
|
+
* Check if fallback has been triggered (for debugging)
|
|
181
|
+
*/
|
|
182
|
+
hasFallbackTriggered(): boolean;
|
|
183
|
+
}
|
|
184
|
+
export default QualityMonitor;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ScreenWakeLockManager - Prevents device sleep during video playback
|
|
3
|
+
*
|
|
4
|
+
* Uses the Screen Wake Lock API to keep the screen awake during:
|
|
5
|
+
* - Fullscreen video playback
|
|
6
|
+
* - Active video playback (optional)
|
|
7
|
+
*
|
|
8
|
+
* Gracefully falls back to no-op on unsupported browsers.
|
|
9
|
+
*/
|
|
10
|
+
export interface ScreenWakeLockConfig {
|
|
11
|
+
/** Acquire wake lock on any playback, not just fullscreen (default: false) */
|
|
12
|
+
acquireOnPlay?: boolean;
|
|
13
|
+
/** Callback when wake lock is acquired */
|
|
14
|
+
onAcquire?: () => void;
|
|
15
|
+
/** Callback when wake lock is released */
|
|
16
|
+
onRelease?: () => void;
|
|
17
|
+
/** Callback on error */
|
|
18
|
+
onError?: (error: Error) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare class ScreenWakeLockManager {
|
|
21
|
+
private wakeLock;
|
|
22
|
+
private config;
|
|
23
|
+
private isSupported;
|
|
24
|
+
private isPlaying;
|
|
25
|
+
private isFullscreen;
|
|
26
|
+
private isDestroyed;
|
|
27
|
+
private boundVisibilityChange;
|
|
28
|
+
constructor(config?: ScreenWakeLockConfig);
|
|
29
|
+
/**
|
|
30
|
+
* Check if Screen Wake Lock API is supported
|
|
31
|
+
*/
|
|
32
|
+
static isSupported(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Update playing state
|
|
35
|
+
*/
|
|
36
|
+
setPlaying(isPlaying: boolean): void;
|
|
37
|
+
/**
|
|
38
|
+
* Update fullscreen state
|
|
39
|
+
*/
|
|
40
|
+
setFullscreen(isFullscreen: boolean): void;
|
|
41
|
+
/**
|
|
42
|
+
* Check if wake lock is currently held
|
|
43
|
+
*/
|
|
44
|
+
isHeld(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Manually acquire wake lock
|
|
47
|
+
*/
|
|
48
|
+
acquire(): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Manually release wake lock
|
|
51
|
+
*/
|
|
52
|
+
release(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Destroy the manager and release wake lock
|
|
55
|
+
*/
|
|
56
|
+
destroy(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Update wake lock based on current state
|
|
59
|
+
*/
|
|
60
|
+
private updateWakeLock;
|
|
61
|
+
/**
|
|
62
|
+
* Handle wake lock release event
|
|
63
|
+
*/
|
|
64
|
+
private handleRelease;
|
|
65
|
+
/**
|
|
66
|
+
* Handle visibility change - re-acquire if page becomes visible
|
|
67
|
+
*/
|
|
68
|
+
private handleVisibilityChange;
|
|
69
|
+
}
|
|
70
|
+
export default ScreenWakeLockManager;
|