hls.js 1.5.13 → 1.5.14-0.canary.10415

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 (103) hide show
  1. package/README.md +4 -3
  2. package/dist/hls-demo.js +41 -38
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +4211 -2666
  5. package/dist/hls.js.d.ts +179 -110
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +2841 -1921
  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 +2569 -1639
  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 +3572 -2017
  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 +38 -38
  20. package/src/config.ts +5 -2
  21. package/src/controller/abr-controller.ts +39 -25
  22. package/src/controller/audio-stream-controller.ts +156 -136
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +27 -10
  25. package/src/controller/base-stream-controller.ts +234 -89
  26. package/src/controller/buffer-controller.ts +250 -97
  27. package/src/controller/buffer-operation-queue.ts +16 -19
  28. package/src/controller/cap-level-controller.ts +3 -2
  29. package/src/controller/cmcd-controller.ts +51 -14
  30. package/src/controller/content-steering-controller.ts +29 -15
  31. package/src/controller/eme-controller.ts +10 -23
  32. package/src/controller/error-controller.ts +28 -22
  33. package/src/controller/fps-controller.ts +8 -3
  34. package/src/controller/fragment-finders.ts +44 -16
  35. package/src/controller/fragment-tracker.ts +58 -25
  36. package/src/controller/gap-controller.ts +43 -16
  37. package/src/controller/id3-track-controller.ts +45 -35
  38. package/src/controller/latency-controller.ts +18 -13
  39. package/src/controller/level-controller.ts +37 -19
  40. package/src/controller/stream-controller.ts +100 -83
  41. package/src/controller/subtitle-stream-controller.ts +35 -47
  42. package/src/controller/subtitle-track-controller.ts +5 -3
  43. package/src/controller/timeline-controller.ts +20 -22
  44. package/src/crypt/aes-crypto.ts +21 -2
  45. package/src/crypt/decrypter-aes-mode.ts +4 -0
  46. package/src/crypt/decrypter.ts +32 -16
  47. package/src/crypt/fast-aes-key.ts +28 -5
  48. package/src/demux/audio/aacdemuxer.ts +2 -2
  49. package/src/demux/audio/ac3-demuxer.ts +4 -3
  50. package/src/demux/audio/adts.ts +9 -4
  51. package/src/demux/audio/base-audio-demuxer.ts +16 -14
  52. package/src/demux/audio/mp3demuxer.ts +4 -3
  53. package/src/demux/audio/mpegaudio.ts +1 -1
  54. package/src/demux/mp4demuxer.ts +7 -7
  55. package/src/demux/sample-aes.ts +2 -0
  56. package/src/demux/transmuxer-interface.ts +8 -16
  57. package/src/demux/transmuxer-worker.ts +4 -4
  58. package/src/demux/transmuxer.ts +16 -3
  59. package/src/demux/tsdemuxer.ts +75 -38
  60. package/src/demux/video/avc-video-parser.ts +210 -121
  61. package/src/demux/video/base-video-parser.ts +135 -2
  62. package/src/demux/video/exp-golomb.ts +0 -208
  63. package/src/demux/video/hevc-video-parser.ts +749 -0
  64. package/src/events.ts +8 -1
  65. package/src/exports-named.ts +1 -1
  66. package/src/hls.ts +84 -47
  67. package/src/loader/date-range.ts +71 -5
  68. package/src/loader/fragment-loader.ts +23 -21
  69. package/src/loader/fragment.ts +8 -4
  70. package/src/loader/key-loader.ts +3 -1
  71. package/src/loader/level-details.ts +6 -6
  72. package/src/loader/level-key.ts +10 -9
  73. package/src/loader/m3u8-parser.ts +138 -144
  74. package/src/loader/playlist-loader.ts +5 -7
  75. package/src/remux/mp4-generator.ts +196 -1
  76. package/src/remux/mp4-remuxer.ts +32 -62
  77. package/src/remux/passthrough-remuxer.ts +1 -1
  78. package/src/task-loop.ts +5 -2
  79. package/src/types/component-api.ts +3 -1
  80. package/src/types/demuxer.ts +3 -0
  81. package/src/types/events.ts +19 -6
  82. package/src/types/fragment-tracker.ts +2 -2
  83. package/src/types/media-playlist.ts +9 -1
  84. package/src/types/remuxer.ts +1 -1
  85. package/src/utils/attr-list.ts +96 -9
  86. package/src/utils/buffer-helper.ts +12 -31
  87. package/src/utils/cea-608-parser.ts +1 -3
  88. package/src/utils/codecs.ts +34 -5
  89. package/src/utils/encryption-methods-util.ts +21 -0
  90. package/src/utils/fetch-loader.ts +1 -1
  91. package/src/utils/hash.ts +10 -0
  92. package/src/utils/hdr.ts +4 -7
  93. package/src/utils/imsc1-ttml-parser.ts +1 -1
  94. package/src/utils/keysystem-util.ts +1 -6
  95. package/src/utils/level-helper.ts +71 -44
  96. package/src/utils/logger.ts +58 -23
  97. package/src/utils/mp4-tools.ts +5 -3
  98. package/src/utils/rendition-helper.ts +100 -74
  99. package/src/utils/utf8-utils.ts +18 -0
  100. package/src/utils/variable-substitution.ts +0 -19
  101. package/src/utils/webvtt-parser.ts +2 -12
  102. package/src/demux/id3.ts +0 -411
  103. package/src/types/general.ts +0 -6
package/package.json CHANGED
@@ -58,52 +58,52 @@
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 install"
61
+ "prepare": "husky"
62
62
  },
63
63
  "devDependencies": {
64
- "@babel/core": "7.23.7",
65
- "@babel/helper-module-imports": "7.22.15",
64
+ "@babel/core": "7.24.7",
65
+ "@babel/helper-module-imports": "7.24.7",
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
- "@babel/plugin-transform-object-assign": "7.23.3",
70
- "@babel/preset-env": "7.23.7",
71
- "@babel/preset-typescript": "7.23.3",
72
- "@babel/register": "7.23.7",
73
- "@microsoft/api-documenter": "7.23.16",
74
- "@microsoft/api-extractor": "7.39.1",
69
+ "@babel/plugin-transform-object-assign": "7.24.7",
70
+ "@babel/preset-env": "7.24.7",
71
+ "@babel/preset-typescript": "7.24.7",
72
+ "@babel/register": "7.24.6",
73
+ "@microsoft/api-documenter": "7.25.3",
74
+ "@microsoft/api-extractor": "7.47.0",
75
75
  "@rollup/plugin-alias": "5.1.0",
76
76
  "@rollup/plugin-babel": "6.0.4",
77
- "@rollup/plugin-commonjs": "25.0.7",
77
+ "@rollup/plugin-commonjs": "25.0.8",
78
78
  "@rollup/plugin-node-resolve": "15.2.3",
79
- "@rollup/plugin-replace": "5.0.5",
79
+ "@rollup/plugin-replace": "5.0.7",
80
80
  "@rollup/plugin-terser": "0.4.4",
81
- "@rollup/plugin-typescript": "11.1.5",
82
- "@svta/common-media-library": "0.6.1",
83
- "@types/chai": "4.3.11",
81
+ "@rollup/plugin-typescript": "11.1.6",
82
+ "@svta/common-media-library": "0.7.1",
83
+ "@types/chai": "4.3.16",
84
84
  "@types/chart.js": "2.9.41",
85
- "@types/mocha": "10.0.6",
85
+ "@types/mocha": "10.0.7",
86
86
  "@types/sinon-chai": "3.2.12",
87
- "@typescript-eslint/eslint-plugin": "6.17.0",
88
- "@typescript-eslint/parser": "6.17.0",
87
+ "@typescript-eslint/eslint-plugin": "7.15.0",
88
+ "@typescript-eslint/parser": "7.15.0",
89
89
  "babel-loader": "9.1.3",
90
90
  "babel-plugin-transform-remove-console": "6.9.4",
91
- "chai": "4.3.10",
91
+ "chai": "4.4.1",
92
92
  "chart.js": "2.9.4",
93
- "chromedriver": "120.0.1",
93
+ "chromedriver": "125.0.3",
94
94
  "doctoc": "2.2.1",
95
- "es-check": "7.1.1",
96
- "eslint": "8.56.0",
95
+ "es-check": "7.2.1",
96
+ "eslint": "8.57.0",
97
97
  "eslint-config-prettier": "9.1.0",
98
98
  "eslint-plugin-import": "2.29.1",
99
- "eslint-plugin-mocha": "10.2.0",
100
- "eslint-plugin-node": "11.1.0",
101
- "eslint-plugin-promise": "6.1.1",
99
+ "eslint-plugin-mocha": "10.4.3",
100
+ "eslint-plugin-n": "17.9.0",
101
+ "eslint-plugin-promise": "6.2.0",
102
102
  "eventemitter3": "5.0.1",
103
103
  "http-server": "14.1.1",
104
- "husky": "8.0.3",
104
+ "husky": "9.0.11",
105
105
  "jsonpack": "1.1.5",
106
- "karma": "6.4.2",
106
+ "karma": "6.4.3",
107
107
  "karma-chrome-launcher": "3.2.0",
108
108
  "karma-coverage": "2.2.1",
109
109
  "karma-mocha": "2.0.1",
@@ -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.0",
114
+ "lint-staged": "15.2.7",
115
115
  "markdown-styles": "3.2.0",
116
- "micromatch": "4.0.5",
117
- "mocha": "10.2.0",
116
+ "micromatch": "4.0.7",
117
+ "mocha": "10.5.2",
118
118
  "node-fetch": "3.3.2",
119
- "npm-run-all": "4.1.5",
120
- "prettier": "3.1.1",
119
+ "npm-run-all2": "6.2.0",
120
+ "prettier": "3.3.2",
121
121
  "promise-polyfill": "8.3.0",
122
- "rollup": "4.9.4",
122
+ "rollup": "4.18.0",
123
123
  "rollup-plugin-istanbul": "5.0.0",
124
124
  "sauce-connect-launcher": "1.3.2",
125
- "selenium-webdriver": "4.16.0",
126
- "semver": "7.5.4",
127
- "sinon": "17.0.1",
125
+ "selenium-webdriver": "4.22.0",
126
+ "semver": "7.6.2",
127
+ "sinon": "18.0.0",
128
128
  "sinon-chai": "3.7.0",
129
- "typescript": "5.3.3",
129
+ "typescript": "5.4.5",
130
130
  "url-toolkit": "2.2.5",
131
- "wrangler": "3.22.4"
131
+ "wrangler": "3.62.0"
132
132
  },
133
- "version": "1.5.13"
133
+ "version": "1.5.14-0.canary.10415"
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';
21
20
 
22
21
  import type Hls from './hls';
23
22
  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,
@@ -235,6 +235,7 @@ export type LatencyControllerConfig = {
235
235
  liveSyncDuration?: number;
236
236
  liveMaxLatencyDuration?: number;
237
237
  maxLiveSyncPlaybackRate: number;
238
+ liveSyncOnStallIncrease: number;
238
239
  };
239
240
 
240
241
  export type MetadataControllerConfig = {
@@ -352,6 +353,7 @@ export const hlsDefaultConfig: HlsConfig = {
352
353
  nudgeMaxRetry: 3, // used by stream-controller
353
354
  maxFragLookUpTolerance: 0.25, // used by stream-controller
354
355
  liveSyncDurationCount: 3, // used by latency-controller
356
+ liveSyncOnStallIncrease: 1, // used by latency-controller
355
357
  liveMaxLatencyDurationCount: Infinity, // used by latency-controller
356
358
  liveSyncDuration: undefined, // used by latency-controller
357
359
  liveMaxLatencyDuration: undefined, // used by latency-controller
@@ -558,6 +560,7 @@ function timelineConfig(): TimelineControllerConfig {
558
560
  export function mergeConfig(
559
561
  defaultConfig: HlsConfig,
560
562
  userConfig: Partial<HlsConfig>,
563
+ logger: ILogger,
561
564
  ): HlsConfig {
562
565
  if (
563
566
  (userConfig.liveSyncDurationCount ||
@@ -664,7 +667,7 @@ function deepCpy(obj: any): any {
664
667
  /**
665
668
  * @ignore
666
669
  */
667
- export function enableStreamingMode(config) {
670
+ export function enableStreamingMode(config: HlsConfig, logger: ILogger) {
668
671
  const currentLoader = config.loader;
669
672
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
670
673
  // 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 implements AbrComponentAPI {
34
+ class AbrController extends Logger implements AbrComponentAPI {
35
35
  protected hls: Hls;
36
36
  private lastLevelLoadSec: number = 0;
37
37
  private lastLoadedFragLevel: number = -1;
@@ -48,6 +48,7 @@ class AbrController implements AbrComponentAPI {
48
48
  public bwEstimator: EwmaBandWidthEstimator;
49
49
 
50
50
  constructor(hls: Hls) {
51
+ super('abr', hls.logger);
51
52
  this.hls = hls;
52
53
  this.bwEstimator = this.initEstimator();
53
54
  this.registerListeners();
@@ -55,7 +56,7 @@ class AbrController implements AbrComponentAPI {
55
56
 
56
57
  public resetEstimator(abrEwmaDefaultEstimate?: number) {
57
58
  if (abrEwmaDefaultEstimate) {
58
- logger.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`);
59
+ this.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`);
59
60
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
60
61
  }
61
62
  this.firstSelection = -1;
@@ -355,7 +356,7 @@ class AbrController implements AbrComponentAPI {
355
356
  }
356
357
 
357
358
  this.clearTimer();
358
- logger.warn(`[abr] Fragment ${frag.sn}${
359
+ this.warn(`Fragment ${frag.sn}${
359
360
  part ? ' part ' + part.index : ''
360
361
  } of level ${frag.level} is loading too slowly;
361
362
  Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
@@ -479,8 +480,8 @@ class AbrController implements AbrComponentAPI {
479
480
  }
480
481
  const firstLevel = this.hls.firstLevel;
481
482
  const clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
482
- logger.warn(
483
- `[abr] Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`,
483
+ this.warn(
484
+ `Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`,
484
485
  );
485
486
  return clamped;
486
487
  }
@@ -538,6 +539,9 @@ class AbrController implements AbrComponentAPI {
538
539
 
539
540
  private getNextABRAutoLevel(): number {
540
541
  const { fragCurrent, partCurrent, hls } = this;
542
+ if (hls.levels.length <= 1) {
543
+ return hls.loadLevel;
544
+ }
541
545
  const { maxAutoLevel, config, minAutoLevel } = hls;
542
546
  const currentFragDuration = partCurrent
543
547
  ? partCurrent.duration
@@ -584,8 +588,8 @@ class AbrController implements AbrComponentAPI {
584
588
  ? Math.min(currentFragDuration, config.maxLoadingDelay)
585
589
  : config.maxLoadingDelay;
586
590
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
587
- logger.info(
588
- `[abr] bitrate test took ${Math.round(
591
+ this.info(
592
+ `bitrate test took ${Math.round(
589
593
  1000 * bitrateTestDelay,
590
594
  )}ms, set first fragment max fetchDuration to ${Math.round(
591
595
  1000 * maxStarvationDelay,
@@ -604,8 +608,8 @@ class AbrController implements AbrComponentAPI {
604
608
  bwFactor,
605
609
  bwUpFactor,
606
610
  );
607
- logger.info(
608
- `[abr] ${
611
+ this.info(
612
+ `${
609
613
  bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty'
610
614
  }, optimal quality level ${bestLevel}`,
611
615
  );
@@ -671,6 +675,7 @@ class AbrController implements AbrComponentAPI {
671
675
  const audioTracksByGroup =
672
676
  this.audioTracksByGroup ||
673
677
  (this.audioTracksByGroup = getAudioTracksByGroup(allAudioTracks));
678
+ let minStartIndex = -1;
674
679
  if (firstSelection) {
675
680
  if (this.firstSelection !== -1) {
676
681
  return this.firstSelection;
@@ -690,15 +695,22 @@ class AbrController implements AbrComponentAPI {
690
695
  audioPreference,
691
696
  videoPreference,
692
697
  );
693
- const { codecSet, videoRanges, minFramerate, minBitrate, preferHDR } =
694
- startTier;
698
+ const {
699
+ codecSet,
700
+ videoRanges,
701
+ minFramerate,
702
+ minBitrate,
703
+ minIndex,
704
+ preferHDR,
705
+ } = startTier;
706
+ minStartIndex = minIndex;
695
707
  currentCodecSet = codecSet;
696
708
  currentVideoRange = preferHDR
697
709
  ? videoRanges[videoRanges.length - 1]
698
710
  : videoRanges[0];
699
711
  currentFrameRate = minFramerate;
700
712
  currentBw = Math.max(currentBw, minBitrate);
701
- logger.log(`[abr] picked start tier ${JSON.stringify(startTier)}`);
713
+ this.log(`picked start tier ${JSON.stringify(startTier)}`);
702
714
  } else {
703
715
  currentCodecSet = level?.codecSet;
704
716
  currentVideoRange = level?.videoRange;
@@ -751,19 +763,19 @@ class AbrController implements AbrComponentAPI {
751
763
  const levels = this.hls.levels;
752
764
  const index = levels.indexOf(levelInfo);
753
765
  if (decodingInfo.error) {
754
- logger.warn(
755
- `[abr] MediaCapabilities decodingInfo error: "${
766
+ this.warn(
767
+ `MediaCapabilities decodingInfo error: "${
756
768
  decodingInfo.error
757
769
  }" for level ${index} ${JSON.stringify(decodingInfo)}`,
758
770
  );
759
771
  } else if (!decodingInfo.supported) {
760
- logger.warn(
761
- `[abr] Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
772
+ this.warn(
773
+ `Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
762
774
  decodingInfo,
763
775
  )}`,
764
776
  );
765
777
  if (index > -1 && levels.length > 1) {
766
- logger.log(`[abr] Removing unsupported level ${index}`);
778
+ this.log(`Removing unsupported level ${index}`);
767
779
  this.hls.removeLevel(index);
768
780
  }
769
781
  }
@@ -785,8 +797,10 @@ class AbrController implements AbrComponentAPI {
785
797
  (levelInfo.supportedResult &&
786
798
  !levelInfo.supportedResult.decodingInfoResults?.[0].smooth)
787
799
  ) {
788
- levelsSkipped.push(i);
789
- continue;
800
+ if (!firstSelection || i !== minStartIndex) {
801
+ levelsSkipped.push(i);
802
+ continue;
803
+ }
790
804
  }
791
805
 
792
806
  const levelDetails = levelInfo.details;
@@ -842,8 +856,8 @@ class AbrController implements AbrComponentAPI {
842
856
  (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)
843
857
  ) {
844
858
  if (levelsSkipped.length) {
845
- logger.trace(
846
- `[abr] Skipped level(s) ${levelsSkipped.join(
859
+ this.trace(
860
+ `Skipped level(s) ${levelsSkipped.join(
847
861
  ',',
848
862
  )} of ${maxAutoLevel} max with CODECS and VIDEO-RANGE:"${
849
863
  levels[levelsSkipped[0]].codecs
@@ -852,8 +866,8 @@ class AbrController implements AbrComponentAPI {
852
866
  }" ${currentVideoRange}`,
853
867
  );
854
868
  }
855
- logger.info(
856
- `[abr] switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
869
+ this.info(
870
+ `switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
857
871
  adjustedbw,
858
872
  )})-bitrate=${Math.round(
859
873
  adjustedbw - bitrate,
@@ -865,7 +879,7 @@ class AbrController implements AbrComponentAPI {
865
879
  1,
866
880
  )} fetchDuration:${fetchDuration.toFixed(
867
881
  1,
868
- )} firstSelection:${firstSelection} codecSet:${currentCodecSet} videoRange:${currentVideoRange} hls.loadLevel:${loadLevel}`,
882
+ )} firstSelection:${firstSelection} codecSet:${levelInfo.codecSet} videoRange:${levelInfo.videoRange} hls.loadLevel:${loadLevel}`,
869
883
  );
870
884
  }
871
885
  if (firstSelection) {