hls.js 1.6.14 → 1.6.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/dist/hls.d.mts CHANGED
@@ -1496,6 +1496,7 @@ export declare class FragmentTracker implements ComponentAPI {
1496
1496
  * Partially loaded fragments will be registered as a partial fragment
1497
1497
  */
1498
1498
  detectPartialFragments(data: FragBufferedData): void;
1499
+ private bufferedEnd;
1499
1500
  private removeParts;
1500
1501
  fragBuffered(frag: MediaFragment, force?: true): void;
1501
1502
  private getBufferedTimes;
@@ -2490,6 +2491,7 @@ export declare class InterstitialsController extends Logger implements NetworkCo
2490
2491
  private createAsset;
2491
2492
  private createAssetPlayer;
2492
2493
  private clearInterstitial;
2494
+ private clearAssetPlayers;
2493
2495
  private resetAssetPlayer;
2494
2496
  private clearAssetPlayer;
2495
2497
  private emptyPlayerQueue;
@@ -2760,6 +2762,7 @@ export declare class LevelKey implements DecryptData {
2760
2762
  pssh: Uint8Array<ArrayBuffer> | null;
2761
2763
  static clearKeyUriToKeyIdMap(): void;
2762
2764
  static setKeyIdForUri(uri: string, keyId: Uint8Array<ArrayBuffer>): void;
2765
+ static addKeyIdForUri(uri: string): Uint8Array<ArrayBuffer>;
2763
2766
  constructor(method: string, uri: string, format: string, formatversions?: number[], iv?: Uint8Array<ArrayBuffer> | null, keyId?: string);
2764
2767
  matches(key: LevelKey): boolean;
2765
2768
  isSupported(): boolean;
package/dist/hls.d.ts CHANGED
@@ -1496,6 +1496,7 @@ export declare class FragmentTracker implements ComponentAPI {
1496
1496
  * Partially loaded fragments will be registered as a partial fragment
1497
1497
  */
1498
1498
  detectPartialFragments(data: FragBufferedData): void;
1499
+ private bufferedEnd;
1499
1500
  private removeParts;
1500
1501
  fragBuffered(frag: MediaFragment, force?: true): void;
1501
1502
  private getBufferedTimes;
@@ -2490,6 +2491,7 @@ export declare class InterstitialsController extends Logger implements NetworkCo
2490
2491
  private createAsset;
2491
2492
  private createAssetPlayer;
2492
2493
  private clearInterstitial;
2494
+ private clearAssetPlayers;
2493
2495
  private resetAssetPlayer;
2494
2496
  private clearAssetPlayer;
2495
2497
  private emptyPlayerQueue;
@@ -2760,6 +2762,7 @@ export declare class LevelKey implements DecryptData {
2760
2762
  pssh: Uint8Array<ArrayBuffer> | null;
2761
2763
  static clearKeyUriToKeyIdMap(): void;
2762
2764
  static setKeyIdForUri(uri: string, keyId: Uint8Array<ArrayBuffer>): void;
2765
+ static addKeyIdForUri(uri: string): Uint8Array<ArrayBuffer>;
2763
2766
  constructor(method: string, uri: string, format: string, formatversions?: number[], iv?: Uint8Array<ArrayBuffer> | null, keyId?: string);
2764
2767
  matches(key: LevelKey): boolean;
2765
2768
  isSupported(): boolean;
package/dist/hls.js CHANGED
@@ -1165,7 +1165,7 @@
1165
1165
  // Some browsers don't allow to use bind on console object anyway
1166
1166
  // fallback to default if needed
1167
1167
  try {
1168
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.14");
1168
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.15");
1169
1169
  } catch (e) {
1170
1170
  /* log fn threw an exception. All logger methods are no-ops. */
1171
1171
  return createLogger();
@@ -5583,11 +5583,7 @@
5583
5583
  });
5584
5584
  fragmentEntity.loaded = null;
5585
5585
  if (Object.keys(fragmentEntity.range).length) {
5586
- fragmentEntity.buffered = true;
5587
- var endList = fragmentEntity.body.endList = frag.endList || fragmentEntity.body.endList;
5588
- if (endList) {
5589
- this.endListFragments[fragmentEntity.body.type] = fragmentEntity;
5590
- }
5586
+ this.bufferedEnd(fragmentEntity, frag);
5591
5587
  if (!isPartial(fragmentEntity)) {
5592
5588
  // Remove older fragment parts from lookup after frag is tracked as buffered
5593
5589
  this.removeParts(frag.sn - 1, frag.type);
@@ -5597,6 +5593,13 @@
5597
5593
  this.removeFragment(fragmentEntity.body);
5598
5594
  }
5599
5595
  };
5596
+ _proto.bufferedEnd = function bufferedEnd(fragmentEntity, frag) {
5597
+ fragmentEntity.buffered = true;
5598
+ var endList = fragmentEntity.body.endList = frag.endList || fragmentEntity.body.endList;
5599
+ if (endList) {
5600
+ this.endListFragments[fragmentEntity.body.type] = fragmentEntity;
5601
+ }
5602
+ };
5600
5603
  _proto.removeParts = function removeParts(snToKeep, levelType) {
5601
5604
  var activeParts = this.activePartLists[levelType];
5602
5605
  if (!activeParts) {
@@ -5623,7 +5626,7 @@
5623
5626
  }
5624
5627
  if (fragmentEntity) {
5625
5628
  fragmentEntity.loaded = null;
5626
- fragmentEntity.buffered = true;
5629
+ this.bufferedEnd(fragmentEntity, frag);
5627
5630
  }
5628
5631
  };
5629
5632
  _proto.getBufferedTimes = function getBufferedTimes(fragment, part, partial, timeRange) {
@@ -7810,6 +7813,14 @@
7810
7813
  LevelKey.setKeyIdForUri = function setKeyIdForUri(uri, keyId) {
7811
7814
  keyUriToKeyIdMap[uri] = keyId;
7812
7815
  };
7816
+ LevelKey.addKeyIdForUri = function addKeyIdForUri(uri) {
7817
+ var val = Object.keys(keyUriToKeyIdMap).length % Number.MAX_SAFE_INTEGER;
7818
+ var keyId = new Uint8Array(16);
7819
+ var dv = new DataView(keyId.buffer, 12, 4); // Just set the last 4 bytes
7820
+ dv.setUint32(0, val);
7821
+ keyUriToKeyIdMap[uri] = keyId;
7822
+ return keyId;
7823
+ };
7813
7824
  var _proto = LevelKey.prototype;
7814
7825
  _proto.matches = function matches(key) {
7815
7826
  return key.uri === this.uri && key.method === this.method && key.encrypted === this.encrypted && key.keyFormat === this.keyFormat && arrayValuesMatch(key.keyFormatVersions, this.keyFormatVersions) && optionalArrayValuesMatch(key.iv, this.iv) && optionalArrayValuesMatch(key.keyId, this.keyId);
@@ -9950,7 +9961,7 @@
9950
9961
  this.state = State.FRAG_LOADING;
9951
9962
 
9952
9963
  // Load key before streaming fragment data
9953
- var dataOnProgress = this.config.progressive;
9964
+ var dataOnProgress = this.config.progressive && frag.type !== PlaylistLevelType.SUBTITLE;
9954
9965
  var result;
9955
9966
  if (dataOnProgress && keyLoadingPromise) {
9956
9967
  result = keyLoadingPromise.then(function (keyLoadedData) {
@@ -10776,11 +10787,12 @@
10776
10787
  }, false);
10777
10788
  if (!parsed) {
10778
10789
  var _this$transmuxer;
10779
- if (level.fragmentError === 0) {
10780
- // Mark and track the odd empty segment as a gap to avoid reloading
10790
+ var mediaNotFound = ((_this$transmuxer = this.transmuxer) == null ? void 0 : _this$transmuxer.error) === null;
10791
+ if (level.fragmentError === 0 || mediaNotFound && (level.fragmentError < 2 || frag.endList)) {
10792
+ // Mark and track the odd (or last) empty segment as a gap to avoid reloading
10781
10793
  this.treatAsGap(frag, level);
10782
10794
  }
10783
- if (((_this$transmuxer = this.transmuxer) == null ? void 0 : _this$transmuxer.error) === null) {
10795
+ if (mediaNotFound) {
10784
10796
  var error = new Error("Found no media in fragment " + frag.sn + " of " + this.playlistLabel() + " " + frag.level + " resetting transmuxer to fallback to playlist timing");
10785
10797
  this.warn(error.message);
10786
10798
  this.hls.trigger(Events.ERROR, {
@@ -16140,7 +16152,7 @@
16140
16152
  // Clear the track samples. This also clears the samples array in the demuxer, since the reference is shared
16141
16153
  track.samples = [];
16142
16154
  var start = (firstPTS - initTime) / inputTimeScale;
16143
- var end = nextAudioTs / inputTimeScale;
16155
+ var end = this.nextAudioTs / inputTimeScale;
16144
16156
  var type = 'audio';
16145
16157
  var audioData = {
16146
16158
  data1: moof,
@@ -17046,7 +17058,7 @@
17046
17058
  return !remuxResult.audio && !remuxResult.video && !remuxResult.text && !remuxResult.id3 && !remuxResult.initSegment;
17047
17059
  }
17048
17060
 
17049
- var version = "1.6.14";
17061
+ var version = "1.6.15";
17050
17062
 
17051
17063
  // ensure the worker ends up in the bundle
17052
17064
  // If the worker should not be included this gets aliased to empty.js
@@ -23626,6 +23638,11 @@
23626
23638
  }
23627
23639
  var keyIdArray = 'buffer' in keyId ? new Uint8Array(keyId.buffer, keyId.byteOffset, keyId.byteLength) : new Uint8Array(keyId);
23628
23640
  if (mediaKeySessionContext.keySystem === KeySystems.PLAYREADY && keyIdArray.length === 16) {
23641
+ // On some devices, the key ID has already been converted for endianness.
23642
+ // In such cases, this key ID is the one we need to cache.
23643
+ var originKeyIdWithStatusChange = arrayToHex(keyIdArray);
23644
+ // Cache the original key IDs to ensure compatibility across all cases.
23645
+ keyStatuses[originKeyIdWithStatusChange] = status;
23629
23646
  changeEndianness(keyIdArray);
23630
23647
  }
23631
23648
  var keyIdWithStatusChange = arrayToHex(keyIdArray);
@@ -25458,7 +25475,8 @@
25458
25475
  if (backwardSeek && currentTime < start || currentTime >= start + duration) {
25459
25476
  var _playingItem$event;
25460
25477
  if ((_playingItem$event = playingItem.event) != null && _playingItem$event.appendInPlace) {
25461
- _this.clearInterstitial(playingItem.event, playingItem);
25478
+ // Return SourceBuffer(s) to primary player and flush
25479
+ _this.clearAssetPlayers(playingItem.event, playingItem);
25462
25480
  _this.flushFrontBuffer(currentTime);
25463
25481
  }
25464
25482
  _this.setScheduleToAssetAtTime(currentTime, playingAsset);
@@ -26852,12 +26870,15 @@
26852
26870
  return player;
26853
26871
  };
26854
26872
  _proto.clearInterstitial = function clearInterstitial(interstitial, toSegment) {
26873
+ this.clearAssetPlayers(interstitial, toSegment);
26874
+ // Remove asset list and resolved duration
26875
+ interstitial.reset();
26876
+ };
26877
+ _proto.clearAssetPlayers = function clearAssetPlayers(interstitial, toSegment) {
26855
26878
  var _this9 = this;
26856
26879
  interstitial.assetList.forEach(function (asset) {
26857
26880
  _this9.clearAssetPlayer(asset.identifier, toSegment);
26858
26881
  });
26859
- // Remove asset list and resolved duration
26860
- interstitial.reset();
26861
26882
  };
26862
26883
  _proto.resetAssetPlayer = function resetAssetPlayer(assetId) {
26863
26884
  // Reset asset player so that it's timeline can be adjusted without reloading the MVP
@@ -27047,10 +27068,10 @@
27047
27068
  // Fallback to Primary by on current or future events by updating schedule to skip errored interstitials/assets
27048
27069
  var flushStart = interstitial.timelineStart;
27049
27070
  var playingItem = this.effectivePlayingItem;
27071
+ var timelinePos = this.timelinePos;
27050
27072
  // Update schedule now that interstitial/assets are flagged with `error` for fallback
27051
27073
  if (playingItem) {
27052
- this.log("Fallback to primary from event \"" + interstitial.identifier + "\" start: " + flushStart + " pos: " + this.timelinePos + " playing: " + segmentToString(playingItem) + " error: " + interstitial.error);
27053
- var timelinePos = this.timelinePos;
27074
+ this.log("Fallback to primary from event \"" + interstitial.identifier + "\" start: " + flushStart + " pos: " + timelinePos + " playing: " + segmentToString(playingItem) + " error: " + interstitial.error);
27054
27075
  if (timelinePos === -1) {
27055
27076
  timelinePos = this.hls.startPosition;
27056
27077
  }
@@ -27062,14 +27083,15 @@
27062
27083
  this.attachPrimary(flushStart, null);
27063
27084
  this.flushFrontBuffer(flushStart);
27064
27085
  }
27065
- if (!this.schedule) {
27066
- return;
27067
- }
27068
- var scheduleIndex = this.schedule.findItemIndexAtTime(timelinePos);
27069
- this.setSchedulePosition(scheduleIndex);
27070
- } else {
27086
+ } else if (timelinePos === -1) {
27071
27087
  this.checkStart();
27088
+ return;
27072
27089
  }
27090
+ if (!this.schedule) {
27091
+ return;
27092
+ }
27093
+ var scheduleIndex = this.schedule.findItemIndexAtTime(timelinePos);
27094
+ this.setSchedulePosition(scheduleIndex);
27073
27095
  }
27074
27096
 
27075
27097
  // Asset List loading
@@ -27113,7 +27135,8 @@
27113
27135
  // Abandon if new duration is reduced enough to land playback in primary start
27114
27136
  var index = this.schedule.findItemIndexAtTime(this.timelinePos);
27115
27137
  if (index !== scheduleIndex) {
27116
- interstitial.error = new Error("Interstitial no longer within playback range " + this.timelinePos + " " + interstitial);
27138
+ interstitial.error = new Error("Interstitial " + (assets.length ? 'no longer within playback range' : 'asset-list is empty') + " " + this.timelinePos + " " + interstitial);
27139
+ this.log(interstitial.error.message);
27117
27140
  this.updateSchedule(true);
27118
27141
  this.primaryFallback(interstitial);
27119
27142
  return;
@@ -34941,7 +34964,7 @@
34941
34964
  var _this2 = this;
34942
34965
  var hls = this.hls;
34943
34966
  // if any URL found on new audio track, it is an alternate audio track
34944
- var fromAltAudio = this.altAudio === 2;
34967
+ var fromAltAudio = this.altAudio !== 0;
34945
34968
  var altAudio = useAlternateAudio(data.url, hls);
34946
34969
  // if we switch on main audio, ensure that main fragment scheduling is synced with media.buffered
34947
34970
  // don't do anything if we switch to alt audio: audio stream controller is handling it.
@@ -34967,6 +34990,7 @@
34967
34990
  }
34968
34991
  // If switching from alt to main audio, flush all audio and trigger track switched
34969
34992
  if (fromAltAudio) {
34993
+ this.altAudio = 0;
34970
34994
  this.fragmentTracker.removeAllFragments();
34971
34995
  hls.once(Events.BUFFER_FLUSHED, function () {
34972
34996
  if (!_this2.hls) {
@@ -35817,11 +35841,19 @@
35817
35841
  return b !== 0;
35818
35842
  })) {
35819
35843
  this.log("Using keyId found in init segment " + arrayToHex(keyId));
35820
- keyInfo.decryptdata.keyId = keyId;
35821
35844
  LevelKey.setKeyIdForUri(keyInfo.decryptdata.uri, keyId);
35845
+ } else {
35846
+ keyId = LevelKey.addKeyIdForUri(keyInfo.decryptdata.uri);
35847
+ this.log("Generating keyId to patch media " + arrayToHex(keyId));
35822
35848
  }
35849
+ keyInfo.decryptdata.keyId = keyId;
35823
35850
  }
35824
35851
  }
35852
+ if (!keyInfo.decryptdata.keyId && !isMediaFragment(frag)) {
35853
+ // Resolve so that unencrypted init segment is loaded
35854
+ // key id is extracted from tenc box when processing key for next segment above
35855
+ return Promise.resolve(keyLoadedData);
35856
+ }
35825
35857
  var keySessionContextPromise = this.emeController.loadKey(keyLoadedData);
35826
35858
  return (keyInfo.keyLoadPromise = keySessionContextPromise.then(function (keySessionContext) {
35827
35859
  keyInfo.mediaKeySessionContext = keySessionContext;
package/dist/hls.js.d.ts CHANGED
@@ -1496,6 +1496,7 @@ export declare class FragmentTracker implements ComponentAPI {
1496
1496
  * Partially loaded fragments will be registered as a partial fragment
1497
1497
  */
1498
1498
  detectPartialFragments(data: FragBufferedData): void;
1499
+ private bufferedEnd;
1499
1500
  private removeParts;
1500
1501
  fragBuffered(frag: MediaFragment, force?: true): void;
1501
1502
  private getBufferedTimes;
@@ -2490,6 +2491,7 @@ export declare class InterstitialsController extends Logger implements NetworkCo
2490
2491
  private createAsset;
2491
2492
  private createAssetPlayer;
2492
2493
  private clearInterstitial;
2494
+ private clearAssetPlayers;
2493
2495
  private resetAssetPlayer;
2494
2496
  private clearAssetPlayer;
2495
2497
  private emptyPlayerQueue;
@@ -2760,6 +2762,7 @@ export declare class LevelKey implements DecryptData {
2760
2762
  pssh: Uint8Array<ArrayBuffer> | null;
2761
2763
  static clearKeyUriToKeyIdMap(): void;
2762
2764
  static setKeyIdForUri(uri: string, keyId: Uint8Array<ArrayBuffer>): void;
2765
+ static addKeyIdForUri(uri: string): Uint8Array<ArrayBuffer>;
2763
2766
  constructor(method: string, uri: string, format: string, formatversions?: number[], iv?: Uint8Array<ArrayBuffer> | null, keyId?: string);
2764
2767
  matches(key: LevelKey): boolean;
2765
2768
  isSupported(): boolean;