@livepeer-frameworks/player-core 0.0.4 → 0.1.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.
- package/README.md +21 -6
- package/dist/cjs/index.js +792 -146
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +792 -146
- package/dist/esm/index.js.map +1 -1
- package/dist/player.css +185 -373
- package/dist/types/core/GatewayClient.d.ts +3 -4
- package/dist/types/core/InteractionController.d.ts +12 -0
- package/dist/types/core/MetaTrackManager.d.ts +1 -1
- package/dist/types/core/PlayerController.d.ts +18 -2
- package/dist/types/core/PlayerInterface.d.ts +10 -0
- package/dist/types/core/SeekingUtils.d.ts +3 -1
- package/dist/types/core/StreamStateClient.d.ts +1 -1
- package/dist/types/players/HlsJsPlayer.d.ts +8 -0
- package/dist/types/players/MewsWsPlayer/index.d.ts +1 -1
- package/dist/types/players/VideoJsPlayer.d.ts +12 -4
- package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +1 -1
- package/dist/types/players/WebCodecsPlayer/index.d.ts +11 -0
- package/dist/types/players/WebCodecsPlayer/types.d.ts +25 -3
- package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +20 -2
- package/dist/types/types.d.ts +32 -1
- package/dist/types/vanilla/FrameWorksPlayer.d.ts +5 -5
- package/dist/types/vanilla/index.d.ts +3 -3
- package/dist/workers/decoder.worker.js +183 -6
- package/dist/workers/decoder.worker.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ABRController.ts +38 -36
- package/src/core/CodecUtils.ts +50 -47
- package/src/core/Disposable.ts +4 -4
- package/src/core/EventEmitter.ts +1 -1
- package/src/core/GatewayClient.ts +48 -48
- package/src/core/InteractionController.ts +89 -82
- package/src/core/LiveDurationProxy.ts +14 -16
- package/src/core/MetaTrackManager.ts +74 -66
- package/src/core/MistReporter.ts +72 -45
- package/src/core/MistSignaling.ts +59 -56
- package/src/core/PlayerController.ts +724 -375
- package/src/core/PlayerInterface.ts +89 -59
- package/src/core/PlayerManager.ts +118 -123
- package/src/core/PlayerRegistry.ts +59 -42
- package/src/core/QualityMonitor.ts +38 -31
- package/src/core/ScreenWakeLockManager.ts +8 -9
- package/src/core/SeekingUtils.ts +31 -22
- package/src/core/StreamStateClient.ts +75 -69
- package/src/core/SubtitleManager.ts +25 -23
- package/src/core/TelemetryReporter.ts +34 -31
- package/src/core/TimeFormat.ts +13 -17
- package/src/core/TimerManager.ts +25 -9
- package/src/core/UrlUtils.ts +20 -17
- package/src/core/detector.ts +44 -44
- package/src/core/index.ts +57 -48
- package/src/core/scorer.ts +137 -138
- package/src/core/selector.ts +2 -6
- package/src/global.d.ts +1 -1
- package/src/index.ts +46 -35
- package/src/players/DashJsPlayer.ts +175 -114
- package/src/players/HlsJsPlayer.ts +154 -76
- package/src/players/MewsWsPlayer/SourceBufferManager.ts +44 -39
- package/src/players/MewsWsPlayer/WebSocketManager.ts +9 -10
- package/src/players/MewsWsPlayer/index.ts +196 -154
- package/src/players/MewsWsPlayer/types.ts +21 -21
- package/src/players/MistPlayer.ts +46 -27
- package/src/players/MistWebRTCPlayer/index.ts +175 -129
- package/src/players/NativePlayer.ts +203 -143
- package/src/players/VideoJsPlayer.ts +200 -146
- package/src/players/WebCodecsPlayer/JitterBuffer.ts +6 -7
- package/src/players/WebCodecsPlayer/LatencyProfiles.ts +43 -43
- package/src/players/WebCodecsPlayer/RawChunkParser.ts +10 -10
- package/src/players/WebCodecsPlayer/SyncController.ts +46 -55
- package/src/players/WebCodecsPlayer/WebSocketController.ts +67 -69
- package/src/players/WebCodecsPlayer/index.ts +280 -220
- package/src/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.ts +12 -17
- package/src/players/WebCodecsPlayer/types.ts +81 -53
- package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +255 -192
- package/src/players/WebCodecsPlayer/worker/types.ts +33 -29
- package/src/players/index.ts +8 -8
- package/src/styles/animations.css +2 -1
- package/src/styles/player.css +182 -356
- package/src/styles/tailwind.css +473 -159
- package/src/types.ts +75 -33
- package/src/vanilla/FrameWorksPlayer.ts +34 -19
- package/src/vanilla/index.ts +7 -7
package/src/core/index.ts
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
// Browser and codec detection
|
|
8
|
-
export * from
|
|
8
|
+
export * from "./detector";
|
|
9
9
|
|
|
10
10
|
// Scoring system
|
|
11
|
-
export * from
|
|
11
|
+
export * from "./scorer";
|
|
12
12
|
|
|
13
13
|
// Player interfaces and base classes
|
|
14
|
-
export * from
|
|
14
|
+
export * from "./PlayerInterface";
|
|
15
15
|
|
|
16
16
|
// Main player manager (single source of truth for selection)
|
|
17
17
|
export {
|
|
@@ -20,31 +20,35 @@ export {
|
|
|
20
20
|
type PlayerCombination,
|
|
21
21
|
type PlayerManagerOptions,
|
|
22
22
|
type PlayerManagerEvents,
|
|
23
|
-
} from
|
|
23
|
+
} from "./PlayerManager";
|
|
24
24
|
|
|
25
25
|
// Player registry with all implementations
|
|
26
|
-
export * from
|
|
26
|
+
export * from "./PlayerRegistry";
|
|
27
27
|
|
|
28
28
|
// Re-export for convenience
|
|
29
|
-
export {
|
|
30
|
-
|
|
29
|
+
export {
|
|
30
|
+
globalPlayerManager,
|
|
31
|
+
createPlayerManager,
|
|
32
|
+
ensurePlayersRegistered,
|
|
33
|
+
} from "./PlayerRegistry";
|
|
34
|
+
export type { IPlayer, PlayerOptions } from "./PlayerInterface";
|
|
31
35
|
|
|
32
36
|
// New core classes (MistMetaPlayer feature backport)
|
|
33
|
-
export { QualityMonitor, PROTOCOL_THRESHOLDS } from
|
|
34
|
-
export type { QualityMonitorOptions, QualityMonitorState, PlayerProtocol } from
|
|
35
|
-
export { TelemetryReporter } from
|
|
36
|
-
export type { TelemetryReporterConfig } from
|
|
37
|
-
export { ABRController } from
|
|
38
|
-
export type { ABRControllerConfig, ABRDecision } from
|
|
39
|
-
export { MetaTrackManager } from
|
|
40
|
-
export type { MetaTrackManagerConfig, MetaTrackSubscription } from
|
|
37
|
+
export { QualityMonitor, PROTOCOL_THRESHOLDS } from "./QualityMonitor";
|
|
38
|
+
export type { QualityMonitorOptions, QualityMonitorState, PlayerProtocol } from "./QualityMonitor";
|
|
39
|
+
export { TelemetryReporter } from "./TelemetryReporter";
|
|
40
|
+
export type { TelemetryReporterConfig } from "./TelemetryReporter";
|
|
41
|
+
export { ABRController } from "./ABRController";
|
|
42
|
+
export type { ABRControllerConfig, ABRDecision } from "./ABRController";
|
|
43
|
+
export { MetaTrackManager } from "./MetaTrackManager";
|
|
44
|
+
export type { MetaTrackManagerConfig, MetaTrackSubscription } from "./MetaTrackManager";
|
|
41
45
|
|
|
42
46
|
// Headless core classes (framework-agnostic)
|
|
43
|
-
export { TypedEventEmitter } from
|
|
44
|
-
export { GatewayClient } from
|
|
45
|
-
export type { GatewayClientConfig, GatewayClientEvents, GatewayStatus } from
|
|
46
|
-
export { StreamStateClient } from
|
|
47
|
-
export type { StreamStateClientConfig, StreamStateClientEvents } from
|
|
47
|
+
export { TypedEventEmitter } from "./EventEmitter";
|
|
48
|
+
export { GatewayClient } from "./GatewayClient";
|
|
49
|
+
export type { GatewayClientConfig, GatewayClientEvents, GatewayStatus } from "./GatewayClient";
|
|
50
|
+
export { StreamStateClient } from "./StreamStateClient";
|
|
51
|
+
export type { StreamStateClientConfig, StreamStateClientEvents } from "./StreamStateClient";
|
|
48
52
|
export {
|
|
49
53
|
PlayerController,
|
|
50
54
|
buildStreamInfoFromEndpoints,
|
|
@@ -52,27 +56,36 @@ export {
|
|
|
52
56
|
PROTOCOL_TO_MIME,
|
|
53
57
|
getMimeTypeForProtocol,
|
|
54
58
|
getSourceTypeInfo,
|
|
55
|
-
} from
|
|
56
|
-
export type { PlayerControllerConfig, PlayerControllerEvents } from
|
|
59
|
+
} from "./PlayerController";
|
|
60
|
+
export type { PlayerControllerConfig, PlayerControllerEvents } from "./PlayerController";
|
|
57
61
|
|
|
58
62
|
// MistServer reporting (MistMetaPlayer feature backport)
|
|
59
|
-
export { MistReporter } from
|
|
60
|
-
export type {
|
|
63
|
+
export { MistReporter } from "./MistReporter";
|
|
64
|
+
export type {
|
|
65
|
+
MistReporterStats,
|
|
66
|
+
MistReporterOptions,
|
|
67
|
+
MistReporterInitialReport,
|
|
68
|
+
} from "./MistReporter";
|
|
61
69
|
|
|
62
70
|
// MistServer WebRTC signaling (MistMetaPlayer feature backport)
|
|
63
|
-
export { MistSignaling } from
|
|
64
|
-
export type {
|
|
71
|
+
export { MistSignaling } from "./MistSignaling";
|
|
72
|
+
export type {
|
|
73
|
+
MistSignalingConfig,
|
|
74
|
+
MistSignalingEvents,
|
|
75
|
+
MistTimeUpdate,
|
|
76
|
+
MistSignalingState,
|
|
77
|
+
} from "./MistSignaling";
|
|
65
78
|
|
|
66
79
|
// Live duration handling for live streams
|
|
67
|
-
export { LiveDurationProxy, createLiveVideoProxy } from
|
|
68
|
-
export type { LiveDurationProxyOptions, LiveDurationState } from
|
|
80
|
+
export { LiveDurationProxy, createLiveVideoProxy } from "./LiveDurationProxy";
|
|
81
|
+
export type { LiveDurationProxyOptions, LiveDurationState } from "./LiveDurationProxy";
|
|
69
82
|
|
|
70
83
|
// Timer management for memory leak prevention
|
|
71
|
-
export { TimerManager } from
|
|
84
|
+
export { TimerManager } from "./TimerManager";
|
|
72
85
|
|
|
73
86
|
// Disposable interface for consistent cleanup
|
|
74
|
-
export { BaseDisposable, disposeAll, createCompositeDisposable } from
|
|
75
|
-
export type { Disposable } from
|
|
87
|
+
export { BaseDisposable, disposeAll, createCompositeDisposable } from "./Disposable";
|
|
88
|
+
export type { Disposable } from "./Disposable";
|
|
76
89
|
|
|
77
90
|
// URL utilities (MistMetaPlayer feature backport)
|
|
78
91
|
export {
|
|
@@ -84,27 +97,23 @@ export {
|
|
|
84
97
|
httpToWs,
|
|
85
98
|
wsToHttp,
|
|
86
99
|
matchPageProtocol,
|
|
87
|
-
} from
|
|
100
|
+
} from "./UrlUtils";
|
|
88
101
|
|
|
89
102
|
// Codec utilities (MistMetaPlayer feature backport)
|
|
90
|
-
export {
|
|
91
|
-
|
|
92
|
-
isCodecSupported,
|
|
93
|
-
getBestSupportedTrack,
|
|
94
|
-
} from './CodecUtils';
|
|
95
|
-
export type { TrackInfo } from './CodecUtils';
|
|
103
|
+
export { translateCodec, isCodecSupported, getBestSupportedTrack } from "./CodecUtils";
|
|
104
|
+
export type { TrackInfo } from "./CodecUtils";
|
|
96
105
|
|
|
97
106
|
// Subtitle management (MistMetaPlayer feature backport)
|
|
98
|
-
export { SubtitleManager } from
|
|
99
|
-
export type { SubtitleTrackInfo, SubtitleManagerConfig } from
|
|
107
|
+
export { SubtitleManager } from "./SubtitleManager";
|
|
108
|
+
export type { SubtitleTrackInfo, SubtitleManagerConfig } from "./SubtitleManager";
|
|
100
109
|
|
|
101
110
|
// Interaction controller for modern player gestures + keyboard (VOD/Clip features)
|
|
102
|
-
export { InteractionController } from
|
|
103
|
-
export type { InteractionControllerConfig, InteractionState } from
|
|
111
|
+
export { InteractionController } from "./InteractionController";
|
|
112
|
+
export type { InteractionControllerConfig, InteractionState } from "./InteractionController";
|
|
104
113
|
|
|
105
114
|
// Screen Wake Lock for preventing device sleep during video playback
|
|
106
|
-
export { ScreenWakeLockManager } from
|
|
107
|
-
export type { ScreenWakeLockConfig } from
|
|
115
|
+
export { ScreenWakeLockManager } from "./ScreenWakeLockManager";
|
|
116
|
+
export type { ScreenWakeLockConfig } from "./ScreenWakeLockManager";
|
|
108
117
|
|
|
109
118
|
// Seeking utilities - centralized seeking/live detection logic
|
|
110
119
|
export {
|
|
@@ -119,14 +128,14 @@ export {
|
|
|
119
128
|
calculateLiveThresholds,
|
|
120
129
|
calculateIsNearLive,
|
|
121
130
|
isLiveContent,
|
|
122
|
-
} from
|
|
131
|
+
} from "./SeekingUtils";
|
|
123
132
|
export type {
|
|
124
133
|
LatencyTier,
|
|
125
134
|
LiveThresholds,
|
|
126
135
|
SeekableRange,
|
|
127
136
|
SeekableRangeParams,
|
|
128
137
|
CanSeekParams,
|
|
129
|
-
} from
|
|
138
|
+
} from "./SeekingUtils";
|
|
130
139
|
|
|
131
140
|
// Time formatting utilities
|
|
132
141
|
export {
|
|
@@ -136,5 +145,5 @@ export {
|
|
|
136
145
|
formatTooltipTime,
|
|
137
146
|
formatDuration,
|
|
138
147
|
parseTime,
|
|
139
|
-
} from
|
|
140
|
-
export type { TimeDisplayParams } from
|
|
148
|
+
} from "./TimeFormat";
|
|
149
|
+
export type { TimeDisplayParams } from "./TimeFormat";
|
package/src/core/scorer.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - Protocol-specific routing (new)
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import type { PlaybackMode } from
|
|
14
|
+
import type { PlaybackMode } from "../types";
|
|
15
15
|
|
|
16
16
|
export interface TrackScore {
|
|
17
17
|
video: number;
|
|
@@ -41,7 +41,7 @@ export interface PlayerScore {
|
|
|
41
41
|
export const DEFAULT_TRACK_SCORES: TrackScore = {
|
|
42
42
|
video: 2.0,
|
|
43
43
|
audio: 1.0,
|
|
44
|
-
subtitle: 0.5
|
|
44
|
+
subtitle: 0.5,
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -87,27 +87,21 @@ export function calculateMaxScore(
|
|
|
87
87
|
export function calculatePriorityScore(priority: number, maxPriority: number): number {
|
|
88
88
|
// Lower priority number = higher score
|
|
89
89
|
// Normalize to 0-1 range, then invert
|
|
90
|
-
return 1 -
|
|
90
|
+
return 1 - priority / Math.max(maxPriority, 1);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
94
|
* Source preference scoring based on MistServer ordering
|
|
95
95
|
*/
|
|
96
|
-
export function calculateSourceScore(
|
|
97
|
-
sourceIndex: number,
|
|
98
|
-
totalSources: number
|
|
99
|
-
): number {
|
|
96
|
+
export function calculateSourceScore(sourceIndex: number, totalSources: number): number {
|
|
100
97
|
// Earlier sources (lower index) get higher scores
|
|
101
|
-
return 1 -
|
|
98
|
+
return 1 - sourceIndex / Math.max(totalSources - 1, 1);
|
|
102
99
|
}
|
|
103
100
|
|
|
104
101
|
/**
|
|
105
102
|
* Bandwidth/quality scoring
|
|
106
103
|
*/
|
|
107
|
-
export function calculateQualityScore(
|
|
108
|
-
bandwidth?: number,
|
|
109
|
-
targetBandwidth?: number
|
|
110
|
-
): number {
|
|
104
|
+
export function calculateQualityScore(bandwidth?: number, targetBandwidth?: number): number {
|
|
111
105
|
if (!bandwidth || !targetBandwidth) {
|
|
112
106
|
return 1.0; // Neutral score if no bandwidth info
|
|
113
107
|
}
|
|
@@ -126,32 +120,32 @@ export function calculateQualityScore(
|
|
|
126
120
|
*/
|
|
127
121
|
export const PROTOCOL_BLACKLIST: Set<string> = new Set([
|
|
128
122
|
// Flash - browsers removed support in 2020
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
"flash/7",
|
|
124
|
+
"flash/10",
|
|
125
|
+
"flash/11",
|
|
132
126
|
// Silverlight - dead technology
|
|
133
|
-
|
|
127
|
+
"silverlight",
|
|
134
128
|
// SDP is WebRTC signaling format, not a playback source type
|
|
135
|
-
|
|
136
|
-
|
|
129
|
+
"html5/application/sdp",
|
|
130
|
+
"sdp",
|
|
137
131
|
// MPEG-TS - no browser support, no wrapper implementation in reference
|
|
138
|
-
|
|
132
|
+
"html5/video/mpeg",
|
|
139
133
|
// Smooth Streaming - intentionally disabled in reference (commented out in dashjs.js!)
|
|
140
|
-
|
|
134
|
+
"html5/application/vnd.ms-sstr+xml",
|
|
141
135
|
// Server-side only protocols - browsers can't connect to these directly
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
136
|
+
"srt",
|
|
137
|
+
"rtsp",
|
|
138
|
+
"rtmp",
|
|
145
139
|
// MistServer internal protocols - not for browser playback
|
|
146
|
-
|
|
140
|
+
"dtsc",
|
|
147
141
|
// NOTE: ws/video/raw is supported by WebCodecs player
|
|
148
142
|
// Image formats - not video playback
|
|
149
|
-
|
|
143
|
+
"html5/image/jpeg",
|
|
150
144
|
// Script/metadata formats - not playback sources
|
|
151
|
-
|
|
145
|
+
"html5/text/javascript",
|
|
152
146
|
// Subtitle-only formats - not standalone playback sources (used as tracks)
|
|
153
|
-
|
|
154
|
-
|
|
147
|
+
"html5/text/vtt",
|
|
148
|
+
"html5/text/plain",
|
|
155
149
|
]);
|
|
156
150
|
|
|
157
151
|
/**
|
|
@@ -175,21 +169,24 @@ export const PROTOCOL_PENALTIES: Record<string, number> = {
|
|
|
175
169
|
// 'ws/video/h264': 0,
|
|
176
170
|
// 'wss/video/h264': 0,
|
|
177
171
|
// WebM - reference supports but unreliable in practice
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
172
|
+
"html5/video/webm": 0.8, // Heavy penalty - very broken
|
|
173
|
+
"html5/audio/webm": 0.6,
|
|
174
|
+
"ws/video/webm": 0.8,
|
|
175
|
+
"wss/video/webm": 0.8,
|
|
182
176
|
// MEWS - heavy penalty, prefer HLS/WebRTC (reference mews.js has issues)
|
|
183
|
-
|
|
184
|
-
|
|
177
|
+
"ws/video/mp4": 0.5,
|
|
178
|
+
"wss/video/mp4": 0.5,
|
|
179
|
+
// Native Mist WebRTC signaling - treat like MEWS (legacy/less stable than WHEP)
|
|
180
|
+
webrtc: 0.5,
|
|
181
|
+
"mist/webrtc": 0.5,
|
|
185
182
|
// DASH - heavy penalty, broken implementation
|
|
186
|
-
|
|
187
|
-
|
|
183
|
+
"dash/video/mp4": 0.9, // Below legacy
|
|
184
|
+
"dash/video/webm": 0.95,
|
|
188
185
|
// CMAF-style protocols (fMP4 over HLS/DASH) - fragmentation issues
|
|
189
|
-
|
|
186
|
+
"html5/application/vnd.apple.mpegurl;version=7": 0.2, // HLSv7 is CMAF-based
|
|
190
187
|
// LL-HLS specific - experimental, spotty support
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
"ll-hls": 0.2,
|
|
189
|
+
cmaf: 0.2,
|
|
193
190
|
};
|
|
194
191
|
|
|
195
192
|
/**
|
|
@@ -202,14 +199,14 @@ export function calculateProtocolPenalty(mimeType: string): number {
|
|
|
202
199
|
}
|
|
203
200
|
// Pattern-based penalties for protocols not explicitly listed
|
|
204
201
|
const lowerMime = mimeType.toLowerCase();
|
|
205
|
-
if (lowerMime.includes(
|
|
206
|
-
return 0.
|
|
202
|
+
if (lowerMime.includes("webm")) {
|
|
203
|
+
return 0.5; // Heavy penalty for any WebM variant
|
|
207
204
|
}
|
|
208
|
-
if (lowerMime.startsWith(
|
|
209
|
-
return 0.
|
|
205
|
+
if (lowerMime.startsWith("dash/")) {
|
|
206
|
+
return 0.4; // DASH penalty
|
|
210
207
|
}
|
|
211
|
-
if (lowerMime.includes(
|
|
212
|
-
return 0.
|
|
208
|
+
if (lowerMime.includes("cmaf") || lowerMime.includes("ll-hls")) {
|
|
209
|
+
return 0.2;
|
|
213
210
|
}
|
|
214
211
|
return 0;
|
|
215
212
|
}
|
|
@@ -219,14 +216,14 @@ export function calculateProtocolPenalty(mimeType: string): number {
|
|
|
219
216
|
* Based on library maturity, error recovery, and overall stability
|
|
220
217
|
*/
|
|
221
218
|
export const PLAYER_RELIABILITY: Record<string, number> = {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
219
|
+
webcodecs: 0.95, // Stable, lowest latency option
|
|
220
|
+
videojs: 0.95, // Fast loading, built-in HLS via VHS
|
|
221
|
+
hlsjs: 0.9, // Battle-tested but slower to load
|
|
222
|
+
native: 0.85, // Native is lightweight but has edge cases
|
|
223
|
+
"mist-webrtc": 0.85, // Full signaling features
|
|
224
|
+
mews: 0.75, // Custom protocol, less tested
|
|
225
|
+
"mist-legacy": 0.7, // Ultimate fallback, delegates everything
|
|
226
|
+
dashjs: 0.5, // Broken, lowest reliability
|
|
230
227
|
};
|
|
231
228
|
|
|
232
229
|
/**
|
|
@@ -250,70 +247,71 @@ export function calculateReliabilityScore(playerShortname: string): number {
|
|
|
250
247
|
* - Auto: MP4/WS balanced choice, WHEP for low latency, HLS last resort
|
|
251
248
|
*/
|
|
252
249
|
export const MODE_PROTOCOL_BONUSES: Record<PlaybackMode, Record<string, number>> = {
|
|
253
|
-
|
|
250
|
+
"low-latency": {
|
|
254
251
|
// WebCodecs raw/h264: HIGHEST PRIORITY - ultra-low latency via WebCodecs API
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
252
|
+
"ws/video/raw": 0.55,
|
|
253
|
+
"wss/video/raw": 0.55,
|
|
254
|
+
"ws/video/h264": 0.52,
|
|
255
|
+
"wss/video/h264": 0.52,
|
|
259
256
|
// WHEP/WebRTC: sub-second latency
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
257
|
+
whep: 0.5,
|
|
258
|
+
webrtc: 0.25,
|
|
259
|
+
"mist/webrtc": 0.25,
|
|
263
260
|
// MP4/WS (MEWS): 2-5s latency, good fallback
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
"ws/video/mp4": 0.3,
|
|
262
|
+
"wss/video/mp4": 0.3,
|
|
266
263
|
// Progressive MP4: lower latency than HLS (5-10s vs 10-30s)
|
|
267
|
-
|
|
264
|
+
"html5/video/mp4": 0.15,
|
|
268
265
|
// HLS: high latency, minimal bonus
|
|
269
|
-
|
|
266
|
+
"html5/application/vnd.apple.mpegurl": 0.05,
|
|
270
267
|
},
|
|
271
|
-
|
|
268
|
+
quality: {
|
|
272
269
|
// MP4/WS: stable + lower latency than HLS, preferred when supported
|
|
273
|
-
|
|
274
|
-
|
|
270
|
+
"ws/video/mp4": 0.45,
|
|
271
|
+
"wss/video/mp4": 0.45,
|
|
275
272
|
// WebCodecs raw: below MEWS but above HLS - good quality + low latency
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
273
|
+
"ws/video/raw": 0.4,
|
|
274
|
+
"wss/video/raw": 0.4,
|
|
275
|
+
"ws/video/h264": 0.38,
|
|
276
|
+
"wss/video/h264": 0.38,
|
|
280
277
|
// HLS: ABR support, universal fallback
|
|
281
|
-
|
|
282
|
-
|
|
278
|
+
"html5/application/vnd.apple.mpegurl": 0.3,
|
|
279
|
+
"html5/video/mp4": 0.2,
|
|
283
280
|
// WebRTC: minimal for quality mode
|
|
284
|
-
|
|
285
|
-
|
|
281
|
+
whep: 0.05,
|
|
282
|
+
webrtc: 0.05,
|
|
283
|
+
"mist/webrtc": 0.05,
|
|
286
284
|
},
|
|
287
|
-
|
|
285
|
+
vod: {
|
|
288
286
|
// VOD/Clip: Prefer seekable protocols, EXCLUDE WebRTC (no seek support)
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
287
|
+
"html5/video/mp4": 0.5, // Progressive MP4 - best for clips
|
|
288
|
+
"html5/application/vnd.apple.mpegurl": 0.45, // HLS - ABR support
|
|
289
|
+
"dash/video/mp4": 0.4, // DASH - ABR support
|
|
290
|
+
"ws/video/mp4": 0.35, // MEWS - seekable via MSE
|
|
291
|
+
"wss/video/mp4": 0.35,
|
|
294
292
|
// WHEP/WebRTC: HARD PENALTY - no seek support, inappropriate for VOD
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
293
|
+
whep: -1.0,
|
|
294
|
+
webrtc: -1.0,
|
|
295
|
+
"mist/webrtc": -1.0,
|
|
298
296
|
},
|
|
299
|
-
|
|
297
|
+
auto: {
|
|
300
298
|
// WebCodecs raw: highest priority for low-latency live streams
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
299
|
+
"ws/video/raw": 0.5,
|
|
300
|
+
"wss/video/raw": 0.5,
|
|
301
|
+
"ws/video/h264": 0.48,
|
|
302
|
+
"wss/video/h264": 0.48,
|
|
305
303
|
// Direct MP4: simple, reliable, preferred over HLS when available
|
|
306
|
-
|
|
304
|
+
"html5/video/mp4": 0.42,
|
|
307
305
|
// WHEP/WebRTC: good for low latency
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
306
|
+
whep: 0.38,
|
|
307
|
+
webrtc: 0.2,
|
|
308
|
+
"mist/webrtc": 0.2,
|
|
311
309
|
// MP4/WS (MEWS): lower latency than HLS
|
|
312
|
-
|
|
313
|
-
|
|
310
|
+
"ws/video/mp4": 0.3,
|
|
311
|
+
"wss/video/mp4": 0.3,
|
|
314
312
|
// HLS: high latency, fallback option (but reliable)
|
|
315
|
-
|
|
316
|
-
}
|
|
313
|
+
"html5/application/vnd.apple.mpegurl": 0.2,
|
|
314
|
+
},
|
|
317
315
|
};
|
|
318
316
|
|
|
319
317
|
/**
|
|
@@ -328,46 +326,46 @@ export function calculateModeBonus(mimeType: string, mode: PlaybackMode): number
|
|
|
328
326
|
* Protocol routing rules - certain players are preferred for certain protocols
|
|
329
327
|
*/
|
|
330
328
|
export const PROTOCOL_ROUTING: Record<string, { prefer: string[]; avoid?: string[] }> = {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
329
|
+
whep: { prefer: ["native"] },
|
|
330
|
+
webrtc: { prefer: ["mist-webrtc", "native"] },
|
|
331
|
+
"mist/webrtc": { prefer: ["mist-webrtc"] },
|
|
334
332
|
|
|
335
333
|
// Raw WebSocket (12-byte header + AVCC NAL units) - WebCodecs only
|
|
336
|
-
|
|
337
|
-
|
|
334
|
+
"ws/video/raw": { prefer: ["webcodecs"] },
|
|
335
|
+
"wss/video/raw": { prefer: ["webcodecs"] },
|
|
338
336
|
|
|
339
337
|
// Annex B WebSocket (H.264 NAL units) - WebCodecs
|
|
340
|
-
|
|
341
|
-
|
|
338
|
+
"ws/video/h264": { prefer: ["webcodecs"] },
|
|
339
|
+
"wss/video/h264": { prefer: ["webcodecs"] },
|
|
342
340
|
|
|
343
341
|
// MP4-muxed WebSocket - MEWS (uses MSE for demuxing)
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
342
|
+
"ws/video/mp4": { prefer: ["mews"] },
|
|
343
|
+
"wss/video/mp4": { prefer: ["mews"] },
|
|
344
|
+
"ws/video/webm": { prefer: ["mews"] },
|
|
345
|
+
"wss/video/webm": { prefer: ["mews"] },
|
|
348
346
|
|
|
349
347
|
// HLS
|
|
350
|
-
|
|
351
|
-
prefer: [
|
|
352
|
-
avoid: [
|
|
348
|
+
"html5/application/vnd.apple.mpegurl": {
|
|
349
|
+
prefer: ["videojs", "hlsjs"],
|
|
350
|
+
avoid: ["native"],
|
|
353
351
|
},
|
|
354
|
-
|
|
355
|
-
prefer: [
|
|
356
|
-
avoid: [
|
|
352
|
+
"html5/application/vnd.apple.mpegurl;version=7": {
|
|
353
|
+
prefer: ["videojs", "hlsjs"],
|
|
354
|
+
avoid: ["native"],
|
|
357
355
|
},
|
|
358
356
|
|
|
359
357
|
// DASH
|
|
360
|
-
|
|
358
|
+
"dash/video/mp4": { prefer: ["dashjs", "videojs"] },
|
|
361
359
|
|
|
362
360
|
// Progressive download
|
|
363
|
-
|
|
364
|
-
|
|
361
|
+
"html5/video/mp4": { prefer: ["native"] },
|
|
362
|
+
"html5/video/webm": { prefer: ["native"] },
|
|
365
363
|
|
|
366
364
|
// Audio-only formats
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
365
|
+
"html5/audio/aac": { prefer: ["native"] },
|
|
366
|
+
"html5/audio/mp3": { prefer: ["native"] },
|
|
367
|
+
"html5/audio/flac": { prefer: ["native"] },
|
|
368
|
+
"html5/audio/wav": { prefer: ["native"] },
|
|
371
369
|
};
|
|
372
370
|
|
|
373
371
|
/**
|
|
@@ -386,7 +384,7 @@ export function calculateRoutingBonus(mimeType: string, playerShortname: string)
|
|
|
386
384
|
if (rules.prefer?.includes(playerShortname)) {
|
|
387
385
|
const preferIndex = rules.prefer.indexOf(playerShortname);
|
|
388
386
|
// First preferred player gets 0.15, second gets 0.10, etc.
|
|
389
|
-
return 0.15 -
|
|
387
|
+
return 0.15 - preferIndex * 0.05;
|
|
390
388
|
}
|
|
391
389
|
|
|
392
390
|
return 0;
|
|
@@ -429,17 +427,17 @@ export function scorePlayer(
|
|
|
429
427
|
targetBandwidth,
|
|
430
428
|
playerShortname,
|
|
431
429
|
mimeType,
|
|
432
|
-
playbackMode =
|
|
430
|
+
playbackMode = "auto",
|
|
433
431
|
weights = {
|
|
434
|
-
tracks: 0.
|
|
435
|
-
priority: 0.
|
|
436
|
-
source: 0.05,
|
|
437
|
-
quality: 0.05,
|
|
438
|
-
reliability: 0.
|
|
439
|
-
mode: 0.
|
|
440
|
-
routing: 0.08,
|
|
432
|
+
tracks: 0.5, // Reduced from 0.70 to make room for new factors
|
|
433
|
+
priority: 0.1, // Reduced from 0.15
|
|
434
|
+
source: 0.05, // Reduced from 0.10
|
|
435
|
+
quality: 0.05, // Unchanged
|
|
436
|
+
reliability: 0.1, // NEW: Player stability
|
|
437
|
+
mode: 0.1, // Playback mode bonus (reduced slightly)
|
|
438
|
+
routing: 0.08, // Protocol routing preference
|
|
441
439
|
protocolPenalty: 1.0, // Protocol penalty weight (applied as subtraction)
|
|
442
|
-
}
|
|
440
|
+
},
|
|
443
441
|
} = options;
|
|
444
442
|
|
|
445
443
|
const finalTrackScores = { ...DEFAULT_TRACK_SCORES, ...trackScores };
|
|
@@ -453,7 +451,8 @@ export function scorePlayer(
|
|
|
453
451
|
// New enhanced scores
|
|
454
452
|
const reliabilityScore = playerShortname ? calculateReliabilityScore(playerShortname) : 0.5;
|
|
455
453
|
const modeBonus = mimeType ? calculateModeBonus(mimeType, playbackMode) : 0;
|
|
456
|
-
const routingBonus =
|
|
454
|
+
const routingBonus =
|
|
455
|
+
mimeType && playerShortname ? calculateRoutingBonus(mimeType, playerShortname) : 0;
|
|
457
456
|
const protocolPenalty = mimeType ? calculateProtocolPenalty(mimeType) : 0;
|
|
458
457
|
|
|
459
458
|
// Weighted total score (penalty is subtracted)
|
|
@@ -479,7 +478,7 @@ export function scorePlayer(
|
|
|
479
478
|
modeBonus,
|
|
480
479
|
routingBonus,
|
|
481
480
|
protocolPenalty,
|
|
482
|
-
}
|
|
481
|
+
},
|
|
483
482
|
};
|
|
484
483
|
}
|
|
485
484
|
|
|
@@ -506,7 +505,7 @@ export function scoreAndRankPlayers<T extends { priority: number }>(
|
|
|
506
505
|
}> {
|
|
507
506
|
const scoredPlayers = players.map(({ player, supportedTracks, sourceIndex }) => ({
|
|
508
507
|
player,
|
|
509
|
-
score: scorePlayer(supportedTracks, player.priority, sourceIndex, options)
|
|
508
|
+
score: scorePlayer(supportedTracks, player.priority, sourceIndex, options),
|
|
510
509
|
}));
|
|
511
510
|
|
|
512
511
|
return scoredPlayers.sort((a, b) => compareScores(a.score, b.score));
|
|
@@ -528,7 +527,7 @@ export function meetsMinimumScore(
|
|
|
528
527
|
minTotal = 0,
|
|
529
528
|
requireVideo = false,
|
|
530
529
|
requireAudio = false,
|
|
531
|
-
minTrackTypes = 0
|
|
530
|
+
minTrackTypes = 0,
|
|
532
531
|
} = requirements;
|
|
533
532
|
|
|
534
533
|
// Check total score
|
|
@@ -537,11 +536,11 @@ export function meetsMinimumScore(
|
|
|
537
536
|
}
|
|
538
537
|
|
|
539
538
|
// Check track type requirements
|
|
540
|
-
if (requireVideo && !score.trackTypes.includes(
|
|
539
|
+
if (requireVideo && !score.trackTypes.includes("video")) {
|
|
541
540
|
return false;
|
|
542
541
|
}
|
|
543
542
|
|
|
544
|
-
if (requireAudio && !score.trackTypes.includes(
|
|
543
|
+
if (requireAudio && !score.trackTypes.includes("audio")) {
|
|
545
544
|
return false;
|
|
546
545
|
}
|
|
547
546
|
|
package/src/core/selector.ts
CHANGED
|
@@ -5,12 +5,8 @@
|
|
|
5
5
|
* All selection logic is now consolidated in PlayerManager.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export type {
|
|
9
|
-
PlayerSelection,
|
|
10
|
-
PlayerCombination,
|
|
11
|
-
PlayerManagerOptions,
|
|
12
|
-
} from './PlayerManager';
|
|
8
|
+
export type { PlayerSelection, PlayerCombination, PlayerManagerOptions } from "./PlayerManager";
|
|
13
9
|
|
|
14
10
|
// Legacy type aliases for external consumers
|
|
15
|
-
import type { PlayerManagerOptions } from
|
|
11
|
+
import type { PlayerManagerOptions } from "./PlayerManager";
|
|
16
12
|
export type SelectionOptions = PlayerManagerOptions;
|