hls.js 1.5.6-0.canary.10011 → 1.5.6

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 +21 -21
  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.6");
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.6-0.canary.10011");
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.
@@ -2654,13 +2628,13 @@
2654
2628
  this.keyFormatVersions = formatversions;
2655
2629
  this.iv = iv;
2656
2630
  this.encrypted = method ? method !== 'NONE' : false;
2657
- this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2631
+ this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2658
2632
  }
2659
2633
  var _proto = LevelKey.prototype;
2660
2634
  _proto.isSupported = function isSupported() {
2661
2635
  // If it's Segment encryption or No encryption, just select that key system
2662
2636
  if (this.method) {
2663
- if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2637
+ if (this.method === 'AES-128' || this.method === 'NONE') {
2664
2638
  return true;
2665
2639
  }
2666
2640
  if (this.keyFormat === 'identity') {
@@ -2674,13 +2648,14 @@
2674
2648
  if (!this.encrypted || !this.uri) {
2675
2649
  return null;
2676
2650
  }
2677
- if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2651
+ if (this.method === 'AES-128' && this.uri && !this.iv) {
2678
2652
  if (typeof sn !== 'number') {
2679
2653
  // We are fetching decryption data for a initialization segment
2680
- // If the segment was encrypted with AES-128/256
2654
+ // If the segment was encrypted with AES-128
2681
2655
  // It must have an IV defined. We cannot substitute the Segment Number in.
2682
- logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2683
-
2656
+ if (this.method === 'AES-128' && !this.iv) {
2657
+ logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2658
+ }
2684
2659
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2685
2660
  sn = 0;
2686
2661
  }
@@ -2842,28 +2817,23 @@
2842
2817
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2843
2818
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2844
2819
  }
2820
+
2821
+ // Idealy fLaC and Opus would be first (spec-compliant) but
2822
+ // some browsers will report that fLaC is supported then fail.
2823
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2845
2824
  var codecsToCheck = {
2846
- // Idealy fLaC and Opus would be first (spec-compliant) but
2847
- // some browsers will report that fLaC is supported then fail.
2848
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2849
2825
  flac: ['flac', 'fLaC', 'FLAC'],
2850
- opus: ['opus', 'Opus'],
2851
- // Replace audio codec info if browser does not support mp4a.40.34,
2852
- // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
2853
- 'mp4a.40.34': ['mp3']
2826
+ opus: ['opus', 'Opus']
2854
2827
  }[lowerCaseCodec];
2855
2828
  for (var i = 0; i < codecsToCheck.length; i++) {
2856
- var _getMediaSource;
2857
2829
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2858
2830
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2859
2831
  return codecsToCheck[i];
2860
- } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2861
- return '';
2862
2832
  }
2863
2833
  }
2864
2834
  return lowerCaseCodec;
2865
2835
  }
2866
- var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2836
+ var AUDIO_CODEC_REGEXP = /flac|opus/i;
2867
2837
  function getCodecCompatibleName(codec, preferManagedMediaSource) {
2868
2838
  if (preferManagedMediaSource === void 0) {
2869
2839
  preferManagedMediaSource = true;
@@ -2891,18 +2861,6 @@
2891
2861
  }
2892
2862
  return codec;
2893
2863
  }
2894
- function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2895
- var MediaSource = getMediaSource(preferManagedMediaSource) || {
2896
- isTypeSupported: function isTypeSupported() {
2897
- return false;
2898
- }
2899
- };
2900
- return {
2901
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
2902
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
2903
- ac3: false
2904
- };
2905
- }
2906
2864
 
2907
2865
  var MASTER_PLAYLIST_REGEX = /#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-(SESSION-DATA|SESSION-KEY|DEFINE|CONTENT-STEERING|START):([^\r\n]*)[\r\n]+/g;
2908
2866
  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -3703,10 +3661,10 @@
3703
3661
  var loaderContext = loader.context;
3704
3662
  if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
3705
3663
  // same URL can't overlap
3706
- this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
3664
+ logger.trace('[playlist-loader]: playlist request ongoing');
3707
3665
  return;
3708
3666
  }
3709
- this.hls.logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
3667
+ logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
3710
3668
  loader.abort();
3711
3669
  }
3712
3670
 
@@ -3816,7 +3774,7 @@
3816
3774
  // alt audio rendition in which quality levels (main)
3817
3775
  // contains both audio+video. but with mixed audio track not signaled
3818
3776
  if (!embeddedAudioFound && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
3819
- this.hls.logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
3777
+ logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
3820
3778
  audioTracks.unshift({
3821
3779
  type: 'main',
3822
3780
  name: 'main',
@@ -3916,7 +3874,7 @@
3916
3874
  message += " id: " + context.id + " group-id: \"" + context.groupId + "\"";
3917
3875
  }
3918
3876
  var error = new Error(message);
3919
- this.hls.logger.warn("[playlist-loader]: " + message);
3877
+ logger.warn("[playlist-loader]: " + message);
3920
3878
  var details = ErrorDetails.UNKNOWN;
3921
3879
  var fatal = false;
3922
3880
  var loader = this.getInternalLoader(context);
@@ -4477,43 +4435,8 @@
4477
4435
  this.currentTime = 0;
4478
4436
  this.stallCount = 0;
4479
4437
  this._latency = null;
4480
- this.onTimeupdate = function () {
4481
- var media = _this.media,
4482
- levelDetails = _this.levelDetails;
4483
- if (!media || !levelDetails) {
4484
- return;
4485
- }
4486
- _this.currentTime = media.currentTime;
4487
- var latency = _this.computeLatency();
4488
- if (latency === null) {
4489
- return;
4490
- }
4491
- _this._latency = latency;
4492
-
4493
- // Adapt playbackRate to meet target latency in low-latency mode
4494
- var _this$config = _this.config,
4495
- lowLatencyMode = _this$config.lowLatencyMode,
4496
- maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4497
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4498
- return;
4499
- }
4500
- var targetLatency = _this.targetLatency;
4501
- if (targetLatency === null) {
4502
- return;
4503
- }
4504
- var distanceFromTarget = latency - targetLatency;
4505
- // Only adjust playbackRate when within one target duration of targetLatency
4506
- // and more than one second from under-buffering.
4507
- // Playback further than one target duration from target can be considered DVR playback.
4508
- var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
4509
- var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4510
- if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
4511
- var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4512
- var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
4513
- media.playbackRate = Math.min(max, Math.max(1, rate));
4514
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4515
- media.playbackRate = 1;
4516
- }
4438
+ this.timeupdateHandler = function () {
4439
+ return _this.timeupdate();
4517
4440
  };
4518
4441
  this.hls = hls;
4519
4442
  this.config = hls.config;
@@ -4525,7 +4448,7 @@
4525
4448
  this.onMediaDetaching();
4526
4449
  this.levelDetails = null;
4527
4450
  // @ts-ignore
4528
- this.hls = null;
4451
+ this.hls = this.timeupdateHandler = null;
4529
4452
  };
4530
4453
  _proto.registerListeners = function registerListeners() {
4531
4454
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4543,11 +4466,11 @@
4543
4466
  };
4544
4467
  _proto.onMediaAttached = function onMediaAttached(event, data) {
4545
4468
  this.media = data.media;
4546
- this.media.addEventListener('timeupdate', this.onTimeupdate);
4469
+ this.media.addEventListener('timeupdate', this.timeupdateHandler);
4547
4470
  };
4548
4471
  _proto.onMediaDetaching = function onMediaDetaching() {
4549
4472
  if (this.media) {
4550
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4473
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4551
4474
  this.media = null;
4552
4475
  }
4553
4476
  };
@@ -4560,10 +4483,10 @@
4560
4483
  var details = _ref.details;
4561
4484
  this.levelDetails = details;
4562
4485
  if (details.advanced) {
4563
- this.onTimeupdate();
4486
+ this.timeupdate();
4564
4487
  }
4565
4488
  if (!details.live && this.media) {
4566
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4489
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4567
4490
  }
4568
4491
  };
4569
4492
  _proto.onError = function onError(event, data) {
@@ -4573,7 +4496,45 @@
4573
4496
  }
4574
4497
  this.stallCount++;
4575
4498
  if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
4576
- this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
4499
+ logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
4500
+ }
4501
+ };
4502
+ _proto.timeupdate = function timeupdate() {
4503
+ var media = this.media,
4504
+ levelDetails = this.levelDetails;
4505
+ if (!media || !levelDetails) {
4506
+ return;
4507
+ }
4508
+ this.currentTime = media.currentTime;
4509
+ var latency = this.computeLatency();
4510
+ if (latency === null) {
4511
+ return;
4512
+ }
4513
+ this._latency = latency;
4514
+
4515
+ // Adapt playbackRate to meet target latency in low-latency mode
4516
+ var _this$config = this.config,
4517
+ lowLatencyMode = _this$config.lowLatencyMode,
4518
+ maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4519
+ if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4520
+ return;
4521
+ }
4522
+ var targetLatency = this.targetLatency;
4523
+ if (targetLatency === null) {
4524
+ return;
4525
+ }
4526
+ var distanceFromTarget = latency - targetLatency;
4527
+ // Only adjust playbackRate when within one target duration of targetLatency
4528
+ // and more than one second from under-buffering.
4529
+ // Playback further than one target duration from target can be considered DVR playback.
4530
+ var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4531
+ var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4532
+ if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4533
+ var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4534
+ var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4535
+ media.playbackRate = Math.min(max, Math.max(1, rate));
4536
+ } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4537
+ media.playbackRate = 1;
4577
4538
  }
4578
4539
  };
4579
4540
  _proto.estimateLiveEdge = function estimateLiveEdge() {
@@ -5481,17 +5442,19 @@
5481
5442
  MoveAllAlternatesMatchingHDCP: 2,
5482
5443
  SwitchToSDR: 4
5483
5444
  }; // Reserved for future use
5484
- var ErrorController = /*#__PURE__*/function (_Logger) {
5485
- _inheritsLoose(ErrorController, _Logger);
5445
+ var ErrorController = /*#__PURE__*/function () {
5486
5446
  function ErrorController(hls) {
5487
- var _this;
5488
- _this = _Logger.call(this, 'error-controller', hls.logger) || this;
5489
- _this.hls = void 0;
5490
- _this.playlistError = 0;
5491
- _this.penalizedRenditions = {};
5492
- _this.hls = hls;
5493
- _this.registerListeners();
5494
- return _this;
5447
+ this.hls = void 0;
5448
+ this.playlistError = 0;
5449
+ this.penalizedRenditions = {};
5450
+ this.log = void 0;
5451
+ this.warn = void 0;
5452
+ this.error = void 0;
5453
+ this.hls = hls;
5454
+ this.log = logger.log.bind(logger, "[info]:");
5455
+ this.warn = logger.warn.bind(logger, "[warning]:");
5456
+ this.error = logger.error.bind(logger, "[error]:");
5457
+ this.registerListeners();
5495
5458
  }
5496
5459
  var _proto = ErrorController.prototype;
5497
5460
  _proto.registerListeners = function registerListeners() {
@@ -5847,19 +5810,19 @@
5847
5810
  }
5848
5811
  };
5849
5812
  return ErrorController;
5850
- }(Logger);
5813
+ }();
5851
5814
 
5852
- var BasePlaylistController = /*#__PURE__*/function (_Logger) {
5853
- _inheritsLoose(BasePlaylistController, _Logger);
5815
+ var BasePlaylistController = /*#__PURE__*/function () {
5854
5816
  function BasePlaylistController(hls, logPrefix) {
5855
- var _this;
5856
- _this = _Logger.call(this, logPrefix, hls.logger) || this;
5857
- _this.hls = void 0;
5858
- _this.timer = -1;
5859
- _this.requestScheduled = -1;
5860
- _this.canLoad = false;
5861
- _this.hls = hls;
5862
- return _this;
5817
+ this.hls = void 0;
5818
+ this.timer = -1;
5819
+ this.requestScheduled = -1;
5820
+ this.canLoad = false;
5821
+ this.log = void 0;
5822
+ this.warn = void 0;
5823
+ this.log = logger.log.bind(logger, logPrefix + ":");
5824
+ this.warn = logger.warn.bind(logger, logPrefix + ":");
5825
+ this.hls = hls;
5863
5826
  }
5864
5827
  var _proto = BasePlaylistController.prototype;
5865
5828
  _proto.destroy = function destroy() {
@@ -5892,7 +5855,7 @@
5892
5855
  try {
5893
5856
  uri = new self.URL(attr.URI, previous.url).href;
5894
5857
  } catch (error) {
5895
- this.warn("Could not construct new URL for Rendition Report: " + error);
5858
+ logger.warn("Could not construct new URL for Rendition Report: " + error);
5896
5859
  uri = attr.URI || '';
5897
5860
  }
5898
5861
  // Use exact match. Otherwise, the last partial match, if any, will be used
@@ -5931,7 +5894,7 @@
5931
5894
  return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
5932
5895
  };
5933
5896
  _proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
5934
- var _this2 = this;
5897
+ var _this = this;
5935
5898
  var details = data.details,
5936
5899
  stats = data.stats;
5937
5900
 
@@ -5978,12 +5941,7 @@
5978
5941
  var cdnAge = lastAdvanced + details.ageHeader;
5979
5942
  var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
5980
5943
  if (currentGoal > 0) {
5981
- if (cdnAge > details.targetduration * 3) {
5982
- // Omit segment and part directives when the last response was more than 3 target durations ago,
5983
- this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
5984
- msn = undefined;
5985
- part = undefined;
5986
- } else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
5944
+ if (previousDetails && currentGoal > previousDetails.tuneInGoal) {
5987
5945
  // If we attempted to get the next or latest playlist update, but currentGoal increased,
5988
5946
  // then we either can't catchup, or the "age" header cannot be trusted.
5989
5947
  this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
@@ -6041,7 +5999,7 @@
6041
5999
  // );
6042
6000
 
6043
6001
  this.timer = self.setTimeout(function () {
6044
- return _this2.loadPlaylist(deliveryDirectives);
6002
+ return _this.loadPlaylist(deliveryDirectives);
6045
6003
  }, estimatedTimeUntilUpdate);
6046
6004
  } else {
6047
6005
  this.clearTimer();
@@ -6057,7 +6015,7 @@
6057
6015
  return new HlsUrlParameters(msn, part, skip);
6058
6016
  };
6059
6017
  _proto.checkRetry = function checkRetry(errorEvent) {
6060
- var _this3 = this;
6018
+ var _this2 = this;
6061
6019
  var errorDetails = errorEvent.details;
6062
6020
  var isTimeout = isTimeoutError(errorEvent);
6063
6021
  var errorAction = errorEvent.errorAction;
@@ -6081,7 +6039,7 @@
6081
6039
  var delay = getRetryDelay(retryConfig, retryCount);
6082
6040
  // Schedule level/track reload
6083
6041
  this.timer = self.setTimeout(function () {
6084
- return _this3.loadPlaylist();
6042
+ return _this2.loadPlaylist();
6085
6043
  }, delay);
6086
6044
  this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
6087
6045
  }
@@ -6092,7 +6050,7 @@
6092
6050
  return retry;
6093
6051
  };
6094
6052
  return BasePlaylistController;
6095
- }(Logger);
6053
+ }();
6096
6054
 
6097
6055
  /*
6098
6056
  * compute an Exponential Weighted moving average
@@ -6466,33 +6424,30 @@
6466
6424
  }, {});
6467
6425
  }
6468
6426
 
6469
- var AbrController = /*#__PURE__*/function (_Logger) {
6470
- _inheritsLoose(AbrController, _Logger);
6427
+ var AbrController = /*#__PURE__*/function () {
6471
6428
  function AbrController(_hls) {
6472
- var _this;
6473
- _this = _Logger.call(this, 'abr', _hls.logger) || this;
6474
- _this.hls = void 0;
6475
- _this.lastLevelLoadSec = 0;
6476
- _this.lastLoadedFragLevel = -1;
6477
- _this.firstSelection = -1;
6478
- _this._nextAutoLevel = -1;
6479
- _this.nextAutoLevelKey = '';
6480
- _this.audioTracksByGroup = null;
6481
- _this.codecTiers = null;
6482
- _this.timer = -1;
6483
- _this.fragCurrent = null;
6484
- _this.partCurrent = null;
6485
- _this.bitrateTestDelay = 0;
6486
- _this.bwEstimator = void 0;
6429
+ var _this = this;
6430
+ this.hls = void 0;
6431
+ this.lastLevelLoadSec = 0;
6432
+ this.lastLoadedFragLevel = -1;
6433
+ this.firstSelection = -1;
6434
+ this._nextAutoLevel = -1;
6435
+ this.nextAutoLevelKey = '';
6436
+ this.audioTracksByGroup = null;
6437
+ this.codecTiers = null;
6438
+ this.timer = -1;
6439
+ this.fragCurrent = null;
6440
+ this.partCurrent = null;
6441
+ this.bitrateTestDelay = 0;
6442
+ this.bwEstimator = void 0;
6487
6443
  /*
6488
6444
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
6489
6445
  quickly enough to prevent underbuffering
6490
6446
  */
6491
- _this._abandonRulesCheck = function () {
6492
- var _assertThisInitialize = _assertThisInitialized(_this),
6493
- frag = _assertThisInitialize.fragCurrent,
6494
- part = _assertThisInitialize.partCurrent,
6495
- hls = _assertThisInitialize.hls;
6447
+ this._abandonRulesCheck = function () {
6448
+ var frag = _this.fragCurrent,
6449
+ part = _this.partCurrent,
6450
+ hls = _this.hls;
6496
6451
  var autoLevelEnabled = hls.autoLevelEnabled,
6497
6452
  media = hls.media;
6498
6453
  if (!frag || !media) {
@@ -6581,22 +6536,21 @@
6581
6536
  _this.resetEstimator(nextLoadLevelBitrate);
6582
6537
  }
6583
6538
  _this.clearTimer();
6584
- _this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
6539
+ logger.warn("[abr] Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
6585
6540
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
6586
6541
  frag: frag,
6587
6542
  part: part,
6588
6543
  stats: stats
6589
6544
  });
6590
6545
  };
6591
- _this.hls = _hls;
6592
- _this.bwEstimator = _this.initEstimator();
6593
- _this.registerListeners();
6594
- return _this;
6546
+ this.hls = _hls;
6547
+ this.bwEstimator = this.initEstimator();
6548
+ this.registerListeners();
6595
6549
  }
6596
6550
  var _proto = AbrController.prototype;
6597
6551
  _proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
6598
6552
  if (abrEwmaDefaultEstimate) {
6599
- this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6553
+ logger.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6600
6554
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
6601
6555
  }
6602
6556
  this.firstSelection = -1;
@@ -6841,13 +6795,13 @@
6841
6795
  // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
6842
6796
  var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
6843
6797
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
6844
- this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
6798
+ logger.info("[abr] bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
6845
6799
  // don't use conservative factor on bitrate test
6846
6800
  bwFactor = bwUpFactor = 1;
6847
6801
  }
6848
6802
  }
6849
6803
  var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
6850
- this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6804
+ logger.info("[abr] " + (bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6851
6805
  if (bestLevel > -1) {
6852
6806
  return bestLevel;
6853
6807
  }
@@ -6915,7 +6869,7 @@
6915
6869
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
6916
6870
  currentFrameRate = minFramerate;
6917
6871
  currentBw = Math.max(currentBw, minBitrate);
6918
- this.log("picked start tier " + JSON.stringify(startTier));
6872
+ logger.log("[abr] picked start tier " + JSON.stringify(startTier));
6919
6873
  } else {
6920
6874
  currentCodecSet = level == null ? void 0 : level.codecSet;
6921
6875
  currentVideoRange = level == null ? void 0 : level.videoRange;
@@ -6968,9 +6922,9 @@
6968
6922
  var forcedAutoLevel = _this2.forcedAutoLevel;
6969
6923
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
6970
6924
  if (levelsSkipped.length) {
6971
- _this2.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
6925
+ logger.trace("[abr] Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
6972
6926
  }
6973
- _this2.info("switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
6927
+ logger.info("[abr] switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
6974
6928
  }
6975
6929
  if (firstSelection) {
6976
6930
  _this2.firstSelection = i;
@@ -7004,7 +6958,7 @@
7004
6958
  }
7005
6959
  var firstLevel = this.hls.firstLevel;
7006
6960
  var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
7007
- this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
6961
+ logger.warn("[abr] Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
7008
6962
  return clamped;
7009
6963
  }
7010
6964
  }, {
@@ -7057,7 +7011,7 @@
7057
7011
  }
7058
7012
  }]);
7059
7013
  return AbrController;
7060
- }(Logger);
7014
+ }();
7061
7015
 
7062
7016
  /**
7063
7017
  * Provides methods dealing with buffer length retrieval for example.
@@ -7278,57 +7232,57 @@
7278
7232
  }();
7279
7233
 
7280
7234
  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
7281
- var BufferController = /*#__PURE__*/function (_Logger) {
7282
- _inheritsLoose(BufferController, _Logger);
7235
+ var BufferController = /*#__PURE__*/function () {
7283
7236
  function BufferController(hls) {
7284
- var _this;
7285
- _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
7237
+ var _this = this;
7286
7238
  // The level details used to determine duration, target-duration and live
7287
- _this.details = null;
7239
+ this.details = null;
7288
7240
  // cache the self generated object url to detect hijack of video tag
7289
- _this._objectUrl = null;
7241
+ this._objectUrl = null;
7290
7242
  // A queue of buffer operations which require the SourceBuffer to not be updating upon execution
7291
- _this.operationQueue = void 0;
7243
+ this.operationQueue = void 0;
7292
7244
  // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
7293
- _this.listeners = void 0;
7294
- _this.hls = void 0;
7245
+ this.listeners = void 0;
7246
+ this.hls = void 0;
7295
7247
  // The number of BUFFER_CODEC events received before any sourceBuffers are created
7296
- _this.bufferCodecEventsExpected = 0;
7248
+ this.bufferCodecEventsExpected = 0;
7297
7249
  // The total number of BUFFER_CODEC events received
7298
- _this._bufferCodecEventsTotal = 0;
7250
+ this._bufferCodecEventsTotal = 0;
7299
7251
  // A reference to the attached media element
7300
- _this.media = null;
7252
+ this.media = null;
7301
7253
  // A reference to the active media source
7302
- _this.mediaSource = null;
7254
+ this.mediaSource = null;
7303
7255
  // Last MP3 audio chunk appended
7304
- _this.lastMpegAudioChunk = null;
7305
- _this.appendSource = void 0;
7256
+ this.lastMpegAudioChunk = null;
7257
+ this.appendSource = void 0;
7306
7258
  // counters
7307
- _this.appendErrors = {
7259
+ this.appendErrors = {
7308
7260
  audio: 0,
7309
7261
  video: 0,
7310
7262
  audiovideo: 0
7311
7263
  };
7312
- _this.tracks = {};
7313
- _this.pendingTracks = {};
7314
- _this.sourceBuffer = void 0;
7315
- _this._onEndStreaming = function (event) {
7264
+ this.tracks = {};
7265
+ this.pendingTracks = {};
7266
+ this.sourceBuffer = void 0;
7267
+ this.log = void 0;
7268
+ this.warn = void 0;
7269
+ this.error = void 0;
7270
+ this._onEndStreaming = function (event) {
7316
7271
  if (!_this.hls) {
7317
7272
  return;
7318
7273
  }
7319
7274
  _this.hls.pauseBuffering();
7320
7275
  };
7321
- _this._onStartStreaming = function (event) {
7276
+ this._onStartStreaming = function (event) {
7322
7277
  if (!_this.hls) {
7323
7278
  return;
7324
7279
  }
7325
7280
  _this.hls.resumeBuffering();
7326
7281
  };
7327
7282
  // Keep as arrow functions so that we can directly reference these functions directly as event listeners
7328
- _this._onMediaSourceOpen = function () {
7329
- var _assertThisInitialize = _assertThisInitialized(_this),
7330
- media = _assertThisInitialize.media,
7331
- mediaSource = _assertThisInitialize.mediaSource;
7283
+ this._onMediaSourceOpen = function () {
7284
+ var media = _this.media,
7285
+ mediaSource = _this.mediaSource;
7332
7286
  _this.log('Media source opened');
7333
7287
  if (media) {
7334
7288
  media.removeEventListener('emptied', _this._onMediaEmptied);
@@ -7344,25 +7298,27 @@
7344
7298
  }
7345
7299
  _this.checkPendingTracks();
7346
7300
  };
7347
- _this._onMediaSourceClose = function () {
7301
+ this._onMediaSourceClose = function () {
7348
7302
  _this.log('Media source closed');
7349
7303
  };
7350
- _this._onMediaSourceEnded = function () {
7304
+ this._onMediaSourceEnded = function () {
7351
7305
  _this.log('Media source ended');
7352
7306
  };
7353
- _this._onMediaEmptied = function () {
7354
- var _assertThisInitialize2 = _assertThisInitialized(_this),
7355
- mediaSrc = _assertThisInitialize2.mediaSrc,
7356
- _objectUrl = _assertThisInitialize2._objectUrl;
7307
+ this._onMediaEmptied = function () {
7308
+ var mediaSrc = _this.mediaSrc,
7309
+ _objectUrl = _this._objectUrl;
7357
7310
  if (mediaSrc !== _objectUrl) {
7358
- _this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7311
+ logger.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7359
7312
  }
7360
7313
  };
7361
- _this.hls = hls;
7362
- _this.appendSource = hls.config.preferManagedMediaSource;
7363
- _this._initSourceBuffer();
7364
- _this.registerListeners();
7365
- return _this;
7314
+ this.hls = hls;
7315
+ var logPrefix = '[buffer-controller]';
7316
+ this.appendSource = hls.config.preferManagedMediaSource;
7317
+ this.log = logger.log.bind(logger, logPrefix);
7318
+ this.warn = logger.warn.bind(logger, logPrefix);
7319
+ this.error = logger.error.bind(logger, logPrefix);
7320
+ this._initSourceBuffer();
7321
+ this.registerListeners();
7366
7322
  }
7367
7323
  var _proto = BufferController.prototype;
7368
7324
  _proto.hasSourceTypes = function hasSourceTypes() {
@@ -7374,12 +7330,6 @@
7374
7330
  this.lastMpegAudioChunk = null;
7375
7331
  // @ts-ignore
7376
7332
  this.hls = null;
7377
- // @ts-ignore
7378
- this._onMediaSourceOpen = this._onMediaSourceClose = null;
7379
- // @ts-ignore
7380
- this._onMediaSourceEnded = null;
7381
- // @ts-ignore
7382
- this._onStartStreaming = this._onEndStreaming = null;
7383
7333
  };
7384
7334
  _proto.registerListeners = function registerListeners() {
7385
7335
  var hls = this.hls;
@@ -7537,7 +7487,6 @@
7537
7487
  _this2.resetBuffer(type);
7538
7488
  });
7539
7489
  this._initSourceBuffer();
7540
- this.hls.resumeBuffering();
7541
7490
  };
7542
7491
  _proto.resetBuffer = function resetBuffer(type) {
7543
7492
  var sb = this.sourceBuffer[type];
@@ -8241,7 +8190,7 @@
8241
8190
  }
8242
8191
  }]);
8243
8192
  return BufferController;
8244
- }(Logger);
8193
+ }();
8245
8194
  function removeSourceChildren(node) {
8246
8195
  var sourceChildren = node.querySelectorAll('source');
8247
8196
  [].slice.call(sourceChildren).forEach(function (source) {
@@ -8365,7 +8314,7 @@
8365
8314
  var hls = this.hls;
8366
8315
  var maxLevel = this.getMaxLevel(levels.length - 1);
8367
8316
  if (maxLevel !== this.autoLevelCapping) {
8368
- hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8317
+ logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8369
8318
  }
8370
8319
  hls.autoLevelCapping = maxLevel;
8371
8320
  if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
@@ -8555,10 +8504,10 @@
8555
8504
  totalDroppedFrames: droppedFrames
8556
8505
  });
8557
8506
  if (droppedFPS > 0) {
8558
- // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8507
+ // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8559
8508
  if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
8560
8509
  var currentLevel = hls.currentLevel;
8561
- hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8510
+ logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8562
8511
  if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
8563
8512
  currentLevel = currentLevel - 1;
8564
8513
  hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
@@ -8592,28 +8541,26 @@
8592
8541
  }();
8593
8542
 
8594
8543
  var PATHWAY_PENALTY_DURATION_MS = 300000;
8595
- var ContentSteeringController = /*#__PURE__*/function (_Logger) {
8596
- _inheritsLoose(ContentSteeringController, _Logger);
8544
+ var ContentSteeringController = /*#__PURE__*/function () {
8597
8545
  function ContentSteeringController(hls) {
8598
- var _this;
8599
- _this = _Logger.call(this, 'content-steering', hls.logger) || this;
8600
- _this.hls = void 0;
8601
- _this.loader = null;
8602
- _this.uri = null;
8603
- _this.pathwayId = '.';
8604
- _this.pathwayPriority = null;
8605
- _this.timeToLoad = 300;
8606
- _this.reloadTimer = -1;
8607
- _this.updated = 0;
8608
- _this.started = false;
8609
- _this.enabled = true;
8610
- _this.levels = null;
8611
- _this.audioTracks = null;
8612
- _this.subtitleTracks = null;
8613
- _this.penalizedPathways = {};
8614
- _this.hls = hls;
8615
- _this.registerListeners();
8616
- return _this;
8546
+ this.hls = void 0;
8547
+ this.log = void 0;
8548
+ this.loader = null;
8549
+ this.uri = null;
8550
+ this.pathwayId = '.';
8551
+ this.pathwayPriority = null;
8552
+ this.timeToLoad = 300;
8553
+ this.reloadTimer = -1;
8554
+ this.updated = 0;
8555
+ this.started = false;
8556
+ this.enabled = true;
8557
+ this.levels = null;
8558
+ this.audioTracks = null;
8559
+ this.subtitleTracks = null;
8560
+ this.penalizedPathways = {};
8561
+ this.hls = hls;
8562
+ this.log = logger.log.bind(logger, "[content-steering]:");
8563
+ this.registerListeners();
8617
8564
  }
8618
8565
  var _proto = ContentSteeringController.prototype;
8619
8566
  _proto.registerListeners = function registerListeners() {
@@ -8734,7 +8681,7 @@
8734
8681
  errorAction.resolved = this.pathwayId !== errorPathway;
8735
8682
  }
8736
8683
  if (!errorAction.resolved) {
8737
- 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));
8684
+ 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));
8738
8685
  }
8739
8686
  }
8740
8687
  };
@@ -8814,7 +8761,7 @@
8814
8761
  return defaultPathway;
8815
8762
  };
8816
8763
  _proto.clonePathways = function clonePathways(pathwayClones) {
8817
- var _this2 = this;
8764
+ var _this = this;
8818
8765
  var levels = this.levels;
8819
8766
  if (!levels) {
8820
8767
  return;
@@ -8830,7 +8777,7 @@
8830
8777
  })) {
8831
8778
  return;
8832
8779
  }
8833
- var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
8780
+ var clonedVariants = _this.getLevelsForPathway(baseId).map(function (baseLevel) {
8834
8781
  var attributes = new AttrList(baseLevel.attrs);
8835
8782
  attributes['PATHWAY-ID'] = cloneId;
8836
8783
  var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
@@ -8867,12 +8814,12 @@
8867
8814
  return clonedLevel;
8868
8815
  });
8869
8816
  levels.push.apply(levels, clonedVariants);
8870
- cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8871
- cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8817
+ cloneRenditionGroups(_this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8818
+ cloneRenditionGroups(_this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8872
8819
  });
8873
8820
  };
8874
8821
  _proto.loadSteeringManifest = function loadSteeringManifest(uri) {
8875
- var _this3 = this;
8822
+ var _this2 = this;
8876
8823
  var config = this.hls.config;
8877
8824
  var Loader = config.loader;
8878
8825
  if (this.loader) {
@@ -8907,87 +8854,87 @@
8907
8854
  };
8908
8855
  var callbacks = {
8909
8856
  onSuccess: function onSuccess(response, stats, context, networkDetails) {
8910
- _this3.log("Loaded steering manifest: \"" + url + "\"");
8857
+ _this2.log("Loaded steering manifest: \"" + url + "\"");
8911
8858
  var steeringData = response.data;
8912
- if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
8913
- _this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
8859
+ if (steeringData.VERSION !== 1) {
8860
+ _this2.log("Steering VERSION " + steeringData.VERSION + " not supported!");
8914
8861
  return;
8915
8862
  }
8916
- _this3.updated = performance.now();
8917
- _this3.timeToLoad = steeringData.TTL;
8863
+ _this2.updated = performance.now();
8864
+ _this2.timeToLoad = steeringData.TTL;
8918
8865
  var reloadUri = steeringData['RELOAD-URI'],
8919
8866
  pathwayClones = steeringData['PATHWAY-CLONES'],
8920
8867
  pathwayPriority = steeringData['PATHWAY-PRIORITY'];
8921
8868
  if (reloadUri) {
8922
8869
  try {
8923
- _this3.uri = new self.URL(reloadUri, url).href;
8870
+ _this2.uri = new self.URL(reloadUri, url).href;
8924
8871
  } catch (error) {
8925
- _this3.enabled = false;
8926
- _this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
8872
+ _this2.enabled = false;
8873
+ _this2.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
8927
8874
  return;
8928
8875
  }
8929
8876
  }
8930
- _this3.scheduleRefresh(_this3.uri || context.url);
8877
+ _this2.scheduleRefresh(_this2.uri || context.url);
8931
8878
  if (pathwayClones) {
8932
- _this3.clonePathways(pathwayClones);
8879
+ _this2.clonePathways(pathwayClones);
8933
8880
  }
8934
8881
  var loadedSteeringData = {
8935
8882
  steeringManifest: steeringData,
8936
8883
  url: url.toString()
8937
8884
  };
8938
- _this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8885
+ _this2.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8939
8886
  if (pathwayPriority) {
8940
- _this3.updatePathwayPriority(pathwayPriority);
8887
+ _this2.updatePathwayPriority(pathwayPriority);
8941
8888
  }
8942
8889
  },
8943
8890
  onError: function onError(error, context, networkDetails, stats) {
8944
- _this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8945
- _this3.stopLoad();
8891
+ _this2.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8892
+ _this2.stopLoad();
8946
8893
  if (error.code === 410) {
8947
- _this3.enabled = false;
8948
- _this3.log("Steering manifest " + context.url + " no longer available");
8894
+ _this2.enabled = false;
8895
+ _this2.log("Steering manifest " + context.url + " no longer available");
8949
8896
  return;
8950
8897
  }
8951
- var ttl = _this3.timeToLoad * 1000;
8898
+ var ttl = _this2.timeToLoad * 1000;
8952
8899
  if (error.code === 429) {
8953
- var loader = _this3.loader;
8900
+ var loader = _this2.loader;
8954
8901
  if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
8955
8902
  var retryAfter = loader.getResponseHeader('Retry-After');
8956
8903
  if (retryAfter) {
8957
8904
  ttl = parseFloat(retryAfter) * 1000;
8958
8905
  }
8959
8906
  }
8960
- _this3.log("Steering manifest " + context.url + " rate limited");
8907
+ _this2.log("Steering manifest " + context.url + " rate limited");
8961
8908
  return;
8962
8909
  }
8963
- _this3.scheduleRefresh(_this3.uri || context.url, ttl);
8910
+ _this2.scheduleRefresh(_this2.uri || context.url, ttl);
8964
8911
  },
8965
8912
  onTimeout: function onTimeout(stats, context, networkDetails) {
8966
- _this3.log("Timeout loading steering manifest (" + context.url + ")");
8967
- _this3.scheduleRefresh(_this3.uri || context.url);
8913
+ _this2.log("Timeout loading steering manifest (" + context.url + ")");
8914
+ _this2.scheduleRefresh(_this2.uri || context.url);
8968
8915
  }
8969
8916
  };
8970
8917
  this.log("Requesting steering manifest: " + url);
8971
8918
  this.loader.load(context, loaderConfig, callbacks);
8972
8919
  };
8973
8920
  _proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
8974
- var _this4 = this;
8921
+ var _this3 = this;
8975
8922
  if (ttlMs === void 0) {
8976
8923
  ttlMs = this.timeToLoad * 1000;
8977
8924
  }
8978
8925
  this.clearTimeout();
8979
8926
  this.reloadTimer = self.setTimeout(function () {
8980
- var _this4$hls;
8981
- var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
8927
+ var _this3$hls;
8928
+ var media = (_this3$hls = _this3.hls) == null ? void 0 : _this3$hls.media;
8982
8929
  if (media && !media.ended) {
8983
- _this4.loadSteeringManifest(uri);
8930
+ _this3.loadSteeringManifest(uri);
8984
8931
  return;
8985
8932
  }
8986
- _this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
8933
+ _this3.scheduleRefresh(uri, _this3.timeToLoad * 1000);
8987
8934
  }, ttlMs);
8988
8935
  };
8989
8936
  return ContentSteeringController;
8990
- }(Logger);
8937
+ }();
8991
8938
  function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
8992
8939
  if (!tracks) {
8993
8940
  return;
@@ -9823,7 +9770,7 @@
9823
9770
  });
9824
9771
  function timelineConfig() {
9825
9772
  return {
9826
- cueHandler: HevcVideoParser,
9773
+ cueHandler: Cues,
9827
9774
  // used by timeline-controller
9828
9775
  enableWebVTT: false,
9829
9776
  // used by timeline-controller
@@ -9854,7 +9801,7 @@
9854
9801
  /**
9855
9802
  * @ignore
9856
9803
  */
9857
- function mergeConfig(defaultConfig, userConfig, logger) {
9804
+ function mergeConfig(defaultConfig, userConfig) {
9858
9805
  if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
9859
9806
  throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
9860
9807
  }
@@ -9924,7 +9871,7 @@
9924
9871
  /**
9925
9872
  * @ignore
9926
9873
  */
9927
- function enableStreamingMode(config, logger) {
9874
+ function enableStreamingMode(config) {
9928
9875
  var currentLoader = config.loader;
9929
9876
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
9930
9877
  // If a developer has configured their own loader, respect that choice
@@ -9941,11 +9888,12 @@
9941
9888
  }
9942
9889
  }
9943
9890
 
9891
+ var chromeOrFirefox;
9944
9892
  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
9945
9893
  _inheritsLoose(LevelController, _BasePlaylistControll);
9946
9894
  function LevelController(hls, contentSteeringController) {
9947
9895
  var _this;
9948
- _this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
9896
+ _this = _BasePlaylistControll.call(this, hls, '[level-controller]') || this;
9949
9897
  _this._levels = [];
9950
9898
  _this._firstLevel = -1;
9951
9899
  _this._maxAutoLevel = -1;
@@ -10014,13 +9962,21 @@
10014
9962
  var videoCodecFound = false;
10015
9963
  var audioCodecFound = false;
10016
9964
  data.levels.forEach(function (levelParsed) {
10017
- var _videoCodec;
9965
+ var _audioCodec, _videoCodec;
10018
9966
  var attributes = levelParsed.attrs;
9967
+
9968
+ // erase audio codec info if browser does not support mp4a.40.34.
9969
+ // demuxer will autodetect codec and fallback to mpeg/audio
10019
9970
  var audioCodec = levelParsed.audioCodec,
10020
9971
  videoCodec = levelParsed.videoCodec;
9972
+ if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
9973
+ chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
9974
+ if (chromeOrFirefox) {
9975
+ levelParsed.audioCodec = audioCodec = undefined;
9976
+ }
9977
+ }
10021
9978
  if (audioCodec) {
10022
- // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
10023
- levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
9979
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
10024
9980
  }
10025
9981
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
10026
9982
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -10252,12 +10208,7 @@
10252
10208
  if (curLevel.fragmentError === 0) {
10253
10209
  curLevel.loadError = 0;
10254
10210
  }
10255
- // Ignore matching details populated by loading a Media Playlist directly
10256
- var previousDetails = curLevel.details;
10257
- if (previousDetails === data.details && previousDetails.advanced) {
10258
- previousDetails = undefined;
10259
- }
10260
- this.playlistLoaded(level, data, previousDetails);
10211
+ this.playlistLoaded(level, data, curLevel.details);
10261
10212
  } else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
10262
10213
  // received a delta playlist update that cannot be merged
10263
10214
  details.deltaUpdateFailed = true;
@@ -11172,8 +11123,8 @@
11172
11123
  var _frag$decryptdata;
11173
11124
  var byteRangeStart = start;
11174
11125
  var byteRangeEnd = end;
11175
- if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
11176
- // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
11126
+ if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
11127
+ // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
11177
11128
  // has the unencrypted size specified in the range.
11178
11129
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
11179
11130
  var fragmentLen = end - start;
@@ -11206,9 +11157,6 @@
11206
11157
  (part ? part : frag).stats.aborted = true;
11207
11158
  return new LoadError(errorData);
11208
11159
  }
11209
- function isMethodFullSegmentAesCbc(method) {
11210
- return method === 'AES-128' || method === 'AES-256';
11211
- }
11212
11160
  var LoadError = /*#__PURE__*/function (_Error) {
11213
11161
  _inheritsLoose(LoadError, _Error);
11214
11162
  function LoadError(data) {
@@ -11365,8 +11313,6 @@
11365
11313
  }
11366
11314
  return this.loadKeyEME(keyInfo, frag);
11367
11315
  case 'AES-128':
11368
- case 'AES-256':
11369
- case 'AES-256-CTR':
11370
11316
  return this.loadKeyHTTP(keyInfo, frag);
11371
11317
  default:
11372
11318
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
@@ -11500,17 +11446,13 @@
11500
11446
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
11501
11447
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
11502
11448
  */
11503
- var TaskLoop = /*#__PURE__*/function (_Logger) {
11504
- _inheritsLoose(TaskLoop, _Logger);
11505
- function TaskLoop(label, logger) {
11506
- var _this;
11507
- _this = _Logger.call(this, label, logger) || this;
11508
- _this._boundTick = void 0;
11509
- _this._tickTimer = null;
11510
- _this._tickInterval = null;
11511
- _this._tickCallCount = 0;
11512
- _this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
11513
- return _this;
11449
+ var TaskLoop = /*#__PURE__*/function () {
11450
+ function TaskLoop() {
11451
+ this._boundTick = void 0;
11452
+ this._tickTimer = null;
11453
+ this._tickInterval = null;
11454
+ this._tickCallCount = 0;
11455
+ this._boundTick = this.tick.bind(this);
11514
11456
  }
11515
11457
  var _proto = TaskLoop.prototype;
11516
11458
  _proto.destroy = function destroy() {
@@ -11596,7 +11538,7 @@
11596
11538
  */;
11597
11539
  _proto.doTick = function doTick() {};
11598
11540
  return TaskLoop;
11599
- }(Logger);
11541
+ }();
11600
11542
 
11601
11543
  var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
11602
11544
  if (size === void 0) {
@@ -11782,65 +11724,37 @@
11782
11724
  }
11783
11725
 
11784
11726
  var AESCrypto = /*#__PURE__*/function () {
11785
- function AESCrypto(subtle, iv, aesMode) {
11727
+ function AESCrypto(subtle, iv) {
11786
11728
  this.subtle = void 0;
11787
11729
  this.aesIV = void 0;
11788
- this.aesMode = void 0;
11789
11730
  this.subtle = subtle;
11790
11731
  this.aesIV = iv;
11791
- this.aesMode = aesMode;
11792
11732
  }
11793
11733
  var _proto = AESCrypto.prototype;
11794
11734
  _proto.decrypt = function decrypt(data, key) {
11795
- switch (this.aesMode) {
11796
- case DecrypterAesMode.cbc:
11797
- return this.subtle.decrypt({
11798
- name: 'AES-CBC',
11799
- iv: this.aesIV
11800
- }, key, data);
11801
- case DecrypterAesMode.ctr:
11802
- return this.subtle.decrypt({
11803
- name: 'AES-CTR',
11804
- counter: this.aesIV,
11805
- length: 64
11806
- },
11807
- //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
11808
- key, data);
11809
- default:
11810
- throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
11811
- }
11735
+ return this.subtle.decrypt({
11736
+ name: 'AES-CBC',
11737
+ iv: this.aesIV
11738
+ }, key, data);
11812
11739
  };
11813
11740
  return AESCrypto;
11814
11741
  }();
11815
11742
 
11816
11743
  var FastAESKey = /*#__PURE__*/function () {
11817
- function FastAESKey(subtle, key, aesMode) {
11744
+ function FastAESKey(subtle, key) {
11818
11745
  this.subtle = void 0;
11819
11746
  this.key = void 0;
11820
- this.aesMode = void 0;
11821
11747
  this.subtle = subtle;
11822
11748
  this.key = key;
11823
- this.aesMode = aesMode;
11824
11749
  }
11825
11750
  var _proto = FastAESKey.prototype;
11826
11751
  _proto.expandKey = function expandKey() {
11827
- var subtleAlgoName = getSubtleAlgoName(this.aesMode);
11828
11752
  return this.subtle.importKey('raw', this.key, {
11829
- name: subtleAlgoName
11753
+ name: 'AES-CBC'
11830
11754
  }, false, ['encrypt', 'decrypt']);
11831
11755
  };
11832
11756
  return FastAESKey;
11833
11757
  }();
11834
- function getSubtleAlgoName(aesMode) {
11835
- switch (aesMode) {
11836
- case DecrypterAesMode.cbc:
11837
- return 'AES-CBC';
11838
- case DecrypterAesMode.ctr:
11839
- return 'AES-CTR';
11840
- default:
11841
- throw new Error("[FastAESKey] invalid aes mode " + aesMode);
11842
- }
11843
- }
11844
11758
 
11845
11759
  // PKCS7
11846
11760
  function removePadding(array) {
@@ -12093,8 +12007,7 @@
12093
12007
  this.currentIV = null;
12094
12008
  this.currentResult = null;
12095
12009
  this.useSoftware = void 0;
12096
- this.enableSoftwareAES = void 0;
12097
- this.enableSoftwareAES = config.enableSoftwareAES;
12010
+ this.useSoftware = config.enableSoftwareAES;
12098
12011
  this.removePKCS7Padding = removePKCS7Padding;
12099
12012
  // built in decryptor expects PKCS7 padding
12100
12013
  if (removePKCS7Padding) {
@@ -12107,7 +12020,9 @@
12107
12020
  /* no-op */
12108
12021
  }
12109
12022
  }
12110
- this.useSoftware = this.subtle === null;
12023
+ if (this.subtle === null) {
12024
+ this.useSoftware = true;
12025
+ }
12111
12026
  }
12112
12027
  var _proto = Decrypter.prototype;
12113
12028
  _proto.destroy = function destroy() {
@@ -12144,11 +12059,11 @@
12144
12059
  this.softwareDecrypter = null;
12145
12060
  }
12146
12061
  };
12147
- _proto.decrypt = function decrypt(data, key, iv, aesMode) {
12062
+ _proto.decrypt = function decrypt(data, key, iv) {
12148
12063
  var _this = this;
12149
12064
  if (this.useSoftware) {
12150
12065
  return new Promise(function (resolve, reject) {
12151
- _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
12066
+ _this.softwareDecrypt(new Uint8Array(data), key, iv);
12152
12067
  var decryptResult = _this.flush();
12153
12068
  if (decryptResult) {
12154
12069
  resolve(decryptResult.buffer);
@@ -12157,20 +12072,16 @@
12157
12072
  }
12158
12073
  });
12159
12074
  }
12160
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
12075
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
12161
12076
  }
12162
12077
 
12163
12078
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
12164
12079
  // data is handled in the flush() call
12165
12080
  ;
12166
- _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
12081
+ _proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
12167
12082
  var currentIV = this.currentIV,
12168
12083
  currentResult = this.currentResult,
12169
12084
  remainderData = this.remainderData;
12170
- if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
12171
- logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
12172
- return null;
12173
- }
12174
12085
  this.logOnce('JS AES decrypt');
12175
12086
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
12176
12087
  // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
@@ -12203,12 +12114,12 @@
12203
12114
  }
12204
12115
  return result;
12205
12116
  };
12206
- _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
12117
+ _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
12207
12118
  var _this2 = this;
12208
12119
  var subtle = this.subtle;
12209
12120
  if (this.key !== key || !this.fastAesKey) {
12210
12121
  this.key = key;
12211
- this.fastAesKey = new FastAESKey(subtle, key, aesMode);
12122
+ this.fastAesKey = new FastAESKey(subtle, key);
12212
12123
  }
12213
12124
  return this.fastAesKey.expandKey().then(function (aesKey) {
12214
12125
  // decrypt using web crypto
@@ -12216,25 +12127,22 @@
12216
12127
  return Promise.reject(new Error('web crypto not initialized'));
12217
12128
  }
12218
12129
  _this2.logOnce('WebCrypto AES decrypt');
12219
- var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
12130
+ var crypto = new AESCrypto(subtle, new Uint8Array(iv));
12220
12131
  return crypto.decrypt(data.buffer, aesKey);
12221
12132
  }).catch(function (err) {
12222
12133
  logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
12223
- return _this2.onWebCryptoError(data, key, iv, aesMode);
12134
+ return _this2.onWebCryptoError(data, key, iv);
12224
12135
  });
12225
12136
  };
12226
- _proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
12227
- var enableSoftwareAES = this.enableSoftwareAES;
12228
- if (enableSoftwareAES) {
12229
- this.useSoftware = true;
12230
- this.logEnabled = true;
12231
- this.softwareDecrypt(data, key, iv, aesMode);
12232
- var decryptResult = this.flush();
12233
- if (decryptResult) {
12234
- return decryptResult.buffer;
12235
- }
12137
+ _proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
12138
+ this.useSoftware = true;
12139
+ this.logEnabled = true;
12140
+ this.softwareDecrypt(data, key, iv);
12141
+ var decryptResult = this.flush();
12142
+ if (decryptResult) {
12143
+ return decryptResult.buffer;
12236
12144
  }
12237
- throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
12145
+ throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
12238
12146
  };
12239
12147
  _proto.getValidChunk = function getValidChunk(data) {
12240
12148
  var currentChunk = data;
@@ -12288,7 +12196,7 @@
12288
12196
  _inheritsLoose(BaseStreamController, _TaskLoop);
12289
12197
  function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
12290
12198
  var _this;
12291
- _this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
12199
+ _this = _TaskLoop.call(this) || this;
12292
12200
  _this.hls = void 0;
12293
12201
  _this.fragPrevious = null;
12294
12202
  _this.fragCurrent = null;
@@ -12313,96 +12221,25 @@
12313
12221
  _this.startFragRequested = false;
12314
12222
  _this.decrypter = void 0;
12315
12223
  _this.initPTS = [];
12316
- _this.buffering = true;
12317
- _this.loadingParts = false;
12318
- _this.onMediaSeeking = function () {
12319
- var _assertThisInitialize = _assertThisInitialized(_this),
12320
- config = _assertThisInitialize.config,
12321
- fragCurrent = _assertThisInitialize.fragCurrent,
12322
- media = _assertThisInitialize.media,
12323
- mediaBuffer = _assertThisInitialize.mediaBuffer,
12324
- state = _assertThisInitialize.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
- if (!_this.loadingParts) {
12354
- var bufferEnd = Math.max(bufferInfo.end, currentTime);
12355
- var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
12356
- if (shouldLoadParts) {
12357
- _this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
12358
- _this.loadingParts = shouldLoadParts;
12359
- }
12360
- }
12361
- }
12362
-
12363
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12364
- if (!_this.loadedmetadata && !bufferInfo.len) {
12365
- _this.nextLoadPosition = _this.startPosition = currentTime;
12366
- }
12367
-
12368
- // Async tick to speed up processing
12369
- _this.tickImmediate();
12370
- };
12371
- _this.onMediaEnded = function () {
12372
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12373
- _this.startPosition = _this.lastCurrentTime = 0;
12374
- if (_this.playlistType === PlaylistLevelType.MAIN) {
12375
- _this.hls.trigger(Events.MEDIA_ENDED, {
12376
- stalled: false
12377
- });
12378
- }
12379
- };
12224
+ _this.onvseeking = null;
12225
+ _this.onvended = null;
12226
+ _this.logPrefix = '';
12227
+ _this.log = void 0;
12228
+ _this.warn = void 0;
12380
12229
  _this.playlistType = playlistType;
12230
+ _this.logPrefix = logPrefix;
12231
+ _this.log = logger.log.bind(logger, logPrefix + ":");
12232
+ _this.warn = logger.warn.bind(logger, logPrefix + ":");
12381
12233
  _this.hls = hls;
12382
12234
  _this.fragmentLoader = new FragmentLoader(hls.config);
12383
12235
  _this.keyLoader = keyLoader;
12384
12236
  _this.fragmentTracker = fragmentTracker;
12385
12237
  _this.config = hls.config;
12386
12238
  _this.decrypter = new Decrypter(hls.config);
12239
+ hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
12387
12240
  return _this;
12388
12241
  }
12389
12242
  var _proto = BaseStreamController.prototype;
12390
- _proto.registerListeners = function registerListeners() {
12391
- var hls = this.hls;
12392
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12393
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12394
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12395
- hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12396
- hls.on(Events.ERROR, this.onError, this);
12397
- };
12398
- _proto.unregisterListeners = function unregisterListeners() {
12399
- var hls = this.hls;
12400
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12401
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12402
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12403
- hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12404
- hls.off(Events.ERROR, this.onError, this);
12405
- };
12406
12243
  _proto.doTick = function doTick() {
12407
12244
  this.onTickEnd();
12408
12245
  };
@@ -12426,12 +12263,6 @@
12426
12263
  this.clearNextTick();
12427
12264
  this.state = State.STOPPED;
12428
12265
  };
12429
- _proto.pauseBuffering = function pauseBuffering() {
12430
- this.buffering = false;
12431
- };
12432
- _proto.resumeBuffering = function resumeBuffering() {
12433
- this.buffering = true;
12434
- };
12435
12266
  _proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
12436
12267
  // If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
12437
12268
  // of nothing loading/loaded return false
@@ -12462,8 +12293,10 @@
12462
12293
  };
12463
12294
  _proto.onMediaAttached = function onMediaAttached(event, data) {
12464
12295
  var media = this.media = this.mediaBuffer = data.media;
12465
- media.addEventListener('seeking', this.onMediaSeeking);
12466
- media.addEventListener('ended', this.onMediaEnded);
12296
+ this.onvseeking = this.onMediaSeeking.bind(this);
12297
+ this.onvended = this.onMediaEnded.bind(this);
12298
+ media.addEventListener('seeking', this.onvseeking);
12299
+ media.addEventListener('ended', this.onvended);
12467
12300
  var config = this.config;
12468
12301
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12469
12302
  this.startLoad(config.startPosition);
@@ -12477,9 +12310,10 @@
12477
12310
  }
12478
12311
 
12479
12312
  // remove video listeners
12480
- if (media) {
12481
- media.removeEventListener('seeking', this.onMediaSeeking);
12482
- media.removeEventListener('ended', this.onMediaEnded);
12313
+ if (media && this.onvseeking && this.onvended) {
12314
+ media.removeEventListener('seeking', this.onvseeking);
12315
+ media.removeEventListener('ended', this.onvended);
12316
+ this.onvseeking = this.onvended = null;
12483
12317
  }
12484
12318
  if (this.keyLoader) {
12485
12319
  this.keyLoader.detach();
@@ -12489,8 +12323,54 @@
12489
12323
  this.fragmentTracker.removeAllFragments();
12490
12324
  this.stopLoad();
12491
12325
  };
12492
- _proto.onManifestLoading = function onManifestLoading() {};
12493
- _proto.onError = function onError(event, data) {};
12326
+ _proto.onMediaSeeking = function onMediaSeeking() {
12327
+ var config = this.config,
12328
+ fragCurrent = this.fragCurrent,
12329
+ media = this.media,
12330
+ mediaBuffer = this.mediaBuffer,
12331
+ state = this.state;
12332
+ var currentTime = media ? media.currentTime : 0;
12333
+ var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12334
+ this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12335
+ if (this.state === State.ENDED) {
12336
+ this.resetLoadingState();
12337
+ } else if (fragCurrent) {
12338
+ // Seeking while frag load is in progress
12339
+ var tolerance = config.maxFragLookUpTolerance;
12340
+ var fragStartOffset = fragCurrent.start - tolerance;
12341
+ var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12342
+ // if seeking out of buffered range or into new one
12343
+ if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12344
+ var pastFragment = currentTime > fragEndOffset;
12345
+ // if the seek position is outside the current fragment range
12346
+ if (currentTime < fragStartOffset || pastFragment) {
12347
+ if (pastFragment && fragCurrent.loader) {
12348
+ this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12349
+ fragCurrent.abortRequests();
12350
+ this.resetLoadingState();
12351
+ }
12352
+ this.fragPrevious = null;
12353
+ }
12354
+ }
12355
+ }
12356
+ if (media) {
12357
+ // Remove gap fragments
12358
+ this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
12359
+ this.lastCurrentTime = currentTime;
12360
+ }
12361
+
12362
+ // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12363
+ if (!this.loadedmetadata && !bufferInfo.len) {
12364
+ this.nextLoadPosition = this.startPosition = currentTime;
12365
+ }
12366
+
12367
+ // Async tick to speed up processing
12368
+ this.tickImmediate();
12369
+ };
12370
+ _proto.onMediaEnded = function onMediaEnded() {
12371
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12372
+ this.startPosition = this.lastCurrentTime = 0;
12373
+ };
12494
12374
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
12495
12375
  this.startTimeOffset = data.startTimeOffset;
12496
12376
  this.initPTS = [];
@@ -12500,7 +12380,7 @@
12500
12380
  this.stopLoad();
12501
12381
  _TaskLoop.prototype.onHandlerDestroying.call(this);
12502
12382
  // @ts-ignore
12503
- this.hls = this.onMediaSeeking = this.onMediaEnded = null;
12383
+ this.hls = null;
12504
12384
  };
12505
12385
  _proto.onHandlerDestroyed = function onHandlerDestroyed() {
12506
12386
  this.state = State.STOPPED;
@@ -12630,10 +12510,10 @@
12630
12510
  var decryptData = frag.decryptdata;
12631
12511
 
12632
12512
  // check to see if the payload needs to be decrypted
12633
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
12513
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
12634
12514
  var startTime = self.performance.now();
12635
12515
  // decrypt init segment data
12636
- return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
12516
+ return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
12637
12517
  hls.trigger(Events.ERROR, {
12638
12518
  type: ErrorTypes.MEDIA_ERROR,
12639
12519
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -12746,7 +12626,7 @@
12746
12626
  }
12747
12627
  var keyLoadingPromise = null;
12748
12628
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
12749
- this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
12629
+ this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + " " + frag.level);
12750
12630
  this.state = State.KEY_LOADING;
12751
12631
  this.fragCurrent = frag;
12752
12632
  keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
@@ -12767,16 +12647,8 @@
12767
12647
  } else if (!frag.encrypted && details.encryptedFragments.length) {
12768
12648
  this.keyLoader.loadClear(frag, details.encryptedFragments);
12769
12649
  }
12770
- var fragPrevious = this.fragPrevious;
12771
- if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
12772
- var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
12773
- if (shouldLoadParts !== this.loadingParts) {
12774
- this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
12775
- this.loadingParts = shouldLoadParts;
12776
- }
12777
- }
12778
12650
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
12779
- if (this.loadingParts && frag.sn !== 'initSegment') {
12651
+ if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
12780
12652
  var partList = details.partList;
12781
12653
  if (partList && progressCallback) {
12782
12654
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -12785,7 +12657,7 @@
12785
12657
  var partIndex = this.getNextPart(partList, frag, targetBufferTime);
12786
12658
  if (partIndex > -1) {
12787
12659
  var part = partList[partIndex];
12788
- 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)));
12660
+ 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)));
12789
12661
  this.nextLoadPosition = part.start + part.duration;
12790
12662
  this.state = State.FRAG_LOADING;
12791
12663
  var _result;
@@ -12818,14 +12690,7 @@
12818
12690
  }
12819
12691
  }
12820
12692
  }
12821
- if (frag.sn !== 'initSegment' && this.loadingParts) {
12822
- this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
12823
- this.loadingParts = false;
12824
- } else if (!frag.url) {
12825
- // Selected fragment hint for part but not loading parts
12826
- return Promise.resolve(null);
12827
- }
12828
- 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)));
12693
+ 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)));
12829
12694
  // Don't update nextLoadPosition for fragments which are not buffered
12830
12695
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
12831
12696
  this.nextLoadPosition = frag.start + frag.duration;
@@ -12927,36 +12792,8 @@
12927
12792
  if (part) {
12928
12793
  part.stats.parsing.end = now;
12929
12794
  }
12930
- // See if part loading should be disabled/enabled based on buffer and playback position.
12931
- if (frag.sn !== 'initSegment') {
12932
- var levelDetails = this.getLevelDetails();
12933
- var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
12934
- var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
12935
- if (shouldLoadParts !== this.loadingParts) {
12936
- this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
12937
- this.loadingParts = shouldLoadParts;
12938
- }
12939
- }
12940
12795
  this.updateLevelTiming(frag, part, level, chunkMeta.partial);
12941
12796
  };
12942
- _proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
12943
- if (this.config.lowLatencyMode) {
12944
- if (!details) {
12945
- return this.loadingParts;
12946
- }
12947
- if (details != null && details.partList) {
12948
- var _details$fragmentHint;
12949
- // Buffer must be ahead of first part + duration of parts after last segment
12950
- // and playback must be at or past segment adjacent to part list
12951
- var firstPart = details.partList[0];
12952
- var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
12953
- if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
12954
- return true;
12955
- }
12956
- }
12957
- }
12958
- return false;
12959
- };
12960
12797
  _proto.getCurrentContext = function getCurrentContext(chunkMeta) {
12961
12798
  var levels = this.levels,
12962
12799
  fragCurrent = this.fragCurrent;
@@ -13091,8 +12928,7 @@
13091
12928
  // find fragment index, contiguous with end of buffer position
13092
12929
  var config = this.config;
13093
12930
  var start = fragments[0].start;
13094
- var canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
13095
- var frag = null;
12931
+ var frag;
13096
12932
  if (levelDetails.live) {
13097
12933
  var initialLiveManifestSize = config.initialLiveManifestSize;
13098
12934
  if (fragLen < initialLiveManifestSize) {
@@ -13104,10 +12940,6 @@
13104
12940
  // Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
13105
12941
  // we get the fragment matching that start time
13106
12942
  if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
13107
- if (canLoadParts && !this.loadingParts) {
13108
- this.log("LL-Part loading ON for initial live fragment");
13109
- this.loadingParts = true;
13110
- }
13111
12943
  frag = this.getInitialLiveFragment(levelDetails, fragments);
13112
12944
  this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
13113
12945
  }
@@ -13118,7 +12950,7 @@
13118
12950
 
13119
12951
  // If we haven't run into any special cases already, just load the fragment most closely matching the requested position
13120
12952
  if (!frag) {
13121
- var end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
12953
+ var end = config.lowLatencyMode ? levelDetails.partEnd : levelDetails.fragmentEnd;
13122
12954
  frag = this.getFragmentAtPosition(pos, end, levelDetails);
13123
12955
  }
13124
12956
  return this.mapToInitFragWhenRequired(frag);
@@ -13232,7 +13064,7 @@
13232
13064
  var fragmentHint = levelDetails.fragmentHint;
13233
13065
  var tolerance = config.maxFragLookUpTolerance;
13234
13066
  var partList = levelDetails.partList;
13235
- var loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
13067
+ var loadingParts = !!(config.lowLatencyMode && partList != null && partList.length && fragmentHint);
13236
13068
  if (loadingParts && fragmentHint && !this.bitrateTest) {
13237
13069
  // Include incomplete fragment with parts at end
13238
13070
  fragments = fragments.concat(fragmentHint);
@@ -13419,7 +13251,7 @@
13419
13251
  errorAction.resolved = true;
13420
13252
  }
13421
13253
  } else {
13422
- this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13254
+ logger.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13423
13255
  return;
13424
13256
  }
13425
13257
  } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
@@ -13809,7 +13641,6 @@
13809
13641
  */
13810
13642
  function getAudioConfig(observer, data, offset, audioCodec) {
13811
13643
  var adtsObjectType;
13812
- var originalAdtsObjectType;
13813
13644
  var adtsExtensionSamplingIndex;
13814
13645
  var adtsChannelConfig;
13815
13646
  var config;
@@ -13817,7 +13648,7 @@
13817
13648
  var manifestCodec = audioCodec;
13818
13649
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
13819
13650
  // byte 2
13820
- adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13651
+ adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13821
13652
  var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
13822
13653
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
13823
13654
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
@@ -13834,8 +13665,8 @@
13834
13665
  // byte 3
13835
13666
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
13836
13667
  logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
13837
- // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
13838
- if (/firefox|palemoon/i.test(userAgent)) {
13668
+ // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
13669
+ if (/firefox/i.test(userAgent)) {
13839
13670
  if (adtsSamplingIndex >= 6) {
13840
13671
  adtsObjectType = 5;
13841
13672
  config = new Array(4);
@@ -13929,7 +13760,6 @@
13929
13760
  samplerate: adtsSamplingRates[adtsSamplingIndex],
13930
13761
  channelCount: adtsChannelConfig,
13931
13762
  codec: 'mp4a.40.' + adtsObjectType,
13932
- parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
13933
13763
  manifestCodec: manifestCodec
13934
13764
  };
13935
13765
  }
@@ -13984,8 +13814,7 @@
13984
13814
  track.channelCount = config.channelCount;
13985
13815
  track.codec = config.codec;
13986
13816
  track.manifestCodec = config.manifestCodec;
13987
- track.parsedCodec = config.parsedCodec;
13988
- logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13817
+ logger.log("parsed codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13989
13818
  }
13990
13819
  }
13991
13820
  function getFrameDuration(samplerate) {
@@ -14465,110 +14294,6 @@
14465
14294
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
14466
14295
  }
14467
14296
  };
14468
- _proto.parseNALu = function parseNALu(track, array) {
14469
- var len = array.byteLength;
14470
- var state = track.naluState || 0;
14471
- var lastState = state;
14472
- var units = [];
14473
- var i = 0;
14474
- var value;
14475
- var overflow;
14476
- var unitType;
14477
- var lastUnitStart = -1;
14478
- var lastUnitType = 0;
14479
- // logger.log('PES:' + Hex.hexDump(array));
14480
-
14481
- if (state === -1) {
14482
- // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14483
- lastUnitStart = 0;
14484
- // NALu type is value read from offset 0
14485
- lastUnitType = this.getNALuType(array, 0);
14486
- state = 0;
14487
- i = 1;
14488
- }
14489
- while (i < len) {
14490
- value = array[i++];
14491
- // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14492
- if (!state) {
14493
- state = value ? 0 : 1;
14494
- continue;
14495
- }
14496
- if (state === 1) {
14497
- state = value ? 0 : 2;
14498
- continue;
14499
- }
14500
- // here we have state either equal to 2 or 3
14501
- if (!value) {
14502
- state = 3;
14503
- } else if (value === 1) {
14504
- overflow = i - state - 1;
14505
- if (lastUnitStart >= 0) {
14506
- var unit = {
14507
- data: array.subarray(lastUnitStart, overflow),
14508
- type: lastUnitType
14509
- };
14510
- // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14511
- units.push(unit);
14512
- } else {
14513
- // lastUnitStart is undefined => this is the first start code found in this PES packet
14514
- // first check if start code delimiter is overlapping between 2 PES packets,
14515
- // ie it started in last packet (lastState not zero)
14516
- // and ended at the beginning of this PES packet (i <= 4 - lastState)
14517
- var lastUnit = this.getLastNalUnit(track.samples);
14518
- if (lastUnit) {
14519
- if (lastState && i <= 4 - lastState) {
14520
- // start delimiter overlapping between PES packets
14521
- // strip start delimiter bytes from the end of last NAL unit
14522
- // check if lastUnit had a state different from zero
14523
- if (lastUnit.state) {
14524
- // strip last bytes
14525
- lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
14526
- }
14527
- }
14528
- // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
14529
-
14530
- if (overflow > 0) {
14531
- // logger.log('first NALU found with overflow:' + overflow);
14532
- lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14533
- lastUnit.state = 0;
14534
- }
14535
- }
14536
- }
14537
- // check if we can read unit type
14538
- if (i < len) {
14539
- unitType = this.getNALuType(array, i);
14540
- // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14541
- lastUnitStart = i;
14542
- lastUnitType = unitType;
14543
- state = 0;
14544
- } else {
14545
- // not enough byte to read unit type. let's read it on next PES parsing
14546
- state = -1;
14547
- }
14548
- } else {
14549
- state = 0;
14550
- }
14551
- }
14552
- if (lastUnitStart >= 0 && state >= 0) {
14553
- var _unit = {
14554
- data: array.subarray(lastUnitStart, len),
14555
- type: lastUnitType,
14556
- state: state
14557
- };
14558
- units.push(_unit);
14559
- // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14560
- }
14561
- // no NALu found
14562
- if (units.length === 0) {
14563
- // append pes.data to previous NAL unit
14564
- var _lastUnit = this.getLastNalUnit(track.samples);
14565
- if (_lastUnit) {
14566
- _lastUnit.data = appendUint8Array(_lastUnit.data, array);
14567
- }
14568
- }
14569
- track.naluState = state;
14570
- return units;
14571
- };
14572
14297
  return BaseVideoParser;
14573
14298
  }();
14574
14299
 
@@ -14723,6 +14448,189 @@
14723
14448
  ;
14724
14449
  _proto.readUInt = function readUInt() {
14725
14450
  return this.readBits(32);
14451
+ }
14452
+
14453
+ /**
14454
+ * Advance the ExpGolomb decoder past a scaling list. The scaling
14455
+ * list is optionally transmitted as part of a sequence parameter
14456
+ * set and is not relevant to transmuxing.
14457
+ * @param count the number of entries in this scaling list
14458
+ * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
14459
+ */;
14460
+ _proto.skipScalingList = function skipScalingList(count) {
14461
+ var lastScale = 8;
14462
+ var nextScale = 8;
14463
+ var deltaScale;
14464
+ for (var j = 0; j < count; j++) {
14465
+ if (nextScale !== 0) {
14466
+ deltaScale = this.readEG();
14467
+ nextScale = (lastScale + deltaScale + 256) % 256;
14468
+ }
14469
+ lastScale = nextScale === 0 ? lastScale : nextScale;
14470
+ }
14471
+ }
14472
+
14473
+ /**
14474
+ * Read a sequence parameter set and return some interesting video
14475
+ * properties. A sequence parameter set is the H264 metadata that
14476
+ * describes the properties of upcoming video frames.
14477
+ * @returns an object with configuration parsed from the
14478
+ * sequence parameter set, including the dimensions of the
14479
+ * associated video frames.
14480
+ */;
14481
+ _proto.readSPS = function readSPS() {
14482
+ var frameCropLeftOffset = 0;
14483
+ var frameCropRightOffset = 0;
14484
+ var frameCropTopOffset = 0;
14485
+ var frameCropBottomOffset = 0;
14486
+ var numRefFramesInPicOrderCntCycle;
14487
+ var scalingListCount;
14488
+ var i;
14489
+ var readUByte = this.readUByte.bind(this);
14490
+ var readBits = this.readBits.bind(this);
14491
+ var readUEG = this.readUEG.bind(this);
14492
+ var readBoolean = this.readBoolean.bind(this);
14493
+ var skipBits = this.skipBits.bind(this);
14494
+ var skipEG = this.skipEG.bind(this);
14495
+ var skipUEG = this.skipUEG.bind(this);
14496
+ var skipScalingList = this.skipScalingList.bind(this);
14497
+ readUByte();
14498
+ var profileIdc = readUByte(); // profile_idc
14499
+ readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
14500
+ skipBits(3); // reserved_zero_3bits u(3),
14501
+ readUByte(); // level_idc u(8)
14502
+ skipUEG(); // seq_parameter_set_id
14503
+ // some profiles have more optional data we don't need
14504
+ if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
14505
+ var chromaFormatIdc = readUEG();
14506
+ if (chromaFormatIdc === 3) {
14507
+ skipBits(1);
14508
+ } // separate_colour_plane_flag
14509
+
14510
+ skipUEG(); // bit_depth_luma_minus8
14511
+ skipUEG(); // bit_depth_chroma_minus8
14512
+ skipBits(1); // qpprime_y_zero_transform_bypass_flag
14513
+ if (readBoolean()) {
14514
+ // seq_scaling_matrix_present_flag
14515
+ scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
14516
+ for (i = 0; i < scalingListCount; i++) {
14517
+ if (readBoolean()) {
14518
+ // seq_scaling_list_present_flag[ i ]
14519
+ if (i < 6) {
14520
+ skipScalingList(16);
14521
+ } else {
14522
+ skipScalingList(64);
14523
+ }
14524
+ }
14525
+ }
14526
+ }
14527
+ }
14528
+ skipUEG(); // log2_max_frame_num_minus4
14529
+ var picOrderCntType = readUEG();
14530
+ if (picOrderCntType === 0) {
14531
+ readUEG(); // log2_max_pic_order_cnt_lsb_minus4
14532
+ } else if (picOrderCntType === 1) {
14533
+ skipBits(1); // delta_pic_order_always_zero_flag
14534
+ skipEG(); // offset_for_non_ref_pic
14535
+ skipEG(); // offset_for_top_to_bottom_field
14536
+ numRefFramesInPicOrderCntCycle = readUEG();
14537
+ for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
14538
+ skipEG();
14539
+ } // offset_for_ref_frame[ i ]
14540
+ }
14541
+ skipUEG(); // max_num_ref_frames
14542
+ skipBits(1); // gaps_in_frame_num_value_allowed_flag
14543
+ var picWidthInMbsMinus1 = readUEG();
14544
+ var picHeightInMapUnitsMinus1 = readUEG();
14545
+ var frameMbsOnlyFlag = readBits(1);
14546
+ if (frameMbsOnlyFlag === 0) {
14547
+ skipBits(1);
14548
+ } // mb_adaptive_frame_field_flag
14549
+
14550
+ skipBits(1); // direct_8x8_inference_flag
14551
+ if (readBoolean()) {
14552
+ // frame_cropping_flag
14553
+ frameCropLeftOffset = readUEG();
14554
+ frameCropRightOffset = readUEG();
14555
+ frameCropTopOffset = readUEG();
14556
+ frameCropBottomOffset = readUEG();
14557
+ }
14558
+ var pixelRatio = [1, 1];
14559
+ if (readBoolean()) {
14560
+ // vui_parameters_present_flag
14561
+ if (readBoolean()) {
14562
+ // aspect_ratio_info_present_flag
14563
+ var aspectRatioIdc = readUByte();
14564
+ switch (aspectRatioIdc) {
14565
+ case 1:
14566
+ pixelRatio = [1, 1];
14567
+ break;
14568
+ case 2:
14569
+ pixelRatio = [12, 11];
14570
+ break;
14571
+ case 3:
14572
+ pixelRatio = [10, 11];
14573
+ break;
14574
+ case 4:
14575
+ pixelRatio = [16, 11];
14576
+ break;
14577
+ case 5:
14578
+ pixelRatio = [40, 33];
14579
+ break;
14580
+ case 6:
14581
+ pixelRatio = [24, 11];
14582
+ break;
14583
+ case 7:
14584
+ pixelRatio = [20, 11];
14585
+ break;
14586
+ case 8:
14587
+ pixelRatio = [32, 11];
14588
+ break;
14589
+ case 9:
14590
+ pixelRatio = [80, 33];
14591
+ break;
14592
+ case 10:
14593
+ pixelRatio = [18, 11];
14594
+ break;
14595
+ case 11:
14596
+ pixelRatio = [15, 11];
14597
+ break;
14598
+ case 12:
14599
+ pixelRatio = [64, 33];
14600
+ break;
14601
+ case 13:
14602
+ pixelRatio = [160, 99];
14603
+ break;
14604
+ case 14:
14605
+ pixelRatio = [4, 3];
14606
+ break;
14607
+ case 15:
14608
+ pixelRatio = [3, 2];
14609
+ break;
14610
+ case 16:
14611
+ pixelRatio = [2, 1];
14612
+ break;
14613
+ case 255:
14614
+ {
14615
+ pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
14616
+ break;
14617
+ }
14618
+ }
14619
+ }
14620
+ }
14621
+ return {
14622
+ width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
14623
+ height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
14624
+ pixelRatio: pixelRatio
14625
+ };
14626
+ };
14627
+ _proto.readSliceType = function readSliceType() {
14628
+ // skip NALu type
14629
+ this.readUByte();
14630
+ // discard first_mb_in_slice
14631
+ this.readUEG();
14632
+ // return slice_type
14633
+ return this.readUEG();
14726
14634
  };
14727
14635
  return ExpGolomb;
14728
14636
  }();
@@ -14733,9 +14641,9 @@
14733
14641
  return _BaseVideoParser.apply(this, arguments) || this;
14734
14642
  }
14735
14643
  var _proto = AvcVideoParser.prototype;
14736
- _proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
14644
+ _proto.parseAVCPES = function parseAVCPES(track, textTrack, pes, last, duration) {
14737
14645
  var _this = this;
14738
- var units = this.parseNALu(track, pes.data);
14646
+ var units = this.parseAVCNALu(track, pes.data);
14739
14647
  var VideoSample = this.VideoSample;
14740
14648
  var push;
14741
14649
  var spsfound = false;
@@ -14760,7 +14668,7 @@
14760
14668
  // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
14761
14669
  if (spsfound && data.length > 4) {
14762
14670
  // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
14763
- var sliceType = _this.readSliceType(data);
14671
+ var sliceType = new ExpGolomb(data).readSliceType();
14764
14672
  // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
14765
14673
  // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
14766
14674
  // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
@@ -14814,7 +14722,8 @@
14814
14722
  push = true;
14815
14723
  spsfound = true;
14816
14724
  var sps = unit.data;
14817
- var config = _this.readSPS(sps);
14725
+ var expGolombDecoder = new ExpGolomb(sps);
14726
+ var config = expGolombDecoder.readSPS();
14818
14727
  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]) {
14819
14728
  track.width = config.width;
14820
14729
  track.height = config.height;
@@ -14870,192 +14779,109 @@
14870
14779
  this.VideoSample = null;
14871
14780
  }
14872
14781
  };
14873
- _proto.getNALuType = function getNALuType(data, offset) {
14874
- return data[offset] & 0x1f;
14875
- };
14876
- _proto.readSliceType = function readSliceType(data) {
14877
- var eg = new ExpGolomb(data);
14878
- // skip NALu type
14879
- eg.readUByte();
14880
- // discard first_mb_in_slice
14881
- eg.readUEG();
14882
- // return slice_type
14883
- return eg.readUEG();
14884
- }
14782
+ _proto.parseAVCNALu = function parseAVCNALu(track, array) {
14783
+ var len = array.byteLength;
14784
+ var state = track.naluState || 0;
14785
+ var lastState = state;
14786
+ var units = [];
14787
+ var i = 0;
14788
+ var value;
14789
+ var overflow;
14790
+ var unitType;
14791
+ var lastUnitStart = -1;
14792
+ var lastUnitType = 0;
14793
+ // logger.log('PES:' + Hex.hexDump(array));
14885
14794
 
14886
- /**
14887
- * The scaling list is optionally transmitted as part of a sequence parameter
14888
- * set and is not relevant to transmuxing.
14889
- * @param count the number of entries in this scaling list
14890
- * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
14891
- */;
14892
- _proto.skipScalingList = function skipScalingList(count, reader) {
14893
- var lastScale = 8;
14894
- var nextScale = 8;
14895
- var deltaScale;
14896
- for (var j = 0; j < count; j++) {
14897
- if (nextScale !== 0) {
14898
- deltaScale = reader.readEG();
14899
- nextScale = (lastScale + deltaScale + 256) % 256;
14900
- }
14901
- lastScale = nextScale === 0 ? lastScale : nextScale;
14795
+ if (state === -1) {
14796
+ // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14797
+ lastUnitStart = 0;
14798
+ // NALu type is value read from offset 0
14799
+ lastUnitType = array[0] & 0x1f;
14800
+ state = 0;
14801
+ i = 1;
14902
14802
  }
14903
- }
14904
-
14905
- /**
14906
- * Read a sequence parameter set and return some interesting video
14907
- * properties. A sequence parameter set is the H264 metadata that
14908
- * describes the properties of upcoming video frames.
14909
- * @returns an object with configuration parsed from the
14910
- * sequence parameter set, including the dimensions of the
14911
- * associated video frames.
14912
- */;
14913
- _proto.readSPS = function readSPS(sps) {
14914
- var eg = new ExpGolomb(sps);
14915
- var frameCropLeftOffset = 0;
14916
- var frameCropRightOffset = 0;
14917
- var frameCropTopOffset = 0;
14918
- var frameCropBottomOffset = 0;
14919
- var numRefFramesInPicOrderCntCycle;
14920
- var scalingListCount;
14921
- var i;
14922
- var readUByte = eg.readUByte.bind(eg);
14923
- var readBits = eg.readBits.bind(eg);
14924
- var readUEG = eg.readUEG.bind(eg);
14925
- var readBoolean = eg.readBoolean.bind(eg);
14926
- var skipBits = eg.skipBits.bind(eg);
14927
- var skipEG = eg.skipEG.bind(eg);
14928
- var skipUEG = eg.skipUEG.bind(eg);
14929
- var skipScalingList = this.skipScalingList.bind(this);
14930
- readUByte();
14931
- var profileIdc = readUByte(); // profile_idc
14932
- readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
14933
- skipBits(3); // reserved_zero_3bits u(3),
14934
- readUByte(); // level_idc u(8)
14935
- skipUEG(); // seq_parameter_set_id
14936
- // some profiles have more optional data we don't need
14937
- if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
14938
- var chromaFormatIdc = readUEG();
14939
- if (chromaFormatIdc === 3) {
14940
- skipBits(1);
14941
- } // separate_colour_plane_flag
14803
+ while (i < len) {
14804
+ value = array[i++];
14805
+ // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14806
+ if (!state) {
14807
+ state = value ? 0 : 1;
14808
+ continue;
14809
+ }
14810
+ if (state === 1) {
14811
+ state = value ? 0 : 2;
14812
+ continue;
14813
+ }
14814
+ // here we have state either equal to 2 or 3
14815
+ if (!value) {
14816
+ state = 3;
14817
+ } else if (value === 1) {
14818
+ overflow = i - state - 1;
14819
+ if (lastUnitStart >= 0) {
14820
+ var unit = {
14821
+ data: array.subarray(lastUnitStart, overflow),
14822
+ type: lastUnitType
14823
+ };
14824
+ // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14825
+ units.push(unit);
14826
+ } else {
14827
+ // lastUnitStart is undefined => this is the first start code found in this PES packet
14828
+ // first check if start code delimiter is overlapping between 2 PES packets,
14829
+ // ie it started in last packet (lastState not zero)
14830
+ // and ended at the beginning of this PES packet (i <= 4 - lastState)
14831
+ var lastUnit = this.getLastNalUnit(track.samples);
14832
+ if (lastUnit) {
14833
+ if (lastState && i <= 4 - lastState) {
14834
+ // start delimiter overlapping between PES packets
14835
+ // strip start delimiter bytes from the end of last NAL unit
14836
+ // check if lastUnit had a state different from zero
14837
+ if (lastUnit.state) {
14838
+ // strip last bytes
14839
+ lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
14840
+ }
14841
+ }
14842
+ // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
14942
14843
 
14943
- skipUEG(); // bit_depth_luma_minus8
14944
- skipUEG(); // bit_depth_chroma_minus8
14945
- skipBits(1); // qpprime_y_zero_transform_bypass_flag
14946
- if (readBoolean()) {
14947
- // seq_scaling_matrix_present_flag
14948
- scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
14949
- for (i = 0; i < scalingListCount; i++) {
14950
- if (readBoolean()) {
14951
- // seq_scaling_list_present_flag[ i ]
14952
- if (i < 6) {
14953
- skipScalingList(16, eg);
14954
- } else {
14955
- skipScalingList(64, eg);
14844
+ if (overflow > 0) {
14845
+ // logger.log('first NALU found with overflow:' + overflow);
14846
+ lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14847
+ lastUnit.state = 0;
14956
14848
  }
14957
14849
  }
14958
14850
  }
14851
+ // check if we can read unit type
14852
+ if (i < len) {
14853
+ unitType = array[i] & 0x1f;
14854
+ // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14855
+ lastUnitStart = i;
14856
+ lastUnitType = unitType;
14857
+ state = 0;
14858
+ } else {
14859
+ // not enough byte to read unit type. let's read it on next PES parsing
14860
+ state = -1;
14861
+ }
14862
+ } else {
14863
+ state = 0;
14959
14864
  }
14960
14865
  }
14961
- skipUEG(); // log2_max_frame_num_minus4
14962
- var picOrderCntType = readUEG();
14963
- if (picOrderCntType === 0) {
14964
- readUEG(); // log2_max_pic_order_cnt_lsb_minus4
14965
- } else if (picOrderCntType === 1) {
14966
- skipBits(1); // delta_pic_order_always_zero_flag
14967
- skipEG(); // offset_for_non_ref_pic
14968
- skipEG(); // offset_for_top_to_bottom_field
14969
- numRefFramesInPicOrderCntCycle = readUEG();
14970
- for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
14971
- skipEG();
14972
- } // offset_for_ref_frame[ i ]
14973
- }
14974
- skipUEG(); // max_num_ref_frames
14975
- skipBits(1); // gaps_in_frame_num_value_allowed_flag
14976
- var picWidthInMbsMinus1 = readUEG();
14977
- var picHeightInMapUnitsMinus1 = readUEG();
14978
- var frameMbsOnlyFlag = readBits(1);
14979
- if (frameMbsOnlyFlag === 0) {
14980
- skipBits(1);
14981
- } // mb_adaptive_frame_field_flag
14982
-
14983
- skipBits(1); // direct_8x8_inference_flag
14984
- if (readBoolean()) {
14985
- // frame_cropping_flag
14986
- frameCropLeftOffset = readUEG();
14987
- frameCropRightOffset = readUEG();
14988
- frameCropTopOffset = readUEG();
14989
- frameCropBottomOffset = readUEG();
14866
+ if (lastUnitStart >= 0 && state >= 0) {
14867
+ var _unit = {
14868
+ data: array.subarray(lastUnitStart, len),
14869
+ type: lastUnitType,
14870
+ state: state
14871
+ };
14872
+ units.push(_unit);
14873
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14990
14874
  }
14991
- var pixelRatio = [1, 1];
14992
- if (readBoolean()) {
14993
- // vui_parameters_present_flag
14994
- if (readBoolean()) {
14995
- // aspect_ratio_info_present_flag
14996
- var aspectRatioIdc = readUByte();
14997
- switch (aspectRatioIdc) {
14998
- case 1:
14999
- pixelRatio = [1, 1];
15000
- break;
15001
- case 2:
15002
- pixelRatio = [12, 11];
15003
- break;
15004
- case 3:
15005
- pixelRatio = [10, 11];
15006
- break;
15007
- case 4:
15008
- pixelRatio = [16, 11];
15009
- break;
15010
- case 5:
15011
- pixelRatio = [40, 33];
15012
- break;
15013
- case 6:
15014
- pixelRatio = [24, 11];
15015
- break;
15016
- case 7:
15017
- pixelRatio = [20, 11];
15018
- break;
15019
- case 8:
15020
- pixelRatio = [32, 11];
15021
- break;
15022
- case 9:
15023
- pixelRatio = [80, 33];
15024
- break;
15025
- case 10:
15026
- pixelRatio = [18, 11];
15027
- break;
15028
- case 11:
15029
- pixelRatio = [15, 11];
15030
- break;
15031
- case 12:
15032
- pixelRatio = [64, 33];
15033
- break;
15034
- case 13:
15035
- pixelRatio = [160, 99];
15036
- break;
15037
- case 14:
15038
- pixelRatio = [4, 3];
15039
- break;
15040
- case 15:
15041
- pixelRatio = [3, 2];
15042
- break;
15043
- case 16:
15044
- pixelRatio = [2, 1];
15045
- break;
15046
- case 255:
15047
- {
15048
- pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
15049
- break;
15050
- }
15051
- }
14875
+ // no NALu found
14876
+ if (units.length === 0) {
14877
+ // append pes.data to previous NAL unit
14878
+ var _lastUnit = this.getLastNalUnit(track.samples);
14879
+ if (_lastUnit) {
14880
+ _lastUnit.data = appendUint8Array(_lastUnit.data, array);
15052
14881
  }
15053
14882
  }
15054
- return {
15055
- width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
15056
- height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
15057
- pixelRatio: pixelRatio
15058
- };
14883
+ track.naluState = state;
14884
+ return units;
15059
14885
  };
15060
14886
  return AvcVideoParser;
15061
14887
  }(BaseVideoParser);
@@ -15075,7 +14901,7 @@
15075
14901
  }
15076
14902
  var _proto = SampleAesDecrypter.prototype;
15077
14903
  _proto.decryptBuffer = function decryptBuffer(encryptedData) {
15078
- return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
14904
+ return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
15079
14905
  }
15080
14906
 
15081
14907
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -15194,7 +15020,7 @@
15194
15020
  this.observer = observer;
15195
15021
  this.config = config;
15196
15022
  this.typeSupported = typeSupported;
15197
- this.videoParser = null;
15023
+ this.videoParser = new AvcVideoParser();
15198
15024
  }
15199
15025
  TSDemuxer.probe = function probe(data) {
15200
15026
  var syncOffset = TSDemuxer.syncOffset(data);
@@ -15364,16 +15190,7 @@
15364
15190
  case videoPid:
15365
15191
  if (stt) {
15366
15192
  if (videoData && (pes = parsePES(videoData))) {
15367
- if (this.videoParser === null) {
15368
- switch (videoTrack.segmentCodec) {
15369
- case 'avc':
15370
- this.videoParser = new AvcVideoParser();
15371
- break;
15372
- }
15373
- }
15374
- if (this.videoParser !== null) {
15375
- this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
15376
- }
15193
+ this.videoParser.parseAVCPES(videoTrack, textTrack, pes, false, this._duration);
15377
15194
  }
15378
15195
  videoData = {
15379
15196
  data: [],
@@ -15531,17 +15348,8 @@
15531
15348
  // try to parse last PES packets
15532
15349
  var pes;
15533
15350
  if (videoData && (pes = parsePES(videoData))) {
15534
- if (this.videoParser === null) {
15535
- switch (videoTrack.segmentCodec) {
15536
- case 'avc':
15537
- this.videoParser = new AvcVideoParser();
15538
- break;
15539
- }
15540
- }
15541
- if (this.videoParser !== null) {
15542
- this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
15543
- videoTrack.pesData = null;
15544
- }
15351
+ this.videoParser.parseAVCPES(videoTrack, textTrack, pes, true, this._duration);
15352
+ videoTrack.pesData = null;
15545
15353
  } else {
15546
15354
  // either avcData null or PES truncated, keep it for next frag parsing
15547
15355
  videoTrack.pesData = videoData;
@@ -15843,10 +15651,7 @@
15843
15651
  logger.warn('Unsupported EC-3 in M2TS found');
15844
15652
  break;
15845
15653
  case 0x24:
15846
- // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
15847
- {
15848
- logger.warn('Unsupported HEVC in M2TS found');
15849
- }
15654
+ logger.warn('Unsupported HEVC in M2TS found');
15850
15655
  break;
15851
15656
  }
15852
15657
  // move to the next table entry
@@ -16074,8 +15879,6 @@
16074
15879
  avc1: [],
16075
15880
  // codingname
16076
15881
  avcC: [],
16077
- hvc1: [],
16078
- hvcC: [],
16079
15882
  btrt: [],
16080
15883
  dinf: [],
16081
15884
  dref: [],
@@ -16503,10 +16306,8 @@
16503
16306
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
16504
16307
  }
16505
16308
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
16506
- } else if (track.segmentCodec === 'avc') {
16507
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
16508
16309
  } else {
16509
- return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
16310
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
16510
16311
  }
16511
16312
  };
16512
16313
  MP4.tkhd = function tkhd(track) {
@@ -16644,84 +16445,6 @@
16644
16445
  var result = appendUint8Array(MP4.FTYP, movie);
16645
16446
  return result;
16646
16447
  };
16647
- MP4.hvc1 = function hvc1(track) {
16648
- var ps = track.params;
16649
- var units = [track.vps, track.sps, track.pps];
16650
- var NALuLengthSize = 4;
16651
- 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]);
16652
-
16653
- // compute hvcC size in bytes
16654
- var length = config.length;
16655
- for (var i = 0; i < units.length; i += 1) {
16656
- length += 3;
16657
- for (var j = 0; j < units[i].length; j += 1) {
16658
- length += 2 + units[i][j].length;
16659
- }
16660
- }
16661
- var hvcC = new Uint8Array(length);
16662
- hvcC.set(config, 0);
16663
- length = config.length;
16664
- // append parameter set units: one vps, one or more sps and pps
16665
- var iMax = units.length - 1;
16666
- for (var _i = 0; _i < units.length; _i += 1) {
16667
- hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
16668
- length += 3;
16669
- for (var _j = 0; _j < units[_i].length; _j += 1) {
16670
- hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
16671
- length += 2;
16672
- hvcC.set(units[_i][_j], length);
16673
- length += units[_i][_j].length;
16674
- }
16675
- }
16676
- var hvcc = MP4.box(MP4.types.hvcC, hvcC);
16677
- var width = track.width;
16678
- var height = track.height;
16679
- var hSpacing = track.pixelRatio[0];
16680
- var vSpacing = track.pixelRatio[1];
16681
- return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
16682
- // reserved
16683
- 0x00, 0x00, 0x00,
16684
- // reserved
16685
- 0x00, 0x01,
16686
- // data_reference_index
16687
- 0x00, 0x00,
16688
- // pre_defined
16689
- 0x00, 0x00,
16690
- // reserved
16691
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16692
- // pre_defined
16693
- width >> 8 & 0xff, width & 0xff,
16694
- // width
16695
- height >> 8 & 0xff, height & 0xff,
16696
- // height
16697
- 0x00, 0x48, 0x00, 0x00,
16698
- // horizresolution
16699
- 0x00, 0x48, 0x00, 0x00,
16700
- // vertresolution
16701
- 0x00, 0x00, 0x00, 0x00,
16702
- // reserved
16703
- 0x00, 0x01,
16704
- // frame_count
16705
- 0x12, 0x64, 0x61, 0x69, 0x6c,
16706
- // dailymotion/hls.js
16707
- 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,
16708
- // compressorname
16709
- 0x00, 0x18,
16710
- // depth = 24
16711
- 0x11, 0x11]),
16712
- // pre_defined = -1
16713
- hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
16714
- // bufferSizeDB
16715
- 0x00, 0x2d, 0xc6, 0xc0,
16716
- // maxBitrate
16717
- 0x00, 0x2d, 0xc6, 0xc0])),
16718
- // avgBitrate
16719
- MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
16720
- // hSpacing
16721
- hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
16722
- // vSpacing
16723
- vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
16724
- };
16725
16448
  return MP4;
16726
16449
  }();
16727
16450
  MP4.types = void 0;
@@ -17108,9 +16831,9 @@
17108
16831
  var foundOverlap = delta < -1;
17109
16832
  if (foundHole || foundOverlap) {
17110
16833
  if (foundHole) {
17111
- logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
16834
+ logger.warn("AVC: " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
17112
16835
  } else {
17113
- logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
16836
+ logger.warn("AVC: " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
17114
16837
  }
17115
16838
  if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
17116
16839
  firstDTS = nextAvcDts;
@@ -17119,24 +16842,12 @@
17119
16842
  inputSamples[0].dts = firstDTS;
17120
16843
  inputSamples[0].pts = firstPTS;
17121
16844
  } else {
17122
- var isPTSOrderRetained = true;
17123
16845
  for (var _i = 0; _i < inputSamples.length; _i++) {
17124
- if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
16846
+ if (inputSamples[_i].dts > firstPTS) {
17125
16847
  break;
17126
16848
  }
17127
- var prevPTS = inputSamples[_i].pts;
17128
16849
  inputSamples[_i].dts -= delta;
17129
16850
  inputSamples[_i].pts -= delta;
17130
-
17131
- // check to see if this sample's PTS order has changed
17132
- // relative to the next one
17133
- if (_i < inputSamples.length - 1) {
17134
- var nextSamplePTS = inputSamples[_i + 1].pts;
17135
- var currentSamplePTS = inputSamples[_i].pts;
17136
- var currentOrder = nextSamplePTS <= currentSamplePTS;
17137
- var prevOrder = nextSamplePTS <= prevPTS;
17138
- isPTSOrderRetained = currentOrder == prevOrder;
17139
- }
17140
16851
  }
17141
16852
  }
17142
16853
  logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
@@ -17284,7 +16995,7 @@
17284
16995
  }
17285
16996
  }
17286
16997
  }
17287
- // next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
16998
+ // next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
17288
16999
  mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
17289
17000
  this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
17290
17001
  this.videoSampleDuration = mp4SampleDuration;
@@ -17419,7 +17130,7 @@
17419
17130
  logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
17420
17131
  for (var j = 0; j < missing; j++) {
17421
17132
  var newStamp = Math.max(nextPts, 0);
17422
- var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17133
+ var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17423
17134
  if (!fillFrame) {
17424
17135
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17425
17136
  fillFrame = sample.unit.subarray();
@@ -17547,7 +17258,7 @@
17547
17258
  // samples count of this segment's duration
17548
17259
  var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
17549
17260
  // silent frame
17550
- var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17261
+ var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17551
17262
  logger.warn('[mp4-remuxer]: remux empty Audio');
17552
17263
  // Can't remux if we can't generate a silent frame...
17553
17264
  if (!silentFrame) {
@@ -17934,15 +17645,13 @@
17934
17645
  duration = transmuxConfig.duration,
17935
17646
  initSegmentData = transmuxConfig.initSegmentData;
17936
17647
  var keyData = getEncryptionType(uintData, decryptdata);
17937
- if (keyData && isFullSegmentEncryption(keyData.method)) {
17648
+ if (keyData && keyData.method === 'AES-128') {
17938
17649
  var decrypter = this.getDecrypter();
17939
- var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
17940
-
17941
17650
  // Software decryption is synchronous; webCrypto is not
17942
17651
  if (decrypter.isSync()) {
17943
17652
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
17944
17653
  // data is handled in the flush() call
17945
- var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
17654
+ var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
17946
17655
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
17947
17656
  var loadingParts = chunkMeta.part > -1;
17948
17657
  if (loadingParts) {
@@ -17954,7 +17663,7 @@
17954
17663
  }
17955
17664
  uintData = new Uint8Array(decryptedData);
17956
17665
  } else {
17957
- this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
17666
+ this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
17958
17667
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
17959
17668
  // the decrypted data has been transmuxed
17960
17669
  var result = _this.push(decryptedData, null, chunkMeta);
@@ -18575,7 +18284,7 @@
18575
18284
  observer.on(Events.ERROR, forwardMessage);
18576
18285
 
18577
18286
  // forward logger events to main thread
18578
- var forwardWorkerLogs = function forwardWorkerLogs(logger) {
18287
+ var forwardWorkerLogs = function forwardWorkerLogs() {
18579
18288
  var _loop = function _loop(logFn) {
18580
18289
  var func = function func(message) {
18581
18290
  forwardMessage('workerLog', {
@@ -18596,8 +18305,8 @@
18596
18305
  {
18597
18306
  var config = JSON.parse(data.config);
18598
18307
  self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
18599
- var logger = enableLogs(config.debug, data.id);
18600
- forwardWorkerLogs(logger);
18308
+ enableLogs(config.debug, data.id);
18309
+ forwardWorkerLogs();
18601
18310
  forwardMessage('init', null);
18602
18311
  break;
18603
18312
  }
@@ -18771,7 +18480,16 @@
18771
18480
  this.observer = new EventEmitter();
18772
18481
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
18773
18482
  this.observer.on(Events.ERROR, forwardMessage);
18774
- var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
18483
+ var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
18484
+ isTypeSupported: function isTypeSupported() {
18485
+ return false;
18486
+ }
18487
+ };
18488
+ var m2tsTypeSupported = {
18489
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
18490
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
18491
+ ac3: false
18492
+ };
18775
18493
 
18776
18494
  // navigator.vendor is not always available in Web Worker
18777
18495
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -19028,26 +18746,21 @@
19028
18746
  var MAX_START_GAP_JUMP = 2.0;
19029
18747
  var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
19030
18748
  var SKIP_BUFFER_RANGE_START = 0.05;
19031
- var GapController = /*#__PURE__*/function (_Logger) {
19032
- _inheritsLoose(GapController, _Logger);
18749
+ var GapController = /*#__PURE__*/function () {
19033
18750
  function GapController(config, media, fragmentTracker, hls) {
19034
- var _this;
19035
- _this = _Logger.call(this, 'gap-controller', hls.logger) || this;
19036
- _this.config = void 0;
19037
- _this.media = null;
19038
- _this.fragmentTracker = void 0;
19039
- _this.hls = void 0;
19040
- _this.nudgeRetry = 0;
19041
- _this.stallReported = false;
19042
- _this.stalled = null;
19043
- _this.moved = false;
19044
- _this.seeking = false;
19045
- _this.ended = 0;
19046
- _this.config = config;
19047
- _this.media = media;
19048
- _this.fragmentTracker = fragmentTracker;
19049
- _this.hls = hls;
19050
- return _this;
18751
+ this.config = void 0;
18752
+ this.media = null;
18753
+ this.fragmentTracker = void 0;
18754
+ this.hls = void 0;
18755
+ this.nudgeRetry = 0;
18756
+ this.stallReported = false;
18757
+ this.stalled = null;
18758
+ this.moved = false;
18759
+ this.seeking = false;
18760
+ this.config = config;
18761
+ this.media = media;
18762
+ this.fragmentTracker = fragmentTracker;
18763
+ this.hls = hls;
19051
18764
  }
19052
18765
  var _proto = GapController.prototype;
19053
18766
  _proto.destroy = function destroy() {
@@ -19062,7 +18775,7 @@
19062
18775
  *
19063
18776
  * @param lastCurrentTime - Previously read playhead position
19064
18777
  */;
19065
- _proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
18778
+ _proto.poll = function poll(lastCurrentTime, activeFrag) {
19066
18779
  var config = this.config,
19067
18780
  media = this.media,
19068
18781
  stalled = this.stalled;
@@ -19077,7 +18790,6 @@
19077
18790
 
19078
18791
  // The playhead is moving, no-op
19079
18792
  if (currentTime !== lastCurrentTime) {
19080
- this.ended = 0;
19081
18793
  this.moved = true;
19082
18794
  if (!seeking) {
19083
18795
  this.nudgeRetry = 0;
@@ -19086,7 +18798,7 @@
19086
18798
  // The playhead is now moving, but was previously stalled
19087
18799
  if (this.stallReported) {
19088
18800
  var _stalledDuration = self.performance.now() - stalled;
19089
- this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
18801
+ logger.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
19090
18802
  this.stallReported = false;
19091
18803
  }
19092
18804
  this.stalled = null;
@@ -19122,6 +18834,7 @@
19122
18834
  // Skip start gaps if we haven't played, but the last poll detected the start of a stall
19123
18835
  // The addition poll gives the browser a chance to jump the gap for us
19124
18836
  if (!this.moved && this.stalled !== null) {
18837
+ var _level$details;
19125
18838
  // There is no playable buffer (seeked, waiting for buffer)
19126
18839
  var isBuffered = bufferInfo.len > 0;
19127
18840
  if (!isBuffered && !nextStart) {
@@ -19133,8 +18846,9 @@
19133
18846
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
19134
18847
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
19135
18848
  // that begins over 1 target duration after the video start position.
19136
- var isLive = !!(levelDetails != null && levelDetails.live);
19137
- var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
18849
+ var level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
18850
+ var isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
18851
+ var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
19138
18852
  var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
19139
18853
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
19140
18854
  if (!media.paused) {
@@ -19152,17 +18866,6 @@
19152
18866
  }
19153
18867
  var stalledDuration = tnow - stalled;
19154
18868
  if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
19155
- // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
19156
- if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
19157
- if (stalledDuration < 1000 || this.ended) {
19158
- return;
19159
- }
19160
- this.ended = currentTime;
19161
- this.hls.trigger(Events.MEDIA_ENDED, {
19162
- stalled: true
19163
- });
19164
- return;
19165
- }
19166
18869
  // Report stalling after trying to fix
19167
18870
  this._reportStall(bufferInfo);
19168
18871
  if (!this.media) {
@@ -19204,7 +18907,7 @@
19204
18907
  // needs to cross some sort of threshold covering all source-buffers content
19205
18908
  // to start playing properly.
19206
18909
  if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
19207
- this.warn('Trying to nudge playhead over buffer-hole');
18910
+ logger.warn('Trying to nudge playhead over buffer-hole');
19208
18911
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
19209
18912
  // We only try to jump the hole if it's under the configured size
19210
18913
  // Reset stalled so to rearm watchdog timer
@@ -19226,7 +18929,7 @@
19226
18929
  // Report stalled error once
19227
18930
  this.stallReported = true;
19228
18931
  var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
19229
- this.warn(error.message);
18932
+ logger.warn(error.message);
19230
18933
  hls.trigger(Events.ERROR, {
19231
18934
  type: ErrorTypes.MEDIA_ERROR,
19232
18935
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19290,7 +18993,7 @@
19290
18993
  }
19291
18994
  }
19292
18995
  var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
19293
- this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
18996
+ logger.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
19294
18997
  this.moved = true;
19295
18998
  this.stalled = null;
19296
18999
  media.currentTime = targetTime;
@@ -19329,7 +19032,7 @@
19329
19032
  var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
19330
19033
  // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
19331
19034
  var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
19332
- this.warn(error.message);
19035
+ logger.warn(error.message);
19333
19036
  media.currentTime = targetTime;
19334
19037
  hls.trigger(Events.ERROR, {
19335
19038
  type: ErrorTypes.MEDIA_ERROR,
@@ -19339,7 +19042,7 @@
19339
19042
  });
19340
19043
  } else {
19341
19044
  var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
19342
- this.error(_error.message);
19045
+ logger.error(_error.message);
19343
19046
  hls.trigger(Events.ERROR, {
19344
19047
  type: ErrorTypes.MEDIA_ERROR,
19345
19048
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19349,14 +19052,14 @@
19349
19052
  }
19350
19053
  };
19351
19054
  return GapController;
19352
- }(Logger);
19055
+ }();
19353
19056
 
19354
19057
  var TICK_INTERVAL = 100; // how often to tick in ms
19355
19058
  var StreamController = /*#__PURE__*/function (_BaseStreamController) {
19356
19059
  _inheritsLoose(StreamController, _BaseStreamController);
19357
19060
  function StreamController(hls, fragmentTracker, keyLoader) {
19358
19061
  var _this;
19359
- _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
19062
+ _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[stream-controller]', PlaylistLevelType.MAIN) || this;
19360
19063
  _this.audioCodecSwap = false;
19361
19064
  _this.gapController = null;
19362
19065
  _this.level = -1;
@@ -19364,43 +19067,27 @@
19364
19067
  _this.altAudio = false;
19365
19068
  _this.audioOnly = false;
19366
19069
  _this.fragPlaying = null;
19070
+ _this.onvplaying = null;
19071
+ _this.onvseeked = null;
19367
19072
  _this.fragLastKbps = 0;
19368
19073
  _this.couldBacktrack = false;
19369
19074
  _this.backtrackFragment = null;
19370
19075
  _this.audioCodecSwitch = false;
19371
19076
  _this.videoBuffer = null;
19372
- _this.onMediaPlaying = function () {
19373
- // tick to speed up FRAG_CHANGED triggering
19374
- _this.tick();
19375
- };
19376
- _this.onMediaSeeked = function () {
19377
- var media = _this.media;
19378
- var currentTime = media ? media.currentTime : null;
19379
- if (isFiniteNumber(currentTime)) {
19380
- _this.log("Media seeked to " + currentTime.toFixed(3));
19381
- }
19382
-
19383
- // If seeked was issued before buffer was appended do not tick immediately
19384
- var bufferInfo = _this.getMainFwdBufferInfo();
19385
- if (bufferInfo === null || bufferInfo.len === 0) {
19386
- _this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19387
- return;
19388
- }
19389
-
19390
- // tick to speed up FRAG_CHANGED triggering
19391
- _this.tick();
19392
- };
19393
- _this.registerListeners();
19077
+ _this._registerListeners();
19394
19078
  return _this;
19395
19079
  }
19396
19080
  var _proto = StreamController.prototype;
19397
- _proto.registerListeners = function registerListeners() {
19398
- _BaseStreamController.prototype.registerListeners.call(this);
19081
+ _proto._registerListeners = function _registerListeners() {
19399
19082
  var hls = this.hls;
19083
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19084
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19085
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19400
19086
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19401
19087
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
19402
19088
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19403
19089
  hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19090
+ hls.on(Events.ERROR, this.onError, this);
19404
19091
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19405
19092
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19406
19093
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19408,12 +19095,15 @@
19408
19095
  hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
19409
19096
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19410
19097
  };
19411
- _proto.unregisterListeners = function unregisterListeners() {
19412
- _BaseStreamController.prototype.unregisterListeners.call(this);
19098
+ _proto._unregisterListeners = function _unregisterListeners() {
19413
19099
  var hls = this.hls;
19100
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19101
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19102
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19414
19103
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19415
19104
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19416
19105
  hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19106
+ hls.off(Events.ERROR, this.onError, this);
19417
19107
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19418
19108
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19419
19109
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19422,9 +19112,7 @@
19422
19112
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19423
19113
  };
19424
19114
  _proto.onHandlerDestroying = function onHandlerDestroying() {
19425
- // @ts-ignore
19426
- this.onMediaPlaying = this.onMediaSeeked = null;
19427
- this.unregisterListeners();
19115
+ this._unregisterListeners();
19428
19116
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
19429
19117
  };
19430
19118
  _proto.startLoad = function startLoad(startPosition) {
@@ -19533,7 +19221,7 @@
19533
19221
  return;
19534
19222
  }
19535
19223
  var level = hls.nextLoadLevel;
19536
- if (!this.buffering || !(levels != null && levels[level])) {
19224
+ if (!(levels != null && levels[level])) {
19537
19225
  return;
19538
19226
  }
19539
19227
  var levelInfo = levels[level];
@@ -19739,15 +19427,18 @@
19739
19427
  _proto.onMediaAttached = function onMediaAttached(event, data) {
19740
19428
  _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
19741
19429
  var media = data.media;
19742
- media.addEventListener('playing', this.onMediaPlaying);
19743
- media.addEventListener('seeked', this.onMediaSeeked);
19430
+ this.onvplaying = this.onMediaPlaying.bind(this);
19431
+ this.onvseeked = this.onMediaSeeked.bind(this);
19432
+ media.addEventListener('playing', this.onvplaying);
19433
+ media.addEventListener('seeked', this.onvseeked);
19744
19434
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
19745
19435
  };
19746
19436
  _proto.onMediaDetaching = function onMediaDetaching() {
19747
19437
  var media = this.media;
19748
- if (media) {
19749
- media.removeEventListener('playing', this.onMediaPlaying);
19750
- media.removeEventListener('seeked', this.onMediaSeeked);
19438
+ if (media && this.onvplaying && this.onvseeked) {
19439
+ media.removeEventListener('playing', this.onvplaying);
19440
+ media.removeEventListener('seeked', this.onvseeked);
19441
+ this.onvplaying = this.onvseeked = null;
19751
19442
  this.videoBuffer = null;
19752
19443
  }
19753
19444
  this.fragPlaying = null;
@@ -19757,6 +19448,27 @@
19757
19448
  }
19758
19449
  _BaseStreamController.prototype.onMediaDetaching.call(this);
19759
19450
  };
19451
+ _proto.onMediaPlaying = function onMediaPlaying() {
19452
+ // tick to speed up FRAG_CHANGED triggering
19453
+ this.tick();
19454
+ };
19455
+ _proto.onMediaSeeked = function onMediaSeeked() {
19456
+ var media = this.media;
19457
+ var currentTime = media ? media.currentTime : null;
19458
+ if (isFiniteNumber(currentTime)) {
19459
+ this.log("Media seeked to " + currentTime.toFixed(3));
19460
+ }
19461
+
19462
+ // If seeked was issued before buffer was appended do not tick immediately
19463
+ var bufferInfo = this.getMainFwdBufferInfo();
19464
+ if (bufferInfo === null || bufferInfo.len === 0) {
19465
+ this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19466
+ return;
19467
+ }
19468
+
19469
+ // tick to speed up FRAG_CHANGED triggering
19470
+ this.tick();
19471
+ };
19760
19472
  _proto.onManifestLoading = function onManifestLoading() {
19761
19473
  // reset buffer on manifest loading
19762
19474
  this.log('Trigger BUFFER_RESET');
@@ -20037,10 +19749,8 @@
20037
19749
  }
20038
19750
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
20039
19751
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
20040
- var state = this.state;
20041
- var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
20042
- var levelDetails = this.getLevelDetails();
20043
- gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
19752
+ var activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
19753
+ gapController.poll(this.lastCurrentTime, activeFrag);
20044
19754
  }
20045
19755
  this.lastCurrentTime = media.currentTime;
20046
19756
  };
@@ -20505,12 +20215,9 @@
20505
20215
  * The configuration object provided on player instantiation.
20506
20216
  */
20507
20217
  this.userConfig = void 0;
20508
- /**
20509
- * The logger functions used by this player instance, configured on player instantiation.
20510
- */
20511
- this.logger = void 0;
20512
20218
  this.coreComponents = void 0;
20513
20219
  this.networkControllers = void 0;
20220
+ this.started = false;
20514
20221
  this._emitter = new EventEmitter();
20515
20222
  this._autoLevelCapping = -1;
20516
20223
  this._maxHdcpLevel = null;
@@ -20527,11 +20234,11 @@
20527
20234
  this._media = null;
20528
20235
  this.url = null;
20529
20236
  this.triggeringException = void 0;
20530
- var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
20531
- var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
20237
+ enableLogs(userConfig.debug || false, 'Hls instance');
20238
+ var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
20532
20239
  this.userConfig = userConfig;
20533
20240
  if (config.progressive) {
20534
- enableStreamingMode(config, logger);
20241
+ enableStreamingMode(config);
20535
20242
  }
20536
20243
 
20537
20244
  // core controllers and network loaders
@@ -20639,7 +20346,7 @@
20639
20346
  try {
20640
20347
  return this.emit(event, event, eventObject);
20641
20348
  } catch (error) {
20642
- this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
20349
+ logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
20643
20350
  // Prevent recursion in error event handlers that throw #5497
20644
20351
  if (!this.triggeringException) {
20645
20352
  this.triggeringException = true;
@@ -20665,7 +20372,7 @@
20665
20372
  * Dispose of the instance
20666
20373
  */;
20667
20374
  _proto.destroy = function destroy() {
20668
- this.logger.log('destroy');
20375
+ logger.log('destroy');
20669
20376
  this.trigger(Events.DESTROYING, undefined);
20670
20377
  this.detachMedia();
20671
20378
  this.removeAllListeners();
@@ -20690,7 +20397,7 @@
20690
20397
  * Attaches Hls.js to a media element
20691
20398
  */;
20692
20399
  _proto.attachMedia = function attachMedia(media) {
20693
- this.logger.log('attachMedia');
20400
+ logger.log('attachMedia');
20694
20401
  this._media = media;
20695
20402
  this.trigger(Events.MEDIA_ATTACHING, {
20696
20403
  media: media
@@ -20701,7 +20408,7 @@
20701
20408
  * Detach Hls.js from the media
20702
20409
  */;
20703
20410
  _proto.detachMedia = function detachMedia() {
20704
- this.logger.log('detachMedia');
20411
+ logger.log('detachMedia');
20705
20412
  this.trigger(Events.MEDIA_DETACHING, undefined);
20706
20413
  this._media = null;
20707
20414
  }
@@ -20718,7 +20425,7 @@
20718
20425
  });
20719
20426
  this._autoLevelCapping = -1;
20720
20427
  this._maxHdcpLevel = null;
20721
- this.logger.log("loadSource:" + loadingSource);
20428
+ logger.log("loadSource:" + loadingSource);
20722
20429
  if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
20723
20430
  this.detachMedia();
20724
20431
  this.attachMedia(media);
@@ -20740,7 +20447,8 @@
20740
20447
  if (startPosition === void 0) {
20741
20448
  startPosition = -1;
20742
20449
  }
20743
- this.logger.log("startLoad(" + startPosition + ")");
20450
+ logger.log("startLoad(" + startPosition + ")");
20451
+ this.started = true;
20744
20452
  this.networkControllers.forEach(function (controller) {
20745
20453
  controller.startLoad(startPosition);
20746
20454
  });
@@ -20750,31 +20458,34 @@
20750
20458
  * Stop loading of any stream data.
20751
20459
  */;
20752
20460
  _proto.stopLoad = function stopLoad() {
20753
- this.logger.log('stopLoad');
20461
+ logger.log('stopLoad');
20462
+ this.started = false;
20754
20463
  this.networkControllers.forEach(function (controller) {
20755
20464
  controller.stopLoad();
20756
20465
  });
20757
20466
  }
20758
20467
 
20759
20468
  /**
20760
- * Resumes stream controller segment loading after `pauseBuffering` has been called.
20469
+ * Resumes stream controller segment loading if previously started.
20761
20470
  */;
20762
20471
  _proto.resumeBuffering = function resumeBuffering() {
20763
- this.networkControllers.forEach(function (controller) {
20764
- if (controller.resumeBuffering) {
20765
- controller.resumeBuffering();
20766
- }
20767
- });
20472
+ if (this.started) {
20473
+ this.networkControllers.forEach(function (controller) {
20474
+ if ('fragmentLoader' in controller) {
20475
+ controller.startLoad(-1);
20476
+ }
20477
+ });
20478
+ }
20768
20479
  }
20769
20480
 
20770
20481
  /**
20771
- * Prevents stream controller from loading new segments until `resumeBuffering` is called.
20482
+ * Stops stream controller segment loading without changing 'started' state like stopLoad().
20772
20483
  * This allows for media buffering to be paused without interupting playlist loading.
20773
20484
  */;
20774
20485
  _proto.pauseBuffering = function pauseBuffering() {
20775
20486
  this.networkControllers.forEach(function (controller) {
20776
- if (controller.pauseBuffering) {
20777
- controller.pauseBuffering();
20487
+ if ('fragmentLoader' in controller) {
20488
+ controller.stopLoad();
20778
20489
  }
20779
20490
  });
20780
20491
  }
@@ -20783,7 +20494,7 @@
20783
20494
  * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
20784
20495
  */;
20785
20496
  _proto.swapAudioCodec = function swapAudioCodec() {
20786
- this.logger.log('swapAudioCodec');
20497
+ logger.log('swapAudioCodec');
20787
20498
  this.streamController.swapAudioCodec();
20788
20499
  }
20789
20500
 
@@ -20794,7 +20505,7 @@
20794
20505
  * Automatic recovery of media-errors by this process is configurable.
20795
20506
  */;
20796
20507
  _proto.recoverMediaError = function recoverMediaError() {
20797
- this.logger.log('recoverMediaError');
20508
+ logger.log('recoverMediaError');
20798
20509
  var media = this._media;
20799
20510
  this.detachMedia();
20800
20511
  if (media) {
@@ -20849,7 +20560,7 @@
20849
20560
  * 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.
20850
20561
  */,
20851
20562
  set: function set(newLevel) {
20852
- this.logger.log("set currentLevel:" + newLevel);
20563
+ logger.log("set currentLevel:" + newLevel);
20853
20564
  this.levelController.manualLevel = newLevel;
20854
20565
  this.streamController.immediateLevelSwitch();
20855
20566
  }
@@ -20870,7 +20581,7 @@
20870
20581
  * @param newLevel - Pass -1 for automatic level selection
20871
20582
  */,
20872
20583
  set: function set(newLevel) {
20873
- this.logger.log("set nextLevel:" + newLevel);
20584
+ logger.log("set nextLevel:" + newLevel);
20874
20585
  this.levelController.manualLevel = newLevel;
20875
20586
  this.streamController.nextLevelSwitch();
20876
20587
  }
@@ -20891,7 +20602,7 @@
20891
20602
  * @param newLevel - Pass -1 for automatic level selection
20892
20603
  */,
20893
20604
  set: function set(newLevel) {
20894
- this.logger.log("set loadLevel:" + newLevel);
20605
+ logger.log("set loadLevel:" + newLevel);
20895
20606
  this.levelController.manualLevel = newLevel;
20896
20607
  }
20897
20608
 
@@ -20926,7 +20637,7 @@
20926
20637
  * Sets "first-level", see getter.
20927
20638
  */,
20928
20639
  set: function set(newLevel) {
20929
- this.logger.log("set firstLevel:" + newLevel);
20640
+ logger.log("set firstLevel:" + newLevel);
20930
20641
  this.levelController.firstLevel = newLevel;
20931
20642
  }
20932
20643
 
@@ -20953,7 +20664,7 @@
20953
20664
  * (determined from download of first segment)
20954
20665
  */,
20955
20666
  set: function set(newLevel) {
20956
- this.logger.log("set startLevel:" + newLevel);
20667
+ logger.log("set startLevel:" + newLevel);
20957
20668
  // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
20958
20669
  if (newLevel !== -1) {
20959
20670
  newLevel = Math.max(newLevel, this.minAutoLevel);
@@ -21006,7 +20717,7 @@
21006
20717
  */
21007
20718
  function set(newLevel) {
21008
20719
  if (this._autoLevelCapping !== newLevel) {
21009
- this.logger.log("set autoLevelCapping:" + newLevel);
20720
+ logger.log("set autoLevelCapping:" + newLevel);
21010
20721
  this._autoLevelCapping = newLevel;
21011
20722
  this.levelController.checkMaxAutoUpdated();
21012
20723
  }
@@ -21331,7 +21042,7 @@
21331
21042
  * Get the video-dev/hls.js package version.
21332
21043
  */
21333
21044
  function get() {
21334
- return "1.5.6-0.canary.10011";
21045
+ return "1.5.6";
21335
21046
  }
21336
21047
  }, {
21337
21048
  key: "Events",