@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
@@ -10,10 +10,10 @@ export type GatewayStatus = 'idle' | 'loading' | 'ready' | 'error';
10
10
  export interface GatewayClientConfig {
11
11
  /** Gateway GraphQL endpoint URL */
12
12
  gatewayUrl: string;
13
- /** Content type to resolve */
14
- contentType: ContentType;
15
13
  /** Content identifier (stream name) */
16
14
  contentId: string;
15
+ /** Optional content type (no longer required for resolution) */
16
+ contentType?: ContentType;
17
17
  /** Optional auth token for private streams */
18
18
  authToken?: string;
19
19
  /** Maximum retry attempts (default: 3) */
@@ -40,8 +40,7 @@ type CircuitBreakerState = 'closed' | 'open' | 'half-open';
40
40
  * ```typescript
41
41
  * const client = new GatewayClient({
42
42
  * gatewayUrl: 'https://gateway.example.com/graphql',
43
- * contentType: 'live',
44
- * contentId: 'my-stream',
43
+ * contentId: 'pk_...', // playbackId (view key)
45
44
  * });
46
45
  *
47
46
  * client.on('statusChange', ({ status }) => console.log('Status:', status));
@@ -12,6 +12,7 @@ export interface InteractionControllerConfig {
12
12
  container: HTMLElement;
13
13
  videoElement: HTMLVideoElement;
14
14
  isLive: boolean;
15
+ isPaused?: () => boolean;
15
16
  onPlayPause: () => void;
16
17
  onSeek: (delta: number) => void;
17
18
  onVolumeChange: (delta: number) => void;
@@ -21,7 +22,11 @@ export interface InteractionControllerConfig {
21
22
  onLoopToggle?: () => void;
22
23
  onSpeedChange: (speed: number, isHolding: boolean) => void;
23
24
  onSeekPercent?: (percent: number) => void;
25
+ /** Optional: player-specific frame stepping (return true if handled) */
26
+ onFrameStep?: (direction: -1 | 1, seconds: number) => boolean | void;
24
27
  speedHoldValue?: number;
28
+ /** Frame step duration in seconds (for prev/next frame shortcuts) */
29
+ frameStepSeconds?: number;
25
30
  /** Idle timeout in ms (default 5000). Set to 0 to disable. */
26
31
  idleTimeout?: number;
27
32
  /** Callback fired when user becomes idle */
@@ -58,6 +63,9 @@ export declare class InteractionController {
58
63
  private boundPointerCancel;
59
64
  private boundContextMenu;
60
65
  private boundMouseMove;
66
+ private boundDoubleClick;
67
+ private boundDocumentKeyDown;
68
+ private boundDocumentKeyUp;
61
69
  constructor(config: InteractionControllerConfig);
62
70
  /**
63
71
  * Attach event listeners to container
@@ -85,8 +93,11 @@ export declare class InteractionController {
85
93
  updateConfig(updates: Partial<InteractionControllerConfig>): void;
86
94
  private handleKeyDown;
87
95
  private handleKeyUp;
96
+ private shouldHandleKeyboard;
88
97
  private handleSpaceDown;
89
98
  private handleSpaceUp;
99
+ private handleDoubleClick;
100
+ private stepFrame;
90
101
  private handlePointerDown;
91
102
  private handlePointerUp;
92
103
  private handlePointerCancel;
@@ -118,4 +129,5 @@ export declare class InteractionController {
118
129
  resumeIdleTracking(): void;
119
130
  private isInputElement;
120
131
  private isControlElement;
132
+ private getFrameStepSeconds;
121
133
  }
@@ -40,7 +40,7 @@ type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecti
40
40
  * ```ts
41
41
  * const manager = new MetaTrackManager({
42
42
  * mistBaseUrl: 'https://mist.example.com',
43
- * streamName: 'my-stream',
43
+ * streamName: 'pk_...', // playbackId (view key)
44
44
  * });
45
45
  *
46
46
  * manager.subscribe('1', (event) => {
@@ -17,7 +17,7 @@ export interface PlayerControllerConfig {
17
17
  /** Content identifier (stream name) */
18
18
  contentId: string;
19
19
  /** Content type */
20
- contentType: ContentType;
20
+ contentType?: ContentType;
21
21
  /** Pre-resolved endpoints (skip gateway) */
22
22
  endpoints?: ContentEndpoints;
23
23
  /** Gateway URL (for FrameWorks Gateway resolution) */
@@ -219,7 +219,7 @@ export declare function buildStreamInfoFromEndpoints(endpoints: ContentEndpoints
219
219
  * @example
220
220
  * ```typescript
221
221
  * const controller = new PlayerController({
222
- * contentId: 'my-stream',
222
+ * contentId: 'pk_...', // playbackId (view key)
223
223
  * contentType: 'live',
224
224
  * gatewayUrl: 'https://gateway.example.com/graphql',
225
225
  * });
@@ -238,6 +238,7 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
238
238
  private config;
239
239
  private state;
240
240
  private lastEmittedState;
241
+ private suppressPlayPauseEventsUntil;
241
242
  private gatewayClient;
242
243
  private streamStateClient;
243
244
  private playerManager;
@@ -249,6 +250,10 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
249
250
  private streamState;
250
251
  /** Tracks parsed from MistServer JSON response (used for direct MistServer mode) */
251
252
  private mistTracks;
253
+ /** Gateway-seeded metadata (used as base for Mist enrichment) */
254
+ private metadataSeed;
255
+ /** Merged metadata (gateway seed + Mist enrichment) */
256
+ private metadata;
252
257
  private cleanupFns;
253
258
  private isDestroyed;
254
259
  private isAttached;
@@ -319,6 +324,10 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
319
324
  getEndpoints(): ContentEndpoints | null;
320
325
  /** Get content metadata (title, description, duration, etc.) */
321
326
  getMetadata(): ContentMetadata | null;
327
+ private setMetadataSeed;
328
+ private refreshMergedMetadata;
329
+ private buildMetadataTracks;
330
+ private sanitizeMistInfo;
322
331
  /** Get stream info (sources + tracks for player selection) */
323
332
  getStreamInfo(): StreamInfo | null;
324
333
  /** Get video element (null if not ready) */
@@ -381,6 +390,8 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
381
390
  hasAudioTrack(): boolean;
382
391
  /** Check if playback rate adjustment is supported */
383
392
  canAdjustPlaybackRate(): boolean;
393
+ /** Resolve content type from config override or Gateway metadata */
394
+ private getResolvedContentType;
384
395
  /** Check if source is WebRTC/MediaStream */
385
396
  isWebRTCSource(): boolean;
386
397
  /** Check if currently in fullscreen mode */
@@ -494,6 +505,7 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
494
505
  private getEffectiveCurrentTime;
495
506
  private getEffectiveDuration;
496
507
  private getPlayerSeekableRange;
508
+ private getFrameStepSecondsFromTracks;
497
509
  private deriveBufferWindowMsFromTracks;
498
510
  /** Get current time */
499
511
  getCurrentTime(): number;
@@ -501,6 +513,10 @@ export declare class PlayerController extends TypedEventEmitter<PlayerController
501
513
  getDuration(): number;
502
514
  /** Check if paused */
503
515
  isPaused(): boolean;
516
+ /** Suppress play/pause-driven UI updates for a short window */
517
+ suppressPlayPauseEvents(ms?: number): void;
518
+ /** Check if play/pause UI updates should be suppressed */
519
+ shouldSuppressVideoEvents(): boolean;
504
520
  /** Check if muted */
505
521
  isMuted(): boolean;
506
522
  /** Skip backward by specified seconds (default 10) */
@@ -42,6 +42,8 @@ export interface PlayerOptions {
42
42
  height?: number;
43
43
  /** Enable dev mode - for Legacy player, uses MistServer's dev skin with source selection */
44
44
  devMode?: boolean;
45
+ /** Enable debug logging in player implementations */
46
+ debug?: boolean;
45
47
  onReady?: (element: HTMLVideoElement) => void;
46
48
  onError?: (error: string | Error) => void;
47
49
  onPlay?: () => void;
@@ -52,6 +54,12 @@ export interface PlayerOptions {
52
54
  onPlaying?: () => void;
53
55
  onCanPlay?: () => void;
54
56
  onDurationChange?: (duration: number) => void;
57
+ /** HLS.js configuration override (merged with defaults) */
58
+ hlsConfig?: Record<string, unknown>;
59
+ /** DASH.js configuration override (merged with defaults) */
60
+ dashConfig?: Record<string, unknown>;
61
+ /** Video.js VHS configuration override (merged with defaults) */
62
+ vhsConfig?: Record<string, unknown>;
55
63
  }
56
64
  export interface PlayerCapability {
57
65
  /** Player name for display */
@@ -173,6 +181,8 @@ export interface IPlayer {
173
181
  getCurrentQuality?(): string | null;
174
182
  isLive?(): boolean;
175
183
  jumpToLive?(): void;
184
+ /** Optional: frame step (direction -1/1, optional step seconds) */
185
+ frameStep?(direction: -1 | 1, seconds?: number): void;
176
186
  requestPiP?(): Promise<void>;
177
187
  /**
178
188
  * Optional: Retrieve player-specific stats (e.g., WebRTC inbound-rtp)
@@ -30,6 +30,8 @@ export interface SeekableRangeParams {
30
30
  mistStreamInfo?: MistStreamInfo;
31
31
  currentTime: number;
32
32
  duration: number;
33
+ /** Allow Mist track metadata for MediaStream sources (e.g., WebCodecs DVR) */
34
+ allowMediaStreamDvr?: boolean;
33
35
  }
34
36
  export interface CanSeekParams {
35
37
  video: HTMLVideoElement | null;
@@ -87,7 +89,7 @@ export declare function supportsPlaybackRate(video: HTMLVideoElement | null): bo
87
89
  * 1. Browser's video.seekable ranges (most accurate for MSE-based players)
88
90
  * 2. Track firstms/lastms from MistServer metadata
89
91
  * 3. buffer_window from MistServer signaling
90
- * 4. Fallback (only for non-WebRTC sources)
92
+ * 4. No fallback (treat as live-only when no reliable data)
91
93
  *
92
94
  * @param params - Calculation parameters
93
95
  * @returns Seekable range with start and live edge
@@ -37,7 +37,7 @@ export interface StreamStateClientEvents {
37
37
  * ```typescript
38
38
  * const client = new StreamStateClient({
39
39
  * mistBaseUrl: 'https://mist.example.com',
40
- * streamName: 'my-stream',
40
+ * streamName: 'pk_...', // playbackId (view key)
41
41
  * });
42
42
  *
43
43
  * client.on('stateChange', ({ state }) => console.log('State:', state));
@@ -29,6 +29,14 @@ export declare class HlsJsPlayerImpl extends BasePlayer {
29
29
  * Uses HLS.js liveSyncPosition when available (more accurate)
30
30
  */
31
31
  jumpToLive(): void;
32
+ /**
33
+ * Provide a seekable range override for live streams.
34
+ * Uses liveSyncPosition as the live edge to avoid waiting for the absolute end.
35
+ */
36
+ getSeekableRange(): {
37
+ start: number;
38
+ end: number;
39
+ } | null;
32
40
  /**
33
41
  * Get latency from live edge (for live streams)
34
42
  */
@@ -37,7 +37,7 @@ export declare class MewsWsPlayerImpl extends BasePlayer {
37
37
  private analyticsTimer;
38
38
  isMimeSupported(mimetype: string): boolean;
39
39
  isBrowserSupported(mimetype: string, source: StreamSource, streamInfo: StreamInfo): boolean | string[];
40
- initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions): Promise<HTMLVideoElement>;
40
+ initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions, streamInfo?: StreamInfo): Promise<HTMLVideoElement>;
41
41
  /**
42
42
  * Handle MediaSource sourceopen event.
43
43
  * Ported from mews.js:143-148, 198-204, 885-902
@@ -21,10 +21,6 @@ export declare class VideoJsPlayerImpl extends BasePlayer {
21
21
  private getVideoJsType;
22
22
  setPlaybackRate(rate: number): void;
23
23
  getCurrentTime(): number;
24
- getSeekableRange(): {
25
- start: number;
26
- end: number;
27
- } | null;
28
24
  /**
29
25
  * Seek to time using VideoJS API (fixes backwards seeking in HLS).
30
26
  * Time should be in the corrected coordinate space (with firstms offset applied).
@@ -46,11 +42,23 @@ export declare class VideoJsPlayerImpl extends BasePlayer {
46
42
  * Check if the stream is live
47
43
  */
48
44
  isLiveStream(): boolean;
45
+ /**
46
+ * Get the calculated duration for live streams
47
+ */
48
+ getDuration(): number;
49
49
  /**
50
50
  * Jump to live edge
51
51
  * Uses VideoJS liveTracker when available, otherwise LiveDurationProxy
52
52
  */
53
53
  jumpToLive(): void;
54
+ /**
55
+ * Provide a seekable range override for live streams.
56
+ * Uses VideoJS liveTracker seekableEnd as the live edge when available.
57
+ */
58
+ getSeekableRange(): {
59
+ start: number;
60
+ end: number;
61
+ } | null;
54
62
  /**
55
63
  * Get latency from live edge (for live streams)
56
64
  */
@@ -158,7 +158,7 @@ export declare class SyncController {
158
158
  /**
159
159
  * Register a new track
160
160
  */
161
- addTrack(trackIndex: number, track: TrackInfo): void;
161
+ addTrack(_trackIndex: number, _track: TrackInfo): void;
162
162
  /**
163
163
  * Remove a track
164
164
  */
@@ -35,6 +35,8 @@ export declare class WebCodecsPlayerImpl extends BasePlayer {
35
35
  private debugging;
36
36
  private verboseDebugging;
37
37
  private streamType;
38
+ /** Payload format: 'avcc' for ws/video/raw, 'annexb' for ws/video/h264 */
39
+ private payloadFormat;
38
40
  private workerUidCounter;
39
41
  private workerListeners;
40
42
  private _duration;
@@ -47,6 +49,12 @@ export declare class WebCodecsPlayerImpl extends BasePlayer {
47
49
  private _framesDecoded;
48
50
  private _bytesReceived;
49
51
  private _messagesReceived;
52
+ private _isPaused;
53
+ private _suppressPlayPauseSync;
54
+ private _onVideoPlay?;
55
+ private _onVideoPause?;
56
+ private _pendingStepPause;
57
+ private _stepPauseTimeout;
50
58
  private static codecCache;
51
59
  /**
52
60
  * Get cache key for a track's codec configuration
@@ -95,8 +103,11 @@ export declare class WebCodecsPlayerImpl extends BasePlayer {
95
103
  private closePipeline;
96
104
  play(): Promise<void>;
97
105
  pause(): void;
106
+ private finishStepPause;
107
+ frameStep(direction: -1 | 1, _seconds?: number): void;
98
108
  seek(time: number): void;
99
109
  setPlaybackRate(rate: number): void;
110
+ isPaused(): boolean;
100
111
  isLive(): boolean;
101
112
  jumpToLive(): void;
102
113
  /**
@@ -143,6 +143,8 @@ export interface CreatePipelineMessage {
143
143
  track: TrackInfo;
144
144
  opts: {
145
145
  optimizeForLatency: boolean;
146
+ /** Payload format: 'avcc' (length-prefixed) or 'annexb' (start-code delimited) */
147
+ payloadFormat?: 'avcc' | 'annexb';
146
148
  };
147
149
  uid?: number;
148
150
  }
@@ -181,9 +183,10 @@ export interface ClosePipelineMessage {
181
183
  }
182
184
  export interface FrameTimingMessage {
183
185
  type: 'frametiming';
184
- action: 'setSpeed' | 'reset';
186
+ action: 'setSpeed' | 'reset' | 'setPaused';
185
187
  speed?: number;
186
188
  tweak?: number;
189
+ paused?: boolean;
187
190
  uid?: number;
188
191
  }
189
192
  export interface SeekWorkerMessage {
@@ -196,7 +199,19 @@ export interface DebuggingMessage {
196
199
  value: boolean | 'verbose';
197
200
  uid?: number;
198
201
  }
199
- export type MainToWorkerMessage = CreatePipelineMessage | ConfigurePipelineMessage | ReceiveChunkMessage | SetWritableMessage | CreateGeneratorMessage | ClosePipelineMessage | FrameTimingMessage | SeekWorkerMessage | DebuggingMessage;
202
+ export interface FrameStepMessage {
203
+ type: 'framestep';
204
+ direction: -1 | 1;
205
+ uid?: number;
206
+ }
207
+ export interface WriteFrameResponseMessage {
208
+ type: 'writeframe';
209
+ idx: number;
210
+ uid?: number;
211
+ status: 'ok' | 'error';
212
+ error?: string;
213
+ }
214
+ export type MainToWorkerMessage = CreatePipelineMessage | ConfigurePipelineMessage | ReceiveChunkMessage | SetWritableMessage | CreateGeneratorMessage | ClosePipelineMessage | FrameTimingMessage | SeekWorkerMessage | DebuggingMessage | FrameStepMessage | WriteFrameResponseMessage;
200
215
  export interface AddTrackMessage {
201
216
  type: 'addtrack';
202
217
  idx: number;
@@ -228,6 +243,7 @@ export interface SendEventMessage {
228
243
  type: 'sendevent';
229
244
  kind: string;
230
245
  message?: string;
246
+ time?: number;
231
247
  idx?: number;
232
248
  uid?: number;
233
249
  }
@@ -243,7 +259,13 @@ export interface AckMessage {
243
259
  status?: 'ok' | 'error';
244
260
  error?: string;
245
261
  }
246
- export type WorkerToMainMessage = AddTrackMessage | RemoveTrackMessage | SetPlaybackRateMessage | ClosedMessage | LogMessage | SendEventMessage | StatsMessage | AckMessage;
262
+ export interface WriteFrameMessage {
263
+ type: 'writeframe';
264
+ idx: number;
265
+ frame: AudioData;
266
+ uid?: number;
267
+ }
268
+ export type WorkerToMainMessage = AddTrackMessage | RemoveTrackMessage | SetPlaybackRateMessage | ClosedMessage | LogMessage | SendEventMessage | StatsMessage | AckMessage | WriteFrameMessage;
247
269
  export interface FrameTimingStats {
248
270
  /** Timestamp when frame entered decoder (microseconds) */
249
271
  in: number;
@@ -10,6 +10,8 @@ export interface CreateMessage {
10
10
  track: TrackInfo;
11
11
  opts: {
12
12
  optimizeForLatency: boolean;
13
+ /** Payload format: 'avcc' (length-prefixed) or 'annexb' (start-code delimited) */
14
+ payloadFormat?: 'avcc' | 'annexb';
13
15
  };
14
16
  uid: number;
15
17
  }
@@ -48,9 +50,10 @@ export interface CloseMessage {
48
50
  }
49
51
  export interface FrameTimingMessage {
50
52
  type: 'frametiming';
51
- action: 'setSpeed' | 'reset';
53
+ action: 'setSpeed' | 'reset' | 'setPaused';
52
54
  speed?: number;
53
55
  tweak?: number;
56
+ paused?: boolean;
54
57
  uid: number;
55
58
  }
56
59
  export interface SeekMessage {
@@ -58,12 +61,17 @@ export interface SeekMessage {
58
61
  seekTime: number;
59
62
  uid: number;
60
63
  }
64
+ export interface FrameStepMessage {
65
+ type: 'framestep';
66
+ direction: -1 | 1;
67
+ uid: number;
68
+ }
61
69
  export interface DebuggingMessage {
62
70
  type: 'debugging';
63
71
  value: boolean | 'verbose';
64
72
  uid: number;
65
73
  }
66
- export type MainToWorkerMessage = CreateMessage | ConfigureMessage | ReceiveMessage | SetWritableMessage | CreateGeneratorMessage | CloseMessage | FrameTimingMessage | SeekMessage | DebuggingMessage;
74
+ export type MainToWorkerMessage = CreateMessage | ConfigureMessage | ReceiveMessage | SetWritableMessage | CreateGeneratorMessage | CloseMessage | FrameTimingMessage | SeekMessage | FrameStepMessage | DebuggingMessage;
67
75
  export interface AddTrackMessage {
68
76
  type: 'addtrack';
69
77
  idx: number;
@@ -97,6 +105,7 @@ export interface SendEventMessage {
97
105
  type: 'sendevent';
98
106
  kind: string;
99
107
  message?: string;
108
+ time?: number;
100
109
  idx?: number;
101
110
  uid: number;
102
111
  }
@@ -159,6 +168,13 @@ export interface PipelineState {
159
168
  data: Uint8Array;
160
169
  }>;
161
170
  outputQueue: DecodedFrame[];
171
+ /** Recent video frames for backward/forward stepping (video only) */
172
+ frameHistory?: Array<{
173
+ frame: VideoFrame;
174
+ timestamp: number;
175
+ }>;
176
+ /** Cursor into frameHistory for step navigation */
177
+ historyCursor?: number | null;
162
178
  stats: {
163
179
  framesIn: number;
164
180
  framesDecoded: number;
@@ -172,6 +188,8 @@ export interface PipelineState {
172
188
  lastChunkBytes: string;
173
189
  };
174
190
  optimizeForLatency: boolean;
191
+ /** Payload format: 'avcc' (length-prefixed) or 'annexb' (start-code delimited) */
192
+ payloadFormat: 'avcc' | 'annexb';
175
193
  }
176
194
  export interface ScheduleResult {
177
195
  /** Whether frame should be output now */
@@ -50,6 +50,8 @@ export interface PlayerOptions {
50
50
  hlsConfig?: HlsJsConfig;
51
51
  /** DASH.js configuration override (merged with defaults) */
52
52
  dashConfig?: DashJsConfig;
53
+ /** Video.js VHS configuration override (merged with defaults) */
54
+ vhsConfig?: VhsConfig;
53
55
  /** WebRTC configuration (ICE servers, etc.) */
54
56
  rtcConfig?: RTCConfiguration;
55
57
  /** String to append to all request URLs (auth tokens, tracking params) */
@@ -98,6 +100,21 @@ export interface DashJsConfig {
98
100
  };
99
101
  [key: string]: unknown;
100
102
  }
103
+ /** Video.js VHS (http-streaming) configuration subset */
104
+ export interface VhsConfig {
105
+ /** Start with lowest quality for faster initial playback */
106
+ enableLowInitialPlaylist?: boolean;
107
+ /** Initial bandwidth estimate in bits per second (e.g., 5_000_000 for 5 Mbps) */
108
+ bandwidth?: number;
109
+ /** Persist bandwidth estimate in localStorage across sessions */
110
+ useBandwidthFromLocalStorage?: boolean;
111
+ /** Enable partial segment appends for lower latency */
112
+ handlePartialData?: boolean;
113
+ /** Time delta for live range safety calculations (seconds) */
114
+ liveRangeSafeTimeDelta?: number;
115
+ /** Pass-through for other VHS options */
116
+ [key: string]: unknown;
117
+ }
101
118
  export type StreamProtocol = 'WHEP' | 'HLS' | 'DASH' | 'MP4' | 'WEBM' | 'RTMP' | 'MIST_HTML';
102
119
  export interface OutputCapabilities {
103
120
  supportsSeek: boolean;
@@ -138,7 +155,7 @@ export interface ContentMetadata {
138
155
  durationSeconds?: number;
139
156
  thumbnailUrl?: string;
140
157
  createdAt?: string;
141
- status?: 'AVAILABLE' | 'PROCESSING' | 'ERROR' | 'OFFLINE';
158
+ status?: 'AVAILABLE' | 'PROCESSING' | 'ERROR' | 'OFFLINE' | 'ONLINE' | 'INITIALIZING' | 'BOOTING' | 'WAITING_FOR_DATA' | 'SHUTTING_DOWN' | 'INVALID';
142
159
  viewers?: number;
143
160
  isLive?: boolean;
144
161
  recordingSizeBytes?: number;
@@ -147,6 +164,19 @@ export interface ContentMetadata {
147
164
  dvrStatus?: 'recording' | 'completed';
148
165
  /** Native container format: mp4, m3u8, webm, etc. */
149
166
  format?: string;
167
+ /** MistServer authoritative snapshot (merged into this metadata) */
168
+ mist?: MistStreamInfo;
169
+ /** Parsed track summary (derived from Mist metadata when available) */
170
+ tracks?: Array<{
171
+ type: 'video' | 'audio' | 'meta';
172
+ codec?: string;
173
+ width?: number;
174
+ height?: number;
175
+ bitrate?: number;
176
+ fps?: number;
177
+ channels?: number;
178
+ sampleRate?: number;
179
+ }>;
150
180
  }
151
181
  export interface ContentEndpoints {
152
182
  primary: EndpointInfo;
@@ -360,4 +390,5 @@ export interface PlayerMetadata {
360
390
  channels?: number;
361
391
  sampleRate?: number;
362
392
  }>;
393
+ mist?: MistStreamInfo;
363
394
  }
@@ -6,11 +6,11 @@
6
6
  *
7
7
  * @example
8
8
  * ```typescript
9
- * import { FrameWorksPlayer } from '@livepeer-frameworks/player/vanilla';
10
- * import '@livepeer-frameworks/player/player.css';
9
+ * import { FrameWorksPlayer } from '@livepeer-frameworks/player-core/vanilla';
10
+ * import '@livepeer-frameworks/player-core/player.css';
11
11
  *
12
12
  * const player = new FrameWorksPlayer('#player', {
13
- * contentId: 'my-stream',
13
+ * contentId: 'pk_...',
14
14
  * contentType: 'live',
15
15
  * gatewayUrl: 'https://gateway.example.com/graphql',
16
16
  * onStateChange: (state) => console.log('State:', state),
@@ -30,7 +30,7 @@ export interface FrameWorksPlayerOptions {
30
30
  /** Content identifier (stream name) */
31
31
  contentId: string;
32
32
  /** Content type */
33
- contentType: ContentType;
33
+ contentType?: ContentType;
34
34
  /** Pre-resolved endpoints (skip gateway) */
35
35
  endpoints?: ContentEndpoints;
36
36
  /** Gateway URL (required if endpoints not provided) */
@@ -57,7 +57,7 @@ export interface FrameWorksPlayerOptions {
57
57
  }
58
58
  interface LegacyConfig {
59
59
  contentId: string;
60
- contentType: ContentType;
60
+ contentType?: ContentType;
61
61
  thumbnailUrl?: string | null;
62
62
  options?: {
63
63
  gatewayUrl?: string;
@@ -3,11 +3,11 @@
3
3
  *
4
4
  * @example
5
5
  * ```typescript
6
- * import { FrameWorksPlayer } from '@livepeer-frameworks/player/vanilla';
7
- * import '@livepeer-frameworks/player/player.css';
6
+ * import { FrameWorksPlayer } from '@livepeer-frameworks/player-core/vanilla';
7
+ * import '@livepeer-frameworks/player-core/player.css';
8
8
  *
9
9
  * const player = new FrameWorksPlayer('#player', {
10
- * contentId: 'my-stream',
10
+ * contentId: 'pk_...',
11
11
  * contentType: 'live',
12
12
  * gatewayUrl: 'https://gateway.example.com/graphql',
13
13
  * });