@stinkycomputing/web-live-player 0.1.0
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 +323 -0
- package/dist/audio/file-audio-player.d.ts +60 -0
- package/dist/audio/live-audio-player.d.ts +64 -0
- package/dist/decoders/decoder-interface.d.ts +63 -0
- package/dist/decoders/wasm-decoder.d.ts +68 -0
- package/dist/decoders/wasm-worker/H264NALDecoder.worker.d.ts +1 -0
- package/dist/decoders/webcodecs-decoder.d.ts +82 -0
- package/dist/index.d.ts +35 -0
- package/dist/player/base-player.d.ts +54 -0
- package/dist/player/base-player.test.d.ts +8 -0
- package/dist/player/file-player.d.ts +200 -0
- package/dist/player/live-player.d.ts +219 -0
- package/dist/protocol/codec-utils.d.ts +25 -0
- package/dist/protocol/sesame-binary-protocol.d.ts +98 -0
- package/dist/scheduling/frame-scheduler.d.ts +122 -0
- package/dist/scheduling/frame-scheduler.test.d.ts +11 -0
- package/dist/sources/mp4-file-source.d.ts +143 -0
- package/dist/sources/standalone-moq-source.d.ts +44 -0
- package/dist/sources/stream-source.d.ts +73 -0
- package/dist/sources/websocket-source.d.ts +120 -0
- package/dist/types.d.ts +58 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/web-live-player.cjs +234 -0
- package/dist/web-live-player.mjs +9559 -0
- package/package.json +54 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Logger } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base player configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface BasePlayerConfig {
|
|
7
|
+
/** Enable debug logging */
|
|
8
|
+
debugLogging?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a logger with configurable debug output
|
|
12
|
+
*/
|
|
13
|
+
export declare function createLogger(debugLogging: boolean): Logger;
|
|
14
|
+
/**
|
|
15
|
+
* Base class for video players providing common event handling and state management
|
|
16
|
+
*/
|
|
17
|
+
export declare abstract class BasePlayer<TState extends string> {
|
|
18
|
+
protected eventHandlers: Map<string, Set<Function>>;
|
|
19
|
+
protected logger: Logger;
|
|
20
|
+
protected _state: TState;
|
|
21
|
+
constructor(initialState: TState, debugLogging?: boolean);
|
|
22
|
+
/**
|
|
23
|
+
* Current player state
|
|
24
|
+
*/
|
|
25
|
+
get state(): TState;
|
|
26
|
+
/**
|
|
27
|
+
* Update player state and emit statechange event
|
|
28
|
+
*/
|
|
29
|
+
protected setState(state: TState): void;
|
|
30
|
+
/**
|
|
31
|
+
* Enable/disable debug logging
|
|
32
|
+
*/
|
|
33
|
+
setDebugLogging(enabled: boolean): void;
|
|
34
|
+
/**
|
|
35
|
+
* Subscribe to an event
|
|
36
|
+
*/
|
|
37
|
+
on(event: string, handler: Function): void;
|
|
38
|
+
/**
|
|
39
|
+
* Unsubscribe from an event
|
|
40
|
+
*/
|
|
41
|
+
off(event: string, handler: Function): void;
|
|
42
|
+
/**
|
|
43
|
+
* Emit an event to all subscribers
|
|
44
|
+
*/
|
|
45
|
+
protected emit(event: string, ...args: any[]): void;
|
|
46
|
+
/**
|
|
47
|
+
* Clear all event handlers (called during dispose)
|
|
48
|
+
*/
|
|
49
|
+
protected clearEventHandlers(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Dispose the player and release resources
|
|
52
|
+
*/
|
|
53
|
+
abstract dispose(): void;
|
|
54
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { MP4FileInfo } from '../sources/mp4-file-source';
|
|
2
|
+
import { PreferredDecoder } from '../types';
|
|
3
|
+
import { BasePlayer } from './base-player';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Play mode for file playback
|
|
7
|
+
*/
|
|
8
|
+
export type FilePlayMode = 'once' | 'loop';
|
|
9
|
+
/**
|
|
10
|
+
* File player configuration
|
|
11
|
+
*/
|
|
12
|
+
export interface FilePlayerConfig {
|
|
13
|
+
preferredDecoder?: PreferredDecoder;
|
|
14
|
+
/** Enable audio playback */
|
|
15
|
+
enableAudio?: boolean;
|
|
16
|
+
/** Audio context to use (creates one if not provided) */
|
|
17
|
+
audioContext?: AudioContext;
|
|
18
|
+
/** Enable debug logging */
|
|
19
|
+
debugLogging?: boolean;
|
|
20
|
+
/** Play mode: 'once' plays to end, 'loop' seamlessly loops (default: 'once') */
|
|
21
|
+
playMode?: FilePlayMode;
|
|
22
|
+
/** @deprecated Use playMode instead */
|
|
23
|
+
loop?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* File player state
|
|
27
|
+
*/
|
|
28
|
+
export type FilePlayerState = 'idle' | 'loading' | 'ready' | 'playing' | 'paused' | 'ended' | 'error';
|
|
29
|
+
/**
|
|
30
|
+
* File player statistics
|
|
31
|
+
*/
|
|
32
|
+
export interface FilePlayerStats {
|
|
33
|
+
duration: number;
|
|
34
|
+
position: number;
|
|
35
|
+
bufferSize: number;
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
frameRate: number;
|
|
39
|
+
codec: string;
|
|
40
|
+
state: FilePlayerState;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* File Video Player
|
|
44
|
+
*/
|
|
45
|
+
export declare class FileVideoPlayer extends BasePlayer<FilePlayerState> {
|
|
46
|
+
private config;
|
|
47
|
+
private fileSource;
|
|
48
|
+
private decoder;
|
|
49
|
+
private audioContext;
|
|
50
|
+
private audioPlayer;
|
|
51
|
+
private ownsAudioContext;
|
|
52
|
+
private audioInitialized;
|
|
53
|
+
private fileInfo;
|
|
54
|
+
private frameBuffer;
|
|
55
|
+
private minBufferSize;
|
|
56
|
+
private sampleQueue;
|
|
57
|
+
private audioSampleQueue;
|
|
58
|
+
private nextSampleIndex;
|
|
59
|
+
private nextAudioSampleIndex;
|
|
60
|
+
private maxDecoderQueue;
|
|
61
|
+
private bufferReadyResolve;
|
|
62
|
+
private playStartTime;
|
|
63
|
+
private playStartPosition;
|
|
64
|
+
private currentPosition;
|
|
65
|
+
private lastVideoFrame;
|
|
66
|
+
private isSeeking;
|
|
67
|
+
constructor(config?: FilePlayerConfig);
|
|
68
|
+
/**
|
|
69
|
+
* Get file info
|
|
70
|
+
*/
|
|
71
|
+
getFileInfo(): MP4FileInfo | null;
|
|
72
|
+
/**
|
|
73
|
+
* Get current position in seconds
|
|
74
|
+
*/
|
|
75
|
+
getPosition(): number;
|
|
76
|
+
/**
|
|
77
|
+
* Get duration in seconds
|
|
78
|
+
*/
|
|
79
|
+
getDuration(): number;
|
|
80
|
+
/**
|
|
81
|
+
* Get player statistics
|
|
82
|
+
*/
|
|
83
|
+
getStats(): FilePlayerStats;
|
|
84
|
+
/**
|
|
85
|
+
* Set play mode ('once' or 'loop')
|
|
86
|
+
*/
|
|
87
|
+
setPlayMode(mode: FilePlayMode): void;
|
|
88
|
+
/**
|
|
89
|
+
* Get current play mode
|
|
90
|
+
*/
|
|
91
|
+
getPlayMode(): FilePlayMode;
|
|
92
|
+
/**
|
|
93
|
+
* Set looping (convenience method, equivalent to setPlayMode)
|
|
94
|
+
* @deprecated Use setPlayMode instead
|
|
95
|
+
*/
|
|
96
|
+
setLoop(loop: boolean): void;
|
|
97
|
+
/**
|
|
98
|
+
* Enable/disable debug logging
|
|
99
|
+
*/
|
|
100
|
+
setDebugLogging(enabled: boolean): void;
|
|
101
|
+
/**
|
|
102
|
+
* Set audio volume (0-1)
|
|
103
|
+
*/
|
|
104
|
+
setVolume(volume: number): void;
|
|
105
|
+
/**
|
|
106
|
+
* Get current audio volume (0-1)
|
|
107
|
+
*/
|
|
108
|
+
getVolume(): number;
|
|
109
|
+
/**
|
|
110
|
+
* Load a video file from URL
|
|
111
|
+
*/
|
|
112
|
+
loadFromUrl(url: string): Promise<MP4FileInfo>;
|
|
113
|
+
/**
|
|
114
|
+
* Load a video file from File object
|
|
115
|
+
*/
|
|
116
|
+
loadFromFile(file: File): Promise<MP4FileInfo>;
|
|
117
|
+
/**
|
|
118
|
+
* Initialize the video decoder
|
|
119
|
+
*/
|
|
120
|
+
private initDecoder;
|
|
121
|
+
/**
|
|
122
|
+
* Initialize the audio decoder
|
|
123
|
+
*/
|
|
124
|
+
private initAudioDecoder;
|
|
125
|
+
/**
|
|
126
|
+
* Wait for the frame buffer to have enough frames for smooth playback
|
|
127
|
+
*/
|
|
128
|
+
private waitForBuffer;
|
|
129
|
+
/**
|
|
130
|
+
* Handle samples from mp4box - queue them for gradual decoding
|
|
131
|
+
*/
|
|
132
|
+
private handleSamples;
|
|
133
|
+
/**
|
|
134
|
+
* Feed video samples to decoder gradually (don't overflow the queue)
|
|
135
|
+
*/
|
|
136
|
+
private feedDecoder;
|
|
137
|
+
private maxAudioBufferMs;
|
|
138
|
+
/**
|
|
139
|
+
* Feed audio samples to decoder - gradually based on playback position
|
|
140
|
+
*/
|
|
141
|
+
private feedAudioDecoder;
|
|
142
|
+
/**
|
|
143
|
+
* Handle decoded frame from decoder
|
|
144
|
+
*/
|
|
145
|
+
private handleDecodedFrame;
|
|
146
|
+
/**
|
|
147
|
+
* Handle source ended (all samples extracted)
|
|
148
|
+
*/
|
|
149
|
+
private handleSourceEnded;
|
|
150
|
+
/**
|
|
151
|
+
* Perform a seamless loop back to the start
|
|
152
|
+
* This resets timing and decoder state for looping
|
|
153
|
+
*/
|
|
154
|
+
private performSeamlessLoop;
|
|
155
|
+
/**
|
|
156
|
+
* Start playback
|
|
157
|
+
*/
|
|
158
|
+
play(): void;
|
|
159
|
+
/**
|
|
160
|
+
* Pause playback
|
|
161
|
+
*/
|
|
162
|
+
pause(): void;
|
|
163
|
+
/**
|
|
164
|
+
* Seek to a specific time in seconds
|
|
165
|
+
*/
|
|
166
|
+
seek(timeSeconds: number): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* Clear the frame buffer
|
|
169
|
+
*/
|
|
170
|
+
private clearFrameBuffer;
|
|
171
|
+
/**
|
|
172
|
+
* Get a video frame for rendering
|
|
173
|
+
*
|
|
174
|
+
* Call this in your render loop. Returns the appropriate frame for the current time.
|
|
175
|
+
*/
|
|
176
|
+
getVideoFrame(): VideoFrame | null;
|
|
177
|
+
/**
|
|
178
|
+
* Subscribe to events (typed overloads)
|
|
179
|
+
*/
|
|
180
|
+
on(event: 'statechange', handler: (state: FilePlayerState) => void): void;
|
|
181
|
+
on(event: 'ready', handler: (info: MP4FileInfo) => void): void;
|
|
182
|
+
on(event: 'progress', handler: (loaded: number, total: number) => void): void;
|
|
183
|
+
on(event: 'error', handler: (error: Error) => void): void;
|
|
184
|
+
on(event: 'ended', handler: () => void): void;
|
|
185
|
+
on(event: 'loop', handler: () => void): void;
|
|
186
|
+
on(event: 'seeked', handler: (time: number) => void): void;
|
|
187
|
+
/**
|
|
188
|
+
* Unsubscribe from events
|
|
189
|
+
*/
|
|
190
|
+
off(event: string, handler: Function): void;
|
|
191
|
+
/**
|
|
192
|
+
* Dispose and clean up resources
|
|
193
|
+
* @param full - If true, also disposes the AudioContext (default: false for reload)
|
|
194
|
+
*/
|
|
195
|
+
dispose(full?: boolean): void;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Factory function to create a file player
|
|
199
|
+
*/
|
|
200
|
+
export declare function createFilePlayer(config?: FilePlayerConfig): FileVideoPlayer;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { IStreamSource } from '../sources/stream-source';
|
|
2
|
+
import { PreferredDecoder } from '../types';
|
|
3
|
+
import { LatencyStats } from '../scheduling/frame-scheduler';
|
|
4
|
+
import { BasePlayer } from './base-player';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Player configuration
|
|
8
|
+
*/
|
|
9
|
+
export interface PlayerConfig {
|
|
10
|
+
preferredDecoder?: PreferredDecoder;
|
|
11
|
+
/** Buffer delay in milliseconds (default: 100ms) */
|
|
12
|
+
bufferDelayMs?: number;
|
|
13
|
+
enableAudio?: boolean;
|
|
14
|
+
/** Video track name for MoQ streams (default: 'video'). Set to null to accept video from any track. */
|
|
15
|
+
videoTrackName?: string | null;
|
|
16
|
+
/** Audio track name for MoQ streams (default: 'audio'). Set to null to accept audio from any track. */
|
|
17
|
+
audioTrackName?: string | null;
|
|
18
|
+
debugLogging?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Player state
|
|
22
|
+
*/
|
|
23
|
+
export type PlayerState = 'idle' | 'playing' | 'paused' | 'error';
|
|
24
|
+
/**
|
|
25
|
+
* Player statistics
|
|
26
|
+
*/
|
|
27
|
+
export interface PlayerStats {
|
|
28
|
+
bufferSize: number;
|
|
29
|
+
bufferMs: number;
|
|
30
|
+
avgBufferMs: number;
|
|
31
|
+
targetBufferMs: number;
|
|
32
|
+
droppedFrames: number;
|
|
33
|
+
totalFrames: number;
|
|
34
|
+
decoderState: string;
|
|
35
|
+
streamWidth: number;
|
|
36
|
+
streamHeight: number;
|
|
37
|
+
frameRate: number;
|
|
38
|
+
latency: LatencyStats | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Player event types
|
|
42
|
+
*/
|
|
43
|
+
type PlayerEventMap = {
|
|
44
|
+
'frame': (frame: VideoFrame) => void;
|
|
45
|
+
'statechange': (state: PlayerState) => void;
|
|
46
|
+
'error': (error: Error) => void;
|
|
47
|
+
'metadata': (metadata: {
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
codec: string;
|
|
51
|
+
}) => void;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Factory function to create a player instance
|
|
55
|
+
*/
|
|
56
|
+
export declare function createPlayer(config?: PlayerConfig): LiveVideoPlayer;
|
|
57
|
+
/**
|
|
58
|
+
* Live Video Player - Main class
|
|
59
|
+
*/
|
|
60
|
+
export declare class LiveVideoPlayer extends BasePlayer<PlayerState> {
|
|
61
|
+
private config;
|
|
62
|
+
private streamSource;
|
|
63
|
+
private trackFilter;
|
|
64
|
+
private boundDataHandler;
|
|
65
|
+
private decoder;
|
|
66
|
+
private currentCodecData;
|
|
67
|
+
private useWasmDecoder;
|
|
68
|
+
private waitingForKeyframe;
|
|
69
|
+
private lastWaitingForKeyframeLog;
|
|
70
|
+
private lastKeyframeRequest;
|
|
71
|
+
private statusLogCounter;
|
|
72
|
+
private isConfiguring;
|
|
73
|
+
private pendingDuringConfig;
|
|
74
|
+
private frameScheduler;
|
|
75
|
+
private lastVideoFrame;
|
|
76
|
+
private consecutiveDrops;
|
|
77
|
+
private totalDrops;
|
|
78
|
+
private lastDropLogTime;
|
|
79
|
+
private streamWidth;
|
|
80
|
+
private streamHeight;
|
|
81
|
+
private estimatedFrameRate;
|
|
82
|
+
private audioContext;
|
|
83
|
+
private audioPlayer;
|
|
84
|
+
private ownsAudioContext;
|
|
85
|
+
private audioCodecData;
|
|
86
|
+
private arrivalTimes;
|
|
87
|
+
constructor(config?: PlayerConfig);
|
|
88
|
+
/**
|
|
89
|
+
* Enable or disable debug logging at runtime
|
|
90
|
+
*/
|
|
91
|
+
setDebugLogging(enabled: boolean): void;
|
|
92
|
+
/**
|
|
93
|
+
* Set audio volume (0-1)
|
|
94
|
+
*/
|
|
95
|
+
setVolume(volume: number): void;
|
|
96
|
+
/**
|
|
97
|
+
* Get current audio volume (0-1)
|
|
98
|
+
*/
|
|
99
|
+
getVolume(): number;
|
|
100
|
+
/**
|
|
101
|
+
* Set the stream source (dependency injection)
|
|
102
|
+
*/
|
|
103
|
+
setStreamSource(source: IStreamSource): void;
|
|
104
|
+
/**
|
|
105
|
+
* Set the track name to filter for
|
|
106
|
+
*/
|
|
107
|
+
setTrackFilter(trackName: string): void;
|
|
108
|
+
/**
|
|
109
|
+
* Convenience method to connect to a MoQ-like session
|
|
110
|
+
*
|
|
111
|
+
* Note: For audio support, the MoQ session must also be subscribed to the audio track.
|
|
112
|
+
* When using StandaloneMoQSource, include both 'video' and 'audio' in subscriptions.
|
|
113
|
+
* When using Elmo's MoQSessionNode, add an audio track to the session config.
|
|
114
|
+
*
|
|
115
|
+
* @param session - MoQ session implementing IStreamSource (e.g., Elmo's MoQSessionNode)
|
|
116
|
+
* @param videoTrackName - Video track name (defaults to config.videoTrackName or 'video')
|
|
117
|
+
*/
|
|
118
|
+
connectToMoQSession(session: IStreamSource, videoTrackName?: string): void;
|
|
119
|
+
/**
|
|
120
|
+
* Connect to a MoQ relay directly with video and optional audio tracks
|
|
121
|
+
*
|
|
122
|
+
* @param relayUrl - URL of the MoQ relay (e.g., 'https://relay.example.com/moq')
|
|
123
|
+
* @param namespace - MoQ namespace/broadcast name
|
|
124
|
+
* @param options - Optional configuration for track names
|
|
125
|
+
*/
|
|
126
|
+
connectToMoQRelay(relayUrl: string, namespace: string, options?: {
|
|
127
|
+
videoTrack?: string;
|
|
128
|
+
audioTrack?: string | false;
|
|
129
|
+
}): Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Start playback
|
|
132
|
+
*/
|
|
133
|
+
play(): void;
|
|
134
|
+
/**
|
|
135
|
+
* Pause playback
|
|
136
|
+
*/
|
|
137
|
+
pause(): void;
|
|
138
|
+
/**
|
|
139
|
+
* Get a video frame for rendering
|
|
140
|
+
*
|
|
141
|
+
* Call this in your render loop with the current timestamp.
|
|
142
|
+
* The returned VideoFrame should be closed after use if you're done with it.
|
|
143
|
+
*/
|
|
144
|
+
getVideoFrame(timestampMs: number): VideoFrame | null;
|
|
145
|
+
/**
|
|
146
|
+
* Set buffer delay in milliseconds (syncs both video and audio)
|
|
147
|
+
*/
|
|
148
|
+
setBufferDelay(delayMs: number): void;
|
|
149
|
+
/**
|
|
150
|
+
* Get current buffer delay in milliseconds
|
|
151
|
+
*/
|
|
152
|
+
getBufferDelay(): number;
|
|
153
|
+
/**
|
|
154
|
+
* Set preferred decoder type
|
|
155
|
+
* If decoder type changes while playing, dispose old decoder and request keyframe
|
|
156
|
+
*/
|
|
157
|
+
setPreferredDecoder(type: PreferredDecoder): void;
|
|
158
|
+
/**
|
|
159
|
+
* Flush the player pipeline (decoder, frame buffer)
|
|
160
|
+
* Used to recover from queue overflow or when seeking
|
|
161
|
+
*/
|
|
162
|
+
flush(): void;
|
|
163
|
+
/**
|
|
164
|
+
* Get player statistics
|
|
165
|
+
*/
|
|
166
|
+
getStats(): PlayerStats;
|
|
167
|
+
/**
|
|
168
|
+
* Subscribe to player events (typed overload)
|
|
169
|
+
*/
|
|
170
|
+
on<K extends keyof PlayerEventMap>(event: K, handler: PlayerEventMap[K]): void;
|
|
171
|
+
/**
|
|
172
|
+
* Unsubscribe from player events (typed overload)
|
|
173
|
+
*/
|
|
174
|
+
off<K extends keyof PlayerEventMap>(event: K, handler: PlayerEventMap[K]): void;
|
|
175
|
+
/**
|
|
176
|
+
* Handle incoming stream data
|
|
177
|
+
*/
|
|
178
|
+
private handleStreamData;
|
|
179
|
+
/**
|
|
180
|
+
* Handle incoming audio frame data
|
|
181
|
+
*/
|
|
182
|
+
private handleAudioData;
|
|
183
|
+
/**
|
|
184
|
+
* Configure the decoder for a specific codec
|
|
185
|
+
*/
|
|
186
|
+
private configureDecoder;
|
|
187
|
+
private getCodecName;
|
|
188
|
+
/**
|
|
189
|
+
* Handle decoded video frame (from WebCodecs)
|
|
190
|
+
*/
|
|
191
|
+
private handleDecodedFrame;
|
|
192
|
+
/**
|
|
193
|
+
* Handle decoded YUV frame (from WASM decoder)
|
|
194
|
+
* Converts YUV to VideoFrame using canvas
|
|
195
|
+
*/
|
|
196
|
+
private handleDecodedYUVFrame;
|
|
197
|
+
/**
|
|
198
|
+
* Convert YUV frame to VideoFrame using native I420 support
|
|
199
|
+
* Much faster than manual pixel-by-pixel conversion
|
|
200
|
+
*
|
|
201
|
+
* @param yuv - YUV frame data from decoder (may have padded dimensions)
|
|
202
|
+
* @param visibleWidth - Actual video width (unpadded)
|
|
203
|
+
* @param visibleHeight - Actual video height (unpadded)
|
|
204
|
+
*/
|
|
205
|
+
private convertYUVToVideoFrame;
|
|
206
|
+
/**
|
|
207
|
+
* Handle decoder error
|
|
208
|
+
*/
|
|
209
|
+
private handleDecoderError;
|
|
210
|
+
/**
|
|
211
|
+
* Handle decoder queue overflow - flush and request keyframe
|
|
212
|
+
*/
|
|
213
|
+
private handleQueueOverflow;
|
|
214
|
+
/**
|
|
215
|
+
* Dispose the player and release resources
|
|
216
|
+
*/
|
|
217
|
+
dispose(): void;
|
|
218
|
+
}
|
|
219
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HeaderCodecData } from './sesame-binary-protocol';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Timebase structure for timestamp conversion
|
|
5
|
+
*/
|
|
6
|
+
export interface Timebase {
|
|
7
|
+
num: number;
|
|
8
|
+
den: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Rescale a timestamp from one timebase to another
|
|
12
|
+
*/
|
|
13
|
+
export declare function rescaleTime(pts: bigint, source: Timebase, target: Timebase): number;
|
|
14
|
+
/**
|
|
15
|
+
* Check if codec data has changed
|
|
16
|
+
*/
|
|
17
|
+
export declare function codecDataChanged(current: HeaderCodecData | undefined, newData: HeaderCodecData | undefined): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Get human-readable codec name
|
|
20
|
+
*/
|
|
21
|
+
export declare function getCodecName(codecType: number): string;
|
|
22
|
+
/**
|
|
23
|
+
* Get WebCodecs codec string for a given codec data
|
|
24
|
+
*/
|
|
25
|
+
export declare function getCodecString(codecData: HeaderCodecData): string | null;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sesame Binary Protocol - TypeScript Implementation
|
|
3
|
+
*
|
|
4
|
+
* This module provides TypeScript implementation of the Sesame binary protocol
|
|
5
|
+
* for serializing and deserializing multimedia data packets.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PROTOCOL_MAGIC = 1297302867;
|
|
8
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
9
|
+
export declare const HEADER_DATA_SIZE = 32;
|
|
10
|
+
export declare const HEADER_CODEC_DATA_SIZE = 24;
|
|
11
|
+
export declare const HEADER_METADATA_SIZE = 64;
|
|
12
|
+
export declare const FLAG_HAS_CODEC_DATA: number;
|
|
13
|
+
export declare const FLAG_HAS_METADATA: number;
|
|
14
|
+
export declare const FLAG_IS_KEYFRAME: number;
|
|
15
|
+
export declare enum PacketType {
|
|
16
|
+
VIDEO_FRAME = 1,
|
|
17
|
+
AUDIO_FRAME = 2,
|
|
18
|
+
RPC = 3,
|
|
19
|
+
MUXED_DATA = 4,
|
|
20
|
+
DECODER_DATA = 5
|
|
21
|
+
}
|
|
22
|
+
export declare enum CodecType {
|
|
23
|
+
VIDEO_VP8 = 1,
|
|
24
|
+
VIDEO_VP9 = 2,
|
|
25
|
+
VIDEO_AVC = 3,
|
|
26
|
+
VIDEO_HEVC = 4,
|
|
27
|
+
VIDEO_AV1 = 5,
|
|
28
|
+
AUDIO_OPUS = 64,
|
|
29
|
+
AUDIO_AAC = 65,
|
|
30
|
+
AUDIO_PCM = 66
|
|
31
|
+
}
|
|
32
|
+
export interface HeaderData {
|
|
33
|
+
magic: number;
|
|
34
|
+
flags: number;
|
|
35
|
+
pts: bigint;
|
|
36
|
+
id: bigint;
|
|
37
|
+
version: number;
|
|
38
|
+
header_size: number;
|
|
39
|
+
type: PacketType;
|
|
40
|
+
reserved: number;
|
|
41
|
+
}
|
|
42
|
+
export interface HeaderCodecData {
|
|
43
|
+
sample_rate: number;
|
|
44
|
+
timebase_num: number;
|
|
45
|
+
timebase_den: number;
|
|
46
|
+
codec_profile: number;
|
|
47
|
+
codec_level: number;
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
codec_type: CodecType;
|
|
51
|
+
channels: number;
|
|
52
|
+
bit_depth: number;
|
|
53
|
+
reserved: number;
|
|
54
|
+
}
|
|
55
|
+
export interface HeaderMetadata {
|
|
56
|
+
metadata: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ParsedData {
|
|
59
|
+
valid: boolean;
|
|
60
|
+
header: HeaderData | null;
|
|
61
|
+
metadata: HeaderMetadata | null;
|
|
62
|
+
codec_data: HeaderCodecData | null;
|
|
63
|
+
payload: Uint8Array | null;
|
|
64
|
+
payload_size: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Main binary protocol class with static methods for serialization/deserialization
|
|
68
|
+
*/
|
|
69
|
+
export declare class SesameBinaryProtocol {
|
|
70
|
+
/**
|
|
71
|
+
* Initialize a header data structure with proper defaults
|
|
72
|
+
*/
|
|
73
|
+
static initHeader(type: PacketType, flags: number, pts: bigint, id: bigint): HeaderData;
|
|
74
|
+
/**
|
|
75
|
+
* Calculate the total header size based on flags
|
|
76
|
+
*/
|
|
77
|
+
static calculateHeaderSize(flags: number): number;
|
|
78
|
+
/**
|
|
79
|
+
* Validate a header structure
|
|
80
|
+
*/
|
|
81
|
+
static validateHeader(header: HeaderData, totalSize: number): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Serialize data into a Uint8Array buffer
|
|
84
|
+
*/
|
|
85
|
+
static serialize(header: HeaderData, metadata?: HeaderMetadata | null, codecData?: HeaderCodecData | null, payload?: Uint8Array | null): Uint8Array | null;
|
|
86
|
+
/**
|
|
87
|
+
* Parse incoming binary data
|
|
88
|
+
*/
|
|
89
|
+
static parseData(data: Uint8Array): ParsedData;
|
|
90
|
+
/**
|
|
91
|
+
* Helper: Convert string to fixed-size byte array (null-terminated)
|
|
92
|
+
*/
|
|
93
|
+
private static stringToFixedBytes;
|
|
94
|
+
/**
|
|
95
|
+
* Helper: Convert fixed-size byte array to string (null-terminated)
|
|
96
|
+
*/
|
|
97
|
+
private static fixedBytesToString;
|
|
98
|
+
}
|