hls.js 1.5.5-0.canary.9985 → 1.5.5-0.canary.9986

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.
@@ -101,6 +101,7 @@ export default class BaseStreamController
101
101
  protected decrypter: Decrypter;
102
102
  protected initPTS: RationalTimestamp[] = [];
103
103
  protected buffering: boolean = true;
104
+ private loadingParts: boolean = false;
104
105
 
105
106
  constructor(
106
107
  hls: Hls,
@@ -304,6 +305,21 @@ export default class BaseStreamController
304
305
  );
305
306
 
306
307
  this.lastCurrentTime = currentTime;
308
+ if (!this.loadingParts) {
309
+ const bufferEnd = Math.max(bufferInfo.end, currentTime);
310
+ const shouldLoadParts = this.shouldLoadParts(
311
+ this.getLevelDetails(),
312
+ bufferEnd,
313
+ );
314
+ if (shouldLoadParts) {
315
+ this.log(
316
+ `LL-Part loading ON after seeking to ${currentTime.toFixed(
317
+ 2,
318
+ )} with buffer @${bufferEnd.toFixed(2)}`,
319
+ );
320
+ this.loadingParts = shouldLoadParts;
321
+ }
322
+ }
307
323
  }
308
324
 
309
325
  // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
@@ -700,8 +716,23 @@ export default class BaseStreamController
700
716
  this.keyLoader.loadClear(frag, details.encryptedFragments);
701
717
  }
702
718
 
719
+ const fragPrevious = this.fragPrevious;
720
+ if (
721
+ frag.sn !== 'initSegment' &&
722
+ (!fragPrevious || frag.sn !== fragPrevious.sn)
723
+ ) {
724
+ const shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
725
+ if (shouldLoadParts !== this.loadingParts) {
726
+ this.log(
727
+ `LL-Part loading ${
728
+ shouldLoadParts ? 'ON' : 'OFF'
729
+ } loading sn ${fragPrevious?.sn}->${frag.sn}`,
730
+ );
731
+ this.loadingParts = shouldLoadParts;
732
+ }
733
+ }
703
734
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
704
- if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
735
+ if (this.loadingParts && frag.sn !== 'initSegment') {
705
736
  const partList = details.partList;
706
737
  if (partList && progressCallback) {
707
738
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -772,6 +803,18 @@ export default class BaseStreamController
772
803
  }
773
804
  }
774
805
 
806
+ if (frag.sn !== 'initSegment' && this.loadingParts) {
807
+ this.log(
808
+ `LL-Part loading OFF after next part miss @${targetBufferTime.toFixed(
809
+ 2,
810
+ )}`,
811
+ );
812
+ this.loadingParts = false;
813
+ } else if (!frag.url) {
814
+ // Selected fragment hint for part but not loading parts
815
+ return Promise.resolve(null);
816
+ }
817
+
775
818
  this.log(
776
819
  `Loading fragment ${frag.sn} cc: ${frag.cc} ${
777
820
  details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : ''
@@ -899,9 +942,50 @@ export default class BaseStreamController
899
942
  if (part) {
900
943
  part.stats.parsing.end = now;
901
944
  }
945
+ // See if part loading should be disabled/enabled based on buffer and playback position.
946
+ if (frag.sn !== 'initSegment') {
947
+ const levelDetails = this.getLevelDetails();
948
+ const loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
949
+ const shouldLoadParts =
950
+ loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
951
+ if (shouldLoadParts !== this.loadingParts) {
952
+ this.log(
953
+ `LL-Part loading ${
954
+ shouldLoadParts ? 'ON' : 'OFF'
955
+ } after parsing segment ending @${frag.end.toFixed(2)}`,
956
+ );
957
+ this.loadingParts = shouldLoadParts;
958
+ }
959
+ }
960
+
902
961
  this.updateLevelTiming(frag, part, level, chunkMeta.partial);
903
962
  }
904
963
 
964
+ private shouldLoadParts(
965
+ details: LevelDetails | undefined,
966
+ bufferEnd: number,
967
+ ): boolean {
968
+ if (this.config.lowLatencyMode) {
969
+ if (!details) {
970
+ return this.loadingParts;
971
+ }
972
+ if (details?.partList) {
973
+ // Buffer must be ahead of first part + duration of parts after last segment
974
+ // and playback must be at or past segment adjacent to part list
975
+ const firstPart = details.partList[0];
976
+ const safePartStart =
977
+ firstPart.end + (details.fragmentHint?.duration || 0);
978
+ if (
979
+ bufferEnd >= safePartStart &&
980
+ this.lastCurrentTime > firstPart.start - firstPart.fragment.duration
981
+ ) {
982
+ return true;
983
+ }
984
+ }
985
+ }
986
+ return false;
987
+ }
988
+
905
989
  protected getCurrentContext(
906
990
  chunkMeta: ChunkMetadata,
907
991
  ): { frag: Fragment; part: Part | null; level: Level } | null {
@@ -1083,7 +1167,8 @@ export default class BaseStreamController
1083
1167
  // find fragment index, contiguous with end of buffer position
1084
1168
  const { config } = this;
1085
1169
  const start = fragments[0].start;
1086
- let frag;
1170
+ const canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
1171
+ let frag: Fragment | null = null;
1087
1172
 
1088
1173
  if (levelDetails.live) {
1089
1174
  const initialLiveManifestSize = config.initialLiveManifestSize;
@@ -1103,6 +1188,10 @@ export default class BaseStreamController
1103
1188
  this.startPosition === -1) ||
1104
1189
  pos < start
1105
1190
  ) {
1191
+ if (canLoadParts && !this.loadingParts) {
1192
+ this.log(`LL-Part loading ON for initial live fragment`);
1193
+ this.loadingParts = true;
1194
+ }
1106
1195
  frag = this.getInitialLiveFragment(levelDetails, fragments);
1107
1196
  this.startPosition = this.nextLoadPosition = frag
1108
1197
  ? this.hls.liveSyncPosition || frag.start
@@ -1115,7 +1204,7 @@ export default class BaseStreamController
1115
1204
 
1116
1205
  // If we haven't run into any special cases already, just load the fragment most closely matching the requested position
1117
1206
  if (!frag) {
1118
- const end = config.lowLatencyMode
1207
+ const end = this.loadingParts
1119
1208
  ? levelDetails.partEnd
1120
1209
  : levelDetails.fragmentEnd;
1121
1210
  frag = this.getFragmentAtPosition(pos, end, levelDetails);
@@ -1298,7 +1387,7 @@ export default class BaseStreamController
1298
1387
  const partList = levelDetails.partList;
1299
1388
 
1300
1389
  const loadingParts = !!(
1301
- config.lowLatencyMode &&
1390
+ this.loadingParts &&
1302
1391
  partList?.length &&
1303
1392
  fragmentHint
1304
1393
  );