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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +0 -1
  2. package/dist/hls-demo.js +0 -10
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1134 -2043
  5. package/dist/hls.js.d.ts +50 -65
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +852 -1141
  8. package/dist/hls.light.js.map +1 -1
  9. package/dist/hls.light.min.js +1 -1
  10. package/dist/hls.light.min.js.map +1 -1
  11. package/dist/hls.light.mjs +686 -974
  12. package/dist/hls.light.mjs.map +1 -1
  13. package/dist/hls.min.js +1 -1
  14. package/dist/hls.min.js.map +1 -1
  15. package/dist/hls.mjs +847 -1741
  16. package/dist/hls.mjs.map +1 -1
  17. package/dist/hls.worker.js +1 -1
  18. package/dist/hls.worker.js.map +1 -1
  19. package/package.json +20 -20
  20. package/src/config.ts +2 -3
  21. package/src/controller/abr-controller.ts +20 -21
  22. package/src/controller/audio-stream-controller.ts +16 -15
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +8 -20
  25. package/src/controller/base-stream-controller.ts +33 -149
  26. package/src/controller/buffer-controller.ts +11 -11
  27. package/src/controller/cap-level-controller.ts +2 -1
  28. package/src/controller/cmcd-controller.ts +6 -27
  29. package/src/controller/content-steering-controller.ts +6 -8
  30. package/src/controller/eme-controller.ts +22 -9
  31. package/src/controller/error-controller.ts +8 -6
  32. package/src/controller/fps-controller.ts +3 -2
  33. package/src/controller/gap-controller.ts +16 -43
  34. package/src/controller/latency-controller.ts +11 -9
  35. package/src/controller/level-controller.ts +18 -12
  36. package/src/controller/stream-controller.ts +32 -25
  37. package/src/controller/subtitle-stream-controller.ts +14 -13
  38. package/src/controller/subtitle-track-controller.ts +3 -5
  39. package/src/controller/timeline-controller.ts +30 -23
  40. package/src/crypt/aes-crypto.ts +2 -21
  41. package/src/crypt/decrypter.ts +18 -32
  42. package/src/crypt/fast-aes-key.ts +5 -24
  43. package/src/demux/audio/adts.ts +4 -9
  44. package/src/demux/sample-aes.ts +0 -2
  45. package/src/demux/transmuxer-interface.ts +12 -4
  46. package/src/demux/transmuxer-worker.ts +4 -4
  47. package/src/demux/transmuxer.ts +3 -16
  48. package/src/demux/tsdemuxer.ts +37 -71
  49. package/src/demux/video/avc-video-parser.ts +119 -208
  50. package/src/demux/video/base-video-parser.ts +2 -134
  51. package/src/demux/video/exp-golomb.ts +208 -0
  52. package/src/events.ts +0 -7
  53. package/src/hls.ts +34 -42
  54. package/src/loader/fragment-loader.ts +2 -9
  55. package/src/loader/key-loader.ts +0 -2
  56. package/src/loader/level-key.ts +9 -10
  57. package/src/loader/playlist-loader.ts +5 -4
  58. package/src/remux/mp4-generator.ts +1 -196
  59. package/src/remux/mp4-remuxer.ts +7 -23
  60. package/src/task-loop.ts +2 -5
  61. package/src/types/component-api.ts +0 -2
  62. package/src/types/demuxer.ts +0 -3
  63. package/src/types/events.ts +0 -4
  64. package/src/utils/codecs.ts +4 -33
  65. package/src/utils/logger.ts +24 -54
  66. package/src/crypt/decrypter-aes-mode.ts +0 -4
  67. package/src/demux/video/hevc-video-parser.ts +0 -746
  68. package/src/utils/encryption-methods-util.ts +0 -21
package/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.5");
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.5-0.canary.9997");
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.
@@ -2652,13 +2626,13 @@
2652
2626
  this.keyFormatVersions = formatversions;
2653
2627
  this.iv = iv;
2654
2628
  this.encrypted = method ? method !== 'NONE' : false;
2655
- this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2629
+ this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2656
2630
  }
2657
2631
  var _proto = LevelKey.prototype;
2658
2632
  _proto.isSupported = function isSupported() {
2659
2633
  // If it's Segment encryption or No encryption, just select that key system
2660
2634
  if (this.method) {
2661
- if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2635
+ if (this.method === 'AES-128' || this.method === 'NONE') {
2662
2636
  return true;
2663
2637
  }
2664
2638
  if (this.keyFormat === 'identity') {
@@ -2672,13 +2646,14 @@
2672
2646
  if (!this.encrypted || !this.uri) {
2673
2647
  return null;
2674
2648
  }
2675
- if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2649
+ if (this.method === 'AES-128' && this.uri && !this.iv) {
2676
2650
  if (typeof sn !== 'number') {
2677
2651
  // We are fetching decryption data for a initialization segment
2678
- // If the segment was encrypted with AES-128/256
2652
+ // If the segment was encrypted with AES-128
2679
2653
  // It must have an IV defined. We cannot substitute the Segment Number in.
2680
- logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2681
-
2654
+ if (this.method === 'AES-128' && !this.iv) {
2655
+ logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2656
+ }
2682
2657
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2683
2658
  sn = 0;
2684
2659
  }
@@ -2840,28 +2815,23 @@
2840
2815
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2841
2816
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2842
2817
  }
2818
+
2819
+ // Idealy fLaC and Opus would be first (spec-compliant) but
2820
+ // some browsers will report that fLaC is supported then fail.
2821
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2843
2822
  var codecsToCheck = {
2844
- // Idealy fLaC and Opus would be first (spec-compliant) but
2845
- // some browsers will report that fLaC is supported then fail.
2846
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2847
2823
  flac: ['flac', 'fLaC', 'FLAC'],
2848
- opus: ['opus', 'Opus'],
2849
- // Replace audio codec info if browser does not support mp4a.40.34,
2850
- // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
2851
- 'mp4a.40.34': ['mp3']
2824
+ opus: ['opus', 'Opus']
2852
2825
  }[lowerCaseCodec];
2853
2826
  for (var i = 0; i < codecsToCheck.length; i++) {
2854
- var _getMediaSource;
2855
2827
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2856
2828
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2857
2829
  return codecsToCheck[i];
2858
- } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2859
- return '';
2860
2830
  }
2861
2831
  }
2862
2832
  return lowerCaseCodec;
2863
2833
  }
2864
- var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2834
+ var AUDIO_CODEC_REGEXP = /flac|opus/i;
2865
2835
  function getCodecCompatibleName(codec, preferManagedMediaSource) {
2866
2836
  if (preferManagedMediaSource === void 0) {
2867
2837
  preferManagedMediaSource = true;
@@ -2889,18 +2859,6 @@
2889
2859
  }
2890
2860
  return codec;
2891
2861
  }
2892
- function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2893
- var MediaSource = getMediaSource(preferManagedMediaSource) || {
2894
- isTypeSupported: function isTypeSupported() {
2895
- return false;
2896
- }
2897
- };
2898
- return {
2899
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
2900
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
2901
- ac3: false
2902
- };
2903
- }
2904
2862
 
2905
2863
  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;
2906
2864
  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -3701,10 +3659,10 @@
3701
3659
  var loaderContext = loader.context;
3702
3660
  if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
3703
3661
  // same URL can't overlap
3704
- this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
3662
+ logger.trace('[playlist-loader]: playlist request ongoing');
3705
3663
  return;
3706
3664
  }
3707
- this.hls.logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
3665
+ logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
3708
3666
  loader.abort();
3709
3667
  }
3710
3668
 
@@ -3814,7 +3772,7 @@
3814
3772
  // alt audio rendition in which quality levels (main)
3815
3773
  // contains both audio+video. but with mixed audio track not signaled
3816
3774
  if (!embeddedAudioFound && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
3817
- this.hls.logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
3775
+ logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
3818
3776
  audioTracks.unshift({
3819
3777
  type: 'main',
3820
3778
  name: 'main',
@@ -3914,7 +3872,7 @@
3914
3872
  message += " id: " + context.id + " group-id: \"" + context.groupId + "\"";
3915
3873
  }
3916
3874
  var error = new Error(message);
3917
- this.hls.logger.warn("[playlist-loader]: " + message);
3875
+ logger.warn("[playlist-loader]: " + message);
3918
3876
  var details = ErrorDetails.UNKNOWN;
3919
3877
  var fatal = false;
3920
3878
  var loader = this.getInternalLoader(context);
@@ -4475,43 +4433,8 @@
4475
4433
  this.currentTime = 0;
4476
4434
  this.stallCount = 0;
4477
4435
  this._latency = null;
4478
- this.onTimeupdate = function () {
4479
- var media = _this.media,
4480
- levelDetails = _this.levelDetails;
4481
- if (!media || !levelDetails) {
4482
- return;
4483
- }
4484
- _this.currentTime = media.currentTime;
4485
- var latency = _this.computeLatency();
4486
- if (latency === null) {
4487
- return;
4488
- }
4489
- _this._latency = latency;
4490
-
4491
- // Adapt playbackRate to meet target latency in low-latency mode
4492
- var _this$config = _this.config,
4493
- lowLatencyMode = _this$config.lowLatencyMode,
4494
- maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4495
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4496
- return;
4497
- }
4498
- var targetLatency = _this.targetLatency;
4499
- if (targetLatency === null) {
4500
- return;
4501
- }
4502
- var distanceFromTarget = latency - targetLatency;
4503
- // Only adjust playbackRate when within one target duration of targetLatency
4504
- // and more than one second from under-buffering.
4505
- // Playback further than one target duration from target can be considered DVR playback.
4506
- var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
4507
- var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4508
- if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
4509
- var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4510
- var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
4511
- media.playbackRate = Math.min(max, Math.max(1, rate));
4512
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4513
- media.playbackRate = 1;
4514
- }
4436
+ this.timeupdateHandler = function () {
4437
+ return _this.timeupdate();
4515
4438
  };
4516
4439
  this.hls = hls;
4517
4440
  this.config = hls.config;
@@ -4523,7 +4446,7 @@
4523
4446
  this.onMediaDetaching();
4524
4447
  this.levelDetails = null;
4525
4448
  // @ts-ignore
4526
- this.hls = null;
4449
+ this.hls = this.timeupdateHandler = null;
4527
4450
  };
4528
4451
  _proto.registerListeners = function registerListeners() {
4529
4452
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4541,11 +4464,11 @@
4541
4464
  };
4542
4465
  _proto.onMediaAttached = function onMediaAttached(event, data) {
4543
4466
  this.media = data.media;
4544
- this.media.addEventListener('timeupdate', this.onTimeupdate);
4467
+ this.media.addEventListener('timeupdate', this.timeupdateHandler);
4545
4468
  };
4546
4469
  _proto.onMediaDetaching = function onMediaDetaching() {
4547
4470
  if (this.media) {
4548
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4471
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4549
4472
  this.media = null;
4550
4473
  }
4551
4474
  };
@@ -4558,10 +4481,10 @@
4558
4481
  var details = _ref.details;
4559
4482
  this.levelDetails = details;
4560
4483
  if (details.advanced) {
4561
- this.onTimeupdate();
4484
+ this.timeupdate();
4562
4485
  }
4563
4486
  if (!details.live && this.media) {
4564
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4487
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4565
4488
  }
4566
4489
  };
4567
4490
  _proto.onError = function onError(event, data) {
@@ -4571,7 +4494,45 @@
4571
4494
  }
4572
4495
  this.stallCount++;
4573
4496
  if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
4574
- this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
4497
+ logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
4498
+ }
4499
+ };
4500
+ _proto.timeupdate = function timeupdate() {
4501
+ var media = this.media,
4502
+ levelDetails = this.levelDetails;
4503
+ if (!media || !levelDetails) {
4504
+ return;
4505
+ }
4506
+ this.currentTime = media.currentTime;
4507
+ var latency = this.computeLatency();
4508
+ if (latency === null) {
4509
+ return;
4510
+ }
4511
+ this._latency = latency;
4512
+
4513
+ // Adapt playbackRate to meet target latency in low-latency mode
4514
+ var _this$config = this.config,
4515
+ lowLatencyMode = _this$config.lowLatencyMode,
4516
+ maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4517
+ if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4518
+ return;
4519
+ }
4520
+ var targetLatency = this.targetLatency;
4521
+ if (targetLatency === null) {
4522
+ return;
4523
+ }
4524
+ var distanceFromTarget = latency - targetLatency;
4525
+ // Only adjust playbackRate when within one target duration of targetLatency
4526
+ // and more than one second from under-buffering.
4527
+ // Playback further than one target duration from target can be considered DVR playback.
4528
+ var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4529
+ var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4530
+ if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4531
+ var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4532
+ var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4533
+ media.playbackRate = Math.min(max, Math.max(1, rate));
4534
+ } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4535
+ media.playbackRate = 1;
4575
4536
  }
4576
4537
  };
4577
4538
  _proto.estimateLiveEdge = function estimateLiveEdge() {
@@ -5479,17 +5440,19 @@
5479
5440
  MoveAllAlternatesMatchingHDCP: 2,
5480
5441
  SwitchToSDR: 4
5481
5442
  }; // Reserved for future use
5482
- var ErrorController = /*#__PURE__*/function (_Logger) {
5483
- _inheritsLoose(ErrorController, _Logger);
5443
+ var ErrorController = /*#__PURE__*/function () {
5484
5444
  function ErrorController(hls) {
5485
- var _this;
5486
- _this = _Logger.call(this, 'error-controller', hls.logger) || this;
5487
- _this.hls = void 0;
5488
- _this.playlistError = 0;
5489
- _this.penalizedRenditions = {};
5490
- _this.hls = hls;
5491
- _this.registerListeners();
5492
- return _this;
5445
+ this.hls = void 0;
5446
+ this.playlistError = 0;
5447
+ this.penalizedRenditions = {};
5448
+ this.log = void 0;
5449
+ this.warn = void 0;
5450
+ this.error = void 0;
5451
+ this.hls = hls;
5452
+ this.log = logger.log.bind(logger, "[info]:");
5453
+ this.warn = logger.warn.bind(logger, "[warning]:");
5454
+ this.error = logger.error.bind(logger, "[error]:");
5455
+ this.registerListeners();
5493
5456
  }
5494
5457
  var _proto = ErrorController.prototype;
5495
5458
  _proto.registerListeners = function registerListeners() {
@@ -5845,19 +5808,19 @@
5845
5808
  }
5846
5809
  };
5847
5810
  return ErrorController;
5848
- }(Logger);
5811
+ }();
5849
5812
 
5850
- var BasePlaylistController = /*#__PURE__*/function (_Logger) {
5851
- _inheritsLoose(BasePlaylistController, _Logger);
5813
+ var BasePlaylistController = /*#__PURE__*/function () {
5852
5814
  function BasePlaylistController(hls, logPrefix) {
5853
- var _this;
5854
- _this = _Logger.call(this, logPrefix, hls.logger) || this;
5855
- _this.hls = void 0;
5856
- _this.timer = -1;
5857
- _this.requestScheduled = -1;
5858
- _this.canLoad = false;
5859
- _this.hls = hls;
5860
- return _this;
5815
+ this.hls = void 0;
5816
+ this.timer = -1;
5817
+ this.requestScheduled = -1;
5818
+ this.canLoad = false;
5819
+ this.log = void 0;
5820
+ this.warn = void 0;
5821
+ this.log = logger.log.bind(logger, logPrefix + ":");
5822
+ this.warn = logger.warn.bind(logger, logPrefix + ":");
5823
+ this.hls = hls;
5861
5824
  }
5862
5825
  var _proto = BasePlaylistController.prototype;
5863
5826
  _proto.destroy = function destroy() {
@@ -5890,7 +5853,7 @@
5890
5853
  try {
5891
5854
  uri = new self.URL(attr.URI, previous.url).href;
5892
5855
  } catch (error) {
5893
- this.warn("Could not construct new URL for Rendition Report: " + error);
5856
+ logger.warn("Could not construct new URL for Rendition Report: " + error);
5894
5857
  uri = attr.URI || '';
5895
5858
  }
5896
5859
  // Use exact match. Otherwise, the last partial match, if any, will be used
@@ -5929,7 +5892,7 @@
5929
5892
  return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
5930
5893
  };
5931
5894
  _proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
5932
- var _this2 = this;
5895
+ var _this = this;
5933
5896
  var details = data.details,
5934
5897
  stats = data.stats;
5935
5898
 
@@ -5976,12 +5939,7 @@
5976
5939
  var cdnAge = lastAdvanced + details.ageHeader;
5977
5940
  var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
5978
5941
  if (currentGoal > 0) {
5979
- if (cdnAge > details.targetduration * 3) {
5980
- // Omit segment and part directives when the last response was more than 3 target durations ago,
5981
- this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
5982
- msn = undefined;
5983
- part = undefined;
5984
- } else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
5942
+ if (previousDetails && currentGoal > previousDetails.tuneInGoal) {
5985
5943
  // If we attempted to get the next or latest playlist update, but currentGoal increased,
5986
5944
  // then we either can't catchup, or the "age" header cannot be trusted.
5987
5945
  this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
@@ -6039,7 +5997,7 @@
6039
5997
  // );
6040
5998
 
6041
5999
  this.timer = self.setTimeout(function () {
6042
- return _this2.loadPlaylist(deliveryDirectives);
6000
+ return _this.loadPlaylist(deliveryDirectives);
6043
6001
  }, estimatedTimeUntilUpdate);
6044
6002
  } else {
6045
6003
  this.clearTimer();
@@ -6055,7 +6013,7 @@
6055
6013
  return new HlsUrlParameters(msn, part, skip);
6056
6014
  };
6057
6015
  _proto.checkRetry = function checkRetry(errorEvent) {
6058
- var _this3 = this;
6016
+ var _this2 = this;
6059
6017
  var errorDetails = errorEvent.details;
6060
6018
  var isTimeout = isTimeoutError(errorEvent);
6061
6019
  var errorAction = errorEvent.errorAction;
@@ -6079,7 +6037,7 @@
6079
6037
  var delay = getRetryDelay(retryConfig, retryCount);
6080
6038
  // Schedule level/track reload
6081
6039
  this.timer = self.setTimeout(function () {
6082
- return _this3.loadPlaylist();
6040
+ return _this2.loadPlaylist();
6083
6041
  }, delay);
6084
6042
  this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
6085
6043
  }
@@ -6090,7 +6048,7 @@
6090
6048
  return retry;
6091
6049
  };
6092
6050
  return BasePlaylistController;
6093
- }(Logger);
6051
+ }();
6094
6052
 
6095
6053
  /*
6096
6054
  * compute an Exponential Weighted moving average
@@ -6464,33 +6422,30 @@
6464
6422
  }, {});
6465
6423
  }
6466
6424
 
6467
- var AbrController = /*#__PURE__*/function (_Logger) {
6468
- _inheritsLoose(AbrController, _Logger);
6425
+ var AbrController = /*#__PURE__*/function () {
6469
6426
  function AbrController(_hls) {
6470
- var _this;
6471
- _this = _Logger.call(this, 'abr', _hls.logger) || this;
6472
- _this.hls = void 0;
6473
- _this.lastLevelLoadSec = 0;
6474
- _this.lastLoadedFragLevel = -1;
6475
- _this.firstSelection = -1;
6476
- _this._nextAutoLevel = -1;
6477
- _this.nextAutoLevelKey = '';
6478
- _this.audioTracksByGroup = null;
6479
- _this.codecTiers = null;
6480
- _this.timer = -1;
6481
- _this.fragCurrent = null;
6482
- _this.partCurrent = null;
6483
- _this.bitrateTestDelay = 0;
6484
- _this.bwEstimator = void 0;
6427
+ var _this = this;
6428
+ this.hls = void 0;
6429
+ this.lastLevelLoadSec = 0;
6430
+ this.lastLoadedFragLevel = -1;
6431
+ this.firstSelection = -1;
6432
+ this._nextAutoLevel = -1;
6433
+ this.nextAutoLevelKey = '';
6434
+ this.audioTracksByGroup = null;
6435
+ this.codecTiers = null;
6436
+ this.timer = -1;
6437
+ this.fragCurrent = null;
6438
+ this.partCurrent = null;
6439
+ this.bitrateTestDelay = 0;
6440
+ this.bwEstimator = void 0;
6485
6441
  /*
6486
6442
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
6487
6443
  quickly enough to prevent underbuffering
6488
6444
  */
6489
- _this._abandonRulesCheck = function () {
6490
- var _assertThisInitialize = _assertThisInitialized(_this),
6491
- frag = _assertThisInitialize.fragCurrent,
6492
- part = _assertThisInitialize.partCurrent,
6493
- hls = _assertThisInitialize.hls;
6445
+ this._abandonRulesCheck = function () {
6446
+ var frag = _this.fragCurrent,
6447
+ part = _this.partCurrent,
6448
+ hls = _this.hls;
6494
6449
  var autoLevelEnabled = hls.autoLevelEnabled,
6495
6450
  media = hls.media;
6496
6451
  if (!frag || !media) {
@@ -6579,22 +6534,21 @@
6579
6534
  _this.resetEstimator(nextLoadLevelBitrate);
6580
6535
  }
6581
6536
  _this.clearTimer();
6582
- _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");
6537
+ 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");
6583
6538
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
6584
6539
  frag: frag,
6585
6540
  part: part,
6586
6541
  stats: stats
6587
6542
  });
6588
6543
  };
6589
- _this.hls = _hls;
6590
- _this.bwEstimator = _this.initEstimator();
6591
- _this.registerListeners();
6592
- return _this;
6544
+ this.hls = _hls;
6545
+ this.bwEstimator = this.initEstimator();
6546
+ this.registerListeners();
6593
6547
  }
6594
6548
  var _proto = AbrController.prototype;
6595
6549
  _proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
6596
6550
  if (abrEwmaDefaultEstimate) {
6597
- this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6551
+ logger.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6598
6552
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
6599
6553
  }
6600
6554
  this.firstSelection = -1;
@@ -6846,13 +6800,13 @@
6846
6800
  // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
6847
6801
  var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
6848
6802
  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");
6803
+ logger.info("[abr] bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
6850
6804
  // don't use conservative factor on bitrate test
6851
6805
  bwFactor = bwUpFactor = 1;
6852
6806
  }
6853
6807
  }
6854
6808
  var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
6855
- this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6809
+ logger.info("[abr] " + (bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6856
6810
  if (bestLevel > -1) {
6857
6811
  return bestLevel;
6858
6812
  }
@@ -6908,7 +6862,7 @@
6908
6862
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
6909
6863
  currentFrameRate = minFramerate;
6910
6864
  currentBw = Math.max(currentBw, minBitrate);
6911
- this.log("picked start tier " + JSON.stringify(startTier));
6865
+ logger.log("[abr] picked start tier " + JSON.stringify(startTier));
6912
6866
  } else {
6913
6867
  currentCodecSet = level == null ? void 0 : level.codecSet;
6914
6868
  currentVideoRange = level == null ? void 0 : level.videoRange;
@@ -6961,9 +6915,9 @@
6961
6915
  var forcedAutoLevel = _this2.forcedAutoLevel;
6962
6916
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
6963
6917
  if (levelsSkipped.length) {
6964
- _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);
6918
+ 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);
6965
6919
  }
6966
- _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);
6920
+ 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);
6967
6921
  }
6968
6922
  if (firstSelection) {
6969
6923
  _this2.firstSelection = i;
@@ -6997,7 +6951,7 @@
6997
6951
  }
6998
6952
  var firstLevel = this.hls.firstLevel;
6999
6953
  var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
7000
- this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
6954
+ logger.warn("[abr] Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
7001
6955
  return clamped;
7002
6956
  }
7003
6957
  }, {
@@ -7050,7 +7004,7 @@
7050
7004
  }
7051
7005
  }]);
7052
7006
  return AbrController;
7053
- }(Logger);
7007
+ }();
7054
7008
 
7055
7009
  /**
7056
7010
  * Provides methods dealing with buffer length retrieval for example.
@@ -7271,57 +7225,57 @@
7271
7225
  }();
7272
7226
 
7273
7227
  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
7274
- var BufferController = /*#__PURE__*/function (_Logger) {
7275
- _inheritsLoose(BufferController, _Logger);
7228
+ var BufferController = /*#__PURE__*/function () {
7276
7229
  function BufferController(hls) {
7277
- var _this;
7278
- _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
7230
+ var _this = this;
7279
7231
  // The level details used to determine duration, target-duration and live
7280
- _this.details = null;
7232
+ this.details = null;
7281
7233
  // cache the self generated object url to detect hijack of video tag
7282
- _this._objectUrl = null;
7234
+ this._objectUrl = null;
7283
7235
  // A queue of buffer operations which require the SourceBuffer to not be updating upon execution
7284
- _this.operationQueue = void 0;
7236
+ this.operationQueue = void 0;
7285
7237
  // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
7286
- _this.listeners = void 0;
7287
- _this.hls = void 0;
7238
+ this.listeners = void 0;
7239
+ this.hls = void 0;
7288
7240
  // The number of BUFFER_CODEC events received before any sourceBuffers are created
7289
- _this.bufferCodecEventsExpected = 0;
7241
+ this.bufferCodecEventsExpected = 0;
7290
7242
  // The total number of BUFFER_CODEC events received
7291
- _this._bufferCodecEventsTotal = 0;
7243
+ this._bufferCodecEventsTotal = 0;
7292
7244
  // A reference to the attached media element
7293
- _this.media = null;
7245
+ this.media = null;
7294
7246
  // A reference to the active media source
7295
- _this.mediaSource = null;
7247
+ this.mediaSource = null;
7296
7248
  // Last MP3 audio chunk appended
7297
- _this.lastMpegAudioChunk = null;
7298
- _this.appendSource = void 0;
7249
+ this.lastMpegAudioChunk = null;
7250
+ this.appendSource = void 0;
7299
7251
  // counters
7300
- _this.appendErrors = {
7252
+ this.appendErrors = {
7301
7253
  audio: 0,
7302
7254
  video: 0,
7303
7255
  audiovideo: 0
7304
7256
  };
7305
- _this.tracks = {};
7306
- _this.pendingTracks = {};
7307
- _this.sourceBuffer = void 0;
7308
- _this._onEndStreaming = function (event) {
7257
+ this.tracks = {};
7258
+ this.pendingTracks = {};
7259
+ this.sourceBuffer = void 0;
7260
+ this.log = void 0;
7261
+ this.warn = void 0;
7262
+ this.error = void 0;
7263
+ this._onEndStreaming = function (event) {
7309
7264
  if (!_this.hls) {
7310
7265
  return;
7311
7266
  }
7312
7267
  _this.hls.pauseBuffering();
7313
7268
  };
7314
- _this._onStartStreaming = function (event) {
7269
+ this._onStartStreaming = function (event) {
7315
7270
  if (!_this.hls) {
7316
7271
  return;
7317
7272
  }
7318
7273
  _this.hls.resumeBuffering();
7319
7274
  };
7320
7275
  // 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;
7276
+ this._onMediaSourceOpen = function () {
7277
+ var media = _this.media,
7278
+ mediaSource = _this.mediaSource;
7325
7279
  _this.log('Media source opened');
7326
7280
  if (media) {
7327
7281
  media.removeEventListener('emptied', _this._onMediaEmptied);
@@ -7337,25 +7291,27 @@
7337
7291
  }
7338
7292
  _this.checkPendingTracks();
7339
7293
  };
7340
- _this._onMediaSourceClose = function () {
7294
+ this._onMediaSourceClose = function () {
7341
7295
  _this.log('Media source closed');
7342
7296
  };
7343
- _this._onMediaSourceEnded = function () {
7297
+ this._onMediaSourceEnded = function () {
7344
7298
  _this.log('Media source ended');
7345
7299
  };
7346
- _this._onMediaEmptied = function () {
7347
- var _assertThisInitialize2 = _assertThisInitialized(_this),
7348
- mediaSrc = _assertThisInitialize2.mediaSrc,
7349
- _objectUrl = _assertThisInitialize2._objectUrl;
7300
+ this._onMediaEmptied = function () {
7301
+ var mediaSrc = _this.mediaSrc,
7302
+ _objectUrl = _this._objectUrl;
7350
7303
  if (mediaSrc !== _objectUrl) {
7351
- _this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7304
+ logger.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7352
7305
  }
7353
7306
  };
7354
- _this.hls = hls;
7355
- _this.appendSource = hls.config.preferManagedMediaSource;
7356
- _this._initSourceBuffer();
7357
- _this.registerListeners();
7358
- return _this;
7307
+ this.hls = hls;
7308
+ var logPrefix = '[buffer-controller]';
7309
+ this.appendSource = hls.config.preferManagedMediaSource;
7310
+ this.log = logger.log.bind(logger, logPrefix);
7311
+ this.warn = logger.warn.bind(logger, logPrefix);
7312
+ this.error = logger.error.bind(logger, logPrefix);
7313
+ this._initSourceBuffer();
7314
+ this.registerListeners();
7359
7315
  }
7360
7316
  var _proto = BufferController.prototype;
7361
7317
  _proto.hasSourceTypes = function hasSourceTypes() {
@@ -7367,12 +7323,6 @@
7367
7323
  this.lastMpegAudioChunk = null;
7368
7324
  // @ts-ignore
7369
7325
  this.hls = null;
7370
- // @ts-ignore
7371
- this._onMediaSourceOpen = this._onMediaSourceClose = null;
7372
- // @ts-ignore
7373
- this._onMediaSourceEnded = null;
7374
- // @ts-ignore
7375
- this._onStartStreaming = this._onEndStreaming = null;
7376
7326
  };
7377
7327
  _proto.registerListeners = function registerListeners() {
7378
7328
  var hls = this.hls;
@@ -7530,7 +7480,6 @@
7530
7480
  _this2.resetBuffer(type);
7531
7481
  });
7532
7482
  this._initSourceBuffer();
7533
- this.hls.resumeBuffering();
7534
7483
  };
7535
7484
  _proto.resetBuffer = function resetBuffer(type) {
7536
7485
  var sb = this.sourceBuffer[type];
@@ -8234,7 +8183,7 @@
8234
8183
  }
8235
8184
  }]);
8236
8185
  return BufferController;
8237
- }(Logger);
8186
+ }();
8238
8187
  function removeSourceChildren(node) {
8239
8188
  var sourceChildren = node.querySelectorAll('source');
8240
8189
  [].slice.call(sourceChildren).forEach(function (source) {
@@ -8358,7 +8307,7 @@
8358
8307
  var hls = this.hls;
8359
8308
  var maxLevel = this.getMaxLevel(levels.length - 1);
8360
8309
  if (maxLevel !== this.autoLevelCapping) {
8361
- hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8310
+ logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8362
8311
  }
8363
8312
  hls.autoLevelCapping = maxLevel;
8364
8313
  if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
@@ -8548,10 +8497,10 @@
8548
8497
  totalDroppedFrames: droppedFrames
8549
8498
  });
8550
8499
  if (droppedFPS > 0) {
8551
- // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8500
+ // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8552
8501
  if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
8553
8502
  var currentLevel = hls.currentLevel;
8554
- hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8503
+ logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8555
8504
  if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
8556
8505
  currentLevel = currentLevel - 1;
8557
8506
  hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
@@ -8585,28 +8534,26 @@
8585
8534
  }();
8586
8535
 
8587
8536
  var PATHWAY_PENALTY_DURATION_MS = 300000;
8588
- var ContentSteeringController = /*#__PURE__*/function (_Logger) {
8589
- _inheritsLoose(ContentSteeringController, _Logger);
8537
+ var ContentSteeringController = /*#__PURE__*/function () {
8590
8538
  function ContentSteeringController(hls) {
8591
- var _this;
8592
- _this = _Logger.call(this, 'content-steering', hls.logger) || this;
8593
- _this.hls = void 0;
8594
- _this.loader = null;
8595
- _this.uri = null;
8596
- _this.pathwayId = '.';
8597
- _this.pathwayPriority = null;
8598
- _this.timeToLoad = 300;
8599
- _this.reloadTimer = -1;
8600
- _this.updated = 0;
8601
- _this.started = false;
8602
- _this.enabled = true;
8603
- _this.levels = null;
8604
- _this.audioTracks = null;
8605
- _this.subtitleTracks = null;
8606
- _this.penalizedPathways = {};
8607
- _this.hls = hls;
8608
- _this.registerListeners();
8609
- return _this;
8539
+ this.hls = void 0;
8540
+ this.log = void 0;
8541
+ this.loader = null;
8542
+ this.uri = null;
8543
+ this.pathwayId = '.';
8544
+ this.pathwayPriority = null;
8545
+ this.timeToLoad = 300;
8546
+ this.reloadTimer = -1;
8547
+ this.updated = 0;
8548
+ this.started = false;
8549
+ this.enabled = true;
8550
+ this.levels = null;
8551
+ this.audioTracks = null;
8552
+ this.subtitleTracks = null;
8553
+ this.penalizedPathways = {};
8554
+ this.hls = hls;
8555
+ this.log = logger.log.bind(logger, "[content-steering]:");
8556
+ this.registerListeners();
8610
8557
  }
8611
8558
  var _proto = ContentSteeringController.prototype;
8612
8559
  _proto.registerListeners = function registerListeners() {
@@ -8727,7 +8674,7 @@
8727
8674
  errorAction.resolved = this.pathwayId !== errorPathway;
8728
8675
  }
8729
8676
  if (!errorAction.resolved) {
8730
- 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));
8677
+ 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));
8731
8678
  }
8732
8679
  }
8733
8680
  };
@@ -8807,7 +8754,7 @@
8807
8754
  return defaultPathway;
8808
8755
  };
8809
8756
  _proto.clonePathways = function clonePathways(pathwayClones) {
8810
- var _this2 = this;
8757
+ var _this = this;
8811
8758
  var levels = this.levels;
8812
8759
  if (!levels) {
8813
8760
  return;
@@ -8823,7 +8770,7 @@
8823
8770
  })) {
8824
8771
  return;
8825
8772
  }
8826
- var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
8773
+ var clonedVariants = _this.getLevelsForPathway(baseId).map(function (baseLevel) {
8827
8774
  var attributes = new AttrList(baseLevel.attrs);
8828
8775
  attributes['PATHWAY-ID'] = cloneId;
8829
8776
  var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
@@ -8860,12 +8807,12 @@
8860
8807
  return clonedLevel;
8861
8808
  });
8862
8809
  levels.push.apply(levels, clonedVariants);
8863
- cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8864
- cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8810
+ cloneRenditionGroups(_this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8811
+ cloneRenditionGroups(_this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8865
8812
  });
8866
8813
  };
8867
8814
  _proto.loadSteeringManifest = function loadSteeringManifest(uri) {
8868
- var _this3 = this;
8815
+ var _this2 = this;
8869
8816
  var config = this.hls.config;
8870
8817
  var Loader = config.loader;
8871
8818
  if (this.loader) {
@@ -8900,87 +8847,87 @@
8900
8847
  };
8901
8848
  var callbacks = {
8902
8849
  onSuccess: function onSuccess(response, stats, context, networkDetails) {
8903
- _this3.log("Loaded steering manifest: \"" + url + "\"");
8850
+ _this2.log("Loaded steering manifest: \"" + url + "\"");
8904
8851
  var steeringData = response.data;
8905
- if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
8906
- _this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
8852
+ if (steeringData.VERSION !== 1) {
8853
+ _this2.log("Steering VERSION " + steeringData.VERSION + " not supported!");
8907
8854
  return;
8908
8855
  }
8909
- _this3.updated = performance.now();
8910
- _this3.timeToLoad = steeringData.TTL;
8856
+ _this2.updated = performance.now();
8857
+ _this2.timeToLoad = steeringData.TTL;
8911
8858
  var reloadUri = steeringData['RELOAD-URI'],
8912
8859
  pathwayClones = steeringData['PATHWAY-CLONES'],
8913
8860
  pathwayPriority = steeringData['PATHWAY-PRIORITY'];
8914
8861
  if (reloadUri) {
8915
8862
  try {
8916
- _this3.uri = new self.URL(reloadUri, url).href;
8863
+ _this2.uri = new self.URL(reloadUri, url).href;
8917
8864
  } catch (error) {
8918
- _this3.enabled = false;
8919
- _this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
8865
+ _this2.enabled = false;
8866
+ _this2.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
8920
8867
  return;
8921
8868
  }
8922
8869
  }
8923
- _this3.scheduleRefresh(_this3.uri || context.url);
8870
+ _this2.scheduleRefresh(_this2.uri || context.url);
8924
8871
  if (pathwayClones) {
8925
- _this3.clonePathways(pathwayClones);
8872
+ _this2.clonePathways(pathwayClones);
8926
8873
  }
8927
8874
  var loadedSteeringData = {
8928
8875
  steeringManifest: steeringData,
8929
8876
  url: url.toString()
8930
8877
  };
8931
- _this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8878
+ _this2.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8932
8879
  if (pathwayPriority) {
8933
- _this3.updatePathwayPriority(pathwayPriority);
8880
+ _this2.updatePathwayPriority(pathwayPriority);
8934
8881
  }
8935
8882
  },
8936
8883
  onError: function onError(error, context, networkDetails, stats) {
8937
- _this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8938
- _this3.stopLoad();
8884
+ _this2.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8885
+ _this2.stopLoad();
8939
8886
  if (error.code === 410) {
8940
- _this3.enabled = false;
8941
- _this3.log("Steering manifest " + context.url + " no longer available");
8887
+ _this2.enabled = false;
8888
+ _this2.log("Steering manifest " + context.url + " no longer available");
8942
8889
  return;
8943
8890
  }
8944
- var ttl = _this3.timeToLoad * 1000;
8891
+ var ttl = _this2.timeToLoad * 1000;
8945
8892
  if (error.code === 429) {
8946
- var loader = _this3.loader;
8893
+ var loader = _this2.loader;
8947
8894
  if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
8948
8895
  var retryAfter = loader.getResponseHeader('Retry-After');
8949
8896
  if (retryAfter) {
8950
8897
  ttl = parseFloat(retryAfter) * 1000;
8951
8898
  }
8952
8899
  }
8953
- _this3.log("Steering manifest " + context.url + " rate limited");
8900
+ _this2.log("Steering manifest " + context.url + " rate limited");
8954
8901
  return;
8955
8902
  }
8956
- _this3.scheduleRefresh(_this3.uri || context.url, ttl);
8903
+ _this2.scheduleRefresh(_this2.uri || context.url, ttl);
8957
8904
  },
8958
8905
  onTimeout: function onTimeout(stats, context, networkDetails) {
8959
- _this3.log("Timeout loading steering manifest (" + context.url + ")");
8960
- _this3.scheduleRefresh(_this3.uri || context.url);
8906
+ _this2.log("Timeout loading steering manifest (" + context.url + ")");
8907
+ _this2.scheduleRefresh(_this2.uri || context.url);
8961
8908
  }
8962
8909
  };
8963
8910
  this.log("Requesting steering manifest: " + url);
8964
8911
  this.loader.load(context, loaderConfig, callbacks);
8965
8912
  };
8966
8913
  _proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
8967
- var _this4 = this;
8914
+ var _this3 = this;
8968
8915
  if (ttlMs === void 0) {
8969
8916
  ttlMs = this.timeToLoad * 1000;
8970
8917
  }
8971
8918
  this.clearTimeout();
8972
8919
  this.reloadTimer = self.setTimeout(function () {
8973
- var _this4$hls;
8974
- var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
8920
+ var _this3$hls;
8921
+ var media = (_this3$hls = _this3.hls) == null ? void 0 : _this3$hls.media;
8975
8922
  if (media && !media.ended) {
8976
- _this4.loadSteeringManifest(uri);
8923
+ _this3.loadSteeringManifest(uri);
8977
8924
  return;
8978
8925
  }
8979
- _this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
8926
+ _this3.scheduleRefresh(uri, _this3.timeToLoad * 1000);
8980
8927
  }, ttlMs);
8981
8928
  };
8982
8929
  return ContentSteeringController;
8983
- }(Logger);
8930
+ }();
8984
8931
  function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
8985
8932
  if (!tracks) {
8986
8933
  return;
@@ -9816,7 +9763,7 @@
9816
9763
  });
9817
9764
  function timelineConfig() {
9818
9765
  return {
9819
- cueHandler: HevcVideoParser,
9766
+ cueHandler: Cues,
9820
9767
  // used by timeline-controller
9821
9768
  enableWebVTT: false,
9822
9769
  // used by timeline-controller
@@ -9847,7 +9794,7 @@
9847
9794
  /**
9848
9795
  * @ignore
9849
9796
  */
9850
- function mergeConfig(defaultConfig, userConfig, logger) {
9797
+ function mergeConfig(defaultConfig, userConfig) {
9851
9798
  if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
9852
9799
  throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
9853
9800
  }
@@ -9917,7 +9864,7 @@
9917
9864
  /**
9918
9865
  * @ignore
9919
9866
  */
9920
- function enableStreamingMode(config, logger) {
9867
+ function enableStreamingMode(config) {
9921
9868
  var currentLoader = config.loader;
9922
9869
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
9923
9870
  // If a developer has configured their own loader, respect that choice
@@ -9934,11 +9881,12 @@
9934
9881
  }
9935
9882
  }
9936
9883
 
9884
+ var chromeOrFirefox;
9937
9885
  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
9938
9886
  _inheritsLoose(LevelController, _BasePlaylistControll);
9939
9887
  function LevelController(hls, contentSteeringController) {
9940
9888
  var _this;
9941
- _this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
9889
+ _this = _BasePlaylistControll.call(this, hls, '[level-controller]') || this;
9942
9890
  _this._levels = [];
9943
9891
  _this._firstLevel = -1;
9944
9892
  _this._maxAutoLevel = -1;
@@ -10007,13 +9955,21 @@
10007
9955
  var videoCodecFound = false;
10008
9956
  var audioCodecFound = false;
10009
9957
  data.levels.forEach(function (levelParsed) {
10010
- var _videoCodec;
9958
+ var _audioCodec, _videoCodec;
10011
9959
  var attributes = levelParsed.attrs;
9960
+
9961
+ // erase audio codec info if browser does not support mp4a.40.34.
9962
+ // demuxer will autodetect codec and fallback to mpeg/audio
10012
9963
  var audioCodec = levelParsed.audioCodec,
10013
9964
  videoCodec = levelParsed.videoCodec;
9965
+ if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
9966
+ chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
9967
+ if (chromeOrFirefox) {
9968
+ levelParsed.audioCodec = audioCodec = undefined;
9969
+ }
9970
+ }
10014
9971
  if (audioCodec) {
10015
- // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
10016
- levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
9972
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
10017
9973
  }
10018
9974
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
10019
9975
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -10245,12 +10201,7 @@
10245
10201
  if (curLevel.fragmentError === 0) {
10246
10202
  curLevel.loadError = 0;
10247
10203
  }
10248
- // Ignore matching details populated by loading a Media Playlist directly
10249
- var previousDetails = curLevel.details;
10250
- if (previousDetails === data.details && previousDetails.advanced) {
10251
- previousDetails = undefined;
10252
- }
10253
- this.playlistLoaded(level, data, previousDetails);
10204
+ this.playlistLoaded(level, data, curLevel.details);
10254
10205
  } else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
10255
10206
  // received a delta playlist update that cannot be merged
10256
10207
  details.deltaUpdateFailed = true;
@@ -11165,8 +11116,8 @@
11165
11116
  var _frag$decryptdata;
11166
11117
  var byteRangeStart = start;
11167
11118
  var byteRangeEnd = end;
11168
- if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
11169
- // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
11119
+ if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
11120
+ // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
11170
11121
  // has the unencrypted size specified in the range.
11171
11122
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
11172
11123
  var fragmentLen = end - start;
@@ -11199,9 +11150,6 @@
11199
11150
  (part ? part : frag).stats.aborted = true;
11200
11151
  return new LoadError(errorData);
11201
11152
  }
11202
- function isMethodFullSegmentAesCbc(method) {
11203
- return method === 'AES-128' || method === 'AES-256';
11204
- }
11205
11153
  var LoadError = /*#__PURE__*/function (_Error) {
11206
11154
  _inheritsLoose(LoadError, _Error);
11207
11155
  function LoadError(data) {
@@ -11358,8 +11306,6 @@
11358
11306
  }
11359
11307
  return this.loadKeyEME(keyInfo, frag);
11360
11308
  case 'AES-128':
11361
- case 'AES-256':
11362
- case 'AES-256-CTR':
11363
11309
  return this.loadKeyHTTP(keyInfo, frag);
11364
11310
  default:
11365
11311
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
@@ -11493,17 +11439,13 @@
11493
11439
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
11494
11440
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
11495
11441
  */
11496
- var TaskLoop = /*#__PURE__*/function (_Logger) {
11497
- _inheritsLoose(TaskLoop, _Logger);
11498
- function TaskLoop(label, logger) {
11499
- var _this;
11500
- _this = _Logger.call(this, label, logger) || this;
11501
- _this._boundTick = void 0;
11502
- _this._tickTimer = null;
11503
- _this._tickInterval = null;
11504
- _this._tickCallCount = 0;
11505
- _this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
11506
- return _this;
11442
+ var TaskLoop = /*#__PURE__*/function () {
11443
+ function TaskLoop() {
11444
+ this._boundTick = void 0;
11445
+ this._tickTimer = null;
11446
+ this._tickInterval = null;
11447
+ this._tickCallCount = 0;
11448
+ this._boundTick = this.tick.bind(this);
11507
11449
  }
11508
11450
  var _proto = TaskLoop.prototype;
11509
11451
  _proto.destroy = function destroy() {
@@ -11589,7 +11531,7 @@
11589
11531
  */;
11590
11532
  _proto.doTick = function doTick() {};
11591
11533
  return TaskLoop;
11592
- }(Logger);
11534
+ }();
11593
11535
 
11594
11536
  var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
11595
11537
  if (size === void 0) {
@@ -11775,65 +11717,37 @@
11775
11717
  }
11776
11718
 
11777
11719
  var AESCrypto = /*#__PURE__*/function () {
11778
- function AESCrypto(subtle, iv, aesMode) {
11720
+ function AESCrypto(subtle, iv) {
11779
11721
  this.subtle = void 0;
11780
11722
  this.aesIV = void 0;
11781
- this.aesMode = void 0;
11782
11723
  this.subtle = subtle;
11783
11724
  this.aesIV = iv;
11784
- this.aesMode = aesMode;
11785
11725
  }
11786
11726
  var _proto = AESCrypto.prototype;
11787
11727
  _proto.decrypt = function decrypt(data, key) {
11788
- switch (this.aesMode) {
11789
- case DecrypterAesMode.cbc:
11790
- return this.subtle.decrypt({
11791
- name: 'AES-CBC',
11792
- iv: this.aesIV
11793
- }, key, data);
11794
- case DecrypterAesMode.ctr:
11795
- return this.subtle.decrypt({
11796
- name: 'AES-CTR',
11797
- counter: this.aesIV,
11798
- length: 64
11799
- },
11800
- //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
11801
- key, data);
11802
- default:
11803
- throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
11804
- }
11728
+ return this.subtle.decrypt({
11729
+ name: 'AES-CBC',
11730
+ iv: this.aesIV
11731
+ }, key, data);
11805
11732
  };
11806
11733
  return AESCrypto;
11807
11734
  }();
11808
11735
 
11809
11736
  var FastAESKey = /*#__PURE__*/function () {
11810
- function FastAESKey(subtle, key, aesMode) {
11737
+ function FastAESKey(subtle, key) {
11811
11738
  this.subtle = void 0;
11812
11739
  this.key = void 0;
11813
- this.aesMode = void 0;
11814
11740
  this.subtle = subtle;
11815
11741
  this.key = key;
11816
- this.aesMode = aesMode;
11817
11742
  }
11818
11743
  var _proto = FastAESKey.prototype;
11819
11744
  _proto.expandKey = function expandKey() {
11820
- var subtleAlgoName = getSubtleAlgoName(this.aesMode);
11821
11745
  return this.subtle.importKey('raw', this.key, {
11822
- name: subtleAlgoName
11746
+ name: 'AES-CBC'
11823
11747
  }, false, ['encrypt', 'decrypt']);
11824
11748
  };
11825
11749
  return FastAESKey;
11826
11750
  }();
11827
- function getSubtleAlgoName(aesMode) {
11828
- switch (aesMode) {
11829
- case DecrypterAesMode.cbc:
11830
- return 'AES-CBC';
11831
- case DecrypterAesMode.ctr:
11832
- return 'AES-CTR';
11833
- default:
11834
- throw new Error("[FastAESKey] invalid aes mode " + aesMode);
11835
- }
11836
- }
11837
11751
 
11838
11752
  // PKCS7
11839
11753
  function removePadding(array) {
@@ -12086,8 +12000,7 @@
12086
12000
  this.currentIV = null;
12087
12001
  this.currentResult = null;
12088
12002
  this.useSoftware = void 0;
12089
- this.enableSoftwareAES = void 0;
12090
- this.enableSoftwareAES = config.enableSoftwareAES;
12003
+ this.useSoftware = config.enableSoftwareAES;
12091
12004
  this.removePKCS7Padding = removePKCS7Padding;
12092
12005
  // built in decryptor expects PKCS7 padding
12093
12006
  if (removePKCS7Padding) {
@@ -12100,7 +12013,9 @@
12100
12013
  /* no-op */
12101
12014
  }
12102
12015
  }
12103
- this.useSoftware = this.subtle === null;
12016
+ if (this.subtle === null) {
12017
+ this.useSoftware = true;
12018
+ }
12104
12019
  }
12105
12020
  var _proto = Decrypter.prototype;
12106
12021
  _proto.destroy = function destroy() {
@@ -12137,11 +12052,11 @@
12137
12052
  this.softwareDecrypter = null;
12138
12053
  }
12139
12054
  };
12140
- _proto.decrypt = function decrypt(data, key, iv, aesMode) {
12055
+ _proto.decrypt = function decrypt(data, key, iv) {
12141
12056
  var _this = this;
12142
12057
  if (this.useSoftware) {
12143
12058
  return new Promise(function (resolve, reject) {
12144
- _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
12059
+ _this.softwareDecrypt(new Uint8Array(data), key, iv);
12145
12060
  var decryptResult = _this.flush();
12146
12061
  if (decryptResult) {
12147
12062
  resolve(decryptResult.buffer);
@@ -12150,20 +12065,16 @@
12150
12065
  }
12151
12066
  });
12152
12067
  }
12153
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
12068
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
12154
12069
  }
12155
12070
 
12156
12071
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
12157
12072
  // data is handled in the flush() call
12158
12073
  ;
12159
- _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
12074
+ _proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
12160
12075
  var currentIV = this.currentIV,
12161
12076
  currentResult = this.currentResult,
12162
12077
  remainderData = this.remainderData;
12163
- if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
12164
- logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
12165
- return null;
12166
- }
12167
12078
  this.logOnce('JS AES decrypt');
12168
12079
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
12169
12080
  // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
@@ -12196,12 +12107,12 @@
12196
12107
  }
12197
12108
  return result;
12198
12109
  };
12199
- _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
12110
+ _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
12200
12111
  var _this2 = this;
12201
12112
  var subtle = this.subtle;
12202
12113
  if (this.key !== key || !this.fastAesKey) {
12203
12114
  this.key = key;
12204
- this.fastAesKey = new FastAESKey(subtle, key, aesMode);
12115
+ this.fastAesKey = new FastAESKey(subtle, key);
12205
12116
  }
12206
12117
  return this.fastAesKey.expandKey().then(function (aesKey) {
12207
12118
  // decrypt using web crypto
@@ -12209,25 +12120,22 @@
12209
12120
  return Promise.reject(new Error('web crypto not initialized'));
12210
12121
  }
12211
12122
  _this2.logOnce('WebCrypto AES decrypt');
12212
- var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
12123
+ var crypto = new AESCrypto(subtle, new Uint8Array(iv));
12213
12124
  return crypto.decrypt(data.buffer, aesKey);
12214
12125
  }).catch(function (err) {
12215
12126
  logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
12216
- return _this2.onWebCryptoError(data, key, iv, aesMode);
12127
+ return _this2.onWebCryptoError(data, key, iv);
12217
12128
  });
12218
12129
  };
12219
- _proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
12220
- var enableSoftwareAES = this.enableSoftwareAES;
12221
- if (enableSoftwareAES) {
12222
- this.useSoftware = true;
12223
- this.logEnabled = true;
12224
- this.softwareDecrypt(data, key, iv, aesMode);
12225
- var decryptResult = this.flush();
12226
- if (decryptResult) {
12227
- return decryptResult.buffer;
12228
- }
12130
+ _proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
12131
+ this.useSoftware = true;
12132
+ this.logEnabled = true;
12133
+ this.softwareDecrypt(data, key, iv);
12134
+ var decryptResult = this.flush();
12135
+ if (decryptResult) {
12136
+ return decryptResult.buffer;
12229
12137
  }
12230
- throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
12138
+ throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
12231
12139
  };
12232
12140
  _proto.getValidChunk = function getValidChunk(data) {
12233
12141
  var currentChunk = data;
@@ -12281,7 +12189,7 @@
12281
12189
  _inheritsLoose(BaseStreamController, _TaskLoop);
12282
12190
  function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
12283
12191
  var _this;
12284
- _this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
12192
+ _this = _TaskLoop.call(this) || this;
12285
12193
  _this.hls = void 0;
12286
12194
  _this.fragPrevious = null;
12287
12195
  _this.fragCurrent = null;
@@ -12306,96 +12214,25 @@
12306
12214
  _this.startFragRequested = false;
12307
12215
  _this.decrypter = void 0;
12308
12216
  _this.initPTS = [];
12309
- _this.buffering = true;
12310
- _this.loadingParts = false;
12311
- _this.onMediaSeeking = function () {
12312
- var _assertThisInitialize = _assertThisInitialized(_this),
12313
- config = _assertThisInitialize.config,
12314
- fragCurrent = _assertThisInitialize.fragCurrent,
12315
- media = _assertThisInitialize.media,
12316
- mediaBuffer = _assertThisInitialize.mediaBuffer,
12317
- state = _assertThisInitialize.state;
12318
- var currentTime = media ? media.currentTime : 0;
12319
- var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12320
- _this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12321
- if (_this.state === State.ENDED) {
12322
- _this.resetLoadingState();
12323
- } else if (fragCurrent) {
12324
- // Seeking while frag load is in progress
12325
- var tolerance = config.maxFragLookUpTolerance;
12326
- var fragStartOffset = fragCurrent.start - tolerance;
12327
- var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12328
- // if seeking out of buffered range or into new one
12329
- if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12330
- var pastFragment = currentTime > fragEndOffset;
12331
- // if the seek position is outside the current fragment range
12332
- if (currentTime < fragStartOffset || pastFragment) {
12333
- if (pastFragment && fragCurrent.loader) {
12334
- _this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12335
- fragCurrent.abortRequests();
12336
- _this.resetLoadingState();
12337
- }
12338
- _this.fragPrevious = null;
12339
- }
12340
- }
12341
- }
12342
- if (media) {
12343
- // Remove gap fragments
12344
- _this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
12345
- _this.lastCurrentTime = currentTime;
12346
- if (!_this.loadingParts) {
12347
- var bufferEnd = Math.max(bufferInfo.end, currentTime);
12348
- var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
12349
- if (shouldLoadParts) {
12350
- _this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
12351
- _this.loadingParts = shouldLoadParts;
12352
- }
12353
- }
12354
- }
12355
-
12356
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12357
- if (!_this.loadedmetadata && !bufferInfo.len) {
12358
- _this.nextLoadPosition = _this.startPosition = currentTime;
12359
- }
12360
-
12361
- // Async tick to speed up processing
12362
- _this.tickImmediate();
12363
- };
12364
- _this.onMediaEnded = function () {
12365
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12366
- _this.startPosition = _this.lastCurrentTime = 0;
12367
- if (_this.playlistType === PlaylistLevelType.MAIN) {
12368
- _this.hls.trigger(Events.MEDIA_ENDED, {
12369
- stalled: false
12370
- });
12371
- }
12372
- };
12217
+ _this.onvseeking = null;
12218
+ _this.onvended = null;
12219
+ _this.logPrefix = '';
12220
+ _this.log = void 0;
12221
+ _this.warn = void 0;
12373
12222
  _this.playlistType = playlistType;
12223
+ _this.logPrefix = logPrefix;
12224
+ _this.log = logger.log.bind(logger, logPrefix + ":");
12225
+ _this.warn = logger.warn.bind(logger, logPrefix + ":");
12374
12226
  _this.hls = hls;
12375
12227
  _this.fragmentLoader = new FragmentLoader(hls.config);
12376
12228
  _this.keyLoader = keyLoader;
12377
12229
  _this.fragmentTracker = fragmentTracker;
12378
12230
  _this.config = hls.config;
12379
12231
  _this.decrypter = new Decrypter(hls.config);
12232
+ hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
12380
12233
  return _this;
12381
12234
  }
12382
12235
  var _proto = BaseStreamController.prototype;
12383
- _proto.registerListeners = function registerListeners() {
12384
- var hls = this.hls;
12385
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12386
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12387
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12388
- hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12389
- hls.on(Events.ERROR, this.onError, this);
12390
- };
12391
- _proto.unregisterListeners = function unregisterListeners() {
12392
- var hls = this.hls;
12393
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12394
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12395
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12396
- hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12397
- hls.off(Events.ERROR, this.onError, this);
12398
- };
12399
12236
  _proto.doTick = function doTick() {
12400
12237
  this.onTickEnd();
12401
12238
  };
@@ -12419,12 +12256,6 @@
12419
12256
  this.clearNextTick();
12420
12257
  this.state = State.STOPPED;
12421
12258
  };
12422
- _proto.pauseBuffering = function pauseBuffering() {
12423
- this.buffering = false;
12424
- };
12425
- _proto.resumeBuffering = function resumeBuffering() {
12426
- this.buffering = true;
12427
- };
12428
12259
  _proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
12429
12260
  // If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
12430
12261
  // of nothing loading/loaded return false
@@ -12455,8 +12286,10 @@
12455
12286
  };
12456
12287
  _proto.onMediaAttached = function onMediaAttached(event, data) {
12457
12288
  var media = this.media = this.mediaBuffer = data.media;
12458
- media.addEventListener('seeking', this.onMediaSeeking);
12459
- media.addEventListener('ended', this.onMediaEnded);
12289
+ this.onvseeking = this.onMediaSeeking.bind(this);
12290
+ this.onvended = this.onMediaEnded.bind(this);
12291
+ media.addEventListener('seeking', this.onvseeking);
12292
+ media.addEventListener('ended', this.onvended);
12460
12293
  var config = this.config;
12461
12294
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12462
12295
  this.startLoad(config.startPosition);
@@ -12470,9 +12303,10 @@
12470
12303
  }
12471
12304
 
12472
12305
  // remove video listeners
12473
- if (media) {
12474
- media.removeEventListener('seeking', this.onMediaSeeking);
12475
- media.removeEventListener('ended', this.onMediaEnded);
12306
+ if (media && this.onvseeking && this.onvended) {
12307
+ media.removeEventListener('seeking', this.onvseeking);
12308
+ media.removeEventListener('ended', this.onvended);
12309
+ this.onvseeking = this.onvended = null;
12476
12310
  }
12477
12311
  if (this.keyLoader) {
12478
12312
  this.keyLoader.detach();
@@ -12482,8 +12316,54 @@
12482
12316
  this.fragmentTracker.removeAllFragments();
12483
12317
  this.stopLoad();
12484
12318
  };
12485
- _proto.onManifestLoading = function onManifestLoading() {};
12486
- _proto.onError = function onError(event, data) {};
12319
+ _proto.onMediaSeeking = function onMediaSeeking() {
12320
+ var config = this.config,
12321
+ fragCurrent = this.fragCurrent,
12322
+ media = this.media,
12323
+ mediaBuffer = this.mediaBuffer,
12324
+ state = this.state;
12325
+ var currentTime = media ? media.currentTime : 0;
12326
+ var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12327
+ this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12328
+ if (this.state === State.ENDED) {
12329
+ this.resetLoadingState();
12330
+ } else if (fragCurrent) {
12331
+ // Seeking while frag load is in progress
12332
+ var tolerance = config.maxFragLookUpTolerance;
12333
+ var fragStartOffset = fragCurrent.start - tolerance;
12334
+ var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12335
+ // if seeking out of buffered range or into new one
12336
+ if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12337
+ var pastFragment = currentTime > fragEndOffset;
12338
+ // if the seek position is outside the current fragment range
12339
+ if (currentTime < fragStartOffset || pastFragment) {
12340
+ if (pastFragment && fragCurrent.loader) {
12341
+ this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12342
+ fragCurrent.abortRequests();
12343
+ this.resetLoadingState();
12344
+ }
12345
+ this.fragPrevious = null;
12346
+ }
12347
+ }
12348
+ }
12349
+ if (media) {
12350
+ // Remove gap fragments
12351
+ this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
12352
+ this.lastCurrentTime = currentTime;
12353
+ }
12354
+
12355
+ // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12356
+ if (!this.loadedmetadata && !bufferInfo.len) {
12357
+ this.nextLoadPosition = this.startPosition = currentTime;
12358
+ }
12359
+
12360
+ // Async tick to speed up processing
12361
+ this.tickImmediate();
12362
+ };
12363
+ _proto.onMediaEnded = function onMediaEnded() {
12364
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12365
+ this.startPosition = this.lastCurrentTime = 0;
12366
+ };
12487
12367
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
12488
12368
  this.startTimeOffset = data.startTimeOffset;
12489
12369
  this.initPTS = [];
@@ -12493,7 +12373,7 @@
12493
12373
  this.stopLoad();
12494
12374
  _TaskLoop.prototype.onHandlerDestroying.call(this);
12495
12375
  // @ts-ignore
12496
- this.hls = this.onMediaSeeking = this.onMediaEnded = null;
12376
+ this.hls = null;
12497
12377
  };
12498
12378
  _proto.onHandlerDestroyed = function onHandlerDestroyed() {
12499
12379
  this.state = State.STOPPED;
@@ -12623,10 +12503,10 @@
12623
12503
  var decryptData = frag.decryptdata;
12624
12504
 
12625
12505
  // check to see if the payload needs to be decrypted
12626
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
12506
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
12627
12507
  var startTime = self.performance.now();
12628
12508
  // decrypt init segment data
12629
- return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
12509
+ return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
12630
12510
  hls.trigger(Events.ERROR, {
12631
12511
  type: ErrorTypes.MEDIA_ERROR,
12632
12512
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -12739,7 +12619,7 @@
12739
12619
  }
12740
12620
  var keyLoadingPromise = null;
12741
12621
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
12742
- this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
12622
+ this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + " " + frag.level);
12743
12623
  this.state = State.KEY_LOADING;
12744
12624
  this.fragCurrent = frag;
12745
12625
  keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
@@ -12760,16 +12640,8 @@
12760
12640
  } else if (!frag.encrypted && details.encryptedFragments.length) {
12761
12641
  this.keyLoader.loadClear(frag, details.encryptedFragments);
12762
12642
  }
12763
- var fragPrevious = this.fragPrevious;
12764
- if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
12765
- var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
12766
- if (shouldLoadParts !== this.loadingParts) {
12767
- this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
12768
- this.loadingParts = shouldLoadParts;
12769
- }
12770
- }
12771
12643
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
12772
- if (this.loadingParts && frag.sn !== 'initSegment') {
12644
+ if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
12773
12645
  var partList = details.partList;
12774
12646
  if (partList && progressCallback) {
12775
12647
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -12778,7 +12650,7 @@
12778
12650
  var partIndex = this.getNextPart(partList, frag, targetBufferTime);
12779
12651
  if (partIndex > -1) {
12780
12652
  var part = partList[partIndex];
12781
- 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)));
12653
+ 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)));
12782
12654
  this.nextLoadPosition = part.start + part.duration;
12783
12655
  this.state = State.FRAG_LOADING;
12784
12656
  var _result;
@@ -12811,14 +12683,7 @@
12811
12683
  }
12812
12684
  }
12813
12685
  }
12814
- if (frag.sn !== 'initSegment' && this.loadingParts) {
12815
- this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
12816
- this.loadingParts = false;
12817
- } else if (!frag.url) {
12818
- // Selected fragment hint for part but not loading parts
12819
- return Promise.resolve(null);
12820
- }
12821
- 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)));
12686
+ 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)));
12822
12687
  // Don't update nextLoadPosition for fragments which are not buffered
12823
12688
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
12824
12689
  this.nextLoadPosition = frag.start + frag.duration;
@@ -12920,36 +12785,8 @@
12920
12785
  if (part) {
12921
12786
  part.stats.parsing.end = now;
12922
12787
  }
12923
- // See if part loading should be disabled/enabled based on buffer and playback position.
12924
- if (frag.sn !== 'initSegment') {
12925
- var levelDetails = this.getLevelDetails();
12926
- var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
12927
- var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
12928
- if (shouldLoadParts !== this.loadingParts) {
12929
- this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
12930
- this.loadingParts = shouldLoadParts;
12931
- }
12932
- }
12933
12788
  this.updateLevelTiming(frag, part, level, chunkMeta.partial);
12934
12789
  };
12935
- _proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
12936
- if (this.config.lowLatencyMode) {
12937
- if (!details) {
12938
- return this.loadingParts;
12939
- }
12940
- if (details != null && details.partList) {
12941
- var _details$fragmentHint;
12942
- // Buffer must be ahead of first part + duration of parts after last segment
12943
- // and playback must be at or past segment adjacent to part list
12944
- var firstPart = details.partList[0];
12945
- var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
12946
- if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
12947
- return true;
12948
- }
12949
- }
12950
- }
12951
- return false;
12952
- };
12953
12790
  _proto.getCurrentContext = function getCurrentContext(chunkMeta) {
12954
12791
  var levels = this.levels,
12955
12792
  fragCurrent = this.fragCurrent;
@@ -13084,8 +12921,7 @@
13084
12921
  // find fragment index, contiguous with end of buffer position
13085
12922
  var config = this.config;
13086
12923
  var start = fragments[0].start;
13087
- var canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
13088
- var frag = null;
12924
+ var frag;
13089
12925
  if (levelDetails.live) {
13090
12926
  var initialLiveManifestSize = config.initialLiveManifestSize;
13091
12927
  if (fragLen < initialLiveManifestSize) {
@@ -13097,10 +12933,6 @@
13097
12933
  // Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
13098
12934
  // we get the fragment matching that start time
13099
12935
  if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
13100
- if (canLoadParts && !this.loadingParts) {
13101
- this.log("LL-Part loading ON for initial live fragment");
13102
- this.loadingParts = true;
13103
- }
13104
12936
  frag = this.getInitialLiveFragment(levelDetails, fragments);
13105
12937
  this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
13106
12938
  }
@@ -13111,7 +12943,7 @@
13111
12943
 
13112
12944
  // If we haven't run into any special cases already, just load the fragment most closely matching the requested position
13113
12945
  if (!frag) {
13114
- var end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
12946
+ var end = config.lowLatencyMode ? levelDetails.partEnd : levelDetails.fragmentEnd;
13115
12947
  frag = this.getFragmentAtPosition(pos, end, levelDetails);
13116
12948
  }
13117
12949
  return this.mapToInitFragWhenRequired(frag);
@@ -13225,7 +13057,7 @@
13225
13057
  var fragmentHint = levelDetails.fragmentHint;
13226
13058
  var tolerance = config.maxFragLookUpTolerance;
13227
13059
  var partList = levelDetails.partList;
13228
- var loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
13060
+ var loadingParts = !!(config.lowLatencyMode && partList != null && partList.length && fragmentHint);
13229
13061
  if (loadingParts && fragmentHint && !this.bitrateTest) {
13230
13062
  // Include incomplete fragment with parts at end
13231
13063
  fragments = fragments.concat(fragmentHint);
@@ -13412,7 +13244,7 @@
13412
13244
  errorAction.resolved = true;
13413
13245
  }
13414
13246
  } else {
13415
- this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13247
+ logger.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13416
13248
  return;
13417
13249
  }
13418
13250
  } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
@@ -13802,7 +13634,6 @@
13802
13634
  */
13803
13635
  function getAudioConfig(observer, data, offset, audioCodec) {
13804
13636
  var adtsObjectType;
13805
- var originalAdtsObjectType;
13806
13637
  var adtsExtensionSamplingIndex;
13807
13638
  var adtsChannelConfig;
13808
13639
  var config;
@@ -13810,7 +13641,7 @@
13810
13641
  var manifestCodec = audioCodec;
13811
13642
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
13812
13643
  // byte 2
13813
- adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13644
+ adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13814
13645
  var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
13815
13646
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
13816
13647
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
@@ -13827,8 +13658,8 @@
13827
13658
  // byte 3
13828
13659
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
13829
13660
  logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
13830
- // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
13831
- if (/firefox|palemoon/i.test(userAgent)) {
13661
+ // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
13662
+ if (/firefox/i.test(userAgent)) {
13832
13663
  if (adtsSamplingIndex >= 6) {
13833
13664
  adtsObjectType = 5;
13834
13665
  config = new Array(4);
@@ -13922,7 +13753,6 @@
13922
13753
  samplerate: adtsSamplingRates[adtsSamplingIndex],
13923
13754
  channelCount: adtsChannelConfig,
13924
13755
  codec: 'mp4a.40.' + adtsObjectType,
13925
- parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
13926
13756
  manifestCodec: manifestCodec
13927
13757
  };
13928
13758
  }
@@ -13977,8 +13807,7 @@
13977
13807
  track.channelCount = config.channelCount;
13978
13808
  track.codec = config.codec;
13979
13809
  track.manifestCodec = config.manifestCodec;
13980
- track.parsedCodec = config.parsedCodec;
13981
- logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13810
+ logger.log("parsed codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13982
13811
  }
13983
13812
  }
13984
13813
  function getFrameDuration(samplerate) {
@@ -14458,110 +14287,6 @@
14458
14287
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
14459
14288
  }
14460
14289
  };
14461
- _proto.parseNALu = function parseNALu(track, array) {
14462
- var len = array.byteLength;
14463
- var state = track.naluState || 0;
14464
- var lastState = state;
14465
- var units = [];
14466
- var i = 0;
14467
- var value;
14468
- var overflow;
14469
- var unitType;
14470
- var lastUnitStart = -1;
14471
- var lastUnitType = 0;
14472
- // logger.log('PES:' + Hex.hexDump(array));
14473
-
14474
- if (state === -1) {
14475
- // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14476
- lastUnitStart = 0;
14477
- // NALu type is value read from offset 0
14478
- lastUnitType = this.getNALuType(array, 0);
14479
- state = 0;
14480
- i = 1;
14481
- }
14482
- while (i < len) {
14483
- value = array[i++];
14484
- // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14485
- if (!state) {
14486
- state = value ? 0 : 1;
14487
- continue;
14488
- }
14489
- if (state === 1) {
14490
- state = value ? 0 : 2;
14491
- continue;
14492
- }
14493
- // here we have state either equal to 2 or 3
14494
- if (!value) {
14495
- state = 3;
14496
- } else if (value === 1) {
14497
- overflow = i - state - 1;
14498
- if (lastUnitStart >= 0) {
14499
- var unit = {
14500
- data: array.subarray(lastUnitStart, overflow),
14501
- type: lastUnitType
14502
- };
14503
- // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14504
- units.push(unit);
14505
- } else {
14506
- // lastUnitStart is undefined => this is the first start code found in this PES packet
14507
- // first check if start code delimiter is overlapping between 2 PES packets,
14508
- // ie it started in last packet (lastState not zero)
14509
- // and ended at the beginning of this PES packet (i <= 4 - lastState)
14510
- var lastUnit = this.getLastNalUnit(track.samples);
14511
- if (lastUnit) {
14512
- if (lastState && i <= 4 - lastState) {
14513
- // start delimiter overlapping between PES packets
14514
- // strip start delimiter bytes from the end of last NAL unit
14515
- // check if lastUnit had a state different from zero
14516
- if (lastUnit.state) {
14517
- // strip last bytes
14518
- lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
14519
- }
14520
- }
14521
- // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
14522
-
14523
- if (overflow > 0) {
14524
- // logger.log('first NALU found with overflow:' + overflow);
14525
- lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14526
- lastUnit.state = 0;
14527
- }
14528
- }
14529
- }
14530
- // check if we can read unit type
14531
- if (i < len) {
14532
- unitType = this.getNALuType(array, i);
14533
- // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14534
- lastUnitStart = i;
14535
- lastUnitType = unitType;
14536
- state = 0;
14537
- } else {
14538
- // not enough byte to read unit type. let's read it on next PES parsing
14539
- state = -1;
14540
- }
14541
- } else {
14542
- state = 0;
14543
- }
14544
- }
14545
- if (lastUnitStart >= 0 && state >= 0) {
14546
- var _unit = {
14547
- data: array.subarray(lastUnitStart, len),
14548
- type: lastUnitType,
14549
- state: state
14550
- };
14551
- units.push(_unit);
14552
- // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14553
- }
14554
- // no NALu found
14555
- if (units.length === 0) {
14556
- // append pes.data to previous NAL unit
14557
- var _lastUnit = this.getLastNalUnit(track.samples);
14558
- if (_lastUnit) {
14559
- _lastUnit.data = appendUint8Array(_lastUnit.data, array);
14560
- }
14561
- }
14562
- track.naluState = state;
14563
- return units;
14564
- };
14565
14290
  return BaseVideoParser;
14566
14291
  }();
14567
14292
 
@@ -14716,6 +14441,189 @@
14716
14441
  ;
14717
14442
  _proto.readUInt = function readUInt() {
14718
14443
  return this.readBits(32);
14444
+ }
14445
+
14446
+ /**
14447
+ * Advance the ExpGolomb decoder past a scaling list. The scaling
14448
+ * list is optionally transmitted as part of a sequence parameter
14449
+ * set and is not relevant to transmuxing.
14450
+ * @param count the number of entries in this scaling list
14451
+ * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
14452
+ */;
14453
+ _proto.skipScalingList = function skipScalingList(count) {
14454
+ var lastScale = 8;
14455
+ var nextScale = 8;
14456
+ var deltaScale;
14457
+ for (var j = 0; j < count; j++) {
14458
+ if (nextScale !== 0) {
14459
+ deltaScale = this.readEG();
14460
+ nextScale = (lastScale + deltaScale + 256) % 256;
14461
+ }
14462
+ lastScale = nextScale === 0 ? lastScale : nextScale;
14463
+ }
14464
+ }
14465
+
14466
+ /**
14467
+ * Read a sequence parameter set and return some interesting video
14468
+ * properties. A sequence parameter set is the H264 metadata that
14469
+ * describes the properties of upcoming video frames.
14470
+ * @returns an object with configuration parsed from the
14471
+ * sequence parameter set, including the dimensions of the
14472
+ * associated video frames.
14473
+ */;
14474
+ _proto.readSPS = function readSPS() {
14475
+ var frameCropLeftOffset = 0;
14476
+ var frameCropRightOffset = 0;
14477
+ var frameCropTopOffset = 0;
14478
+ var frameCropBottomOffset = 0;
14479
+ var numRefFramesInPicOrderCntCycle;
14480
+ var scalingListCount;
14481
+ var i;
14482
+ var readUByte = this.readUByte.bind(this);
14483
+ var readBits = this.readBits.bind(this);
14484
+ var readUEG = this.readUEG.bind(this);
14485
+ var readBoolean = this.readBoolean.bind(this);
14486
+ var skipBits = this.skipBits.bind(this);
14487
+ var skipEG = this.skipEG.bind(this);
14488
+ var skipUEG = this.skipUEG.bind(this);
14489
+ var skipScalingList = this.skipScalingList.bind(this);
14490
+ readUByte();
14491
+ var profileIdc = readUByte(); // profile_idc
14492
+ readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
14493
+ skipBits(3); // reserved_zero_3bits u(3),
14494
+ readUByte(); // level_idc u(8)
14495
+ skipUEG(); // seq_parameter_set_id
14496
+ // some profiles have more optional data we don't need
14497
+ if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
14498
+ var chromaFormatIdc = readUEG();
14499
+ if (chromaFormatIdc === 3) {
14500
+ skipBits(1);
14501
+ } // separate_colour_plane_flag
14502
+
14503
+ skipUEG(); // bit_depth_luma_minus8
14504
+ skipUEG(); // bit_depth_chroma_minus8
14505
+ skipBits(1); // qpprime_y_zero_transform_bypass_flag
14506
+ if (readBoolean()) {
14507
+ // seq_scaling_matrix_present_flag
14508
+ scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
14509
+ for (i = 0; i < scalingListCount; i++) {
14510
+ if (readBoolean()) {
14511
+ // seq_scaling_list_present_flag[ i ]
14512
+ if (i < 6) {
14513
+ skipScalingList(16);
14514
+ } else {
14515
+ skipScalingList(64);
14516
+ }
14517
+ }
14518
+ }
14519
+ }
14520
+ }
14521
+ skipUEG(); // log2_max_frame_num_minus4
14522
+ var picOrderCntType = readUEG();
14523
+ if (picOrderCntType === 0) {
14524
+ readUEG(); // log2_max_pic_order_cnt_lsb_minus4
14525
+ } else if (picOrderCntType === 1) {
14526
+ skipBits(1); // delta_pic_order_always_zero_flag
14527
+ skipEG(); // offset_for_non_ref_pic
14528
+ skipEG(); // offset_for_top_to_bottom_field
14529
+ numRefFramesInPicOrderCntCycle = readUEG();
14530
+ for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
14531
+ skipEG();
14532
+ } // offset_for_ref_frame[ i ]
14533
+ }
14534
+ skipUEG(); // max_num_ref_frames
14535
+ skipBits(1); // gaps_in_frame_num_value_allowed_flag
14536
+ var picWidthInMbsMinus1 = readUEG();
14537
+ var picHeightInMapUnitsMinus1 = readUEG();
14538
+ var frameMbsOnlyFlag = readBits(1);
14539
+ if (frameMbsOnlyFlag === 0) {
14540
+ skipBits(1);
14541
+ } // mb_adaptive_frame_field_flag
14542
+
14543
+ skipBits(1); // direct_8x8_inference_flag
14544
+ if (readBoolean()) {
14545
+ // frame_cropping_flag
14546
+ frameCropLeftOffset = readUEG();
14547
+ frameCropRightOffset = readUEG();
14548
+ frameCropTopOffset = readUEG();
14549
+ frameCropBottomOffset = readUEG();
14550
+ }
14551
+ var pixelRatio = [1, 1];
14552
+ if (readBoolean()) {
14553
+ // vui_parameters_present_flag
14554
+ if (readBoolean()) {
14555
+ // aspect_ratio_info_present_flag
14556
+ var aspectRatioIdc = readUByte();
14557
+ switch (aspectRatioIdc) {
14558
+ case 1:
14559
+ pixelRatio = [1, 1];
14560
+ break;
14561
+ case 2:
14562
+ pixelRatio = [12, 11];
14563
+ break;
14564
+ case 3:
14565
+ pixelRatio = [10, 11];
14566
+ break;
14567
+ case 4:
14568
+ pixelRatio = [16, 11];
14569
+ break;
14570
+ case 5:
14571
+ pixelRatio = [40, 33];
14572
+ break;
14573
+ case 6:
14574
+ pixelRatio = [24, 11];
14575
+ break;
14576
+ case 7:
14577
+ pixelRatio = [20, 11];
14578
+ break;
14579
+ case 8:
14580
+ pixelRatio = [32, 11];
14581
+ break;
14582
+ case 9:
14583
+ pixelRatio = [80, 33];
14584
+ break;
14585
+ case 10:
14586
+ pixelRatio = [18, 11];
14587
+ break;
14588
+ case 11:
14589
+ pixelRatio = [15, 11];
14590
+ break;
14591
+ case 12:
14592
+ pixelRatio = [64, 33];
14593
+ break;
14594
+ case 13:
14595
+ pixelRatio = [160, 99];
14596
+ break;
14597
+ case 14:
14598
+ pixelRatio = [4, 3];
14599
+ break;
14600
+ case 15:
14601
+ pixelRatio = [3, 2];
14602
+ break;
14603
+ case 16:
14604
+ pixelRatio = [2, 1];
14605
+ break;
14606
+ case 255:
14607
+ {
14608
+ pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
14609
+ break;
14610
+ }
14611
+ }
14612
+ }
14613
+ }
14614
+ return {
14615
+ width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
14616
+ height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
14617
+ pixelRatio: pixelRatio
14618
+ };
14619
+ };
14620
+ _proto.readSliceType = function readSliceType() {
14621
+ // skip NALu type
14622
+ this.readUByte();
14623
+ // discard first_mb_in_slice
14624
+ this.readUEG();
14625
+ // return slice_type
14626
+ return this.readUEG();
14719
14627
  };
14720
14628
  return ExpGolomb;
14721
14629
  }();
@@ -14726,9 +14634,9 @@
14726
14634
  return _BaseVideoParser.apply(this, arguments) || this;
14727
14635
  }
14728
14636
  var _proto = AvcVideoParser.prototype;
14729
- _proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
14637
+ _proto.parseAVCPES = function parseAVCPES(track, textTrack, pes, last, duration) {
14730
14638
  var _this = this;
14731
- var units = this.parseNALu(track, pes.data);
14639
+ var units = this.parseAVCNALu(track, pes.data);
14732
14640
  var VideoSample = this.VideoSample;
14733
14641
  var push;
14734
14642
  var spsfound = false;
@@ -14753,7 +14661,7 @@
14753
14661
  // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
14754
14662
  if (spsfound && data.length > 4) {
14755
14663
  // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
14756
- var sliceType = _this.readSliceType(data);
14664
+ var sliceType = new ExpGolomb(data).readSliceType();
14757
14665
  // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
14758
14666
  // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
14759
14667
  // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
@@ -14807,7 +14715,8 @@
14807
14715
  push = true;
14808
14716
  spsfound = true;
14809
14717
  var sps = unit.data;
14810
- var config = _this.readSPS(sps);
14718
+ var expGolombDecoder = new ExpGolomb(sps);
14719
+ var config = expGolombDecoder.readSPS();
14811
14720
  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]) {
14812
14721
  track.width = config.width;
14813
14722
  track.height = config.height;
@@ -14863,192 +14772,109 @@
14863
14772
  this.VideoSample = null;
14864
14773
  }
14865
14774
  };
14866
- _proto.getNALuType = function getNALuType(data, offset) {
14867
- return data[offset] & 0x1f;
14868
- };
14869
- _proto.readSliceType = function readSliceType(data) {
14870
- var eg = new ExpGolomb(data);
14871
- // skip NALu type
14872
- eg.readUByte();
14873
- // discard first_mb_in_slice
14874
- eg.readUEG();
14875
- // return slice_type
14876
- return eg.readUEG();
14877
- }
14775
+ _proto.parseAVCNALu = function parseAVCNALu(track, array) {
14776
+ var len = array.byteLength;
14777
+ var state = track.naluState || 0;
14778
+ var lastState = state;
14779
+ var units = [];
14780
+ var i = 0;
14781
+ var value;
14782
+ var overflow;
14783
+ var unitType;
14784
+ var lastUnitStart = -1;
14785
+ var lastUnitType = 0;
14786
+ // logger.log('PES:' + Hex.hexDump(array));
14878
14787
 
14879
- /**
14880
- * The scaling list is optionally transmitted as part of a sequence parameter
14881
- * set and is not relevant to transmuxing.
14882
- * @param count the number of entries in this scaling list
14883
- * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
14884
- */;
14885
- _proto.skipScalingList = function skipScalingList(count, reader) {
14886
- var lastScale = 8;
14887
- var nextScale = 8;
14888
- var deltaScale;
14889
- for (var j = 0; j < count; j++) {
14890
- if (nextScale !== 0) {
14891
- deltaScale = reader.readEG();
14892
- nextScale = (lastScale + deltaScale + 256) % 256;
14893
- }
14894
- lastScale = nextScale === 0 ? lastScale : nextScale;
14788
+ if (state === -1) {
14789
+ // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14790
+ lastUnitStart = 0;
14791
+ // NALu type is value read from offset 0
14792
+ lastUnitType = array[0] & 0x1f;
14793
+ state = 0;
14794
+ i = 1;
14895
14795
  }
14896
- }
14897
-
14898
- /**
14899
- * Read a sequence parameter set and return some interesting video
14900
- * properties. A sequence parameter set is the H264 metadata that
14901
- * describes the properties of upcoming video frames.
14902
- * @returns an object with configuration parsed from the
14903
- * sequence parameter set, including the dimensions of the
14904
- * associated video frames.
14905
- */;
14906
- _proto.readSPS = function readSPS(sps) {
14907
- var eg = new ExpGolomb(sps);
14908
- var frameCropLeftOffset = 0;
14909
- var frameCropRightOffset = 0;
14910
- var frameCropTopOffset = 0;
14911
- var frameCropBottomOffset = 0;
14912
- var numRefFramesInPicOrderCntCycle;
14913
- var scalingListCount;
14914
- var i;
14915
- var readUByte = eg.readUByte.bind(eg);
14916
- var readBits = eg.readBits.bind(eg);
14917
- var readUEG = eg.readUEG.bind(eg);
14918
- var readBoolean = eg.readBoolean.bind(eg);
14919
- var skipBits = eg.skipBits.bind(eg);
14920
- var skipEG = eg.skipEG.bind(eg);
14921
- var skipUEG = eg.skipUEG.bind(eg);
14922
- var skipScalingList = this.skipScalingList.bind(this);
14923
- readUByte();
14924
- var profileIdc = readUByte(); // profile_idc
14925
- readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
14926
- skipBits(3); // reserved_zero_3bits u(3),
14927
- readUByte(); // level_idc u(8)
14928
- skipUEG(); // seq_parameter_set_id
14929
- // some profiles have more optional data we don't need
14930
- if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
14931
- var chromaFormatIdc = readUEG();
14932
- if (chromaFormatIdc === 3) {
14933
- skipBits(1);
14934
- } // separate_colour_plane_flag
14796
+ while (i < len) {
14797
+ value = array[i++];
14798
+ // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14799
+ if (!state) {
14800
+ state = value ? 0 : 1;
14801
+ continue;
14802
+ }
14803
+ if (state === 1) {
14804
+ state = value ? 0 : 2;
14805
+ continue;
14806
+ }
14807
+ // here we have state either equal to 2 or 3
14808
+ if (!value) {
14809
+ state = 3;
14810
+ } else if (value === 1) {
14811
+ overflow = i - state - 1;
14812
+ if (lastUnitStart >= 0) {
14813
+ var unit = {
14814
+ data: array.subarray(lastUnitStart, overflow),
14815
+ type: lastUnitType
14816
+ };
14817
+ // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14818
+ units.push(unit);
14819
+ } else {
14820
+ // lastUnitStart is undefined => this is the first start code found in this PES packet
14821
+ // first check if start code delimiter is overlapping between 2 PES packets,
14822
+ // ie it started in last packet (lastState not zero)
14823
+ // and ended at the beginning of this PES packet (i <= 4 - lastState)
14824
+ var lastUnit = this.getLastNalUnit(track.samples);
14825
+ if (lastUnit) {
14826
+ if (lastState && i <= 4 - lastState) {
14827
+ // start delimiter overlapping between PES packets
14828
+ // strip start delimiter bytes from the end of last NAL unit
14829
+ // check if lastUnit had a state different from zero
14830
+ if (lastUnit.state) {
14831
+ // strip last bytes
14832
+ lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
14833
+ }
14834
+ }
14835
+ // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
14935
14836
 
14936
- skipUEG(); // bit_depth_luma_minus8
14937
- skipUEG(); // bit_depth_chroma_minus8
14938
- skipBits(1); // qpprime_y_zero_transform_bypass_flag
14939
- if (readBoolean()) {
14940
- // seq_scaling_matrix_present_flag
14941
- scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
14942
- for (i = 0; i < scalingListCount; i++) {
14943
- if (readBoolean()) {
14944
- // seq_scaling_list_present_flag[ i ]
14945
- if (i < 6) {
14946
- skipScalingList(16, eg);
14947
- } else {
14948
- skipScalingList(64, eg);
14837
+ if (overflow > 0) {
14838
+ // logger.log('first NALU found with overflow:' + overflow);
14839
+ lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14840
+ lastUnit.state = 0;
14949
14841
  }
14950
14842
  }
14951
14843
  }
14844
+ // check if we can read unit type
14845
+ if (i < len) {
14846
+ unitType = array[i] & 0x1f;
14847
+ // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14848
+ lastUnitStart = i;
14849
+ lastUnitType = unitType;
14850
+ state = 0;
14851
+ } else {
14852
+ // not enough byte to read unit type. let's read it on next PES parsing
14853
+ state = -1;
14854
+ }
14855
+ } else {
14856
+ state = 0;
14952
14857
  }
14953
14858
  }
14954
- skipUEG(); // log2_max_frame_num_minus4
14955
- var picOrderCntType = readUEG();
14956
- if (picOrderCntType === 0) {
14957
- readUEG(); // log2_max_pic_order_cnt_lsb_minus4
14958
- } else if (picOrderCntType === 1) {
14959
- skipBits(1); // delta_pic_order_always_zero_flag
14960
- skipEG(); // offset_for_non_ref_pic
14961
- skipEG(); // offset_for_top_to_bottom_field
14962
- numRefFramesInPicOrderCntCycle = readUEG();
14963
- for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
14964
- skipEG();
14965
- } // offset_for_ref_frame[ i ]
14966
- }
14967
- skipUEG(); // max_num_ref_frames
14968
- skipBits(1); // gaps_in_frame_num_value_allowed_flag
14969
- var picWidthInMbsMinus1 = readUEG();
14970
- var picHeightInMapUnitsMinus1 = readUEG();
14971
- var frameMbsOnlyFlag = readBits(1);
14972
- if (frameMbsOnlyFlag === 0) {
14973
- skipBits(1);
14974
- } // mb_adaptive_frame_field_flag
14975
-
14976
- skipBits(1); // direct_8x8_inference_flag
14977
- if (readBoolean()) {
14978
- // frame_cropping_flag
14979
- frameCropLeftOffset = readUEG();
14980
- frameCropRightOffset = readUEG();
14981
- frameCropTopOffset = readUEG();
14982
- frameCropBottomOffset = readUEG();
14859
+ if (lastUnitStart >= 0 && state >= 0) {
14860
+ var _unit = {
14861
+ data: array.subarray(lastUnitStart, len),
14862
+ type: lastUnitType,
14863
+ state: state
14864
+ };
14865
+ units.push(_unit);
14866
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14983
14867
  }
14984
- var pixelRatio = [1, 1];
14985
- if (readBoolean()) {
14986
- // vui_parameters_present_flag
14987
- if (readBoolean()) {
14988
- // aspect_ratio_info_present_flag
14989
- var aspectRatioIdc = readUByte();
14990
- switch (aspectRatioIdc) {
14991
- case 1:
14992
- pixelRatio = [1, 1];
14993
- break;
14994
- case 2:
14995
- pixelRatio = [12, 11];
14996
- break;
14997
- case 3:
14998
- pixelRatio = [10, 11];
14999
- break;
15000
- case 4:
15001
- pixelRatio = [16, 11];
15002
- break;
15003
- case 5:
15004
- pixelRatio = [40, 33];
15005
- break;
15006
- case 6:
15007
- pixelRatio = [24, 11];
15008
- break;
15009
- case 7:
15010
- pixelRatio = [20, 11];
15011
- break;
15012
- case 8:
15013
- pixelRatio = [32, 11];
15014
- break;
15015
- case 9:
15016
- pixelRatio = [80, 33];
15017
- break;
15018
- case 10:
15019
- pixelRatio = [18, 11];
15020
- break;
15021
- case 11:
15022
- pixelRatio = [15, 11];
15023
- break;
15024
- case 12:
15025
- pixelRatio = [64, 33];
15026
- break;
15027
- case 13:
15028
- pixelRatio = [160, 99];
15029
- break;
15030
- case 14:
15031
- pixelRatio = [4, 3];
15032
- break;
15033
- case 15:
15034
- pixelRatio = [3, 2];
15035
- break;
15036
- case 16:
15037
- pixelRatio = [2, 1];
15038
- break;
15039
- case 255:
15040
- {
15041
- pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
15042
- break;
15043
- }
15044
- }
14868
+ // no NALu found
14869
+ if (units.length === 0) {
14870
+ // append pes.data to previous NAL unit
14871
+ var _lastUnit = this.getLastNalUnit(track.samples);
14872
+ if (_lastUnit) {
14873
+ _lastUnit.data = appendUint8Array(_lastUnit.data, array);
15045
14874
  }
15046
14875
  }
15047
- return {
15048
- width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
15049
- height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
15050
- pixelRatio: pixelRatio
15051
- };
14876
+ track.naluState = state;
14877
+ return units;
15052
14878
  };
15053
14879
  return AvcVideoParser;
15054
14880
  }(BaseVideoParser);
@@ -15068,7 +14894,7 @@
15068
14894
  }
15069
14895
  var _proto = SampleAesDecrypter.prototype;
15070
14896
  _proto.decryptBuffer = function decryptBuffer(encryptedData) {
15071
- return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
14897
+ return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
15072
14898
  }
15073
14899
 
15074
14900
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -15187,7 +15013,7 @@
15187
15013
  this.observer = observer;
15188
15014
  this.config = config;
15189
15015
  this.typeSupported = typeSupported;
15190
- this.videoParser = null;
15016
+ this.videoParser = new AvcVideoParser();
15191
15017
  }
15192
15018
  TSDemuxer.probe = function probe(data) {
15193
15019
  var syncOffset = TSDemuxer.syncOffset(data);
@@ -15357,16 +15183,7 @@
15357
15183
  case videoPid:
15358
15184
  if (stt) {
15359
15185
  if (videoData && (pes = parsePES(videoData))) {
15360
- if (this.videoParser === null) {
15361
- switch (videoTrack.segmentCodec) {
15362
- case 'avc':
15363
- this.videoParser = new AvcVideoParser();
15364
- break;
15365
- }
15366
- }
15367
- if (this.videoParser !== null) {
15368
- this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
15369
- }
15186
+ this.videoParser.parseAVCPES(videoTrack, textTrack, pes, false, this._duration);
15370
15187
  }
15371
15188
  videoData = {
15372
15189
  data: [],
@@ -15524,17 +15341,8 @@
15524
15341
  // try to parse last PES packets
15525
15342
  var pes;
15526
15343
  if (videoData && (pes = parsePES(videoData))) {
15527
- if (this.videoParser === null) {
15528
- switch (videoTrack.segmentCodec) {
15529
- case 'avc':
15530
- this.videoParser = new AvcVideoParser();
15531
- break;
15532
- }
15533
- }
15534
- if (this.videoParser !== null) {
15535
- this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
15536
- videoTrack.pesData = null;
15537
- }
15344
+ this.videoParser.parseAVCPES(videoTrack, textTrack, pes, true, this._duration);
15345
+ videoTrack.pesData = null;
15538
15346
  } else {
15539
15347
  // either avcData null or PES truncated, keep it for next frag parsing
15540
15348
  videoTrack.pesData = videoData;
@@ -15836,10 +15644,7 @@
15836
15644
  logger.warn('Unsupported EC-3 in M2TS found');
15837
15645
  break;
15838
15646
  case 0x24:
15839
- // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
15840
- {
15841
- logger.warn('Unsupported HEVC in M2TS found');
15842
- }
15647
+ logger.warn('Unsupported HEVC in M2TS found');
15843
15648
  break;
15844
15649
  }
15845
15650
  // move to the next table entry
@@ -16067,8 +15872,6 @@
16067
15872
  avc1: [],
16068
15873
  // codingname
16069
15874
  avcC: [],
16070
- hvc1: [],
16071
- hvcC: [],
16072
15875
  btrt: [],
16073
15876
  dinf: [],
16074
15877
  dref: [],
@@ -16496,10 +16299,8 @@
16496
16299
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
16497
16300
  }
16498
16301
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
16499
- } else if (track.segmentCodec === 'avc') {
16500
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
16501
16302
  } else {
16502
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
16303
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
16503
16304
  }
16504
16305
  };
16505
16306
  MP4.tkhd = function tkhd(track) {
@@ -16637,84 +16438,6 @@
16637
16438
  var result = appendUint8Array(MP4.FTYP, movie);
16638
16439
  return result;
16639
16440
  };
16640
- MP4.hvc1 = function hvc1(track) {
16641
- var ps = track.params;
16642
- var units = [track.vps, track.sps, track.pps];
16643
- var NALuLengthSize = 4;
16644
- 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]);
16645
-
16646
- // compute hvcC size in bytes
16647
- var length = config.length;
16648
- for (var i = 0; i < units.length; i += 1) {
16649
- length += 3;
16650
- for (var j = 0; j < units[i].length; j += 1) {
16651
- length += 2 + units[i][j].length;
16652
- }
16653
- }
16654
- var hvcC = new Uint8Array(length);
16655
- hvcC.set(config, 0);
16656
- length = config.length;
16657
- // append parameter set units: one vps, one or more sps and pps
16658
- var iMax = units.length - 1;
16659
- for (var _i = 0; _i < units.length; _i += 1) {
16660
- hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
16661
- length += 3;
16662
- for (var _j = 0; _j < units[_i].length; _j += 1) {
16663
- hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
16664
- length += 2;
16665
- hvcC.set(units[_i][_j], length);
16666
- length += units[_i][_j].length;
16667
- }
16668
- }
16669
- var hvcc = MP4.box(MP4.types.hvcC, hvcC);
16670
- var width = track.width;
16671
- var height = track.height;
16672
- var hSpacing = track.pixelRatio[0];
16673
- var vSpacing = track.pixelRatio[1];
16674
- return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
16675
- // reserved
16676
- 0x00, 0x00, 0x00,
16677
- // reserved
16678
- 0x00, 0x01,
16679
- // data_reference_index
16680
- 0x00, 0x00,
16681
- // pre_defined
16682
- 0x00, 0x00,
16683
- // reserved
16684
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16685
- // pre_defined
16686
- width >> 8 & 0xff, width & 0xff,
16687
- // width
16688
- height >> 8 & 0xff, height & 0xff,
16689
- // height
16690
- 0x00, 0x48, 0x00, 0x00,
16691
- // horizresolution
16692
- 0x00, 0x48, 0x00, 0x00,
16693
- // vertresolution
16694
- 0x00, 0x00, 0x00, 0x00,
16695
- // reserved
16696
- 0x00, 0x01,
16697
- // frame_count
16698
- 0x12, 0x64, 0x61, 0x69, 0x6c,
16699
- // dailymotion/hls.js
16700
- 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,
16701
- // compressorname
16702
- 0x00, 0x18,
16703
- // depth = 24
16704
- 0x11, 0x11]),
16705
- // pre_defined = -1
16706
- hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
16707
- // bufferSizeDB
16708
- 0x00, 0x2d, 0xc6, 0xc0,
16709
- // maxBitrate
16710
- 0x00, 0x2d, 0xc6, 0xc0])),
16711
- // avgBitrate
16712
- MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
16713
- // hSpacing
16714
- hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
16715
- // vSpacing
16716
- vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
16717
- };
16718
16441
  return MP4;
16719
16442
  }();
16720
16443
  MP4.types = void 0;
@@ -17101,9 +16824,9 @@
17101
16824
  var foundOverlap = delta < -1;
17102
16825
  if (foundHole || foundOverlap) {
17103
16826
  if (foundHole) {
17104
- logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
16827
+ logger.warn("AVC: " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
17105
16828
  } else {
17106
- logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
16829
+ logger.warn("AVC: " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
17107
16830
  }
17108
16831
  if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
17109
16832
  firstDTS = nextAvcDts;
@@ -17112,24 +16835,12 @@
17112
16835
  inputSamples[0].dts = firstDTS;
17113
16836
  inputSamples[0].pts = firstPTS;
17114
16837
  } else {
17115
- var isPTSOrderRetained = true;
17116
16838
  for (var _i = 0; _i < inputSamples.length; _i++) {
17117
- if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
16839
+ if (inputSamples[_i].dts > firstPTS) {
17118
16840
  break;
17119
16841
  }
17120
- var prevPTS = inputSamples[_i].pts;
17121
16842
  inputSamples[_i].dts -= delta;
17122
16843
  inputSamples[_i].pts -= delta;
17123
-
17124
- // check to see if this sample's PTS order has changed
17125
- // relative to the next one
17126
- if (_i < inputSamples.length - 1) {
17127
- var nextSamplePTS = inputSamples[_i + 1].pts;
17128
- var currentSamplePTS = inputSamples[_i].pts;
17129
- var currentOrder = nextSamplePTS <= currentSamplePTS;
17130
- var prevOrder = nextSamplePTS <= prevPTS;
17131
- isPTSOrderRetained = currentOrder == prevOrder;
17132
- }
17133
16844
  }
17134
16845
  }
17135
16846
  logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
@@ -17277,7 +16988,7 @@
17277
16988
  }
17278
16989
  }
17279
16990
  }
17280
- // next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
16991
+ // next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
17281
16992
  mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
17282
16993
  this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
17283
16994
  this.videoSampleDuration = mp4SampleDuration;
@@ -17412,7 +17123,7 @@
17412
17123
  logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
17413
17124
  for (var j = 0; j < missing; j++) {
17414
17125
  var newStamp = Math.max(nextPts, 0);
17415
- var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17126
+ var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17416
17127
  if (!fillFrame) {
17417
17128
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17418
17129
  fillFrame = sample.unit.subarray();
@@ -17540,7 +17251,7 @@
17540
17251
  // samples count of this segment's duration
17541
17252
  var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
17542
17253
  // silent frame
17543
- var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17254
+ var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17544
17255
  logger.warn('[mp4-remuxer]: remux empty Audio');
17545
17256
  // Can't remux if we can't generate a silent frame...
17546
17257
  if (!silentFrame) {
@@ -17927,15 +17638,13 @@
17927
17638
  duration = transmuxConfig.duration,
17928
17639
  initSegmentData = transmuxConfig.initSegmentData;
17929
17640
  var keyData = getEncryptionType(uintData, decryptdata);
17930
- if (keyData && isFullSegmentEncryption(keyData.method)) {
17641
+ if (keyData && keyData.method === 'AES-128') {
17931
17642
  var decrypter = this.getDecrypter();
17932
- var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
17933
-
17934
17643
  // Software decryption is synchronous; webCrypto is not
17935
17644
  if (decrypter.isSync()) {
17936
17645
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
17937
17646
  // data is handled in the flush() call
17938
- var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
17647
+ var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
17939
17648
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
17940
17649
  var loadingParts = chunkMeta.part > -1;
17941
17650
  if (loadingParts) {
@@ -17947,7 +17656,7 @@
17947
17656
  }
17948
17657
  uintData = new Uint8Array(decryptedData);
17949
17658
  } else {
17950
- this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
17659
+ this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
17951
17660
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
17952
17661
  // the decrypted data has been transmuxed
17953
17662
  var result = _this.push(decryptedData, null, chunkMeta);
@@ -18568,7 +18277,7 @@
18568
18277
  observer.on(Events.ERROR, forwardMessage);
18569
18278
 
18570
18279
  // forward logger events to main thread
18571
- var forwardWorkerLogs = function forwardWorkerLogs(logger) {
18280
+ var forwardWorkerLogs = function forwardWorkerLogs() {
18572
18281
  var _loop = function _loop(logFn) {
18573
18282
  var func = function func(message) {
18574
18283
  forwardMessage('workerLog', {
@@ -18589,8 +18298,8 @@
18589
18298
  {
18590
18299
  var config = JSON.parse(data.config);
18591
18300
  self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
18592
- var logger = enableLogs(config.debug, data.id);
18593
- forwardWorkerLogs(logger);
18301
+ enableLogs(config.debug, data.id);
18302
+ forwardWorkerLogs();
18594
18303
  forwardMessage('init', null);
18595
18304
  break;
18596
18305
  }
@@ -18764,7 +18473,16 @@
18764
18473
  this.observer = new EventEmitter();
18765
18474
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
18766
18475
  this.observer.on(Events.ERROR, forwardMessage);
18767
- var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
18476
+ var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
18477
+ isTypeSupported: function isTypeSupported() {
18478
+ return false;
18479
+ }
18480
+ };
18481
+ var m2tsTypeSupported = {
18482
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
18483
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
18484
+ ac3: false
18485
+ };
18768
18486
 
18769
18487
  // navigator.vendor is not always available in Web Worker
18770
18488
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -19021,26 +18739,21 @@
19021
18739
  var MAX_START_GAP_JUMP = 2.0;
19022
18740
  var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
19023
18741
  var SKIP_BUFFER_RANGE_START = 0.05;
19024
- var GapController = /*#__PURE__*/function (_Logger) {
19025
- _inheritsLoose(GapController, _Logger);
18742
+ var GapController = /*#__PURE__*/function () {
19026
18743
  function GapController(config, media, fragmentTracker, hls) {
19027
- var _this;
19028
- _this = _Logger.call(this, 'gap-controller', hls.logger) || this;
19029
- _this.config = void 0;
19030
- _this.media = null;
19031
- _this.fragmentTracker = void 0;
19032
- _this.hls = void 0;
19033
- _this.nudgeRetry = 0;
19034
- _this.stallReported = false;
19035
- _this.stalled = null;
19036
- _this.moved = false;
19037
- _this.seeking = false;
19038
- _this.ended = 0;
19039
- _this.config = config;
19040
- _this.media = media;
19041
- _this.fragmentTracker = fragmentTracker;
19042
- _this.hls = hls;
19043
- return _this;
18744
+ this.config = void 0;
18745
+ this.media = null;
18746
+ this.fragmentTracker = void 0;
18747
+ this.hls = void 0;
18748
+ this.nudgeRetry = 0;
18749
+ this.stallReported = false;
18750
+ this.stalled = null;
18751
+ this.moved = false;
18752
+ this.seeking = false;
18753
+ this.config = config;
18754
+ this.media = media;
18755
+ this.fragmentTracker = fragmentTracker;
18756
+ this.hls = hls;
19044
18757
  }
19045
18758
  var _proto = GapController.prototype;
19046
18759
  _proto.destroy = function destroy() {
@@ -19055,7 +18768,7 @@
19055
18768
  *
19056
18769
  * @param lastCurrentTime - Previously read playhead position
19057
18770
  */;
19058
- _proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
18771
+ _proto.poll = function poll(lastCurrentTime, activeFrag) {
19059
18772
  var config = this.config,
19060
18773
  media = this.media,
19061
18774
  stalled = this.stalled;
@@ -19070,7 +18783,6 @@
19070
18783
 
19071
18784
  // The playhead is moving, no-op
19072
18785
  if (currentTime !== lastCurrentTime) {
19073
- this.ended = 0;
19074
18786
  this.moved = true;
19075
18787
  if (!seeking) {
19076
18788
  this.nudgeRetry = 0;
@@ -19079,7 +18791,7 @@
19079
18791
  // The playhead is now moving, but was previously stalled
19080
18792
  if (this.stallReported) {
19081
18793
  var _stalledDuration = self.performance.now() - stalled;
19082
- this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
18794
+ logger.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
19083
18795
  this.stallReported = false;
19084
18796
  }
19085
18797
  this.stalled = null;
@@ -19115,6 +18827,7 @@
19115
18827
  // Skip start gaps if we haven't played, but the last poll detected the start of a stall
19116
18828
  // The addition poll gives the browser a chance to jump the gap for us
19117
18829
  if (!this.moved && this.stalled !== null) {
18830
+ var _level$details;
19118
18831
  // There is no playable buffer (seeked, waiting for buffer)
19119
18832
  var isBuffered = bufferInfo.len > 0;
19120
18833
  if (!isBuffered && !nextStart) {
@@ -19126,8 +18839,9 @@
19126
18839
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
19127
18840
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
19128
18841
  // that begins over 1 target duration after the video start position.
19129
- var isLive = !!(levelDetails != null && levelDetails.live);
19130
- var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
18842
+ var level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
18843
+ var isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
18844
+ var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
19131
18845
  var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
19132
18846
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
19133
18847
  if (!media.paused) {
@@ -19145,17 +18859,6 @@
19145
18859
  }
19146
18860
  var stalledDuration = tnow - stalled;
19147
18861
  if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
19148
- // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
19149
- if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
19150
- if (stalledDuration < 1000 || this.ended) {
19151
- return;
19152
- }
19153
- this.ended = currentTime;
19154
- this.hls.trigger(Events.MEDIA_ENDED, {
19155
- stalled: true
19156
- });
19157
- return;
19158
- }
19159
18862
  // Report stalling after trying to fix
19160
18863
  this._reportStall(bufferInfo);
19161
18864
  if (!this.media) {
@@ -19197,7 +18900,7 @@
19197
18900
  // needs to cross some sort of threshold covering all source-buffers content
19198
18901
  // to start playing properly.
19199
18902
  if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
19200
- this.warn('Trying to nudge playhead over buffer-hole');
18903
+ logger.warn('Trying to nudge playhead over buffer-hole');
19201
18904
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
19202
18905
  // We only try to jump the hole if it's under the configured size
19203
18906
  // Reset stalled so to rearm watchdog timer
@@ -19219,7 +18922,7 @@
19219
18922
  // Report stalled error once
19220
18923
  this.stallReported = true;
19221
18924
  var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
19222
- this.warn(error.message);
18925
+ logger.warn(error.message);
19223
18926
  hls.trigger(Events.ERROR, {
19224
18927
  type: ErrorTypes.MEDIA_ERROR,
19225
18928
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19283,7 +18986,7 @@
19283
18986
  }
19284
18987
  }
19285
18988
  var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
19286
- this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
18989
+ logger.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
19287
18990
  this.moved = true;
19288
18991
  this.stalled = null;
19289
18992
  media.currentTime = targetTime;
@@ -19322,7 +19025,7 @@
19322
19025
  var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
19323
19026
  // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
19324
19027
  var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
19325
- this.warn(error.message);
19028
+ logger.warn(error.message);
19326
19029
  media.currentTime = targetTime;
19327
19030
  hls.trigger(Events.ERROR, {
19328
19031
  type: ErrorTypes.MEDIA_ERROR,
@@ -19332,7 +19035,7 @@
19332
19035
  });
19333
19036
  } else {
19334
19037
  var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
19335
- this.error(_error.message);
19038
+ logger.error(_error.message);
19336
19039
  hls.trigger(Events.ERROR, {
19337
19040
  type: ErrorTypes.MEDIA_ERROR,
19338
19041
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19342,14 +19045,14 @@
19342
19045
  }
19343
19046
  };
19344
19047
  return GapController;
19345
- }(Logger);
19048
+ }();
19346
19049
 
19347
19050
  var TICK_INTERVAL = 100; // how often to tick in ms
19348
19051
  var StreamController = /*#__PURE__*/function (_BaseStreamController) {
19349
19052
  _inheritsLoose(StreamController, _BaseStreamController);
19350
19053
  function StreamController(hls, fragmentTracker, keyLoader) {
19351
19054
  var _this;
19352
- _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
19055
+ _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[stream-controller]', PlaylistLevelType.MAIN) || this;
19353
19056
  _this.audioCodecSwap = false;
19354
19057
  _this.gapController = null;
19355
19058
  _this.level = -1;
@@ -19357,43 +19060,27 @@
19357
19060
  _this.altAudio = false;
19358
19061
  _this.audioOnly = false;
19359
19062
  _this.fragPlaying = null;
19063
+ _this.onvplaying = null;
19064
+ _this.onvseeked = null;
19360
19065
  _this.fragLastKbps = 0;
19361
19066
  _this.couldBacktrack = false;
19362
19067
  _this.backtrackFragment = null;
19363
19068
  _this.audioCodecSwitch = false;
19364
19069
  _this.videoBuffer = null;
19365
- _this.onMediaPlaying = function () {
19366
- // tick to speed up FRAG_CHANGED triggering
19367
- _this.tick();
19368
- };
19369
- _this.onMediaSeeked = function () {
19370
- var media = _this.media;
19371
- var currentTime = media ? media.currentTime : null;
19372
- if (isFiniteNumber(currentTime)) {
19373
- _this.log("Media seeked to " + currentTime.toFixed(3));
19374
- }
19375
-
19376
- // If seeked was issued before buffer was appended do not tick immediately
19377
- var bufferInfo = _this.getMainFwdBufferInfo();
19378
- if (bufferInfo === null || bufferInfo.len === 0) {
19379
- _this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19380
- return;
19381
- }
19382
-
19383
- // tick to speed up FRAG_CHANGED triggering
19384
- _this.tick();
19385
- };
19386
- _this.registerListeners();
19070
+ _this._registerListeners();
19387
19071
  return _this;
19388
19072
  }
19389
19073
  var _proto = StreamController.prototype;
19390
- _proto.registerListeners = function registerListeners() {
19391
- _BaseStreamController.prototype.registerListeners.call(this);
19074
+ _proto._registerListeners = function _registerListeners() {
19392
19075
  var hls = this.hls;
19076
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19077
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19078
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19393
19079
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19394
19080
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
19395
19081
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19396
19082
  hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19083
+ hls.on(Events.ERROR, this.onError, this);
19397
19084
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19398
19085
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19399
19086
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19401,12 +19088,15 @@
19401
19088
  hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
19402
19089
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19403
19090
  };
19404
- _proto.unregisterListeners = function unregisterListeners() {
19405
- _BaseStreamController.prototype.unregisterListeners.call(this);
19091
+ _proto._unregisterListeners = function _unregisterListeners() {
19406
19092
  var hls = this.hls;
19093
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19094
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19095
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19407
19096
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19408
19097
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19409
19098
  hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19099
+ hls.off(Events.ERROR, this.onError, this);
19410
19100
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19411
19101
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19412
19102
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19415,9 +19105,7 @@
19415
19105
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19416
19106
  };
19417
19107
  _proto.onHandlerDestroying = function onHandlerDestroying() {
19418
- // @ts-ignore
19419
- this.onMediaPlaying = this.onMediaSeeked = null;
19420
- this.unregisterListeners();
19108
+ this._unregisterListeners();
19421
19109
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
19422
19110
  };
19423
19111
  _proto.startLoad = function startLoad(startPosition) {
@@ -19527,7 +19215,7 @@
19527
19215
  if (this.altAudio && this.audioOnly) {
19528
19216
  return;
19529
19217
  }
19530
- if (!this.buffering || !(levels != null && levels[level])) {
19218
+ if (!(levels != null && levels[level])) {
19531
19219
  return;
19532
19220
  }
19533
19221
  var levelInfo = levels[level];
@@ -19733,15 +19421,18 @@
19733
19421
  _proto.onMediaAttached = function onMediaAttached(event, data) {
19734
19422
  _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
19735
19423
  var media = data.media;
19736
- media.addEventListener('playing', this.onMediaPlaying);
19737
- media.addEventListener('seeked', this.onMediaSeeked);
19424
+ this.onvplaying = this.onMediaPlaying.bind(this);
19425
+ this.onvseeked = this.onMediaSeeked.bind(this);
19426
+ media.addEventListener('playing', this.onvplaying);
19427
+ media.addEventListener('seeked', this.onvseeked);
19738
19428
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
19739
19429
  };
19740
19430
  _proto.onMediaDetaching = function onMediaDetaching() {
19741
19431
  var media = this.media;
19742
- if (media) {
19743
- media.removeEventListener('playing', this.onMediaPlaying);
19744
- media.removeEventListener('seeked', this.onMediaSeeked);
19432
+ if (media && this.onvplaying && this.onvseeked) {
19433
+ media.removeEventListener('playing', this.onvplaying);
19434
+ media.removeEventListener('seeked', this.onvseeked);
19435
+ this.onvplaying = this.onvseeked = null;
19745
19436
  this.videoBuffer = null;
19746
19437
  }
19747
19438
  this.fragPlaying = null;
@@ -19751,6 +19442,27 @@
19751
19442
  }
19752
19443
  _BaseStreamController.prototype.onMediaDetaching.call(this);
19753
19444
  };
19445
+ _proto.onMediaPlaying = function onMediaPlaying() {
19446
+ // tick to speed up FRAG_CHANGED triggering
19447
+ this.tick();
19448
+ };
19449
+ _proto.onMediaSeeked = function onMediaSeeked() {
19450
+ var media = this.media;
19451
+ var currentTime = media ? media.currentTime : null;
19452
+ if (isFiniteNumber(currentTime)) {
19453
+ this.log("Media seeked to " + currentTime.toFixed(3));
19454
+ }
19455
+
19456
+ // If seeked was issued before buffer was appended do not tick immediately
19457
+ var bufferInfo = this.getMainFwdBufferInfo();
19458
+ if (bufferInfo === null || bufferInfo.len === 0) {
19459
+ this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19460
+ return;
19461
+ }
19462
+
19463
+ // tick to speed up FRAG_CHANGED triggering
19464
+ this.tick();
19465
+ };
19754
19466
  _proto.onManifestLoading = function onManifestLoading() {
19755
19467
  // reset buffer on manifest loading
19756
19468
  this.log('Trigger BUFFER_RESET');
@@ -20031,10 +19743,8 @@
20031
19743
  }
20032
19744
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
20033
19745
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
20034
- var state = this.state;
20035
- var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
20036
- var levelDetails = this.getLevelDetails();
20037
- gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
19746
+ var activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
19747
+ gapController.poll(this.lastCurrentTime, activeFrag);
20038
19748
  }
20039
19749
  this.lastCurrentTime = media.currentTime;
20040
19750
  };
@@ -20499,12 +20209,9 @@
20499
20209
  * The configuration object provided on player instantiation.
20500
20210
  */
20501
20211
  this.userConfig = void 0;
20502
- /**
20503
- * The logger functions used by this player instance, configured on player instantiation.
20504
- */
20505
- this.logger = void 0;
20506
20212
  this.coreComponents = void 0;
20507
20213
  this.networkControllers = void 0;
20214
+ this.started = false;
20508
20215
  this._emitter = new EventEmitter();
20509
20216
  this._autoLevelCapping = -1;
20510
20217
  this._maxHdcpLevel = null;
@@ -20521,11 +20228,11 @@
20521
20228
  this._media = null;
20522
20229
  this.url = null;
20523
20230
  this.triggeringException = void 0;
20524
- var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
20525
- var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
20231
+ enableLogs(userConfig.debug || false, 'Hls instance');
20232
+ var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
20526
20233
  this.userConfig = userConfig;
20527
20234
  if (config.progressive) {
20528
- enableStreamingMode(config, logger);
20235
+ enableStreamingMode(config);
20529
20236
  }
20530
20237
 
20531
20238
  // core controllers and network loaders
@@ -20633,7 +20340,7 @@
20633
20340
  try {
20634
20341
  return this.emit(event, event, eventObject);
20635
20342
  } catch (error) {
20636
- this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
20343
+ logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
20637
20344
  // Prevent recursion in error event handlers that throw #5497
20638
20345
  if (!this.triggeringException) {
20639
20346
  this.triggeringException = true;
@@ -20659,7 +20366,7 @@
20659
20366
  * Dispose of the instance
20660
20367
  */;
20661
20368
  _proto.destroy = function destroy() {
20662
- this.logger.log('destroy');
20369
+ logger.log('destroy');
20663
20370
  this.trigger(Events.DESTROYING, undefined);
20664
20371
  this.detachMedia();
20665
20372
  this.removeAllListeners();
@@ -20684,7 +20391,7 @@
20684
20391
  * Attaches Hls.js to a media element
20685
20392
  */;
20686
20393
  _proto.attachMedia = function attachMedia(media) {
20687
- this.logger.log('attachMedia');
20394
+ logger.log('attachMedia');
20688
20395
  this._media = media;
20689
20396
  this.trigger(Events.MEDIA_ATTACHING, {
20690
20397
  media: media
@@ -20695,7 +20402,7 @@
20695
20402
  * Detach Hls.js from the media
20696
20403
  */;
20697
20404
  _proto.detachMedia = function detachMedia() {
20698
- this.logger.log('detachMedia');
20405
+ logger.log('detachMedia');
20699
20406
  this.trigger(Events.MEDIA_DETACHING, undefined);
20700
20407
  this._media = null;
20701
20408
  }
@@ -20712,7 +20419,7 @@
20712
20419
  });
20713
20420
  this._autoLevelCapping = -1;
20714
20421
  this._maxHdcpLevel = null;
20715
- this.logger.log("loadSource:" + loadingSource);
20422
+ logger.log("loadSource:" + loadingSource);
20716
20423
  if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
20717
20424
  this.detachMedia();
20718
20425
  this.attachMedia(media);
@@ -20734,7 +20441,8 @@
20734
20441
  if (startPosition === void 0) {
20735
20442
  startPosition = -1;
20736
20443
  }
20737
- this.logger.log("startLoad(" + startPosition + ")");
20444
+ logger.log("startLoad(" + startPosition + ")");
20445
+ this.started = true;
20738
20446
  this.networkControllers.forEach(function (controller) {
20739
20447
  controller.startLoad(startPosition);
20740
20448
  });
@@ -20744,31 +20452,34 @@
20744
20452
  * Stop loading of any stream data.
20745
20453
  */;
20746
20454
  _proto.stopLoad = function stopLoad() {
20747
- this.logger.log('stopLoad');
20455
+ logger.log('stopLoad');
20456
+ this.started = false;
20748
20457
  this.networkControllers.forEach(function (controller) {
20749
20458
  controller.stopLoad();
20750
20459
  });
20751
20460
  }
20752
20461
 
20753
20462
  /**
20754
- * Resumes stream controller segment loading after `pauseBuffering` has been called.
20463
+ * Resumes stream controller segment loading if previously started.
20755
20464
  */;
20756
20465
  _proto.resumeBuffering = function resumeBuffering() {
20757
- this.networkControllers.forEach(function (controller) {
20758
- if (controller.resumeBuffering) {
20759
- controller.resumeBuffering();
20760
- }
20761
- });
20466
+ if (this.started) {
20467
+ this.networkControllers.forEach(function (controller) {
20468
+ if ('fragmentLoader' in controller) {
20469
+ controller.startLoad(-1);
20470
+ }
20471
+ });
20472
+ }
20762
20473
  }
20763
20474
 
20764
20475
  /**
20765
- * Prevents stream controller from loading new segments until `resumeBuffering` is called.
20476
+ * Stops stream controller segment loading without changing 'started' state like stopLoad().
20766
20477
  * This allows for media buffering to be paused without interupting playlist loading.
20767
20478
  */;
20768
20479
  _proto.pauseBuffering = function pauseBuffering() {
20769
20480
  this.networkControllers.forEach(function (controller) {
20770
- if (controller.pauseBuffering) {
20771
- controller.pauseBuffering();
20481
+ if ('fragmentLoader' in controller) {
20482
+ controller.stopLoad();
20772
20483
  }
20773
20484
  });
20774
20485
  }
@@ -20777,7 +20488,7 @@
20777
20488
  * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
20778
20489
  */;
20779
20490
  _proto.swapAudioCodec = function swapAudioCodec() {
20780
- this.logger.log('swapAudioCodec');
20491
+ logger.log('swapAudioCodec');
20781
20492
  this.streamController.swapAudioCodec();
20782
20493
  }
20783
20494
 
@@ -20788,7 +20499,7 @@
20788
20499
  * Automatic recovery of media-errors by this process is configurable.
20789
20500
  */;
20790
20501
  _proto.recoverMediaError = function recoverMediaError() {
20791
- this.logger.log('recoverMediaError');
20502
+ logger.log('recoverMediaError');
20792
20503
  var media = this._media;
20793
20504
  this.detachMedia();
20794
20505
  if (media) {
@@ -20843,7 +20554,7 @@
20843
20554
  * 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.
20844
20555
  */,
20845
20556
  set: function set(newLevel) {
20846
- this.logger.log("set currentLevel:" + newLevel);
20557
+ logger.log("set currentLevel:" + newLevel);
20847
20558
  this.levelController.manualLevel = newLevel;
20848
20559
  this.streamController.immediateLevelSwitch();
20849
20560
  }
@@ -20864,7 +20575,7 @@
20864
20575
  * @param newLevel - Pass -1 for automatic level selection
20865
20576
  */,
20866
20577
  set: function set(newLevel) {
20867
- this.logger.log("set nextLevel:" + newLevel);
20578
+ logger.log("set nextLevel:" + newLevel);
20868
20579
  this.levelController.manualLevel = newLevel;
20869
20580
  this.streamController.nextLevelSwitch();
20870
20581
  }
@@ -20885,7 +20596,7 @@
20885
20596
  * @param newLevel - Pass -1 for automatic level selection
20886
20597
  */,
20887
20598
  set: function set(newLevel) {
20888
- this.logger.log("set loadLevel:" + newLevel);
20599
+ logger.log("set loadLevel:" + newLevel);
20889
20600
  this.levelController.manualLevel = newLevel;
20890
20601
  }
20891
20602
 
@@ -20920,7 +20631,7 @@
20920
20631
  * Sets "first-level", see getter.
20921
20632
  */,
20922
20633
  set: function set(newLevel) {
20923
- this.logger.log("set firstLevel:" + newLevel);
20634
+ logger.log("set firstLevel:" + newLevel);
20924
20635
  this.levelController.firstLevel = newLevel;
20925
20636
  }
20926
20637
 
@@ -20947,7 +20658,7 @@
20947
20658
  * (determined from download of first segment)
20948
20659
  */,
20949
20660
  set: function set(newLevel) {
20950
- this.logger.log("set startLevel:" + newLevel);
20661
+ logger.log("set startLevel:" + newLevel);
20951
20662
  // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
20952
20663
  if (newLevel !== -1) {
20953
20664
  newLevel = Math.max(newLevel, this.minAutoLevel);
@@ -21000,7 +20711,7 @@
21000
20711
  */
21001
20712
  function set(newLevel) {
21002
20713
  if (this._autoLevelCapping !== newLevel) {
21003
- this.logger.log("set autoLevelCapping:" + newLevel);
20714
+ logger.log("set autoLevelCapping:" + newLevel);
21004
20715
  this._autoLevelCapping = newLevel;
21005
20716
  this.levelController.checkMaxAutoUpdated();
21006
20717
  }
@@ -21325,7 +21036,7 @@
21325
21036
  * Get the video-dev/hls.js package version.
21326
21037
  */
21327
21038
  function get() {
21328
- return "1.5.5-0.canary.9997";
21039
+ return "1.5.5";
21329
21040
  }
21330
21041
  }, {
21331
21042
  key: "Events",