@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.
Files changed (82) hide show
  1. package/README.md +21 -6
  2. package/dist/cjs/index.js +792 -146
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/esm/index.js +792 -146
  5. package/dist/esm/index.js.map +1 -1
  6. package/dist/player.css +185 -373
  7. package/dist/types/core/GatewayClient.d.ts +3 -4
  8. package/dist/types/core/InteractionController.d.ts +12 -0
  9. package/dist/types/core/MetaTrackManager.d.ts +1 -1
  10. package/dist/types/core/PlayerController.d.ts +18 -2
  11. package/dist/types/core/PlayerInterface.d.ts +10 -0
  12. package/dist/types/core/SeekingUtils.d.ts +3 -1
  13. package/dist/types/core/StreamStateClient.d.ts +1 -1
  14. package/dist/types/players/HlsJsPlayer.d.ts +8 -0
  15. package/dist/types/players/MewsWsPlayer/index.d.ts +1 -1
  16. package/dist/types/players/VideoJsPlayer.d.ts +12 -4
  17. package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +1 -1
  18. package/dist/types/players/WebCodecsPlayer/index.d.ts +11 -0
  19. package/dist/types/players/WebCodecsPlayer/types.d.ts +25 -3
  20. package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +20 -2
  21. package/dist/types/types.d.ts +32 -1
  22. package/dist/types/vanilla/FrameWorksPlayer.d.ts +5 -5
  23. package/dist/types/vanilla/index.d.ts +3 -3
  24. package/dist/workers/decoder.worker.js +183 -6
  25. package/dist/workers/decoder.worker.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/core/ABRController.ts +38 -36
  28. package/src/core/CodecUtils.ts +50 -47
  29. package/src/core/Disposable.ts +4 -4
  30. package/src/core/EventEmitter.ts +1 -1
  31. package/src/core/GatewayClient.ts +48 -48
  32. package/src/core/InteractionController.ts +89 -82
  33. package/src/core/LiveDurationProxy.ts +14 -16
  34. package/src/core/MetaTrackManager.ts +74 -66
  35. package/src/core/MistReporter.ts +72 -45
  36. package/src/core/MistSignaling.ts +59 -56
  37. package/src/core/PlayerController.ts +724 -375
  38. package/src/core/PlayerInterface.ts +89 -59
  39. package/src/core/PlayerManager.ts +118 -123
  40. package/src/core/PlayerRegistry.ts +59 -42
  41. package/src/core/QualityMonitor.ts +38 -31
  42. package/src/core/ScreenWakeLockManager.ts +8 -9
  43. package/src/core/SeekingUtils.ts +31 -22
  44. package/src/core/StreamStateClient.ts +75 -69
  45. package/src/core/SubtitleManager.ts +25 -23
  46. package/src/core/TelemetryReporter.ts +34 -31
  47. package/src/core/TimeFormat.ts +13 -17
  48. package/src/core/TimerManager.ts +25 -9
  49. package/src/core/UrlUtils.ts +20 -17
  50. package/src/core/detector.ts +44 -44
  51. package/src/core/index.ts +57 -48
  52. package/src/core/scorer.ts +137 -138
  53. package/src/core/selector.ts +2 -6
  54. package/src/global.d.ts +1 -1
  55. package/src/index.ts +46 -35
  56. package/src/players/DashJsPlayer.ts +175 -114
  57. package/src/players/HlsJsPlayer.ts +154 -76
  58. package/src/players/MewsWsPlayer/SourceBufferManager.ts +44 -39
  59. package/src/players/MewsWsPlayer/WebSocketManager.ts +9 -10
  60. package/src/players/MewsWsPlayer/index.ts +196 -154
  61. package/src/players/MewsWsPlayer/types.ts +21 -21
  62. package/src/players/MistPlayer.ts +46 -27
  63. package/src/players/MistWebRTCPlayer/index.ts +175 -129
  64. package/src/players/NativePlayer.ts +203 -143
  65. package/src/players/VideoJsPlayer.ts +200 -146
  66. package/src/players/WebCodecsPlayer/JitterBuffer.ts +6 -7
  67. package/src/players/WebCodecsPlayer/LatencyProfiles.ts +43 -43
  68. package/src/players/WebCodecsPlayer/RawChunkParser.ts +10 -10
  69. package/src/players/WebCodecsPlayer/SyncController.ts +46 -55
  70. package/src/players/WebCodecsPlayer/WebSocketController.ts +67 -69
  71. package/src/players/WebCodecsPlayer/index.ts +280 -220
  72. package/src/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.ts +12 -17
  73. package/src/players/WebCodecsPlayer/types.ts +81 -53
  74. package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +255 -192
  75. package/src/players/WebCodecsPlayer/worker/types.ts +33 -29
  76. package/src/players/index.ts +8 -8
  77. package/src/styles/animations.css +2 -1
  78. package/src/styles/player.css +182 -356
  79. package/src/styles/tailwind.css +473 -159
  80. package/src/types.ts +75 -33
  81. package/src/vanilla/FrameWorksPlayer.ts +34 -19
  82. 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 './detector';
8
+ export * from "./detector";
9
9
 
10
10
  // Scoring system
11
- export * from './scorer';
11
+ export * from "./scorer";
12
12
 
13
13
  // Player interfaces and base classes
14
- export * from './PlayerInterface';
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 './PlayerManager';
23
+ } from "./PlayerManager";
24
24
 
25
25
  // Player registry with all implementations
26
- export * from './PlayerRegistry';
26
+ export * from "./PlayerRegistry";
27
27
 
28
28
  // Re-export for convenience
29
- export { globalPlayerManager, createPlayerManager, ensurePlayersRegistered } from './PlayerRegistry';
30
- export type { IPlayer, PlayerOptions } from './PlayerInterface';
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 './QualityMonitor';
34
- export type { QualityMonitorOptions, QualityMonitorState, PlayerProtocol } from './QualityMonitor';
35
- export { TelemetryReporter } from './TelemetryReporter';
36
- export type { TelemetryReporterConfig } from './TelemetryReporter';
37
- export { ABRController } from './ABRController';
38
- export type { ABRControllerConfig, ABRDecision } from './ABRController';
39
- export { MetaTrackManager } from './MetaTrackManager';
40
- export type { MetaTrackManagerConfig, MetaTrackSubscription } from './MetaTrackManager';
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 './EventEmitter';
44
- export { GatewayClient } from './GatewayClient';
45
- export type { GatewayClientConfig, GatewayClientEvents, GatewayStatus } from './GatewayClient';
46
- export { StreamStateClient } from './StreamStateClient';
47
- export type { StreamStateClientConfig, StreamStateClientEvents } from './StreamStateClient';
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 './PlayerController';
56
- export type { PlayerControllerConfig, PlayerControllerEvents } from './PlayerController';
59
+ } from "./PlayerController";
60
+ export type { PlayerControllerConfig, PlayerControllerEvents } from "./PlayerController";
57
61
 
58
62
  // MistServer reporting (MistMetaPlayer feature backport)
59
- export { MistReporter } from './MistReporter';
60
- export type { MistReporterStats, MistReporterOptions, MistReporterInitialReport } from './MistReporter';
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 './MistSignaling';
64
- export type { MistSignalingConfig, MistSignalingEvents, MistTimeUpdate, MistSignalingState } from './MistSignaling';
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 './LiveDurationProxy';
68
- export type { LiveDurationProxyOptions, LiveDurationState } from './LiveDurationProxy';
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 './TimerManager';
84
+ export { TimerManager } from "./TimerManager";
72
85
 
73
86
  // Disposable interface for consistent cleanup
74
- export { BaseDisposable, disposeAll, createCompositeDisposable } from './Disposable';
75
- export type { Disposable } from './Disposable';
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 './UrlUtils';
100
+ } from "./UrlUtils";
88
101
 
89
102
  // Codec utilities (MistMetaPlayer feature backport)
90
- export {
91
- translateCodec,
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 './SubtitleManager';
99
- export type { SubtitleTrackInfo, SubtitleManagerConfig } from './SubtitleManager';
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 './InteractionController';
103
- export type { InteractionControllerConfig, InteractionState } from './InteractionController';
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 './ScreenWakeLockManager';
107
- export type { ScreenWakeLockConfig } from './ScreenWakeLockManager';
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 './SeekingUtils';
131
+ } from "./SeekingUtils";
123
132
  export type {
124
133
  LatencyTier,
125
134
  LiveThresholds,
126
135
  SeekableRange,
127
136
  SeekableRangeParams,
128
137
  CanSeekParams,
129
- } from './SeekingUtils';
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 './TimeFormat';
140
- export type { TimeDisplayParams } from './TimeFormat';
148
+ } from "./TimeFormat";
149
+ export type { TimeDisplayParams } from "./TimeFormat";
@@ -11,7 +11,7 @@
11
11
  * - Protocol-specific routing (new)
12
12
  */
13
13
 
14
- import type { PlaybackMode } from '../types';
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 - (priority / Math.max(maxPriority, 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 - (sourceIndex / Math.max(totalSources - 1, 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
- 'flash/7',
130
- 'flash/10',
131
- 'flash/11',
123
+ "flash/7",
124
+ "flash/10",
125
+ "flash/11",
132
126
  // Silverlight - dead technology
133
- 'silverlight',
127
+ "silverlight",
134
128
  // SDP is WebRTC signaling format, not a playback source type
135
- 'html5/application/sdp',
136
- 'sdp',
129
+ "html5/application/sdp",
130
+ "sdp",
137
131
  // MPEG-TS - no browser support, no wrapper implementation in reference
138
- 'html5/video/mpeg',
132
+ "html5/video/mpeg",
139
133
  // Smooth Streaming - intentionally disabled in reference (commented out in dashjs.js!)
140
- 'html5/application/vnd.ms-sstr+xml',
134
+ "html5/application/vnd.ms-sstr+xml",
141
135
  // Server-side only protocols - browsers can't connect to these directly
142
- 'srt',
143
- 'rtsp',
144
- 'rtmp',
136
+ "srt",
137
+ "rtsp",
138
+ "rtmp",
145
139
  // MistServer internal protocols - not for browser playback
146
- 'dtsc',
140
+ "dtsc",
147
141
  // NOTE: ws/video/raw is supported by WebCodecs player
148
142
  // Image formats - not video playback
149
- 'html5/image/jpeg',
143
+ "html5/image/jpeg",
150
144
  // Script/metadata formats - not playback sources
151
- 'html5/text/javascript',
145
+ "html5/text/javascript",
152
146
  // Subtitle-only formats - not standalone playback sources (used as tracks)
153
- 'html5/text/vtt',
154
- 'html5/text/plain',
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
- 'html5/video/webm': 0.80, // Heavy penalty - very broken
179
- 'html5/audio/webm': 0.60,
180
- 'ws/video/webm': 0.80,
181
- 'wss/video/webm': 0.80,
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
- 'ws/video/mp4': 0.50,
184
- 'wss/video/mp4': 0.50,
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
- 'dash/video/mp4': 0.90, // Below legacy
187
- 'dash/video/webm': 0.95,
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
- 'html5/application/vnd.apple.mpegurl;version=7': 0.20, // HLSv7 is CMAF-based
186
+ "html5/application/vnd.apple.mpegurl;version=7": 0.2, // HLSv7 is CMAF-based
190
187
  // LL-HLS specific - experimental, spotty support
191
- 'll-hls': 0.20,
192
- 'cmaf': 0.20,
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('webm')) {
206
- return 0.50; // Heavy penalty for any WebM variant
202
+ if (lowerMime.includes("webm")) {
203
+ return 0.5; // Heavy penalty for any WebM variant
207
204
  }
208
- if (lowerMime.startsWith('dash/')) {
209
- return 0.40; // DASH penalty
205
+ if (lowerMime.startsWith("dash/")) {
206
+ return 0.4; // DASH penalty
210
207
  }
211
- if (lowerMime.includes('cmaf') || lowerMime.includes('ll-hls')) {
212
- return 0.20;
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
- 'webcodecs': 0.95, // Stable, lowest latency option
223
- 'videojs': 0.95, // Fast loading, built-in HLS via VHS
224
- 'hlsjs': 0.90, // Battle-tested but slower to load
225
- 'native': 0.85, // Native is lightweight but has edge cases
226
- 'mist-webrtc': 0.85, // Full signaling features
227
- 'mews': 0.75, // Custom protocol, less tested
228
- 'mist-legacy': 0.70, // Ultimate fallback, delegates everything
229
- 'dashjs': 0.50, // Broken, lowest reliability
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
- 'low-latency': {
250
+ "low-latency": {
254
251
  // WebCodecs raw/h264: HIGHEST PRIORITY - ultra-low latency via WebCodecs API
255
- 'ws/video/raw': 0.55,
256
- 'wss/video/raw': 0.55,
257
- 'ws/video/h264': 0.52,
258
- 'wss/video/h264': 0.52,
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
- 'whep': 0.50,
261
- 'webrtc': 0.45,
262
- 'mist/webrtc': 0.45,
257
+ whep: 0.5,
258
+ webrtc: 0.25,
259
+ "mist/webrtc": 0.25,
263
260
  // MP4/WS (MEWS): 2-5s latency, good fallback
264
- 'ws/video/mp4': 0.30,
265
- 'wss/video/mp4': 0.30,
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
- 'html5/video/mp4': 0.15,
264
+ "html5/video/mp4": 0.15,
268
265
  // HLS: high latency, minimal bonus
269
- 'html5/application/vnd.apple.mpegurl': 0.05,
266
+ "html5/application/vnd.apple.mpegurl": 0.05,
270
267
  },
271
- 'quality': {
268
+ quality: {
272
269
  // MP4/WS: stable + lower latency than HLS, preferred when supported
273
- 'ws/video/mp4': 0.45,
274
- 'wss/video/mp4': 0.45,
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
- 'ws/video/raw': 0.40,
277
- 'wss/video/raw': 0.40,
278
- 'ws/video/h264': 0.38,
279
- 'wss/video/h264': 0.38,
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
- 'html5/application/vnd.apple.mpegurl': 0.30,
282
- 'html5/video/mp4': 0.20,
278
+ "html5/application/vnd.apple.mpegurl": 0.3,
279
+ "html5/video/mp4": 0.2,
283
280
  // WebRTC: minimal for quality mode
284
- 'whep': 0.05,
285
- 'webrtc': 0.05,
281
+ whep: 0.05,
282
+ webrtc: 0.05,
283
+ "mist/webrtc": 0.05,
286
284
  },
287
- 'vod': {
285
+ vod: {
288
286
  // VOD/Clip: Prefer seekable protocols, EXCLUDE WebRTC (no seek support)
289
- 'html5/video/mp4': 0.50, // Progressive MP4 - best for clips
290
- 'html5/application/vnd.apple.mpegurl': 0.45, // HLS - ABR support
291
- 'dash/video/mp4': 0.40, // DASH - ABR support
292
- 'ws/video/mp4': 0.35, // MEWS - seekable via MSE
293
- 'wss/video/mp4': 0.35,
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
- 'whep': -1.0,
296
- 'webrtc': -1.0,
297
- 'mist/webrtc': -1.0,
293
+ whep: -1.0,
294
+ webrtc: -1.0,
295
+ "mist/webrtc": -1.0,
298
296
  },
299
- 'auto': {
297
+ auto: {
300
298
  // WebCodecs raw: highest priority for low-latency live streams
301
- 'ws/video/raw': 0.50,
302
- 'wss/video/raw': 0.50,
303
- 'ws/video/h264': 0.48,
304
- 'wss/video/h264': 0.48,
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
- 'html5/video/mp4': 0.42,
304
+ "html5/video/mp4": 0.42,
307
305
  // WHEP/WebRTC: good for low latency
308
- 'whep': 0.38,
309
- 'webrtc': 0.35,
310
- 'mist/webrtc': 0.35,
306
+ whep: 0.38,
307
+ webrtc: 0.2,
308
+ "mist/webrtc": 0.2,
311
309
  // MP4/WS (MEWS): lower latency than HLS
312
- 'ws/video/mp4': 0.30,
313
- 'wss/video/mp4': 0.30,
310
+ "ws/video/mp4": 0.3,
311
+ "wss/video/mp4": 0.3,
314
312
  // HLS: high latency, fallback option (but reliable)
315
- 'html5/application/vnd.apple.mpegurl': 0.20,
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
- 'whep': { prefer: ['native'] },
332
- 'webrtc': { prefer: ['mist-webrtc', 'native'] },
333
- 'mist/webrtc': { prefer: ['mist-webrtc'] },
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
- 'ws/video/raw': { prefer: ['webcodecs'] },
337
- 'wss/video/raw': { prefer: ['webcodecs'] },
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
- 'ws/video/h264': { prefer: ['webcodecs'] },
341
- 'wss/video/h264': { prefer: ['webcodecs'] },
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
- 'ws/video/mp4': { prefer: ['mews'] },
345
- 'wss/video/mp4': { prefer: ['mews'] },
346
- 'ws/video/webm': { prefer: ['mews'] },
347
- 'wss/video/webm': { prefer: ['mews'] },
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
- 'html5/application/vnd.apple.mpegurl': {
351
- prefer: ['videojs', 'hlsjs'],
352
- avoid: ['native'],
348
+ "html5/application/vnd.apple.mpegurl": {
349
+ prefer: ["videojs", "hlsjs"],
350
+ avoid: ["native"],
353
351
  },
354
- 'html5/application/vnd.apple.mpegurl;version=7': {
355
- prefer: ['videojs', 'hlsjs'],
356
- avoid: ['native'],
352
+ "html5/application/vnd.apple.mpegurl;version=7": {
353
+ prefer: ["videojs", "hlsjs"],
354
+ avoid: ["native"],
357
355
  },
358
356
 
359
357
  // DASH
360
- 'dash/video/mp4': { prefer: ['dashjs', 'videojs'] },
358
+ "dash/video/mp4": { prefer: ["dashjs", "videojs"] },
361
359
 
362
360
  // Progressive download
363
- 'html5/video/mp4': { prefer: ['native'] },
364
- 'html5/video/webm': { prefer: ['native'] },
361
+ "html5/video/mp4": { prefer: ["native"] },
362
+ "html5/video/webm": { prefer: ["native"] },
365
363
 
366
364
  // Audio-only formats
367
- 'html5/audio/aac': { prefer: ['native'] },
368
- 'html5/audio/mp3': { prefer: ['native'] },
369
- 'html5/audio/flac': { prefer: ['native'] },
370
- 'html5/audio/wav': { prefer: ['native'] },
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 - (preferIndex * 0.05);
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 = 'auto',
430
+ playbackMode = "auto",
433
431
  weights = {
434
- tracks: 0.50, // Reduced from 0.70 to make room for new factors
435
- priority: 0.10, // Reduced from 0.15
436
- source: 0.05, // Reduced from 0.10
437
- quality: 0.05, // Unchanged
438
- reliability: 0.10, // NEW: Player stability
439
- mode: 0.10, // Playback mode bonus (reduced slightly)
440
- routing: 0.08, // Protocol routing preference
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 = mimeType && playerShortname ? calculateRoutingBonus(mimeType, playerShortname) : 0;
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('video')) {
539
+ if (requireVideo && !score.trackTypes.includes("video")) {
541
540
  return false;
542
541
  }
543
542
 
544
- if (requireAudio && !score.trackTypes.includes('audio')) {
543
+ if (requireAudio && !score.trackTypes.includes("audio")) {
545
544
  return false;
546
545
  }
547
546
 
@@ -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 './PlayerManager';
11
+ import type { PlayerManagerOptions } from "./PlayerManager";
16
12
  export type SelectionOptions = PlayerManagerOptions;