hls.js 1.5.14-0.canary.10559 → 1.5.15
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 +3 -4
- package/dist/hls-demo.js +38 -41
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +2911 -4558
- package/dist/hls.js.d.ts +112 -186
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2291 -3311
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +1813 -2835
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +4707 -6356
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +42 -42
- package/src/config.ts +2 -5
- package/src/controller/abr-controller.ts +25 -39
- package/src/controller/audio-stream-controller.ts +136 -156
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +10 -27
- package/src/controller/base-stream-controller.ts +107 -263
- package/src/controller/buffer-controller.ts +97 -250
- package/src/controller/buffer-operation-queue.ts +19 -16
- package/src/controller/cap-level-controller.ts +2 -3
- package/src/controller/cmcd-controller.ts +14 -51
- package/src/controller/content-steering-controller.ts +15 -29
- package/src/controller/eme-controller.ts +23 -10
- package/src/controller/error-controller.ts +22 -28
- package/src/controller/fps-controller.ts +3 -8
- package/src/controller/fragment-finders.ts +16 -44
- package/src/controller/fragment-tracker.ts +25 -58
- package/src/controller/gap-controller.ts +16 -43
- package/src/controller/id3-track-controller.ts +35 -45
- package/src/controller/latency-controller.ts +13 -18
- package/src/controller/level-controller.ts +19 -37
- package/src/controller/stream-controller.ts +83 -100
- package/src/controller/subtitle-stream-controller.ts +47 -35
- package/src/controller/subtitle-track-controller.ts +3 -5
- package/src/controller/timeline-controller.ts +22 -20
- package/src/crypt/aes-crypto.ts +2 -21
- package/src/crypt/decrypter.ts +16 -32
- package/src/crypt/fast-aes-key.ts +5 -28
- package/src/demux/audio/aacdemuxer.ts +5 -5
- package/src/demux/audio/ac3-demuxer.ts +4 -5
- package/src/demux/audio/adts.ts +4 -9
- package/src/demux/audio/base-audio-demuxer.ts +15 -21
- package/src/demux/audio/mp3demuxer.ts +3 -4
- package/src/demux/audio/mpegaudio.ts +1 -1
- package/src/demux/id3.ts +411 -0
- package/src/demux/inject-worker.ts +4 -38
- package/src/demux/mp4demuxer.ts +8 -17
- package/src/demux/sample-aes.ts +0 -2
- package/src/demux/transmuxer-interface.ts +83 -106
- package/src/demux/transmuxer-worker.ts +77 -111
- package/src/demux/transmuxer.ts +22 -46
- package/src/demux/tsdemuxer.ts +65 -131
- package/src/demux/video/avc-video-parser.ts +156 -219
- package/src/demux/video/base-video-parser.ts +9 -133
- package/src/demux/video/exp-golomb.ts +208 -0
- package/src/errors.ts +0 -2
- package/src/events.ts +1 -8
- package/src/exports-named.ts +1 -1
- package/src/hls.ts +48 -97
- package/src/loader/date-range.ts +5 -71
- package/src/loader/fragment-loader.ts +21 -23
- package/src/loader/fragment.ts +4 -8
- package/src/loader/key-loader.ts +1 -3
- package/src/loader/level-details.ts +6 -6
- package/src/loader/level-key.ts +9 -10
- package/src/loader/m3u8-parser.ts +144 -138
- package/src/loader/playlist-loader.ts +7 -5
- package/src/remux/mp4-generator.ts +1 -196
- package/src/remux/mp4-remuxer.ts +84 -55
- package/src/remux/passthrough-remuxer.ts +8 -23
- package/src/task-loop.ts +2 -5
- package/src/types/component-api.ts +1 -3
- package/src/types/demuxer.ts +1 -3
- package/src/types/events.ts +6 -19
- package/src/types/fragment-tracker.ts +2 -2
- package/src/types/general.ts +6 -0
- package/src/types/media-playlist.ts +1 -9
- package/src/types/remuxer.ts +1 -1
- package/src/utils/attr-list.ts +9 -96
- package/src/utils/buffer-helper.ts +31 -12
- package/src/utils/cea-608-parser.ts +3 -1
- package/src/utils/codecs.ts +5 -34
- package/src/utils/discontinuities.ts +47 -21
- package/src/utils/fetch-loader.ts +1 -1
- package/src/utils/hdr.ts +7 -4
- package/src/utils/imsc1-ttml-parser.ts +1 -1
- package/src/utils/keysystem-util.ts +6 -1
- package/src/utils/level-helper.ts +44 -71
- package/src/utils/logger.ts +23 -58
- package/src/utils/mp4-tools.ts +3 -5
- package/src/utils/rendition-helper.ts +74 -100
- package/src/utils/variable-substitution.ts +19 -0
- package/src/utils/webvtt-parser.ts +12 -2
- package/dist/hls.d.mts +0 -3179
- package/dist/hls.d.ts +0 -3179
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/demux/video/hevc-video-parser.ts +0 -718
- package/src/utils/encryption-methods-util.ts +0 -21
- package/src/utils/hash.ts +0 -10
- package/src/utils/utf8-utils.ts +0 -18
- package/src/version.ts +0 -1
@@ -3,7 +3,6 @@ import {
|
|
3
3
|
hasUMDWorker,
|
4
4
|
injectWorker,
|
5
5
|
loadWorker,
|
6
|
-
removeWorkerFromStore as removeWorkerClient,
|
7
6
|
} from './inject-worker';
|
8
7
|
import { Events } from '../events';
|
9
8
|
import Transmuxer, {
|
@@ -11,30 +10,30 @@ import Transmuxer, {
|
|
11
10
|
TransmuxState,
|
12
11
|
isPromise,
|
13
12
|
} from '../demux/transmuxer';
|
13
|
+
import { logger } from '../utils/logger';
|
14
14
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
15
|
+
import { getMediaSource } from '../utils/mediasource-helper';
|
15
16
|
import { EventEmitter } from 'eventemitter3';
|
16
|
-
import {
|
17
|
-
import { getM2TSSupportedAudioTypes } from '../utils/codecs';
|
18
|
-
|
17
|
+
import { Fragment, Part } from '../loader/fragment';
|
19
18
|
import type { ChunkMetadata, TransmuxerResult } from '../types/transmuxer';
|
20
19
|
import type Hls from '../hls';
|
21
20
|
import type { HlsEventEmitter, HlsListeners } from '../events';
|
22
|
-
import type { ErrorData, FragDecryptedData } from '../types/events';
|
23
21
|
import type { PlaylistLevelType } from '../types/loader';
|
22
|
+
import type { TypeSupported } from './tsdemuxer';
|
24
23
|
import type { RationalTimestamp } from '../utils/timescale-conversion';
|
25
24
|
|
26
|
-
let transmuxerInstanceCount: number = 0;
|
27
|
-
|
28
25
|
export default class TransmuxerInterface {
|
29
26
|
public error: Error | null = null;
|
30
27
|
private hls: Hls;
|
31
28
|
private id: PlaylistLevelType;
|
32
|
-
private instanceNo: number = transmuxerInstanceCount++;
|
33
29
|
private observer: HlsEventEmitter;
|
34
|
-
private frag:
|
30
|
+
private frag: Fragment | null = null;
|
35
31
|
private part: Part | null = null;
|
36
32
|
private useWorker: boolean;
|
37
33
|
private workerContext: WorkerContext | null = null;
|
34
|
+
private onwmsg?: (
|
35
|
+
event: MessageEvent<{ event: string; data?: any } | null>,
|
36
|
+
) => void;
|
38
37
|
private transmuxer: Transmuxer | null = null;
|
39
38
|
private onTransmuxComplete: (transmuxResult: TransmuxerResult) => void;
|
40
39
|
private onFlush: (chunkMeta: ChunkMetadata) => void;
|
@@ -52,16 +51,11 @@ export default class TransmuxerInterface {
|
|
52
51
|
this.onTransmuxComplete = onTransmuxComplete;
|
53
52
|
this.onFlush = onFlush;
|
54
53
|
|
55
|
-
const forwardMessage = (
|
56
|
-
ev: Events.ERROR | Events.FRAG_DECRYPTED,
|
57
|
-
data: ErrorData | FragDecryptedData,
|
58
|
-
) => {
|
54
|
+
const forwardMessage = (ev, data) => {
|
59
55
|
data = data || {};
|
60
|
-
data.frag = this.frag
|
56
|
+
data.frag = this.frag;
|
57
|
+
data.id = this.id;
|
61
58
|
if (ev === Events.ERROR) {
|
62
|
-
data = data as ErrorData;
|
63
|
-
data.parent = this.id;
|
64
|
-
data.part = this.part;
|
65
59
|
this.error = data.error;
|
66
60
|
}
|
67
61
|
this.hls.trigger(ev, data);
|
@@ -72,12 +66,18 @@ export default class TransmuxerInterface {
|
|
72
66
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
73
67
|
this.observer.on(Events.ERROR, forwardMessage);
|
74
68
|
|
75
|
-
const
|
76
|
-
|
77
|
-
|
69
|
+
const MediaSource = getMediaSource(config.preferManagedMediaSource) || {
|
70
|
+
isTypeSupported: () => false,
|
71
|
+
};
|
72
|
+
const m2tsTypeSupported: TypeSupported = {
|
73
|
+
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
74
|
+
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
75
|
+
ac3: __USE_M2TS_ADVANCED_CODECS__
|
76
|
+
? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
|
77
|
+
: false,
|
78
|
+
};
|
78
79
|
|
79
80
|
if (this.useWorker && typeof Worker !== 'undefined') {
|
80
|
-
const logger = this.hls.logger;
|
81
81
|
const canCreateWorker = config.workerPath || hasUMDWorker();
|
82
82
|
if (canCreateWorker) {
|
83
83
|
try {
|
@@ -88,14 +88,28 @@ export default class TransmuxerInterface {
|
|
88
88
|
logger.log(`injecting Web Worker for "${id}"`);
|
89
89
|
this.workerContext = injectWorker();
|
90
90
|
}
|
91
|
+
this.onwmsg = (event) => this.onWorkerMessage(event);
|
91
92
|
const { worker } = this.workerContext;
|
92
|
-
worker.addEventListener('message', this.
|
93
|
-
worker.
|
93
|
+
worker.addEventListener('message', this.onwmsg);
|
94
|
+
worker.onerror = (event) => {
|
95
|
+
const error = new Error(
|
96
|
+
`${event.message} (${event.filename}:${event.lineno})`,
|
97
|
+
);
|
98
|
+
config.enableWorker = false;
|
99
|
+
logger.warn(`Error in "${id}" Web Worker, fallback to inline`);
|
100
|
+
this.hls.trigger(Events.ERROR, {
|
101
|
+
type: ErrorTypes.OTHER_ERROR,
|
102
|
+
details: ErrorDetails.INTERNAL_EXCEPTION,
|
103
|
+
fatal: false,
|
104
|
+
event: 'demuxerWorker',
|
105
|
+
error,
|
106
|
+
});
|
107
|
+
};
|
94
108
|
worker.postMessage({
|
95
|
-
instanceNo: this.instanceNo,
|
96
109
|
cmd: 'init',
|
97
110
|
typeSupported: m2tsTypeSupported,
|
98
|
-
|
111
|
+
vendor: '',
|
112
|
+
id: id,
|
99
113
|
config: JSON.stringify(config),
|
100
114
|
});
|
101
115
|
} catch (err) {
|
@@ -103,7 +117,7 @@ export default class TransmuxerInterface {
|
|
103
117
|
`Error setting up "${id}" Web Worker, fallback to inline`,
|
104
118
|
err,
|
105
119
|
);
|
106
|
-
this.
|
120
|
+
this.resetWorker();
|
107
121
|
this.error = null;
|
108
122
|
this.transmuxer = new Transmuxer(
|
109
123
|
this.observer,
|
@@ -111,7 +125,6 @@ export default class TransmuxerInterface {
|
|
111
125
|
config,
|
112
126
|
'',
|
113
127
|
id,
|
114
|
-
hls.logger,
|
115
128
|
);
|
116
129
|
}
|
117
130
|
return;
|
@@ -124,46 +137,27 @@ export default class TransmuxerInterface {
|
|
124
137
|
config,
|
125
138
|
'',
|
126
139
|
id,
|
127
|
-
hls.logger,
|
128
140
|
);
|
129
141
|
}
|
130
142
|
|
131
|
-
|
132
|
-
this.frag = null;
|
133
|
-
this.part = null;
|
143
|
+
resetWorker() {
|
134
144
|
if (this.workerContext) {
|
135
|
-
const
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
);
|
141
|
-
|
142
|
-
|
143
|
-
cmd: 'reset',
|
144
|
-
resetNo: instanceNo,
|
145
|
-
typeSupported: m2tsTypeSupported,
|
146
|
-
id: this.id,
|
147
|
-
config: JSON.stringify(config),
|
148
|
-
});
|
149
|
-
}
|
150
|
-
}
|
151
|
-
|
152
|
-
private terminateWorker() {
|
153
|
-
if (this.workerContext) {
|
154
|
-
const { worker } = this.workerContext;
|
145
|
+
const { worker, objectURL } = this.workerContext;
|
146
|
+
if (objectURL) {
|
147
|
+
// revoke the Object URL that was used to create transmuxer worker, so as not to leak it
|
148
|
+
self.URL.revokeObjectURL(objectURL);
|
149
|
+
}
|
150
|
+
worker.removeEventListener('message', this.onwmsg as any);
|
151
|
+
worker.onerror = null;
|
152
|
+
worker.terminate();
|
155
153
|
this.workerContext = null;
|
156
|
-
worker.removeEventListener('message', this.onWorkerMessage);
|
157
|
-
worker.removeEventListener('error', this.onWorkerError);
|
158
|
-
removeWorkerClient(this.hls.config.workerPath);
|
159
154
|
}
|
160
155
|
}
|
161
156
|
|
162
157
|
destroy() {
|
163
158
|
if (this.workerContext) {
|
164
|
-
this.
|
165
|
-
|
166
|
-
this.onWorkerMessage = this.onWorkerError = null;
|
159
|
+
this.resetWorker();
|
160
|
+
this.onwmsg = undefined;
|
167
161
|
} else {
|
168
162
|
const transmuxer = this.transmuxer;
|
169
163
|
if (transmuxer) {
|
@@ -176,7 +170,6 @@ export default class TransmuxerInterface {
|
|
176
170
|
observer.removeAllListeners();
|
177
171
|
}
|
178
172
|
this.frag = null;
|
179
|
-
this.part = null;
|
180
173
|
// @ts-ignore
|
181
174
|
this.observer = null;
|
182
175
|
// @ts-ignore
|
@@ -188,7 +181,7 @@ export default class TransmuxerInterface {
|
|
188
181
|
initSegmentData: Uint8Array | undefined,
|
189
182
|
audioCodec: string | undefined,
|
190
183
|
videoCodec: string | undefined,
|
191
|
-
frag:
|
184
|
+
frag: Fragment,
|
192
185
|
part: Part | null,
|
193
186
|
duration: number,
|
194
187
|
accurateTimeOffset: boolean,
|
@@ -196,7 +189,7 @@ export default class TransmuxerInterface {
|
|
196
189
|
defaultInitPTS?: RationalTimestamp,
|
197
190
|
) {
|
198
191
|
chunkMeta.transmuxing.start = self.performance.now();
|
199
|
-
const {
|
192
|
+
const { transmuxer } = this;
|
200
193
|
const timeOffset = part ? part.start : frag.start;
|
201
194
|
// TODO: push "clear-lead" decrypt data for unencrypted fragments in streams with encrypted ones
|
202
195
|
const decryptdata = frag.decryptdata;
|
@@ -204,7 +197,7 @@ export default class TransmuxerInterface {
|
|
204
197
|
|
205
198
|
const discontinuity = !(lastFrag && frag.cc === lastFrag.cc);
|
206
199
|
const trackSwitch = !(lastFrag && chunkMeta.level === lastFrag.level);
|
207
|
-
const snDiff = lastFrag ? chunkMeta.sn - lastFrag.sn : -1;
|
200
|
+
const snDiff = lastFrag ? chunkMeta.sn - (lastFrag.sn as number) : -1;
|
208
201
|
const partDiff = this.part ? chunkMeta.part - this.part.index : -1;
|
209
202
|
const progressive =
|
210
203
|
snDiff === 0 &&
|
@@ -234,8 +227,7 @@ export default class TransmuxerInterface {
|
|
234
227
|
initSegmentChange,
|
235
228
|
);
|
236
229
|
if (!contiguous || discontinuity || initSegmentChange) {
|
237
|
-
|
238
|
-
.log(`[transmuxer-interface, ${frag.type}]: Starting new transmux session for sn: ${chunkMeta.sn} p: ${chunkMeta.part} level: ${chunkMeta.level} id: ${chunkMeta.id}
|
230
|
+
logger.log(`[transmuxer-interface, ${frag.type}]: Starting new transmux session for sn: ${chunkMeta.sn} p: ${chunkMeta.part} level: ${chunkMeta.level} id: ${chunkMeta.id}
|
239
231
|
discontinuity: ${discontinuity}
|
240
232
|
trackSwitch: ${trackSwitch}
|
241
233
|
contiguous: ${contiguous}
|
@@ -260,7 +252,6 @@ export default class TransmuxerInterface {
|
|
260
252
|
// post fragment payload as transferable objects for ArrayBuffer (no copy)
|
261
253
|
this.workerContext.worker.postMessage(
|
262
254
|
{
|
263
|
-
instanceNo,
|
264
255
|
cmd: 'demux',
|
265
256
|
data,
|
266
257
|
decryptdata,
|
@@ -277,6 +268,7 @@ export default class TransmuxerInterface {
|
|
277
268
|
state,
|
278
269
|
);
|
279
270
|
if (isPromise(transmuxResult)) {
|
271
|
+
transmuxer.async = true;
|
280
272
|
transmuxResult
|
281
273
|
.then((data) => {
|
282
274
|
this.handleTransmuxComplete(data);
|
@@ -289,6 +281,7 @@ export default class TransmuxerInterface {
|
|
289
281
|
);
|
290
282
|
});
|
291
283
|
} else {
|
284
|
+
transmuxer.async = false;
|
292
285
|
this.handleTransmuxComplete(transmuxResult as TransmuxerResult);
|
293
286
|
}
|
294
287
|
}
|
@@ -296,17 +289,20 @@ export default class TransmuxerInterface {
|
|
296
289
|
|
297
290
|
flush(chunkMeta: ChunkMetadata) {
|
298
291
|
chunkMeta.transmuxing.start = self.performance.now();
|
299
|
-
const {
|
292
|
+
const { transmuxer } = this;
|
300
293
|
if (this.workerContext) {
|
301
294
|
1;
|
302
295
|
this.workerContext.worker.postMessage({
|
303
|
-
instanceNo,
|
304
296
|
cmd: 'flush',
|
305
297
|
chunkMeta,
|
306
298
|
});
|
307
299
|
} else if (transmuxer) {
|
308
|
-
|
309
|
-
|
300
|
+
let transmuxResult = transmuxer.flush(chunkMeta);
|
301
|
+
const asyncFlush = isPromise(transmuxResult);
|
302
|
+
if (asyncFlush || transmuxer.async) {
|
303
|
+
if (!isPromise(transmuxResult)) {
|
304
|
+
transmuxResult = Promise.resolve(transmuxResult);
|
305
|
+
}
|
310
306
|
transmuxResult
|
311
307
|
.then((data) => {
|
312
308
|
this.handleFlushResult(data, chunkMeta);
|
@@ -319,7 +315,10 @@ export default class TransmuxerInterface {
|
|
319
315
|
);
|
320
316
|
});
|
321
317
|
} else {
|
322
|
-
this.handleFlushResult(
|
318
|
+
this.handleFlushResult(
|
319
|
+
transmuxResult as Array<TransmuxerResult>,
|
320
|
+
chunkMeta,
|
321
|
+
);
|
323
322
|
}
|
324
323
|
}
|
325
324
|
}
|
@@ -338,7 +337,6 @@ export default class TransmuxerInterface {
|
|
338
337
|
details: ErrorDetails.FRAG_PARSING_ERROR,
|
339
338
|
chunkMeta,
|
340
339
|
frag: this.frag || undefined,
|
341
|
-
part: this.part || undefined,
|
342
340
|
fatal: false,
|
343
341
|
error,
|
344
342
|
err: error,
|
@@ -356,16 +354,18 @@ export default class TransmuxerInterface {
|
|
356
354
|
this.onFlush(chunkMeta);
|
357
355
|
}
|
358
356
|
|
359
|
-
private onWorkerMessage
|
360
|
-
event: MessageEvent<{
|
361
|
-
|
362
|
-
data?: any;
|
363
|
-
instanceNo?: number;
|
364
|
-
} | null>,
|
365
|
-
) => {
|
357
|
+
private onWorkerMessage(
|
358
|
+
event: MessageEvent<{ event: string; data?: any } | null>,
|
359
|
+
) {
|
366
360
|
const data = event.data;
|
361
|
+
if (!data?.event) {
|
362
|
+
logger.warn(
|
363
|
+
`worker message received with no ${data ? 'event name' : 'data'}`,
|
364
|
+
);
|
365
|
+
return;
|
366
|
+
}
|
367
367
|
const hls = this.hls;
|
368
|
-
if (!
|
368
|
+
if (!this.hls) {
|
369
369
|
return;
|
370
370
|
}
|
371
371
|
switch (data.event) {
|
@@ -389,49 +389,26 @@ export default class TransmuxerInterface {
|
|
389
389
|
}
|
390
390
|
|
391
391
|
// pass logs from the worker thread to the main logger
|
392
|
-
case 'workerLog':
|
393
|
-
if (
|
394
|
-
|
392
|
+
case 'workerLog':
|
393
|
+
if (logger[data.data.logType]) {
|
394
|
+
logger[data.data.logType](data.data.message);
|
395
395
|
}
|
396
396
|
break;
|
397
|
-
}
|
398
397
|
|
399
398
|
default: {
|
400
399
|
data.data = data.data || {};
|
401
400
|
data.data.frag = this.frag;
|
402
|
-
data.data.part = this.part;
|
403
401
|
data.data.id = this.id;
|
404
402
|
hls.trigger(data.event as keyof HlsListeners, data.data);
|
405
403
|
break;
|
406
404
|
}
|
407
405
|
}
|
408
|
-
}
|
409
|
-
|
410
|
-
private onWorkerError = (event) => {
|
411
|
-
if (!this.hls) {
|
412
|
-
return;
|
413
|
-
}
|
414
|
-
const error = new Error(
|
415
|
-
`${event.message} (${event.filename}:${event.lineno})`,
|
416
|
-
);
|
417
|
-
this.hls.config.enableWorker = false;
|
418
|
-
this.hls.logger.warn(
|
419
|
-
`Error in "${this.id}" Web Worker, fallback to inline`,
|
420
|
-
);
|
421
|
-
this.hls.trigger(Events.ERROR, {
|
422
|
-
type: ErrorTypes.OTHER_ERROR,
|
423
|
-
details: ErrorDetails.INTERNAL_EXCEPTION,
|
424
|
-
fatal: false,
|
425
|
-
event: 'demuxerWorker',
|
426
|
-
error,
|
427
|
-
});
|
428
|
-
};
|
406
|
+
}
|
429
407
|
|
430
408
|
private configureTransmuxer(config: TransmuxConfig) {
|
431
|
-
const {
|
409
|
+
const { transmuxer } = this;
|
432
410
|
if (this.workerContext) {
|
433
411
|
this.workerContext.worker.postMessage({
|
434
|
-
instanceNo,
|
435
412
|
cmd: 'configure',
|
436
413
|
config,
|
437
414
|
});
|
@@ -1,126 +1,119 @@
|
|
1
1
|
import Transmuxer, { isPromise } from '../demux/transmuxer';
|
2
2
|
import { Events } from '../events';
|
3
|
-
import {
|
3
|
+
import { ILogFunction, enableLogs, logger } from '../utils/logger';
|
4
4
|
import { EventEmitter } from 'eventemitter3';
|
5
5
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
6
6
|
import type { RemuxedTrack, RemuxerResult } from '../types/remuxer';
|
7
7
|
import type { TransmuxerResult, ChunkMetadata } from '../types/transmuxer';
|
8
8
|
|
9
|
-
const transmuxers: (Transmuxer | undefined)[] = [];
|
10
|
-
|
11
9
|
if (typeof __IN_WORKER__ !== 'undefined' && __IN_WORKER__) {
|
12
|
-
startWorker();
|
10
|
+
startWorker(self);
|
13
11
|
}
|
14
12
|
|
15
|
-
function startWorker() {
|
13
|
+
function startWorker(self) {
|
14
|
+
const observer = new EventEmitter();
|
15
|
+
const forwardMessage = (ev, data) => {
|
16
|
+
self.postMessage({ event: ev, data: data });
|
17
|
+
};
|
18
|
+
|
19
|
+
// forward events to main thread
|
20
|
+
observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
21
|
+
observer.on(Events.ERROR, forwardMessage);
|
22
|
+
|
23
|
+
// forward logger events to main thread
|
24
|
+
const forwardWorkerLogs = () => {
|
25
|
+
for (const logFn in logger) {
|
26
|
+
const func: ILogFunction = (message?) => {
|
27
|
+
forwardMessage('workerLog', {
|
28
|
+
logType: logFn,
|
29
|
+
message,
|
30
|
+
});
|
31
|
+
};
|
32
|
+
|
33
|
+
logger[logFn] = func;
|
34
|
+
}
|
35
|
+
};
|
36
|
+
|
16
37
|
self.addEventListener('message', (ev) => {
|
17
38
|
const data = ev.data;
|
18
|
-
const instanceNo = data.instanceNo;
|
19
|
-
if (instanceNo === undefined) {
|
20
|
-
return;
|
21
|
-
}
|
22
|
-
const transmuxer = transmuxers[instanceNo];
|
23
|
-
if (data.cmd === 'reset') {
|
24
|
-
delete transmuxers[data.resetNo];
|
25
|
-
if (transmuxer) {
|
26
|
-
transmuxer.destroy();
|
27
|
-
}
|
28
|
-
data.cmd = 'init';
|
29
|
-
}
|
30
|
-
if (data.cmd === 'init') {
|
31
|
-
const config = JSON.parse(data.config);
|
32
|
-
const observer = new EventEmitter();
|
33
|
-
observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
34
|
-
observer.on(Events.ERROR, forwardMessage);
|
35
|
-
const logger = enableLogs(config.debug, data.id);
|
36
|
-
forwardWorkerLogs(logger, instanceNo);
|
37
|
-
transmuxers[instanceNo] = new Transmuxer(
|
38
|
-
observer,
|
39
|
-
data.typeSupported,
|
40
|
-
config,
|
41
|
-
'',
|
42
|
-
data.id,
|
43
|
-
logger,
|
44
|
-
);
|
45
|
-
forwardMessage('init', null, instanceNo);
|
46
|
-
return;
|
47
|
-
}
|
48
|
-
if (!transmuxer) {
|
49
|
-
return;
|
50
|
-
}
|
51
39
|
switch (data.cmd) {
|
40
|
+
case 'init': {
|
41
|
+
const config = JSON.parse(data.config);
|
42
|
+
self.transmuxer = new Transmuxer(
|
43
|
+
observer,
|
44
|
+
data.typeSupported,
|
45
|
+
config,
|
46
|
+
'',
|
47
|
+
data.id,
|
48
|
+
);
|
49
|
+
enableLogs(config.debug, data.id);
|
50
|
+
forwardWorkerLogs();
|
51
|
+
forwardMessage('init', null);
|
52
|
+
break;
|
53
|
+
}
|
52
54
|
case 'configure': {
|
53
|
-
transmuxer.configure(data.config);
|
55
|
+
self.transmuxer.configure(data.config);
|
54
56
|
break;
|
55
57
|
}
|
56
58
|
case 'demux': {
|
57
59
|
const transmuxResult: TransmuxerResult | Promise<TransmuxerResult> =
|
58
|
-
transmuxer.push(
|
60
|
+
self.transmuxer.push(
|
59
61
|
data.data,
|
60
62
|
data.decryptdata,
|
61
63
|
data.chunkMeta,
|
62
64
|
data.state,
|
63
65
|
);
|
64
66
|
if (isPromise(transmuxResult)) {
|
67
|
+
self.transmuxer.async = true;
|
65
68
|
transmuxResult
|
66
69
|
.then((data) => {
|
67
|
-
emitTransmuxComplete(self, data
|
70
|
+
emitTransmuxComplete(self, data);
|
68
71
|
})
|
69
72
|
.catch((error) => {
|
70
|
-
forwardMessage(
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
err: error,
|
80
|
-
reason: `transmuxer-worker push error`,
|
81
|
-
},
|
82
|
-
instanceNo,
|
83
|
-
);
|
73
|
+
forwardMessage(Events.ERROR, {
|
74
|
+
type: ErrorTypes.MEDIA_ERROR,
|
75
|
+
details: ErrorDetails.FRAG_PARSING_ERROR,
|
76
|
+
chunkMeta: data.chunkMeta,
|
77
|
+
fatal: false,
|
78
|
+
error,
|
79
|
+
err: error,
|
80
|
+
reason: `transmuxer-worker push error`,
|
81
|
+
});
|
84
82
|
});
|
85
83
|
} else {
|
86
|
-
|
84
|
+
self.transmuxer.async = false;
|
85
|
+
emitTransmuxComplete(self, transmuxResult);
|
87
86
|
}
|
88
87
|
break;
|
89
88
|
}
|
90
89
|
case 'flush': {
|
91
|
-
const
|
92
|
-
|
93
|
-
|
90
|
+
const id = data.chunkMeta;
|
91
|
+
let transmuxResult = self.transmuxer.flush(id);
|
92
|
+
const asyncFlush = isPromise(transmuxResult);
|
93
|
+
if (asyncFlush || self.transmuxer.async) {
|
94
|
+
if (!isPromise(transmuxResult)) {
|
95
|
+
transmuxResult = Promise.resolve(transmuxResult);
|
96
|
+
}
|
94
97
|
transmuxResult
|
95
98
|
.then((results: Array<TransmuxerResult>) => {
|
96
|
-
handleFlushResult(
|
97
|
-
self,
|
98
|
-
results as Array<TransmuxerResult>,
|
99
|
-
chunkMeta,
|
100
|
-
instanceNo,
|
101
|
-
);
|
99
|
+
handleFlushResult(self, results as Array<TransmuxerResult>, id);
|
102
100
|
})
|
103
101
|
.catch((error) => {
|
104
|
-
forwardMessage(
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
reason: `transmuxer-worker flush error`,
|
114
|
-
},
|
115
|
-
instanceNo,
|
116
|
-
);
|
102
|
+
forwardMessage(Events.ERROR, {
|
103
|
+
type: ErrorTypes.MEDIA_ERROR,
|
104
|
+
details: ErrorDetails.FRAG_PARSING_ERROR,
|
105
|
+
chunkMeta: data.chunkMeta,
|
106
|
+
fatal: false,
|
107
|
+
error,
|
108
|
+
err: error,
|
109
|
+
reason: `transmuxer-worker flush error`,
|
110
|
+
});
|
117
111
|
});
|
118
112
|
} else {
|
119
113
|
handleFlushResult(
|
120
114
|
self,
|
121
115
|
transmuxResult as Array<TransmuxerResult>,
|
122
|
-
|
123
|
-
instanceNo,
|
116
|
+
id,
|
124
117
|
);
|
125
118
|
}
|
126
119
|
break;
|
@@ -134,7 +127,6 @@ function startWorker() {
|
|
134
127
|
function emitTransmuxComplete(
|
135
128
|
self: any,
|
136
129
|
transmuxResult: TransmuxerResult,
|
137
|
-
instanceNo: number,
|
138
130
|
): boolean {
|
139
131
|
if (isEmptyResult(transmuxResult.remuxResult)) {
|
140
132
|
return false;
|
@@ -148,7 +140,7 @@ function emitTransmuxComplete(
|
|
148
140
|
addToTransferable(transferable, video);
|
149
141
|
}
|
150
142
|
self.postMessage(
|
151
|
-
{ event: 'transmuxComplete', data: transmuxResult
|
143
|
+
{ event: 'transmuxComplete', data: transmuxResult },
|
152
144
|
transferable,
|
153
145
|
);
|
154
146
|
return true;
|
@@ -172,42 +164,16 @@ function handleFlushResult(
|
|
172
164
|
self: any,
|
173
165
|
results: Array<TransmuxerResult>,
|
174
166
|
chunkMeta: ChunkMetadata,
|
175
|
-
instanceNo: number,
|
176
167
|
) {
|
177
168
|
const parsed = results.reduce(
|
178
|
-
(parsed, result) =>
|
179
|
-
emitTransmuxComplete(self, result, instanceNo) || parsed,
|
169
|
+
(parsed, result) => emitTransmuxComplete(self, result) || parsed,
|
180
170
|
false,
|
181
171
|
);
|
182
172
|
if (!parsed) {
|
183
173
|
// Emit at least one "transmuxComplete" message even if media is not found to update stream-controller state to PARSING
|
184
|
-
self.postMessage({
|
185
|
-
event: 'transmuxComplete',
|
186
|
-
data: results[0],
|
187
|
-
instanceNo,
|
188
|
-
});
|
189
|
-
}
|
190
|
-
self.postMessage({ event: 'flush', data: chunkMeta, instanceNo });
|
191
|
-
}
|
192
|
-
|
193
|
-
function forwardMessage(event, data, instanceNo) {
|
194
|
-
self.postMessage({ event, data, instanceNo });
|
195
|
-
}
|
196
|
-
|
197
|
-
function forwardWorkerLogs(logger: ILogger, instanceNo: number) {
|
198
|
-
for (const logFn in logger) {
|
199
|
-
const func: ILogFunction = (message?) => {
|
200
|
-
forwardMessage(
|
201
|
-
'workerLog',
|
202
|
-
{
|
203
|
-
logType: logFn,
|
204
|
-
message,
|
205
|
-
},
|
206
|
-
instanceNo,
|
207
|
-
);
|
208
|
-
};
|
209
|
-
logger[logFn] = func;
|
174
|
+
self.postMessage({ event: 'transmuxComplete', data: results[0] });
|
210
175
|
}
|
176
|
+
self.postMessage({ event: 'flush', data: chunkMeta });
|
211
177
|
}
|
212
178
|
|
213
179
|
function isEmptyResult(remuxResult: RemuxerResult) {
|