hls.js 1.5.5-0.canary.9997 → 1.5.5

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 +20 -20
  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
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.9.6",
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.26.0"
131
+ "wrangler": "3.22.4"
132
132
  },
133
- "version": "1.5.5-0.canary.9997"
133
+ "version": "1.5.5"
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
  }
@@ -592,8 +591,8 @@ class AbrController extends Logger implements AbrComponentAPI {
592
591
  ? Math.min(currentFragDuration, config.maxLoadingDelay)
593
592
  : config.maxLoadingDelay;
594
593
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
595
- this.info(
596
- `bitrate test took ${Math.round(
594
+ logger.info(
595
+ `[abr] bitrate test took ${Math.round(
597
596
  1000 * bitrateTestDelay,
598
597
  )}ms, set first fragment max fetchDuration to ${Math.round(
599
598
  1000 * maxStarvationDelay,
@@ -612,8 +611,8 @@ class AbrController extends Logger implements AbrComponentAPI {
612
611
  bwFactor,
613
612
  bwUpFactor,
614
613
  );
615
- this.info(
616
- `${
614
+ logger.info(
615
+ `[abr] ${
617
616
  bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty'
618
617
  }, optimal quality level ${bestLevel}`,
619
618
  );
@@ -692,7 +691,7 @@ class AbrController extends Logger implements AbrComponentAPI {
692
691
  : videoRanges[0];
693
692
  currentFrameRate = minFramerate;
694
693
  currentBw = Math.max(currentBw, minBitrate);
695
- this.log(`picked start tier ${JSON.stringify(startTier)}`);
694
+ logger.log(`[abr] picked start tier ${JSON.stringify(startTier)}`);
696
695
  } else {
697
696
  currentCodecSet = level?.codecSet;
698
697
  currentVideoRange = level?.videoRange;
@@ -742,19 +741,19 @@ class AbrController extends Logger implements AbrComponentAPI {
742
741
  const levels = this.hls.levels;
743
742
  const index = levels.indexOf(levelInfo);
744
743
  if (decodingInfo.error) {
745
- this.warn(
746
- `MediaCapabilities decodingInfo error: "${
744
+ logger.warn(
745
+ `[abr] MediaCapabilities decodingInfo error: "${
747
746
  decodingInfo.error
748
747
  }" for level ${index} ${JSON.stringify(decodingInfo)}`,
749
748
  );
750
749
  } else if (!decodingInfo.supported) {
751
- this.warn(
752
- `Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
750
+ logger.warn(
751
+ `[abr] Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
753
752
  decodingInfo,
754
753
  )}`,
755
754
  );
756
755
  if (index > -1 && levels.length > 1) {
757
- this.log(`Removing unsupported level ${index}`);
756
+ logger.log(`[abr] Removing unsupported level ${index}`);
758
757
  this.hls.removeLevel(index);
759
758
  }
760
759
  }
@@ -833,8 +832,8 @@ class AbrController extends Logger implements AbrComponentAPI {
833
832
  (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)
834
833
  ) {
835
834
  if (levelsSkipped.length) {
836
- this.trace(
837
- `Skipped level(s) ${levelsSkipped.join(
835
+ logger.trace(
836
+ `[abr] Skipped level(s) ${levelsSkipped.join(
838
837
  ',',
839
838
  )} of ${maxAutoLevel} max with CODECS and VIDEO-RANGE:"${
840
839
  levels[levelsSkipped[0]].codecs
@@ -843,8 +842,8 @@ class AbrController extends Logger implements AbrComponentAPI {
843
842
  }" ${currentVideoRange}`,
844
843
  );
845
844
  }
846
- this.info(
847
- `switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
845
+ logger.info(
846
+ `[abr] switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
848
847
  adjustedbw,
849
848
  )})-bitrate=${Math.round(
850
849
  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(