hls.js 1.6.3-0.canary.11252 → 1.6.3-0.canary.11254

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.
@@ -1,5 +1,5 @@
1
1
  import BaseStreamController, { State } from './base-stream-controller';
2
- import { findFragWithCC, findNearestWithCC } from './fragment-finders';
2
+ import { findNearestWithCC } from './fragment-finders';
3
3
  import { FragmentState } from './fragment-tracker';
4
4
  import ChunkCache from '../demux/chunk-cache';
5
5
  import TransmuxerInterface from '../demux/transmuxer-interface';
@@ -161,32 +161,56 @@ class AudioStreamController
161
161
  (!waitingData && !this.loadingParts) ||
162
162
  (waitingData && waitingData.frag.cc !== cc)
163
163
  ) {
164
- this.nextLoadPosition = this.findSyncFrag(frag).start;
164
+ this.syncWithAnchor(frag, waitingData?.frag);
165
165
  }
166
- this.tick();
167
166
  } else if (
168
167
  !this.hls.hasEnoughToStart &&
169
168
  inFlightFrag &&
170
169
  inFlightFrag.cc !== cc
171
170
  ) {
172
- this.startFragRequested = false;
173
- this.nextLoadPosition = this.findSyncFrag(frag).start;
174
171
  inFlightFrag.abortRequests();
175
- this.resetLoadingState();
172
+ this.syncWithAnchor(frag, inFlightFrag);
176
173
  } else if (this.state === State.IDLE) {
177
174
  this.tick();
178
175
  }
179
176
  }
180
177
  }
181
178
 
182
- private findSyncFrag(mainFrag: MediaFragment): MediaFragment {
179
+ protected getLoadPosition(): number {
180
+ if (!this.startFragRequested && this.nextLoadPosition >= 0) {
181
+ return this.nextLoadPosition;
182
+ }
183
+ return super.getLoadPosition();
184
+ }
185
+
186
+ private syncWithAnchor(
187
+ mainAnchor: MediaFragment,
188
+ waitingToAppend: Fragment | undefined,
189
+ ) {
190
+ // Drop waiting fragment if videoTrackCC has changed since waitingFragment was set and initPTS was not found
191
+ const mainFragLoading = this.mainFragLoading?.frag || null;
192
+ if (waitingToAppend) {
193
+ if (mainFragLoading?.cc === waitingToAppend.cc) {
194
+ // Wait for loading frag to complete and INIT_PTS_FOUND
195
+ return;
196
+ }
197
+ }
198
+ const targetDiscontinuity = (mainFragLoading || mainAnchor).cc;
183
199
  const trackDetails = this.getLevelDetails();
184
- const cc = mainFrag.cc;
185
- return (
186
- findNearestWithCC(trackDetails, cc, mainFrag) ||
187
- (trackDetails && findFragWithCC(trackDetails.fragments, cc)) ||
188
- mainFrag
189
- );
200
+ const pos = this.getLoadPosition();
201
+ const syncFrag = findNearestWithCC(trackDetails, targetDiscontinuity, pos);
202
+ // Only stop waiting for audioFrag.cc if an audio segment of the same discontinuity domain (cc) is found
203
+ if (syncFrag) {
204
+ this.log(
205
+ `Waiting fragment cc (${waitingToAppend?.cc}) cancelled because video is at cc ${mainAnchor.cc}`,
206
+ );
207
+ this.startFragRequested = false;
208
+ this.nextLoadPosition = syncFrag.start;
209
+ this.resetLoadingState();
210
+ if (this.state === State.IDLE) {
211
+ this.doTickIdle();
212
+ }
213
+ }
190
214
  }
191
215
 
192
216
  startLoad(startPosition: number, skipSeekToStartPosition?: boolean) {
@@ -265,12 +289,7 @@ class AudioStreamController
265
289
  super._handleFragmentLoadComplete(data);
266
290
  }
267
291
  } else if (mainAnchor && mainAnchor.cc !== waitingData.frag.cc) {
268
- // Drop waiting fragment if videoTrackCC has changed since waitingFragment was set and initPTS was not found
269
- this.log(
270
- `Waiting fragment cc (${frag.cc}) cancelled because video is at cc ${mainAnchor.cc}`,
271
- );
272
- this.nextLoadPosition = this.findSyncFrag(mainAnchor).start;
273
- this.clearWaitingFragment();
292
+ this.syncWithAnchor(mainAnchor, waitingData.frag);
274
293
  }
275
294
  } else {
276
295
  this.state = State.IDLE;
@@ -281,23 +300,12 @@ class AudioStreamController
281
300
  this.onTickEnd();
282
301
  }
283
302
 
284
- clearWaitingFragment() {
303
+ protected resetLoadingState() {
285
304
  const waitingData = this.waitingData;
286
305
  if (waitingData) {
287
- if (!this.hls.hasEnoughToStart) {
288
- // Load overlapping fragment on start when discontinuity start times are not aligned
289
- this.startFragRequested = false;
290
- }
291
306
  this.fragmentTracker.removeFragment(waitingData.frag);
292
307
  this.waitingData = null;
293
- if (this.state !== State.STOPPED) {
294
- this.state = State.IDLE;
295
- }
296
308
  }
297
- }
298
-
299
- protected resetLoadingState() {
300
- this.clearWaitingFragment();
301
309
  super.resetLoadingState();
302
310
  }
303
311
 
@@ -2,7 +2,7 @@ import { ErrorActionFlags, NetworkErrorAction } from './error-controller';
2
2
  import {
3
3
  findFragmentByPDT,
4
4
  findFragmentByPTS,
5
- findFragWithCC,
5
+ findNearestWithCC,
6
6
  } from './fragment-finders';
7
7
  import { FragmentState } from './fragment-tracker';
8
8
  import Decrypter from '../crypt/decrypter';
@@ -1298,7 +1298,7 @@ export default class BaseStreamController
1298
1298
  this.log(`LL-Part loading ON for initial live fragment`);
1299
1299
  this.loadingParts = true;
1300
1300
  }
1301
- frag = this.getInitialLiveFragment(levelDetails, fragments);
1301
+ frag = this.getInitialLiveFragment(levelDetails);
1302
1302
  const mainStart = this.hls.startPosition;
1303
1303
  const liveSyncPosition = this.hls.liveSyncPosition;
1304
1304
  const startPosition = frag
@@ -1506,8 +1506,8 @@ export default class BaseStreamController
1506
1506
  */
1507
1507
  protected getInitialLiveFragment(
1508
1508
  levelDetails: LevelDetails,
1509
- fragments: MediaFragment[],
1510
1509
  ): MediaFragment | null {
1510
+ const fragments = levelDetails.fragments;
1511
1511
  const fragPrevious = this.fragPrevious;
1512
1512
  let frag: MediaFragment | null = null;
1513
1513
  if (fragPrevious) {
@@ -1543,7 +1543,11 @@ export default class BaseStreamController
1543
1543
  // It's important to stay within the continuity range if available; otherwise the fragments in the playlist
1544
1544
  // will have the wrong start times
1545
1545
  if (!frag) {
1546
- frag = findFragWithCC(fragments, fragPrevious.cc);
1546
+ frag = findNearestWithCC(
1547
+ levelDetails,
1548
+ fragPrevious.cc,
1549
+ fragPrevious.end,
1550
+ );
1547
1551
  if (frag) {
1548
1552
  this.log(
1549
1553
  `Live playlist, switching playlist, load frag with same CC: ${frag.sn}`,
@@ -341,7 +341,7 @@ export default class ErrorController
341
341
  // Search for next level to retry
342
342
  let nextLevel = -1;
343
343
  const { levels, loadLevel, minAutoLevel, maxAutoLevel } = hls;
344
- if (!hls.autoLevelEnabled) {
344
+ if (!hls.autoLevelEnabled && !hls.config.preserveManualLevelOnError) {
345
345
  hls.loadLevel = -1;
346
346
  }
347
347
  const fragErrorType = data.frag?.type;
@@ -33,7 +33,6 @@ export function findFragmentByPDT(
33
33
  return null;
34
34
  }
35
35
 
36
- maxFragLookUpTolerance = maxFragLookUpTolerance || 0;
37
36
  for (let seg = 0; seg < fragments.length; ++seg) {
38
37
  const frag = fragments[seg];
39
38
  if (pdtWithinToleranceTest(PDTValue, maxFragLookUpTolerance, frag)) {
@@ -225,28 +224,33 @@ export function findFragWithCC(
225
224
  export function findNearestWithCC(
226
225
  details: LevelDetails | undefined,
227
226
  cc: number,
228
- fragment: MediaFragment,
227
+ pos: number,
229
228
  ): MediaFragment | null {
230
229
  if (details) {
231
230
  if (details.startCC <= cc && details.endCC >= cc) {
232
- const start = fragment.start;
233
- const end = fragment.end;
234
231
  let fragments = details.fragments;
235
- if (!fragment.relurl) {
236
- const { fragmentHint } = details;
237
- if (fragmentHint) {
238
- fragments = fragments.concat(fragmentHint);
239
- }
232
+ const { fragmentHint } = details;
233
+ if (fragmentHint) {
234
+ fragments = fragments.concat(fragmentHint);
240
235
  }
241
- return BinarySearch.search(fragments, (candidate) => {
242
- if (candidate.cc < cc || candidate.end <= start) {
236
+ let closest: MediaFragment | undefined;
237
+ BinarySearch.search(fragments, (candidate) => {
238
+ if (candidate.cc < cc) {
239
+ return 1;
240
+ }
241
+ if (candidate.cc > cc) {
242
+ return -1;
243
+ }
244
+ closest = candidate;
245
+ if (candidate.end <= pos) {
243
246
  return 1;
244
- } else if (candidate.cc > cc || candidate.start >= end) {
247
+ }
248
+ if (candidate.start > pos) {
245
249
  return -1;
246
- } else {
247
- return 0;
248
250
  }
251
+ return 0;
249
252
  });
253
+ return closest || null;
250
254
  }
251
255
  }
252
256
  return null;
@@ -2437,7 +2437,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
2437
2437
  }
2438
2438
 
2439
2439
  private bufferAssetPlayer(player: HlsAssetPlayer, media: HTMLMediaElement) {
2440
- const { interstitial, assetItem, assetId } = player;
2440
+ const { interstitial, assetItem } = player;
2441
2441
  const scheduleIndex = this.schedule.findEventIndex(interstitial.identifier);
2442
2442
  const item = this.schedule.items?.[scheduleIndex];
2443
2443
  if (!item) {