swadhinbiswas

[email protected]
2026-07-24 22:12:43 +0600 committed NaN years ago
1e62e45
commit 1e62e45
1 file changed
+192 -7
Showing 1 changed file+192-7
▼packages/worker/src/index.ts
+192-7
1
1
export interface WorkerMessage<T = unknown> {
2
- type: 'demux' | 'decode' | 'packet' | 'frame' | 'error';
2
+ type: 'demux' | 'decode' | 'packet' | 'frame' | 'error' | 'ready' | 'stats';
3
3
payload: T;
4
+ id?: string;
4
5
}
5
6
7
+export interface WorkerStatistics {
8
+ packetsSent: number;
9
+ framesReceived: number;
10
+ errors: number;
11
+ startTime: number;
12
+}
13
+
14
+export type WorkerState = 'idle' | 'connected' | 'error';
15
+
6
16
export class WorkerPipelineHost {
7
17
private worker?: Worker;
18
+ private state: WorkerState = 'idle';
19
+ private stats: WorkerStatistics = {
20
+ packetsSent: 0,
21
+ framesReceived: 0,
22
+ errors: 0,
23
+ startTime: Date.now()
24
+ };
25
+ private handlers: Map<string, Set<(payload: unknown) => void>> = new Map();
26
+ private errorHandler?: (error: { type: string; message: string; stack?: string }) => void;
27
+ private stateHandler?: (state: WorkerState) => void;
28
+ private workerScriptUrl?: string;
8
29
9
30
constructor(workerScriptUrl?: string) {
31
+ this.workerScriptUrl = workerScriptUrl;
10
32
if (typeof Worker !== 'undefined' && workerScriptUrl) {
11
- this.worker = new Worker(workerScriptUrl, { type: 'module' });
33
+ this.connect();
34
+ }
35
+ }
36
+
37
+ private connect(): void {
38
+ if (!this.workerScriptUrl) return;
39
+
40
+ try {
41
+ this.worker = new Worker(this.workerScriptUrl, { type: 'module' });
42
+
43
+ this.worker.onmessage = (event: MessageEvent<WorkerMessage>) => {
44
+ const { type, payload, id } = event.data;
45
+
46
+ if (type === 'frame') {
47
+ this.stats.framesReceived++;
48
+ } else if (type === 'error') {
49
+ this.stats.errors++;
50
+ if (this.errorHandler) {
51
+ this.errorHandler(payload as { type: string; message: string; stack?: string });
52
+ }
53
+ } else if (type === 'ready') {
54
+ this.state = 'connected';
55
+ if (this.stateHandler) {
56
+ this.stateHandler(this.state);
57
+ }
58
+ } else if (type === 'stats') {
59
+ // Handle stats updates
60
+ }
61
+
62
+ // Call registered handlers
63
+ const typeHandlers = this.handlers.get(type);
64
+ if (typeHandlers) {
65
+ for (const handler of typeHandlers) {
66
+ handler(payload);
67
+ }
68
+ }
69
+ };
70
+
71
+ this.worker.onerror = (event) => {
72
+ this.state = 'error';
73
+ this.stats.errors++;
74
+
75
+ if (this.errorHandler) {
76
+ this.errorHandler({
77
+ type: 'worker-error',
78
+ message: event.message || 'Unknown worker error',
79
+ stack: undefined
80
+ });
81
+ }
82
+
83
+ if (this.stateHandler) {
84
+ this.stateHandler(this.state);
85
+ }
86
+ };
87
+
88
+ this.state = 'connected';
89
+ } catch (error) {
90
+ this.state = 'error';
91
+ if (this.stateHandler) {
92
+ this.stateHandler(this.state);
93
+ }
12
94
}
13
95
}
14
96
15
97
public sendPacket(packetData: Uint8Array, transfer: boolean = true): void {
16
- if (!this.worker) return;
98
+ if (!this.worker || this.state !== 'connected') return;
99
+
17
100
const message: WorkerMessage<{ data: Uint8Array }> = {
18
101
type: 'packet',
19
102
payload: { data: packetData }
20
103
};
104
+
21
105
if (transfer && packetData.buffer instanceof ArrayBuffer) {
22
106
this.worker.postMessage(message, [packetData.buffer]);
23
107
} else {
24
108
this.worker.postMessage(message);
25
109
}
110
+
111
+ this.stats.packetsSent++;
112
+ }
113
+
114
+ public sendDemuxCommand(sourceUrl: string, format?: string): void {
115
+ if (!this.worker || this.state !== 'connected') return;
116
+
117
+ const message: WorkerMessage<{ sourceUrl: string; format?: string }> = {
118
+ type: 'demux',
119
+ payload: { sourceUrl, format }
120
+ };
121
+
122
+ this.worker.postMessage(message);
123
+ }
124
+
125
+ public sendDecodeCommand(trackId: string, codec: string): void {
126
+ if (!this.worker || this.state !== 'connected') return;
127
+
128
+ const message: WorkerMessage<{ trackId: string; codec: string }> = {
129
+ type: 'decode',
130
+ payload: { trackId, codec }
131
+ };
132
+
133
+ this.worker.postMessage(message);
26
134
}
27
135
28
136
public onFrame(handler: (frame: unknown) => void): void {
29
- if (!this.worker) return;
30
- this.worker.onmessage = (event: MessageEvent<WorkerMessage>) => {
31
- if (event.data.type === 'frame') {
32
- handler(event.data.payload);
137
+ this.on('frame', handler);
138
+ }
139
+
140
+ public on(type: string, handler: (payload: unknown) => void): () => void {
141
+ if (!this.handlers.has(type)) {
142
+ this.handlers.set(type, new Set());
143
+ }
144
+ this.handlers.get(type)!.add(handler);
145
+
146
+ return () => {
147
+ const handlers = this.handlers.get(type);
148
+ if (handlers) {
149
+ handlers.delete(handler);
33
150
}
34
151
};
35
152
}
36
153
154
+ public onError(handler: (error: { type: string; message: string; stack?: string }) => void): void {
155
+ this.errorHandler = handler;
156
+ }
157
+
158
+ public onStateChange(handler: (state: WorkerState) => void): void {
159
+ this.stateHandler = handler;
160
+ }
161
+
162
+ public getState(): WorkerState {
163
+ return this.state;
164
+ }
165
+
166
+ public getStatistics(): WorkerStatistics {
167
+ return { ...this.stats };
168
+ }
169
+
170
+ public reconnect(): void {
171
+ this.terminate();
172
+ this.state = 'idle';
173
+ this.connect();
174
+ }
175
+
37
176
public terminate(): void {
38
177
if (this.worker) {
39
178
this.worker.terminate();
179
+ this.worker = undefined;
180
+ this.state = 'idle';
40
181
}
41
182
}
42
183
}
184
+
185
+// Worker-side consumer code
186
+export function createWorkerHandler(): (event: MessageEvent<WorkerMessage>) => void {
187
+ return (event: MessageEvent<WorkerMessage>) => {
188
+ const { type, payload } = event.data;
189
+
190
+ switch (type) {
191
+ case 'demux':
192
+ handleDemux(payload as { sourceUrl: string; format?: string });
193
+ break;
194
+ case 'decode':
195
+ handleDecode(payload as { trackId: string; codec: string });
196
+ break;
197
+ case 'packet':
198
+ handlePacket(payload as { data: Uint8Array });
199
+ break;
200
+ default:
201
+ console.warn(`Unknown message type: ${type}`);
202
+ }
203
+ };
204
+}
205
+
206
+function handleDemux(payload: { sourceUrl: string; format?: string }): void {
207
+ // TODO: Implement demux handling
208
+ // This would use ContainerRegistry to demux the source
209
+ console.log('Demux command received:', payload);
210
+}
211
+
212
+function handleDecode(payload: { trackId: string; codec: string }): void {
213
+ // TODO: Implement decode handling
214
+ // This would use CodecNegotiator and WebCodecsVideoDecoder
215
+ console.log('Decode command received:', payload);
216
+}
217
+
218
+function handlePacket(payload: { data: Uint8Array }): void {
219
+ // TODO: Implement packet handling
220
+ // This would process the packet data
221
+ console.log('Packet received:', payload.data.length, 'bytes');
222
+}
223
+
224
+// Setup worker self message handler
225
+if (typeof self !== 'undefined' && typeof (self as any).onmessage !== 'undefined') {
226
+ (self as any).onmessage = createWorkerHandler();
227
+}
43
228