hls.js 1.5.6-0.canary.10011 → 1.5.6

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 (68) hide show
  1. package/README.md +0 -1
  2. package/dist/hls-demo.js +0 -10
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1134 -2043
  5. package/dist/hls.js.d.ts +50 -65
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +852 -1141
  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 +686 -974
  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 +847 -1741
  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 +21 -21
  20. package/src/config.ts +2 -3
  21. package/src/controller/abr-controller.ts +20 -21
  22. package/src/controller/audio-stream-controller.ts +16 -15
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +8 -20
  25. package/src/controller/base-stream-controller.ts +33 -149
  26. package/src/controller/buffer-controller.ts +11 -11
  27. package/src/controller/cap-level-controller.ts +2 -1
  28. package/src/controller/cmcd-controller.ts +6 -27
  29. package/src/controller/content-steering-controller.ts +6 -8
  30. package/src/controller/eme-controller.ts +22 -9
  31. package/src/controller/error-controller.ts +8 -6
  32. package/src/controller/fps-controller.ts +3 -2
  33. package/src/controller/gap-controller.ts +16 -43
  34. package/src/controller/latency-controller.ts +11 -9
  35. package/src/controller/level-controller.ts +18 -12
  36. package/src/controller/stream-controller.ts +32 -25
  37. package/src/controller/subtitle-stream-controller.ts +14 -13
  38. package/src/controller/subtitle-track-controller.ts +3 -5
  39. package/src/controller/timeline-controller.ts +30 -23
  40. package/src/crypt/aes-crypto.ts +2 -21
  41. package/src/crypt/decrypter.ts +18 -32
  42. package/src/crypt/fast-aes-key.ts +5 -24
  43. package/src/demux/audio/adts.ts +4 -9
  44. package/src/demux/sample-aes.ts +0 -2
  45. package/src/demux/transmuxer-interface.ts +12 -4
  46. package/src/demux/transmuxer-worker.ts +4 -4
  47. package/src/demux/transmuxer.ts +3 -16
  48. package/src/demux/tsdemuxer.ts +37 -71
  49. package/src/demux/video/avc-video-parser.ts +119 -208
  50. package/src/demux/video/base-video-parser.ts +2 -134
  51. package/src/demux/video/exp-golomb.ts +208 -0
  52. package/src/events.ts +0 -7
  53. package/src/hls.ts +34 -42
  54. package/src/loader/fragment-loader.ts +2 -9
  55. package/src/loader/key-loader.ts +0 -2
  56. package/src/loader/level-key.ts +9 -10
  57. package/src/loader/playlist-loader.ts +5 -4
  58. package/src/remux/mp4-generator.ts +1 -196
  59. package/src/remux/mp4-remuxer.ts +7 -23
  60. package/src/task-loop.ts +2 -5
  61. package/src/types/component-api.ts +0 -2
  62. package/src/types/demuxer.ts +0 -3
  63. package/src/types/events.ts +0 -4
  64. package/src/utils/codecs.ts +4 -33
  65. package/src/utils/logger.ts +24 -54
  66. package/src/crypt/decrypter-aes-mode.ts +0 -4
  67. package/src/demux/video/hevc-video-parser.ts +0 -746
  68. package/src/utils/encryption-methods-util.ts +0 -21
package/package.json CHANGED
@@ -58,39 +58,39 @@
58
58
  "test:func:sauce": "SAUCE=1 UA=safari OS='OS X 10.15' BABEL_ENV=development mocha --require @babel/register tests/functional/auto/setup.js --timeout 40000 --exit",
59
59
  "type-check": "tsc --noEmit",
60
60
  "type-check:watch": "npm run type-check -- --watch",
61
- "prepare": "husky"
61
+ "prepare": "husky install"
62
62
  },
63
63
  "devDependencies": {
64
- "@babel/core": "7.23.9",
64
+ "@babel/core": "7.23.7",
65
65
  "@babel/helper-module-imports": "7.22.15",
66
66
  "@babel/plugin-proposal-class-properties": "7.18.6",
67
67
  "@babel/plugin-proposal-object-rest-spread": "7.20.7",
68
68
  "@babel/plugin-proposal-optional-chaining": "7.21.0",
69
69
  "@babel/plugin-transform-object-assign": "7.23.3",
70
- "@babel/preset-env": "7.23.9",
70
+ "@babel/preset-env": "7.23.7",
71
71
  "@babel/preset-typescript": "7.23.3",
72
72
  "@babel/register": "7.23.7",
73
- "@microsoft/api-documenter": "7.23.23",
74
- "@microsoft/api-extractor": "7.40.1",
73
+ "@microsoft/api-documenter": "7.23.16",
74
+ "@microsoft/api-extractor": "7.39.1",
75
75
  "@rollup/plugin-alias": "5.1.0",
76
76
  "@rollup/plugin-babel": "6.0.4",
77
77
  "@rollup/plugin-commonjs": "25.0.7",
78
78
  "@rollup/plugin-node-resolve": "15.2.3",
79
79
  "@rollup/plugin-replace": "5.0.5",
80
80
  "@rollup/plugin-terser": "0.4.4",
81
- "@rollup/plugin-typescript": "11.1.6",
82
- "@svta/common-media-library": "0.6.2",
81
+ "@rollup/plugin-typescript": "11.1.5",
82
+ "@svta/common-media-library": "0.6.1",
83
83
  "@types/chai": "4.3.11",
84
84
  "@types/chart.js": "2.9.41",
85
85
  "@types/mocha": "10.0.6",
86
86
  "@types/sinon-chai": "3.2.12",
87
- "@typescript-eslint/eslint-plugin": "6.21.0",
88
- "@typescript-eslint/parser": "6.21.0",
87
+ "@typescript-eslint/eslint-plugin": "6.17.0",
88
+ "@typescript-eslint/parser": "6.17.0",
89
89
  "babel-loader": "9.1.3",
90
90
  "babel-plugin-transform-remove-console": "6.9.4",
91
- "chai": "4.4.1",
91
+ "chai": "4.3.10",
92
92
  "chart.js": "2.9.4",
93
- "chromedriver": "121.0.0",
93
+ "chromedriver": "120.0.1",
94
94
  "doctoc": "2.2.1",
95
95
  "es-check": "7.1.1",
96
96
  "eslint": "8.56.0",
@@ -101,7 +101,7 @@
101
101
  "eslint-plugin-promise": "6.1.1",
102
102
  "eventemitter3": "5.0.1",
103
103
  "http-server": "14.1.1",
104
- "husky": "9.0.10",
104
+ "husky": "8.0.3",
105
105
  "jsonpack": "1.1.5",
106
106
  "karma": "6.4.2",
107
107
  "karma-chrome-launcher": "3.2.0",
@@ -111,24 +111,24 @@
111
111
  "karma-rollup-preprocessor": "github:jlmakes/karma-rollup-preprocessor#7a7268d91149307b3cf2888ee4e65ccd079955a3",
112
112
  "karma-sinon-chai": "2.0.2",
113
113
  "karma-sourcemap-loader": "0.4.0",
114
- "lint-staged": "15.2.2",
114
+ "lint-staged": "15.2.0",
115
115
  "markdown-styles": "3.2.0",
116
116
  "micromatch": "4.0.5",
117
- "mocha": "10.3.0",
117
+ "mocha": "10.2.0",
118
118
  "node-fetch": "3.3.2",
119
- "npm-run-all2": "5.0.2",
120
- "prettier": "3.2.4",
119
+ "npm-run-all": "4.1.5",
120
+ "prettier": "3.1.1",
121
121
  "promise-polyfill": "8.3.0",
122
- "rollup": "4.12.0",
122
+ "rollup": "4.9.4",
123
123
  "rollup-plugin-istanbul": "5.0.0",
124
124
  "sauce-connect-launcher": "1.3.2",
125
- "selenium-webdriver": "4.17.0",
126
- "semver": "7.6.0",
125
+ "selenium-webdriver": "4.16.0",
126
+ "semver": "7.5.4",
127
127
  "sinon": "17.0.1",
128
128
  "sinon-chai": "3.7.0",
129
129
  "typescript": "5.3.3",
130
130
  "url-toolkit": "2.2.5",
131
- "wrangler": "3.28.2"
131
+ "wrangler": "3.22.4"
132
132
  },
133
- "version": "1.5.6-0.canary.10011"
133
+ "version": "1.5.6"
134
134
  }
package/src/config.ts CHANGED
@@ -17,10 +17,10 @@ import XhrLoader from './utils/xhr-loader';
17
17
  import FetchLoader, { fetchSupported } from './utils/fetch-loader';
18
18
  import Cues from './utils/cues';
19
19
  import { requestMediaKeySystemAccess } from './utils/mediakeys-helper';
20
+ import { ILogger, logger } from './utils/logger';
20
21
 
21
22
  import type Hls from './hls';
22
23
  import type { CuesInterface } from './utils/cues';
23
- import type { ILogger } from './utils/logger';
24
24
  import type { MediaKeyFunc, KeySystems } from './utils/mediakeys-helper';
25
25
  import type {
26
26
  FragmentLoaderContext,
@@ -558,7 +558,6 @@ function timelineConfig(): TimelineControllerConfig {
558
558
  export function mergeConfig(
559
559
  defaultConfig: HlsConfig,
560
560
  userConfig: Partial<HlsConfig>,
561
- logger: ILogger,
562
561
  ): HlsConfig {
563
562
  if (
564
563
  (userConfig.liveSyncDurationCount ||
@@ -665,7 +664,7 @@ function deepCpy(obj: any): any {
665
664
  /**
666
665
  * @ignore
667
666
  */
668
- export function enableStreamingMode(config: HlsConfig, logger: ILogger) {
667
+ export function enableStreamingMode(config) {
669
668
  const currentLoader = config.loader;
670
669
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
671
670
  // If a developer has configured their own loader, respect that choice
@@ -2,7 +2,7 @@ import EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator';
2
2
  import { Events } from '../events';
3
3
  import { ErrorDetails } from '../errors';
4
4
  import { PlaylistLevelType } from '../types/loader';
5
- import { Logger } from '../utils/logger';
5
+ import { logger } from '../utils/logger';
6
6
  import {
7
7
  SUPPORTED_INFO_DEFAULT,
8
8
  getMediaDecodingInfoPromise,
@@ -31,7 +31,7 @@ import type {
31
31
  } from '../types/events';
32
32
  import type { AbrComponentAPI } from '../types/component-api';
33
33
 
34
- class AbrController extends Logger implements AbrComponentAPI {
34
+ class AbrController implements AbrComponentAPI {
35
35
  protected hls: Hls;
36
36
  private lastLevelLoadSec: number = 0;
37
37
  private lastLoadedFragLevel: number = -1;
@@ -48,7 +48,6 @@ class AbrController extends Logger implements AbrComponentAPI {
48
48
  public bwEstimator: EwmaBandWidthEstimator;
49
49
 
50
50
  constructor(hls: Hls) {
51
- super('abr', hls.logger);
52
51
  this.hls = hls;
53
52
  this.bwEstimator = this.initEstimator();
54
53
  this.registerListeners();
@@ -56,7 +55,7 @@ class AbrController extends Logger implements AbrComponentAPI {
56
55
 
57
56
  public resetEstimator(abrEwmaDefaultEstimate?: number) {
58
57
  if (abrEwmaDefaultEstimate) {
59
- this.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`);
58
+ logger.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`);
60
59
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
61
60
  }
62
61
  this.firstSelection = -1;
@@ -356,7 +355,7 @@ class AbrController extends Logger implements AbrComponentAPI {
356
355
  }
357
356
 
358
357
  this.clearTimer();
359
- this.warn(`Fragment ${frag.sn}${
358
+ logger.warn(`[abr] Fragment ${frag.sn}${
360
359
  part ? ' part ' + part.index : ''
361
360
  } of level ${frag.level} is loading too slowly;
362
361
  Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
@@ -480,8 +479,8 @@ class AbrController extends Logger implements AbrComponentAPI {
480
479
  }
481
480
  const firstLevel = this.hls.firstLevel;
482
481
  const clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
483
- this.warn(
484
- `Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`,
482
+ logger.warn(
483
+ `[abr] Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`,
485
484
  );
486
485
  return clamped;
487
486
  }
@@ -585,8 +584,8 @@ class AbrController extends Logger implements AbrComponentAPI {
585
584
  ? Math.min(currentFragDuration, config.maxLoadingDelay)
586
585
  : config.maxLoadingDelay;
587
586
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
588
- this.info(
589
- `bitrate test took ${Math.round(
587
+ logger.info(
588
+ `[abr] bitrate test took ${Math.round(
590
589
  1000 * bitrateTestDelay,
591
590
  )}ms, set first fragment max fetchDuration to ${Math.round(
592
591
  1000 * maxStarvationDelay,
@@ -605,8 +604,8 @@ class AbrController extends Logger implements AbrComponentAPI {
605
604
  bwFactor,
606
605
  bwUpFactor,
607
606
  );
608
- this.info(
609
- `${
607
+ logger.info(
608
+ `[abr] ${
610
609
  bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty'
611
610
  }, optimal quality level ${bestLevel}`,
612
611
  );
@@ -699,7 +698,7 @@ class AbrController extends Logger implements AbrComponentAPI {
699
698
  : videoRanges[0];
700
699
  currentFrameRate = minFramerate;
701
700
  currentBw = Math.max(currentBw, minBitrate);
702
- this.log(`picked start tier ${JSON.stringify(startTier)}`);
701
+ logger.log(`[abr] picked start tier ${JSON.stringify(startTier)}`);
703
702
  } else {
704
703
  currentCodecSet = level?.codecSet;
705
704
  currentVideoRange = level?.videoRange;
@@ -752,19 +751,19 @@ class AbrController extends Logger implements AbrComponentAPI {
752
751
  const levels = this.hls.levels;
753
752
  const index = levels.indexOf(levelInfo);
754
753
  if (decodingInfo.error) {
755
- this.warn(
756
- `MediaCapabilities decodingInfo error: "${
754
+ logger.warn(
755
+ `[abr] MediaCapabilities decodingInfo error: "${
757
756
  decodingInfo.error
758
757
  }" for level ${index} ${JSON.stringify(decodingInfo)}`,
759
758
  );
760
759
  } else if (!decodingInfo.supported) {
761
- this.warn(
762
- `Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
760
+ logger.warn(
761
+ `[abr] Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
763
762
  decodingInfo,
764
763
  )}`,
765
764
  );
766
765
  if (index > -1 && levels.length > 1) {
767
- this.log(`Removing unsupported level ${index}`);
766
+ logger.log(`[abr] Removing unsupported level ${index}`);
768
767
  this.hls.removeLevel(index);
769
768
  }
770
769
  }
@@ -843,8 +842,8 @@ class AbrController extends Logger implements AbrComponentAPI {
843
842
  (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)
844
843
  ) {
845
844
  if (levelsSkipped.length) {
846
- this.trace(
847
- `Skipped level(s) ${levelsSkipped.join(
845
+ logger.trace(
846
+ `[abr] Skipped level(s) ${levelsSkipped.join(
848
847
  ',',
849
848
  )} of ${maxAutoLevel} max with CODECS and VIDEO-RANGE:"${
850
849
  levels[levelsSkipped[0]].codecs
@@ -853,8 +852,8 @@ class AbrController extends Logger implements AbrComponentAPI {
853
852
  }" ${currentVideoRange}`,
854
853
  );
855
854
  }
856
- this.info(
857
- `switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
855
+ logger.info(
856
+ `[abr] switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
858
857
  adjustedbw,
859
858
  )})-bitrate=${Math.round(
860
859
  adjustedbw - bitrate,
@@ -71,27 +71,30 @@ class AudioStreamController
71
71
  hls,
72
72
  fragmentTracker,
73
73
  keyLoader,
74
- 'audio-stream-controller',
74
+ '[audio-stream-controller]',
75
75
  PlaylistLevelType.AUDIO,
76
76
  );
77
- this.registerListeners();
77
+ this._registerListeners();
78
78
  }
79
79
 
80
80
  protected onHandlerDestroying() {
81
- this.unregisterListeners();
81
+ this._unregisterListeners();
82
82
  super.onHandlerDestroying();
83
83
  this.mainDetails = null;
84
84
  this.bufferedTrack = null;
85
85
  this.switchingTrack = null;
86
86
  }
87
87
 
88
- protected registerListeners() {
89
- super.registerListeners();
88
+ private _registerListeners() {
90
89
  const { hls } = this;
90
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
91
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
92
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
91
93
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
92
94
  hls.on(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this);
93
95
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
94
96
  hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
97
+ hls.on(Events.ERROR, this.onError, this);
95
98
  hls.on(Events.BUFFER_RESET, this.onBufferReset, this);
96
99
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
97
100
  hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
@@ -100,16 +103,16 @@ class AudioStreamController
100
103
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
101
104
  }
102
105
 
103
- protected unregisterListeners() {
106
+ private _unregisterListeners() {
104
107
  const { hls } = this;
105
- if (!hls) {
106
- return;
107
- }
108
- super.unregisterListeners();
108
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
109
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
110
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
109
111
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
110
112
  hls.off(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this);
111
113
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
112
114
  hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
115
+ hls.off(Events.ERROR, this.onError, this);
113
116
  hls.off(Events.BUFFER_RESET, this.onBufferReset, this);
114
117
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
115
118
  hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
@@ -278,14 +281,12 @@ class AudioStreamController
278
281
  const { hls, levels, media, trackId } = this;
279
282
  const config = hls.config;
280
283
 
281
- // 1. if buffering is suspended
282
- // 2. if video not attached AND
284
+ // 1. if video not attached AND
283
285
  // start fragment already requested OR start frag prefetch not enabled
284
- // 3. if tracks or track not loaded and selected
286
+ // 2. if tracks or track not loaded and selected
285
287
  // then exit loop
286
288
  // => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
287
289
  if (
288
- !this.buffering ||
289
290
  (!media && (this.startFragRequested || !config.startFragPrefetch)) ||
290
291
  !levels?.[trackId]
291
292
  ) {
@@ -712,7 +713,7 @@ class AudioStreamController
712
713
  this.fragBufferedComplete(frag, part);
713
714
  }
714
715
 
715
- protected onError(event: Events.ERROR, data: ErrorData) {
716
+ private onError(event: Events.ERROR, data: ErrorData) {
716
717
  if (data.fatal) {
717
718
  this.state = State.ERROR;
718
719
  return;
@@ -33,7 +33,7 @@ class AudioTrackController extends BasePlaylistController {
33
33
  private selectDefaultTrack: boolean = true;
34
34
 
35
35
  constructor(hls: Hls) {
36
- super(hls, 'audio-track-controller');
36
+ super(hls, '[audio-track-controller]');
37
37
  this.registerListeners();
38
38
  }
39
39
 
@@ -5,7 +5,7 @@ import { computeReloadInterval, mergeDetails } from '../utils/level-helper';
5
5
  import { ErrorData } from '../types/events';
6
6
  import { getRetryDelay, isTimeoutError } from '../utils/error-helper';
7
7
  import { NetworkErrorAction } from './error-controller';
8
- import { Logger } from '../utils/logger';
8
+ import { logger } from '../utils/logger';
9
9
  import type { LevelDetails } from '../loader/level-details';
10
10
  import type { MediaPlaylist } from '../types/media-playlist';
11
11
  import type {
@@ -14,17 +14,17 @@ import type {
14
14
  TrackLoadedData,
15
15
  } from '../types/events';
16
16
 
17
- export default class BasePlaylistController
18
- extends Logger
19
- implements NetworkComponentAPI
20
- {
17
+ export default class BasePlaylistController implements NetworkComponentAPI {
21
18
  protected hls: Hls;
22
19
  protected timer: number = -1;
23
20
  protected requestScheduled: number = -1;
24
21
  protected canLoad: boolean = false;
22
+ protected log: (msg: any) => void;
23
+ protected warn: (msg: any) => void;
25
24
 
26
25
  constructor(hls: Hls, logPrefix: string) {
27
- super(logPrefix, hls.logger);
26
+ this.log = logger.log.bind(logger, `${logPrefix}:`);
27
+ this.warn = logger.warn.bind(logger, `${logPrefix}:`);
28
28
  this.hls = hls;
29
29
  }
30
30
 
@@ -65,7 +65,7 @@ export default class BasePlaylistController
65
65
  try {
66
66
  uri = new self.URL(attr.URI, previous.url).href;
67
67
  } catch (error) {
68
- this.warn(
68
+ logger.warn(
69
69
  `Could not construct new URL for Rendition Report: ${error}`,
70
70
  );
71
71
  uri = attr.URI || '';
@@ -192,19 +192,7 @@ export default class BasePlaylistController
192
192
  details.targetduration * 1.5,
193
193
  );
194
194
  if (currentGoal > 0) {
195
- if (cdnAge > details.targetduration * 3) {
196
- // Omit segment and part directives when the last response was more than 3 target durations ago,
197
- this.log(
198
- `Playlist last advanced ${lastAdvanced.toFixed(
199
- 2,
200
- )}s ago. Omitting segment and part directives.`,
201
- );
202
- msn = undefined;
203
- part = undefined;
204
- } else if (
205
- previousDetails?.tuneInGoal &&
206
- cdnAge - details.partTarget > previousDetails.tuneInGoal
207
- ) {
195
+ if (previousDetails && currentGoal > previousDetails.tuneInGoal) {
208
196
  // If we attempted to get the next or latest playlist update, but currentGoal increased,
209
197
  // then we either can't catchup, or the "age" header cannot be trusted.
210
198
  this.warn(