hls.js 1.5.14-0.canary.10429 → 1.5.14-0.canary.10432

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.
@@ -420,7 +420,7 @@ function enableLogs(debugConfig, context, id) {
420
420
  // Some browsers don't allow to use bind on console object anyway
421
421
  // fallback to default if needed
422
422
  try {
423
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.14-0.canary.10429"}`);
423
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.14-0.canary.10432"}`);
424
424
  } catch (e) {
425
425
  /* log fn threw an exception. All logger methods are no-ops. */
426
426
  return createLogger();
@@ -11836,30 +11836,14 @@ function findFirstFragWithCC(fragments, cc) {
11836
11836
  }
11837
11837
  return null;
11838
11838
  }
11839
- function shouldAlignOnDiscontinuities(lastFrag, switchDetails, details) {
11840
- if (switchDetails) {
11841
- if (details.endCC > details.startCC || lastFrag && lastFrag.cc < details.startCC) {
11839
+ function shouldAlignOnDiscontinuities(refDetails, details) {
11840
+ if (refDetails) {
11841
+ if (details.startCC < refDetails.endCC && details.endCC > refDetails.startCC) {
11842
11842
  return true;
11843
11843
  }
11844
11844
  }
11845
11845
  return false;
11846
11846
  }
11847
-
11848
- // Find the first frag in the previous level which matches the CC of the first frag of the new level
11849
- function findDiscontinuousReferenceFrag(prevDetails, curDetails) {
11850
- const prevFrags = prevDetails.fragments;
11851
- const curFrags = curDetails.fragments;
11852
- if (!curFrags.length || !prevFrags.length) {
11853
- logger.log('No fragments to align');
11854
- return;
11855
- }
11856
- const prevStartFrag = findFirstFragWithCC(prevFrags, curFrags[0].cc);
11857
- if (!prevStartFrag || prevStartFrag && !prevStartFrag.startPTS) {
11858
- logger.log('No frag in previous level to align on');
11859
- return;
11860
- }
11861
- return prevStartFrag;
11862
- }
11863
11847
  function adjustFragmentStart(frag, sliding) {
11864
11848
  if (frag) {
11865
11849
  const start = frag.start + sliding;
@@ -11894,7 +11878,7 @@ function alignStream(lastFrag, switchDetails, details) {
11894
11878
  if (!switchDetails) {
11895
11879
  return;
11896
11880
  }
11897
- alignDiscontinuities(lastFrag, details, switchDetails);
11881
+ alignDiscontinuities(details, switchDetails);
11898
11882
  if (!details.alignedSliding && switchDetails) {
11899
11883
  // If the PTS wasn't figured out via discontinuity sequence that means there was no CC increase within the level.
11900
11884
  // Aligning via Program Date Time should therefore be reliable, since PDT should be the same within the same
@@ -11910,20 +11894,24 @@ function alignStream(lastFrag, switchDetails, details) {
11910
11894
  }
11911
11895
 
11912
11896
  /**
11913
- * Computes the PTS if a new level's fragments using the PTS of a fragment in the last level which shares the same
11914
- * discontinuity sequence.
11915
- * @param lastFrag - The last Fragment which shares the same discontinuity sequence
11897
+ * Ajust the start of fragments in `details` by the difference in time between fragments of the latest
11898
+ * shared discontinuity sequence change.
11916
11899
  * @param lastLevel - The details of the last loaded level
11917
11900
  * @param details - The details of the new level
11918
11901
  */
11919
- function alignDiscontinuities(lastFrag, details, switchDetails) {
11920
- if (shouldAlignOnDiscontinuities(lastFrag, switchDetails, details)) {
11921
- const referenceFrag = findDiscontinuousReferenceFrag(switchDetails, details);
11922
- if (referenceFrag && isFiniteNumber(referenceFrag.start)) {
11923
- logger.log(`Adjusting PTS using last level due to CC increase within current level ${details.url}`);
11924
- adjustSlidingStart(referenceFrag.start, details);
11925
- }
11902
+ function alignDiscontinuities(details, refDetails) {
11903
+ if (!shouldAlignOnDiscontinuities(refDetails, details)) {
11904
+ return;
11926
11905
  }
11906
+ const targetCC = Math.min(refDetails.endCC, details.endCC);
11907
+ const refFrag = findFirstFragWithCC(refDetails.fragments, targetCC);
11908
+ const frag = findFirstFragWithCC(details.fragments, targetCC);
11909
+ if (!refFrag || !frag) {
11910
+ return;
11911
+ }
11912
+ logger.log(`Aligning playlist at start of dicontinuity sequence ${targetCC}`);
11913
+ const delta = refFrag.start - frag.start;
11914
+ adjustSlidingStart(delta, details);
11927
11915
  }
11928
11916
 
11929
11917
  /**
@@ -12696,6 +12684,10 @@ class BaseStreamController extends TaskLoop {
12696
12684
  }
12697
12685
  onHandlerDestroying() {
12698
12686
  this.stopLoad();
12687
+ if (this.transmuxer) {
12688
+ this.transmuxer.destroy();
12689
+ this.transmuxer = null;
12690
+ }
12699
12691
  super.onHandlerDestroying();
12700
12692
  // @ts-ignore
12701
12693
  this.hls = this.onMediaSeeking = this.onMediaEnded = null;
@@ -12742,7 +12734,7 @@ class BaseStreamController extends TaskLoop {
12742
12734
  return;
12743
12735
  }
12744
12736
  if ('payload' in data) {
12745
- this.log(`Loaded fragment ${frag.sn} of level ${frag.level}`);
12737
+ this.log(`Loaded ${frag.type} sn: ${frag.sn} of ${this.playlistLabel()} ${frag.level}`);
12746
12738
  this.hls.trigger(Events.FRAG_LOADED, data);
12747
12739
  }
12748
12740
 
@@ -12892,9 +12884,9 @@ class BaseStreamController extends TaskLoop {
12892
12884
  return !frag || !fragCurrent || frag.sn !== fragCurrent.sn || frag.level !== fragCurrent.level;
12893
12885
  }
12894
12886
  fragBufferedComplete(frag, part) {
12895
- var _frag$startPTS, _frag$endPTS, _this$fragCurrent, _this$fragPrevious;
12887
+ var _this$fragCurrent, _this$fragPrevious;
12896
12888
  const media = this.mediaBuffer ? this.mediaBuffer : this.media;
12897
- this.log(`Buffered ${frag.type} sn: ${frag.sn}${part ? ' part: ' + part.index : ''} of ${this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'} ${frag.level} (frag:[${((_frag$startPTS = frag.startPTS) != null ? _frag$startPTS : NaN).toFixed(3)}-${((_frag$endPTS = frag.endPTS) != null ? _frag$endPTS : NaN).toFixed(3)}] > buffer:${media ? TimeRanges.toString(BufferHelper.getBuffered(media)) : '(detached)'})`);
12889
+ this.log(`Buffered ${frag.type} sn: ${frag.sn}${part ? ' part: ' + part.index : ''} of ${this.fragInfo(frag)} > buffer:${media ? TimeRanges.toString(BufferHelper.getBuffered(media)) : '(detached)'})`);
12898
12890
  if (frag.sn !== 'initSegment') {
12899
12891
  var _this$levels;
12900
12892
  if (frag.type !== PlaylistLevelType.SUBTITLE) {
@@ -12951,7 +12943,7 @@ class BaseStreamController extends TaskLoop {
12951
12943
  }
12952
12944
  let keyLoadingPromise = null;
12953
12945
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
12954
- this.log(`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'} ${frag.level}`);
12946
+ this.log(`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${this.playlistLabel()} ${frag.level}`);
12955
12947
  this.state = State.KEY_LOADING;
12956
12948
  this.fragCurrent = frag;
12957
12949
  keyLoadingPromise = this.keyLoader.load(frag).then(keyLoadedData => {
@@ -12990,7 +12982,7 @@ class BaseStreamController extends TaskLoop {
12990
12982
  const partIndex = this.getNextPart(partList, frag, targetBufferTime);
12991
12983
  if (partIndex > -1) {
12992
12984
  const part = partList[partIndex];
12993
- this.log(`Loading part sn: ${frag.sn} p: ${part.index} cc: ${frag.cc} of playlist [${details.startSN}-${details.endSN}] parts [0-${partIndex}-${partList.length - 1}] ${this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'}: ${frag.level}, target: ${parseFloat(targetBufferTime.toFixed(3))}`);
12985
+ this.log(`Loading part sn: ${frag.sn} p: ${part.index} cc: ${frag.cc} of playlist [${details.startSN}-${details.endSN}] parts [0-${partIndex}-${partList.length - 1}] ${this.playlistLabel()}: ${frag.level}, target: ${parseFloat(targetBufferTime.toFixed(3))}`);
12994
12986
  this.nextLoadPosition = part.start + part.duration;
12995
12987
  this.state = State.FRAG_LOADING;
12996
12988
  let _result;
@@ -13026,7 +13018,7 @@ class BaseStreamController extends TaskLoop {
13026
13018
  // Selected fragment hint for part but not loading parts
13027
13019
  return Promise.resolve(null);
13028
13020
  }
13029
- this.log(`Loading fragment ${frag.sn} cc: ${frag.cc} ${details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : ''}${this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'}: ${frag.level}, target: ${parseFloat(targetBufferTime.toFixed(3))}`);
13021
+ this.log(`Loading ${frag.type} sn: ${frag.sn} of ${this.fragInfo(frag, false)}) cc: ${frag.cc} ${details ? '[' + details.startSN + '-' + details.endSN + ']' : ''}, target: ${parseFloat(targetBufferTime.toFixed(3))}`);
13030
13022
  // Don't update nextLoadPosition for fragments which are not buffered
13031
13023
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
13032
13024
  this.nextLoadPosition = frag.start + frag.duration;
@@ -13805,16 +13797,22 @@ class BaseStreamController extends TaskLoop {
13805
13797
  // For this error fallthrough. Marking parsed will allow advancing to next fragment.
13806
13798
  }
13807
13799
  this.state = State.PARSED;
13800
+ this.log(`Parsed ${frag.type} sn: ${frag.sn}${part ? ' part: ' + part.index : ''} of ${this.fragInfo(frag)})`);
13808
13801
  this.hls.trigger(Events.FRAG_PARSED, {
13809
13802
  frag,
13810
13803
  part
13811
13804
  });
13812
13805
  }
13806
+ playlistLabel() {
13807
+ return this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track';
13808
+ }
13809
+ fragInfo(frag, pts = true) {
13810
+ var _ref, _ref2;
13811
+ return `${this.playlistLabel()} ${frag.level} (frag:[${((_ref = pts ? frag.startPTS : frag.start) != null ? _ref : NaN).toFixed(3)}-${((_ref2 = pts ? frag.endPTS : frag.end) != null ? _ref2 : NaN).toFixed(3)}]`;
13812
+ }
13813
13813
  resetTransmuxer() {
13814
- if (this.transmuxer) {
13815
- this.transmuxer.destroy();
13816
- this.transmuxer = null;
13817
- }
13814
+ var _this$transmuxer2;
13815
+ (_this$transmuxer2 = this.transmuxer) == null ? void 0 : _this$transmuxer2.reset();
13818
13816
  }
13819
13817
  recoverWorkerError(data) {
13820
13818
  if (data.event === 'demuxerWorker') {
@@ -13863,29 +13861,66 @@ function changeTypeSupported() {
13863
13861
  return typeof (sourceBuffer == null ? void 0 : (_sourceBuffer$prototy = sourceBuffer.prototype) == null ? void 0 : _sourceBuffer$prototy.changeType) === 'function';
13864
13862
  }
13865
13863
 
13864
+ const version = "1.5.14-0.canary.10432";
13865
+
13866
13866
  // ensure the worker ends up in the bundle
13867
13867
  // If the worker should not be included this gets aliased to empty.js
13868
+ const workerStore = {};
13868
13869
  function hasUMDWorker() {
13869
13870
  return typeof __HLS_WORKER_BUNDLE__ === 'function';
13870
13871
  }
13871
13872
  function injectWorker() {
13873
+ const workerContext = workerStore[version];
13874
+ if (workerContext) {
13875
+ workerContext.clientCount++;
13876
+ return workerContext;
13877
+ }
13872
13878
  const blob = new self.Blob([`var exports={};var module={exports:exports};function define(f){f()};define.amd=true;(${__HLS_WORKER_BUNDLE__.toString()})(true);`], {
13873
13879
  type: 'text/javascript'
13874
13880
  });
13875
13881
  const objectURL = self.URL.createObjectURL(blob);
13876
13882
  const worker = new self.Worker(objectURL);
13877
- return {
13883
+ const result = {
13878
13884
  worker,
13879
- objectURL
13885
+ objectURL,
13886
+ clientCount: 1
13880
13887
  };
13888
+ workerStore[version] = result;
13889
+ return result;
13881
13890
  }
13882
13891
  function loadWorker(path) {
13892
+ const workerContext = workerStore[path];
13893
+ if (workerContext) {
13894
+ workerContext.clientCount++;
13895
+ return workerContext;
13896
+ }
13883
13897
  const scriptURL = new self.URL(path, self.location.href).href;
13884
13898
  const worker = new self.Worker(scriptURL);
13885
- return {
13899
+ const result = {
13886
13900
  worker,
13887
- scriptURL
13901
+ scriptURL,
13902
+ clientCount: 1
13888
13903
  };
13904
+ workerStore[path] = result;
13905
+ return result;
13906
+ }
13907
+ function removeWorkerFromStore(path) {
13908
+ const workerContext = workerStore[path || version];
13909
+ if (workerContext) {
13910
+ const clientCount = workerContext.clientCount--;
13911
+ if (clientCount === 1) {
13912
+ const {
13913
+ worker,
13914
+ objectURL
13915
+ } = workerContext;
13916
+ delete workerStore[path || version];
13917
+ if (objectURL) {
13918
+ // revoke the Object URL that was used to create transmuxer worker, so as not to leak it
13919
+ self.URL.revokeObjectURL(objectURL);
13920
+ }
13921
+ worker.terminate();
13922
+ }
13923
+ }
13889
13924
  }
13890
13925
 
13891
13926
  function dummyTrack(type = '', inputTimeScale = 90000) {
@@ -14562,7 +14597,7 @@ class AACDemuxer extends BaseAudioDemuxer {
14562
14597
  }
14563
14598
 
14564
14599
  // Source for probe info - https://wiki.multimedia.cx/index.php?title=ADTS
14565
- static probe(data) {
14600
+ static probe(data, logger) {
14566
14601
  if (!data) {
14567
14602
  return false;
14568
14603
  }
@@ -15482,7 +15517,8 @@ class SampleAesDecrypter {
15482
15517
 
15483
15518
  const PACKET_LENGTH = 188;
15484
15519
  class TSDemuxer {
15485
- constructor(observer, config, typeSupported) {
15520
+ constructor(observer, config, typeSupported, logger) {
15521
+ this.logger = void 0;
15486
15522
  this.observer = void 0;
15487
15523
  this.config = void 0;
15488
15524
  this.typeSupported = void 0;
@@ -15502,9 +15538,10 @@ class TSDemuxer {
15502
15538
  this.observer = observer;
15503
15539
  this.config = config;
15504
15540
  this.typeSupported = typeSupported;
15541
+ this.logger = logger;
15505
15542
  this.videoParser = null;
15506
15543
  }
15507
- static probe(data) {
15544
+ static probe(data, logger) {
15508
15545
  const syncOffset = TSDemuxer.syncOffset(data);
15509
15546
  if (syncOffset > 0) {
15510
15547
  logger.warn(`MPEG2-TS detected but first sync word found @ offset ${syncOffset}`);
@@ -15666,7 +15703,7 @@ class TSDemuxer {
15666
15703
  switch (pid) {
15667
15704
  case videoPid:
15668
15705
  if (stt) {
15669
- if (videoData && (pes = parsePES(videoData))) {
15706
+ if (videoData && (pes = parsePES(videoData, this.logger))) {
15670
15707
  if (this.videoParser === null) {
15671
15708
  switch (videoTrack.segmentCodec) {
15672
15709
  case 'avc':
@@ -15690,7 +15727,7 @@ class TSDemuxer {
15690
15727
  break;
15691
15728
  case audioPid:
15692
15729
  if (stt) {
15693
- if (audioData && (pes = parsePES(audioData))) {
15730
+ if (audioData && (pes = parsePES(audioData, this.logger))) {
15694
15731
  switch (audioTrack.segmentCodec) {
15695
15732
  case 'aac':
15696
15733
  this.parseAACPES(audioTrack, pes);
@@ -15712,7 +15749,7 @@ class TSDemuxer {
15712
15749
  break;
15713
15750
  case id3Pid:
15714
15751
  if (stt) {
15715
- if (id3Data && (pes = parsePES(id3Data))) {
15752
+ if (id3Data && (pes = parsePES(id3Data, this.logger))) {
15716
15753
  this.parseID3PES(id3Track, pes);
15717
15754
  }
15718
15755
  id3Data = {
@@ -15730,14 +15767,14 @@ class TSDemuxer {
15730
15767
  offset += data[offset] + 1;
15731
15768
  }
15732
15769
  pmtId = this._pmtId = parsePAT(data, offset);
15733
- // logger.log('PMT PID:' + this._pmtId);
15770
+ // this.logger.log('PMT PID:' + this._pmtId);
15734
15771
  break;
15735
15772
  case pmtId:
15736
15773
  {
15737
15774
  if (stt) {
15738
15775
  offset += data[offset] + 1;
15739
15776
  }
15740
- const parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes, this.observer);
15777
+ const parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes, this.observer, this.logger);
15741
15778
 
15742
15779
  // only update track id if track PID found while parsing PMT
15743
15780
  // this is to avoid resetting the PID to -1 in case
@@ -15760,7 +15797,7 @@ class TSDemuxer {
15760
15797
  id3Track.pid = id3Pid;
15761
15798
  }
15762
15799
  if (unknownPID !== null && !pmtParsed) {
15763
- logger.warn(`MPEG-TS PMT found at ${start} after unknown PID '${unknownPID}'. Backtracking to sync byte @${syncOffset} to parse all TS packets.`);
15800
+ this.logger.warn(`MPEG-TS PMT found at ${start} after unknown PID '${unknownPID}'. Backtracking to sync byte @${syncOffset} to parse all TS packets.`);
15764
15801
  unknownPID = null;
15765
15802
  // we set it to -188, the += 188 in the for loop will reset start to 0
15766
15803
  start = syncOffset - 188;
@@ -15780,7 +15817,7 @@ class TSDemuxer {
15780
15817
  }
15781
15818
  }
15782
15819
  if (tsPacketErrors > 0) {
15783
- emitParsingError(this.observer, new Error(`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`));
15820
+ emitParsingError(this.observer, new Error(`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`), undefined, this.logger);
15784
15821
  }
15785
15822
  videoTrack.pesData = videoData;
15786
15823
  audioTrack.pesData = audioData;
@@ -15830,7 +15867,7 @@ class TSDemuxer {
15830
15867
  const id3Data = id3Track.pesData;
15831
15868
  // try to parse last PES packets
15832
15869
  let pes;
15833
- if (videoData && (pes = parsePES(videoData))) {
15870
+ if (videoData && (pes = parsePES(videoData, this.logger))) {
15834
15871
  if (this.videoParser === null) {
15835
15872
  switch (videoTrack.segmentCodec) {
15836
15873
  case 'avc':
@@ -15846,7 +15883,7 @@ class TSDemuxer {
15846
15883
  // either avcData null or PES truncated, keep it for next frag parsing
15847
15884
  videoTrack.pesData = videoData;
15848
15885
  }
15849
- if (audioData && (pes = parsePES(audioData))) {
15886
+ if (audioData && (pes = parsePES(audioData, this.logger))) {
15850
15887
  switch (audioTrack.segmentCodec) {
15851
15888
  case 'aac':
15852
15889
  this.parseAACPES(audioTrack, pes);
@@ -15858,13 +15895,13 @@ class TSDemuxer {
15858
15895
  audioTrack.pesData = null;
15859
15896
  } else {
15860
15897
  if (audioData != null && audioData.size) {
15861
- logger.log('last AAC PES packet truncated,might overlap between fragments');
15898
+ this.logger.log('last AAC PES packet truncated,might overlap between fragments');
15862
15899
  }
15863
15900
 
15864
15901
  // either audioData null or PES truncated, keep it for next frag parsing
15865
15902
  audioTrack.pesData = audioData;
15866
15903
  }
15867
- if (id3Data && (pes = parsePES(id3Data))) {
15904
+ if (id3Data && (pes = parsePES(id3Data, this.logger))) {
15868
15905
  this.parseID3PES(id3Track, pes);
15869
15906
  id3Track.pesData = null;
15870
15907
  } else {
@@ -15938,7 +15975,7 @@ class TSDemuxer {
15938
15975
  } else {
15939
15976
  reason = 'No ADTS header found in AAC PES';
15940
15977
  }
15941
- emitParsingError(this.observer, new Error(reason), recoverable);
15978
+ emitParsingError(this.observer, new Error(reason), recoverable, this.logger);
15942
15979
  if (!recoverable) {
15943
15980
  return;
15944
15981
  }
@@ -15953,7 +15990,7 @@ class TSDemuxer {
15953
15990
  const frameDuration = getFrameDuration(track.samplerate);
15954
15991
  pts = aacOverFlow.sample.pts + frameDuration;
15955
15992
  } else {
15956
- logger.warn('[tsdemuxer]: AAC PES unknown PTS');
15993
+ this.logger.warn('[tsdemuxer]: AAC PES unknown PTS');
15957
15994
  return;
15958
15995
  }
15959
15996
 
@@ -15983,7 +16020,7 @@ class TSDemuxer {
15983
16020
  let offset = 0;
15984
16021
  const pts = pes.pts;
15985
16022
  if (pts === undefined) {
15986
- logger.warn('[tsdemuxer]: MPEG PES unknown PTS');
16023
+ this.logger.warn('[tsdemuxer]: MPEG PES unknown PTS');
15987
16024
  return;
15988
16025
  }
15989
16026
  while (offset < length) {
@@ -16006,7 +16043,7 @@ class TSDemuxer {
16006
16043
  }
16007
16044
  parseID3PES(id3Track, pes) {
16008
16045
  if (pes.pts === undefined) {
16009
- logger.warn('[tsdemuxer]: ID3 PES unknown PTS');
16046
+ this.logger.warn('[tsdemuxer]: ID3 PES unknown PTS');
16010
16047
  return;
16011
16048
  }
16012
16049
  const id3Sample = _extends({}, pes, {
@@ -16024,7 +16061,7 @@ function parsePAT(data, offset) {
16024
16061
  // skip the PSI header and parse the first PMT entry
16025
16062
  return (data[offset + 10] & 0x1f) << 8 | data[offset + 11];
16026
16063
  }
16027
- function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
16064
+ function parsePMT(data, offset, typeSupported, isSampleAes, observer, logger) {
16028
16065
  const result = {
16029
16066
  audioPid: -1,
16030
16067
  videoPid: -1,
@@ -16046,7 +16083,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
16046
16083
  case 0xcf:
16047
16084
  // SAMPLE-AES AAC
16048
16085
  if (!isSampleAes) {
16049
- logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC');
16086
+ logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC', this.logger);
16050
16087
  break;
16051
16088
  }
16052
16089
  /* falls through */
@@ -16068,7 +16105,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
16068
16105
  case 0xdb:
16069
16106
  // SAMPLE-AES AVC
16070
16107
  if (!isSampleAes) {
16071
- logEncryptedSamplesFoundInUnencryptedStream('H.264');
16108
+ logEncryptedSamplesFoundInUnencryptedStream('H.264', this.logger);
16072
16109
  break;
16073
16110
  }
16074
16111
  /* falls through */
@@ -16096,7 +16133,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
16096
16133
  case 0xc1:
16097
16134
  // SAMPLE-AES AC3
16098
16135
  if (!isSampleAes) {
16099
- logEncryptedSamplesFoundInUnencryptedStream('AC-3');
16136
+ logEncryptedSamplesFoundInUnencryptedStream('AC-3', this.logger);
16100
16137
  break;
16101
16138
  }
16102
16139
  /* falls through */
@@ -16132,12 +16169,12 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
16132
16169
  case 0xc2: // SAMPLE-AES EC3
16133
16170
  /* falls through */
16134
16171
  case 0x87:
16135
- emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'));
16172
+ emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'), undefined, this.logger);
16136
16173
  return result;
16137
16174
  case 0x24:
16138
16175
  // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
16139
16176
  {
16140
- emitParsingError(observer, new Error('Unsupported HEVC in M2TS found'));
16177
+ emitParsingError(observer, new Error('Unsupported HEVC in M2TS found'), undefined, this.logger);
16141
16178
  return result;
16142
16179
  }
16143
16180
  }
@@ -16147,7 +16184,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
16147
16184
  }
16148
16185
  return result;
16149
16186
  }
16150
- function emitParsingError(observer, error, levelRetry) {
16187
+ function emitParsingError(observer, error, levelRetry, logger) {
16151
16188
  logger.warn(`parsing error: ${error.message}`);
16152
16189
  observer.emit(Events.ERROR, Events.ERROR, {
16153
16190
  type: ErrorTypes.MEDIA_ERROR,
@@ -16158,10 +16195,10 @@ function emitParsingError(observer, error, levelRetry) {
16158
16195
  reason: error.message
16159
16196
  });
16160
16197
  }
16161
- function logEncryptedSamplesFoundInUnencryptedStream(type) {
16198
+ function logEncryptedSamplesFoundInUnencryptedStream(type, logger) {
16162
16199
  logger.log(`${type} with AES-128-CBC encryption found in unencrypted stream`);
16163
16200
  }
16164
- function parsePES(stream) {
16201
+ function parsePES(stream, logger) {
16165
16202
  let i = 0;
16166
16203
  let frag;
16167
16204
  let pesLen;
@@ -17046,7 +17083,8 @@ const AC3_SAMPLES_PER_FRAME = 1536;
17046
17083
  let chromeVersion = null;
17047
17084
  let safariWebkitVersion = null;
17048
17085
  class MP4Remuxer {
17049
- constructor(observer, config, typeSupported, vendor = '') {
17086
+ constructor(observer, config, typeSupported, logger) {
17087
+ this.logger = void 0;
17050
17088
  this.observer = void 0;
17051
17089
  this.config = void 0;
17052
17090
  this.typeSupported = void 0;
@@ -17062,6 +17100,7 @@ class MP4Remuxer {
17062
17100
  this.observer = observer;
17063
17101
  this.config = config;
17064
17102
  this.typeSupported = typeSupported;
17103
+ this.logger = logger;
17065
17104
  this.ISGenerated = false;
17066
17105
  if (chromeVersion === null) {
17067
17106
  const userAgent = navigator.userAgent || '';
@@ -17078,16 +17117,16 @@ class MP4Remuxer {
17078
17117
  this.config = this.videoTrackConfig = this._initPTS = this._initDTS = null;
17079
17118
  }
17080
17119
  resetTimeStamp(defaultTimeStamp) {
17081
- logger.log('[mp4-remuxer]: initPTS & initDTS reset');
17120
+ this.logger.log('[mp4-remuxer]: initPTS & initDTS reset');
17082
17121
  this._initPTS = this._initDTS = defaultTimeStamp;
17083
17122
  }
17084
17123
  resetNextTimestamp() {
17085
- logger.log('[mp4-remuxer]: reset next timestamp');
17124
+ this.logger.log('[mp4-remuxer]: reset next timestamp');
17086
17125
  this.isVideoContiguous = false;
17087
17126
  this.isAudioContiguous = false;
17088
17127
  }
17089
17128
  resetInitSegment() {
17090
- logger.log('[mp4-remuxer]: ISGenerated flag reset');
17129
+ this.logger.log('[mp4-remuxer]: ISGenerated flag reset');
17091
17130
  this.ISGenerated = false;
17092
17131
  this.videoTrackConfig = undefined;
17093
17132
  }
@@ -17106,7 +17145,7 @@ class MP4Remuxer {
17106
17145
  }
17107
17146
  }, videoSamples[0].pts);
17108
17147
  if (rolloverDetected) {
17109
- logger.debug('PTS rollover detected');
17148
+ this.logger.debug('PTS rollover detected');
17110
17149
  }
17111
17150
  return startPTS;
17112
17151
  }
@@ -17150,14 +17189,14 @@ class MP4Remuxer {
17150
17189
  if (!isVideoContiguous && this.config.forceKeyFrameOnDiscontinuity) {
17151
17190
  independent = true;
17152
17191
  if (firstKeyFrameIndex > 0) {
17153
- logger.warn(`[mp4-remuxer]: Dropped ${firstKeyFrameIndex} out of ${length} video samples due to a missing keyframe`);
17192
+ this.logger.warn(`[mp4-remuxer]: Dropped ${firstKeyFrameIndex} out of ${length} video samples due to a missing keyframe`);
17154
17193
  const startPTS = this.getVideoStartPts(videoTrack.samples);
17155
17194
  videoTrack.samples = videoTrack.samples.slice(firstKeyFrameIndex);
17156
17195
  videoTrack.dropped += firstKeyFrameIndex;
17157
17196
  videoTimeOffset += (videoTrack.samples[0].pts - startPTS) / videoTrack.inputTimeScale;
17158
17197
  firstKeyFramePTS = videoTimeOffset;
17159
17198
  } else if (firstKeyFrameIndex === -1) {
17160
- logger.warn(`[mp4-remuxer]: No keyframe found out of ${length} video samples`);
17199
+ this.logger.warn(`[mp4-remuxer]: No keyframe found out of ${length} video samples`);
17161
17200
  independent = false;
17162
17201
  }
17163
17202
  }
@@ -17179,7 +17218,7 @@ class MP4Remuxer {
17179
17218
  if (enoughAudioSamples) {
17180
17219
  // if initSegment was generated without audio samples, regenerate it again
17181
17220
  if (!audioTrack.samplerate) {
17182
- logger.warn('[mp4-remuxer]: regenerate InitSegment as audio detected');
17221
+ this.logger.warn('[mp4-remuxer]: regenerate InitSegment as audio detected');
17183
17222
  initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
17184
17223
  }
17185
17224
  audio = this.remuxAudio(audioTrack, audioTimeOffset, this.isAudioContiguous, accurateTimeOffset, hasVideo || enoughVideoSamples || playlistType === PlaylistLevelType.AUDIO ? videoTimeOffset : undefined);
@@ -17187,7 +17226,7 @@ class MP4Remuxer {
17187
17226
  const audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0;
17188
17227
  // if initSegment was generated without video samples, regenerate it again
17189
17228
  if (!videoTrack.inputTimeScale) {
17190
- logger.warn('[mp4-remuxer]: regenerate InitSegment as video detected');
17229
+ this.logger.warn('[mp4-remuxer]: regenerate InitSegment as video detected');
17191
17230
  initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
17192
17231
  }
17193
17232
  video = this.remuxVideo(videoTrack, videoTimeOffset, isVideoContiguous, audioTrackLength);
@@ -17393,9 +17432,9 @@ class MP4Remuxer {
17393
17432
  const foundOverlap = delta < -1;
17394
17433
  if (foundHole || foundOverlap) {
17395
17434
  if (foundHole) {
17396
- logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(delta, true)} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(3)}`);
17435
+ this.logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(delta, true)} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(3)}`);
17397
17436
  } else {
17398
- logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(-delta, true)} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(3)}`);
17437
+ this.logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(-delta, true)} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(3)}`);
17399
17438
  }
17400
17439
  if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
17401
17440
  firstDTS = nextAvcDts;
@@ -17424,7 +17463,7 @@ class MP4Remuxer {
17424
17463
  }
17425
17464
  }
17426
17465
  }
17427
- logger.log(`Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(firstPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
17466
+ this.logger.log(`Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(firstPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
17428
17467
  }
17429
17468
  }
17430
17469
  }
@@ -17524,7 +17563,7 @@ class MP4Remuxer {
17524
17563
  } else {
17525
17564
  stretchedLastFrame = true;
17526
17565
  }
17527
- logger.log(`[mp4-remuxer]: It is approximately ${deltaToFrameEnd / 90} ms to the next segment; using duration ${mp4SampleDuration / 90} ms for the last video frame.`);
17566
+ this.logger.log(`[mp4-remuxer]: It is approximately ${deltaToFrameEnd / 90} ms to the next segment; using duration ${mp4SampleDuration / 90} ms for the last video frame.`);
17528
17567
  } else {
17529
17568
  mp4SampleDuration = lastFrameDuration;
17530
17569
  }
@@ -17552,7 +17591,7 @@ class MP4Remuxer {
17552
17591
  // Fix for "CNN special report, with CC" in test-streams (Safari browser only)
17553
17592
  // Ignore DTS when frame durations are irregular. Safari MSE does not handle this leading to gaps.
17554
17593
  if (maxPtsDelta - minPtsDelta < maxDtsDelta - minDtsDelta && averageSampleDuration / maxDtsDelta < 0.025 && outputSamples[0].cts === 0) {
17555
- logger.warn('Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration.');
17594
+ this.logger.warn('Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration.');
17556
17595
  let dts = firstDTS;
17557
17596
  for (let i = 0, len = outputSamples.length; i < len; i++) {
17558
17597
  const nextDts = dts + outputSamples[i].duration;
@@ -17677,7 +17716,7 @@ class MP4Remuxer {
17677
17716
  // When remuxing with video, if we're overlapping by more than a duration, drop this sample to stay in sync
17678
17717
  if (delta <= -maxAudioFramesDrift * inputSampleDuration && alignedWithVideo) {
17679
17718
  if (i === 0) {
17680
- logger.warn(`Audio frame @ ${(pts / inputTimeScale).toFixed(3)}s overlaps nextAudioPts by ${Math.round(1000 * delta / inputTimeScale)} ms.`);
17719
+ this.logger.warn(`Audio frame @ ${(pts / inputTimeScale).toFixed(3)}s overlaps nextAudioPts by ${Math.round(1000 * delta / inputTimeScale)} ms.`);
17681
17720
  this.nextAudioPts = nextAudioPts = nextPts = pts;
17682
17721
  }
17683
17722
  } // eslint-disable-line brace-style
@@ -17699,12 +17738,12 @@ class MP4Remuxer {
17699
17738
  if (i === 0) {
17700
17739
  this.nextAudioPts = nextAudioPts = nextPts;
17701
17740
  }
17702
- logger.warn(`[mp4-remuxer]: Injecting ${missing} audio frame @ ${(nextPts / inputTimeScale).toFixed(3)}s due to ${Math.round(1000 * delta / inputTimeScale)} ms gap.`);
17741
+ this.logger.warn(`[mp4-remuxer]: Injecting ${missing} audio frame @ ${(nextPts / inputTimeScale).toFixed(3)}s due to ${Math.round(1000 * delta / inputTimeScale)} ms gap.`);
17703
17742
  for (let j = 0; j < missing; j++) {
17704
17743
  const newStamp = Math.max(nextPts, 0);
17705
17744
  let fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17706
17745
  if (!fillFrame) {
17707
- logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17746
+ this.logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17708
17747
  fillFrame = sample.unit.subarray();
17709
17748
  }
17710
17749
  inputSamples.splice(i, 0, {
@@ -17903,7 +17942,8 @@ class Mp4Sample {
17903
17942
  }
17904
17943
 
17905
17944
  class PassThroughRemuxer {
17906
- constructor() {
17945
+ constructor(observer, config, typeSupported, logger) {
17946
+ this.logger = void 0;
17907
17947
  this.emitInitSegment = false;
17908
17948
  this.audioCodec = void 0;
17909
17949
  this.videoCodec = void 0;
@@ -17911,6 +17951,7 @@ class PassThroughRemuxer {
17911
17951
  this.initPTS = null;
17912
17952
  this.initTracks = void 0;
17913
17953
  this.lastEndTime = null;
17954
+ this.logger = logger;
17914
17955
  }
17915
17956
  destroy() {}
17916
17957
  resetTimeStamp(defaultInitPTS) {
@@ -17968,7 +18009,7 @@ class PassThroughRemuxer {
17968
18009
  id: 'main'
17969
18010
  };
17970
18011
  } else {
17971
- logger.warn('[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes.');
18012
+ this.logger.warn('[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes.');
17972
18013
  }
17973
18014
  this.initTracks = tracks;
17974
18015
  }
@@ -18010,7 +18051,7 @@ class PassThroughRemuxer {
18010
18051
  }
18011
18052
  if (!((_initData2 = initData) != null && _initData2.length)) {
18012
18053
  // We can't remux if the initSegment could not be generated
18013
- logger.warn('[passthrough-remuxer.ts]: Failed to generate initSegment.');
18054
+ this.logger.warn('[passthrough-remuxer.ts]: Failed to generate initSegment.');
18014
18055
  return result;
18015
18056
  }
18016
18057
  if (this.emitInitSegment) {
@@ -18023,7 +18064,7 @@ class PassThroughRemuxer {
18023
18064
  if (isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) || initSegment.timescale !== initPTS.timescale && accurateTimeOffset) {
18024
18065
  initSegment.initPTS = decodeTime - timeOffset;
18025
18066
  if (initPTS && initPTS.timescale === 1) {
18026
- logger.warn(`Adjusting initPTS @${timeOffset} from ${initPTS.baseTime / initPTS.timescale} to ${initSegment.initPTS}`);
18067
+ this.logger.warn(`Adjusting initPTS @${timeOffset} from ${initPTS.baseTime / initPTS.timescale} to ${initSegment.initPTS}`);
18027
18068
  }
18028
18069
  this.initPTS = initPTS = {
18029
18070
  baseTime: initSegment.initPTS,
@@ -18036,7 +18077,7 @@ class PassThroughRemuxer {
18036
18077
  if (duration > 0) {
18037
18078
  this.lastEndTime = endTime;
18038
18079
  } else {
18039
- logger.warn('Duration parsed from mp4 should be greater than zero');
18080
+ this.logger.warn('Duration parsed from mp4 should be greater than zero');
18040
18081
  this.resetNextTimestamp();
18041
18082
  }
18042
18083
  const hasAudio = !!initData.audio;
@@ -18094,12 +18135,12 @@ function getParsedTrackCodec(track, type) {
18094
18135
  return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
18095
18136
  }
18096
18137
  const result = 'mp4a.40.5';
18097
- logger.info(`Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`);
18138
+ this.logger.info(`Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`);
18098
18139
  return result;
18099
18140
  }
18100
18141
  // Provide defaults based on codec type
18101
18142
  // This allows for some playback of some fmp4 playlists without CODECS defined in manifest
18102
- logger.warn(`Unhandled video codec "${parsedCodec}"`);
18143
+ this.logger.warn(`Unhandled video codec "${parsedCodec}"`);
18103
18144
  if (parsedCodec === 'hvc1' || parsedCodec === 'hev1') {
18104
18145
  return 'hvc1.1.6.L120.90';
18105
18146
  }
@@ -18109,16 +18150,12 @@ function getParsedTrackCodec(track, type) {
18109
18150
  return 'avc1.42e01e';
18110
18151
  }
18111
18152
 
18112
- /** returns `undefined` is `self` is missing, e.g. in node */
18113
- const optionalSelf = typeof self !== 'undefined' ? self : undefined;
18114
-
18115
18153
  let now;
18116
18154
  // performance.now() not available on WebWorker, at least on Safari Desktop
18117
18155
  try {
18118
18156
  now = self.performance.now.bind(self.performance);
18119
18157
  } catch (err) {
18120
- logger.debug('Unable to use Performance API on this environment');
18121
- now = optionalSelf == null ? void 0 : optionalSelf.Date.now;
18158
+ now = Date.now;
18122
18159
  }
18123
18160
  const muxConfig = [{
18124
18161
  demux: MP4Demuxer,
@@ -18134,8 +18171,9 @@ const muxConfig = [{
18134
18171
  remux: MP4Remuxer
18135
18172
  }];
18136
18173
  class Transmuxer {
18137
- constructor(observer, typeSupported, config, vendor, id) {
18138
- this.async = false;
18174
+ constructor(observer, typeSupported, config, vendor, id, logger) {
18175
+ this.asyncResult = false;
18176
+ this.logger = void 0;
18139
18177
  this.observer = void 0;
18140
18178
  this.typeSupported = void 0;
18141
18179
  this.config = void 0;
@@ -18153,6 +18191,7 @@ class Transmuxer {
18153
18191
  this.config = config;
18154
18192
  this.vendor = vendor;
18155
18193
  this.id = id;
18194
+ this.logger = logger;
18156
18195
  }
18157
18196
  configure(transmuxConfig) {
18158
18197
  this.transmuxConfig = transmuxConfig;
@@ -18207,6 +18246,7 @@ class Transmuxer {
18207
18246
  }
18208
18247
  uintData = new Uint8Array(decryptedData);
18209
18248
  } else {
18249
+ this.asyncResult = true;
18210
18250
  this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(decryptedData => {
18211
18251
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
18212
18252
  // the decrypted data has been transmuxed
@@ -18221,7 +18261,7 @@ class Transmuxer {
18221
18261
  if (resetMuxers) {
18222
18262
  const error = this.configureTransmuxer(uintData);
18223
18263
  if (error) {
18224
- logger.warn(`[transmuxer] ${error.message}`);
18264
+ this.logger.warn(`[transmuxer] ${error.message}`);
18225
18265
  this.observer.emit(Events.ERROR, Events.ERROR, {
18226
18266
  type: ErrorTypes.MEDIA_ERROR,
18227
18267
  details: ErrorDetails.FRAG_PARSING_ERROR,
@@ -18243,6 +18283,7 @@ class Transmuxer {
18243
18283
  this.resetContiguity();
18244
18284
  }
18245
18285
  const result = this.transmux(uintData, keyData, timeOffset, accurateTimeOffset, chunkMeta);
18286
+ this.asyncResult = isPromise(result);
18246
18287
  const currentState = this.currentTransmuxState;
18247
18288
  currentState.contiguous = true;
18248
18289
  currentState.discontinuity = false;
@@ -18261,6 +18302,7 @@ class Transmuxer {
18261
18302
  decryptionPromise
18262
18303
  } = this;
18263
18304
  if (decryptionPromise) {
18305
+ this.asyncResult = true;
18264
18306
  // Upon resolution, the decryption promise calls push() and returns its TransmuxerResult up the stack. Therefore
18265
18307
  // only flushing is required for async decryption
18266
18308
  return decryptionPromise.then(() => {
@@ -18288,10 +18330,15 @@ class Transmuxer {
18288
18330
  if (!demuxer || !remuxer) {
18289
18331
  // If probing failed, then Hls.js has been given content its not able to handle
18290
18332
  stats.executeEnd = now();
18291
- return [emptyResult(chunkMeta)];
18333
+ const emptyResults = [emptyResult(chunkMeta)];
18334
+ if (this.asyncResult) {
18335
+ return Promise.resolve(emptyResults);
18336
+ }
18337
+ return emptyResults;
18292
18338
  }
18293
18339
  const demuxResultOrPromise = demuxer.flush(timeOffset);
18294
18340
  if (isPromise(demuxResultOrPromise)) {
18341
+ this.asyncResult = true;
18295
18342
  // Decrypt final SAMPLE-AES samples
18296
18343
  return demuxResultOrPromise.then(demuxResult => {
18297
18344
  this.flushRemux(transmuxResults, demuxResult, chunkMeta);
@@ -18299,6 +18346,9 @@ class Transmuxer {
18299
18346
  });
18300
18347
  }
18301
18348
  this.flushRemux(transmuxResults, demuxResultOrPromise, chunkMeta);
18349
+ if (this.asyncResult) {
18350
+ return Promise.resolve(transmuxResults);
18351
+ }
18302
18352
  return transmuxResults;
18303
18353
  }
18304
18354
  flushRemux(transmuxResults, demuxResult, chunkMeta) {
@@ -18312,7 +18362,7 @@ class Transmuxer {
18312
18362
  accurateTimeOffset,
18313
18363
  timeOffset
18314
18364
  } = this.currentTransmuxState;
18315
- logger.log(`[transmuxer.ts]: Flushed fragment ${chunkMeta.sn}${chunkMeta.part > -1 ? ' p: ' + chunkMeta.part : ''} of level ${chunkMeta.level}`);
18365
+ this.logger.log(`[transmuxer.ts]: Flushed ${this.id} sn: ${chunkMeta.sn}${chunkMeta.part > -1 ? ' p: ' + chunkMeta.part : ''} of ${this.id === PlaylistLevelType.MAIN ? 'level' : 'track'} ${chunkMeta.level}`);
18316
18366
  const remuxResult = this.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset, true, this.id);
18317
18367
  transmuxResults.push({
18318
18368
  remuxResult,
@@ -18405,7 +18455,7 @@ class Transmuxer {
18405
18455
  let mux;
18406
18456
  for (let i = 0, len = muxConfig.length; i < len; i++) {
18407
18457
  var _muxConfig$i$demux;
18408
- if ((_muxConfig$i$demux = muxConfig[i].demux) != null && _muxConfig$i$demux.probe(data)) {
18458
+ if ((_muxConfig$i$demux = muxConfig[i].demux) != null && _muxConfig$i$demux.probe(data, this.logger)) {
18409
18459
  mux = muxConfig[i];
18410
18460
  break;
18411
18461
  }
@@ -18419,10 +18469,10 @@ class Transmuxer {
18419
18469
  const Remuxer = mux.remux;
18420
18470
  const Demuxer = mux.demux;
18421
18471
  if (!remuxer || !(remuxer instanceof Remuxer)) {
18422
- this.remuxer = new Remuxer(observer, config, typeSupported, vendor);
18472
+ this.remuxer = new Remuxer(observer, config, typeSupported, this.logger);
18423
18473
  }
18424
18474
  if (!demuxer || !(demuxer instanceof Demuxer)) {
18425
- this.demuxer = new Demuxer(observer, config, typeSupported);
18475
+ this.demuxer = new Demuxer(observer, config, typeSupported, this.logger);
18426
18476
  this.probe = Demuxer.probe;
18427
18477
  }
18428
18478
  }
@@ -18827,31 +18877,96 @@ var eventemitter3 = {exports: {}};
18827
18877
  var eventemitter3Exports = eventemitter3.exports;
18828
18878
  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
18829
18879
 
18880
+ let transmuxerInstanceCount = 0;
18830
18881
  class TransmuxerInterface {
18831
- constructor(hls, id, onTransmuxComplete, onFlush) {
18882
+ constructor(_hls, id, onTransmuxComplete, onFlush) {
18832
18883
  this.error = null;
18833
18884
  this.hls = void 0;
18834
18885
  this.id = void 0;
18886
+ this.instanceNo = transmuxerInstanceCount++;
18835
18887
  this.observer = void 0;
18836
18888
  this.frag = null;
18837
18889
  this.part = null;
18838
18890
  this.useWorker = void 0;
18839
18891
  this.workerContext = null;
18840
- this.onwmsg = void 0;
18841
18892
  this.transmuxer = null;
18842
18893
  this.onTransmuxComplete = void 0;
18843
18894
  this.onFlush = void 0;
18844
- const config = hls.config;
18845
- this.hls = hls;
18895
+ this.onWorkerMessage = event => {
18896
+ const data = event.data;
18897
+ const hls = this.hls;
18898
+ if (!hls || !(data != null && data.event) || data.instanceNo !== this.instanceNo) {
18899
+ return;
18900
+ }
18901
+ switch (data.event) {
18902
+ case 'init':
18903
+ {
18904
+ var _this$workerContext;
18905
+ const objectURL = (_this$workerContext = this.workerContext) == null ? void 0 : _this$workerContext.objectURL;
18906
+ if (objectURL) {
18907
+ // revoke the Object URL that was used to create transmuxer worker, so as not to leak it
18908
+ self.URL.revokeObjectURL(objectURL);
18909
+ }
18910
+ break;
18911
+ }
18912
+ case 'transmuxComplete':
18913
+ {
18914
+ this.handleTransmuxComplete(data.data);
18915
+ break;
18916
+ }
18917
+ case 'flush':
18918
+ {
18919
+ this.onFlush(data.data);
18920
+ break;
18921
+ }
18922
+
18923
+ // pass logs from the worker thread to the main logger
18924
+ case 'workerLog':
18925
+ {
18926
+ if (hls.logger[data.data.logType]) {
18927
+ hls.logger[data.data.logType](data.data.message);
18928
+ }
18929
+ break;
18930
+ }
18931
+ default:
18932
+ {
18933
+ data.data = data.data || {};
18934
+ data.data.frag = this.frag;
18935
+ data.data.part = this.part;
18936
+ data.data.id = this.id;
18937
+ hls.trigger(data.event, data.data);
18938
+ break;
18939
+ }
18940
+ }
18941
+ };
18942
+ this.onWorkerError = event => {
18943
+ if (!this.hls) {
18944
+ return;
18945
+ }
18946
+ const error = new Error(`${event.message} (${event.filename}:${event.lineno})`);
18947
+ this.hls.config.enableWorker = false;
18948
+ this.hls.logger.warn(`Error in "${this.id}" Web Worker, fallback to inline`);
18949
+ this.hls.trigger(Events.ERROR, {
18950
+ type: ErrorTypes.OTHER_ERROR,
18951
+ details: ErrorDetails.INTERNAL_EXCEPTION,
18952
+ fatal: false,
18953
+ event: 'demuxerWorker',
18954
+ error
18955
+ });
18956
+ };
18957
+ const config = _hls.config;
18958
+ this.hls = _hls;
18846
18959
  this.id = id;
18847
18960
  this.useWorker = !!config.enableWorker;
18848
18961
  this.onTransmuxComplete = onTransmuxComplete;
18849
18962
  this.onFlush = onFlush;
18850
18963
  const forwardMessage = (ev, data) => {
18851
18964
  data = data || {};
18852
- data.frag = this.frag;
18853
- data.id = this.id;
18965
+ data.frag = this.frag || undefined;
18854
18966
  if (ev === Events.ERROR) {
18967
+ data = data;
18968
+ data.parent = this.id;
18969
+ data.part = this.part;
18855
18970
  this.error = data.error;
18856
18971
  }
18857
18972
  this.hls.trigger(ev, data);
@@ -18863,6 +18978,7 @@ class TransmuxerInterface {
18863
18978
  this.observer.on(Events.ERROR, forwardMessage);
18864
18979
  const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
18865
18980
  if (this.useWorker && typeof Worker !== 'undefined') {
18981
+ const logger = this.hls.logger;
18866
18982
  const canCreateWorker = config.workerPath || hasUMDWorker();
18867
18983
  if (canCreateWorker) {
18868
18984
  try {
@@ -18873,61 +18989,63 @@ class TransmuxerInterface {
18873
18989
  logger.log(`injecting Web Worker for "${id}"`);
18874
18990
  this.workerContext = injectWorker();
18875
18991
  }
18876
- this.onwmsg = event => this.onWorkerMessage(event);
18877
18992
  const {
18878
18993
  worker
18879
18994
  } = this.workerContext;
18880
- worker.addEventListener('message', this.onwmsg);
18881
- worker.onerror = event => {
18882
- const error = new Error(`${event.message} (${event.filename}:${event.lineno})`);
18883
- config.enableWorker = false;
18884
- logger.warn(`Error in "${id}" Web Worker, fallback to inline`);
18885
- this.hls.trigger(Events.ERROR, {
18886
- type: ErrorTypes.OTHER_ERROR,
18887
- details: ErrorDetails.INTERNAL_EXCEPTION,
18888
- fatal: false,
18889
- event: 'demuxerWorker',
18890
- error
18891
- });
18892
- };
18995
+ worker.addEventListener('message', this.onWorkerMessage);
18996
+ worker.addEventListener('error', this.onWorkerError);
18893
18997
  worker.postMessage({
18998
+ instanceNo: this.instanceNo,
18894
18999
  cmd: 'init',
18895
19000
  typeSupported: m2tsTypeSupported,
18896
- vendor: '',
18897
- id: id,
19001
+ id,
18898
19002
  config: JSON.stringify(config)
18899
19003
  });
18900
19004
  } catch (err) {
18901
19005
  logger.warn(`Error setting up "${id}" Web Worker, fallback to inline`, err);
18902
- this.resetWorker();
19006
+ this.terminateWorker();
18903
19007
  this.error = null;
18904
- this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id);
19008
+ this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id, _hls.logger);
18905
19009
  }
18906
19010
  return;
18907
19011
  }
18908
19012
  }
18909
- this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id);
19013
+ this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id, _hls.logger);
18910
19014
  }
18911
- resetWorker() {
19015
+ reset() {
19016
+ this.frag = null;
19017
+ this.part = null;
19018
+ if (this.workerContext) {
19019
+ const instanceNo = this.instanceNo;
19020
+ this.instanceNo = transmuxerInstanceCount++;
19021
+ const config = this.hls.config;
19022
+ const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
19023
+ this.workerContext.worker.postMessage({
19024
+ instanceNo: this.instanceNo,
19025
+ cmd: 'reset',
19026
+ resetNo: instanceNo,
19027
+ typeSupported: m2tsTypeSupported,
19028
+ id: this.id,
19029
+ config: JSON.stringify(config)
19030
+ });
19031
+ }
19032
+ }
19033
+ terminateWorker() {
18912
19034
  if (this.workerContext) {
18913
19035
  const {
18914
- worker,
18915
- objectURL
19036
+ worker
18916
19037
  } = this.workerContext;
18917
- if (objectURL) {
18918
- // revoke the Object URL that was used to create transmuxer worker, so as not to leak it
18919
- self.URL.revokeObjectURL(objectURL);
18920
- }
18921
- worker.removeEventListener('message', this.onwmsg);
18922
- worker.onerror = null;
18923
- worker.terminate();
18924
19038
  this.workerContext = null;
19039
+ worker.removeEventListener('message', this.onWorkerMessage);
19040
+ worker.removeEventListener('error', this.onWorkerError);
19041
+ removeWorkerFromStore(this.hls.config.workerPath);
18925
19042
  }
18926
19043
  }
18927
19044
  destroy() {
18928
19045
  if (this.workerContext) {
18929
- this.resetWorker();
18930
- this.onwmsg = undefined;
19046
+ this.terminateWorker();
19047
+ // @ts-ignore
19048
+ this.onWorkerMessage = this.onWorkerError = null;
18931
19049
  } else {
18932
19050
  const transmuxer = this.transmuxer;
18933
19051
  if (transmuxer) {
@@ -18940,6 +19058,7 @@ class TransmuxerInterface {
18940
19058
  observer.removeAllListeners();
18941
19059
  }
18942
19060
  this.frag = null;
19061
+ this.part = null;
18943
19062
  // @ts-ignore
18944
19063
  this.observer = null;
18945
19064
  // @ts-ignore
@@ -18949,6 +19068,7 @@ class TransmuxerInterface {
18949
19068
  var _frag$initSegment, _lastFrag$initSegment;
18950
19069
  chunkMeta.transmuxing.start = self.performance.now();
18951
19070
  const {
19071
+ instanceNo,
18952
19072
  transmuxer
18953
19073
  } = this;
18954
19074
  const timeOffset = part ? part.start : frag.start;
@@ -18971,7 +19091,7 @@ class TransmuxerInterface {
18971
19091
  const initSegmentChange = !(lastFrag && ((_frag$initSegment = frag.initSegment) == null ? void 0 : _frag$initSegment.url) === ((_lastFrag$initSegment = lastFrag.initSegment) == null ? void 0 : _lastFrag$initSegment.url));
18972
19092
  const state = new TransmuxState(discontinuity, contiguous, accurateTimeOffset, trackSwitch, timeOffset, initSegmentChange);
18973
19093
  if (!contiguous || discontinuity || initSegmentChange) {
18974
- logger.log(`[transmuxer-interface, ${frag.type}]: Starting new transmux session for sn: ${chunkMeta.sn} p: ${chunkMeta.part} level: ${chunkMeta.level} id: ${chunkMeta.id}
19094
+ this.hls.logger.log(`[transmuxer-interface, ${frag.type}]: Starting new transmux session for sn: ${chunkMeta.sn} p: ${chunkMeta.part} level: ${chunkMeta.level} id: ${chunkMeta.id}
18975
19095
  discontinuity: ${discontinuity}
18976
19096
  trackSwitch: ${trackSwitch}
18977
19097
  contiguous: ${contiguous}
@@ -18988,6 +19108,7 @@ class TransmuxerInterface {
18988
19108
  if (this.workerContext) {
18989
19109
  // post fragment payload as transferable objects for ArrayBuffer (no copy)
18990
19110
  this.workerContext.worker.postMessage({
19111
+ instanceNo,
18991
19112
  cmd: 'demux',
18992
19113
  data,
18993
19114
  decryptdata,
@@ -18997,14 +19118,12 @@ class TransmuxerInterface {
18997
19118
  } else if (transmuxer) {
18998
19119
  const transmuxResult = transmuxer.push(data, decryptdata, chunkMeta, state);
18999
19120
  if (isPromise(transmuxResult)) {
19000
- transmuxer.async = true;
19001
19121
  transmuxResult.then(data => {
19002
19122
  this.handleTransmuxComplete(data);
19003
19123
  }).catch(error => {
19004
19124
  this.transmuxerError(error, chunkMeta, 'transmuxer-interface push error');
19005
19125
  });
19006
19126
  } else {
19007
- transmuxer.async = false;
19008
19127
  this.handleTransmuxComplete(transmuxResult);
19009
19128
  }
19010
19129
  }
@@ -19012,20 +19131,18 @@ class TransmuxerInterface {
19012
19131
  flush(chunkMeta) {
19013
19132
  chunkMeta.transmuxing.start = self.performance.now();
19014
19133
  const {
19134
+ instanceNo,
19015
19135
  transmuxer
19016
19136
  } = this;
19017
19137
  if (this.workerContext) {
19018
19138
  this.workerContext.worker.postMessage({
19139
+ instanceNo,
19019
19140
  cmd: 'flush',
19020
19141
  chunkMeta
19021
19142
  });
19022
19143
  } else if (transmuxer) {
19023
- let transmuxResult = transmuxer.flush(chunkMeta);
19024
- const asyncFlush = isPromise(transmuxResult);
19025
- if (asyncFlush || transmuxer.async) {
19026
- if (!isPromise(transmuxResult)) {
19027
- transmuxResult = Promise.resolve(transmuxResult);
19028
- }
19144
+ const transmuxResult = transmuxer.flush(chunkMeta);
19145
+ if (isPromise(transmuxResult)) {
19029
19146
  transmuxResult.then(data => {
19030
19147
  this.handleFlushResult(data, chunkMeta);
19031
19148
  }).catch(error => {
@@ -19046,6 +19163,7 @@ class TransmuxerInterface {
19046
19163
  details: ErrorDetails.FRAG_PARSING_ERROR,
19047
19164
  chunkMeta,
19048
19165
  frag: this.frag || undefined,
19166
+ part: this.part || undefined,
19049
19167
  fatal: false,
19050
19168
  error,
19051
19169
  err: error,
@@ -19058,60 +19176,14 @@ class TransmuxerInterface {
19058
19176
  });
19059
19177
  this.onFlush(chunkMeta);
19060
19178
  }
19061
- onWorkerMessage(event) {
19062
- const data = event.data;
19063
- if (!(data != null && data.event)) {
19064
- logger.warn(`worker message received with no ${data ? 'event name' : 'data'}`);
19065
- return;
19066
- }
19067
- const hls = this.hls;
19068
- if (!this.hls) {
19069
- return;
19070
- }
19071
- switch (data.event) {
19072
- case 'init':
19073
- {
19074
- var _this$workerContext;
19075
- const objectURL = (_this$workerContext = this.workerContext) == null ? void 0 : _this$workerContext.objectURL;
19076
- if (objectURL) {
19077
- // revoke the Object URL that was used to create transmuxer worker, so as not to leak it
19078
- self.URL.revokeObjectURL(objectURL);
19079
- }
19080
- break;
19081
- }
19082
- case 'transmuxComplete':
19083
- {
19084
- this.handleTransmuxComplete(data.data);
19085
- break;
19086
- }
19087
- case 'flush':
19088
- {
19089
- this.onFlush(data.data);
19090
- break;
19091
- }
19092
-
19093
- // pass logs from the worker thread to the main logger
19094
- case 'workerLog':
19095
- if (logger[data.data.logType]) {
19096
- logger[data.data.logType](data.data.message);
19097
- }
19098
- break;
19099
- default:
19100
- {
19101
- data.data = data.data || {};
19102
- data.data.frag = this.frag;
19103
- data.data.id = this.id;
19104
- hls.trigger(data.event, data.data);
19105
- break;
19106
- }
19107
- }
19108
- }
19109
19179
  configureTransmuxer(config) {
19110
19180
  const {
19181
+ instanceNo,
19111
19182
  transmuxer
19112
19183
  } = this;
19113
19184
  if (this.workerContext) {
19114
19185
  this.workerContext.worker.postMessage({
19186
+ instanceNo,
19115
19187
  cmd: 'configure',
19116
19188
  config
19117
19189
  });
@@ -20640,7 +20712,7 @@ class Hls {
20640
20712
  * Get the video-dev/hls.js package version.
20641
20713
  */
20642
20714
  static get version() {
20643
- return "1.5.14-0.canary.10429";
20715
+ return version;
20644
20716
  }
20645
20717
 
20646
20718
  /**