hls.js 1.5.2-0.canary.9923 → 1.5.2

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 (44) hide show
  1. package/dist/hls-demo.js +0 -5
  2. package/dist/hls-demo.js.map +1 -1
  3. package/dist/hls.js +379 -431
  4. package/dist/hls.js.d.ts +14 -14
  5. package/dist/hls.js.map +1 -1
  6. package/dist/hls.light.js +217 -275
  7. package/dist/hls.light.js.map +1 -1
  8. package/dist/hls.light.min.js +1 -1
  9. package/dist/hls.light.min.js.map +1 -1
  10. package/dist/hls.light.mjs +219 -278
  11. package/dist/hls.light.mjs.map +1 -1
  12. package/dist/hls.min.js +1 -1
  13. package/dist/hls.min.js.map +1 -1
  14. package/dist/hls.mjs +350 -401
  15. package/dist/hls.mjs.map +1 -1
  16. package/dist/hls.worker.js +1 -1
  17. package/dist/hls.worker.js.map +1 -1
  18. package/package.json +9 -9
  19. package/src/controller/abr-controller.ts +2 -2
  20. package/src/controller/base-stream-controller.ts +16 -16
  21. package/src/controller/buffer-controller.ts +0 -6
  22. package/src/controller/eme-controller.ts +12 -6
  23. package/src/controller/latency-controller.ts +8 -7
  24. package/src/controller/level-controller.ts +18 -7
  25. package/src/controller/stream-controller.ts +14 -11
  26. package/src/controller/subtitle-stream-controller.ts +1 -6
  27. package/src/controller/subtitle-track-controller.ts +2 -4
  28. package/src/controller/timeline-controller.ts +26 -20
  29. package/src/crypt/aes-crypto.ts +2 -21
  30. package/src/crypt/decrypter.ts +18 -32
  31. package/src/crypt/fast-aes-key.ts +5 -24
  32. package/src/demux/audio/adts.ts +4 -9
  33. package/src/demux/sample-aes.ts +0 -2
  34. package/src/demux/transmuxer-interface.ts +12 -4
  35. package/src/demux/transmuxer.ts +3 -16
  36. package/src/demux/tsdemuxer.ts +17 -12
  37. package/src/loader/fragment-loader.ts +2 -9
  38. package/src/loader/key-loader.ts +0 -2
  39. package/src/loader/level-key.ts +9 -10
  40. package/src/remux/mp4-remuxer.ts +3 -4
  41. package/src/types/demuxer.ts +0 -1
  42. package/src/utils/codecs.ts +4 -33
  43. package/src/crypt/decrypter-aes-mode.ts +0 -4
  44. package/src/utils/encryption-methods-util.ts +0 -21
package/dist/hls.light.js CHANGED
@@ -521,7 +521,7 @@
521
521
  // Some browsers don't allow to use bind on console object anyway
522
522
  // fallback to default if needed
523
523
  try {
524
- exportedLogger.log("Debug logs enabled for \"" + id + "\" in hls.js version " + "1.5.2-0.canary.9923");
524
+ exportedLogger.log("Debug logs enabled for \"" + id + "\" in hls.js version " + "1.5.2");
525
525
  } catch (e) {
526
526
  exportedLogger = fakeLogger;
527
527
  }
@@ -1173,26 +1173,6 @@
1173
1173
  return LevelDetails;
1174
1174
  }();
1175
1175
 
1176
- var DecrypterAesMode = {
1177
- cbc: 0,
1178
- ctr: 1
1179
- };
1180
-
1181
- function isFullSegmentEncryption(method) {
1182
- return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
1183
- }
1184
- function getAesModeFromFullSegmentMethod(method) {
1185
- switch (method) {
1186
- case 'AES-128':
1187
- case 'AES-256':
1188
- return DecrypterAesMode.cbc;
1189
- case 'AES-256-CTR':
1190
- return DecrypterAesMode.ctr;
1191
- default:
1192
- throw new Error("invalid full segment method " + method);
1193
- }
1194
- }
1195
-
1196
1176
  // This file is inserted as a shim for modules which we do not want to include into the distro.
1197
1177
  // This replacement is done in the "alias" plugin of the rollup config.
1198
1178
  var empty = undefined;
@@ -2634,13 +2614,13 @@
2634
2614
  this.keyFormatVersions = formatversions;
2635
2615
  this.iv = iv;
2636
2616
  this.encrypted = method ? method !== 'NONE' : false;
2637
- this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2617
+ this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2638
2618
  }
2639
2619
  var _proto = LevelKey.prototype;
2640
2620
  _proto.isSupported = function isSupported() {
2641
2621
  // If it's Segment encryption or No encryption, just select that key system
2642
2622
  if (this.method) {
2643
- if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2623
+ if (this.method === 'AES-128' || this.method === 'NONE') {
2644
2624
  return true;
2645
2625
  }
2646
2626
  if (this.keyFormat === 'identity') {
@@ -2654,13 +2634,14 @@
2654
2634
  if (!this.encrypted || !this.uri) {
2655
2635
  return null;
2656
2636
  }
2657
- if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2637
+ if (this.method === 'AES-128' && this.uri && !this.iv) {
2658
2638
  if (typeof sn !== 'number') {
2659
2639
  // We are fetching decryption data for a initialization segment
2660
- // If the segment was encrypted with AES-128/256
2640
+ // If the segment was encrypted with AES-128
2661
2641
  // It must have an IV defined. We cannot substitute the Segment Number in.
2662
- logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2663
-
2642
+ if (this.method === 'AES-128' && !this.iv) {
2643
+ logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2644
+ }
2664
2645
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2665
2646
  sn = 0;
2666
2647
  }
@@ -2822,28 +2803,23 @@
2822
2803
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2823
2804
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2824
2805
  }
2806
+
2807
+ // Idealy fLaC and Opus would be first (spec-compliant) but
2808
+ // some browsers will report that fLaC is supported then fail.
2809
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2825
2810
  var codecsToCheck = {
2826
- // Idealy fLaC and Opus would be first (spec-compliant) but
2827
- // some browsers will report that fLaC is supported then fail.
2828
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2829
2811
  flac: ['flac', 'fLaC', 'FLAC'],
2830
- opus: ['opus', 'Opus'],
2831
- // Replace audio codec info if browser does not support mp4a.40.34,
2832
- // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
2833
- 'mp4a.40.34': ['mp3']
2812
+ opus: ['opus', 'Opus']
2834
2813
  }[lowerCaseCodec];
2835
2814
  for (var i = 0; i < codecsToCheck.length; i++) {
2836
- var _getMediaSource;
2837
2815
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2838
2816
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2839
2817
  return codecsToCheck[i];
2840
- } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2841
- return '';
2842
2818
  }
2843
2819
  }
2844
2820
  return lowerCaseCodec;
2845
2821
  }
2846
- var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2822
+ var AUDIO_CODEC_REGEXP = /flac|opus/i;
2847
2823
  function getCodecCompatibleName(codec, preferManagedMediaSource) {
2848
2824
  if (preferManagedMediaSource === void 0) {
2849
2825
  preferManagedMediaSource = true;
@@ -2871,18 +2847,6 @@
2871
2847
  }
2872
2848
  return codec;
2873
2849
  }
2874
- function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2875
- var MediaSource = getMediaSource(preferManagedMediaSource) || {
2876
- isTypeSupported: function isTypeSupported() {
2877
- return false;
2878
- }
2879
- };
2880
- return {
2881
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
2882
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
2883
- ac3: false
2884
- };
2885
- }
2886
2850
 
2887
2851
  var MASTER_PLAYLIST_REGEX = /#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-(SESSION-DATA|SESSION-KEY|DEFINE|CONTENT-STEERING|START):([^\r\n]*)[\r\n]+/g;
2888
2852
  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -4457,43 +4421,8 @@
4457
4421
  this.currentTime = 0;
4458
4422
  this.stallCount = 0;
4459
4423
  this._latency = null;
4460
- this.onTimeupdate = function () {
4461
- var media = _this.media,
4462
- levelDetails = _this.levelDetails;
4463
- if (!media || !levelDetails) {
4464
- return;
4465
- }
4466
- _this.currentTime = media.currentTime;
4467
- var latency = _this.computeLatency();
4468
- if (latency === null) {
4469
- return;
4470
- }
4471
- _this._latency = latency;
4472
-
4473
- // Adapt playbackRate to meet target latency in low-latency mode
4474
- var _this$config = _this.config,
4475
- lowLatencyMode = _this$config.lowLatencyMode,
4476
- maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4477
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4478
- return;
4479
- }
4480
- var targetLatency = _this.targetLatency;
4481
- if (targetLatency === null) {
4482
- return;
4483
- }
4484
- var distanceFromTarget = latency - targetLatency;
4485
- // Only adjust playbackRate when within one target duration of targetLatency
4486
- // and more than one second from under-buffering.
4487
- // Playback further than one target duration from target can be considered DVR playback.
4488
- var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
4489
- var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4490
- if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
4491
- var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4492
- var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
4493
- media.playbackRate = Math.min(max, Math.max(1, rate));
4494
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4495
- media.playbackRate = 1;
4496
- }
4424
+ this.timeupdateHandler = function () {
4425
+ return _this.timeupdate();
4497
4426
  };
4498
4427
  this.hls = hls;
4499
4428
  this.config = hls.config;
@@ -4505,7 +4434,7 @@
4505
4434
  this.onMediaDetaching();
4506
4435
  this.levelDetails = null;
4507
4436
  // @ts-ignore
4508
- this.hls = this.onTimeupdate = null;
4437
+ this.hls = this.timeupdateHandler = null;
4509
4438
  };
4510
4439
  _proto.registerListeners = function registerListeners() {
4511
4440
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4523,11 +4452,11 @@
4523
4452
  };
4524
4453
  _proto.onMediaAttached = function onMediaAttached(event, data) {
4525
4454
  this.media = data.media;
4526
- this.media.addEventListener('timeupdate', this.onTimeupdate);
4455
+ this.media.addEventListener('timeupdate', this.timeupdateHandler);
4527
4456
  };
4528
4457
  _proto.onMediaDetaching = function onMediaDetaching() {
4529
4458
  if (this.media) {
4530
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4459
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4531
4460
  this.media = null;
4532
4461
  }
4533
4462
  };
@@ -4540,10 +4469,10 @@
4540
4469
  var details = _ref.details;
4541
4470
  this.levelDetails = details;
4542
4471
  if (details.advanced) {
4543
- this.onTimeupdate();
4472
+ this.timeupdate();
4544
4473
  }
4545
4474
  if (!details.live && this.media) {
4546
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4475
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4547
4476
  }
4548
4477
  };
4549
4478
  _proto.onError = function onError(event, data) {
@@ -4556,6 +4485,44 @@
4556
4485
  logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
4557
4486
  }
4558
4487
  };
4488
+ _proto.timeupdate = function timeupdate() {
4489
+ var media = this.media,
4490
+ levelDetails = this.levelDetails;
4491
+ if (!media || !levelDetails) {
4492
+ return;
4493
+ }
4494
+ this.currentTime = media.currentTime;
4495
+ var latency = this.computeLatency();
4496
+ if (latency === null) {
4497
+ return;
4498
+ }
4499
+ this._latency = latency;
4500
+
4501
+ // Adapt playbackRate to meet target latency in low-latency mode
4502
+ var _this$config = this.config,
4503
+ lowLatencyMode = _this$config.lowLatencyMode,
4504
+ maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4505
+ if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4506
+ return;
4507
+ }
4508
+ var targetLatency = this.targetLatency;
4509
+ if (targetLatency === null) {
4510
+ return;
4511
+ }
4512
+ var distanceFromTarget = latency - targetLatency;
4513
+ // Only adjust playbackRate when within one target duration of targetLatency
4514
+ // and more than one second from under-buffering.
4515
+ // Playback further than one target duration from target can be considered DVR playback.
4516
+ var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4517
+ var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4518
+ if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4519
+ var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4520
+ var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4521
+ media.playbackRate = Math.min(max, Math.max(1, rate));
4522
+ } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4523
+ media.playbackRate = 1;
4524
+ }
4525
+ };
4559
4526
  _proto.estimateLiveEdge = function estimateLiveEdge() {
4560
4527
  var levelDetails = this.levelDetails;
4561
4528
  if (levelDetails === null) {
@@ -6507,7 +6474,7 @@
6507
6474
  var bwEstimate = _this.getBwEstimate();
6508
6475
  var levels = hls.levels;
6509
6476
  var level = levels[frag.level];
6510
- var expectedLen = stats.total || Math.max(stats.loaded, Math.round(duration * level.maxBitrate / 8));
6477
+ var expectedLen = stats.total || Math.max(stats.loaded, Math.round(duration * level.averageBitrate / 8));
6511
6478
  var timeStreaming = loadedFirstByte ? timeLoading - ttfb : timeLoading;
6512
6479
  if (timeStreaming < 1 && loadedFirstByte) {
6513
6480
  timeStreaming = Math.min(timeLoading, stats.loaded * 8 / bwEstimate);
@@ -6550,7 +6517,7 @@
6550
6517
  // If there has been no loading progress, sample TTFB
6551
6518
  _this.bwEstimator.sampleTTFB(timeLoading);
6552
6519
  }
6553
- var nextLoadLevelBitrate = levels[nextLoadLevel].bitrate;
6520
+ var nextLoadLevelBitrate = levels[nextLoadLevel].maxBitrate;
6554
6521
  if (_this.getBwEstimate() * _this.hls.config.abrBandWidthUpFactor > nextLoadLevelBitrate) {
6555
6522
  _this.resetEstimator(nextLoadLevelBitrate);
6556
6523
  }
@@ -7341,12 +7308,6 @@
7341
7308
  this.lastMpegAudioChunk = null;
7342
7309
  // @ts-ignore
7343
7310
  this.hls = null;
7344
- // @ts-ignore
7345
- this._onMediaSourceOpen = this._onMediaSourceClose = null;
7346
- // @ts-ignore
7347
- this._onMediaSourceEnded = null;
7348
- // @ts-ignore
7349
- this._onStartStreaming = this._onEndStreaming = null;
7350
7311
  };
7351
7312
  _proto.registerListeners = function registerListeners() {
7352
7313
  var hls = this.hls;
@@ -9905,6 +9866,7 @@
9905
9866
  }
9906
9867
  }
9907
9868
 
9869
+ var chromeOrFirefox;
9908
9870
  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
9909
9871
  _inheritsLoose(LevelController, _BasePlaylistControll);
9910
9872
  function LevelController(hls, contentSteeringController) {
@@ -9978,13 +9940,21 @@
9978
9940
  var videoCodecFound = false;
9979
9941
  var audioCodecFound = false;
9980
9942
  data.levels.forEach(function (levelParsed) {
9981
- var _videoCodec;
9943
+ var _audioCodec, _videoCodec;
9982
9944
  var attributes = levelParsed.attrs;
9945
+
9946
+ // erase audio codec info if browser does not support mp4a.40.34.
9947
+ // demuxer will autodetect codec and fallback to mpeg/audio
9983
9948
  var audioCodec = levelParsed.audioCodec,
9984
9949
  videoCodec = levelParsed.videoCodec;
9950
+ if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
9951
+ chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
9952
+ if (chromeOrFirefox) {
9953
+ levelParsed.audioCodec = audioCodec = undefined;
9954
+ }
9955
+ }
9985
9956
  if (audioCodec) {
9986
- // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
9987
- levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
9957
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
9988
9958
  }
9989
9959
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
9990
9960
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -10107,8 +10077,8 @@
10107
10077
  return _valueB - _valueA;
10108
10078
  }
10109
10079
  }
10110
- if (a.bitrate !== b.bitrate) {
10111
- return a.bitrate - b.bitrate;
10080
+ if (a.averageBitrate !== b.averageBitrate) {
10081
+ return a.averageBitrate - b.averageBitrate;
10112
10082
  }
10113
10083
  return 0;
10114
10084
  });
@@ -11131,8 +11101,8 @@
11131
11101
  var _frag$decryptdata;
11132
11102
  var byteRangeStart = start;
11133
11103
  var byteRangeEnd = end;
11134
- if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
11135
- // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
11104
+ if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
11105
+ // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
11136
11106
  // has the unencrypted size specified in the range.
11137
11107
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
11138
11108
  var fragmentLen = end - start;
@@ -11165,9 +11135,6 @@
11165
11135
  (part ? part : frag).stats.aborted = true;
11166
11136
  return new LoadError(errorData);
11167
11137
  }
11168
- function isMethodFullSegmentAesCbc(method) {
11169
- return method === 'AES-128' || method === 'AES-256';
11170
- }
11171
11138
  var LoadError = /*#__PURE__*/function (_Error) {
11172
11139
  _inheritsLoose(LoadError, _Error);
11173
11140
  function LoadError(data) {
@@ -11324,8 +11291,6 @@
11324
11291
  }
11325
11292
  return this.loadKeyEME(keyInfo, frag);
11326
11293
  case 'AES-128':
11327
- case 'AES-256':
11328
- case 'AES-256-CTR':
11329
11294
  return this.loadKeyHTTP(keyInfo, frag);
11330
11295
  default:
11331
11296
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
@@ -11737,65 +11702,37 @@
11737
11702
  }
11738
11703
 
11739
11704
  var AESCrypto = /*#__PURE__*/function () {
11740
- function AESCrypto(subtle, iv, aesMode) {
11705
+ function AESCrypto(subtle, iv) {
11741
11706
  this.subtle = void 0;
11742
11707
  this.aesIV = void 0;
11743
- this.aesMode = void 0;
11744
11708
  this.subtle = subtle;
11745
11709
  this.aesIV = iv;
11746
- this.aesMode = aesMode;
11747
11710
  }
11748
11711
  var _proto = AESCrypto.prototype;
11749
11712
  _proto.decrypt = function decrypt(data, key) {
11750
- switch (this.aesMode) {
11751
- case DecrypterAesMode.cbc:
11752
- return this.subtle.decrypt({
11753
- name: 'AES-CBC',
11754
- iv: this.aesIV
11755
- }, key, data);
11756
- case DecrypterAesMode.ctr:
11757
- return this.subtle.decrypt({
11758
- name: 'AES-CTR',
11759
- counter: this.aesIV,
11760
- length: 64
11761
- },
11762
- //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
11763
- key, data);
11764
- default:
11765
- throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
11766
- }
11713
+ return this.subtle.decrypt({
11714
+ name: 'AES-CBC',
11715
+ iv: this.aesIV
11716
+ }, key, data);
11767
11717
  };
11768
11718
  return AESCrypto;
11769
11719
  }();
11770
11720
 
11771
11721
  var FastAESKey = /*#__PURE__*/function () {
11772
- function FastAESKey(subtle, key, aesMode) {
11722
+ function FastAESKey(subtle, key) {
11773
11723
  this.subtle = void 0;
11774
11724
  this.key = void 0;
11775
- this.aesMode = void 0;
11776
11725
  this.subtle = subtle;
11777
11726
  this.key = key;
11778
- this.aesMode = aesMode;
11779
11727
  }
11780
11728
  var _proto = FastAESKey.prototype;
11781
11729
  _proto.expandKey = function expandKey() {
11782
- var subtleAlgoName = getSubtleAlgoName(this.aesMode);
11783
11730
  return this.subtle.importKey('raw', this.key, {
11784
- name: subtleAlgoName
11731
+ name: 'AES-CBC'
11785
11732
  }, false, ['encrypt', 'decrypt']);
11786
11733
  };
11787
11734
  return FastAESKey;
11788
11735
  }();
11789
- function getSubtleAlgoName(aesMode) {
11790
- switch (aesMode) {
11791
- case DecrypterAesMode.cbc:
11792
- return 'AES-CBC';
11793
- case DecrypterAesMode.ctr:
11794
- return 'AES-CTR';
11795
- default:
11796
- throw new Error("[FastAESKey] invalid aes mode " + aesMode);
11797
- }
11798
- }
11799
11736
 
11800
11737
  // PKCS7
11801
11738
  function removePadding(array) {
@@ -12048,8 +11985,7 @@
12048
11985
  this.currentIV = null;
12049
11986
  this.currentResult = null;
12050
11987
  this.useSoftware = void 0;
12051
- this.enableSoftwareAES = void 0;
12052
- this.enableSoftwareAES = config.enableSoftwareAES;
11988
+ this.useSoftware = config.enableSoftwareAES;
12053
11989
  this.removePKCS7Padding = removePKCS7Padding;
12054
11990
  // built in decryptor expects PKCS7 padding
12055
11991
  if (removePKCS7Padding) {
@@ -12062,7 +11998,9 @@
12062
11998
  /* no-op */
12063
11999
  }
12064
12000
  }
12065
- this.useSoftware = this.subtle === null;
12001
+ if (this.subtle === null) {
12002
+ this.useSoftware = true;
12003
+ }
12066
12004
  }
12067
12005
  var _proto = Decrypter.prototype;
12068
12006
  _proto.destroy = function destroy() {
@@ -12099,11 +12037,11 @@
12099
12037
  this.softwareDecrypter = null;
12100
12038
  }
12101
12039
  };
12102
- _proto.decrypt = function decrypt(data, key, iv, aesMode) {
12040
+ _proto.decrypt = function decrypt(data, key, iv) {
12103
12041
  var _this = this;
12104
12042
  if (this.useSoftware) {
12105
12043
  return new Promise(function (resolve, reject) {
12106
- _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
12044
+ _this.softwareDecrypt(new Uint8Array(data), key, iv);
12107
12045
  var decryptResult = _this.flush();
12108
12046
  if (decryptResult) {
12109
12047
  resolve(decryptResult.buffer);
@@ -12112,20 +12050,16 @@
12112
12050
  }
12113
12051
  });
12114
12052
  }
12115
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
12053
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
12116
12054
  }
12117
12055
 
12118
12056
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
12119
12057
  // data is handled in the flush() call
12120
12058
  ;
12121
- _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
12059
+ _proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
12122
12060
  var currentIV = this.currentIV,
12123
12061
  currentResult = this.currentResult,
12124
12062
  remainderData = this.remainderData;
12125
- if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
12126
- logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
12127
- return null;
12128
- }
12129
12063
  this.logOnce('JS AES decrypt');
12130
12064
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
12131
12065
  // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
@@ -12158,12 +12092,12 @@
12158
12092
  }
12159
12093
  return result;
12160
12094
  };
12161
- _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
12095
+ _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
12162
12096
  var _this2 = this;
12163
12097
  var subtle = this.subtle;
12164
12098
  if (this.key !== key || !this.fastAesKey) {
12165
12099
  this.key = key;
12166
- this.fastAesKey = new FastAESKey(subtle, key, aesMode);
12100
+ this.fastAesKey = new FastAESKey(subtle, key);
12167
12101
  }
12168
12102
  return this.fastAesKey.expandKey().then(function (aesKey) {
12169
12103
  // decrypt using web crypto
@@ -12171,25 +12105,22 @@
12171
12105
  return Promise.reject(new Error('web crypto not initialized'));
12172
12106
  }
12173
12107
  _this2.logOnce('WebCrypto AES decrypt');
12174
- var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
12108
+ var crypto = new AESCrypto(subtle, new Uint8Array(iv));
12175
12109
  return crypto.decrypt(data.buffer, aesKey);
12176
12110
  }).catch(function (err) {
12177
12111
  logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
12178
- return _this2.onWebCryptoError(data, key, iv, aesMode);
12112
+ return _this2.onWebCryptoError(data, key, iv);
12179
12113
  });
12180
12114
  };
12181
- _proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
12182
- var enableSoftwareAES = this.enableSoftwareAES;
12183
- if (enableSoftwareAES) {
12184
- this.useSoftware = true;
12185
- this.logEnabled = true;
12186
- this.softwareDecrypt(data, key, iv, aesMode);
12187
- var decryptResult = this.flush();
12188
- if (decryptResult) {
12189
- return decryptResult.buffer;
12190
- }
12115
+ _proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
12116
+ this.useSoftware = true;
12117
+ this.logEnabled = true;
12118
+ this.softwareDecrypt(data, key, iv);
12119
+ var decryptResult = this.flush();
12120
+ if (decryptResult) {
12121
+ return decryptResult.buffer;
12191
12122
  }
12192
- throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
12123
+ throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
12193
12124
  };
12194
12125
  _proto.getValidChunk = function getValidChunk(data) {
12195
12126
  var currentChunk = data;
@@ -12268,58 +12199,11 @@
12268
12199
  _this.startFragRequested = false;
12269
12200
  _this.decrypter = void 0;
12270
12201
  _this.initPTS = [];
12202
+ _this.onvseeking = null;
12203
+ _this.onvended = null;
12271
12204
  _this.logPrefix = '';
12272
12205
  _this.log = void 0;
12273
12206
  _this.warn = void 0;
12274
- _this.onMediaSeeking = function () {
12275
- var _assertThisInitialize = _assertThisInitialized(_this),
12276
- config = _assertThisInitialize.config,
12277
- fragCurrent = _assertThisInitialize.fragCurrent,
12278
- media = _assertThisInitialize.media,
12279
- mediaBuffer = _assertThisInitialize.mediaBuffer,
12280
- state = _assertThisInitialize.state;
12281
- var currentTime = media ? media.currentTime : 0;
12282
- var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12283
- _this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12284
- if (_this.state === State.ENDED) {
12285
- _this.resetLoadingState();
12286
- } else if (fragCurrent) {
12287
- // Seeking while frag load is in progress
12288
- var tolerance = config.maxFragLookUpTolerance;
12289
- var fragStartOffset = fragCurrent.start - tolerance;
12290
- var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12291
- // if seeking out of buffered range or into new one
12292
- if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12293
- var pastFragment = currentTime > fragEndOffset;
12294
- // if the seek position is outside the current fragment range
12295
- if (currentTime < fragStartOffset || pastFragment) {
12296
- if (pastFragment && fragCurrent.loader) {
12297
- _this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12298
- fragCurrent.abortRequests();
12299
- _this.resetLoadingState();
12300
- }
12301
- _this.fragPrevious = null;
12302
- }
12303
- }
12304
- }
12305
- if (media) {
12306
- // Remove gap fragments
12307
- _this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
12308
- _this.lastCurrentTime = currentTime;
12309
- }
12310
-
12311
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12312
- if (!_this.loadedmetadata && !bufferInfo.len) {
12313
- _this.nextLoadPosition = _this.startPosition = currentTime;
12314
- }
12315
-
12316
- // Async tick to speed up processing
12317
- _this.tickImmediate();
12318
- };
12319
- _this.onMediaEnded = function () {
12320
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12321
- _this.startPosition = _this.lastCurrentTime = 0;
12322
- };
12323
12207
  _this.playlistType = playlistType;
12324
12208
  _this.logPrefix = logPrefix;
12325
12209
  _this.log = logger.log.bind(logger, logPrefix + ":");
@@ -12387,8 +12271,10 @@
12387
12271
  };
12388
12272
  _proto.onMediaAttached = function onMediaAttached(event, data) {
12389
12273
  var media = this.media = this.mediaBuffer = data.media;
12390
- media.addEventListener('seeking', this.onMediaSeeking);
12391
- media.addEventListener('ended', this.onMediaEnded);
12274
+ this.onvseeking = this.onMediaSeeking.bind(this);
12275
+ this.onvended = this.onMediaEnded.bind(this);
12276
+ media.addEventListener('seeking', this.onvseeking);
12277
+ media.addEventListener('ended', this.onvended);
12392
12278
  var config = this.config;
12393
12279
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12394
12280
  this.startLoad(config.startPosition);
@@ -12402,9 +12288,10 @@
12402
12288
  }
12403
12289
 
12404
12290
  // remove video listeners
12405
- if (media) {
12406
- media.removeEventListener('seeking', this.onMediaSeeking);
12407
- media.removeEventListener('ended', this.onMediaEnded);
12291
+ if (media && this.onvseeking && this.onvended) {
12292
+ media.removeEventListener('seeking', this.onvseeking);
12293
+ media.removeEventListener('ended', this.onvended);
12294
+ this.onvseeking = this.onvended = null;
12408
12295
  }
12409
12296
  if (this.keyLoader) {
12410
12297
  this.keyLoader.detach();
@@ -12414,6 +12301,54 @@
12414
12301
  this.fragmentTracker.removeAllFragments();
12415
12302
  this.stopLoad();
12416
12303
  };
12304
+ _proto.onMediaSeeking = function onMediaSeeking() {
12305
+ var config = this.config,
12306
+ fragCurrent = this.fragCurrent,
12307
+ media = this.media,
12308
+ mediaBuffer = this.mediaBuffer,
12309
+ state = this.state;
12310
+ var currentTime = media ? media.currentTime : 0;
12311
+ var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12312
+ this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12313
+ if (this.state === State.ENDED) {
12314
+ this.resetLoadingState();
12315
+ } else if (fragCurrent) {
12316
+ // Seeking while frag load is in progress
12317
+ var tolerance = config.maxFragLookUpTolerance;
12318
+ var fragStartOffset = fragCurrent.start - tolerance;
12319
+ var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12320
+ // if seeking out of buffered range or into new one
12321
+ if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12322
+ var pastFragment = currentTime > fragEndOffset;
12323
+ // if the seek position is outside the current fragment range
12324
+ if (currentTime < fragStartOffset || pastFragment) {
12325
+ if (pastFragment && fragCurrent.loader) {
12326
+ this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12327
+ fragCurrent.abortRequests();
12328
+ this.resetLoadingState();
12329
+ }
12330
+ this.fragPrevious = null;
12331
+ }
12332
+ }
12333
+ }
12334
+ if (media) {
12335
+ // Remove gap fragments
12336
+ this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
12337
+ this.lastCurrentTime = currentTime;
12338
+ }
12339
+
12340
+ // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12341
+ if (!this.loadedmetadata && !bufferInfo.len) {
12342
+ this.nextLoadPosition = this.startPosition = currentTime;
12343
+ }
12344
+
12345
+ // Async tick to speed up processing
12346
+ this.tickImmediate();
12347
+ };
12348
+ _proto.onMediaEnded = function onMediaEnded() {
12349
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12350
+ this.startPosition = this.lastCurrentTime = 0;
12351
+ };
12417
12352
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
12418
12353
  this.startTimeOffset = data.startTimeOffset;
12419
12354
  this.initPTS = [];
@@ -12423,7 +12358,7 @@
12423
12358
  this.stopLoad();
12424
12359
  _TaskLoop.prototype.onHandlerDestroying.call(this);
12425
12360
  // @ts-ignore
12426
- this.hls = this.onMediaSeeking = this.onMediaEnded = null;
12361
+ this.hls = null;
12427
12362
  };
12428
12363
  _proto.onHandlerDestroyed = function onHandlerDestroyed() {
12429
12364
  this.state = State.STOPPED;
@@ -12553,10 +12488,10 @@
12553
12488
  var decryptData = frag.decryptdata;
12554
12489
 
12555
12490
  // check to see if the payload needs to be decrypted
12556
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
12491
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
12557
12492
  var startTime = self.performance.now();
12558
12493
  // decrypt init segment data
12559
- return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
12494
+ return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
12560
12495
  hls.trigger(Events.ERROR, {
12561
12496
  type: ErrorTypes.MEDIA_ERROR,
12562
12497
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -13684,7 +13619,6 @@
13684
13619
  */
13685
13620
  function getAudioConfig(observer, data, offset, audioCodec) {
13686
13621
  var adtsObjectType;
13687
- var originalAdtsObjectType;
13688
13622
  var adtsExtensionSamplingIndex;
13689
13623
  var adtsChannelConfig;
13690
13624
  var config;
@@ -13692,7 +13626,7 @@
13692
13626
  var manifestCodec = audioCodec;
13693
13627
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
13694
13628
  // byte 2
13695
- adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13629
+ adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13696
13630
  var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
13697
13631
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
13698
13632
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
@@ -13709,8 +13643,8 @@
13709
13643
  // byte 3
13710
13644
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
13711
13645
  logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
13712
- // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
13713
- if (/firefox|palemoon/i.test(userAgent)) {
13646
+ // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
13647
+ if (/firefox/i.test(userAgent)) {
13714
13648
  if (adtsSamplingIndex >= 6) {
13715
13649
  adtsObjectType = 5;
13716
13650
  config = new Array(4);
@@ -13804,7 +13738,6 @@
13804
13738
  samplerate: adtsSamplingRates[adtsSamplingIndex],
13805
13739
  channelCount: adtsChannelConfig,
13806
13740
  codec: 'mp4a.40.' + adtsObjectType,
13807
- parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
13808
13741
  manifestCodec: manifestCodec
13809
13742
  };
13810
13743
  }
@@ -13859,8 +13792,7 @@
13859
13792
  track.channelCount = config.channelCount;
13860
13793
  track.codec = config.codec;
13861
13794
  track.manifestCodec = config.manifestCodec;
13862
- track.parsedCodec = config.parsedCodec;
13863
- logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13795
+ logger.log("parsed codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13864
13796
  }
13865
13797
  }
13866
13798
  function getFrameDuration(samplerate) {
@@ -14947,7 +14879,7 @@
14947
14879
  }
14948
14880
  var _proto = SampleAesDecrypter.prototype;
14949
14881
  _proto.decryptBuffer = function decryptBuffer(encryptedData) {
14950
- return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
14882
+ return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
14951
14883
  }
14952
14884
 
14953
14885
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -17176,7 +17108,7 @@
17176
17108
  logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
17177
17109
  for (var j = 0; j < missing; j++) {
17178
17110
  var newStamp = Math.max(nextPts, 0);
17179
- var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17111
+ var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17180
17112
  if (!fillFrame) {
17181
17113
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17182
17114
  fillFrame = sample.unit.subarray();
@@ -17304,7 +17236,7 @@
17304
17236
  // samples count of this segment's duration
17305
17237
  var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
17306
17238
  // silent frame
17307
- var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17239
+ var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17308
17240
  logger.warn('[mp4-remuxer]: remux empty Audio');
17309
17241
  // Can't remux if we can't generate a silent frame...
17310
17242
  if (!silentFrame) {
@@ -17691,15 +17623,13 @@
17691
17623
  duration = transmuxConfig.duration,
17692
17624
  initSegmentData = transmuxConfig.initSegmentData;
17693
17625
  var keyData = getEncryptionType(uintData, decryptdata);
17694
- if (keyData && isFullSegmentEncryption(keyData.method)) {
17626
+ if (keyData && keyData.method === 'AES-128') {
17695
17627
  var decrypter = this.getDecrypter();
17696
- var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
17697
-
17698
17628
  // Software decryption is synchronous; webCrypto is not
17699
17629
  if (decrypter.isSync()) {
17700
17630
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
17701
17631
  // data is handled in the flush() call
17702
- var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
17632
+ var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
17703
17633
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
17704
17634
  var loadingParts = chunkMeta.part > -1;
17705
17635
  if (loadingParts) {
@@ -17711,7 +17641,7 @@
17711
17641
  }
17712
17642
  uintData = new Uint8Array(decryptedData);
17713
17643
  } else {
17714
- this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
17644
+ this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
17715
17645
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
17716
17646
  // the decrypted data has been transmuxed
17717
17647
  var result = _this.push(decryptedData, null, chunkMeta);
@@ -18528,7 +18458,16 @@
18528
18458
  this.observer = new EventEmitter();
18529
18459
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
18530
18460
  this.observer.on(Events.ERROR, forwardMessage);
18531
- var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
18461
+ var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
18462
+ isTypeSupported: function isTypeSupported() {
18463
+ return false;
18464
+ }
18465
+ };
18466
+ var m2tsTypeSupported = {
18467
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
18468
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
18469
+ ac3: false
18470
+ };
18532
18471
 
18533
18472
  // navigator.vendor is not always available in Web Worker
18534
18473
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -19106,32 +19045,13 @@
19106
19045
  _this.altAudio = false;
19107
19046
  _this.audioOnly = false;
19108
19047
  _this.fragPlaying = null;
19048
+ _this.onvplaying = null;
19049
+ _this.onvseeked = null;
19109
19050
  _this.fragLastKbps = 0;
19110
19051
  _this.couldBacktrack = false;
19111
19052
  _this.backtrackFragment = null;
19112
19053
  _this.audioCodecSwitch = false;
19113
19054
  _this.videoBuffer = null;
19114
- _this.onMediaPlaying = function () {
19115
- // tick to speed up FRAG_CHANGED triggering
19116
- _this.tick();
19117
- };
19118
- _this.onMediaSeeked = function () {
19119
- var media = _this.media;
19120
- var currentTime = media ? media.currentTime : null;
19121
- if (isFiniteNumber(currentTime)) {
19122
- _this.log("Media seeked to " + currentTime.toFixed(3));
19123
- }
19124
-
19125
- // If seeked was issued before buffer was appended do not tick immediately
19126
- var bufferInfo = _this.getMainFwdBufferInfo();
19127
- if (bufferInfo === null || bufferInfo.len === 0) {
19128
- _this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19129
- return;
19130
- }
19131
-
19132
- // tick to speed up FRAG_CHANGED triggering
19133
- _this.tick();
19134
- };
19135
19055
  _this._registerListeners();
19136
19056
  return _this;
19137
19057
  }
@@ -19171,8 +19091,6 @@
19171
19091
  };
19172
19092
  _proto.onHandlerDestroying = function onHandlerDestroying() {
19173
19093
  this._unregisterListeners();
19174
- // @ts-ignore
19175
- this.onMediaPlaying = this.onMediaSeeked = null;
19176
19094
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
19177
19095
  };
19178
19096
  _proto.startLoad = function startLoad(startPosition) {
@@ -19487,15 +19405,18 @@
19487
19405
  _proto.onMediaAttached = function onMediaAttached(event, data) {
19488
19406
  _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
19489
19407
  var media = data.media;
19490
- media.addEventListener('playing', this.onMediaPlaying);
19491
- media.addEventListener('seeked', this.onMediaSeeked);
19408
+ this.onvplaying = this.onMediaPlaying.bind(this);
19409
+ this.onvseeked = this.onMediaSeeked.bind(this);
19410
+ media.addEventListener('playing', this.onvplaying);
19411
+ media.addEventListener('seeked', this.onvseeked);
19492
19412
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
19493
19413
  };
19494
19414
  _proto.onMediaDetaching = function onMediaDetaching() {
19495
19415
  var media = this.media;
19496
- if (media) {
19497
- media.removeEventListener('playing', this.onMediaPlaying);
19498
- media.removeEventListener('seeked', this.onMediaSeeked);
19416
+ if (media && this.onvplaying && this.onvseeked) {
19417
+ media.removeEventListener('playing', this.onvplaying);
19418
+ media.removeEventListener('seeked', this.onvseeked);
19419
+ this.onvplaying = this.onvseeked = null;
19499
19420
  this.videoBuffer = null;
19500
19421
  }
19501
19422
  this.fragPlaying = null;
@@ -19505,6 +19426,27 @@
19505
19426
  }
19506
19427
  _BaseStreamController.prototype.onMediaDetaching.call(this);
19507
19428
  };
19429
+ _proto.onMediaPlaying = function onMediaPlaying() {
19430
+ // tick to speed up FRAG_CHANGED triggering
19431
+ this.tick();
19432
+ };
19433
+ _proto.onMediaSeeked = function onMediaSeeked() {
19434
+ var media = this.media;
19435
+ var currentTime = media ? media.currentTime : null;
19436
+ if (isFiniteNumber(currentTime)) {
19437
+ this.log("Media seeked to " + currentTime.toFixed(3));
19438
+ }
19439
+
19440
+ // If seeked was issued before buffer was appended do not tick immediately
19441
+ var bufferInfo = this.getMainFwdBufferInfo();
19442
+ if (bufferInfo === null || bufferInfo.len === 0) {
19443
+ this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19444
+ return;
19445
+ }
19446
+
19447
+ // tick to speed up FRAG_CHANGED triggering
19448
+ this.tick();
19449
+ };
19508
19450
  _proto.onManifestLoading = function onManifestLoading() {
19509
19451
  // reset buffer on manifest loading
19510
19452
  this.log('Trigger BUFFER_RESET');
@@ -21078,7 +21020,7 @@
21078
21020
  * Get the video-dev/hls.js package version.
21079
21021
  */
21080
21022
  function get() {
21081
- return "1.5.2-0.canary.9923";
21023
+ return "1.5.2";
21082
21024
  }
21083
21025
  }, {
21084
21026
  key: "Events",