@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,143 @@
|
|
|
1
|
+
import { BasePlayer } from '../core/PlayerInterface';
|
|
2
|
+
import type { StreamSource, StreamInfo, PlayerOptions, PlayerCapability } from '../core/PlayerInterface';
|
|
3
|
+
/**
|
|
4
|
+
* Native Player Implementation
|
|
5
|
+
*
|
|
6
|
+
* Handles direct playback using native browser APIs:
|
|
7
|
+
* - HTML5 video element for direct media
|
|
8
|
+
* - WHEP (WebRTC HTTP Egress Protocol) for WebRTC streams
|
|
9
|
+
*
|
|
10
|
+
* Ported from reference html5.js with:
|
|
11
|
+
* - Live duration proxy for meaningful seek bar
|
|
12
|
+
* - Auto-recovery on long pause (reload after 5s)
|
|
13
|
+
* - MP3 seeking restriction
|
|
14
|
+
* - Dynamic source switching via setSource()
|
|
15
|
+
*/
|
|
16
|
+
export declare class NativePlayerImpl extends BasePlayer {
|
|
17
|
+
readonly capability: PlayerCapability;
|
|
18
|
+
private peerConnection;
|
|
19
|
+
private sessionUrl;
|
|
20
|
+
private lastInboundStats;
|
|
21
|
+
private reconnectEnabled;
|
|
22
|
+
private reconnectAttempts;
|
|
23
|
+
private maxReconnectAttempts;
|
|
24
|
+
private reconnectTimer;
|
|
25
|
+
private currentWhepUrl;
|
|
26
|
+
private currentHeaders;
|
|
27
|
+
private currentIceServers;
|
|
28
|
+
private container;
|
|
29
|
+
private destroyed;
|
|
30
|
+
private liveDurationProxy;
|
|
31
|
+
private pausedAt;
|
|
32
|
+
private currentSourceUrl;
|
|
33
|
+
private currentMimeType;
|
|
34
|
+
private isMP3Source;
|
|
35
|
+
private liveSeekEnabled;
|
|
36
|
+
private liveSeekOffsetSec;
|
|
37
|
+
private liveSeekBaseUrl;
|
|
38
|
+
private liveSeekListeners;
|
|
39
|
+
private liveSeekTimer;
|
|
40
|
+
private pendingLiveSeekOffset;
|
|
41
|
+
private static readonly PAUSE_RECOVERY_THRESHOLD;
|
|
42
|
+
private static readonly LIVE_SEEK_DEBOUNCE_MS;
|
|
43
|
+
isMimeSupported(mimetype: string): boolean;
|
|
44
|
+
isBrowserSupported(mimetype: string, source: StreamSource, streamInfo: StreamInfo): boolean | string[];
|
|
45
|
+
private translateCodecForHtml5;
|
|
46
|
+
private getAndroidVersion;
|
|
47
|
+
initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions, streamInfo?: StreamInfo): Promise<HTMLVideoElement>;
|
|
48
|
+
/**
|
|
49
|
+
* Setup live duration proxy for meaningful seek bar on live streams
|
|
50
|
+
* Ported from reference html5.js:194-202
|
|
51
|
+
*/
|
|
52
|
+
private setupLiveDurationProxy;
|
|
53
|
+
/**
|
|
54
|
+
* Setup auto-recovery on long pause
|
|
55
|
+
* Ported from reference html5.js:227-239
|
|
56
|
+
*
|
|
57
|
+
* If the stream has been paused for more than 5 seconds,
|
|
58
|
+
* reload the stream on play to recover from stale buffer.
|
|
59
|
+
*/
|
|
60
|
+
private setupAutoRecovery;
|
|
61
|
+
/**
|
|
62
|
+
* Set a new source URL dynamically
|
|
63
|
+
* Ported from reference html5.js:276-281
|
|
64
|
+
*/
|
|
65
|
+
setSource(url: string): void;
|
|
66
|
+
/**
|
|
67
|
+
* Override seek for MP3 files (seeking not supported)
|
|
68
|
+
* Ported from reference html5.js:185-191
|
|
69
|
+
*/
|
|
70
|
+
seek(time: number): void;
|
|
71
|
+
/**
|
|
72
|
+
* Get the calculated duration (live-aware)
|
|
73
|
+
*/
|
|
74
|
+
getDuration(): number;
|
|
75
|
+
getCurrentTime(): number;
|
|
76
|
+
getSeekableRange(): {
|
|
77
|
+
start: number;
|
|
78
|
+
end: number;
|
|
79
|
+
} | null;
|
|
80
|
+
getBufferedRanges(): TimeRanges | null;
|
|
81
|
+
/**
|
|
82
|
+
* Check if current stream is live
|
|
83
|
+
*/
|
|
84
|
+
isLive(): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Get live latency in seconds
|
|
87
|
+
*/
|
|
88
|
+
getLiveLatency(): number;
|
|
89
|
+
/**
|
|
90
|
+
* Jump to live edge
|
|
91
|
+
*/
|
|
92
|
+
jumpToLive(): void;
|
|
93
|
+
destroy(): Promise<void>;
|
|
94
|
+
private stripStartUnixParam;
|
|
95
|
+
private buildLiveSeekUrl;
|
|
96
|
+
private applyLiveSeekOffset;
|
|
97
|
+
private createTimeRanges;
|
|
98
|
+
private scheduleLiveSeekOffset;
|
|
99
|
+
/**
|
|
100
|
+
* Get WebRTC-specific stats including RTT, packet loss, jitter, bitrate
|
|
101
|
+
*/
|
|
102
|
+
getStats(): Promise<{
|
|
103
|
+
type: 'webrtc';
|
|
104
|
+
video?: {
|
|
105
|
+
bytesReceived: number;
|
|
106
|
+
packetsReceived: number;
|
|
107
|
+
packetsLost: number;
|
|
108
|
+
packetLossRate: number;
|
|
109
|
+
jitter: number;
|
|
110
|
+
framesDecoded: number;
|
|
111
|
+
framesDropped: number;
|
|
112
|
+
frameDropRate: number;
|
|
113
|
+
frameWidth: number;
|
|
114
|
+
frameHeight: number;
|
|
115
|
+
framesPerSecond: number;
|
|
116
|
+
bitrate: number;
|
|
117
|
+
jitterBufferDelay: number;
|
|
118
|
+
};
|
|
119
|
+
audio?: {
|
|
120
|
+
bytesReceived: number;
|
|
121
|
+
packetsReceived: number;
|
|
122
|
+
packetsLost: number;
|
|
123
|
+
packetLossRate: number;
|
|
124
|
+
jitter: number;
|
|
125
|
+
bitrate: number;
|
|
126
|
+
};
|
|
127
|
+
network?: {
|
|
128
|
+
rtt: number;
|
|
129
|
+
availableOutgoingBitrate: number;
|
|
130
|
+
availableIncomingBitrate: number;
|
|
131
|
+
bytesSent: number;
|
|
132
|
+
bytesReceived: number;
|
|
133
|
+
};
|
|
134
|
+
timestamp: number;
|
|
135
|
+
} | undefined>;
|
|
136
|
+
getLatency(): Promise<{
|
|
137
|
+
estimatedMs: number;
|
|
138
|
+
jitterBufferMs: number;
|
|
139
|
+
rttMs: number;
|
|
140
|
+
} | undefined>;
|
|
141
|
+
private startWhep;
|
|
142
|
+
}
|
|
143
|
+
export { NativePlayerImpl as DirectPlaybackPlayerImpl };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { BasePlayer } from '../core/PlayerInterface';
|
|
2
|
+
import type { StreamSource, StreamInfo, PlayerOptions, PlayerCapability } from '../core/PlayerInterface';
|
|
3
|
+
export declare class VideoJsPlayerImpl extends BasePlayer {
|
|
4
|
+
readonly capability: PlayerCapability;
|
|
5
|
+
private videojsPlayer;
|
|
6
|
+
private container;
|
|
7
|
+
private destroyed;
|
|
8
|
+
private timeCorrection;
|
|
9
|
+
private proxyElement;
|
|
10
|
+
private currentStreamInfo;
|
|
11
|
+
private liveDurationProxy;
|
|
12
|
+
isMimeSupported(mimetype: string): boolean;
|
|
13
|
+
isBrowserSupported(mimetype: string, source: StreamSource, streamInfo: StreamInfo): boolean | string[];
|
|
14
|
+
initialize(container: HTMLElement, source: StreamSource, options: PlayerOptions, streamInfo?: StreamInfo): Promise<HTMLVideoElement>;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a Proxy wrapper around the video element that corrects
|
|
17
|
+
* currentTime/duration/buffered using the firstms offset from MistServer.
|
|
18
|
+
* This ensures timestamps align with MistServer's track metadata.
|
|
19
|
+
*/
|
|
20
|
+
private createTimeCorrectedProxy;
|
|
21
|
+
private getVideoJsType;
|
|
22
|
+
setPlaybackRate(rate: number): void;
|
|
23
|
+
getCurrentTime(): number;
|
|
24
|
+
getSeekableRange(): {
|
|
25
|
+
start: number;
|
|
26
|
+
end: number;
|
|
27
|
+
} | null;
|
|
28
|
+
/**
|
|
29
|
+
* Seek to time using VideoJS API (fixes backwards seeking in HLS).
|
|
30
|
+
* Time should be in the corrected coordinate space (with firstms offset applied).
|
|
31
|
+
*/
|
|
32
|
+
seek(time: number): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get VideoJS-specific stats for playback monitoring
|
|
35
|
+
*/
|
|
36
|
+
getStats(): Promise<{
|
|
37
|
+
type: 'videojs';
|
|
38
|
+
buffered: number;
|
|
39
|
+
currentTime: number;
|
|
40
|
+
duration: number;
|
|
41
|
+
readyState: number;
|
|
42
|
+
networkState: number;
|
|
43
|
+
playbackRate: number;
|
|
44
|
+
} | undefined>;
|
|
45
|
+
/**
|
|
46
|
+
* Check if the stream is live
|
|
47
|
+
*/
|
|
48
|
+
isLiveStream(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Jump to live edge
|
|
51
|
+
* Uses VideoJS liveTracker when available, otherwise LiveDurationProxy
|
|
52
|
+
*/
|
|
53
|
+
jumpToLive(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Get latency from live edge (for live streams)
|
|
56
|
+
*/
|
|
57
|
+
getLiveLatency(): number;
|
|
58
|
+
destroy(): Promise<void>;
|
|
59
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JitterBuffer - Network Jitter Estimation
|
|
3
|
+
*
|
|
4
|
+
* Tracks network jitter to inform buffer sizing decisions.
|
|
5
|
+
* Ported from legacy rawws.js JitterTracker with improvements:
|
|
6
|
+
* - Per-track jitter tracking (audio/video can differ)
|
|
7
|
+
* - TypeScript types
|
|
8
|
+
* - Better edge case handling
|
|
9
|
+
*
|
|
10
|
+
* Algorithm:
|
|
11
|
+
* 1. Track arrival time vs media time for last N chunks
|
|
12
|
+
* 2. Calculate jitter = (mediaTimePassed / speed) - clockTimePassed
|
|
13
|
+
* 3. Maintain sliding window of peak jitter per second
|
|
14
|
+
* 4. Weighted average: (avgPeak + maxPeak * 2) / 3 + 1ms
|
|
15
|
+
* 5. Limit lowering rate to prevent oscillation
|
|
16
|
+
*/
|
|
17
|
+
import type { JitterState } from './types';
|
|
18
|
+
export interface JitterTrackerOptions {
|
|
19
|
+
/** Initial jitter estimate (ms) */
|
|
20
|
+
initialJitter?: number;
|
|
21
|
+
/** Sliding window size for chunks */
|
|
22
|
+
chunkWindowSize?: number;
|
|
23
|
+
/** Sliding window size for peaks */
|
|
24
|
+
peakWindowSize?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* JitterTracker - Estimates network jitter for a single track
|
|
28
|
+
*/
|
|
29
|
+
export declare class JitterTracker {
|
|
30
|
+
/** Sliding window of chunk timings */
|
|
31
|
+
private chunks;
|
|
32
|
+
/** Current playback speed (1 = realtime) */
|
|
33
|
+
private speed;
|
|
34
|
+
/** Last time a peak was recorded */
|
|
35
|
+
private lastPeakTime;
|
|
36
|
+
/** Maximum jitter observed in current interval */
|
|
37
|
+
private currentPeak;
|
|
38
|
+
/** Sliding window of peak jitter values */
|
|
39
|
+
private peaks;
|
|
40
|
+
/** Weighted average jitter estimate */
|
|
41
|
+
private maxJitter;
|
|
42
|
+
/** Configuration */
|
|
43
|
+
private readonly chunkWindowSize;
|
|
44
|
+
private readonly peakWindowSize;
|
|
45
|
+
constructor(options?: JitterTrackerOptions);
|
|
46
|
+
/**
|
|
47
|
+
* Add a received chunk to jitter calculation
|
|
48
|
+
*
|
|
49
|
+
* @param mediaTime - Media timestamp from chunk (ms)
|
|
50
|
+
* @param receiveTime - Wall clock time (performance.now())
|
|
51
|
+
*/
|
|
52
|
+
addChunk(mediaTime: number, receiveTime?: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Calculate current instantaneous jitter
|
|
55
|
+
*/
|
|
56
|
+
private calculateJitter;
|
|
57
|
+
/**
|
|
58
|
+
* Record current peak and update weighted average
|
|
59
|
+
*/
|
|
60
|
+
private recordPeak;
|
|
61
|
+
/**
|
|
62
|
+
* Get current jitter estimate (ms)
|
|
63
|
+
*/
|
|
64
|
+
get(): number;
|
|
65
|
+
/**
|
|
66
|
+
* Get detailed jitter state
|
|
67
|
+
*/
|
|
68
|
+
getState(): JitterState;
|
|
69
|
+
/**
|
|
70
|
+
* Set playback speed for jitter calculation
|
|
71
|
+
*/
|
|
72
|
+
setSpeed(speed: number | 'auto'): void;
|
|
73
|
+
/**
|
|
74
|
+
* Reset jitter tracking (e.g., after seek)
|
|
75
|
+
*/
|
|
76
|
+
reset(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Full reset including learned jitter estimate
|
|
79
|
+
*/
|
|
80
|
+
fullReset(): void;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* MultiTrackJitterTracker - Manages jitter tracking for multiple tracks
|
|
84
|
+
*/
|
|
85
|
+
export declare class MultiTrackJitterTracker {
|
|
86
|
+
private trackers;
|
|
87
|
+
private globalSpeed;
|
|
88
|
+
private options;
|
|
89
|
+
constructor(options?: JitterTrackerOptions);
|
|
90
|
+
/**
|
|
91
|
+
* Add a chunk for a specific track
|
|
92
|
+
*/
|
|
93
|
+
addChunk(trackIndex: number, mediaTime: number, receiveTime?: number): void;
|
|
94
|
+
/**
|
|
95
|
+
* Get maximum jitter across all tracks
|
|
96
|
+
*/
|
|
97
|
+
getMax(): number;
|
|
98
|
+
/**
|
|
99
|
+
* Get jitter for a specific track
|
|
100
|
+
*/
|
|
101
|
+
getForTrack(trackIndex: number): number;
|
|
102
|
+
/**
|
|
103
|
+
* Set playback speed for all trackers
|
|
104
|
+
*/
|
|
105
|
+
setSpeed(speed: number | 'auto'): void;
|
|
106
|
+
/**
|
|
107
|
+
* Reset all trackers
|
|
108
|
+
*/
|
|
109
|
+
reset(): void;
|
|
110
|
+
/**
|
|
111
|
+
* Remove a track's tracker
|
|
112
|
+
*/
|
|
113
|
+
removeTrack(trackIndex: number): void;
|
|
114
|
+
/**
|
|
115
|
+
* Clear all trackers
|
|
116
|
+
*/
|
|
117
|
+
clear(): void;
|
|
118
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Latency Profiles for WebCodecs Player
|
|
3
|
+
*
|
|
4
|
+
* Presets for trading off latency vs stability.
|
|
5
|
+
*
|
|
6
|
+
* Buffer calculation: desiredBuffer = keepAway + serverDelay + (jitter * jitterMultiplier)
|
|
7
|
+
*
|
|
8
|
+
* Speed tweaking:
|
|
9
|
+
* - If buffer > desired * speedUpThreshold → speed up to maxSpeedUp
|
|
10
|
+
* - If buffer < desired * speedDownThreshold → slow down to minSpeedDown
|
|
11
|
+
*/
|
|
12
|
+
import type { LatencyProfile, LatencyProfileName } from './types';
|
|
13
|
+
/**
|
|
14
|
+
* Ultra-low latency profile
|
|
15
|
+
* Target: <200ms end-to-end latency
|
|
16
|
+
* Use case: Real-time conferencing, remote control
|
|
17
|
+
* Trade-offs: May stutter on poor networks
|
|
18
|
+
*/
|
|
19
|
+
export declare const ULTRA_LOW_PROFILE: LatencyProfile;
|
|
20
|
+
/**
|
|
21
|
+
* Low latency profile
|
|
22
|
+
* Target: ~300-500ms end-to-end latency
|
|
23
|
+
* Use case: Live sports, gaming streams
|
|
24
|
+
* Trade-offs: Balanced latency/stability
|
|
25
|
+
*/
|
|
26
|
+
export declare const LOW_PROFILE: LatencyProfile;
|
|
27
|
+
/**
|
|
28
|
+
* Balanced profile
|
|
29
|
+
* Target: ~500-1000ms end-to-end latency
|
|
30
|
+
* Use case: General live streaming
|
|
31
|
+
* Trade-offs: Prioritizes stability over latency
|
|
32
|
+
*/
|
|
33
|
+
export declare const BALANCED_PROFILE: LatencyProfile;
|
|
34
|
+
/**
|
|
35
|
+
* Quality priority profile
|
|
36
|
+
* Target: ~1-2s end-to-end latency
|
|
37
|
+
* Use case: VOD, recorded content, poor networks
|
|
38
|
+
* Trade-offs: Maximum stability, higher latency
|
|
39
|
+
*/
|
|
40
|
+
export declare const QUALITY_PROFILE: LatencyProfile;
|
|
41
|
+
/**
|
|
42
|
+
* All available latency profiles
|
|
43
|
+
*/
|
|
44
|
+
export declare const LATENCY_PROFILES: Record<LatencyProfileName, LatencyProfile>;
|
|
45
|
+
/**
|
|
46
|
+
* Get a latency profile by name
|
|
47
|
+
* @param name - Profile name
|
|
48
|
+
* @returns The profile, or 'low' as default
|
|
49
|
+
*/
|
|
50
|
+
export declare function getLatencyProfile(name?: LatencyProfileName): LatencyProfile;
|
|
51
|
+
/**
|
|
52
|
+
* Merge a custom partial profile with a base profile
|
|
53
|
+
* @param base - Base profile name or profile object
|
|
54
|
+
* @param custom - Partial overrides
|
|
55
|
+
* @returns Merged profile
|
|
56
|
+
*/
|
|
57
|
+
export declare function mergeLatencyProfile(base: LatencyProfileName | LatencyProfile, custom?: Partial<LatencyProfile>): LatencyProfile;
|
|
58
|
+
/**
|
|
59
|
+
* Select appropriate profile based on stream type
|
|
60
|
+
* @param isLive - Whether the stream is live
|
|
61
|
+
* @param preferLowLatency - Whether to prefer low latency (e.g., WebRTC source)
|
|
62
|
+
* @returns Recommended profile name
|
|
63
|
+
*/
|
|
64
|
+
export declare function selectDefaultProfile(isLive: boolean, preferLowLatency?: boolean): LatencyProfileName;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RawChunkParser - Binary Frame Header Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses the 12-byte binary header from MistServer's raw WebSocket stream.
|
|
5
|
+
*
|
|
6
|
+
* Header format:
|
|
7
|
+
* Byte 0: Track index (uint8)
|
|
8
|
+
* Byte 1: Chunk type: 0=delta, 1=key, 2=init
|
|
9
|
+
* Bytes 2-9: Timestamp in milliseconds (uint64 big-endian)
|
|
10
|
+
* Bytes 10-11: Offset in milliseconds (int16 big-endian, signed)
|
|
11
|
+
*
|
|
12
|
+
* The offset is server-calculated and used for A/V synchronization.
|
|
13
|
+
* Combined presentation time = timestamp + offset
|
|
14
|
+
*/
|
|
15
|
+
import type { RawChunk } from './types';
|
|
16
|
+
/**
|
|
17
|
+
* Parse a raw binary chunk from MistServer
|
|
18
|
+
*
|
|
19
|
+
* @param data - ArrayBuffer containing header + frame data
|
|
20
|
+
* @returns Parsed RawChunk object
|
|
21
|
+
* @throws Error if data is too short
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseRawChunk(data: ArrayBuffer): RawChunk;
|
|
24
|
+
/**
|
|
25
|
+
* Calculate the presentation timestamp for a chunk
|
|
26
|
+
* This combines the server timestamp with the sync offset
|
|
27
|
+
*
|
|
28
|
+
* @param chunk - Parsed raw chunk
|
|
29
|
+
* @returns Presentation timestamp in microseconds (for WebCodecs API)
|
|
30
|
+
*/
|
|
31
|
+
export declare function getPresentationTimestamp(chunk: RawChunk): number;
|
|
32
|
+
/**
|
|
33
|
+
* Check if this chunk is a keyframe
|
|
34
|
+
*/
|
|
35
|
+
export declare function isKeyframe(chunk: RawChunk): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Check if this chunk contains codec initialization data
|
|
38
|
+
*/
|
|
39
|
+
export declare function isInitData(chunk: RawChunk): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Format chunk for debug logging
|
|
42
|
+
*/
|
|
43
|
+
export declare function formatChunkForLog(chunk: RawChunk): string;
|
|
44
|
+
/**
|
|
45
|
+
* RawChunkParser class for stateful parsing with validation
|
|
46
|
+
*/
|
|
47
|
+
export declare class RawChunkParser {
|
|
48
|
+
private debug;
|
|
49
|
+
constructor(options?: {
|
|
50
|
+
debug?: boolean;
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Parse binary data from WebSocket
|
|
54
|
+
*
|
|
55
|
+
* @param data - ArrayBuffer from WebSocket message
|
|
56
|
+
* @returns Parsed chunk or null if invalid
|
|
57
|
+
*/
|
|
58
|
+
parse(data: ArrayBuffer): RawChunk | null;
|
|
59
|
+
/**
|
|
60
|
+
* Set debug mode
|
|
61
|
+
*/
|
|
62
|
+
setDebug(enabled: boolean | 'verbose'): void;
|
|
63
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SyncController - Buffer Management & Playback Timing
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates:
|
|
5
|
+
* - Buffer level monitoring
|
|
6
|
+
* - Adaptive playback speed (catchup/slowdown)
|
|
7
|
+
* - Jitter tracking integration
|
|
8
|
+
* - Server delay estimation
|
|
9
|
+
* - Seek coordination
|
|
10
|
+
*
|
|
11
|
+
* Based on legacy rawws.js FrameTiming + buffer management with improvements:
|
|
12
|
+
* - Post-decode drift correction
|
|
13
|
+
* - Better seek cancellation
|
|
14
|
+
* - TypeScript types
|
|
15
|
+
*/
|
|
16
|
+
import type { LatencyProfile, SyncState, TrackInfo } from './types';
|
|
17
|
+
/** Events emitted by SyncController */
|
|
18
|
+
export interface SyncControllerEvents {
|
|
19
|
+
speedchange: {
|
|
20
|
+
speed: number;
|
|
21
|
+
reason: 'catchup' | 'slowdown' | 'normal';
|
|
22
|
+
};
|
|
23
|
+
bufferlow: {
|
|
24
|
+
current: number;
|
|
25
|
+
desired: number;
|
|
26
|
+
};
|
|
27
|
+
bufferhigh: {
|
|
28
|
+
current: number;
|
|
29
|
+
desired: number;
|
|
30
|
+
};
|
|
31
|
+
underrun: void;
|
|
32
|
+
livecatchup: {
|
|
33
|
+
fastForwardMs: number;
|
|
34
|
+
};
|
|
35
|
+
seekstart: {
|
|
36
|
+
seekId: number;
|
|
37
|
+
time: number;
|
|
38
|
+
};
|
|
39
|
+
seekcomplete: {
|
|
40
|
+
seekId: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
type EventListener<K extends keyof SyncControllerEvents> = (data: SyncControllerEvents[K]) => void;
|
|
44
|
+
/**
|
|
45
|
+
* SyncController - Manages playback synchronization
|
|
46
|
+
*/
|
|
47
|
+
export declare class SyncController {
|
|
48
|
+
private profile;
|
|
49
|
+
private jitterTracker;
|
|
50
|
+
private listeners;
|
|
51
|
+
private mainSpeed;
|
|
52
|
+
private tweakSpeed;
|
|
53
|
+
private lastBufferCheck;
|
|
54
|
+
private bufferCheckInterval;
|
|
55
|
+
private serverDelays;
|
|
56
|
+
private maxServerDelaysSamples;
|
|
57
|
+
private lastLiveCatchup;
|
|
58
|
+
private liveCatchupCooldown;
|
|
59
|
+
private liveCatchupThresholdMs;
|
|
60
|
+
private liveCatchupRequestMs;
|
|
61
|
+
private serverTime;
|
|
62
|
+
private localTimeAtServerUpdate;
|
|
63
|
+
private seekState;
|
|
64
|
+
private isLive;
|
|
65
|
+
private onSpeedChange?;
|
|
66
|
+
private onFastForwardRequest?;
|
|
67
|
+
constructor(options?: {
|
|
68
|
+
profile?: LatencyProfile;
|
|
69
|
+
isLive?: boolean;
|
|
70
|
+
onSpeedChange?: (main: number, tweak: number) => void;
|
|
71
|
+
onFastForwardRequest?: (ms: number) => void;
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Update latency profile
|
|
75
|
+
*/
|
|
76
|
+
setProfile(profile: LatencyProfile): void;
|
|
77
|
+
/**
|
|
78
|
+
* Update stream type (live vs VOD)
|
|
79
|
+
*/
|
|
80
|
+
setLive(isLive: boolean): void;
|
|
81
|
+
/**
|
|
82
|
+
* Record a chunk arrival for jitter tracking
|
|
83
|
+
*/
|
|
84
|
+
recordChunkArrival(trackIndex: number, mediaTimeMs: number): void;
|
|
85
|
+
/**
|
|
86
|
+
* Update server time from on_time message
|
|
87
|
+
*/
|
|
88
|
+
updateServerTime(currentTime: number): void;
|
|
89
|
+
/**
|
|
90
|
+
* Record server delay measurement
|
|
91
|
+
*/
|
|
92
|
+
recordServerDelay(delayMs: number): void;
|
|
93
|
+
/**
|
|
94
|
+
* Get current server delay estimate
|
|
95
|
+
*/
|
|
96
|
+
getServerDelay(): number;
|
|
97
|
+
/**
|
|
98
|
+
* Get estimated current server time (interpolated)
|
|
99
|
+
*/
|
|
100
|
+
getEstimatedServerTime(): number;
|
|
101
|
+
/**
|
|
102
|
+
* Calculate desired buffer size based on profile + jitter + server delay
|
|
103
|
+
* Matches MistServer mews.js pattern with Chrome-specific handling
|
|
104
|
+
*/
|
|
105
|
+
getDesiredBuffer(): number;
|
|
106
|
+
/**
|
|
107
|
+
* Evaluate buffer state and adjust playback speed if needed
|
|
108
|
+
*
|
|
109
|
+
* @param currentBufferMs - Current buffer level in milliseconds
|
|
110
|
+
* @returns Updated sync state
|
|
111
|
+
*/
|
|
112
|
+
evaluateBuffer(currentBufferMs: number): SyncState;
|
|
113
|
+
/**
|
|
114
|
+
* Get current sync state
|
|
115
|
+
*/
|
|
116
|
+
getState(currentBufferMs?: number): SyncState;
|
|
117
|
+
/**
|
|
118
|
+
* Get combined playback speed (main * tweak)
|
|
119
|
+
*/
|
|
120
|
+
getCombinedSpeed(): number;
|
|
121
|
+
/**
|
|
122
|
+
* Set main playback speed (user-controlled)
|
|
123
|
+
*/
|
|
124
|
+
setMainSpeed(speed: number): void;
|
|
125
|
+
/**
|
|
126
|
+
* Set tweak speed (automatic adjustment)
|
|
127
|
+
*/
|
|
128
|
+
private setTweakSpeed;
|
|
129
|
+
/**
|
|
130
|
+
* Notify external listeners of speed change
|
|
131
|
+
*/
|
|
132
|
+
private notifySpeedChange;
|
|
133
|
+
/**
|
|
134
|
+
* Request additional data from server
|
|
135
|
+
*/
|
|
136
|
+
private requestFastForward;
|
|
137
|
+
/**
|
|
138
|
+
* Start a seek operation
|
|
139
|
+
* Returns a seek ID that can be used to check if seek is still active
|
|
140
|
+
*/
|
|
141
|
+
startSeek(targetTimeMs: number): number;
|
|
142
|
+
/**
|
|
143
|
+
* Check if a seek is still the active one
|
|
144
|
+
*/
|
|
145
|
+
isSeekActive(seekId: number): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Complete a seek operation
|
|
148
|
+
*/
|
|
149
|
+
completeSeek(seekId: number): void;
|
|
150
|
+
/**
|
|
151
|
+
* Cancel any active seek
|
|
152
|
+
*/
|
|
153
|
+
cancelSeek(): void;
|
|
154
|
+
/**
|
|
155
|
+
* Check if currently seeking
|
|
156
|
+
*/
|
|
157
|
+
isSeeking(): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Register a new track
|
|
160
|
+
*/
|
|
161
|
+
addTrack(trackIndex: number, track: TrackInfo): void;
|
|
162
|
+
/**
|
|
163
|
+
* Remove a track
|
|
164
|
+
*/
|
|
165
|
+
removeTrack(trackIndex: number): void;
|
|
166
|
+
/**
|
|
167
|
+
* Reset all state
|
|
168
|
+
*/
|
|
169
|
+
reset(): void;
|
|
170
|
+
on<K extends keyof SyncControllerEvents>(event: K, listener: EventListener<K>): void;
|
|
171
|
+
off<K extends keyof SyncControllerEvents>(event: K, listener: EventListener<K>): void;
|
|
172
|
+
private emit;
|
|
173
|
+
}
|
|
174
|
+
export {};
|