hls.js 1.5.14-0.canary.10515 → 1.5.14

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 (107) hide show
  1. package/README.md +3 -4
  2. package/dist/hls-demo.js +38 -41
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +2903 -4542
  5. package/dist/hls.js.d.ts +112 -186
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +2284 -3295
  8. package/dist/hls.light.js.map +1 -1
  9. package/dist/hls.light.min.js +1 -1
  10. package/dist/hls.light.min.js.map +1 -1
  11. package/dist/hls.light.mjs +1804 -2817
  12. package/dist/hls.light.mjs.map +1 -1
  13. package/dist/hls.min.js +1 -1
  14. package/dist/hls.min.js.map +1 -1
  15. package/dist/hls.mjs +4652 -6293
  16. package/dist/hls.mjs.map +1 -1
  17. package/dist/hls.worker.js +1 -1
  18. package/dist/hls.worker.js.map +1 -1
  19. package/package.json +38 -38
  20. package/src/config.ts +2 -5
  21. package/src/controller/abr-controller.ts +25 -39
  22. package/src/controller/audio-stream-controller.ts +136 -156
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +10 -27
  25. package/src/controller/base-stream-controller.ts +107 -263
  26. package/src/controller/buffer-controller.ts +98 -252
  27. package/src/controller/buffer-operation-queue.ts +19 -16
  28. package/src/controller/cap-level-controller.ts +2 -3
  29. package/src/controller/cmcd-controller.ts +14 -51
  30. package/src/controller/content-steering-controller.ts +15 -29
  31. package/src/controller/eme-controller.ts +23 -10
  32. package/src/controller/error-controller.ts +22 -28
  33. package/src/controller/fps-controller.ts +3 -8
  34. package/src/controller/fragment-finders.ts +16 -44
  35. package/src/controller/fragment-tracker.ts +25 -58
  36. package/src/controller/gap-controller.ts +16 -43
  37. package/src/controller/id3-track-controller.ts +35 -45
  38. package/src/controller/latency-controller.ts +13 -18
  39. package/src/controller/level-controller.ts +19 -37
  40. package/src/controller/stream-controller.ts +83 -100
  41. package/src/controller/subtitle-stream-controller.ts +47 -35
  42. package/src/controller/subtitle-track-controller.ts +3 -5
  43. package/src/controller/timeline-controller.ts +22 -20
  44. package/src/crypt/aes-crypto.ts +2 -21
  45. package/src/crypt/decrypter.ts +16 -32
  46. package/src/crypt/fast-aes-key.ts +5 -28
  47. package/src/demux/audio/aacdemuxer.ts +5 -5
  48. package/src/demux/audio/ac3-demuxer.ts +4 -5
  49. package/src/demux/audio/adts.ts +4 -9
  50. package/src/demux/audio/base-audio-demuxer.ts +14 -16
  51. package/src/demux/audio/mp3demuxer.ts +3 -4
  52. package/src/demux/audio/mpegaudio.ts +1 -1
  53. package/src/demux/id3.ts +411 -0
  54. package/src/demux/inject-worker.ts +4 -38
  55. package/src/demux/mp4demuxer.ts +7 -7
  56. package/src/demux/sample-aes.ts +0 -2
  57. package/src/demux/transmuxer-interface.ts +83 -106
  58. package/src/demux/transmuxer-worker.ts +77 -111
  59. package/src/demux/transmuxer.ts +22 -46
  60. package/src/demux/tsdemuxer.ts +62 -122
  61. package/src/demux/video/avc-video-parser.ts +121 -210
  62. package/src/demux/video/base-video-parser.ts +2 -135
  63. package/src/demux/video/exp-golomb.ts +208 -0
  64. package/src/errors.ts +0 -2
  65. package/src/events.ts +1 -8
  66. package/src/exports-named.ts +1 -1
  67. package/src/hls.ts +48 -97
  68. package/src/loader/date-range.ts +5 -71
  69. package/src/loader/fragment-loader.ts +21 -23
  70. package/src/loader/fragment.ts +4 -8
  71. package/src/loader/key-loader.ts +1 -3
  72. package/src/loader/level-details.ts +6 -6
  73. package/src/loader/level-key.ts +9 -10
  74. package/src/loader/m3u8-parser.ts +144 -138
  75. package/src/loader/playlist-loader.ts +7 -5
  76. package/src/remux/mp4-generator.ts +1 -196
  77. package/src/remux/mp4-remuxer.ts +84 -55
  78. package/src/remux/passthrough-remuxer.ts +8 -23
  79. package/src/task-loop.ts +2 -5
  80. package/src/types/component-api.ts +1 -3
  81. package/src/types/demuxer.ts +0 -3
  82. package/src/types/events.ts +6 -19
  83. package/src/types/fragment-tracker.ts +2 -2
  84. package/src/types/general.ts +6 -0
  85. package/src/types/media-playlist.ts +1 -9
  86. package/src/types/remuxer.ts +1 -1
  87. package/src/utils/attr-list.ts +9 -96
  88. package/src/utils/buffer-helper.ts +31 -12
  89. package/src/utils/cea-608-parser.ts +3 -1
  90. package/src/utils/codecs.ts +5 -34
  91. package/src/utils/discontinuities.ts +47 -21
  92. package/src/utils/fetch-loader.ts +1 -1
  93. package/src/utils/hdr.ts +7 -4
  94. package/src/utils/imsc1-ttml-parser.ts +1 -1
  95. package/src/utils/keysystem-util.ts +6 -1
  96. package/src/utils/level-helper.ts +44 -71
  97. package/src/utils/logger.ts +23 -58
  98. package/src/utils/mp4-tools.ts +3 -5
  99. package/src/utils/rendition-helper.ts +74 -100
  100. package/src/utils/variable-substitution.ts +19 -0
  101. package/src/utils/webvtt-parser.ts +12 -2
  102. package/src/crypt/decrypter-aes-mode.ts +0 -4
  103. package/src/demux/video/hevc-video-parser.ts +0 -749
  104. package/src/utils/encryption-methods-util.ts +0 -21
  105. package/src/utils/hash.ts +0 -10
  106. package/src/utils/utf8-utils.ts +0 -18
  107. 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 { MediaFragment, Part } from '../loader/fragment';
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: MediaFragment | null = null;
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 || undefined;
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 m2tsTypeSupported = getM2TSSupportedAudioTypes(
76
- config.preferManagedMediaSource,
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.onWorkerMessage);
93
- worker.addEventListener('error', this.onWorkerError);
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
- id,
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.terminateWorker();
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
- reset() {
132
- this.frag = null;
133
- this.part = null;
143
+ resetWorker() {
134
144
  if (this.workerContext) {
135
- const instanceNo = this.instanceNo;
136
- this.instanceNo = transmuxerInstanceCount++;
137
- const config = this.hls.config;
138
- const m2tsTypeSupported = getM2TSSupportedAudioTypes(
139
- config.preferManagedMediaSource,
140
- );
141
- this.workerContext.worker.postMessage({
142
- instanceNo: this.instanceNo,
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.terminateWorker();
165
- // @ts-ignore
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: MediaFragment,
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 { instanceNo, transmuxer } = this;
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
- this.hls.logger
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 { instanceNo, transmuxer } = this;
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
- const transmuxResult = transmuxer.flush(chunkMeta);
309
- if (isPromise(transmuxResult)) {
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(transmuxResult, chunkMeta);
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
- event: string;
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 (!hls || !data?.event || data.instanceNo !== this.instanceNo) {
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 (hls.logger[data.data.logType]) {
394
- hls.logger[data.data.logType](data.data.message);
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 { instanceNo, transmuxer } = this;
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 { enableLogs, type ILogFunction, type ILogger } from '../utils/logger';
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, instanceNo);
70
+ emitTransmuxComplete(self, data);
68
71
  })
69
72
  .catch((error) => {
70
- forwardMessage(
71
- Events.ERROR,
72
- {
73
- instanceNo,
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
- },
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
- emitTransmuxComplete(self, transmuxResult, instanceNo);
84
+ self.transmuxer.async = false;
85
+ emitTransmuxComplete(self, transmuxResult);
87
86
  }
88
87
  break;
89
88
  }
90
89
  case 'flush': {
91
- const chunkMeta = data.chunkMeta as ChunkMetadata;
92
- const transmuxResult = transmuxer.flush(chunkMeta);
93
- if (isPromise(transmuxResult)) {
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
- Events.ERROR,
106
- {
107
- type: ErrorTypes.MEDIA_ERROR,
108
- details: ErrorDetails.FRAG_PARSING_ERROR,
109
- chunkMeta: data.chunkMeta,
110
- fatal: false,
111
- error,
112
- err: error,
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
- chunkMeta,
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, instanceNo },
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) {