hls.js 1.5.7-0.canary.10040 → 1.5.7

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 (72) hide show
  1. package/README.md +1 -2
  2. package/dist/hls-demo.js +0 -10
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1283 -2293
  5. package/dist/hls.js.d.ts +84 -97
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1030 -1435
  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 +809 -1209
  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 +1039 -2030
  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 +22 -22
  20. package/src/config.ts +2 -3
  21. package/src/controller/abr-controller.ts +20 -24
  22. package/src/controller/audio-stream-controller.ts +74 -68
  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 +36 -157
  26. package/src/controller/buffer-controller.ts +99 -226
  27. package/src/controller/buffer-operation-queue.ts +19 -16
  28. package/src/controller/cap-level-controller.ts +2 -2
  29. package/src/controller/cmcd-controller.ts +6 -27
  30. package/src/controller/content-steering-controller.ts +6 -8
  31. package/src/controller/eme-controller.ts +22 -9
  32. package/src/controller/error-controller.ts +8 -6
  33. package/src/controller/fps-controller.ts +3 -2
  34. package/src/controller/fragment-tracker.ts +11 -15
  35. package/src/controller/gap-controller.ts +16 -43
  36. package/src/controller/latency-controller.ts +11 -9
  37. package/src/controller/level-controller.ts +18 -12
  38. package/src/controller/stream-controller.ts +31 -36
  39. package/src/controller/subtitle-stream-controller.ts +40 -28
  40. package/src/controller/subtitle-track-controller.ts +3 -5
  41. package/src/controller/timeline-controller.ts +30 -23
  42. package/src/crypt/aes-crypto.ts +2 -21
  43. package/src/crypt/decrypter.ts +18 -32
  44. package/src/crypt/fast-aes-key.ts +5 -24
  45. package/src/demux/audio/adts.ts +4 -9
  46. package/src/demux/sample-aes.ts +0 -2
  47. package/src/demux/transmuxer-interface.ts +12 -4
  48. package/src/demux/transmuxer-worker.ts +4 -4
  49. package/src/demux/transmuxer.ts +3 -16
  50. package/src/demux/tsdemuxer.ts +37 -71
  51. package/src/demux/video/avc-video-parser.ts +119 -208
  52. package/src/demux/video/base-video-parser.ts +2 -134
  53. package/src/demux/video/exp-golomb.ts +208 -0
  54. package/src/events.ts +0 -7
  55. package/src/hls.ts +37 -49
  56. package/src/loader/fragment-loader.ts +2 -9
  57. package/src/loader/key-loader.ts +0 -2
  58. package/src/loader/level-key.ts +9 -10
  59. package/src/loader/playlist-loader.ts +5 -4
  60. package/src/remux/mp4-generator.ts +1 -196
  61. package/src/remux/mp4-remuxer.ts +7 -23
  62. package/src/task-loop.ts +2 -5
  63. package/src/types/component-api.ts +0 -2
  64. package/src/types/demuxer.ts +0 -3
  65. package/src/types/events.ts +0 -4
  66. package/src/utils/buffer-helper.ts +31 -12
  67. package/src/utils/codecs.ts +5 -34
  68. package/src/utils/logger.ts +24 -54
  69. package/src/utils/mp4-tools.ts +2 -4
  70. package/src/crypt/decrypter-aes-mode.ts +0 -4
  71. package/src/demux/video/hevc-video-parser.ts +0 -746
  72. package/src/utils/encryption-methods-util.ts +0 -21
package/dist/hls.light.js CHANGED
@@ -5,21 +5,6 @@
5
5
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Hls = factory());
6
6
  })(this, (function () { 'use strict';
7
7
 
8
- function _construct(t, e, r) {
9
- if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
10
- var o = [null];
11
- o.push.apply(o, e);
12
- var p = new (t.bind.apply(t, o))();
13
- return r && _setPrototypeOf(p, r.prototype), p;
14
- }
15
- function _isNativeReflectConstruct() {
16
- try {
17
- var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
18
- } catch (t) {}
19
- return (_isNativeReflectConstruct = function () {
20
- return !!t;
21
- })();
22
- }
23
8
  function ownKeys(e, r) {
24
9
  var t = Object.keys(e);
25
10
  if (Object.getOwnPropertySymbols) {
@@ -118,6 +103,32 @@
118
103
  };
119
104
  return _setPrototypeOf(o, p);
120
105
  }
106
+ function _isNativeReflectConstruct() {
107
+ if (typeof Reflect === "undefined" || !Reflect.construct) return false;
108
+ if (Reflect.construct.sham) return false;
109
+ if (typeof Proxy === "function") return true;
110
+ try {
111
+ Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
112
+ return true;
113
+ } catch (e) {
114
+ return false;
115
+ }
116
+ }
117
+ function _construct(Parent, args, Class) {
118
+ if (_isNativeReflectConstruct()) {
119
+ _construct = Reflect.construct.bind();
120
+ } else {
121
+ _construct = function _construct(Parent, args, Class) {
122
+ var a = [null];
123
+ a.push.apply(a, args);
124
+ var Constructor = Function.bind.apply(Parent, a);
125
+ var instance = new Constructor();
126
+ if (Class) _setPrototypeOf(instance, Class.prototype);
127
+ return instance;
128
+ };
129
+ }
130
+ return _construct.apply(null, arguments);
131
+ }
121
132
  function _isNativeFunction(fn) {
122
133
  try {
123
134
  return Function.toString.call(fn).indexOf("[native code]") !== -1;
@@ -352,7 +363,6 @@
352
363
  Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
353
364
  Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
354
365
  Events["MEDIA_DETACHED"] = "hlsMediaDetached";
355
- Events["MEDIA_ENDED"] = "hlsMediaEnded";
356
366
  Events["BUFFER_RESET"] = "hlsBufferReset";
357
367
  Events["BUFFER_CODECS"] = "hlsBufferCodecs";
358
368
  Events["BUFFER_CREATED"] = "hlsBufferCreated";
@@ -466,6 +476,61 @@
466
476
  return ErrorDetails;
467
477
  }({});
468
478
 
479
+ var noop = function noop() {};
480
+ var fakeLogger = {
481
+ trace: noop,
482
+ debug: noop,
483
+ log: noop,
484
+ warn: noop,
485
+ info: noop,
486
+ error: noop
487
+ };
488
+ var exportedLogger = fakeLogger;
489
+
490
+ // let lastCallTime;
491
+ // function formatMsgWithTimeInfo(type, msg) {
492
+ // const now = Date.now();
493
+ // const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
494
+ // lastCallTime = now;
495
+ // msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
496
+ // return msg;
497
+ // }
498
+
499
+ function consolePrintFn(type) {
500
+ var func = self.console[type];
501
+ if (func) {
502
+ return func.bind(self.console, "[" + type + "] >");
503
+ }
504
+ return noop;
505
+ }
506
+ function exportLoggerFunctions(debugConfig) {
507
+ for (var _len = arguments.length, functions = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
508
+ functions[_key - 1] = arguments[_key];
509
+ }
510
+ functions.forEach(function (type) {
511
+ exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
512
+ });
513
+ }
514
+ function enableLogs(debugConfig, id) {
515
+ // check that console is available
516
+ if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
517
+ exportLoggerFunctions(debugConfig,
518
+ // Remove out from list here to hard-disable a log-level
519
+ // 'trace',
520
+ 'debug', 'log', 'info', 'warn', 'error');
521
+ // Some browsers don't allow to use bind on console object anyway
522
+ // fallback to default if needed
523
+ try {
524
+ exportedLogger.log("Debug logs enabled for \"" + id + "\" in hls.js version " + "1.5.7");
525
+ } catch (e) {
526
+ exportedLogger = fakeLogger;
527
+ }
528
+ } else {
529
+ exportedLogger = fakeLogger;
530
+ }
531
+ }
532
+ var logger = exportedLogger;
533
+
469
534
  var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/;
470
535
  var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g;
471
536
 
@@ -554,77 +619,6 @@
554
619
  return AttrList;
555
620
  }();
556
621
 
557
- var Logger = function Logger(label, logger) {
558
- this.trace = void 0;
559
- this.debug = void 0;
560
- this.log = void 0;
561
- this.warn = void 0;
562
- this.info = void 0;
563
- this.error = void 0;
564
- var lb = "[" + label + "]:";
565
- this.trace = noop;
566
- this.debug = logger.debug.bind(null, lb);
567
- this.log = logger.log.bind(null, lb);
568
- this.warn = logger.warn.bind(null, lb);
569
- this.info = logger.info.bind(null, lb);
570
- this.error = logger.error.bind(null, lb);
571
- };
572
- var noop = function noop() {};
573
- var fakeLogger = {
574
- trace: noop,
575
- debug: noop,
576
- log: noop,
577
- warn: noop,
578
- info: noop,
579
- error: noop
580
- };
581
- function createLogger() {
582
- return _extends({}, fakeLogger);
583
- }
584
-
585
- // let lastCallTime;
586
- // function formatMsgWithTimeInfo(type, msg) {
587
- // const now = Date.now();
588
- // const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
589
- // lastCallTime = now;
590
- // msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
591
- // return msg;
592
- // }
593
-
594
- function consolePrintFn(type, id) {
595
- var func = self.console[type];
596
- return func ? func.bind(self.console, (id ? '[' + id + '] ' : '') + "[" + type + "] >") : noop;
597
- }
598
- function getLoggerFn(key, debugConfig, id) {
599
- return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
600
- }
601
- var exportedLogger = createLogger();
602
- function enableLogs(debugConfig, context, id) {
603
- // check that console is available
604
- var newLogger = createLogger();
605
- if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
606
- var keys = [
607
- // Remove out from list here to hard-disable a log-level
608
- // 'trace',
609
- 'debug', 'log', 'info', 'warn', 'error'];
610
- keys.forEach(function (key) {
611
- newLogger[key] = getLoggerFn(key, debugConfig, id);
612
- });
613
- // Some browsers don't allow to use bind on console object anyway
614
- // fallback to default if needed
615
- try {
616
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.7-0.canary.10040");
617
- } catch (e) {
618
- /* log fn threw an exception. All logger methods are no-ops. */
619
- return createLogger();
620
- }
621
- }
622
- // global exported logger uses the log methods from last call to `enableLogs`
623
- _extends(exportedLogger, newLogger);
624
- return newLogger;
625
- }
626
- var logger = exportedLogger;
627
-
628
622
  // Avoid exporting const enum so that these values can be inlined
629
623
 
630
624
  function isDateRangeCueAttribute(attrName) {
@@ -1179,30 +1173,10 @@
1179
1173
  return LevelDetails;
1180
1174
  }();
1181
1175
 
1182
- var DecrypterAesMode = {
1183
- cbc: 0,
1184
- ctr: 1
1185
- };
1186
-
1187
- function isFullSegmentEncryption(method) {
1188
- return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
1189
- }
1190
- function getAesModeFromFullSegmentMethod(method) {
1191
- switch (method) {
1192
- case 'AES-128':
1193
- case 'AES-256':
1194
- return DecrypterAesMode.cbc;
1195
- case 'AES-256-CTR':
1196
- return DecrypterAesMode.ctr;
1197
- default:
1198
- throw new Error("invalid full segment method " + method);
1199
- }
1200
- }
1201
-
1202
1176
  // This file is inserted as a shim for modules which we do not want to include into the distro.
1203
1177
  // This replacement is done in the "alias" plugin of the rollup config.
1204
1178
  var empty = undefined;
1205
- var HevcVideoParser = /*@__PURE__*/getDefaultExportFromCjs(empty);
1179
+ var Cues = /*@__PURE__*/getDefaultExportFromCjs(empty);
1206
1180
 
1207
1181
  function sliceUint8(array, start, end) {
1208
1182
  // @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
@@ -1837,7 +1811,7 @@
1837
1811
  {
1838
1812
  var codecBox = findBox(sampleEntries, [fourCC])[0];
1839
1813
  var esdsBox = findBox(codecBox.subarray(28), ['esds'])[0];
1840
- if (esdsBox && esdsBox.length > 7) {
1814
+ if (esdsBox && esdsBox.length > 12) {
1841
1815
  var i = 4;
1842
1816
  // ES Descriptor tag
1843
1817
  if (esdsBox[i++] !== 0x03) {
@@ -1952,9 +1926,7 @@
1952
1926
  }
1953
1927
  function skipBERInteger(bytes, i) {
1954
1928
  var limit = i + 5;
1955
- while (bytes[i++] & 0x80 && i < limit) {
1956
- /* do nothing */
1957
- }
1929
+ while (bytes[i++] & 0x80 && i < limit) {}
1958
1930
  return i;
1959
1931
  }
1960
1932
  function toHex(x) {
@@ -2656,13 +2628,13 @@
2656
2628
  this.keyFormatVersions = formatversions;
2657
2629
  this.iv = iv;
2658
2630
  this.encrypted = method ? method !== 'NONE' : false;
2659
- this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2631
+ this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2660
2632
  }
2661
2633
  var _proto = LevelKey.prototype;
2662
2634
  _proto.isSupported = function isSupported() {
2663
2635
  // If it's Segment encryption or No encryption, just select that key system
2664
2636
  if (this.method) {
2665
- if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2637
+ if (this.method === 'AES-128' || this.method === 'NONE') {
2666
2638
  return true;
2667
2639
  }
2668
2640
  if (this.keyFormat === 'identity') {
@@ -2676,13 +2648,14 @@
2676
2648
  if (!this.encrypted || !this.uri) {
2677
2649
  return null;
2678
2650
  }
2679
- if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2651
+ if (this.method === 'AES-128' && this.uri && !this.iv) {
2680
2652
  if (typeof sn !== 'number') {
2681
2653
  // We are fetching decryption data for a initialization segment
2682
- // If the segment was encrypted with AES-128/256
2654
+ // If the segment was encrypted with AES-128
2683
2655
  // It must have an IV defined. We cannot substitute the Segment Number in.
2684
- logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2685
-
2656
+ if (this.method === 'AES-128' && !this.iv) {
2657
+ logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2658
+ }
2686
2659
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2687
2660
  sn = 0;
2688
2661
  }
@@ -2844,28 +2817,23 @@
2844
2817
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2845
2818
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2846
2819
  }
2820
+
2821
+ // Idealy fLaC and Opus would be first (spec-compliant) but
2822
+ // some browsers will report that fLaC is supported then fail.
2823
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2847
2824
  var codecsToCheck = {
2848
- // Idealy fLaC and Opus would be first (spec-compliant) but
2849
- // some browsers will report that fLaC is supported then fail.
2850
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2851
2825
  flac: ['flac', 'fLaC', 'FLAC'],
2852
- opus: ['opus', 'Opus'],
2853
- // Replace audio codec info if browser does not support mp4a.40.34,
2854
- // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
2855
- 'mp4a.40.34': ['mp3']
2826
+ opus: ['opus', 'Opus']
2856
2827
  }[lowerCaseCodec];
2857
2828
  for (var i = 0; i < codecsToCheck.length; i++) {
2858
- var _getMediaSource;
2859
2829
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2860
2830
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2861
2831
  return codecsToCheck[i];
2862
- } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2863
- return '';
2864
2832
  }
2865
2833
  }
2866
2834
  return lowerCaseCodec;
2867
2835
  }
2868
- var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2836
+ var AUDIO_CODEC_REGEXP = /flac|opus/i;
2869
2837
  function getCodecCompatibleName(codec, preferManagedMediaSource) {
2870
2838
  if (preferManagedMediaSource === void 0) {
2871
2839
  preferManagedMediaSource = true;
@@ -2893,18 +2861,6 @@
2893
2861
  }
2894
2862
  return codec;
2895
2863
  }
2896
- function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2897
- var MediaSource = getMediaSource(preferManagedMediaSource) || {
2898
- isTypeSupported: function isTypeSupported() {
2899
- return false;
2900
- }
2901
- };
2902
- return {
2903
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
2904
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
2905
- ac3: false
2906
- };
2907
- }
2908
2864
 
2909
2865
  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;
2910
2866
  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -3705,10 +3661,10 @@
3705
3661
  var loaderContext = loader.context;
3706
3662
  if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
3707
3663
  // same URL can't overlap
3708
- this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
3664
+ logger.trace('[playlist-loader]: playlist request ongoing');
3709
3665
  return;
3710
3666
  }
3711
- this.hls.logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
3667
+ logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
3712
3668
  loader.abort();
3713
3669
  }
3714
3670
 
@@ -3818,7 +3774,7 @@
3818
3774
  // alt audio rendition in which quality levels (main)
3819
3775
  // contains both audio+video. but with mixed audio track not signaled
3820
3776
  if (!embeddedAudioFound && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
3821
- this.hls.logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
3777
+ logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
3822
3778
  audioTracks.unshift({
3823
3779
  type: 'main',
3824
3780
  name: 'main',
@@ -3918,7 +3874,7 @@
3918
3874
  message += " id: " + context.id + " group-id: \"" + context.groupId + "\"";
3919
3875
  }
3920
3876
  var error = new Error(message);
3921
- this.hls.logger.warn("[playlist-loader]: " + message);
3877
+ logger.warn("[playlist-loader]: " + message);
3922
3878
  var details = ErrorDetails.UNKNOWN;
3923
3879
  var fatal = false;
3924
3880
  var loader = this.getInternalLoader(context);
@@ -4479,43 +4435,8 @@
4479
4435
  this.currentTime = 0;
4480
4436
  this.stallCount = 0;
4481
4437
  this._latency = null;
4482
- this.onTimeupdate = function () {
4483
- var media = _this.media,
4484
- levelDetails = _this.levelDetails;
4485
- if (!media || !levelDetails) {
4486
- return;
4487
- }
4488
- _this.currentTime = media.currentTime;
4489
- var latency = _this.computeLatency();
4490
- if (latency === null) {
4491
- return;
4492
- }
4493
- _this._latency = latency;
4494
-
4495
- // Adapt playbackRate to meet target latency in low-latency mode
4496
- var _this$config = _this.config,
4497
- lowLatencyMode = _this$config.lowLatencyMode,
4498
- maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4499
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4500
- return;
4501
- }
4502
- var targetLatency = _this.targetLatency;
4503
- if (targetLatency === null) {
4504
- return;
4505
- }
4506
- var distanceFromTarget = latency - targetLatency;
4507
- // Only adjust playbackRate when within one target duration of targetLatency
4508
- // and more than one second from under-buffering.
4509
- // Playback further than one target duration from target can be considered DVR playback.
4510
- var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
4511
- var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4512
- if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
4513
- var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4514
- var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
4515
- media.playbackRate = Math.min(max, Math.max(1, rate));
4516
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4517
- media.playbackRate = 1;
4518
- }
4438
+ this.timeupdateHandler = function () {
4439
+ return _this.timeupdate();
4519
4440
  };
4520
4441
  this.hls = hls;
4521
4442
  this.config = hls.config;
@@ -4527,7 +4448,7 @@
4527
4448
  this.onMediaDetaching();
4528
4449
  this.levelDetails = null;
4529
4450
  // @ts-ignore
4530
- this.hls = null;
4451
+ this.hls = this.timeupdateHandler = null;
4531
4452
  };
4532
4453
  _proto.registerListeners = function registerListeners() {
4533
4454
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4545,11 +4466,11 @@
4545
4466
  };
4546
4467
  _proto.onMediaAttached = function onMediaAttached(event, data) {
4547
4468
  this.media = data.media;
4548
- this.media.addEventListener('timeupdate', this.onTimeupdate);
4469
+ this.media.addEventListener('timeupdate', this.timeupdateHandler);
4549
4470
  };
4550
4471
  _proto.onMediaDetaching = function onMediaDetaching() {
4551
4472
  if (this.media) {
4552
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4473
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4553
4474
  this.media = null;
4554
4475
  }
4555
4476
  };
@@ -4562,10 +4483,10 @@
4562
4483
  var details = _ref.details;
4563
4484
  this.levelDetails = details;
4564
4485
  if (details.advanced) {
4565
- this.onTimeupdate();
4486
+ this.timeupdate();
4566
4487
  }
4567
4488
  if (!details.live && this.media) {
4568
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4489
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4569
4490
  }
4570
4491
  };
4571
4492
  _proto.onError = function onError(event, data) {
@@ -4575,7 +4496,45 @@
4575
4496
  }
4576
4497
  this.stallCount++;
4577
4498
  if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
4578
- this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
4499
+ logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
4500
+ }
4501
+ };
4502
+ _proto.timeupdate = function timeupdate() {
4503
+ var media = this.media,
4504
+ levelDetails = this.levelDetails;
4505
+ if (!media || !levelDetails) {
4506
+ return;
4507
+ }
4508
+ this.currentTime = media.currentTime;
4509
+ var latency = this.computeLatency();
4510
+ if (latency === null) {
4511
+ return;
4512
+ }
4513
+ this._latency = latency;
4514
+
4515
+ // Adapt playbackRate to meet target latency in low-latency mode
4516
+ var _this$config = this.config,
4517
+ lowLatencyMode = _this$config.lowLatencyMode,
4518
+ maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4519
+ if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4520
+ return;
4521
+ }
4522
+ var targetLatency = this.targetLatency;
4523
+ if (targetLatency === null) {
4524
+ return;
4525
+ }
4526
+ var distanceFromTarget = latency - targetLatency;
4527
+ // Only adjust playbackRate when within one target duration of targetLatency
4528
+ // and more than one second from under-buffering.
4529
+ // Playback further than one target duration from target can be considered DVR playback.
4530
+ var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4531
+ var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4532
+ if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4533
+ var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4534
+ var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4535
+ media.playbackRate = Math.min(max, Math.max(1, rate));
4536
+ } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4537
+ media.playbackRate = 1;
4579
4538
  }
4580
4539
  };
4581
4540
  _proto.estimateLiveEdge = function estimateLiveEdge() {
@@ -5483,17 +5442,19 @@
5483
5442
  MoveAllAlternatesMatchingHDCP: 2,
5484
5443
  SwitchToSDR: 4
5485
5444
  }; // Reserved for future use
5486
- var ErrorController = /*#__PURE__*/function (_Logger) {
5487
- _inheritsLoose(ErrorController, _Logger);
5445
+ var ErrorController = /*#__PURE__*/function () {
5488
5446
  function ErrorController(hls) {
5489
- var _this;
5490
- _this = _Logger.call(this, 'error-controller', hls.logger) || this;
5491
- _this.hls = void 0;
5492
- _this.playlistError = 0;
5493
- _this.penalizedRenditions = {};
5494
- _this.hls = hls;
5495
- _this.registerListeners();
5496
- return _this;
5447
+ this.hls = void 0;
5448
+ this.playlistError = 0;
5449
+ this.penalizedRenditions = {};
5450
+ this.log = void 0;
5451
+ this.warn = void 0;
5452
+ this.error = void 0;
5453
+ this.hls = hls;
5454
+ this.log = logger.log.bind(logger, "[info]:");
5455
+ this.warn = logger.warn.bind(logger, "[warning]:");
5456
+ this.error = logger.error.bind(logger, "[error]:");
5457
+ this.registerListeners();
5497
5458
  }
5498
5459
  var _proto = ErrorController.prototype;
5499
5460
  _proto.registerListeners = function registerListeners() {
@@ -5849,19 +5810,19 @@
5849
5810
  }
5850
5811
  };
5851
5812
  return ErrorController;
5852
- }(Logger);
5813
+ }();
5853
5814
 
5854
- var BasePlaylistController = /*#__PURE__*/function (_Logger) {
5855
- _inheritsLoose(BasePlaylistController, _Logger);
5815
+ var BasePlaylistController = /*#__PURE__*/function () {
5856
5816
  function BasePlaylistController(hls, logPrefix) {
5857
- var _this;
5858
- _this = _Logger.call(this, logPrefix, hls.logger) || this;
5859
- _this.hls = void 0;
5860
- _this.timer = -1;
5861
- _this.requestScheduled = -1;
5862
- _this.canLoad = false;
5863
- _this.hls = hls;
5864
- return _this;
5817
+ this.hls = void 0;
5818
+ this.timer = -1;
5819
+ this.requestScheduled = -1;
5820
+ this.canLoad = false;
5821
+ this.log = void 0;
5822
+ this.warn = void 0;
5823
+ this.log = logger.log.bind(logger, logPrefix + ":");
5824
+ this.warn = logger.warn.bind(logger, logPrefix + ":");
5825
+ this.hls = hls;
5865
5826
  }
5866
5827
  var _proto = BasePlaylistController.prototype;
5867
5828
  _proto.destroy = function destroy() {
@@ -5894,7 +5855,7 @@
5894
5855
  try {
5895
5856
  uri = new self.URL(attr.URI, previous.url).href;
5896
5857
  } catch (error) {
5897
- this.warn("Could not construct new URL for Rendition Report: " + error);
5858
+ logger.warn("Could not construct new URL for Rendition Report: " + error);
5898
5859
  uri = attr.URI || '';
5899
5860
  }
5900
5861
  // Use exact match. Otherwise, the last partial match, if any, will be used
@@ -5933,7 +5894,7 @@
5933
5894
  return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
5934
5895
  };
5935
5896
  _proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
5936
- var _this2 = this;
5897
+ var _this = this;
5937
5898
  var details = data.details,
5938
5899
  stats = data.stats;
5939
5900
 
@@ -5980,12 +5941,7 @@
5980
5941
  var cdnAge = lastAdvanced + details.ageHeader;
5981
5942
  var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
5982
5943
  if (currentGoal > 0) {
5983
- if (cdnAge > details.targetduration * 3) {
5984
- // Omit segment and part directives when the last response was more than 3 target durations ago,
5985
- this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
5986
- msn = undefined;
5987
- part = undefined;
5988
- } else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
5944
+ if (previousDetails && currentGoal > previousDetails.tuneInGoal) {
5989
5945
  // If we attempted to get the next or latest playlist update, but currentGoal increased,
5990
5946
  // then we either can't catchup, or the "age" header cannot be trusted.
5991
5947
  this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
@@ -6043,7 +5999,7 @@
6043
5999
  // );
6044
6000
 
6045
6001
  this.timer = self.setTimeout(function () {
6046
- return _this2.loadPlaylist(deliveryDirectives);
6002
+ return _this.loadPlaylist(deliveryDirectives);
6047
6003
  }, estimatedTimeUntilUpdate);
6048
6004
  } else {
6049
6005
  this.clearTimer();
@@ -6059,7 +6015,7 @@
6059
6015
  return new HlsUrlParameters(msn, part, skip);
6060
6016
  };
6061
6017
  _proto.checkRetry = function checkRetry(errorEvent) {
6062
- var _this3 = this;
6018
+ var _this2 = this;
6063
6019
  var errorDetails = errorEvent.details;
6064
6020
  var isTimeout = isTimeoutError(errorEvent);
6065
6021
  var errorAction = errorEvent.errorAction;
@@ -6083,7 +6039,7 @@
6083
6039
  var delay = getRetryDelay(retryConfig, retryCount);
6084
6040
  // Schedule level/track reload
6085
6041
  this.timer = self.setTimeout(function () {
6086
- return _this3.loadPlaylist();
6042
+ return _this2.loadPlaylist();
6087
6043
  }, delay);
6088
6044
  this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
6089
6045
  }
@@ -6094,7 +6050,7 @@
6094
6050
  return retry;
6095
6051
  };
6096
6052
  return BasePlaylistController;
6097
- }(Logger);
6053
+ }();
6098
6054
 
6099
6055
  /*
6100
6056
  * compute an Exponential Weighted moving average
@@ -6468,33 +6424,30 @@
6468
6424
  }, {});
6469
6425
  }
6470
6426
 
6471
- var AbrController = /*#__PURE__*/function (_Logger) {
6472
- _inheritsLoose(AbrController, _Logger);
6427
+ var AbrController = /*#__PURE__*/function () {
6473
6428
  function AbrController(_hls) {
6474
- var _this;
6475
- _this = _Logger.call(this, 'abr', _hls.logger) || this;
6476
- _this.hls = void 0;
6477
- _this.lastLevelLoadSec = 0;
6478
- _this.lastLoadedFragLevel = -1;
6479
- _this.firstSelection = -1;
6480
- _this._nextAutoLevel = -1;
6481
- _this.nextAutoLevelKey = '';
6482
- _this.audioTracksByGroup = null;
6483
- _this.codecTiers = null;
6484
- _this.timer = -1;
6485
- _this.fragCurrent = null;
6486
- _this.partCurrent = null;
6487
- _this.bitrateTestDelay = 0;
6488
- _this.bwEstimator = void 0;
6429
+ var _this = this;
6430
+ this.hls = void 0;
6431
+ this.lastLevelLoadSec = 0;
6432
+ this.lastLoadedFragLevel = -1;
6433
+ this.firstSelection = -1;
6434
+ this._nextAutoLevel = -1;
6435
+ this.nextAutoLevelKey = '';
6436
+ this.audioTracksByGroup = null;
6437
+ this.codecTiers = null;
6438
+ this.timer = -1;
6439
+ this.fragCurrent = null;
6440
+ this.partCurrent = null;
6441
+ this.bitrateTestDelay = 0;
6442
+ this.bwEstimator = void 0;
6489
6443
  /*
6490
6444
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
6491
6445
  quickly enough to prevent underbuffering
6492
6446
  */
6493
- _this._abandonRulesCheck = function () {
6494
- var _assertThisInitialize = _assertThisInitialized(_this),
6495
- frag = _assertThisInitialize.fragCurrent,
6496
- part = _assertThisInitialize.partCurrent,
6497
- hls = _assertThisInitialize.hls;
6447
+ this._abandonRulesCheck = function () {
6448
+ var frag = _this.fragCurrent,
6449
+ part = _this.partCurrent,
6450
+ hls = _this.hls;
6498
6451
  var autoLevelEnabled = hls.autoLevelEnabled,
6499
6452
  media = hls.media;
6500
6453
  if (!frag || !media) {
@@ -6583,22 +6536,21 @@
6583
6536
  _this.resetEstimator(nextLoadLevelBitrate);
6584
6537
  }
6585
6538
  _this.clearTimer();
6586
- _this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
6539
+ logger.warn("[abr] Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
6587
6540
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
6588
6541
  frag: frag,
6589
6542
  part: part,
6590
6543
  stats: stats
6591
6544
  });
6592
6545
  };
6593
- _this.hls = _hls;
6594
- _this.bwEstimator = _this.initEstimator();
6595
- _this.registerListeners();
6596
- return _this;
6546
+ this.hls = _hls;
6547
+ this.bwEstimator = this.initEstimator();
6548
+ this.registerListeners();
6597
6549
  }
6598
6550
  var _proto = AbrController.prototype;
6599
6551
  _proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
6600
6552
  if (abrEwmaDefaultEstimate) {
6601
- this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6553
+ logger.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6602
6554
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
6603
6555
  }
6604
6556
  this.firstSelection = -1;
@@ -6813,9 +6765,6 @@
6813
6765
  var fragCurrent = this.fragCurrent,
6814
6766
  partCurrent = this.partCurrent,
6815
6767
  hls = this.hls;
6816
- if (hls.levels.length <= 1) {
6817
- return hls.loadLevel;
6818
- }
6819
6768
  var maxAutoLevel = hls.maxAutoLevel,
6820
6769
  config = hls.config,
6821
6770
  minAutoLevel = hls.minAutoLevel;
@@ -6846,13 +6795,13 @@
6846
6795
  // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
6847
6796
  var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
6848
6797
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
6849
- this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
6798
+ logger.info("[abr] bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
6850
6799
  // don't use conservative factor on bitrate test
6851
6800
  bwFactor = bwUpFactor = 1;
6852
6801
  }
6853
6802
  }
6854
6803
  var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
6855
- this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6804
+ logger.info("[abr] " + (bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6856
6805
  if (bestLevel > -1) {
6857
6806
  return bestLevel;
6858
6807
  }
@@ -6920,7 +6869,7 @@
6920
6869
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
6921
6870
  currentFrameRate = minFramerate;
6922
6871
  currentBw = Math.max(currentBw, minBitrate);
6923
- this.log("picked start tier " + JSON.stringify(startTier));
6872
+ logger.log("[abr] picked start tier " + JSON.stringify(startTier));
6924
6873
  } else {
6925
6874
  currentCodecSet = level == null ? void 0 : level.codecSet;
6926
6875
  currentVideoRange = level == null ? void 0 : level.videoRange;
@@ -6973,9 +6922,9 @@
6973
6922
  var forcedAutoLevel = _this2.forcedAutoLevel;
6974
6923
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
6975
6924
  if (levelsSkipped.length) {
6976
- _this2.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
6925
+ logger.trace("[abr] Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
6977
6926
  }
6978
- _this2.info("switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
6927
+ logger.info("[abr] switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
6979
6928
  }
6980
6929
  if (firstSelection) {
6981
6930
  _this2.firstSelection = i;
@@ -7009,7 +6958,7 @@
7009
6958
  }
7010
6959
  var firstLevel = this.hls.firstLevel;
7011
6960
  var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
7012
- this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
6961
+ logger.warn("[abr] Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
7013
6962
  return clamped;
7014
6963
  }
7015
6964
  }, {
@@ -7062,7 +7011,7 @@
7062
7011
  }
7063
7012
  }]);
7064
7013
  return AbrController;
7065
- }(Logger);
7014
+ }();
7066
7015
 
7067
7016
  /**
7068
7017
  * Provides methods dealing with buffer length retrieval for example.
@@ -7087,29 +7036,40 @@
7087
7036
  * Return true if `media`'s buffered include `position`
7088
7037
  */
7089
7038
  BufferHelper.isBuffered = function isBuffered(media, position) {
7090
- if (media) {
7091
- var buffered = BufferHelper.getBuffered(media);
7092
- for (var i = buffered.length; i--;) {
7093
- if (position >= buffered.start(i) && position <= buffered.end(i)) {
7094
- return true;
7039
+ try {
7040
+ if (media) {
7041
+ var buffered = BufferHelper.getBuffered(media);
7042
+ for (var i = 0; i < buffered.length; i++) {
7043
+ if (position >= buffered.start(i) && position <= buffered.end(i)) {
7044
+ return true;
7045
+ }
7095
7046
  }
7096
7047
  }
7048
+ } catch (error) {
7049
+ // this is to catch
7050
+ // InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer':
7051
+ // This SourceBuffer has been removed from the parent media source
7097
7052
  }
7098
7053
  return false;
7099
7054
  };
7100
7055
  BufferHelper.bufferInfo = function bufferInfo(media, pos, maxHoleDuration) {
7101
- if (media) {
7102
- var vbuffered = BufferHelper.getBuffered(media);
7103
- if (vbuffered.length) {
7056
+ try {
7057
+ if (media) {
7058
+ var vbuffered = BufferHelper.getBuffered(media);
7104
7059
  var buffered = [];
7105
- for (var i = 0; i < vbuffered.length; i++) {
7060
+ var i;
7061
+ for (i = 0; i < vbuffered.length; i++) {
7106
7062
  buffered.push({
7107
7063
  start: vbuffered.start(i),
7108
7064
  end: vbuffered.end(i)
7109
7065
  });
7110
7066
  }
7111
- return BufferHelper.bufferedInfo(buffered, pos, maxHoleDuration);
7067
+ return this.bufferedInfo(buffered, pos, maxHoleDuration);
7112
7068
  }
7069
+ } catch (error) {
7070
+ // this is to catch
7071
+ // InvalidStateError: Failed to read the 'buffered' property from 'SourceBuffer':
7072
+ // This SourceBuffer has been removed from the parent media source
7113
7073
  }
7114
7074
  return {
7115
7075
  len: 0,
@@ -7122,7 +7082,12 @@
7122
7082
  pos = Math.max(0, pos);
7123
7083
  // sort on buffer.start/smaller end (IE does not always return sorted buffered range)
7124
7084
  buffered.sort(function (a, b) {
7125
- return a.start - b.start || b.end - a.end;
7085
+ var diff = a.start - b.start;
7086
+ if (diff) {
7087
+ return diff;
7088
+ } else {
7089
+ return b.end - a.end;
7090
+ }
7126
7091
  });
7127
7092
  var buffered2 = [];
7128
7093
  if (maxHoleDuration) {
@@ -7190,7 +7155,7 @@
7190
7155
  */;
7191
7156
  BufferHelper.getBuffered = function getBuffered(media) {
7192
7157
  try {
7193
- return media.buffered || noopBuffered;
7158
+ return media.buffered;
7194
7159
  } catch (e) {
7195
7160
  logger.log('failed to get media.buffered', e);
7196
7161
  return noopBuffered;
@@ -7217,23 +7182,24 @@
7217
7182
  this.executeNext(type);
7218
7183
  }
7219
7184
  };
7185
+ _proto.insertAbort = function insertAbort(operation, type) {
7186
+ var queue = this.queues[type];
7187
+ queue.unshift(operation);
7188
+ this.executeNext(type);
7189
+ };
7220
7190
  _proto.appendBlocker = function appendBlocker(type) {
7221
- var _this = this;
7222
- return new Promise(function (resolve) {
7223
- var operation = {
7224
- execute: resolve,
7225
- onStart: function onStart() {},
7226
- onComplete: function onComplete() {},
7227
- onError: function onError() {}
7228
- };
7229
- _this.append(operation, type);
7191
+ var execute;
7192
+ var promise = new Promise(function (resolve) {
7193
+ execute = resolve;
7230
7194
  });
7231
- };
7232
- _proto.unblockAudio = function unblockAudio(op) {
7233
- var queue = this.queues.audio;
7234
- if (queue[0] === op) {
7235
- this.shiftAndExecuteNext('audio');
7236
- }
7195
+ var operation = {
7196
+ execute: execute,
7197
+ onStart: function onStart() {},
7198
+ onComplete: function onComplete() {},
7199
+ onError: function onError() {}
7200
+ };
7201
+ this.append(operation, type);
7202
+ return promise;
7237
7203
  };
7238
7204
  _proto.executeNext = function executeNext(type) {
7239
7205
  var queue = this.queues[type];
@@ -7266,69 +7232,61 @@
7266
7232
  }();
7267
7233
 
7268
7234
  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
7269
- var BufferController = /*#__PURE__*/function (_Logger) {
7270
- _inheritsLoose(BufferController, _Logger);
7271
- function BufferController(hls, fragmentTracker) {
7272
- var _this;
7273
- _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
7235
+ var BufferController = /*#__PURE__*/function () {
7236
+ function BufferController(hls) {
7237
+ var _this = this;
7274
7238
  // The level details used to determine duration, target-duration and live
7275
- _this.details = null;
7239
+ this.details = null;
7276
7240
  // cache the self generated object url to detect hijack of video tag
7277
- _this._objectUrl = null;
7241
+ this._objectUrl = null;
7278
7242
  // A queue of buffer operations which require the SourceBuffer to not be updating upon execution
7279
- _this.operationQueue = void 0;
7243
+ this.operationQueue = void 0;
7280
7244
  // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
7281
- _this.listeners = void 0;
7282
- _this.hls = void 0;
7283
- _this.fragmentTracker = void 0;
7245
+ this.listeners = void 0;
7246
+ this.hls = void 0;
7284
7247
  // The number of BUFFER_CODEC events received before any sourceBuffers are created
7285
- _this.bufferCodecEventsExpected = 0;
7248
+ this.bufferCodecEventsExpected = 0;
7286
7249
  // The total number of BUFFER_CODEC events received
7287
- _this._bufferCodecEventsTotal = 0;
7250
+ this._bufferCodecEventsTotal = 0;
7288
7251
  // A reference to the attached media element
7289
- _this.media = null;
7252
+ this.media = null;
7290
7253
  // A reference to the active media source
7291
- _this.mediaSource = null;
7254
+ this.mediaSource = null;
7292
7255
  // Last MP3 audio chunk appended
7293
- _this.lastMpegAudioChunk = null;
7294
- // Audio fragment blocked from appending until corresponding video appends or context changes
7295
- _this.blockedAudioAppend = null;
7296
- // Keep track of video append position for unblocking audio
7297
- _this.lastVideoAppendEnd = 0;
7298
- _this.appendSource = void 0;
7256
+ this.lastMpegAudioChunk = null;
7257
+ this.appendSource = void 0;
7299
7258
  // counters
7300
- _this.appendErrors = {
7259
+ this.appendErrors = {
7301
7260
  audio: 0,
7302
7261
  video: 0,
7303
7262
  audiovideo: 0
7304
7263
  };
7305
- _this.tracks = {};
7306
- _this.pendingTracks = {};
7307
- _this.sourceBuffer = void 0;
7308
- _this._onEndStreaming = function (event) {
7264
+ this.tracks = {};
7265
+ this.pendingTracks = {};
7266
+ this.sourceBuffer = void 0;
7267
+ this.log = void 0;
7268
+ this.warn = void 0;
7269
+ this.error = void 0;
7270
+ this._onEndStreaming = function (event) {
7309
7271
  if (!_this.hls) {
7310
7272
  return;
7311
7273
  }
7312
7274
  _this.hls.pauseBuffering();
7313
7275
  };
7314
- _this._onStartStreaming = function (event) {
7276
+ this._onStartStreaming = function (event) {
7315
7277
  if (!_this.hls) {
7316
7278
  return;
7317
7279
  }
7318
7280
  _this.hls.resumeBuffering();
7319
7281
  };
7320
7282
  // Keep as arrow functions so that we can directly reference these functions directly as event listeners
7321
- _this._onMediaSourceOpen = function () {
7322
- var _assertThisInitialize = _assertThisInitialized(_this),
7323
- media = _assertThisInitialize.media,
7324
- mediaSource = _assertThisInitialize.mediaSource;
7283
+ this._onMediaSourceOpen = function () {
7284
+ var media = _this.media,
7285
+ mediaSource = _this.mediaSource;
7325
7286
  _this.log('Media source opened');
7326
7287
  if (media) {
7327
7288
  media.removeEventListener('emptied', _this._onMediaEmptied);
7328
- var durationAndRange = _this.getDurationAndRange();
7329
- if (durationAndRange) {
7330
- _this.updateMediaSource(durationAndRange);
7331
- }
7289
+ _this.updateMediaElementDuration();
7332
7290
  _this.hls.trigger(Events.MEDIA_ATTACHED, {
7333
7291
  media: media,
7334
7292
  mediaSource: mediaSource
@@ -7340,26 +7298,27 @@
7340
7298
  }
7341
7299
  _this.checkPendingTracks();
7342
7300
  };
7343
- _this._onMediaSourceClose = function () {
7301
+ this._onMediaSourceClose = function () {
7344
7302
  _this.log('Media source closed');
7345
7303
  };
7346
- _this._onMediaSourceEnded = function () {
7304
+ this._onMediaSourceEnded = function () {
7347
7305
  _this.log('Media source ended');
7348
7306
  };
7349
- _this._onMediaEmptied = function () {
7350
- var _assertThisInitialize2 = _assertThisInitialized(_this),
7351
- mediaSrc = _assertThisInitialize2.mediaSrc,
7352
- _objectUrl = _assertThisInitialize2._objectUrl;
7307
+ this._onMediaEmptied = function () {
7308
+ var mediaSrc = _this.mediaSrc,
7309
+ _objectUrl = _this._objectUrl;
7353
7310
  if (mediaSrc !== _objectUrl) {
7354
- _this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7311
+ logger.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7355
7312
  }
7356
7313
  };
7357
- _this.hls = hls;
7358
- _this.fragmentTracker = fragmentTracker;
7359
- _this.appendSource = hls.config.preferManagedMediaSource;
7360
- _this._initSourceBuffer();
7361
- _this.registerListeners();
7362
- return _this;
7314
+ this.hls = hls;
7315
+ var logPrefix = '[buffer-controller]';
7316
+ this.appendSource = hls.config.preferManagedMediaSource && typeof self !== 'undefined' && self.ManagedMediaSource;
7317
+ this.log = logger.log.bind(logger, logPrefix);
7318
+ this.warn = logger.warn.bind(logger, logPrefix);
7319
+ this.error = logger.error.bind(logger, logPrefix);
7320
+ this._initSourceBuffer();
7321
+ this.registerListeners();
7363
7322
  }
7364
7323
  var _proto = BufferController.prototype;
7365
7324
  _proto.hasSourceTypes = function hasSourceTypes() {
@@ -7370,13 +7329,7 @@
7370
7329
  this.details = null;
7371
7330
  this.lastMpegAudioChunk = null;
7372
7331
  // @ts-ignore
7373
- this.hls = this.fragmentTracker = null;
7374
- // @ts-ignore
7375
- this._onMediaSourceOpen = this._onMediaSourceClose = null;
7376
- // @ts-ignore
7377
- this._onMediaSourceEnded = null;
7378
- // @ts-ignore
7379
- this._onStartStreaming = this._onEndStreaming = null;
7332
+ this.hls = null;
7380
7333
  };
7381
7334
  _proto.registerListeners = function registerListeners() {
7382
7335
  var hls = this.hls;
@@ -7422,8 +7375,6 @@
7422
7375
  audiovideo: 0
7423
7376
  };
7424
7377
  this.lastMpegAudioChunk = null;
7425
- this.blockedAudioAppend = null;
7426
- this.lastVideoAppendEnd = 0;
7427
7378
  };
7428
7379
  _proto.onManifestLoading = function onManifestLoading() {
7429
7380
  this.bufferCodecEventsExpected = this._bufferCodecEventsTotal = 0;
@@ -7452,8 +7403,10 @@
7452
7403
  ms.addEventListener('sourceopen', this._onMediaSourceOpen);
7453
7404
  ms.addEventListener('sourceended', this._onMediaSourceEnded);
7454
7405
  ms.addEventListener('sourceclose', this._onMediaSourceClose);
7455
- ms.addEventListener('startstreaming', this._onStartStreaming);
7456
- ms.addEventListener('endstreaming', this._onEndStreaming);
7406
+ if (this.appendSource) {
7407
+ ms.addEventListener('startstreaming', this._onStartStreaming);
7408
+ ms.addEventListener('endstreaming', this._onEndStreaming);
7409
+ }
7457
7410
 
7458
7411
  // cache the locally generated object url
7459
7412
  var objectUrl = this._objectUrl = self.URL.createObjectURL(ms);
@@ -7498,8 +7451,10 @@
7498
7451
  mediaSource.removeEventListener('sourceopen', this._onMediaSourceOpen);
7499
7452
  mediaSource.removeEventListener('sourceended', this._onMediaSourceEnded);
7500
7453
  mediaSource.removeEventListener('sourceclose', this._onMediaSourceClose);
7501
- mediaSource.removeEventListener('startstreaming', this._onStartStreaming);
7502
- mediaSource.removeEventListener('endstreaming', this._onEndStreaming);
7454
+ if (this.appendSource) {
7455
+ mediaSource.removeEventListener('startstreaming', this._onStartStreaming);
7456
+ mediaSource.removeEventListener('endstreaming', this._onEndStreaming);
7457
+ }
7503
7458
 
7504
7459
  // Detach properly the MediaSource from the HTMLMediaElement as
7505
7460
  // suggested in https://github.com/w3c/media-source/issues/53.
@@ -7536,7 +7491,6 @@
7536
7491
  _this2.resetBuffer(type);
7537
7492
  });
7538
7493
  this._initSourceBuffer();
7539
- this.hls.resumeBuffering();
7540
7494
  };
7541
7495
  _proto.resetBuffer = function resetBuffer(type) {
7542
7496
  var sb = this.sourceBuffer[type];
@@ -7561,10 +7515,9 @@
7561
7515
  var trackNames = Object.keys(data);
7562
7516
  trackNames.forEach(function (trackName) {
7563
7517
  if (sourceBufferCount) {
7564
- var _track$buffer;
7565
7518
  // check if SourceBuffer codec needs to change
7566
7519
  var track = _this3.tracks[trackName];
7567
- if (track && typeof ((_track$buffer = track.buffer) == null ? void 0 : _track$buffer.changeType) === 'function') {
7520
+ if (track && typeof track.buffer.changeType === 'function') {
7568
7521
  var _trackCodec;
7569
7522
  var _data$trackName = data[trackName],
7570
7523
  id = _data$trackName.id,
@@ -7578,7 +7531,7 @@
7578
7531
  var nextCodec = (_trackCodec = trackCodec) == null ? void 0 : _trackCodec.replace(VIDEO_CODEC_PROFILE_REPLACE, '$1');
7579
7532
  if (trackCodec && currentCodec !== nextCodec) {
7580
7533
  if (trackName.slice(0, 5) === 'audio') {
7581
- trackCodec = getCodecCompatibleName(trackCodec, _this3.hls.config.preferManagedMediaSource);
7534
+ trackCodec = getCodecCompatibleName(trackCodec, _this3.appendSource);
7582
7535
  }
7583
7536
  var mimeType = container + ";codecs=" + trackCodec;
7584
7537
  _this3.appendChangeType(trackName, mimeType);
@@ -7632,52 +7585,17 @@
7632
7585
  };
7633
7586
  operationQueue.append(operation, type, !!this.pendingTracks[type]);
7634
7587
  };
7635
- _proto.blockAudio = function blockAudio(partOrFrag) {
7636
- var _this$fragmentTracker,
7637
- _this5 = this;
7638
- var pStart = partOrFrag.start;
7639
- var pTime = pStart + partOrFrag.duration * 0.05;
7640
- var atGap = ((_this$fragmentTracker = this.fragmentTracker.getAppendedFrag(pStart, PlaylistLevelType.MAIN)) == null ? void 0 : _this$fragmentTracker.gap) === true;
7641
- if (atGap) {
7642
- return;
7643
- }
7644
- var op = {
7645
- execute: function execute() {
7646
- var _this5$fragmentTracke;
7647
- if (_this5.lastVideoAppendEnd > pTime || _this5.sourceBuffer.video && BufferHelper.isBuffered(_this5.sourceBuffer.video, pTime) || ((_this5$fragmentTracke = _this5.fragmentTracker.getAppendedFrag(pTime, PlaylistLevelType.MAIN)) == null ? void 0 : _this5$fragmentTracke.gap) === true) {
7648
- _this5.blockedAudioAppend = null;
7649
- _this5.operationQueue.shiftAndExecuteNext('audio');
7650
- }
7651
- },
7652
- onStart: function onStart() {},
7653
- onComplete: function onComplete() {},
7654
- onError: function onError() {}
7655
- };
7656
- this.blockedAudioAppend = {
7657
- op: op,
7658
- frag: partOrFrag
7659
- };
7660
- this.operationQueue.append(op, 'audio', true);
7661
- };
7662
- _proto.unblockAudio = function unblockAudio() {
7663
- var blockedAudioAppend = this.blockedAudioAppend;
7664
- if (blockedAudioAppend) {
7665
- this.blockedAudioAppend = null;
7666
- this.operationQueue.unblockAudio(blockedAudioAppend.op);
7667
- }
7668
- };
7669
7588
  _proto.onBufferAppending = function onBufferAppending(event, eventData) {
7670
- var _this6 = this;
7671
- var operationQueue = this.operationQueue,
7589
+ var _this5 = this;
7590
+ var hls = this.hls,
7591
+ operationQueue = this.operationQueue,
7672
7592
  tracks = this.tracks;
7673
7593
  var data = eventData.data,
7674
7594
  type = eventData.type,
7675
- parent = eventData.parent,
7676
7595
  frag = eventData.frag,
7677
7596
  part = eventData.part,
7678
7597
  chunkMeta = eventData.chunkMeta;
7679
7598
  var chunkStats = chunkMeta.buffering[type];
7680
- var sn = frag.sn;
7681
7599
  var bufferAppendingStart = self.performance.now();
7682
7600
  chunkStats.start = bufferAppendingStart;
7683
7601
  var fragBuffering = frag.stats.buffering;
@@ -7700,50 +7618,21 @@
7700
7618
  checkTimestampOffset = !this.lastMpegAudioChunk || chunkMeta.id === 1 || this.lastMpegAudioChunk.sn !== chunkMeta.sn;
7701
7619
  this.lastMpegAudioChunk = chunkMeta;
7702
7620
  }
7703
-
7704
- // Block audio append until overlapping video append
7705
- var videoSb = this.sourceBuffer.video;
7706
- if (videoSb && sn !== 'initSegment') {
7707
- var partOrFrag = part || frag;
7708
- var blockedAudioAppend = this.blockedAudioAppend;
7709
- if (type === 'audio' && parent !== 'main' && !this.blockedAudioAppend) {
7710
- var pStart = partOrFrag.start;
7711
- var pTime = pStart + partOrFrag.duration * 0.05;
7712
- var vbuffered = videoSb.buffered;
7713
- var vappending = this.operationQueue.current('video');
7714
- if (!vbuffered.length && !vappending) {
7715
- // wait for video before appending audio
7716
- this.blockAudio(partOrFrag);
7717
- } else if (!vappending && !BufferHelper.isBuffered(videoSb, pTime) && this.lastVideoAppendEnd < pTime) {
7718
- // audio is ahead of video
7719
- this.blockAudio(partOrFrag);
7720
- }
7721
- } else if (type === 'video') {
7722
- var videoAppendEnd = partOrFrag.end;
7723
- if (blockedAudioAppend) {
7724
- var audioStart = blockedAudioAppend.frag.start;
7725
- if (videoAppendEnd > audioStart || videoAppendEnd < this.lastVideoAppendEnd || BufferHelper.isBuffered(videoSb, audioStart)) {
7726
- this.unblockAudio();
7727
- }
7728
- }
7729
- this.lastVideoAppendEnd = videoAppendEnd;
7730
- }
7731
- }
7732
- var fragStart = (part || frag).start;
7621
+ var fragStart = frag.start;
7733
7622
  var operation = {
7734
7623
  execute: function execute() {
7735
7624
  chunkStats.executeStart = self.performance.now();
7736
7625
  if (checkTimestampOffset) {
7737
- var sb = _this6.sourceBuffer[type];
7626
+ var sb = _this5.sourceBuffer[type];
7738
7627
  if (sb) {
7739
7628
  var delta = fragStart - sb.timestampOffset;
7740
7629
  if (Math.abs(delta) >= 0.1) {
7741
- _this6.log("Updating audio SourceBuffer timestampOffset to " + fragStart + " (delta: " + delta + ") sn: " + sn + ")");
7630
+ _this5.log("Updating audio SourceBuffer timestampOffset to " + fragStart + " (delta: " + delta + ") sn: " + frag.sn + ")");
7742
7631
  sb.timestampOffset = fragStart;
7743
7632
  }
7744
7633
  }
7745
7634
  }
7746
- _this6.appendExecutor(data, type);
7635
+ _this5.appendExecutor(data, type);
7747
7636
  },
7748
7637
  onStart: function onStart() {
7749
7638
  // logger.debug(`[buffer-controller]: ${type} SourceBuffer updatestart`);
@@ -7758,19 +7647,19 @@
7758
7647
  if (partBuffering && partBuffering.first === 0) {
7759
7648
  partBuffering.first = end;
7760
7649
  }
7761
- var sourceBuffer = _this6.sourceBuffer;
7650
+ var sourceBuffer = _this5.sourceBuffer;
7762
7651
  var timeRanges = {};
7763
7652
  for (var _type in sourceBuffer) {
7764
7653
  timeRanges[_type] = BufferHelper.getBuffered(sourceBuffer[_type]);
7765
7654
  }
7766
- _this6.appendErrors[type] = 0;
7655
+ _this5.appendErrors[type] = 0;
7767
7656
  if (type === 'audio' || type === 'video') {
7768
- _this6.appendErrors.audiovideo = 0;
7657
+ _this5.appendErrors.audiovideo = 0;
7769
7658
  } else {
7770
- _this6.appendErrors.audio = 0;
7771
- _this6.appendErrors.video = 0;
7659
+ _this5.appendErrors.audio = 0;
7660
+ _this5.appendErrors.video = 0;
7772
7661
  }
7773
- _this6.hls.trigger(Events.BUFFER_APPENDED, {
7662
+ _this5.hls.trigger(Events.BUFFER_APPENDED, {
7774
7663
  type: type,
7775
7664
  frag: frag,
7776
7665
  part: part,
@@ -7798,57 +7687,51 @@
7798
7687
  // let's stop appending any segments, and report BUFFER_FULL_ERROR error
7799
7688
  event.details = ErrorDetails.BUFFER_FULL_ERROR;
7800
7689
  } else {
7801
- var appendErrorCount = ++_this6.appendErrors[type];
7690
+ var appendErrorCount = ++_this5.appendErrors[type];
7802
7691
  event.details = ErrorDetails.BUFFER_APPEND_ERROR;
7803
7692
  /* with UHD content, we could get loop of quota exceeded error until
7804
7693
  browser is able to evict some data from sourcebuffer. Retrying can help recover.
7805
7694
  */
7806
- _this6.warn("Failed " + appendErrorCount + "/" + _this6.hls.config.appendErrorMaxRetry + " times to append segment in \"" + type + "\" sourceBuffer");
7807
- if (appendErrorCount >= _this6.hls.config.appendErrorMaxRetry) {
7695
+ _this5.warn("Failed " + appendErrorCount + "/" + hls.config.appendErrorMaxRetry + " times to append segment in \"" + type + "\" sourceBuffer");
7696
+ if (appendErrorCount >= hls.config.appendErrorMaxRetry) {
7808
7697
  event.fatal = true;
7809
7698
  }
7810
7699
  }
7811
- _this6.hls.trigger(Events.ERROR, event);
7700
+ hls.trigger(Events.ERROR, event);
7812
7701
  }
7813
7702
  };
7814
7703
  operationQueue.append(operation, type, !!this.pendingTracks[type]);
7815
7704
  };
7816
- _proto.getFlushOp = function getFlushOp(type, start, end) {
7817
- var _this7 = this;
7818
- return {
7819
- execute: function execute() {
7820
- _this7.removeExecutor(type, start, end);
7821
- },
7822
- onStart: function onStart() {
7823
- // logger.debug(`[buffer-controller]: Started flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7824
- },
7825
- onComplete: function onComplete() {
7826
- // logger.debug(`[buffer-controller]: Finished flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7827
- _this7.hls.trigger(Events.BUFFER_FLUSHED, {
7828
- type: type
7829
- });
7830
- },
7831
- onError: function onError(error) {
7832
- _this7.warn("Failed to remove from " + type + " SourceBuffer", error);
7833
- }
7834
- };
7835
- };
7836
7705
  _proto.onBufferFlushing = function onBufferFlushing(event, data) {
7837
- var _this8 = this;
7706
+ var _this6 = this;
7838
7707
  var operationQueue = this.operationQueue;
7839
- var type = data.type,
7840
- startOffset = data.startOffset,
7841
- endOffset = data.endOffset;
7842
- if (type) {
7843
- operationQueue.append(this.getFlushOp(type, startOffset, endOffset), type);
7708
+ var flushOperation = function flushOperation(type) {
7709
+ return {
7710
+ execute: _this6.removeExecutor.bind(_this6, type, data.startOffset, data.endOffset),
7711
+ onStart: function onStart() {
7712
+ // logger.debug(`[buffer-controller]: Started flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7713
+ },
7714
+ onComplete: function onComplete() {
7715
+ // logger.debug(`[buffer-controller]: Finished flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7716
+ _this6.hls.trigger(Events.BUFFER_FLUSHED, {
7717
+ type: type
7718
+ });
7719
+ },
7720
+ onError: function onError(error) {
7721
+ _this6.warn("Failed to remove from " + type + " SourceBuffer", error);
7722
+ }
7723
+ };
7724
+ };
7725
+ if (data.type) {
7726
+ operationQueue.append(flushOperation(data.type), data.type);
7844
7727
  } else {
7845
- this.getSourceBufferTypes().forEach(function (sbType) {
7846
- operationQueue.append(_this8.getFlushOp(sbType, startOffset, endOffset), sbType);
7728
+ this.getSourceBufferTypes().forEach(function (type) {
7729
+ operationQueue.append(flushOperation(type), type);
7847
7730
  });
7848
7731
  }
7849
7732
  };
7850
7733
  _proto.onFragParsed = function onFragParsed(event, data) {
7851
- var _this9 = this;
7734
+ var _this7 = this;
7852
7735
  var frag = data.frag,
7853
7736
  part = data.part;
7854
7737
  var buffersAppendedTo = [];
@@ -7870,7 +7753,7 @@
7870
7753
  part.stats.buffering.end = now;
7871
7754
  }
7872
7755
  var stats = part ? part.stats : frag.stats;
7873
- _this9.hls.trigger(Events.FRAG_BUFFERED, {
7756
+ _this7.hls.trigger(Events.FRAG_BUFFERED, {
7874
7757
  frag: frag,
7875
7758
  part: part,
7876
7759
  stats: stats,
@@ -7890,17 +7773,14 @@
7890
7773
  // an undefined data.type will mark all buffers as EOS.
7891
7774
  ;
7892
7775
  _proto.onBufferEos = function onBufferEos(event, data) {
7893
- var _this10 = this;
7894
- if (data.type === 'video') {
7895
- this.unblockAudio();
7896
- }
7776
+ var _this8 = this;
7897
7777
  var ended = this.getSourceBufferTypes().reduce(function (acc, type) {
7898
- var sb = _this10.sourceBuffer[type];
7778
+ var sb = _this8.sourceBuffer[type];
7899
7779
  if (sb && (!data.type || data.type === type)) {
7900
7780
  sb.ending = true;
7901
7781
  if (!sb.ended) {
7902
7782
  sb.ended = true;
7903
- _this10.log(type + " sourceBuffer now EOS");
7783
+ _this8.log(type + " sourceBuffer now EOS");
7904
7784
  }
7905
7785
  }
7906
7786
  return acc && !!(!sb || sb.ended);
@@ -7908,42 +7788,35 @@
7908
7788
  if (ended) {
7909
7789
  this.log("Queueing mediaSource.endOfStream()");
7910
7790
  this.blockBuffers(function () {
7911
- _this10.getSourceBufferTypes().forEach(function (type) {
7912
- var sb = _this10.sourceBuffer[type];
7791
+ _this8.getSourceBufferTypes().forEach(function (type) {
7792
+ var sb = _this8.sourceBuffer[type];
7913
7793
  if (sb) {
7914
7794
  sb.ending = false;
7915
7795
  }
7916
7796
  });
7917
- var mediaSource = _this10.mediaSource;
7797
+ var mediaSource = _this8.mediaSource;
7918
7798
  if (!mediaSource || mediaSource.readyState !== 'open') {
7919
7799
  if (mediaSource) {
7920
- _this10.log("Could not call mediaSource.endOfStream(). mediaSource.readyState: " + mediaSource.readyState);
7800
+ _this8.log("Could not call mediaSource.endOfStream(). mediaSource.readyState: " + mediaSource.readyState);
7921
7801
  }
7922
7802
  return;
7923
7803
  }
7924
- _this10.log("Calling mediaSource.endOfStream()");
7804
+ _this8.log("Calling mediaSource.endOfStream()");
7925
7805
  // Allow this to throw and be caught by the enqueueing function
7926
7806
  mediaSource.endOfStream();
7927
7807
  });
7928
7808
  }
7929
7809
  };
7930
7810
  _proto.onLevelUpdated = function onLevelUpdated(event, _ref) {
7931
- var _this11 = this;
7932
7811
  var details = _ref.details;
7933
7812
  if (!details.fragments.length) {
7934
7813
  return;
7935
7814
  }
7936
7815
  this.details = details;
7937
- var durationAndRange = this.getDurationAndRange();
7938
- if (!durationAndRange) {
7939
- return;
7940
- }
7941
7816
  if (this.getSourceBufferTypes().length) {
7942
- this.blockBuffers(function () {
7943
- return _this11.updateMediaSource(durationAndRange);
7944
- });
7817
+ this.blockBuffers(this.updateMediaElementDuration.bind(this));
7945
7818
  } else {
7946
- this.updateMediaSource(durationAndRange);
7819
+ this.updateMediaElementDuration();
7947
7820
  }
7948
7821
  };
7949
7822
  _proto.trimBuffers = function trimBuffers() {
@@ -7976,7 +7849,7 @@
7976
7849
  }
7977
7850
  };
7978
7851
  _proto.flushBackBuffer = function flushBackBuffer(currentTime, targetDuration, targetBackBufferPosition) {
7979
- var _this12 = this;
7852
+ var _this9 = this;
7980
7853
  var details = this.details,
7981
7854
  sourceBuffer = this.sourceBuffer;
7982
7855
  var sourceBufferTypes = this.getSourceBufferTypes();
@@ -7986,20 +7859,20 @@
7986
7859
  var buffered = BufferHelper.getBuffered(sb);
7987
7860
  // when target buffer start exceeds actual buffer start
7988
7861
  if (buffered.length > 0 && targetBackBufferPosition > buffered.start(0)) {
7989
- _this12.hls.trigger(Events.BACK_BUFFER_REACHED, {
7862
+ _this9.hls.trigger(Events.BACK_BUFFER_REACHED, {
7990
7863
  bufferEnd: targetBackBufferPosition
7991
7864
  });
7992
7865
 
7993
7866
  // Support for deprecated event:
7994
7867
  if (details != null && details.live) {
7995
- _this12.hls.trigger(Events.LIVE_BACK_BUFFER_REACHED, {
7868
+ _this9.hls.trigger(Events.LIVE_BACK_BUFFER_REACHED, {
7996
7869
  bufferEnd: targetBackBufferPosition
7997
7870
  });
7998
7871
  } else if (sb.ended && buffered.end(buffered.length - 1) - currentTime < targetDuration * 2) {
7999
- _this12.log("Cannot flush " + type + " back buffer while SourceBuffer is in ended state");
7872
+ _this9.log("Cannot flush " + type + " back buffer while SourceBuffer is in ended state");
8000
7873
  return;
8001
7874
  }
8002
- _this12.hls.trigger(Events.BUFFER_FLUSHING, {
7875
+ _this9.hls.trigger(Events.BUFFER_FLUSHING, {
8003
7876
  startOffset: 0,
8004
7877
  endOffset: targetBackBufferPosition,
8005
7878
  type: type
@@ -8009,7 +7882,7 @@
8009
7882
  });
8010
7883
  };
8011
7884
  _proto.flushFrontBuffer = function flushFrontBuffer(currentTime, targetDuration, targetFrontBufferPosition) {
8012
- var _this13 = this;
7885
+ var _this10 = this;
8013
7886
  var sourceBuffer = this.sourceBuffer;
8014
7887
  var sourceBufferTypes = this.getSourceBufferTypes();
8015
7888
  sourceBufferTypes.forEach(function (type) {
@@ -8027,10 +7900,10 @@
8027
7900
  if (targetFrontBufferPosition > bufferStart || currentTime >= bufferStart && currentTime <= bufferEnd) {
8028
7901
  return;
8029
7902
  } else if (sb.ended && currentTime - bufferEnd < 2 * targetDuration) {
8030
- _this13.log("Cannot flush " + type + " front buffer while SourceBuffer is in ended state");
7903
+ _this10.log("Cannot flush " + type + " front buffer while SourceBuffer is in ended state");
8031
7904
  return;
8032
7905
  }
8033
- _this13.hls.trigger(Events.BUFFER_FLUSHING, {
7906
+ _this10.hls.trigger(Events.BUFFER_FLUSHING, {
8034
7907
  startOffset: bufferStart,
8035
7908
  endOffset: Infinity,
8036
7909
  type: type
@@ -8044,9 +7917,9 @@
8044
7917
  * 'liveDurationInfinity` is set to `true`
8045
7918
  * More details: https://github.com/video-dev/hls.js/issues/355
8046
7919
  */;
8047
- _proto.getDurationAndRange = function getDurationAndRange() {
7920
+ _proto.updateMediaElementDuration = function updateMediaElementDuration() {
8048
7921
  if (!this.details || !this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
8049
- return null;
7922
+ return;
8050
7923
  }
8051
7924
  var details = this.details,
8052
7925
  hls = this.hls,
@@ -8058,40 +7931,25 @@
8058
7931
  if (details.live && hls.config.liveDurationInfinity) {
8059
7932
  // Override duration to Infinity
8060
7933
  mediaSource.duration = Infinity;
8061
- var len = details.fragments.length;
8062
- if (len && details.live && !!mediaSource.setLiveSeekableRange) {
8063
- var start = Math.max(0, details.fragments[0].start);
8064
- var end = Math.max(start, start + details.totalduration);
8065
- return {
8066
- duration: Infinity,
8067
- start: start,
8068
- end: end
8069
- };
8070
- }
8071
- return {
8072
- duration: Infinity
8073
- };
7934
+ this.updateSeekableRange(details);
8074
7935
  } else if (levelDuration > msDuration && levelDuration > mediaDuration || !isFiniteNumber(mediaDuration)) {
8075
- return {
8076
- duration: levelDuration
8077
- };
7936
+ // levelDuration was the last value we set.
7937
+ // not using mediaSource.duration as the browser may tweak this value
7938
+ // only update Media Source duration if its value increase, this is to avoid
7939
+ // flushing already buffered portion when switching between quality level
7940
+ this.log("Updating Media Source duration to " + levelDuration.toFixed(3));
7941
+ mediaSource.duration = levelDuration;
8078
7942
  }
8079
- return null;
8080
7943
  };
8081
- _proto.updateMediaSource = function updateMediaSource(_ref2) {
8082
- var duration = _ref2.duration,
8083
- start = _ref2.start,
8084
- end = _ref2.end;
8085
- if (!this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
8086
- return;
8087
- }
8088
- if (isFiniteNumber(duration)) {
8089
- this.log("Updating Media Source duration to " + duration.toFixed(3));
8090
- }
8091
- this.mediaSource.duration = duration;
8092
- if (start !== undefined && end !== undefined) {
8093
- this.log("Media Source duration is set to " + this.mediaSource.duration + ". Setting seekable range to " + start + "-" + end + ".");
8094
- this.mediaSource.setLiveSeekableRange(start, end);
7944
+ _proto.updateSeekableRange = function updateSeekableRange(levelDetails) {
7945
+ var mediaSource = this.mediaSource;
7946
+ var fragments = levelDetails.fragments;
7947
+ var len = fragments.length;
7948
+ if (len && levelDetails.live && mediaSource != null && mediaSource.setLiveSeekableRange) {
7949
+ var start = Math.max(0, fragments[0].start);
7950
+ var end = Math.max(start, start + levelDetails.totalduration);
7951
+ this.log("Media Source duration is set to " + mediaSource.duration + ". Setting seekable range to " + start + "-" + end + ".");
7952
+ mediaSource.setLiveSeekableRange(start, end);
8095
7953
  }
8096
7954
  };
8097
7955
  _proto.checkPendingTracks = function checkPendingTracks() {
@@ -8130,7 +7988,7 @@
8130
7988
  }
8131
7989
  };
8132
7990
  _proto.createSourceBuffers = function createSourceBuffers(tracks) {
8133
- var _this14 = this;
7991
+ var _this11 = this;
8134
7992
  var sourceBuffer = this.sourceBuffer,
8135
7993
  mediaSource = this.mediaSource;
8136
7994
  if (!mediaSource) {
@@ -8146,28 +8004,30 @@
8146
8004
  var codec = track.levelCodec || track.codec;
8147
8005
  if (codec) {
8148
8006
  if (trackName.slice(0, 5) === 'audio') {
8149
- codec = getCodecCompatibleName(codec, _this14.hls.config.preferManagedMediaSource);
8007
+ codec = getCodecCompatibleName(codec, _this11.appendSource);
8150
8008
  }
8151
8009
  }
8152
8010
  var mimeType = track.container + ";codecs=" + codec;
8153
- _this14.log("creating sourceBuffer(" + mimeType + ")");
8011
+ _this11.log("creating sourceBuffer(" + mimeType + ")");
8154
8012
  try {
8155
8013
  var sb = sourceBuffer[trackName] = mediaSource.addSourceBuffer(mimeType);
8156
8014
  var sbName = trackName;
8157
- _this14.addBufferListener(sbName, 'updatestart', _this14._onSBUpdateStart);
8158
- _this14.addBufferListener(sbName, 'updateend', _this14._onSBUpdateEnd);
8159
- _this14.addBufferListener(sbName, 'error', _this14._onSBUpdateError);
8015
+ _this11.addBufferListener(sbName, 'updatestart', _this11._onSBUpdateStart);
8016
+ _this11.addBufferListener(sbName, 'updateend', _this11._onSBUpdateEnd);
8017
+ _this11.addBufferListener(sbName, 'error', _this11._onSBUpdateError);
8160
8018
  // ManagedSourceBuffer bufferedchange event
8161
- _this14.addBufferListener(sbName, 'bufferedchange', function (type, event) {
8162
- // If media was ejected check for a change. Added ranges are redundant with changes on 'updateend' event.
8163
- var removedRanges = event.removedRanges;
8164
- if (removedRanges != null && removedRanges.length) {
8165
- _this14.hls.trigger(Events.BUFFER_FLUSHED, {
8166
- type: trackName
8167
- });
8168
- }
8169
- });
8170
- _this14.tracks[trackName] = {
8019
+ if (_this11.appendSource) {
8020
+ _this11.addBufferListener(sbName, 'bufferedchange', function (type, event) {
8021
+ // If media was ejected check for a change. Added ranges are redundant with changes on 'updateend' event.
8022
+ var removedRanges = event.removedRanges;
8023
+ if (removedRanges != null && removedRanges.length) {
8024
+ _this11.hls.trigger(Events.BUFFER_FLUSHED, {
8025
+ type: trackName
8026
+ });
8027
+ }
8028
+ });
8029
+ }
8030
+ _this11.tracks[trackName] = {
8171
8031
  buffer: sb,
8172
8032
  codec: codec,
8173
8033
  container: track.container,
@@ -8176,8 +8036,8 @@
8176
8036
  id: track.id
8177
8037
  };
8178
8038
  } catch (err) {
8179
- _this14.error("error while trying to add sourceBuffer: " + err.message);
8180
- _this14.hls.trigger(Events.ERROR, {
8039
+ _this11.error("error while trying to add sourceBuffer: " + err.message);
8040
+ _this11.hls.trigger(Events.ERROR, {
8181
8041
  type: ErrorTypes.MEDIA_ERROR,
8182
8042
  details: ErrorDetails.BUFFER_ADD_CODEC_ERROR,
8183
8043
  fatal: false,
@@ -8265,7 +8125,6 @@
8265
8125
  }
8266
8126
  return;
8267
8127
  }
8268
- sb.ending = false;
8269
8128
  sb.ended = false;
8270
8129
  sb.appendBuffer(data);
8271
8130
  }
@@ -8275,7 +8134,7 @@
8275
8134
  // upon completion, since we already do it here
8276
8135
  ;
8277
8136
  _proto.blockBuffers = function blockBuffers(onUnblocked, buffers) {
8278
- var _this15 = this;
8137
+ var _this12 = this;
8279
8138
  if (buffers === void 0) {
8280
8139
  buffers = this.getSourceBufferTypes();
8281
8140
  }
@@ -8290,15 +8149,11 @@
8290
8149
  var blockingOperations = buffers.map(function (type) {
8291
8150
  return operationQueue.appendBlocker(type);
8292
8151
  });
8293
- var audioBlocked = buffers.length > 1 && !!this.blockedAudioAppend;
8294
- if (audioBlocked) {
8295
- this.unblockAudio();
8296
- }
8297
- Promise.all(blockingOperations).then(function (result) {
8152
+ Promise.all(blockingOperations).then(function () {
8298
8153
  // logger.debug(`[buffer-controller]: Blocking operation resolved; unblocking ${buffers} SourceBuffer`);
8299
8154
  onUnblocked();
8300
- buffers.forEach(function (type, i) {
8301
- var sb = _this15.sourceBuffer[type];
8155
+ buffers.forEach(function (type) {
8156
+ var sb = _this12.sourceBuffer[type];
8302
8157
  // Only cycle the queue if the SB is not updating. There's a bug in Chrome which sets the SB updating flag to
8303
8158
  // true when changing the MediaSource duration (https://bugs.chromium.org/p/chromium/issues/detail?id=959359&can=2&q=mediasource%20duration)
8304
8159
  // While this is a workaround, it's probably useful to have around
@@ -8341,7 +8196,7 @@
8341
8196
  }
8342
8197
  }]);
8343
8198
  return BufferController;
8344
- }(Logger);
8199
+ }();
8345
8200
  function removeSourceChildren(node) {
8346
8201
  var sourceChildren = node.querySelectorAll('source');
8347
8202
  [].slice.call(sourceChildren).forEach(function (source) {
@@ -8465,10 +8320,10 @@
8465
8320
  var hls = this.hls;
8466
8321
  var maxLevel = this.getMaxLevel(levels.length - 1);
8467
8322
  if (maxLevel !== this.autoLevelCapping) {
8468
- hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8323
+ logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8469
8324
  }
8470
8325
  hls.autoLevelCapping = maxLevel;
8471
- if (hls.autoLevelEnabled && hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
8326
+ if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
8472
8327
  // if auto level capping has a higher value for the previous one, flush the buffer using nextLevelSwitch
8473
8328
  // usually happen when the user go to the fullscreen mode.
8474
8329
  this.streamController.nextLevelSwitch();
@@ -8655,10 +8510,10 @@
8655
8510
  totalDroppedFrames: droppedFrames
8656
8511
  });
8657
8512
  if (droppedFPS > 0) {
8658
- // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8513
+ // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8659
8514
  if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
8660
8515
  var currentLevel = hls.currentLevel;
8661
- hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8516
+ logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8662
8517
  if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
8663
8518
  currentLevel = currentLevel - 1;
8664
8519
  hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
@@ -8692,28 +8547,26 @@
8692
8547
  }();
8693
8548
 
8694
8549
  var PATHWAY_PENALTY_DURATION_MS = 300000;
8695
- var ContentSteeringController = /*#__PURE__*/function (_Logger) {
8696
- _inheritsLoose(ContentSteeringController, _Logger);
8550
+ var ContentSteeringController = /*#__PURE__*/function () {
8697
8551
  function ContentSteeringController(hls) {
8698
- var _this;
8699
- _this = _Logger.call(this, 'content-steering', hls.logger) || this;
8700
- _this.hls = void 0;
8701
- _this.loader = null;
8702
- _this.uri = null;
8703
- _this.pathwayId = '.';
8704
- _this.pathwayPriority = null;
8705
- _this.timeToLoad = 300;
8706
- _this.reloadTimer = -1;
8707
- _this.updated = 0;
8708
- _this.started = false;
8709
- _this.enabled = true;
8710
- _this.levels = null;
8711
- _this.audioTracks = null;
8712
- _this.subtitleTracks = null;
8713
- _this.penalizedPathways = {};
8714
- _this.hls = hls;
8715
- _this.registerListeners();
8716
- return _this;
8552
+ this.hls = void 0;
8553
+ this.log = void 0;
8554
+ this.loader = null;
8555
+ this.uri = null;
8556
+ this.pathwayId = '.';
8557
+ this.pathwayPriority = null;
8558
+ this.timeToLoad = 300;
8559
+ this.reloadTimer = -1;
8560
+ this.updated = 0;
8561
+ this.started = false;
8562
+ this.enabled = true;
8563
+ this.levels = null;
8564
+ this.audioTracks = null;
8565
+ this.subtitleTracks = null;
8566
+ this.penalizedPathways = {};
8567
+ this.hls = hls;
8568
+ this.log = logger.log.bind(logger, "[content-steering]:");
8569
+ this.registerListeners();
8717
8570
  }
8718
8571
  var _proto = ContentSteeringController.prototype;
8719
8572
  _proto.registerListeners = function registerListeners() {
@@ -8834,7 +8687,7 @@
8834
8687
  errorAction.resolved = this.pathwayId !== errorPathway;
8835
8688
  }
8836
8689
  if (!errorAction.resolved) {
8837
- this.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
8690
+ logger.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
8838
8691
  }
8839
8692
  }
8840
8693
  };
@@ -8914,7 +8767,7 @@
8914
8767
  return defaultPathway;
8915
8768
  };
8916
8769
  _proto.clonePathways = function clonePathways(pathwayClones) {
8917
- var _this2 = this;
8770
+ var _this = this;
8918
8771
  var levels = this.levels;
8919
8772
  if (!levels) {
8920
8773
  return;
@@ -8930,7 +8783,7 @@
8930
8783
  })) {
8931
8784
  return;
8932
8785
  }
8933
- var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
8786
+ var clonedVariants = _this.getLevelsForPathway(baseId).map(function (baseLevel) {
8934
8787
  var attributes = new AttrList(baseLevel.attrs);
8935
8788
  attributes['PATHWAY-ID'] = cloneId;
8936
8789
  var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
@@ -8967,12 +8820,12 @@
8967
8820
  return clonedLevel;
8968
8821
  });
8969
8822
  levels.push.apply(levels, clonedVariants);
8970
- cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8971
- cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8823
+ cloneRenditionGroups(_this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8824
+ cloneRenditionGroups(_this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8972
8825
  });
8973
8826
  };
8974
8827
  _proto.loadSteeringManifest = function loadSteeringManifest(uri) {
8975
- var _this3 = this;
8828
+ var _this2 = this;
8976
8829
  var config = this.hls.config;
8977
8830
  var Loader = config.loader;
8978
8831
  if (this.loader) {
@@ -9007,87 +8860,87 @@
9007
8860
  };
9008
8861
  var callbacks = {
9009
8862
  onSuccess: function onSuccess(response, stats, context, networkDetails) {
9010
- _this3.log("Loaded steering manifest: \"" + url + "\"");
8863
+ _this2.log("Loaded steering manifest: \"" + url + "\"");
9011
8864
  var steeringData = response.data;
9012
- if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
9013
- _this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
8865
+ if (steeringData.VERSION !== 1) {
8866
+ _this2.log("Steering VERSION " + steeringData.VERSION + " not supported!");
9014
8867
  return;
9015
8868
  }
9016
- _this3.updated = performance.now();
9017
- _this3.timeToLoad = steeringData.TTL;
8869
+ _this2.updated = performance.now();
8870
+ _this2.timeToLoad = steeringData.TTL;
9018
8871
  var reloadUri = steeringData['RELOAD-URI'],
9019
8872
  pathwayClones = steeringData['PATHWAY-CLONES'],
9020
8873
  pathwayPriority = steeringData['PATHWAY-PRIORITY'];
9021
8874
  if (reloadUri) {
9022
8875
  try {
9023
- _this3.uri = new self.URL(reloadUri, url).href;
8876
+ _this2.uri = new self.URL(reloadUri, url).href;
9024
8877
  } catch (error) {
9025
- _this3.enabled = false;
9026
- _this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
8878
+ _this2.enabled = false;
8879
+ _this2.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
9027
8880
  return;
9028
8881
  }
9029
8882
  }
9030
- _this3.scheduleRefresh(_this3.uri || context.url);
8883
+ _this2.scheduleRefresh(_this2.uri || context.url);
9031
8884
  if (pathwayClones) {
9032
- _this3.clonePathways(pathwayClones);
8885
+ _this2.clonePathways(pathwayClones);
9033
8886
  }
9034
8887
  var loadedSteeringData = {
9035
8888
  steeringManifest: steeringData,
9036
8889
  url: url.toString()
9037
8890
  };
9038
- _this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8891
+ _this2.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
9039
8892
  if (pathwayPriority) {
9040
- _this3.updatePathwayPriority(pathwayPriority);
8893
+ _this2.updatePathwayPriority(pathwayPriority);
9041
8894
  }
9042
8895
  },
9043
8896
  onError: function onError(error, context, networkDetails, stats) {
9044
- _this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
9045
- _this3.stopLoad();
8897
+ _this2.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8898
+ _this2.stopLoad();
9046
8899
  if (error.code === 410) {
9047
- _this3.enabled = false;
9048
- _this3.log("Steering manifest " + context.url + " no longer available");
8900
+ _this2.enabled = false;
8901
+ _this2.log("Steering manifest " + context.url + " no longer available");
9049
8902
  return;
9050
8903
  }
9051
- var ttl = _this3.timeToLoad * 1000;
8904
+ var ttl = _this2.timeToLoad * 1000;
9052
8905
  if (error.code === 429) {
9053
- var loader = _this3.loader;
8906
+ var loader = _this2.loader;
9054
8907
  if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
9055
8908
  var retryAfter = loader.getResponseHeader('Retry-After');
9056
8909
  if (retryAfter) {
9057
8910
  ttl = parseFloat(retryAfter) * 1000;
9058
8911
  }
9059
8912
  }
9060
- _this3.log("Steering manifest " + context.url + " rate limited");
8913
+ _this2.log("Steering manifest " + context.url + " rate limited");
9061
8914
  return;
9062
8915
  }
9063
- _this3.scheduleRefresh(_this3.uri || context.url, ttl);
8916
+ _this2.scheduleRefresh(_this2.uri || context.url, ttl);
9064
8917
  },
9065
8918
  onTimeout: function onTimeout(stats, context, networkDetails) {
9066
- _this3.log("Timeout loading steering manifest (" + context.url + ")");
9067
- _this3.scheduleRefresh(_this3.uri || context.url);
8919
+ _this2.log("Timeout loading steering manifest (" + context.url + ")");
8920
+ _this2.scheduleRefresh(_this2.uri || context.url);
9068
8921
  }
9069
8922
  };
9070
8923
  this.log("Requesting steering manifest: " + url);
9071
8924
  this.loader.load(context, loaderConfig, callbacks);
9072
8925
  };
9073
8926
  _proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
9074
- var _this4 = this;
8927
+ var _this3 = this;
9075
8928
  if (ttlMs === void 0) {
9076
8929
  ttlMs = this.timeToLoad * 1000;
9077
8930
  }
9078
8931
  this.clearTimeout();
9079
8932
  this.reloadTimer = self.setTimeout(function () {
9080
- var _this4$hls;
9081
- var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
8933
+ var _this3$hls;
8934
+ var media = (_this3$hls = _this3.hls) == null ? void 0 : _this3$hls.media;
9082
8935
  if (media && !media.ended) {
9083
- _this4.loadSteeringManifest(uri);
8936
+ _this3.loadSteeringManifest(uri);
9084
8937
  return;
9085
8938
  }
9086
- _this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
8939
+ _this3.scheduleRefresh(uri, _this3.timeToLoad * 1000);
9087
8940
  }, ttlMs);
9088
8941
  };
9089
8942
  return ContentSteeringController;
9090
- }(Logger);
8943
+ }();
9091
8944
  function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
9092
8945
  if (!tracks) {
9093
8946
  return;
@@ -9923,7 +9776,7 @@
9923
9776
  });
9924
9777
  function timelineConfig() {
9925
9778
  return {
9926
- cueHandler: HevcVideoParser,
9779
+ cueHandler: Cues,
9927
9780
  // used by timeline-controller
9928
9781
  enableWebVTT: false,
9929
9782
  // used by timeline-controller
@@ -9954,7 +9807,7 @@
9954
9807
  /**
9955
9808
  * @ignore
9956
9809
  */
9957
- function mergeConfig(defaultConfig, userConfig, logger) {
9810
+ function mergeConfig(defaultConfig, userConfig) {
9958
9811
  if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
9959
9812
  throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
9960
9813
  }
@@ -10024,7 +9877,7 @@
10024
9877
  /**
10025
9878
  * @ignore
10026
9879
  */
10027
- function enableStreamingMode(config, logger) {
9880
+ function enableStreamingMode(config) {
10028
9881
  var currentLoader = config.loader;
10029
9882
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
10030
9883
  // If a developer has configured their own loader, respect that choice
@@ -10041,11 +9894,12 @@
10041
9894
  }
10042
9895
  }
10043
9896
 
9897
+ var chromeOrFirefox;
10044
9898
  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
10045
9899
  _inheritsLoose(LevelController, _BasePlaylistControll);
10046
9900
  function LevelController(hls, contentSteeringController) {
10047
9901
  var _this;
10048
- _this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
9902
+ _this = _BasePlaylistControll.call(this, hls, '[level-controller]') || this;
10049
9903
  _this._levels = [];
10050
9904
  _this._firstLevel = -1;
10051
9905
  _this._maxAutoLevel = -1;
@@ -10114,13 +9968,21 @@
10114
9968
  var videoCodecFound = false;
10115
9969
  var audioCodecFound = false;
10116
9970
  data.levels.forEach(function (levelParsed) {
10117
- var _videoCodec;
9971
+ var _audioCodec, _videoCodec;
10118
9972
  var attributes = levelParsed.attrs;
9973
+
9974
+ // erase audio codec info if browser does not support mp4a.40.34.
9975
+ // demuxer will autodetect codec and fallback to mpeg/audio
10119
9976
  var audioCodec = levelParsed.audioCodec,
10120
9977
  videoCodec = levelParsed.videoCodec;
9978
+ if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
9979
+ chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
9980
+ if (chromeOrFirefox) {
9981
+ levelParsed.audioCodec = audioCodec = undefined;
9982
+ }
9983
+ }
10121
9984
  if (audioCodec) {
10122
- // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
10123
- levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
9985
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
10124
9986
  }
10125
9987
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
10126
9988
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -10352,12 +10214,7 @@
10352
10214
  if (curLevel.fragmentError === 0) {
10353
10215
  curLevel.loadError = 0;
10354
10216
  }
10355
- // Ignore matching details populated by loading a Media Playlist directly
10356
- var previousDetails = curLevel.details;
10357
- if (previousDetails === data.details && previousDetails.advanced) {
10358
- previousDetails = undefined;
10359
- }
10360
- this.playlistLoaded(level, data, previousDetails);
10217
+ this.playlistLoaded(level, data, curLevel.details);
10361
10218
  } else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
10362
10219
  // received a delta playlist update that cannot be merged
10363
10220
  details.deltaUpdateFailed = true;
@@ -10657,14 +10514,11 @@
10657
10514
  * If not found any Fragment, return null
10658
10515
  */;
10659
10516
  _proto.getBufferedFrag = function getBufferedFrag(position, levelType) {
10660
- return this.getFragAtPos(position, levelType, true);
10661
- };
10662
- _proto.getFragAtPos = function getFragAtPos(position, levelType, buffered) {
10663
10517
  var fragments = this.fragments;
10664
10518
  var keys = Object.keys(fragments);
10665
10519
  for (var i = keys.length; i--;) {
10666
10520
  var fragmentEntity = fragments[keys[i]];
10667
- if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && (!buffered || fragmentEntity.buffered)) {
10521
+ if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && fragmentEntity.buffered) {
10668
10522
  var frag = fragmentEntity.body;
10669
10523
  if (frag.start <= position && position <= frag.end) {
10670
10524
  return frag;
@@ -10914,10 +10768,10 @@
10914
10768
  };
10915
10769
  };
10916
10770
  _proto.onBufferAppended = function onBufferAppended(event, data) {
10771
+ var _this3 = this;
10917
10772
  var frag = data.frag,
10918
10773
  part = data.part,
10919
- timeRanges = data.timeRanges,
10920
- type = data.type;
10774
+ timeRanges = data.timeRanges;
10921
10775
  if (frag.sn === 'initSegment') {
10922
10776
  return;
10923
10777
  }
@@ -10931,8 +10785,10 @@
10931
10785
  }
10932
10786
  // Store the latest timeRanges loaded in the buffer
10933
10787
  this.timeRanges = timeRanges;
10934
- var timeRange = timeRanges[type];
10935
- this.detectEvictedFragments(type, timeRange, playlistType, part);
10788
+ Object.keys(timeRanges).forEach(function (elementaryStream) {
10789
+ var timeRange = timeRanges[elementaryStream];
10790
+ _this3.detectEvictedFragments(elementaryStream, timeRange, playlistType, part);
10791
+ });
10936
10792
  };
10937
10793
  _proto.onFragBuffered = function onFragBuffered(event, data) {
10938
10794
  this.detectPartialFragments(data);
@@ -10946,12 +10802,12 @@
10946
10802
  return !!((_this$activePartLists = this.activePartLists[type]) != null && _this$activePartLists.length);
10947
10803
  };
10948
10804
  _proto.removeFragmentsInRange = function removeFragmentsInRange(start, end, playlistType, withGapOnly, unbufferedOnly) {
10949
- var _this3 = this;
10805
+ var _this4 = this;
10950
10806
  if (withGapOnly && !this.hasGaps) {
10951
10807
  return;
10952
10808
  }
10953
10809
  Object.keys(this.fragments).forEach(function (key) {
10954
- var fragmentEntity = _this3.fragments[key];
10810
+ var fragmentEntity = _this4.fragments[key];
10955
10811
  if (!fragmentEntity) {
10956
10812
  return;
10957
10813
  }
@@ -10960,7 +10816,7 @@
10960
10816
  return;
10961
10817
  }
10962
10818
  if (frag.start < end && frag.end > start && (fragmentEntity.buffered || unbufferedOnly)) {
10963
- _this3.removeFragment(frag);
10819
+ _this4.removeFragment(frag);
10964
10820
  }
10965
10821
  });
10966
10822
  };
@@ -11273,8 +11129,8 @@
11273
11129
  var _frag$decryptdata;
11274
11130
  var byteRangeStart = start;
11275
11131
  var byteRangeEnd = end;
11276
- if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
11277
- // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
11132
+ if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
11133
+ // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
11278
11134
  // has the unencrypted size specified in the range.
11279
11135
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
11280
11136
  var fragmentLen = end - start;
@@ -11307,9 +11163,6 @@
11307
11163
  (part ? part : frag).stats.aborted = true;
11308
11164
  return new LoadError(errorData);
11309
11165
  }
11310
- function isMethodFullSegmentAesCbc(method) {
11311
- return method === 'AES-128' || method === 'AES-256';
11312
- }
11313
11166
  var LoadError = /*#__PURE__*/function (_Error) {
11314
11167
  _inheritsLoose(LoadError, _Error);
11315
11168
  function LoadError(data) {
@@ -11466,8 +11319,6 @@
11466
11319
  }
11467
11320
  return this.loadKeyEME(keyInfo, frag);
11468
11321
  case 'AES-128':
11469
- case 'AES-256':
11470
- case 'AES-256-CTR':
11471
11322
  return this.loadKeyHTTP(keyInfo, frag);
11472
11323
  default:
11473
11324
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
@@ -11601,17 +11452,13 @@
11601
11452
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
11602
11453
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
11603
11454
  */
11604
- var TaskLoop = /*#__PURE__*/function (_Logger) {
11605
- _inheritsLoose(TaskLoop, _Logger);
11606
- function TaskLoop(label, logger) {
11607
- var _this;
11608
- _this = _Logger.call(this, label, logger) || this;
11609
- _this._boundTick = void 0;
11610
- _this._tickTimer = null;
11611
- _this._tickInterval = null;
11612
- _this._tickCallCount = 0;
11613
- _this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
11614
- return _this;
11455
+ var TaskLoop = /*#__PURE__*/function () {
11456
+ function TaskLoop() {
11457
+ this._boundTick = void 0;
11458
+ this._tickTimer = null;
11459
+ this._tickInterval = null;
11460
+ this._tickCallCount = 0;
11461
+ this._boundTick = this.tick.bind(this);
11615
11462
  }
11616
11463
  var _proto = TaskLoop.prototype;
11617
11464
  _proto.destroy = function destroy() {
@@ -11697,7 +11544,7 @@
11697
11544
  */;
11698
11545
  _proto.doTick = function doTick() {};
11699
11546
  return TaskLoop;
11700
- }(Logger);
11547
+ }();
11701
11548
 
11702
11549
  var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
11703
11550
  if (size === void 0) {
@@ -11883,65 +11730,37 @@
11883
11730
  }
11884
11731
 
11885
11732
  var AESCrypto = /*#__PURE__*/function () {
11886
- function AESCrypto(subtle, iv, aesMode) {
11733
+ function AESCrypto(subtle, iv) {
11887
11734
  this.subtle = void 0;
11888
11735
  this.aesIV = void 0;
11889
- this.aesMode = void 0;
11890
11736
  this.subtle = subtle;
11891
11737
  this.aesIV = iv;
11892
- this.aesMode = aesMode;
11893
11738
  }
11894
11739
  var _proto = AESCrypto.prototype;
11895
11740
  _proto.decrypt = function decrypt(data, key) {
11896
- switch (this.aesMode) {
11897
- case DecrypterAesMode.cbc:
11898
- return this.subtle.decrypt({
11899
- name: 'AES-CBC',
11900
- iv: this.aesIV
11901
- }, key, data);
11902
- case DecrypterAesMode.ctr:
11903
- return this.subtle.decrypt({
11904
- name: 'AES-CTR',
11905
- counter: this.aesIV,
11906
- length: 64
11907
- },
11908
- //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
11909
- key, data);
11910
- default:
11911
- throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
11912
- }
11741
+ return this.subtle.decrypt({
11742
+ name: 'AES-CBC',
11743
+ iv: this.aesIV
11744
+ }, key, data);
11913
11745
  };
11914
11746
  return AESCrypto;
11915
11747
  }();
11916
11748
 
11917
11749
  var FastAESKey = /*#__PURE__*/function () {
11918
- function FastAESKey(subtle, key, aesMode) {
11750
+ function FastAESKey(subtle, key) {
11919
11751
  this.subtle = void 0;
11920
11752
  this.key = void 0;
11921
- this.aesMode = void 0;
11922
11753
  this.subtle = subtle;
11923
11754
  this.key = key;
11924
- this.aesMode = aesMode;
11925
11755
  }
11926
11756
  var _proto = FastAESKey.prototype;
11927
11757
  _proto.expandKey = function expandKey() {
11928
- var subtleAlgoName = getSubtleAlgoName(this.aesMode);
11929
11758
  return this.subtle.importKey('raw', this.key, {
11930
- name: subtleAlgoName
11759
+ name: 'AES-CBC'
11931
11760
  }, false, ['encrypt', 'decrypt']);
11932
11761
  };
11933
11762
  return FastAESKey;
11934
11763
  }();
11935
- function getSubtleAlgoName(aesMode) {
11936
- switch (aesMode) {
11937
- case DecrypterAesMode.cbc:
11938
- return 'AES-CBC';
11939
- case DecrypterAesMode.ctr:
11940
- return 'AES-CTR';
11941
- default:
11942
- throw new Error("[FastAESKey] invalid aes mode " + aesMode);
11943
- }
11944
- }
11945
11764
 
11946
11765
  // PKCS7
11947
11766
  function removePadding(array) {
@@ -12194,8 +12013,7 @@
12194
12013
  this.currentIV = null;
12195
12014
  this.currentResult = null;
12196
12015
  this.useSoftware = void 0;
12197
- this.enableSoftwareAES = void 0;
12198
- this.enableSoftwareAES = config.enableSoftwareAES;
12016
+ this.useSoftware = config.enableSoftwareAES;
12199
12017
  this.removePKCS7Padding = removePKCS7Padding;
12200
12018
  // built in decryptor expects PKCS7 padding
12201
12019
  if (removePKCS7Padding) {
@@ -12208,7 +12026,9 @@
12208
12026
  /* no-op */
12209
12027
  }
12210
12028
  }
12211
- this.useSoftware = this.subtle === null;
12029
+ if (this.subtle === null) {
12030
+ this.useSoftware = true;
12031
+ }
12212
12032
  }
12213
12033
  var _proto = Decrypter.prototype;
12214
12034
  _proto.destroy = function destroy() {
@@ -12245,11 +12065,11 @@
12245
12065
  this.softwareDecrypter = null;
12246
12066
  }
12247
12067
  };
12248
- _proto.decrypt = function decrypt(data, key, iv, aesMode) {
12068
+ _proto.decrypt = function decrypt(data, key, iv) {
12249
12069
  var _this = this;
12250
12070
  if (this.useSoftware) {
12251
12071
  return new Promise(function (resolve, reject) {
12252
- _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
12072
+ _this.softwareDecrypt(new Uint8Array(data), key, iv);
12253
12073
  var decryptResult = _this.flush();
12254
12074
  if (decryptResult) {
12255
12075
  resolve(decryptResult.buffer);
@@ -12258,20 +12078,16 @@
12258
12078
  }
12259
12079
  });
12260
12080
  }
12261
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
12081
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
12262
12082
  }
12263
12083
 
12264
12084
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
12265
12085
  // data is handled in the flush() call
12266
12086
  ;
12267
- _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
12087
+ _proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
12268
12088
  var currentIV = this.currentIV,
12269
12089
  currentResult = this.currentResult,
12270
12090
  remainderData = this.remainderData;
12271
- if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
12272
- logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
12273
- return null;
12274
- }
12275
12091
  this.logOnce('JS AES decrypt');
12276
12092
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
12277
12093
  // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
@@ -12304,12 +12120,12 @@
12304
12120
  }
12305
12121
  return result;
12306
12122
  };
12307
- _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
12123
+ _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
12308
12124
  var _this2 = this;
12309
12125
  var subtle = this.subtle;
12310
12126
  if (this.key !== key || !this.fastAesKey) {
12311
12127
  this.key = key;
12312
- this.fastAesKey = new FastAESKey(subtle, key, aesMode);
12128
+ this.fastAesKey = new FastAESKey(subtle, key);
12313
12129
  }
12314
12130
  return this.fastAesKey.expandKey().then(function (aesKey) {
12315
12131
  // decrypt using web crypto
@@ -12317,25 +12133,22 @@
12317
12133
  return Promise.reject(new Error('web crypto not initialized'));
12318
12134
  }
12319
12135
  _this2.logOnce('WebCrypto AES decrypt');
12320
- var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
12136
+ var crypto = new AESCrypto(subtle, new Uint8Array(iv));
12321
12137
  return crypto.decrypt(data.buffer, aesKey);
12322
12138
  }).catch(function (err) {
12323
12139
  logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
12324
- return _this2.onWebCryptoError(data, key, iv, aesMode);
12140
+ return _this2.onWebCryptoError(data, key, iv);
12325
12141
  });
12326
12142
  };
12327
- _proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
12328
- var enableSoftwareAES = this.enableSoftwareAES;
12329
- if (enableSoftwareAES) {
12330
- this.useSoftware = true;
12331
- this.logEnabled = true;
12332
- this.softwareDecrypt(data, key, iv, aesMode);
12333
- var decryptResult = this.flush();
12334
- if (decryptResult) {
12335
- return decryptResult.buffer;
12336
- }
12143
+ _proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
12144
+ this.useSoftware = true;
12145
+ this.logEnabled = true;
12146
+ this.softwareDecrypt(data, key, iv);
12147
+ var decryptResult = this.flush();
12148
+ if (decryptResult) {
12149
+ return decryptResult.buffer;
12337
12150
  }
12338
- throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
12151
+ throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
12339
12152
  };
12340
12153
  _proto.getValidChunk = function getValidChunk(data) {
12341
12154
  var currentChunk = data;
@@ -12389,7 +12202,7 @@
12389
12202
  _inheritsLoose(BaseStreamController, _TaskLoop);
12390
12203
  function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
12391
12204
  var _this;
12392
- _this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
12205
+ _this = _TaskLoop.call(this) || this;
12393
12206
  _this.hls = void 0;
12394
12207
  _this.fragPrevious = null;
12395
12208
  _this.fragCurrent = null;
@@ -12414,96 +12227,25 @@
12414
12227
  _this.startFragRequested = false;
12415
12228
  _this.decrypter = void 0;
12416
12229
  _this.initPTS = [];
12417
- _this.buffering = true;
12418
- _this.loadingParts = false;
12419
- _this.onMediaSeeking = function () {
12420
- var _assertThisInitialize = _assertThisInitialized(_this),
12421
- config = _assertThisInitialize.config,
12422
- fragCurrent = _assertThisInitialize.fragCurrent,
12423
- media = _assertThisInitialize.media,
12424
- mediaBuffer = _assertThisInitialize.mediaBuffer,
12425
- state = _assertThisInitialize.state;
12426
- var currentTime = media ? media.currentTime : 0;
12427
- var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12428
- _this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12429
- if (_this.state === State.ENDED) {
12430
- _this.resetLoadingState();
12431
- } else if (fragCurrent) {
12432
- // Seeking while frag load is in progress
12433
- var tolerance = config.maxFragLookUpTolerance;
12434
- var fragStartOffset = fragCurrent.start - tolerance;
12435
- var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12436
- // if seeking out of buffered range or into new one
12437
- if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12438
- var pastFragment = currentTime > fragEndOffset;
12439
- // if the seek position is outside the current fragment range
12440
- if (currentTime < fragStartOffset || pastFragment) {
12441
- if (pastFragment && fragCurrent.loader) {
12442
- _this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12443
- fragCurrent.abortRequests();
12444
- _this.resetLoadingState();
12445
- }
12446
- _this.fragPrevious = null;
12447
- }
12448
- }
12449
- }
12450
- if (media) {
12451
- // Remove gap fragments
12452
- _this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
12453
- _this.lastCurrentTime = currentTime;
12454
- if (!_this.loadingParts) {
12455
- var bufferEnd = Math.max(bufferInfo.end, currentTime);
12456
- var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
12457
- if (shouldLoadParts) {
12458
- _this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
12459
- _this.loadingParts = shouldLoadParts;
12460
- }
12461
- }
12462
- }
12463
-
12464
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12465
- if (!_this.loadedmetadata && !bufferInfo.len) {
12466
- _this.nextLoadPosition = _this.startPosition = currentTime;
12467
- }
12468
-
12469
- // Async tick to speed up processing
12470
- _this.tickImmediate();
12471
- };
12472
- _this.onMediaEnded = function () {
12473
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12474
- _this.startPosition = _this.lastCurrentTime = 0;
12475
- if (_this.playlistType === PlaylistLevelType.MAIN) {
12476
- _this.hls.trigger(Events.MEDIA_ENDED, {
12477
- stalled: false
12478
- });
12479
- }
12480
- };
12230
+ _this.onvseeking = null;
12231
+ _this.onvended = null;
12232
+ _this.logPrefix = '';
12233
+ _this.log = void 0;
12234
+ _this.warn = void 0;
12481
12235
  _this.playlistType = playlistType;
12236
+ _this.logPrefix = logPrefix;
12237
+ _this.log = logger.log.bind(logger, logPrefix + ":");
12238
+ _this.warn = logger.warn.bind(logger, logPrefix + ":");
12482
12239
  _this.hls = hls;
12483
12240
  _this.fragmentLoader = new FragmentLoader(hls.config);
12484
12241
  _this.keyLoader = keyLoader;
12485
12242
  _this.fragmentTracker = fragmentTracker;
12486
12243
  _this.config = hls.config;
12487
12244
  _this.decrypter = new Decrypter(hls.config);
12245
+ hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
12488
12246
  return _this;
12489
12247
  }
12490
12248
  var _proto = BaseStreamController.prototype;
12491
- _proto.registerListeners = function registerListeners() {
12492
- var hls = this.hls;
12493
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12494
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12495
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12496
- hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12497
- hls.on(Events.ERROR, this.onError, this);
12498
- };
12499
- _proto.unregisterListeners = function unregisterListeners() {
12500
- var hls = this.hls;
12501
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12502
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12503
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12504
- hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12505
- hls.off(Events.ERROR, this.onError, this);
12506
- };
12507
12249
  _proto.doTick = function doTick() {
12508
12250
  this.onTickEnd();
12509
12251
  };
@@ -12527,12 +12269,6 @@
12527
12269
  this.clearNextTick();
12528
12270
  this.state = State.STOPPED;
12529
12271
  };
12530
- _proto.pauseBuffering = function pauseBuffering() {
12531
- this.buffering = false;
12532
- };
12533
- _proto.resumeBuffering = function resumeBuffering() {
12534
- this.buffering = true;
12535
- };
12536
12272
  _proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
12537
12273
  // If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
12538
12274
  // of nothing loading/loaded return false
@@ -12563,8 +12299,10 @@
12563
12299
  };
12564
12300
  _proto.onMediaAttached = function onMediaAttached(event, data) {
12565
12301
  var media = this.media = this.mediaBuffer = data.media;
12566
- media.addEventListener('seeking', this.onMediaSeeking);
12567
- media.addEventListener('ended', this.onMediaEnded);
12302
+ this.onvseeking = this.onMediaSeeking.bind(this);
12303
+ this.onvended = this.onMediaEnded.bind(this);
12304
+ media.addEventListener('seeking', this.onvseeking);
12305
+ media.addEventListener('ended', this.onvended);
12568
12306
  var config = this.config;
12569
12307
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12570
12308
  this.startLoad(config.startPosition);
@@ -12578,9 +12316,10 @@
12578
12316
  }
12579
12317
 
12580
12318
  // remove video listeners
12581
- if (media) {
12582
- media.removeEventListener('seeking', this.onMediaSeeking);
12583
- media.removeEventListener('ended', this.onMediaEnded);
12319
+ if (media && this.onvseeking && this.onvended) {
12320
+ media.removeEventListener('seeking', this.onvseeking);
12321
+ media.removeEventListener('ended', this.onvended);
12322
+ this.onvseeking = this.onvended = null;
12584
12323
  }
12585
12324
  if (this.keyLoader) {
12586
12325
  this.keyLoader.detach();
@@ -12590,8 +12329,54 @@
12590
12329
  this.fragmentTracker.removeAllFragments();
12591
12330
  this.stopLoad();
12592
12331
  };
12593
- _proto.onManifestLoading = function onManifestLoading() {};
12594
- _proto.onError = function onError(event, data) {};
12332
+ _proto.onMediaSeeking = function onMediaSeeking() {
12333
+ var config = this.config,
12334
+ fragCurrent = this.fragCurrent,
12335
+ media = this.media,
12336
+ mediaBuffer = this.mediaBuffer,
12337
+ state = this.state;
12338
+ var currentTime = media ? media.currentTime : 0;
12339
+ var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12340
+ this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12341
+ if (this.state === State.ENDED) {
12342
+ this.resetLoadingState();
12343
+ } else if (fragCurrent) {
12344
+ // Seeking while frag load is in progress
12345
+ var tolerance = config.maxFragLookUpTolerance;
12346
+ var fragStartOffset = fragCurrent.start - tolerance;
12347
+ var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12348
+ // if seeking out of buffered range or into new one
12349
+ if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12350
+ var pastFragment = currentTime > fragEndOffset;
12351
+ // if the seek position is outside the current fragment range
12352
+ if (currentTime < fragStartOffset || pastFragment) {
12353
+ if (pastFragment && fragCurrent.loader) {
12354
+ this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12355
+ fragCurrent.abortRequests();
12356
+ this.resetLoadingState();
12357
+ }
12358
+ this.fragPrevious = null;
12359
+ }
12360
+ }
12361
+ }
12362
+ if (media) {
12363
+ // Remove gap fragments
12364
+ this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
12365
+ this.lastCurrentTime = currentTime;
12366
+ }
12367
+
12368
+ // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12369
+ if (!this.loadedmetadata && !bufferInfo.len) {
12370
+ this.nextLoadPosition = this.startPosition = currentTime;
12371
+ }
12372
+
12373
+ // Async tick to speed up processing
12374
+ this.tickImmediate();
12375
+ };
12376
+ _proto.onMediaEnded = function onMediaEnded() {
12377
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12378
+ this.startPosition = this.lastCurrentTime = 0;
12379
+ };
12595
12380
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
12596
12381
  this.startTimeOffset = data.startTimeOffset;
12597
12382
  this.initPTS = [];
@@ -12601,7 +12386,7 @@
12601
12386
  this.stopLoad();
12602
12387
  _TaskLoop.prototype.onHandlerDestroying.call(this);
12603
12388
  // @ts-ignore
12604
- this.hls = this.onMediaSeeking = this.onMediaEnded = null;
12389
+ this.hls = null;
12605
12390
  };
12606
12391
  _proto.onHandlerDestroyed = function onHandlerDestroyed() {
12607
12392
  this.state = State.STOPPED;
@@ -12731,10 +12516,10 @@
12731
12516
  var decryptData = frag.decryptdata;
12732
12517
 
12733
12518
  // check to see if the payload needs to be decrypted
12734
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
12519
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
12735
12520
  var startTime = self.performance.now();
12736
12521
  // decrypt init segment data
12737
- return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
12522
+ return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
12738
12523
  hls.trigger(Events.ERROR, {
12739
12524
  type: ErrorTypes.MEDIA_ERROR,
12740
12525
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -12847,7 +12632,7 @@
12847
12632
  }
12848
12633
  var keyLoadingPromise = null;
12849
12634
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
12850
- this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
12635
+ this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + " " + frag.level);
12851
12636
  this.state = State.KEY_LOADING;
12852
12637
  this.fragCurrent = frag;
12853
12638
  keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
@@ -12868,16 +12653,8 @@
12868
12653
  } else if (!frag.encrypted && details.encryptedFragments.length) {
12869
12654
  this.keyLoader.loadClear(frag, details.encryptedFragments);
12870
12655
  }
12871
- var fragPrevious = this.fragPrevious;
12872
- if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
12873
- var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
12874
- if (shouldLoadParts !== this.loadingParts) {
12875
- this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
12876
- this.loadingParts = shouldLoadParts;
12877
- }
12878
- }
12879
12656
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
12880
- if (this.loadingParts && frag.sn !== 'initSegment') {
12657
+ if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
12881
12658
  var partList = details.partList;
12882
12659
  if (partList && progressCallback) {
12883
12660
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -12886,7 +12663,7 @@
12886
12663
  var partIndex = this.getNextPart(partList, frag, targetBufferTime);
12887
12664
  if (partIndex > -1) {
12888
12665
  var part = partList[partIndex];
12889
- this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12666
+ this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12890
12667
  this.nextLoadPosition = part.start + part.duration;
12891
12668
  this.state = State.FRAG_LOADING;
12892
12669
  var _result;
@@ -12919,14 +12696,7 @@
12919
12696
  }
12920
12697
  }
12921
12698
  }
12922
- if (frag.sn !== 'initSegment' && this.loadingParts) {
12923
- this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
12924
- this.loadingParts = false;
12925
- } else if (!frag.url) {
12926
- // Selected fragment hint for part but not loading parts
12927
- return Promise.resolve(null);
12928
- }
12929
- this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12699
+ this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12930
12700
  // Don't update nextLoadPosition for fragments which are not buffered
12931
12701
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
12932
12702
  this.nextLoadPosition = frag.start + frag.duration;
@@ -13028,36 +12798,8 @@
13028
12798
  if (part) {
13029
12799
  part.stats.parsing.end = now;
13030
12800
  }
13031
- // See if part loading should be disabled/enabled based on buffer and playback position.
13032
- if (frag.sn !== 'initSegment') {
13033
- var levelDetails = this.getLevelDetails();
13034
- var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
13035
- var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
13036
- if (shouldLoadParts !== this.loadingParts) {
13037
- this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
13038
- this.loadingParts = shouldLoadParts;
13039
- }
13040
- }
13041
12801
  this.updateLevelTiming(frag, part, level, chunkMeta.partial);
13042
12802
  };
13043
- _proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
13044
- if (this.config.lowLatencyMode) {
13045
- if (!details) {
13046
- return this.loadingParts;
13047
- }
13048
- if (details != null && details.partList) {
13049
- var _details$fragmentHint;
13050
- // Buffer must be ahead of first part + duration of parts after last segment
13051
- // and playback must be at or past segment adjacent to part list
13052
- var firstPart = details.partList[0];
13053
- var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
13054
- if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
13055
- return true;
13056
- }
13057
- }
13058
- }
13059
- return false;
13060
- };
13061
12803
  _proto.getCurrentContext = function getCurrentContext(chunkMeta) {
13062
12804
  var levels = this.levels,
13063
12805
  fragCurrent = this.fragCurrent;
@@ -13148,7 +12890,7 @@
13148
12890
  // Workaround flaw in getting forward buffer when maxBufferHole is smaller than gap at current pos
13149
12891
  if (bufferInfo.len === 0 && bufferInfo.nextStart !== undefined) {
13150
12892
  var bufferedFragAtPos = this.fragmentTracker.getBufferedFrag(pos, type);
13151
- if (bufferedFragAtPos && (bufferInfo.nextStart <= bufferedFragAtPos.end || bufferedFragAtPos.gap)) {
12893
+ if (bufferedFragAtPos && bufferInfo.nextStart < bufferedFragAtPos.end) {
13152
12894
  return BufferHelper.bufferInfo(bufferable, pos, Math.max(bufferInfo.nextStart, maxBufferHole));
13153
12895
  }
13154
12896
  }
@@ -13192,8 +12934,7 @@
13192
12934
  // find fragment index, contiguous with end of buffer position
13193
12935
  var config = this.config;
13194
12936
  var start = fragments[0].start;
13195
- var canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
13196
- var frag = null;
12937
+ var frag;
13197
12938
  if (levelDetails.live) {
13198
12939
  var initialLiveManifestSize = config.initialLiveManifestSize;
13199
12940
  if (fragLen < initialLiveManifestSize) {
@@ -13205,10 +12946,6 @@
13205
12946
  // Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
13206
12947
  // we get the fragment matching that start time
13207
12948
  if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
13208
- if (canLoadParts && !this.loadingParts) {
13209
- this.log("LL-Part loading ON for initial live fragment");
13210
- this.loadingParts = true;
13211
- }
13212
12949
  frag = this.getInitialLiveFragment(levelDetails, fragments);
13213
12950
  this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
13214
12951
  }
@@ -13219,7 +12956,7 @@
13219
12956
 
13220
12957
  // If we haven't run into any special cases already, just load the fragment most closely matching the requested position
13221
12958
  if (!frag) {
13222
- var end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
12959
+ var end = config.lowLatencyMode ? levelDetails.partEnd : levelDetails.fragmentEnd;
13223
12960
  frag = this.getFragmentAtPosition(pos, end, levelDetails);
13224
12961
  }
13225
12962
  return this.mapToInitFragWhenRequired(frag);
@@ -13333,7 +13070,7 @@
13333
13070
  var fragmentHint = levelDetails.fragmentHint;
13334
13071
  var tolerance = config.maxFragLookUpTolerance;
13335
13072
  var partList = levelDetails.partList;
13336
- var loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
13073
+ var loadingParts = !!(config.lowLatencyMode && partList != null && partList.length && fragmentHint);
13337
13074
  if (loadingParts && fragmentHint && !this.bitrateTest) {
13338
13075
  // Include incomplete fragment with parts at end
13339
13076
  fragments = fragments.concat(fragmentHint);
@@ -13520,7 +13257,7 @@
13520
13257
  errorAction.resolved = true;
13521
13258
  }
13522
13259
  } else {
13523
- this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13260
+ logger.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13524
13261
  return;
13525
13262
  }
13526
13263
  } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
@@ -13588,9 +13325,7 @@
13588
13325
  this.log('Reset loading state');
13589
13326
  this.fragCurrent = null;
13590
13327
  this.fragPrevious = null;
13591
- if (this.state !== State.STOPPED) {
13592
- this.state = State.IDLE;
13593
- }
13328
+ this.state = State.IDLE;
13594
13329
  };
13595
13330
  _proto.resetStartWhenNotLoaded = function resetStartWhenNotLoaded(level) {
13596
13331
  // if loadedmetadata is not set, it means that first frag request failed
@@ -13912,7 +13647,6 @@
13912
13647
  */
13913
13648
  function getAudioConfig(observer, data, offset, audioCodec) {
13914
13649
  var adtsObjectType;
13915
- var originalAdtsObjectType;
13916
13650
  var adtsExtensionSamplingIndex;
13917
13651
  var adtsChannelConfig;
13918
13652
  var config;
@@ -13920,7 +13654,7 @@
13920
13654
  var manifestCodec = audioCodec;
13921
13655
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
13922
13656
  // byte 2
13923
- adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13657
+ adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13924
13658
  var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
13925
13659
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
13926
13660
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
@@ -13937,8 +13671,8 @@
13937
13671
  // byte 3
13938
13672
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
13939
13673
  logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
13940
- // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
13941
- if (/firefox|palemoon/i.test(userAgent)) {
13674
+ // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
13675
+ if (/firefox/i.test(userAgent)) {
13942
13676
  if (adtsSamplingIndex >= 6) {
13943
13677
  adtsObjectType = 5;
13944
13678
  config = new Array(4);
@@ -14032,7 +13766,6 @@
14032
13766
  samplerate: adtsSamplingRates[adtsSamplingIndex],
14033
13767
  channelCount: adtsChannelConfig,
14034
13768
  codec: 'mp4a.40.' + adtsObjectType,
14035
- parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
14036
13769
  manifestCodec: manifestCodec
14037
13770
  };
14038
13771
  }
@@ -14087,8 +13820,7 @@
14087
13820
  track.channelCount = config.channelCount;
14088
13821
  track.codec = config.codec;
14089
13822
  track.manifestCodec = config.manifestCodec;
14090
- track.parsedCodec = config.parsedCodec;
14091
- logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13823
+ logger.log("parsed codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
14092
13824
  }
14093
13825
  }
14094
13826
  function getFrameDuration(samplerate) {
@@ -14568,116 +14300,12 @@
14568
14300
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
14569
14301
  }
14570
14302
  };
14571
- _proto.parseNALu = function parseNALu(track, array) {
14572
- var len = array.byteLength;
14573
- var state = track.naluState || 0;
14574
- var lastState = state;
14575
- var units = [];
14576
- var i = 0;
14577
- var value;
14578
- var overflow;
14579
- var unitType;
14580
- var lastUnitStart = -1;
14581
- var lastUnitType = 0;
14582
- // logger.log('PES:' + Hex.hexDump(array));
14303
+ return BaseVideoParser;
14304
+ }();
14583
14305
 
14584
- if (state === -1) {
14585
- // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14586
- lastUnitStart = 0;
14587
- // NALu type is value read from offset 0
14588
- lastUnitType = this.getNALuType(array, 0);
14589
- state = 0;
14590
- i = 1;
14591
- }
14592
- while (i < len) {
14593
- value = array[i++];
14594
- // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14595
- if (!state) {
14596
- state = value ? 0 : 1;
14597
- continue;
14598
- }
14599
- if (state === 1) {
14600
- state = value ? 0 : 2;
14601
- continue;
14602
- }
14603
- // here we have state either equal to 2 or 3
14604
- if (!value) {
14605
- state = 3;
14606
- } else if (value === 1) {
14607
- overflow = i - state - 1;
14608
- if (lastUnitStart >= 0) {
14609
- var unit = {
14610
- data: array.subarray(lastUnitStart, overflow),
14611
- type: lastUnitType
14612
- };
14613
- // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14614
- units.push(unit);
14615
- } else {
14616
- // lastUnitStart is undefined => this is the first start code found in this PES packet
14617
- // first check if start code delimiter is overlapping between 2 PES packets,
14618
- // ie it started in last packet (lastState not zero)
14619
- // and ended at the beginning of this PES packet (i <= 4 - lastState)
14620
- var lastUnit = this.getLastNalUnit(track.samples);
14621
- if (lastUnit) {
14622
- if (lastState && i <= 4 - lastState) {
14623
- // start delimiter overlapping between PES packets
14624
- // strip start delimiter bytes from the end of last NAL unit
14625
- // check if lastUnit had a state different from zero
14626
- if (lastUnit.state) {
14627
- // strip last bytes
14628
- lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
14629
- }
14630
- }
14631
- // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
14632
-
14633
- if (overflow > 0) {
14634
- // logger.log('first NALU found with overflow:' + overflow);
14635
- lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14636
- lastUnit.state = 0;
14637
- }
14638
- }
14639
- }
14640
- // check if we can read unit type
14641
- if (i < len) {
14642
- unitType = this.getNALuType(array, i);
14643
- // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14644
- lastUnitStart = i;
14645
- lastUnitType = unitType;
14646
- state = 0;
14647
- } else {
14648
- // not enough byte to read unit type. let's read it on next PES parsing
14649
- state = -1;
14650
- }
14651
- } else {
14652
- state = 0;
14653
- }
14654
- }
14655
- if (lastUnitStart >= 0 && state >= 0) {
14656
- var _unit = {
14657
- data: array.subarray(lastUnitStart, len),
14658
- type: lastUnitType,
14659
- state: state
14660
- };
14661
- units.push(_unit);
14662
- // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14663
- }
14664
- // no NALu found
14665
- if (units.length === 0) {
14666
- // append pes.data to previous NAL unit
14667
- var _lastUnit = this.getLastNalUnit(track.samples);
14668
- if (_lastUnit) {
14669
- _lastUnit.data = appendUint8Array(_lastUnit.data, array);
14670
- }
14671
- }
14672
- track.naluState = state;
14673
- return units;
14674
- };
14675
- return BaseVideoParser;
14676
- }();
14677
-
14678
- /**
14679
- * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
14680
- */
14306
+ /**
14307
+ * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
14308
+ */
14681
14309
 
14682
14310
  var ExpGolomb = /*#__PURE__*/function () {
14683
14311
  function ExpGolomb(data) {
@@ -14826,179 +14454,22 @@
14826
14454
  ;
14827
14455
  _proto.readUInt = function readUInt() {
14828
14456
  return this.readBits(32);
14829
- };
14830
- return ExpGolomb;
14831
- }();
14832
-
14833
- var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
14834
- _inheritsLoose(AvcVideoParser, _BaseVideoParser);
14835
- function AvcVideoParser() {
14836
- return _BaseVideoParser.apply(this, arguments) || this;
14837
- }
14838
- var _proto = AvcVideoParser.prototype;
14839
- _proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
14840
- var _this = this;
14841
- var units = this.parseNALu(track, pes.data);
14842
- var VideoSample = this.VideoSample;
14843
- var push;
14844
- var spsfound = false;
14845
- // free pes.data to save up some memory
14846
- pes.data = null;
14847
-
14848
- // if new NAL units found and last sample still there, let's push ...
14849
- // this helps parsing streams with missing AUD (only do this if AUD never found)
14850
- if (VideoSample && units.length && !track.audFound) {
14851
- this.pushAccessUnit(VideoSample, track);
14852
- VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts, '');
14853
- }
14854
- units.forEach(function (unit) {
14855
- var _VideoSample2;
14856
- switch (unit.type) {
14857
- // NDR
14858
- case 1:
14859
- {
14860
- var iskey = false;
14861
- push = true;
14862
- var data = unit.data;
14863
- // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
14864
- if (spsfound && data.length > 4) {
14865
- // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
14866
- var sliceType = _this.readSliceType(data);
14867
- // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
14868
- // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
14869
- // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
14870
- // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
14871
- // if (sliceType === 2 || sliceType === 7) {
14872
- if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
14873
- iskey = true;
14874
- }
14875
- }
14876
- if (iskey) {
14877
- var _VideoSample;
14878
- // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
14879
- if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
14880
- _this.pushAccessUnit(VideoSample, track);
14881
- VideoSample = _this.VideoSample = null;
14882
- }
14883
- }
14884
- if (!VideoSample) {
14885
- VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
14886
- }
14887
- VideoSample.frame = true;
14888
- VideoSample.key = iskey;
14889
- break;
14890
- // IDR
14891
- }
14892
- case 5:
14893
- push = true;
14894
- // handle PES not starting with AUD
14895
- // if we have frame data already, that cannot belong to the same frame, so force a push
14896
- if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
14897
- _this.pushAccessUnit(VideoSample, track);
14898
- VideoSample = _this.VideoSample = null;
14899
- }
14900
- if (!VideoSample) {
14901
- VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
14902
- }
14903
- VideoSample.key = true;
14904
- VideoSample.frame = true;
14905
- break;
14906
- // SEI
14907
- case 6:
14908
- {
14909
- push = true;
14910
- parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
14911
- break;
14912
- // SPS
14913
- }
14914
- case 7:
14915
- {
14916
- var _track$pixelRatio, _track$pixelRatio2;
14917
- push = true;
14918
- spsfound = true;
14919
- var sps = unit.data;
14920
- var config = _this.readSPS(sps);
14921
- if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) {
14922
- track.width = config.width;
14923
- track.height = config.height;
14924
- track.pixelRatio = config.pixelRatio;
14925
- track.sps = [sps];
14926
- track.duration = duration;
14927
- var codecarray = sps.subarray(1, 4);
14928
- var codecstring = 'avc1.';
14929
- for (var i = 0; i < 3; i++) {
14930
- var h = codecarray[i].toString(16);
14931
- if (h.length < 2) {
14932
- h = '0' + h;
14933
- }
14934
- codecstring += h;
14935
- }
14936
- track.codec = codecstring;
14937
- }
14938
- break;
14939
- }
14940
- // PPS
14941
- case 8:
14942
- push = true;
14943
- track.pps = [unit.data];
14944
- break;
14945
- // AUD
14946
- case 9:
14947
- push = true;
14948
- track.audFound = true;
14949
- if (VideoSample) {
14950
- _this.pushAccessUnit(VideoSample, track);
14951
- }
14952
- VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
14953
- break;
14954
- // Filler Data
14955
- case 12:
14956
- push = true;
14957
- break;
14958
- default:
14959
- push = false;
14960
- if (VideoSample) {
14961
- VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
14962
- }
14963
- break;
14964
- }
14965
- if (VideoSample && push) {
14966
- var _units = VideoSample.units;
14967
- _units.push(unit);
14968
- }
14969
- });
14970
- // if last PES packet, push samples
14971
- if (last && VideoSample) {
14972
- this.pushAccessUnit(VideoSample, track);
14973
- this.VideoSample = null;
14974
- }
14975
- };
14976
- _proto.getNALuType = function getNALuType(data, offset) {
14977
- return data[offset] & 0x1f;
14978
- };
14979
- _proto.readSliceType = function readSliceType(data) {
14980
- var eg = new ExpGolomb(data);
14981
- // skip NALu type
14982
- eg.readUByte();
14983
- // discard first_mb_in_slice
14984
- eg.readUEG();
14985
- // return slice_type
14986
- return eg.readUEG();
14987
14457
  }
14988
14458
 
14989
14459
  /**
14990
- * The scaling list is optionally transmitted as part of a sequence parameter
14460
+ * Advance the ExpGolomb decoder past a scaling list. The scaling
14461
+ * list is optionally transmitted as part of a sequence parameter
14991
14462
  * set and is not relevant to transmuxing.
14992
14463
  * @param count the number of entries in this scaling list
14993
14464
  * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
14994
14465
  */;
14995
- _proto.skipScalingList = function skipScalingList(count, reader) {
14466
+ _proto.skipScalingList = function skipScalingList(count) {
14996
14467
  var lastScale = 8;
14997
14468
  var nextScale = 8;
14998
14469
  var deltaScale;
14999
14470
  for (var j = 0; j < count; j++) {
15000
14471
  if (nextScale !== 0) {
15001
- deltaScale = reader.readEG();
14472
+ deltaScale = this.readEG();
15002
14473
  nextScale = (lastScale + deltaScale + 256) % 256;
15003
14474
  }
15004
14475
  lastScale = nextScale === 0 ? lastScale : nextScale;
@@ -15013,8 +14484,7 @@
15013
14484
  * sequence parameter set, including the dimensions of the
15014
14485
  * associated video frames.
15015
14486
  */;
15016
- _proto.readSPS = function readSPS(sps) {
15017
- var eg = new ExpGolomb(sps);
14487
+ _proto.readSPS = function readSPS() {
15018
14488
  var frameCropLeftOffset = 0;
15019
14489
  var frameCropRightOffset = 0;
15020
14490
  var frameCropTopOffset = 0;
@@ -15022,13 +14492,13 @@
15022
14492
  var numRefFramesInPicOrderCntCycle;
15023
14493
  var scalingListCount;
15024
14494
  var i;
15025
- var readUByte = eg.readUByte.bind(eg);
15026
- var readBits = eg.readBits.bind(eg);
15027
- var readUEG = eg.readUEG.bind(eg);
15028
- var readBoolean = eg.readBoolean.bind(eg);
15029
- var skipBits = eg.skipBits.bind(eg);
15030
- var skipEG = eg.skipEG.bind(eg);
15031
- var skipUEG = eg.skipUEG.bind(eg);
14495
+ var readUByte = this.readUByte.bind(this);
14496
+ var readBits = this.readBits.bind(this);
14497
+ var readUEG = this.readUEG.bind(this);
14498
+ var readBoolean = this.readBoolean.bind(this);
14499
+ var skipBits = this.skipBits.bind(this);
14500
+ var skipEG = this.skipEG.bind(this);
14501
+ var skipUEG = this.skipUEG.bind(this);
15032
14502
  var skipScalingList = this.skipScalingList.bind(this);
15033
14503
  readUByte();
15034
14504
  var profileIdc = readUByte(); // profile_idc
@@ -15053,9 +14523,9 @@
15053
14523
  if (readBoolean()) {
15054
14524
  // seq_scaling_list_present_flag[ i ]
15055
14525
  if (i < 6) {
15056
- skipScalingList(16, eg);
14526
+ skipScalingList(16);
15057
14527
  } else {
15058
- skipScalingList(64, eg);
14528
+ skipScalingList(64);
15059
14529
  }
15060
14530
  }
15061
14531
  }
@@ -15154,11 +14624,270 @@
15154
14624
  }
15155
14625
  }
15156
14626
  }
15157
- return {
15158
- width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
15159
- height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
15160
- pixelRatio: pixelRatio
15161
- };
14627
+ return {
14628
+ width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
14629
+ height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
14630
+ pixelRatio: pixelRatio
14631
+ };
14632
+ };
14633
+ _proto.readSliceType = function readSliceType() {
14634
+ // skip NALu type
14635
+ this.readUByte();
14636
+ // discard first_mb_in_slice
14637
+ this.readUEG();
14638
+ // return slice_type
14639
+ return this.readUEG();
14640
+ };
14641
+ return ExpGolomb;
14642
+ }();
14643
+
14644
+ var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
14645
+ _inheritsLoose(AvcVideoParser, _BaseVideoParser);
14646
+ function AvcVideoParser() {
14647
+ return _BaseVideoParser.apply(this, arguments) || this;
14648
+ }
14649
+ var _proto = AvcVideoParser.prototype;
14650
+ _proto.parseAVCPES = function parseAVCPES(track, textTrack, pes, last, duration) {
14651
+ var _this = this;
14652
+ var units = this.parseAVCNALu(track, pes.data);
14653
+ var VideoSample = this.VideoSample;
14654
+ var push;
14655
+ var spsfound = false;
14656
+ // free pes.data to save up some memory
14657
+ pes.data = null;
14658
+
14659
+ // if new NAL units found and last sample still there, let's push ...
14660
+ // this helps parsing streams with missing AUD (only do this if AUD never found)
14661
+ if (VideoSample && units.length && !track.audFound) {
14662
+ this.pushAccessUnit(VideoSample, track);
14663
+ VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts, '');
14664
+ }
14665
+ units.forEach(function (unit) {
14666
+ var _VideoSample2;
14667
+ switch (unit.type) {
14668
+ // NDR
14669
+ case 1:
14670
+ {
14671
+ var iskey = false;
14672
+ push = true;
14673
+ var data = unit.data;
14674
+ // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
14675
+ if (spsfound && data.length > 4) {
14676
+ // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
14677
+ var sliceType = new ExpGolomb(data).readSliceType();
14678
+ // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
14679
+ // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
14680
+ // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
14681
+ // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
14682
+ // if (sliceType === 2 || sliceType === 7) {
14683
+ if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
14684
+ iskey = true;
14685
+ }
14686
+ }
14687
+ if (iskey) {
14688
+ var _VideoSample;
14689
+ // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
14690
+ if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
14691
+ _this.pushAccessUnit(VideoSample, track);
14692
+ VideoSample = _this.VideoSample = null;
14693
+ }
14694
+ }
14695
+ if (!VideoSample) {
14696
+ VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
14697
+ }
14698
+ VideoSample.frame = true;
14699
+ VideoSample.key = iskey;
14700
+ break;
14701
+ // IDR
14702
+ }
14703
+ case 5:
14704
+ push = true;
14705
+ // handle PES not starting with AUD
14706
+ // if we have frame data already, that cannot belong to the same frame, so force a push
14707
+ if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
14708
+ _this.pushAccessUnit(VideoSample, track);
14709
+ VideoSample = _this.VideoSample = null;
14710
+ }
14711
+ if (!VideoSample) {
14712
+ VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
14713
+ }
14714
+ VideoSample.key = true;
14715
+ VideoSample.frame = true;
14716
+ break;
14717
+ // SEI
14718
+ case 6:
14719
+ {
14720
+ push = true;
14721
+ parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
14722
+ break;
14723
+ // SPS
14724
+ }
14725
+ case 7:
14726
+ {
14727
+ var _track$pixelRatio, _track$pixelRatio2;
14728
+ push = true;
14729
+ spsfound = true;
14730
+ var sps = unit.data;
14731
+ var expGolombDecoder = new ExpGolomb(sps);
14732
+ var config = expGolombDecoder.readSPS();
14733
+ if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) {
14734
+ track.width = config.width;
14735
+ track.height = config.height;
14736
+ track.pixelRatio = config.pixelRatio;
14737
+ track.sps = [sps];
14738
+ track.duration = duration;
14739
+ var codecarray = sps.subarray(1, 4);
14740
+ var codecstring = 'avc1.';
14741
+ for (var i = 0; i < 3; i++) {
14742
+ var h = codecarray[i].toString(16);
14743
+ if (h.length < 2) {
14744
+ h = '0' + h;
14745
+ }
14746
+ codecstring += h;
14747
+ }
14748
+ track.codec = codecstring;
14749
+ }
14750
+ break;
14751
+ }
14752
+ // PPS
14753
+ case 8:
14754
+ push = true;
14755
+ track.pps = [unit.data];
14756
+ break;
14757
+ // AUD
14758
+ case 9:
14759
+ push = true;
14760
+ track.audFound = true;
14761
+ if (VideoSample) {
14762
+ _this.pushAccessUnit(VideoSample, track);
14763
+ }
14764
+ VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
14765
+ break;
14766
+ // Filler Data
14767
+ case 12:
14768
+ push = true;
14769
+ break;
14770
+ default:
14771
+ push = false;
14772
+ if (VideoSample) {
14773
+ VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
14774
+ }
14775
+ break;
14776
+ }
14777
+ if (VideoSample && push) {
14778
+ var _units = VideoSample.units;
14779
+ _units.push(unit);
14780
+ }
14781
+ });
14782
+ // if last PES packet, push samples
14783
+ if (last && VideoSample) {
14784
+ this.pushAccessUnit(VideoSample, track);
14785
+ this.VideoSample = null;
14786
+ }
14787
+ };
14788
+ _proto.parseAVCNALu = function parseAVCNALu(track, array) {
14789
+ var len = array.byteLength;
14790
+ var state = track.naluState || 0;
14791
+ var lastState = state;
14792
+ var units = [];
14793
+ var i = 0;
14794
+ var value;
14795
+ var overflow;
14796
+ var unitType;
14797
+ var lastUnitStart = -1;
14798
+ var lastUnitType = 0;
14799
+ // logger.log('PES:' + Hex.hexDump(array));
14800
+
14801
+ if (state === -1) {
14802
+ // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14803
+ lastUnitStart = 0;
14804
+ // NALu type is value read from offset 0
14805
+ lastUnitType = array[0] & 0x1f;
14806
+ state = 0;
14807
+ i = 1;
14808
+ }
14809
+ while (i < len) {
14810
+ value = array[i++];
14811
+ // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14812
+ if (!state) {
14813
+ state = value ? 0 : 1;
14814
+ continue;
14815
+ }
14816
+ if (state === 1) {
14817
+ state = value ? 0 : 2;
14818
+ continue;
14819
+ }
14820
+ // here we have state either equal to 2 or 3
14821
+ if (!value) {
14822
+ state = 3;
14823
+ } else if (value === 1) {
14824
+ overflow = i - state - 1;
14825
+ if (lastUnitStart >= 0) {
14826
+ var unit = {
14827
+ data: array.subarray(lastUnitStart, overflow),
14828
+ type: lastUnitType
14829
+ };
14830
+ // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14831
+ units.push(unit);
14832
+ } else {
14833
+ // lastUnitStart is undefined => this is the first start code found in this PES packet
14834
+ // first check if start code delimiter is overlapping between 2 PES packets,
14835
+ // ie it started in last packet (lastState not zero)
14836
+ // and ended at the beginning of this PES packet (i <= 4 - lastState)
14837
+ var lastUnit = this.getLastNalUnit(track.samples);
14838
+ if (lastUnit) {
14839
+ if (lastState && i <= 4 - lastState) {
14840
+ // start delimiter overlapping between PES packets
14841
+ // strip start delimiter bytes from the end of last NAL unit
14842
+ // check if lastUnit had a state different from zero
14843
+ if (lastUnit.state) {
14844
+ // strip last bytes
14845
+ lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
14846
+ }
14847
+ }
14848
+ // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
14849
+
14850
+ if (overflow > 0) {
14851
+ // logger.log('first NALU found with overflow:' + overflow);
14852
+ lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14853
+ lastUnit.state = 0;
14854
+ }
14855
+ }
14856
+ }
14857
+ // check if we can read unit type
14858
+ if (i < len) {
14859
+ unitType = array[i] & 0x1f;
14860
+ // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14861
+ lastUnitStart = i;
14862
+ lastUnitType = unitType;
14863
+ state = 0;
14864
+ } else {
14865
+ // not enough byte to read unit type. let's read it on next PES parsing
14866
+ state = -1;
14867
+ }
14868
+ } else {
14869
+ state = 0;
14870
+ }
14871
+ }
14872
+ if (lastUnitStart >= 0 && state >= 0) {
14873
+ var _unit = {
14874
+ data: array.subarray(lastUnitStart, len),
14875
+ type: lastUnitType,
14876
+ state: state
14877
+ };
14878
+ units.push(_unit);
14879
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14880
+ }
14881
+ // no NALu found
14882
+ if (units.length === 0) {
14883
+ // append pes.data to previous NAL unit
14884
+ var _lastUnit = this.getLastNalUnit(track.samples);
14885
+ if (_lastUnit) {
14886
+ _lastUnit.data = appendUint8Array(_lastUnit.data, array);
14887
+ }
14888
+ }
14889
+ track.naluState = state;
14890
+ return units;
15162
14891
  };
15163
14892
  return AvcVideoParser;
15164
14893
  }(BaseVideoParser);
@@ -15178,7 +14907,7 @@
15178
14907
  }
15179
14908
  var _proto = SampleAesDecrypter.prototype;
15180
14909
  _proto.decryptBuffer = function decryptBuffer(encryptedData) {
15181
- return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
14910
+ return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
15182
14911
  }
15183
14912
 
15184
14913
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -15297,7 +15026,7 @@
15297
15026
  this.observer = observer;
15298
15027
  this.config = config;
15299
15028
  this.typeSupported = typeSupported;
15300
- this.videoParser = null;
15029
+ this.videoParser = new AvcVideoParser();
15301
15030
  }
15302
15031
  TSDemuxer.probe = function probe(data) {
15303
15032
  var syncOffset = TSDemuxer.syncOffset(data);
@@ -15467,16 +15196,7 @@
15467
15196
  case videoPid:
15468
15197
  if (stt) {
15469
15198
  if (videoData && (pes = parsePES(videoData))) {
15470
- if (this.videoParser === null) {
15471
- switch (videoTrack.segmentCodec) {
15472
- case 'avc':
15473
- this.videoParser = new AvcVideoParser();
15474
- break;
15475
- }
15476
- }
15477
- if (this.videoParser !== null) {
15478
- this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
15479
- }
15199
+ this.videoParser.parseAVCPES(videoTrack, textTrack, pes, false, this._duration);
15480
15200
  }
15481
15201
  videoData = {
15482
15202
  data: [],
@@ -15634,17 +15354,8 @@
15634
15354
  // try to parse last PES packets
15635
15355
  var pes;
15636
15356
  if (videoData && (pes = parsePES(videoData))) {
15637
- if (this.videoParser === null) {
15638
- switch (videoTrack.segmentCodec) {
15639
- case 'avc':
15640
- this.videoParser = new AvcVideoParser();
15641
- break;
15642
- }
15643
- }
15644
- if (this.videoParser !== null) {
15645
- this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
15646
- videoTrack.pesData = null;
15647
- }
15357
+ this.videoParser.parseAVCPES(videoTrack, textTrack, pes, true, this._duration);
15358
+ videoTrack.pesData = null;
15648
15359
  } else {
15649
15360
  // either avcData null or PES truncated, keep it for next frag parsing
15650
15361
  videoTrack.pesData = videoData;
@@ -15946,10 +15657,7 @@
15946
15657
  logger.warn('Unsupported EC-3 in M2TS found');
15947
15658
  break;
15948
15659
  case 0x24:
15949
- // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
15950
- {
15951
- logger.warn('Unsupported HEVC in M2TS found');
15952
- }
15660
+ logger.warn('Unsupported HEVC in M2TS found');
15953
15661
  break;
15954
15662
  }
15955
15663
  // move to the next table entry
@@ -16177,8 +15885,6 @@
16177
15885
  avc1: [],
16178
15886
  // codingname
16179
15887
  avcC: [],
16180
- hvc1: [],
16181
- hvcC: [],
16182
15888
  btrt: [],
16183
15889
  dinf: [],
16184
15890
  dref: [],
@@ -16606,10 +16312,8 @@
16606
16312
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
16607
16313
  }
16608
16314
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
16609
- } else if (track.segmentCodec === 'avc') {
16610
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
16611
16315
  } else {
16612
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
16316
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
16613
16317
  }
16614
16318
  };
16615
16319
  MP4.tkhd = function tkhd(track) {
@@ -16747,84 +16451,6 @@
16747
16451
  var result = appendUint8Array(MP4.FTYP, movie);
16748
16452
  return result;
16749
16453
  };
16750
- MP4.hvc1 = function hvc1(track) {
16751
- var ps = track.params;
16752
- var units = [track.vps, track.sps, track.pps];
16753
- var NALuLengthSize = 4;
16754
- var config = new Uint8Array([0x01, ps.general_profile_space << 6 | (ps.general_tier_flag ? 32 : 0) | ps.general_profile_idc, ps.general_profile_compatibility_flags[0], ps.general_profile_compatibility_flags[1], ps.general_profile_compatibility_flags[2], ps.general_profile_compatibility_flags[3], ps.general_constraint_indicator_flags[0], ps.general_constraint_indicator_flags[1], ps.general_constraint_indicator_flags[2], ps.general_constraint_indicator_flags[3], ps.general_constraint_indicator_flags[4], ps.general_constraint_indicator_flags[5], ps.general_level_idc, 240 | ps.min_spatial_segmentation_idc >> 8, 255 & ps.min_spatial_segmentation_idc, 252 | ps.parallelismType, 252 | ps.chroma_format_idc, 248 | ps.bit_depth_luma_minus8, 248 | ps.bit_depth_chroma_minus8, 0x00, parseInt(ps.frame_rate.fps), NALuLengthSize - 1 | ps.temporal_id_nested << 2 | ps.num_temporal_layers << 3 | (ps.frame_rate.fixed ? 64 : 0), units.length]);
16755
-
16756
- // compute hvcC size in bytes
16757
- var length = config.length;
16758
- for (var i = 0; i < units.length; i += 1) {
16759
- length += 3;
16760
- for (var j = 0; j < units[i].length; j += 1) {
16761
- length += 2 + units[i][j].length;
16762
- }
16763
- }
16764
- var hvcC = new Uint8Array(length);
16765
- hvcC.set(config, 0);
16766
- length = config.length;
16767
- // append parameter set units: one vps, one or more sps and pps
16768
- var iMax = units.length - 1;
16769
- for (var _i = 0; _i < units.length; _i += 1) {
16770
- hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
16771
- length += 3;
16772
- for (var _j = 0; _j < units[_i].length; _j += 1) {
16773
- hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
16774
- length += 2;
16775
- hvcC.set(units[_i][_j], length);
16776
- length += units[_i][_j].length;
16777
- }
16778
- }
16779
- var hvcc = MP4.box(MP4.types.hvcC, hvcC);
16780
- var width = track.width;
16781
- var height = track.height;
16782
- var hSpacing = track.pixelRatio[0];
16783
- var vSpacing = track.pixelRatio[1];
16784
- return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
16785
- // reserved
16786
- 0x00, 0x00, 0x00,
16787
- // reserved
16788
- 0x00, 0x01,
16789
- // data_reference_index
16790
- 0x00, 0x00,
16791
- // pre_defined
16792
- 0x00, 0x00,
16793
- // reserved
16794
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16795
- // pre_defined
16796
- width >> 8 & 0xff, width & 0xff,
16797
- // width
16798
- height >> 8 & 0xff, height & 0xff,
16799
- // height
16800
- 0x00, 0x48, 0x00, 0x00,
16801
- // horizresolution
16802
- 0x00, 0x48, 0x00, 0x00,
16803
- // vertresolution
16804
- 0x00, 0x00, 0x00, 0x00,
16805
- // reserved
16806
- 0x00, 0x01,
16807
- // frame_count
16808
- 0x12, 0x64, 0x61, 0x69, 0x6c,
16809
- // dailymotion/hls.js
16810
- 0x79, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x68, 0x6c, 0x73, 0x2e, 0x6a, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16811
- // compressorname
16812
- 0x00, 0x18,
16813
- // depth = 24
16814
- 0x11, 0x11]),
16815
- // pre_defined = -1
16816
- hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
16817
- // bufferSizeDB
16818
- 0x00, 0x2d, 0xc6, 0xc0,
16819
- // maxBitrate
16820
- 0x00, 0x2d, 0xc6, 0xc0])),
16821
- // avgBitrate
16822
- MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
16823
- // hSpacing
16824
- hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
16825
- // vSpacing
16826
- vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
16827
- };
16828
16454
  return MP4;
16829
16455
  }();
16830
16456
  MP4.types = void 0;
@@ -17211,9 +16837,9 @@
17211
16837
  var foundOverlap = delta < -1;
17212
16838
  if (foundHole || foundOverlap) {
17213
16839
  if (foundHole) {
17214
- logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
16840
+ logger.warn("AVC: " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
17215
16841
  } else {
17216
- logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
16842
+ logger.warn("AVC: " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
17217
16843
  }
17218
16844
  if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
17219
16845
  firstDTS = nextAvcDts;
@@ -17222,24 +16848,12 @@
17222
16848
  inputSamples[0].dts = firstDTS;
17223
16849
  inputSamples[0].pts = firstPTS;
17224
16850
  } else {
17225
- var isPTSOrderRetained = true;
17226
16851
  for (var _i = 0; _i < inputSamples.length; _i++) {
17227
- if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
16852
+ if (inputSamples[_i].dts > firstPTS) {
17228
16853
  break;
17229
16854
  }
17230
- var prevPTS = inputSamples[_i].pts;
17231
16855
  inputSamples[_i].dts -= delta;
17232
16856
  inputSamples[_i].pts -= delta;
17233
-
17234
- // check to see if this sample's PTS order has changed
17235
- // relative to the next one
17236
- if (_i < inputSamples.length - 1) {
17237
- var nextSamplePTS = inputSamples[_i + 1].pts;
17238
- var currentSamplePTS = inputSamples[_i].pts;
17239
- var currentOrder = nextSamplePTS <= currentSamplePTS;
17240
- var prevOrder = nextSamplePTS <= prevPTS;
17241
- isPTSOrderRetained = currentOrder == prevOrder;
17242
- }
17243
16857
  }
17244
16858
  }
17245
16859
  logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
@@ -17387,7 +17001,7 @@
17387
17001
  }
17388
17002
  }
17389
17003
  }
17390
- // next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
17004
+ // next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
17391
17005
  mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
17392
17006
  this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
17393
17007
  this.videoSampleDuration = mp4SampleDuration;
@@ -17522,7 +17136,7 @@
17522
17136
  logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
17523
17137
  for (var j = 0; j < missing; j++) {
17524
17138
  var newStamp = Math.max(nextPts, 0);
17525
- var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17139
+ var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17526
17140
  if (!fillFrame) {
17527
17141
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17528
17142
  fillFrame = sample.unit.subarray();
@@ -17650,7 +17264,7 @@
17650
17264
  // samples count of this segment's duration
17651
17265
  var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
17652
17266
  // silent frame
17653
- var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17267
+ var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17654
17268
  logger.warn('[mp4-remuxer]: remux empty Audio');
17655
17269
  // Can't remux if we can't generate a silent frame...
17656
17270
  if (!silentFrame) {
@@ -18037,15 +17651,13 @@
18037
17651
  duration = transmuxConfig.duration,
18038
17652
  initSegmentData = transmuxConfig.initSegmentData;
18039
17653
  var keyData = getEncryptionType(uintData, decryptdata);
18040
- if (keyData && isFullSegmentEncryption(keyData.method)) {
17654
+ if (keyData && keyData.method === 'AES-128') {
18041
17655
  var decrypter = this.getDecrypter();
18042
- var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
18043
-
18044
17656
  // Software decryption is synchronous; webCrypto is not
18045
17657
  if (decrypter.isSync()) {
18046
17658
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
18047
17659
  // data is handled in the flush() call
18048
- var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
17660
+ var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
18049
17661
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
18050
17662
  var loadingParts = chunkMeta.part > -1;
18051
17663
  if (loadingParts) {
@@ -18057,7 +17669,7 @@
18057
17669
  }
18058
17670
  uintData = new Uint8Array(decryptedData);
18059
17671
  } else {
18060
- this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
17672
+ this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
18061
17673
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
18062
17674
  // the decrypted data has been transmuxed
18063
17675
  var result = _this.push(decryptedData, null, chunkMeta);
@@ -18678,7 +18290,7 @@
18678
18290
  observer.on(Events.ERROR, forwardMessage);
18679
18291
 
18680
18292
  // forward logger events to main thread
18681
- var forwardWorkerLogs = function forwardWorkerLogs(logger) {
18293
+ var forwardWorkerLogs = function forwardWorkerLogs() {
18682
18294
  var _loop = function _loop(logFn) {
18683
18295
  var func = function func(message) {
18684
18296
  forwardMessage('workerLog', {
@@ -18699,8 +18311,8 @@
18699
18311
  {
18700
18312
  var config = JSON.parse(data.config);
18701
18313
  self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
18702
- var logger = enableLogs(config.debug, data.id);
18703
- forwardWorkerLogs(logger);
18314
+ enableLogs(config.debug, data.id);
18315
+ forwardWorkerLogs();
18704
18316
  forwardMessage('init', null);
18705
18317
  break;
18706
18318
  }
@@ -18874,7 +18486,16 @@
18874
18486
  this.observer = new EventEmitter();
18875
18487
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
18876
18488
  this.observer.on(Events.ERROR, forwardMessage);
18877
- var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
18489
+ var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
18490
+ isTypeSupported: function isTypeSupported() {
18491
+ return false;
18492
+ }
18493
+ };
18494
+ var m2tsTypeSupported = {
18495
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
18496
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
18497
+ ac3: false
18498
+ };
18878
18499
 
18879
18500
  // navigator.vendor is not always available in Web Worker
18880
18501
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -19131,26 +18752,21 @@
19131
18752
  var MAX_START_GAP_JUMP = 2.0;
19132
18753
  var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
19133
18754
  var SKIP_BUFFER_RANGE_START = 0.05;
19134
- var GapController = /*#__PURE__*/function (_Logger) {
19135
- _inheritsLoose(GapController, _Logger);
18755
+ var GapController = /*#__PURE__*/function () {
19136
18756
  function GapController(config, media, fragmentTracker, hls) {
19137
- var _this;
19138
- _this = _Logger.call(this, 'gap-controller', hls.logger) || this;
19139
- _this.config = void 0;
19140
- _this.media = null;
19141
- _this.fragmentTracker = void 0;
19142
- _this.hls = void 0;
19143
- _this.nudgeRetry = 0;
19144
- _this.stallReported = false;
19145
- _this.stalled = null;
19146
- _this.moved = false;
19147
- _this.seeking = false;
19148
- _this.ended = 0;
19149
- _this.config = config;
19150
- _this.media = media;
19151
- _this.fragmentTracker = fragmentTracker;
19152
- _this.hls = hls;
19153
- return _this;
18757
+ this.config = void 0;
18758
+ this.media = null;
18759
+ this.fragmentTracker = void 0;
18760
+ this.hls = void 0;
18761
+ this.nudgeRetry = 0;
18762
+ this.stallReported = false;
18763
+ this.stalled = null;
18764
+ this.moved = false;
18765
+ this.seeking = false;
18766
+ this.config = config;
18767
+ this.media = media;
18768
+ this.fragmentTracker = fragmentTracker;
18769
+ this.hls = hls;
19154
18770
  }
19155
18771
  var _proto = GapController.prototype;
19156
18772
  _proto.destroy = function destroy() {
@@ -19165,7 +18781,7 @@
19165
18781
  *
19166
18782
  * @param lastCurrentTime - Previously read playhead position
19167
18783
  */;
19168
- _proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
18784
+ _proto.poll = function poll(lastCurrentTime, activeFrag) {
19169
18785
  var config = this.config,
19170
18786
  media = this.media,
19171
18787
  stalled = this.stalled;
@@ -19180,7 +18796,6 @@
19180
18796
 
19181
18797
  // The playhead is moving, no-op
19182
18798
  if (currentTime !== lastCurrentTime) {
19183
- this.ended = 0;
19184
18799
  this.moved = true;
19185
18800
  if (!seeking) {
19186
18801
  this.nudgeRetry = 0;
@@ -19189,7 +18804,7 @@
19189
18804
  // The playhead is now moving, but was previously stalled
19190
18805
  if (this.stallReported) {
19191
18806
  var _stalledDuration = self.performance.now() - stalled;
19192
- this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
18807
+ logger.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
19193
18808
  this.stallReported = false;
19194
18809
  }
19195
18810
  this.stalled = null;
@@ -19225,6 +18840,7 @@
19225
18840
  // Skip start gaps if we haven't played, but the last poll detected the start of a stall
19226
18841
  // The addition poll gives the browser a chance to jump the gap for us
19227
18842
  if (!this.moved && this.stalled !== null) {
18843
+ var _level$details;
19228
18844
  // There is no playable buffer (seeked, waiting for buffer)
19229
18845
  var isBuffered = bufferInfo.len > 0;
19230
18846
  if (!isBuffered && !nextStart) {
@@ -19236,8 +18852,9 @@
19236
18852
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
19237
18853
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
19238
18854
  // that begins over 1 target duration after the video start position.
19239
- var isLive = !!(levelDetails != null && levelDetails.live);
19240
- var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
18855
+ var level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
18856
+ var isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
18857
+ var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
19241
18858
  var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
19242
18859
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
19243
18860
  if (!media.paused) {
@@ -19255,17 +18872,6 @@
19255
18872
  }
19256
18873
  var stalledDuration = tnow - stalled;
19257
18874
  if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
19258
- // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
19259
- if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
19260
- if (stalledDuration < 1000 || this.ended) {
19261
- return;
19262
- }
19263
- this.ended = currentTime;
19264
- this.hls.trigger(Events.MEDIA_ENDED, {
19265
- stalled: true
19266
- });
19267
- return;
19268
- }
19269
18875
  // Report stalling after trying to fix
19270
18876
  this._reportStall(bufferInfo);
19271
18877
  if (!this.media) {
@@ -19307,7 +18913,7 @@
19307
18913
  // needs to cross some sort of threshold covering all source-buffers content
19308
18914
  // to start playing properly.
19309
18915
  if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
19310
- this.warn('Trying to nudge playhead over buffer-hole');
18916
+ logger.warn('Trying to nudge playhead over buffer-hole');
19311
18917
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
19312
18918
  // We only try to jump the hole if it's under the configured size
19313
18919
  // Reset stalled so to rearm watchdog timer
@@ -19329,7 +18935,7 @@
19329
18935
  // Report stalled error once
19330
18936
  this.stallReported = true;
19331
18937
  var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
19332
- this.warn(error.message);
18938
+ logger.warn(error.message);
19333
18939
  hls.trigger(Events.ERROR, {
19334
18940
  type: ErrorTypes.MEDIA_ERROR,
19335
18941
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19393,7 +18999,7 @@
19393
18999
  }
19394
19000
  }
19395
19001
  var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
19396
- this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
19002
+ logger.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
19397
19003
  this.moved = true;
19398
19004
  this.stalled = null;
19399
19005
  media.currentTime = targetTime;
@@ -19432,7 +19038,7 @@
19432
19038
  var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
19433
19039
  // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
19434
19040
  var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
19435
- this.warn(error.message);
19041
+ logger.warn(error.message);
19436
19042
  media.currentTime = targetTime;
19437
19043
  hls.trigger(Events.ERROR, {
19438
19044
  type: ErrorTypes.MEDIA_ERROR,
@@ -19442,7 +19048,7 @@
19442
19048
  });
19443
19049
  } else {
19444
19050
  var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
19445
- this.error(_error.message);
19051
+ logger.error(_error.message);
19446
19052
  hls.trigger(Events.ERROR, {
19447
19053
  type: ErrorTypes.MEDIA_ERROR,
19448
19054
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19452,14 +19058,14 @@
19452
19058
  }
19453
19059
  };
19454
19060
  return GapController;
19455
- }(Logger);
19061
+ }();
19456
19062
 
19457
19063
  var TICK_INTERVAL = 100; // how often to tick in ms
19458
19064
  var StreamController = /*#__PURE__*/function (_BaseStreamController) {
19459
19065
  _inheritsLoose(StreamController, _BaseStreamController);
19460
19066
  function StreamController(hls, fragmentTracker, keyLoader) {
19461
19067
  var _this;
19462
- _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
19068
+ _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[stream-controller]', PlaylistLevelType.MAIN) || this;
19463
19069
  _this.audioCodecSwap = false;
19464
19070
  _this.gapController = null;
19465
19071
  _this.level = -1;
@@ -19467,43 +19073,27 @@
19467
19073
  _this.altAudio = false;
19468
19074
  _this.audioOnly = false;
19469
19075
  _this.fragPlaying = null;
19076
+ _this.onvplaying = null;
19077
+ _this.onvseeked = null;
19470
19078
  _this.fragLastKbps = 0;
19471
19079
  _this.couldBacktrack = false;
19472
19080
  _this.backtrackFragment = null;
19473
19081
  _this.audioCodecSwitch = false;
19474
19082
  _this.videoBuffer = null;
19475
- _this.onMediaPlaying = function () {
19476
- // tick to speed up FRAG_CHANGED triggering
19477
- _this.tick();
19478
- };
19479
- _this.onMediaSeeked = function () {
19480
- var media = _this.media;
19481
- var currentTime = media ? media.currentTime : null;
19482
- if (isFiniteNumber(currentTime)) {
19483
- _this.log("Media seeked to " + currentTime.toFixed(3));
19484
- }
19485
-
19486
- // If seeked was issued before buffer was appended do not tick immediately
19487
- var bufferInfo = _this.getMainFwdBufferInfo();
19488
- if (bufferInfo === null || bufferInfo.len === 0) {
19489
- _this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19490
- return;
19491
- }
19492
-
19493
- // tick to speed up FRAG_CHANGED triggering
19494
- _this.tick();
19495
- };
19496
- _this.registerListeners();
19083
+ _this._registerListeners();
19497
19084
  return _this;
19498
19085
  }
19499
19086
  var _proto = StreamController.prototype;
19500
- _proto.registerListeners = function registerListeners() {
19501
- _BaseStreamController.prototype.registerListeners.call(this);
19087
+ _proto._registerListeners = function _registerListeners() {
19502
19088
  var hls = this.hls;
19089
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19090
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19091
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19503
19092
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19504
19093
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
19505
19094
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19506
19095
  hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19096
+ hls.on(Events.ERROR, this.onError, this);
19507
19097
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19508
19098
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19509
19099
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19511,12 +19101,15 @@
19511
19101
  hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
19512
19102
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19513
19103
  };
19514
- _proto.unregisterListeners = function unregisterListeners() {
19515
- _BaseStreamController.prototype.unregisterListeners.call(this);
19104
+ _proto._unregisterListeners = function _unregisterListeners() {
19516
19105
  var hls = this.hls;
19106
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19107
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19108
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19517
19109
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19518
19110
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19519
19111
  hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19112
+ hls.off(Events.ERROR, this.onError, this);
19520
19113
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19521
19114
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19522
19115
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19525,9 +19118,7 @@
19525
19118
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19526
19119
  };
19527
19120
  _proto.onHandlerDestroying = function onHandlerDestroying() {
19528
- // @ts-ignore
19529
- this.onMediaPlaying = this.onMediaSeeked = null;
19530
- this.unregisterListeners();
19121
+ this._unregisterListeners();
19531
19122
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
19532
19123
  };
19533
19124
  _proto.startLoad = function startLoad(startPosition) {
@@ -19619,9 +19210,6 @@
19619
19210
  this.checkFragmentChanged();
19620
19211
  };
19621
19212
  _proto.doTickIdle = function doTickIdle() {
19622
- if (!this.buffering) {
19623
- return;
19624
- }
19625
19213
  var hls = this.hls,
19626
19214
  levelLastLoaded = this.levelLastLoaded,
19627
19215
  levels = this.levels,
@@ -19845,15 +19433,18 @@
19845
19433
  _proto.onMediaAttached = function onMediaAttached(event, data) {
19846
19434
  _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
19847
19435
  var media = data.media;
19848
- media.addEventListener('playing', this.onMediaPlaying);
19849
- media.addEventListener('seeked', this.onMediaSeeked);
19436
+ this.onvplaying = this.onMediaPlaying.bind(this);
19437
+ this.onvseeked = this.onMediaSeeked.bind(this);
19438
+ media.addEventListener('playing', this.onvplaying);
19439
+ media.addEventListener('seeked', this.onvseeked);
19850
19440
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
19851
19441
  };
19852
19442
  _proto.onMediaDetaching = function onMediaDetaching() {
19853
19443
  var media = this.media;
19854
- if (media) {
19855
- media.removeEventListener('playing', this.onMediaPlaying);
19856
- media.removeEventListener('seeked', this.onMediaSeeked);
19444
+ if (media && this.onvplaying && this.onvseeked) {
19445
+ media.removeEventListener('playing', this.onvplaying);
19446
+ media.removeEventListener('seeked', this.onvseeked);
19447
+ this.onvplaying = this.onvseeked = null;
19857
19448
  this.videoBuffer = null;
19858
19449
  }
19859
19450
  this.fragPlaying = null;
@@ -19863,6 +19454,27 @@
19863
19454
  }
19864
19455
  _BaseStreamController.prototype.onMediaDetaching.call(this);
19865
19456
  };
19457
+ _proto.onMediaPlaying = function onMediaPlaying() {
19458
+ // tick to speed up FRAG_CHANGED triggering
19459
+ this.tick();
19460
+ };
19461
+ _proto.onMediaSeeked = function onMediaSeeked() {
19462
+ var media = this.media;
19463
+ var currentTime = media ? media.currentTime : null;
19464
+ if (isFiniteNumber(currentTime)) {
19465
+ this.log("Media seeked to " + currentTime.toFixed(3));
19466
+ }
19467
+
19468
+ // If seeked was issued before buffer was appended do not tick immediately
19469
+ var bufferInfo = this.getMainFwdBufferInfo();
19470
+ if (bufferInfo === null || bufferInfo.len === 0) {
19471
+ this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19472
+ return;
19473
+ }
19474
+
19475
+ // tick to speed up FRAG_CHANGED triggering
19476
+ this.tick();
19477
+ };
19866
19478
  _proto.onManifestLoading = function onManifestLoading() {
19867
19479
  // reset buffer on manifest loading
19868
19480
  this.log('Trigger BUFFER_RESET');
@@ -20143,10 +19755,8 @@
20143
19755
  }
20144
19756
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
20145
19757
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
20146
- var state = this.state;
20147
- var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
20148
- var levelDetails = this.getLevelDetails();
20149
- gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
19758
+ var activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
19759
+ gapController.poll(this.lastCurrentTime, activeFrag);
20150
19760
  }
20151
19761
  this.lastCurrentTime = media.currentTime;
20152
19762
  };
@@ -20512,17 +20122,6 @@
20512
20122
  }
20513
20123
  };
20514
20124
  _createClass(StreamController, [{
20515
- key: "maxBufferLength",
20516
- get: function get() {
20517
- var levels = this.levels,
20518
- level = this.level;
20519
- var levelInfo = levels == null ? void 0 : levels[level];
20520
- if (!levelInfo) {
20521
- return this.config.maxBufferLength;
20522
- }
20523
- return this.getMaxBufferLength(levelInfo.maxBitrate);
20524
- }
20525
- }, {
20526
20125
  key: "nextLevel",
20527
20126
  get: function get() {
20528
20127
  var frag = this.nextBufferedFrag;
@@ -20622,12 +20221,9 @@
20622
20221
  * The configuration object provided on player instantiation.
20623
20222
  */
20624
20223
  this.userConfig = void 0;
20625
- /**
20626
- * The logger functions used by this player instance, configured on player instantiation.
20627
- */
20628
- this.logger = void 0;
20629
20224
  this.coreComponents = void 0;
20630
20225
  this.networkControllers = void 0;
20226
+ this.started = false;
20631
20227
  this._emitter = new EventEmitter();
20632
20228
  this._autoLevelCapping = -1;
20633
20229
  this._maxHdcpLevel = null;
@@ -20644,11 +20240,11 @@
20644
20240
  this._media = null;
20645
20241
  this.url = null;
20646
20242
  this.triggeringException = void 0;
20647
- var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
20648
- var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
20243
+ enableLogs(userConfig.debug || false, 'Hls instance');
20244
+ var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
20649
20245
  this.userConfig = userConfig;
20650
20246
  if (config.progressive) {
20651
- enableStreamingMode(config, logger);
20247
+ enableStreamingMode(config);
20652
20248
  }
20653
20249
 
20654
20250
  // core controllers and network loaders
@@ -20659,9 +20255,7 @@
20659
20255
  ConfigFpsController = config.fpsController;
20660
20256
  var errorController = new ConfigErrorController(this);
20661
20257
  var abrController = this.abrController = new ConfigAbrController(this);
20662
- // FragmentTracker must be defined before StreamController because the order of event handling is important
20663
- var fragmentTracker = new FragmentTracker(this);
20664
- var bufferController = this.bufferController = new ConfigBufferController(this, fragmentTracker);
20258
+ var bufferController = this.bufferController = new ConfigBufferController(this);
20665
20259
  var capLevelController = this.capLevelController = new ConfigCapLevelController(this);
20666
20260
  var fpsController = new ConfigFpsController(this);
20667
20261
  var playListLoader = new PlaylistLoader(this);
@@ -20670,6 +20264,8 @@
20670
20264
  // ConentSteeringController is defined before LevelController to receive Multivariant Playlist events first
20671
20265
  var contentSteering = ConfigContentSteeringController ? new ConfigContentSteeringController(this) : null;
20672
20266
  var levelController = this.levelController = new LevelController(this, contentSteering);
20267
+ // FragmentTracker must be defined before StreamController because the order of event handling is important
20268
+ var fragmentTracker = new FragmentTracker(this);
20673
20269
  var keyLoader = new KeyLoader(this.config);
20674
20270
  var streamController = this.streamController = new StreamController(this, fragmentTracker, keyLoader);
20675
20271
 
@@ -20756,7 +20352,7 @@
20756
20352
  try {
20757
20353
  return this.emit(event, event, eventObject);
20758
20354
  } catch (error) {
20759
- this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
20355
+ logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
20760
20356
  // Prevent recursion in error event handlers that throw #5497
20761
20357
  if (!this.triggeringException) {
20762
20358
  this.triggeringException = true;
@@ -20782,7 +20378,7 @@
20782
20378
  * Dispose of the instance
20783
20379
  */;
20784
20380
  _proto.destroy = function destroy() {
20785
- this.logger.log('destroy');
20381
+ logger.log('destroy');
20786
20382
  this.trigger(Events.DESTROYING, undefined);
20787
20383
  this.detachMedia();
20788
20384
  this.removeAllListeners();
@@ -20807,7 +20403,7 @@
20807
20403
  * Attaches Hls.js to a media element
20808
20404
  */;
20809
20405
  _proto.attachMedia = function attachMedia(media) {
20810
- this.logger.log('attachMedia');
20406
+ logger.log('attachMedia');
20811
20407
  this._media = media;
20812
20408
  this.trigger(Events.MEDIA_ATTACHING, {
20813
20409
  media: media
@@ -20818,7 +20414,7 @@
20818
20414
  * Detach Hls.js from the media
20819
20415
  */;
20820
20416
  _proto.detachMedia = function detachMedia() {
20821
- this.logger.log('detachMedia');
20417
+ logger.log('detachMedia');
20822
20418
  this.trigger(Events.MEDIA_DETACHING, undefined);
20823
20419
  this._media = null;
20824
20420
  }
@@ -20835,7 +20431,7 @@
20835
20431
  });
20836
20432
  this._autoLevelCapping = -1;
20837
20433
  this._maxHdcpLevel = null;
20838
- this.logger.log("loadSource:" + loadingSource);
20434
+ logger.log("loadSource:" + loadingSource);
20839
20435
  if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
20840
20436
  this.detachMedia();
20841
20437
  this.attachMedia(media);
@@ -20857,7 +20453,8 @@
20857
20453
  if (startPosition === void 0) {
20858
20454
  startPosition = -1;
20859
20455
  }
20860
- this.logger.log("startLoad(" + startPosition + ")");
20456
+ logger.log("startLoad(" + startPosition + ")");
20457
+ this.started = true;
20861
20458
  this.networkControllers.forEach(function (controller) {
20862
20459
  controller.startLoad(startPosition);
20863
20460
  });
@@ -20867,31 +20464,34 @@
20867
20464
  * Stop loading of any stream data.
20868
20465
  */;
20869
20466
  _proto.stopLoad = function stopLoad() {
20870
- this.logger.log('stopLoad');
20467
+ logger.log('stopLoad');
20468
+ this.started = false;
20871
20469
  this.networkControllers.forEach(function (controller) {
20872
20470
  controller.stopLoad();
20873
20471
  });
20874
20472
  }
20875
20473
 
20876
20474
  /**
20877
- * Resumes stream controller segment loading after `pauseBuffering` has been called.
20475
+ * Resumes stream controller segment loading if previously started.
20878
20476
  */;
20879
20477
  _proto.resumeBuffering = function resumeBuffering() {
20880
- this.networkControllers.forEach(function (controller) {
20881
- if (controller.resumeBuffering) {
20882
- controller.resumeBuffering();
20883
- }
20884
- });
20478
+ if (this.started) {
20479
+ this.networkControllers.forEach(function (controller) {
20480
+ if ('fragmentLoader' in controller) {
20481
+ controller.startLoad(-1);
20482
+ }
20483
+ });
20484
+ }
20885
20485
  }
20886
20486
 
20887
20487
  /**
20888
- * Prevents stream controller from loading new segments until `resumeBuffering` is called.
20488
+ * Stops stream controller segment loading without changing 'started' state like stopLoad().
20889
20489
  * This allows for media buffering to be paused without interupting playlist loading.
20890
20490
  */;
20891
20491
  _proto.pauseBuffering = function pauseBuffering() {
20892
20492
  this.networkControllers.forEach(function (controller) {
20893
- if (controller.pauseBuffering) {
20894
- controller.pauseBuffering();
20493
+ if ('fragmentLoader' in controller) {
20494
+ controller.stopLoad();
20895
20495
  }
20896
20496
  });
20897
20497
  }
@@ -20900,7 +20500,7 @@
20900
20500
  * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
20901
20501
  */;
20902
20502
  _proto.swapAudioCodec = function swapAudioCodec() {
20903
- this.logger.log('swapAudioCodec');
20503
+ logger.log('swapAudioCodec');
20904
20504
  this.streamController.swapAudioCodec();
20905
20505
  }
20906
20506
 
@@ -20911,7 +20511,7 @@
20911
20511
  * Automatic recovery of media-errors by this process is configurable.
20912
20512
  */;
20913
20513
  _proto.recoverMediaError = function recoverMediaError() {
20914
- this.logger.log('recoverMediaError');
20514
+ logger.log('recoverMediaError');
20915
20515
  var media = this._media;
20916
20516
  this.detachMedia();
20917
20517
  if (media) {
@@ -20966,7 +20566,7 @@
20966
20566
  * Set quality level index immediately. This will flush the current buffer to replace the quality asap. That means playback will interrupt at least shortly to re-buffer and re-sync eventually. Set to -1 for automatic level selection.
20967
20567
  */,
20968
20568
  set: function set(newLevel) {
20969
- this.logger.log("set currentLevel:" + newLevel);
20569
+ logger.log("set currentLevel:" + newLevel);
20970
20570
  this.levelController.manualLevel = newLevel;
20971
20571
  this.streamController.immediateLevelSwitch();
20972
20572
  }
@@ -20987,7 +20587,7 @@
20987
20587
  * @param newLevel - Pass -1 for automatic level selection
20988
20588
  */,
20989
20589
  set: function set(newLevel) {
20990
- this.logger.log("set nextLevel:" + newLevel);
20590
+ logger.log("set nextLevel:" + newLevel);
20991
20591
  this.levelController.manualLevel = newLevel;
20992
20592
  this.streamController.nextLevelSwitch();
20993
20593
  }
@@ -21008,7 +20608,7 @@
21008
20608
  * @param newLevel - Pass -1 for automatic level selection
21009
20609
  */,
21010
20610
  set: function set(newLevel) {
21011
- this.logger.log("set loadLevel:" + newLevel);
20611
+ logger.log("set loadLevel:" + newLevel);
21012
20612
  this.levelController.manualLevel = newLevel;
21013
20613
  }
21014
20614
 
@@ -21043,7 +20643,7 @@
21043
20643
  * Sets "first-level", see getter.
21044
20644
  */,
21045
20645
  set: function set(newLevel) {
21046
- this.logger.log("set firstLevel:" + newLevel);
20646
+ logger.log("set firstLevel:" + newLevel);
21047
20647
  this.levelController.firstLevel = newLevel;
21048
20648
  }
21049
20649
 
@@ -21070,7 +20670,7 @@
21070
20670
  * (determined from download of first segment)
21071
20671
  */,
21072
20672
  set: function set(newLevel) {
21073
- this.logger.log("set startLevel:" + newLevel);
20673
+ logger.log("set startLevel:" + newLevel);
21074
20674
  // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
21075
20675
  if (newLevel !== -1) {
21076
20676
  newLevel = Math.max(newLevel, this.minAutoLevel);
@@ -21123,7 +20723,7 @@
21123
20723
  */
21124
20724
  function set(newLevel) {
21125
20725
  if (this._autoLevelCapping !== newLevel) {
21126
- this.logger.log("set autoLevelCapping:" + newLevel);
20726
+ logger.log("set autoLevelCapping:" + newLevel);
21127
20727
  this._autoLevelCapping = newLevel;
21128
20728
  this.levelController.checkMaxAutoUpdated();
21129
20729
  }
@@ -21266,11 +20866,6 @@
21266
20866
  get: function get() {
21267
20867
  return this.streamController.getMainFwdBufferInfo();
21268
20868
  }
21269
- }, {
21270
- key: "maxBufferLength",
21271
- get: function get() {
21272
- return this.streamController.maxBufferLength;
21273
- }
21274
20869
  }, {
21275
20870
  key: "allAudioTracks",
21276
20871
  get: function get() {
@@ -21453,7 +21048,7 @@
21453
21048
  * Get the video-dev/hls.js package version.
21454
21049
  */
21455
21050
  function get() {
21456
- return "1.5.7-0.canary.10040";
21051
+ return "1.5.7";
21457
21052
  }
21458
21053
  }, {
21459
21054
  key: "Events",