hls.js 1.5.2-0.canary.9934 → 1.5.3

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 (60) hide show
  1. package/dist/hls-demo.js +0 -5
  2. package/dist/hls-demo.js.map +1 -1
  3. package/dist/hls.js +757 -883
  4. package/dist/hls.js.d.ts +47 -56
  5. package/dist/hls.js.map +1 -1
  6. package/dist/hls.light.js +477 -600
  7. package/dist/hls.light.js.map +1 -1
  8. package/dist/hls.light.min.js +1 -1
  9. package/dist/hls.light.min.js.map +1 -1
  10. package/dist/hls.light.mjs +335 -446
  11. package/dist/hls.light.mjs.map +1 -1
  12. package/dist/hls.min.js +1 -1
  13. package/dist/hls.min.js.map +1 -1
  14. package/dist/hls.mjs +572 -681
  15. package/dist/hls.mjs.map +1 -1
  16. package/dist/hls.worker.js +1 -1
  17. package/dist/hls.worker.js.map +1 -1
  18. package/package.json +11 -11
  19. package/src/config.ts +2 -3
  20. package/src/controller/abr-controller.ts +22 -22
  21. package/src/controller/audio-stream-controller.ts +14 -11
  22. package/src/controller/audio-track-controller.ts +1 -1
  23. package/src/controller/base-playlist-controller.ts +7 -7
  24. package/src/controller/base-stream-controller.ts +29 -47
  25. package/src/controller/buffer-controller.ts +11 -10
  26. package/src/controller/cap-level-controller.ts +2 -1
  27. package/src/controller/cmcd-controller.ts +3 -25
  28. package/src/controller/content-steering-controller.ts +6 -8
  29. package/src/controller/eme-controller.ts +22 -9
  30. package/src/controller/error-controller.ts +8 -6
  31. package/src/controller/fps-controller.ts +3 -2
  32. package/src/controller/gap-controller.ts +16 -43
  33. package/src/controller/latency-controller.ts +11 -9
  34. package/src/controller/level-controller.ts +17 -5
  35. package/src/controller/stream-controller.ts +31 -24
  36. package/src/controller/subtitle-stream-controller.ts +14 -13
  37. package/src/controller/subtitle-track-controller.ts +3 -5
  38. package/src/controller/timeline-controller.ts +30 -23
  39. package/src/crypt/aes-crypto.ts +2 -21
  40. package/src/crypt/decrypter.ts +18 -32
  41. package/src/crypt/fast-aes-key.ts +5 -24
  42. package/src/demux/audio/adts.ts +4 -9
  43. package/src/demux/sample-aes.ts +0 -2
  44. package/src/demux/transmuxer-interface.ts +12 -4
  45. package/src/demux/transmuxer-worker.ts +4 -4
  46. package/src/demux/transmuxer.ts +3 -16
  47. package/src/demux/tsdemuxer.ts +17 -12
  48. package/src/events.ts +0 -7
  49. package/src/hls.ts +20 -33
  50. package/src/loader/fragment-loader.ts +2 -9
  51. package/src/loader/key-loader.ts +0 -2
  52. package/src/loader/level-key.ts +9 -10
  53. package/src/remux/mp4-remuxer.ts +4 -20
  54. package/src/task-loop.ts +2 -5
  55. package/src/types/demuxer.ts +0 -1
  56. package/src/types/events.ts +0 -4
  57. package/src/utils/codecs.ts +4 -33
  58. package/src/utils/logger.ts +24 -53
  59. package/src/crypt/decrypter-aes-mode.ts +0 -4
  60. package/src/utils/encryption-methods-util.ts +0 -21
@@ -256,7 +256,6 @@ let Events = /*#__PURE__*/function (Events) {
256
256
  Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
257
257
  Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
258
258
  Events["MEDIA_DETACHED"] = "hlsMediaDetached";
259
- Events["MEDIA_ENDED"] = "hlsMediaEnded";
260
259
  Events["BUFFER_RESET"] = "hlsBufferReset";
261
260
  Events["BUFFER_CODECS"] = "hlsBufferCodecs";
262
261
  Events["BUFFER_CREATED"] = "hlsBufferCreated";
@@ -370,23 +369,6 @@ let ErrorDetails = /*#__PURE__*/function (ErrorDetails) {
370
369
  return ErrorDetails;
371
370
  }({});
372
371
 
373
- class Logger {
374
- constructor(label, logger) {
375
- this.trace = void 0;
376
- this.debug = void 0;
377
- this.log = void 0;
378
- this.warn = void 0;
379
- this.info = void 0;
380
- this.error = void 0;
381
- const lb = `[${label}]:`;
382
- this.trace = noop;
383
- this.debug = logger.debug.bind(null, lb);
384
- this.log = logger.log.bind(null, lb);
385
- this.warn = logger.warn.bind(null, lb);
386
- this.info = logger.info.bind(null, lb);
387
- this.error = logger.error.bind(null, lb);
388
- }
389
- }
390
372
  const noop = function noop() {};
391
373
  const fakeLogger = {
392
374
  trace: noop,
@@ -396,9 +378,7 @@ const fakeLogger = {
396
378
  info: noop,
397
379
  error: noop
398
380
  };
399
- function createLogger() {
400
- return _extends({}, fakeLogger);
401
- }
381
+ let exportedLogger = fakeLogger;
402
382
 
403
383
  // let lastCallTime;
404
384
  // function formatMsgWithTimeInfo(type, msg) {
@@ -409,36 +389,35 @@ function createLogger() {
409
389
  // return msg;
410
390
  // }
411
391
 
412
- function consolePrintFn(type, id) {
392
+ function consolePrintFn(type) {
413
393
  const func = self.console[type];
414
- return func ? func.bind(self.console, `${id ? '[' + id + '] ' : ''}[${type}] >`) : noop;
394
+ if (func) {
395
+ return func.bind(self.console, `[${type}] >`);
396
+ }
397
+ return noop;
415
398
  }
416
- function getLoggerFn(key, debugConfig, id) {
417
- return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
399
+ function exportLoggerFunctions(debugConfig, ...functions) {
400
+ functions.forEach(function (type) {
401
+ exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
402
+ });
418
403
  }
419
- let exportedLogger = createLogger();
420
- function enableLogs(debugConfig, context, id) {
404
+ function enableLogs(debugConfig, id) {
421
405
  // check that console is available
422
- const newLogger = createLogger();
423
406
  if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
424
- const keys = [
407
+ exportLoggerFunctions(debugConfig,
425
408
  // Remove out from list here to hard-disable a log-level
426
409
  // 'trace',
427
- 'debug', 'log', 'info', 'warn', 'error'];
428
- keys.forEach(key => {
429
- newLogger[key] = getLoggerFn(key, debugConfig, id);
430
- });
410
+ 'debug', 'log', 'info', 'warn', 'error');
431
411
  // Some browsers don't allow to use bind on console object anyway
432
412
  // fallback to default if needed
433
413
  try {
434
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.2-0.canary.9934"}`);
414
+ exportedLogger.log(`Debug logs enabled for "${id}" in hls.js version ${"1.5.3"}`);
435
415
  } catch (e) {
436
- /* log fn threw an exception. All logger methods are no-ops. */
437
- return createLogger();
416
+ exportedLogger = fakeLogger;
438
417
  }
418
+ } else {
419
+ exportedLogger = fakeLogger;
439
420
  }
440
- exportedLogger = newLogger;
441
- return newLogger;
442
421
  }
443
422
  const logger = exportedLogger;
444
423
 
@@ -1012,26 +991,6 @@ class LevelDetails {
1012
991
  }
1013
992
  }
1014
993
 
1015
- var DecrypterAesMode = {
1016
- cbc: 0,
1017
- ctr: 1
1018
- };
1019
-
1020
- function isFullSegmentEncryption(method) {
1021
- return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
1022
- }
1023
- function getAesModeFromFullSegmentMethod(method) {
1024
- switch (method) {
1025
- case 'AES-128':
1026
- case 'AES-256':
1027
- return DecrypterAesMode.cbc;
1028
- case 'AES-256-CTR':
1029
- return DecrypterAesMode.ctr;
1030
- default:
1031
- throw new Error(`invalid full segment method ${method}`);
1032
- }
1033
- }
1034
-
1035
994
  // This file is inserted as a shim for modules which we do not want to include into the distro.
1036
995
  // This replacement is done in the "alias" plugin of the rollup config.
1037
996
  var empty = undefined;
@@ -2460,12 +2419,12 @@ class LevelKey {
2460
2419
  this.keyFormatVersions = formatversions;
2461
2420
  this.iv = iv;
2462
2421
  this.encrypted = method ? method !== 'NONE' : false;
2463
- this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2422
+ this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2464
2423
  }
2465
2424
  isSupported() {
2466
2425
  // If it's Segment encryption or No encryption, just select that key system
2467
2426
  if (this.method) {
2468
- if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2427
+ if (this.method === 'AES-128' || this.method === 'NONE') {
2469
2428
  return true;
2470
2429
  }
2471
2430
  if (this.keyFormat === 'identity') {
@@ -2479,13 +2438,14 @@ class LevelKey {
2479
2438
  if (!this.encrypted || !this.uri) {
2480
2439
  return null;
2481
2440
  }
2482
- if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2441
+ if (this.method === 'AES-128' && this.uri && !this.iv) {
2483
2442
  if (typeof sn !== 'number') {
2484
2443
  // We are fetching decryption data for a initialization segment
2485
- // If the segment was encrypted with AES-128/256
2444
+ // If the segment was encrypted with AES-128
2486
2445
  // It must have an IV defined. We cannot substitute the Segment Number in.
2487
- logger.warn(`missing IV for initialization segment with method="${this.method}" - compliance issue`);
2488
-
2446
+ if (this.method === 'AES-128' && !this.iv) {
2447
+ logger.warn(`missing IV for initialization segment with method="${this.method}" - compliance issue`);
2448
+ }
2489
2449
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2490
2450
  sn = 0;
2491
2451
  }
@@ -2632,28 +2592,23 @@ function getCodecCompatibleNameLower(lowerCaseCodec, preferManagedMediaSource =
2632
2592
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2633
2593
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2634
2594
  }
2595
+
2596
+ // Idealy fLaC and Opus would be first (spec-compliant) but
2597
+ // some browsers will report that fLaC is supported then fail.
2598
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2635
2599
  const codecsToCheck = {
2636
- // Idealy fLaC and Opus would be first (spec-compliant) but
2637
- // some browsers will report that fLaC is supported then fail.
2638
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2639
2600
  flac: ['flac', 'fLaC', 'FLAC'],
2640
- opus: ['opus', 'Opus'],
2641
- // Replace audio codec info if browser does not support mp4a.40.34,
2642
- // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
2643
- 'mp4a.40.34': ['mp3']
2601
+ opus: ['opus', 'Opus']
2644
2602
  }[lowerCaseCodec];
2645
2603
  for (let i = 0; i < codecsToCheck.length; i++) {
2646
- var _getMediaSource;
2647
2604
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2648
2605
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2649
2606
  return codecsToCheck[i];
2650
- } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2651
- return '';
2652
2607
  }
2653
2608
  }
2654
2609
  return lowerCaseCodec;
2655
2610
  }
2656
- const AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2611
+ const AUDIO_CODEC_REGEXP = /flac|opus/i;
2657
2612
  function getCodecCompatibleName(codec, preferManagedMediaSource = true) {
2658
2613
  return codec.replace(AUDIO_CODEC_REGEXP, m => getCodecCompatibleNameLower(m.toLowerCase(), preferManagedMediaSource));
2659
2614
  }
@@ -2676,16 +2631,6 @@ function convertAVC1ToAVCOTI(codec) {
2676
2631
  }
2677
2632
  return codec;
2678
2633
  }
2679
- function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2680
- const MediaSource = getMediaSource(preferManagedMediaSource) || {
2681
- isTypeSupported: () => false
2682
- };
2683
- return {
2684
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
2685
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
2686
- ac3: false
2687
- };
2688
- }
2689
2634
 
2690
2635
  const 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;
2691
2636
  const MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -4263,47 +4208,7 @@ class LatencyController {
4263
4208
  this.currentTime = 0;
4264
4209
  this.stallCount = 0;
4265
4210
  this._latency = null;
4266
- this.onTimeupdate = () => {
4267
- const {
4268
- media,
4269
- levelDetails
4270
- } = this;
4271
- if (!media || !levelDetails) {
4272
- return;
4273
- }
4274
- this.currentTime = media.currentTime;
4275
- const latency = this.computeLatency();
4276
- if (latency === null) {
4277
- return;
4278
- }
4279
- this._latency = latency;
4280
-
4281
- // Adapt playbackRate to meet target latency in low-latency mode
4282
- const {
4283
- lowLatencyMode,
4284
- maxLiveSyncPlaybackRate
4285
- } = this.config;
4286
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4287
- return;
4288
- }
4289
- const targetLatency = this.targetLatency;
4290
- if (targetLatency === null) {
4291
- return;
4292
- }
4293
- const distanceFromTarget = latency - targetLatency;
4294
- // Only adjust playbackRate when within one target duration of targetLatency
4295
- // and more than one second from under-buffering.
4296
- // Playback further than one target duration from target can be considered DVR playback.
4297
- const liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4298
- const inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4299
- if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4300
- const max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4301
- const rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4302
- media.playbackRate = Math.min(max, Math.max(1, rate));
4303
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4304
- media.playbackRate = 1;
4305
- }
4306
- };
4211
+ this.timeupdateHandler = () => this.timeupdate();
4307
4212
  this.hls = hls;
4308
4213
  this.config = hls.config;
4309
4214
  this.registerListeners();
@@ -4395,7 +4300,7 @@ class LatencyController {
4395
4300
  this.onMediaDetaching();
4396
4301
  this.levelDetails = null;
4397
4302
  // @ts-ignore
4398
- this.hls = null;
4303
+ this.hls = this.timeupdateHandler = null;
4399
4304
  }
4400
4305
  registerListeners() {
4401
4306
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4413,11 +4318,11 @@ class LatencyController {
4413
4318
  }
4414
4319
  onMediaAttached(event, data) {
4415
4320
  this.media = data.media;
4416
- this.media.addEventListener('timeupdate', this.onTimeupdate);
4321
+ this.media.addEventListener('timeupdate', this.timeupdateHandler);
4417
4322
  }
4418
4323
  onMediaDetaching() {
4419
4324
  if (this.media) {
4420
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4325
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4421
4326
  this.media = null;
4422
4327
  }
4423
4328
  }
@@ -4431,10 +4336,10 @@ class LatencyController {
4431
4336
  }) {
4432
4337
  this.levelDetails = details;
4433
4338
  if (details.advanced) {
4434
- this.onTimeupdate();
4339
+ this.timeupdate();
4435
4340
  }
4436
4341
  if (!details.live && this.media) {
4437
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
4342
+ this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4438
4343
  }
4439
4344
  }
4440
4345
  onError(event, data) {
@@ -4444,7 +4349,48 @@ class LatencyController {
4444
4349
  }
4445
4350
  this.stallCount++;
4446
4351
  if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
4447
- this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
4352
+ logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
4353
+ }
4354
+ }
4355
+ timeupdate() {
4356
+ const {
4357
+ media,
4358
+ levelDetails
4359
+ } = this;
4360
+ if (!media || !levelDetails) {
4361
+ return;
4362
+ }
4363
+ this.currentTime = media.currentTime;
4364
+ const latency = this.computeLatency();
4365
+ if (latency === null) {
4366
+ return;
4367
+ }
4368
+ this._latency = latency;
4369
+
4370
+ // Adapt playbackRate to meet target latency in low-latency mode
4371
+ const {
4372
+ lowLatencyMode,
4373
+ maxLiveSyncPlaybackRate
4374
+ } = this.config;
4375
+ if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4376
+ return;
4377
+ }
4378
+ const targetLatency = this.targetLatency;
4379
+ if (targetLatency === null) {
4380
+ return;
4381
+ }
4382
+ const distanceFromTarget = latency - targetLatency;
4383
+ // Only adjust playbackRate when within one target duration of targetLatency
4384
+ // and more than one second from under-buffering.
4385
+ // Playback further than one target duration from target can be considered DVR playback.
4386
+ const liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4387
+ const inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4388
+ if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4389
+ const max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4390
+ const rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4391
+ media.playbackRate = Math.min(max, Math.max(1, rate));
4392
+ } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4393
+ media.playbackRate = 1;
4448
4394
  }
4449
4395
  }
4450
4396
  estimateLiveEdge() {
@@ -5216,13 +5162,18 @@ var ErrorActionFlags = {
5216
5162
  MoveAllAlternatesMatchingHDCP: 2,
5217
5163
  SwitchToSDR: 4
5218
5164
  }; // Reserved for future use
5219
- class ErrorController extends Logger {
5165
+ class ErrorController {
5220
5166
  constructor(hls) {
5221
- super('error-controller', hls.logger);
5222
5167
  this.hls = void 0;
5223
5168
  this.playlistError = 0;
5224
5169
  this.penalizedRenditions = {};
5170
+ this.log = void 0;
5171
+ this.warn = void 0;
5172
+ this.error = void 0;
5225
5173
  this.hls = hls;
5174
+ this.log = logger.log.bind(logger, `[info]:`);
5175
+ this.warn = logger.warn.bind(logger, `[warning]:`);
5176
+ this.error = logger.error.bind(logger, `[error]:`);
5226
5177
  this.registerListeners();
5227
5178
  }
5228
5179
  registerListeners() {
@@ -5574,13 +5525,16 @@ class ErrorController extends Logger {
5574
5525
  }
5575
5526
  }
5576
5527
 
5577
- class BasePlaylistController extends Logger {
5528
+ class BasePlaylistController {
5578
5529
  constructor(hls, logPrefix) {
5579
- super(logPrefix, hls.logger);
5580
5530
  this.hls = void 0;
5581
5531
  this.timer = -1;
5582
5532
  this.requestScheduled = -1;
5583
5533
  this.canLoad = false;
5534
+ this.log = void 0;
5535
+ this.warn = void 0;
5536
+ this.log = logger.log.bind(logger, `${logPrefix}:`);
5537
+ this.warn = logger.warn.bind(logger, `${logPrefix}:`);
5584
5538
  this.hls = hls;
5585
5539
  }
5586
5540
  destroy() {
@@ -5613,7 +5567,7 @@ class BasePlaylistController extends Logger {
5613
5567
  try {
5614
5568
  uri = new self.URL(attr.URI, previous.url).href;
5615
5569
  } catch (error) {
5616
- this.warn(`Could not construct new URL for Rendition Report: ${error}`);
5570
+ logger.warn(`Could not construct new URL for Rendition Report: ${error}`);
5617
5571
  uri = attr.URI || '';
5618
5572
  }
5619
5573
  // Use exact match. Otherwise, the last partial match, if any, will be used
@@ -6159,9 +6113,8 @@ function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
6159
6113
  }, {});
6160
6114
  }
6161
6115
 
6162
- class AbrController extends Logger {
6116
+ class AbrController {
6163
6117
  constructor(_hls) {
6164
- super('abr', _hls.logger);
6165
6118
  this.hls = void 0;
6166
6119
  this.lastLevelLoadSec = 0;
6167
6120
  this.lastLoadedFragLevel = -1;
@@ -6275,7 +6228,7 @@ class AbrController extends Logger {
6275
6228
  this.resetEstimator(nextLoadLevelBitrate);
6276
6229
  }
6277
6230
  this.clearTimer();
6278
- this.warn(`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${frag.level} is loading too slowly;
6231
+ logger.warn(`[abr] Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${frag.level} is loading too slowly;
6279
6232
  Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
6280
6233
  Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s
6281
6234
  Estimated load time for down switch fragment: ${fragLevelNextLoadedDelay.toFixed(3)} s
@@ -6295,7 +6248,7 @@ class AbrController extends Logger {
6295
6248
  }
6296
6249
  resetEstimator(abrEwmaDefaultEstimate) {
6297
6250
  if (abrEwmaDefaultEstimate) {
6298
- this.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`);
6251
+ logger.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`);
6299
6252
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
6300
6253
  }
6301
6254
  this.firstSelection = -1;
@@ -6527,7 +6480,7 @@ class AbrController extends Logger {
6527
6480
  }
6528
6481
  const firstLevel = this.hls.firstLevel;
6529
6482
  const clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
6530
- this.warn(`Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`);
6483
+ logger.warn(`[abr] Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`);
6531
6484
  return clamped;
6532
6485
  }
6533
6486
  get forcedAutoLevel() {
@@ -6612,13 +6565,13 @@ class AbrController extends Logger {
6612
6565
  // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
6613
6566
  const maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
6614
6567
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
6615
- this.info(`bitrate test took ${Math.round(1000 * bitrateTestDelay)}ms, set first fragment max fetchDuration to ${Math.round(1000 * maxStarvationDelay)} ms`);
6568
+ logger.info(`[abr] bitrate test took ${Math.round(1000 * bitrateTestDelay)}ms, set first fragment max fetchDuration to ${Math.round(1000 * maxStarvationDelay)} ms`);
6616
6569
  // don't use conservative factor on bitrate test
6617
6570
  bwFactor = bwUpFactor = 1;
6618
6571
  }
6619
6572
  }
6620
6573
  const bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
6621
- this.info(`${bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty'}, optimal quality level ${bestLevel}`);
6574
+ logger.info(`[abr] ${bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty'}, optimal quality level ${bestLevel}`);
6622
6575
  if (bestLevel > -1) {
6623
6576
  return bestLevel;
6624
6577
  }
@@ -6680,7 +6633,7 @@ class AbrController extends Logger {
6680
6633
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
6681
6634
  currentFrameRate = minFramerate;
6682
6635
  currentBw = Math.max(currentBw, minBitrate);
6683
- this.log(`picked start tier ${JSON.stringify(startTier)}`);
6636
+ logger.log(`[abr] picked start tier ${JSON.stringify(startTier)}`);
6684
6637
  } else {
6685
6638
  currentCodecSet = level == null ? void 0 : level.codecSet;
6686
6639
  currentVideoRange = level == null ? void 0 : level.videoRange;
@@ -6689,7 +6642,7 @@ class AbrController extends Logger {
6689
6642
  const ttfbEstimateSec = this.bwEstimator.getEstimateTTFB() / 1000;
6690
6643
  const levelsSkipped = [];
6691
6644
  for (let i = maxAutoLevel; i >= minAutoLevel; i--) {
6692
- var _levelInfo$supportedR, _levelInfo$supportedR2;
6645
+ var _levelInfo$supportedR;
6693
6646
  const levelInfo = levels[i];
6694
6647
  const upSwitch = i > selectionBaseLevel;
6695
6648
  if (!levelInfo) {
@@ -6698,7 +6651,7 @@ class AbrController extends Logger {
6698
6651
 
6699
6652
  // skip candidates which change codec-family or video-range,
6700
6653
  // and which decrease or increase frame-rate for up and down-switch respectfully
6701
- if (currentCodecSet && levelInfo.codecSet !== currentCodecSet || currentVideoRange && levelInfo.videoRange !== currentVideoRange || upSwitch && currentFrameRate > levelInfo.frameRate || !upSwitch && currentFrameRate > 0 && currentFrameRate < levelInfo.frameRate || !((_levelInfo$supportedR = levelInfo.supportedResult) != null && (_levelInfo$supportedR2 = _levelInfo$supportedR.decodingInfoResults) != null && _levelInfo$supportedR2[0].smooth)) {
6654
+ if (currentCodecSet && levelInfo.codecSet !== currentCodecSet || currentVideoRange && levelInfo.videoRange !== currentVideoRange || upSwitch && currentFrameRate > levelInfo.frameRate || !upSwitch && currentFrameRate > 0 && currentFrameRate < levelInfo.frameRate || levelInfo.supportedResult && !((_levelInfo$supportedR = levelInfo.supportedResult.decodingInfoResults) != null && _levelInfo$supportedR[0].smooth)) {
6702
6655
  levelsSkipped.push(i);
6703
6656
  continue;
6704
6657
  }
@@ -6733,9 +6686,9 @@ class AbrController extends Logger {
6733
6686
  const forcedAutoLevel = this.forcedAutoLevel;
6734
6687
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
6735
6688
  if (levelsSkipped.length) {
6736
- this.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}`);
6689
+ 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}`);
6737
6690
  }
6738
- this.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}`);
6691
+ 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}`);
6739
6692
  }
6740
6693
  if (firstSelection) {
6741
6694
  this.firstSelection = i;
@@ -6967,9 +6920,8 @@ class BufferOperationQueue {
6967
6920
  }
6968
6921
 
6969
6922
  const VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
6970
- class BufferController extends Logger {
6923
+ class BufferController {
6971
6924
  constructor(hls) {
6972
- super('buffer-controller', hls.logger);
6973
6925
  // The level details used to determine duration, target-duration and live
6974
6926
  this.details = null;
6975
6927
  // cache the self generated object url to detect hijack of video tag
@@ -6999,6 +6951,9 @@ class BufferController extends Logger {
6999
6951
  this.tracks = {};
7000
6952
  this.pendingTracks = {};
7001
6953
  this.sourceBuffer = void 0;
6954
+ this.log = void 0;
6955
+ this.warn = void 0;
6956
+ this.error = void 0;
7002
6957
  this._onEndStreaming = event => {
7003
6958
  if (!this.hls) {
7004
6959
  return;
@@ -7044,11 +6999,15 @@ class BufferController extends Logger {
7044
6999
  _objectUrl
7045
7000
  } = this;
7046
7001
  if (mediaSrc !== _objectUrl) {
7047
- this.error(`Media element src was set while attaching MediaSource (${_objectUrl} > ${mediaSrc})`);
7002
+ logger.error(`Media element src was set while attaching MediaSource (${_objectUrl} > ${mediaSrc})`);
7048
7003
  }
7049
7004
  };
7050
7005
  this.hls = hls;
7006
+ const logPrefix = '[buffer-controller]';
7051
7007
  this.appendSource = hls.config.preferManagedMediaSource;
7008
+ this.log = logger.log.bind(logger, logPrefix);
7009
+ this.warn = logger.warn.bind(logger, logPrefix);
7010
+ this.error = logger.error.bind(logger, logPrefix);
7052
7011
  this._initSourceBuffer();
7053
7012
  this.registerListeners();
7054
7013
  }
@@ -7061,12 +7020,6 @@ class BufferController extends Logger {
7061
7020
  this.lastMpegAudioChunk = null;
7062
7021
  // @ts-ignore
7063
7022
  this.hls = null;
7064
- // @ts-ignore
7065
- this._onMediaSourceOpen = this._onMediaSourceClose = null;
7066
- // @ts-ignore
7067
- this._onMediaSourceEnded = null;
7068
- // @ts-ignore
7069
- this._onStartStreaming = this._onEndStreaming = null;
7070
7023
  }
7071
7024
  registerListeners() {
7072
7025
  const {
@@ -8066,7 +8019,7 @@ class CapLevelController {
8066
8019
  const hls = this.hls;
8067
8020
  const maxLevel = this.getMaxLevel(levels.length - 1);
8068
8021
  if (maxLevel !== this.autoLevelCapping) {
8069
- hls.logger.log(`Setting autoLevelCapping to ${maxLevel}: ${levels[maxLevel].height}p@${levels[maxLevel].bitrate} for media ${this.mediaWidth}x${this.mediaHeight}`);
8022
+ logger.log(`Setting autoLevelCapping to ${maxLevel}: ${levels[maxLevel].height}p@${levels[maxLevel].bitrate} for media ${this.mediaWidth}x${this.mediaHeight}`);
8070
8023
  }
8071
8024
  hls.autoLevelCapping = maxLevel;
8072
8025
  if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
@@ -8244,10 +8197,10 @@ class FPSController {
8244
8197
  totalDroppedFrames: droppedFrames
8245
8198
  });
8246
8199
  if (droppedFPS > 0) {
8247
- // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8200
+ // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8248
8201
  if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
8249
8202
  let currentLevel = hls.currentLevel;
8250
- hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8203
+ logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8251
8204
  if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
8252
8205
  currentLevel = currentLevel - 1;
8253
8206
  hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
@@ -8280,10 +8233,10 @@ class FPSController {
8280
8233
  }
8281
8234
 
8282
8235
  const PATHWAY_PENALTY_DURATION_MS = 300000;
8283
- class ContentSteeringController extends Logger {
8236
+ class ContentSteeringController {
8284
8237
  constructor(hls) {
8285
- super('content-steering', hls.logger);
8286
8238
  this.hls = void 0;
8239
+ this.log = void 0;
8287
8240
  this.loader = null;
8288
8241
  this.uri = null;
8289
8242
  this.pathwayId = '.';
@@ -8298,6 +8251,7 @@ class ContentSteeringController extends Logger {
8298
8251
  this.subtitleTracks = null;
8299
8252
  this.penalizedPathways = {};
8300
8253
  this.hls = hls;
8254
+ this.log = logger.log.bind(logger, `[content-steering]:`);
8301
8255
  this.registerListeners();
8302
8256
  }
8303
8257
  registerListeners() {
@@ -8421,7 +8375,7 @@ class ContentSteeringController extends Logger {
8421
8375
  errorAction.resolved = this.pathwayId !== errorPathway;
8422
8376
  }
8423
8377
  if (!errorAction.resolved) {
8424
- 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)}`);
8378
+ 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)}`);
8425
8379
  }
8426
8380
  }
8427
8381
  }
@@ -8592,7 +8546,7 @@ class ContentSteeringController extends Logger {
8592
8546
  onSuccess: (response, stats, context, networkDetails) => {
8593
8547
  this.log(`Loaded steering manifest: "${url}"`);
8594
8548
  const steeringData = response.data;
8595
- if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
8549
+ if (steeringData.VERSION !== 1) {
8596
8550
  this.log(`Steering VERSION ${steeringData.VERSION} not supported!`);
8597
8551
  return;
8598
8552
  }
@@ -9531,7 +9485,7 @@ function timelineConfig() {
9531
9485
  /**
9532
9486
  * @ignore
9533
9487
  */
9534
- function mergeConfig(defaultConfig, userConfig, logger) {
9488
+ function mergeConfig(defaultConfig, userConfig) {
9535
9489
  if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
9536
9490
  throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
9537
9491
  }
@@ -9601,7 +9555,7 @@ function deepCpy(obj) {
9601
9555
  /**
9602
9556
  * @ignore
9603
9557
  */
9604
- function enableStreamingMode(config, logger) {
9558
+ function enableStreamingMode(config) {
9605
9559
  const currentLoader = config.loader;
9606
9560
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
9607
9561
  // If a developer has configured their own loader, respect that choice
@@ -9618,9 +9572,10 @@ function enableStreamingMode(config, logger) {
9618
9572
  }
9619
9573
  }
9620
9574
 
9575
+ let chromeOrFirefox;
9621
9576
  class LevelController extends BasePlaylistController {
9622
9577
  constructor(hls, contentSteeringController) {
9623
- super(hls, 'level-controller');
9578
+ super(hls, '[level-controller]');
9624
9579
  this._levels = [];
9625
9580
  this._firstLevel = -1;
9626
9581
  this._maxAutoLevel = -1;
@@ -9691,15 +9646,23 @@ class LevelController extends BasePlaylistController {
9691
9646
  let videoCodecFound = false;
9692
9647
  let audioCodecFound = false;
9693
9648
  data.levels.forEach(levelParsed => {
9694
- var _videoCodec;
9649
+ var _audioCodec, _videoCodec;
9695
9650
  const attributes = levelParsed.attrs;
9651
+
9652
+ // erase audio codec info if browser does not support mp4a.40.34.
9653
+ // demuxer will autodetect codec and fallback to mpeg/audio
9696
9654
  let {
9697
9655
  audioCodec,
9698
9656
  videoCodec
9699
9657
  } = levelParsed;
9658
+ if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
9659
+ chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
9660
+ if (chromeOrFirefox) {
9661
+ levelParsed.audioCodec = audioCodec = undefined;
9662
+ }
9663
+ }
9700
9664
  if (audioCodec) {
9701
- // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
9702
- levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
9665
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
9703
9666
  }
9704
9667
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
9705
9668
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -10827,8 +10790,8 @@ function createLoaderContext(frag, part = null) {
10827
10790
  var _frag$decryptdata;
10828
10791
  let byteRangeStart = start;
10829
10792
  let byteRangeEnd = end;
10830
- if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
10831
- // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
10793
+ if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
10794
+ // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
10832
10795
  // has the unencrypted size specified in the range.
10833
10796
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
10834
10797
  const fragmentLen = end - start;
@@ -10861,9 +10824,6 @@ function createGapLoadError(frag, part) {
10861
10824
  (part ? part : frag).stats.aborted = true;
10862
10825
  return new LoadError(errorData);
10863
10826
  }
10864
- function isMethodFullSegmentAesCbc(method) {
10865
- return method === 'AES-128' || method === 'AES-256';
10866
- }
10867
10827
  class LoadError extends Error {
10868
10828
  constructor(data) {
10869
10829
  super(data.error.message);
@@ -11009,8 +10969,6 @@ class KeyLoader {
11009
10969
  }
11010
10970
  return this.loadKeyEME(keyInfo, frag);
11011
10971
  case 'AES-128':
11012
- case 'AES-256':
11013
- case 'AES-256-CTR':
11014
10972
  return this.loadKeyHTTP(keyInfo, frag);
11015
10973
  default:
11016
10974
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error(`Key supplied with unsupported METHOD: "${decryptdata.method}"`)));
@@ -11146,9 +11104,8 @@ class KeyLoader {
11146
11104
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
11147
11105
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
11148
11106
  */
11149
- class TaskLoop extends Logger {
11150
- constructor(label, logger) {
11151
- super(label, logger);
11107
+ class TaskLoop {
11108
+ constructor() {
11152
11109
  this._boundTick = void 0;
11153
11110
  this._tickTimer = null;
11154
11111
  this._tickInterval = null;
@@ -11416,61 +11373,33 @@ function alignMediaPlaylistByPDT(details, refDetails) {
11416
11373
  }
11417
11374
 
11418
11375
  class AESCrypto {
11419
- constructor(subtle, iv, aesMode) {
11376
+ constructor(subtle, iv) {
11420
11377
  this.subtle = void 0;
11421
11378
  this.aesIV = void 0;
11422
- this.aesMode = void 0;
11423
11379
  this.subtle = subtle;
11424
11380
  this.aesIV = iv;
11425
- this.aesMode = aesMode;
11426
11381
  }
11427
11382
  decrypt(data, key) {
11428
- switch (this.aesMode) {
11429
- case DecrypterAesMode.cbc:
11430
- return this.subtle.decrypt({
11431
- name: 'AES-CBC',
11432
- iv: this.aesIV
11433
- }, key, data);
11434
- case DecrypterAesMode.ctr:
11435
- return this.subtle.decrypt({
11436
- name: 'AES-CTR',
11437
- counter: this.aesIV,
11438
- length: 64
11439
- },
11440
- //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
11441
- key, data);
11442
- default:
11443
- throw new Error(`[AESCrypto] invalid aes mode ${this.aesMode}`);
11444
- }
11383
+ return this.subtle.decrypt({
11384
+ name: 'AES-CBC',
11385
+ iv: this.aesIV
11386
+ }, key, data);
11445
11387
  }
11446
11388
  }
11447
11389
 
11448
11390
  class FastAESKey {
11449
- constructor(subtle, key, aesMode) {
11391
+ constructor(subtle, key) {
11450
11392
  this.subtle = void 0;
11451
11393
  this.key = void 0;
11452
- this.aesMode = void 0;
11453
11394
  this.subtle = subtle;
11454
11395
  this.key = key;
11455
- this.aesMode = aesMode;
11456
11396
  }
11457
11397
  expandKey() {
11458
- const subtleAlgoName = getSubtleAlgoName(this.aesMode);
11459
11398
  return this.subtle.importKey('raw', this.key, {
11460
- name: subtleAlgoName
11399
+ name: 'AES-CBC'
11461
11400
  }, false, ['encrypt', 'decrypt']);
11462
11401
  }
11463
11402
  }
11464
- function getSubtleAlgoName(aesMode) {
11465
- switch (aesMode) {
11466
- case DecrypterAesMode.cbc:
11467
- return 'AES-CBC';
11468
- case DecrypterAesMode.ctr:
11469
- return 'AES-CTR';
11470
- default:
11471
- throw new Error(`[FastAESKey] invalid aes mode ${aesMode}`);
11472
- }
11473
- }
11474
11403
 
11475
11404
  // PKCS7
11476
11405
  function removePadding(array) {
@@ -11720,8 +11649,7 @@ class Decrypter {
11720
11649
  this.currentIV = null;
11721
11650
  this.currentResult = null;
11722
11651
  this.useSoftware = void 0;
11723
- this.enableSoftwareAES = void 0;
11724
- this.enableSoftwareAES = config.enableSoftwareAES;
11652
+ this.useSoftware = config.enableSoftwareAES;
11725
11653
  this.removePKCS7Padding = removePKCS7Padding;
11726
11654
  // built in decryptor expects PKCS7 padding
11727
11655
  if (removePKCS7Padding) {
@@ -11734,7 +11662,9 @@ class Decrypter {
11734
11662
  /* no-op */
11735
11663
  }
11736
11664
  }
11737
- this.useSoftware = this.subtle === null;
11665
+ if (this.subtle === null) {
11666
+ this.useSoftware = true;
11667
+ }
11738
11668
  }
11739
11669
  destroy() {
11740
11670
  this.subtle = null;
@@ -11772,10 +11702,10 @@ class Decrypter {
11772
11702
  this.softwareDecrypter = null;
11773
11703
  }
11774
11704
  }
11775
- decrypt(data, key, iv, aesMode) {
11705
+ decrypt(data, key, iv) {
11776
11706
  if (this.useSoftware) {
11777
11707
  return new Promise((resolve, reject) => {
11778
- this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
11708
+ this.softwareDecrypt(new Uint8Array(data), key, iv);
11779
11709
  const decryptResult = this.flush();
11780
11710
  if (decryptResult) {
11781
11711
  resolve(decryptResult.buffer);
@@ -11784,21 +11714,17 @@ class Decrypter {
11784
11714
  }
11785
11715
  });
11786
11716
  }
11787
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
11717
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
11788
11718
  }
11789
11719
 
11790
11720
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
11791
11721
  // data is handled in the flush() call
11792
- softwareDecrypt(data, key, iv, aesMode) {
11722
+ softwareDecrypt(data, key, iv) {
11793
11723
  const {
11794
11724
  currentIV,
11795
11725
  currentResult,
11796
11726
  remainderData
11797
11727
  } = this;
11798
- if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
11799
- logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
11800
- return null;
11801
- }
11802
11728
  this.logOnce('JS AES decrypt');
11803
11729
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
11804
11730
  // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
@@ -11831,11 +11757,11 @@ class Decrypter {
11831
11757
  }
11832
11758
  return result;
11833
11759
  }
11834
- webCryptoDecrypt(data, key, iv, aesMode) {
11760
+ webCryptoDecrypt(data, key, iv) {
11835
11761
  const subtle = this.subtle;
11836
11762
  if (this.key !== key || !this.fastAesKey) {
11837
11763
  this.key = key;
11838
- this.fastAesKey = new FastAESKey(subtle, key, aesMode);
11764
+ this.fastAesKey = new FastAESKey(subtle, key);
11839
11765
  }
11840
11766
  return this.fastAesKey.expandKey().then(aesKey => {
11841
11767
  // decrypt using web crypto
@@ -11843,25 +11769,22 @@ class Decrypter {
11843
11769
  return Promise.reject(new Error('web crypto not initialized'));
11844
11770
  }
11845
11771
  this.logOnce('WebCrypto AES decrypt');
11846
- const crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
11772
+ const crypto = new AESCrypto(subtle, new Uint8Array(iv));
11847
11773
  return crypto.decrypt(data.buffer, aesKey);
11848
11774
  }).catch(err => {
11849
11775
  logger.warn(`[decrypter]: WebCrypto Error, disable WebCrypto API, ${err.name}: ${err.message}`);
11850
- return this.onWebCryptoError(data, key, iv, aesMode);
11776
+ return this.onWebCryptoError(data, key, iv);
11851
11777
  });
11852
11778
  }
11853
- onWebCryptoError(data, key, iv, aesMode) {
11854
- const enableSoftwareAES = this.enableSoftwareAES;
11855
- if (enableSoftwareAES) {
11856
- this.useSoftware = true;
11857
- this.logEnabled = true;
11858
- this.softwareDecrypt(data, key, iv, aesMode);
11859
- const decryptResult = this.flush();
11860
- if (decryptResult) {
11861
- return decryptResult.buffer;
11862
- }
11779
+ onWebCryptoError(data, key, iv) {
11780
+ this.useSoftware = true;
11781
+ this.logEnabled = true;
11782
+ this.softwareDecrypt(data, key, iv);
11783
+ const decryptResult = this.flush();
11784
+ if (decryptResult) {
11785
+ return decryptResult.buffer;
11863
11786
  }
11864
- throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
11787
+ throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
11865
11788
  }
11866
11789
  getValidChunk(data) {
11867
11790
  let currentChunk = data;
@@ -11912,7 +11835,7 @@ const State = {
11912
11835
  };
11913
11836
  class BaseStreamController extends TaskLoop {
11914
11837
  constructor(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
11915
- super(logPrefix, hls.logger);
11838
+ super();
11916
11839
  this.hls = void 0;
11917
11840
  this.fragPrevious = null;
11918
11841
  this.fragCurrent = null;
@@ -11937,88 +11860,22 @@ class BaseStreamController extends TaskLoop {
11937
11860
  this.startFragRequested = false;
11938
11861
  this.decrypter = void 0;
11939
11862
  this.initPTS = [];
11940
- this.onMediaSeeking = () => {
11941
- const {
11942
- config,
11943
- fragCurrent,
11944
- media,
11945
- mediaBuffer,
11946
- state
11947
- } = this;
11948
- const currentTime = media ? media.currentTime : 0;
11949
- const bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
11950
- this.log(`media seeking to ${isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime}, state: ${state}`);
11951
- if (this.state === State.ENDED) {
11952
- this.resetLoadingState();
11953
- } else if (fragCurrent) {
11954
- // Seeking while frag load is in progress
11955
- const tolerance = config.maxFragLookUpTolerance;
11956
- const fragStartOffset = fragCurrent.start - tolerance;
11957
- const fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
11958
- // if seeking out of buffered range or into new one
11959
- if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
11960
- const pastFragment = currentTime > fragEndOffset;
11961
- // if the seek position is outside the current fragment range
11962
- if (currentTime < fragStartOffset || pastFragment) {
11963
- if (pastFragment && fragCurrent.loader) {
11964
- this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
11965
- fragCurrent.abortRequests();
11966
- this.resetLoadingState();
11967
- }
11968
- this.fragPrevious = null;
11969
- }
11970
- }
11971
- }
11972
- if (media) {
11973
- // Remove gap fragments
11974
- this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
11975
- this.lastCurrentTime = currentTime;
11976
- }
11977
-
11978
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
11979
- if (!this.loadedmetadata && !bufferInfo.len) {
11980
- this.nextLoadPosition = this.startPosition = currentTime;
11981
- }
11982
-
11983
- // Async tick to speed up processing
11984
- this.tickImmediate();
11985
- };
11986
- this.onMediaEnded = () => {
11987
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
11988
- this.startPosition = this.lastCurrentTime = 0;
11989
- if (this.playlistType === PlaylistLevelType.MAIN) {
11990
- this.hls.trigger(Events.MEDIA_ENDED, {
11991
- stalled: false
11992
- });
11993
- }
11994
- };
11863
+ this.onvseeking = null;
11864
+ this.onvended = null;
11865
+ this.logPrefix = '';
11866
+ this.log = void 0;
11867
+ this.warn = void 0;
11995
11868
  this.playlistType = playlistType;
11869
+ this.logPrefix = logPrefix;
11870
+ this.log = logger.log.bind(logger, `${logPrefix}:`);
11871
+ this.warn = logger.warn.bind(logger, `${logPrefix}:`);
11996
11872
  this.hls = hls;
11997
11873
  this.fragmentLoader = new FragmentLoader(hls.config);
11998
11874
  this.keyLoader = keyLoader;
11999
11875
  this.fragmentTracker = fragmentTracker;
12000
11876
  this.config = hls.config;
12001
11877
  this.decrypter = new Decrypter(hls.config);
12002
- }
12003
- registerListeners() {
12004
- const {
12005
- hls
12006
- } = this;
12007
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12008
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12009
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12010
11878
  hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12011
- hls.on(Events.ERROR, this.onError, this);
12012
- }
12013
- unregisterListeners() {
12014
- const {
12015
- hls
12016
- } = this;
12017
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12018
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12019
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12020
- hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12021
- hls.off(Events.ERROR, this.onError, this);
12022
11879
  }
12023
11880
  doTick() {
12024
11881
  this.onTickEnd();
@@ -12072,8 +11929,10 @@ class BaseStreamController extends TaskLoop {
12072
11929
  }
12073
11930
  onMediaAttached(event, data) {
12074
11931
  const media = this.media = this.mediaBuffer = data.media;
12075
- media.addEventListener('seeking', this.onMediaSeeking);
12076
- media.addEventListener('ended', this.onMediaEnded);
11932
+ this.onvseeking = this.onMediaSeeking.bind(this);
11933
+ this.onvended = this.onMediaEnded.bind(this);
11934
+ media.addEventListener('seeking', this.onvseeking);
11935
+ media.addEventListener('ended', this.onvended);
12077
11936
  const config = this.config;
12078
11937
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12079
11938
  this.startLoad(config.startPosition);
@@ -12087,9 +11946,10 @@ class BaseStreamController extends TaskLoop {
12087
11946
  }
12088
11947
 
12089
11948
  // remove video listeners
12090
- if (media) {
12091
- media.removeEventListener('seeking', this.onMediaSeeking);
12092
- media.removeEventListener('ended', this.onMediaEnded);
11949
+ if (media && this.onvseeking && this.onvended) {
11950
+ media.removeEventListener('seeking', this.onvseeking);
11951
+ media.removeEventListener('ended', this.onvended);
11952
+ this.onvseeking = this.onvended = null;
12093
11953
  }
12094
11954
  if (this.keyLoader) {
12095
11955
  this.keyLoader.detach();
@@ -12099,8 +11959,56 @@ class BaseStreamController extends TaskLoop {
12099
11959
  this.fragmentTracker.removeAllFragments();
12100
11960
  this.stopLoad();
12101
11961
  }
12102
- onManifestLoading() {}
12103
- onError(event, data) {}
11962
+ onMediaSeeking() {
11963
+ const {
11964
+ config,
11965
+ fragCurrent,
11966
+ media,
11967
+ mediaBuffer,
11968
+ state
11969
+ } = this;
11970
+ const currentTime = media ? media.currentTime : 0;
11971
+ const bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
11972
+ this.log(`media seeking to ${isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime}, state: ${state}`);
11973
+ if (this.state === State.ENDED) {
11974
+ this.resetLoadingState();
11975
+ } else if (fragCurrent) {
11976
+ // Seeking while frag load is in progress
11977
+ const tolerance = config.maxFragLookUpTolerance;
11978
+ const fragStartOffset = fragCurrent.start - tolerance;
11979
+ const fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
11980
+ // if seeking out of buffered range or into new one
11981
+ if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
11982
+ const pastFragment = currentTime > fragEndOffset;
11983
+ // if the seek position is outside the current fragment range
11984
+ if (currentTime < fragStartOffset || pastFragment) {
11985
+ if (pastFragment && fragCurrent.loader) {
11986
+ this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
11987
+ fragCurrent.abortRequests();
11988
+ this.resetLoadingState();
11989
+ }
11990
+ this.fragPrevious = null;
11991
+ }
11992
+ }
11993
+ }
11994
+ if (media) {
11995
+ // Remove gap fragments
11996
+ this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
11997
+ this.lastCurrentTime = currentTime;
11998
+ }
11999
+
12000
+ // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12001
+ if (!this.loadedmetadata && !bufferInfo.len) {
12002
+ this.nextLoadPosition = this.startPosition = currentTime;
12003
+ }
12004
+
12005
+ // Async tick to speed up processing
12006
+ this.tickImmediate();
12007
+ }
12008
+ onMediaEnded() {
12009
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12010
+ this.startPosition = this.lastCurrentTime = 0;
12011
+ }
12104
12012
  onManifestLoaded(event, data) {
12105
12013
  this.startTimeOffset = data.startTimeOffset;
12106
12014
  this.initPTS = [];
@@ -12110,7 +12018,7 @@ class BaseStreamController extends TaskLoop {
12110
12018
  this.stopLoad();
12111
12019
  super.onHandlerDestroying();
12112
12020
  // @ts-ignore
12113
- this.hls = this.onMediaSeeking = this.onMediaEnded = null;
12021
+ this.hls = null;
12114
12022
  }
12115
12023
  onHandlerDestroyed() {
12116
12024
  this.state = State.STOPPED;
@@ -12241,10 +12149,10 @@ class BaseStreamController extends TaskLoop {
12241
12149
  const decryptData = frag.decryptdata;
12242
12150
 
12243
12151
  // check to see if the payload needs to be decrypted
12244
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
12152
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
12245
12153
  const startTime = self.performance.now();
12246
12154
  // decrypt init segment data
12247
- return this.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(err => {
12155
+ return this.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(err => {
12248
12156
  hls.trigger(Events.ERROR, {
12249
12157
  type: ErrorTypes.MEDIA_ERROR,
12250
12158
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -12356,7 +12264,7 @@ class BaseStreamController extends TaskLoop {
12356
12264
  }
12357
12265
  let keyLoadingPromise = null;
12358
12266
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
12359
- this.log(`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'} ${frag.level}`);
12267
+ this.log(`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${this.logPrefix === '[stream-controller]' ? 'level' : 'track'} ${frag.level}`);
12360
12268
  this.state = State.KEY_LOADING;
12361
12269
  this.fragCurrent = frag;
12362
12270
  keyLoadingPromise = this.keyLoader.load(frag).then(keyLoadedData => {
@@ -12387,7 +12295,7 @@ class BaseStreamController extends TaskLoop {
12387
12295
  const partIndex = this.getNextPart(partList, frag, targetBufferTime);
12388
12296
  if (partIndex > -1) {
12389
12297
  const part = partList[partIndex];
12390
- 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))}`);
12298
+ 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))}`);
12391
12299
  this.nextLoadPosition = part.start + part.duration;
12392
12300
  this.state = State.FRAG_LOADING;
12393
12301
  let _result;
@@ -12416,7 +12324,7 @@ class BaseStreamController extends TaskLoop {
12416
12324
  }
12417
12325
  }
12418
12326
  }
12419
- 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))}`);
12327
+ 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))}`);
12420
12328
  // Don't update nextLoadPosition for fragments which are not buffered
12421
12329
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
12422
12330
  this.nextLoadPosition = frag.start + frag.duration;
@@ -13001,7 +12909,7 @@ class BaseStreamController extends TaskLoop {
13001
12909
  errorAction.resolved = true;
13002
12910
  }
13003
12911
  } else {
13004
- this.warn(`${data.details} reached or exceeded max retry (${retryCount})`);
12912
+ logger.warn(`${data.details} reached or exceeded max retry (${retryCount})`);
13005
12913
  return;
13006
12914
  }
13007
12915
  } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
@@ -13396,7 +13304,6 @@ const initPTSFn = (timestamp, timeOffset, initPTS) => {
13396
13304
  */
13397
13305
  function getAudioConfig(observer, data, offset, audioCodec) {
13398
13306
  let adtsObjectType;
13399
- let originalAdtsObjectType;
13400
13307
  let adtsExtensionSamplingIndex;
13401
13308
  let adtsChannelConfig;
13402
13309
  let config;
@@ -13404,7 +13311,7 @@ function getAudioConfig(observer, data, offset, audioCodec) {
13404
13311
  const manifestCodec = audioCodec;
13405
13312
  const adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
13406
13313
  // byte 2
13407
- adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13314
+ adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13408
13315
  const adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
13409
13316
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
13410
13317
  const error = new Error(`invalid ADTS sampling index:${adtsSamplingIndex}`);
@@ -13421,8 +13328,8 @@ function getAudioConfig(observer, data, offset, audioCodec) {
13421
13328
  // byte 3
13422
13329
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
13423
13330
  logger.log(`manifest codec:${audioCodec}, ADTS type:${adtsObjectType}, samplingIndex:${adtsSamplingIndex}`);
13424
- // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
13425
- if (/firefox|palemoon/i.test(userAgent)) {
13331
+ // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
13332
+ if (/firefox/i.test(userAgent)) {
13426
13333
  if (adtsSamplingIndex >= 6) {
13427
13334
  adtsObjectType = 5;
13428
13335
  config = new Array(4);
@@ -13516,7 +13423,6 @@ function getAudioConfig(observer, data, offset, audioCodec) {
13516
13423
  samplerate: adtsSamplingRates[adtsSamplingIndex],
13517
13424
  channelCount: adtsChannelConfig,
13518
13425
  codec: 'mp4a.40.' + adtsObjectType,
13519
- parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
13520
13426
  manifestCodec
13521
13427
  };
13522
13428
  }
@@ -13571,8 +13477,7 @@ function initTrackConfig(track, observer, data, offset, audioCodec) {
13571
13477
  track.channelCount = config.channelCount;
13572
13478
  track.codec = config.codec;
13573
13479
  track.manifestCodec = config.manifestCodec;
13574
- track.parsedCodec = config.parsedCodec;
13575
- logger.log(`parsed codec:${track.parsedCodec}, codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`);
13480
+ logger.log(`parsed codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`);
13576
13481
  }
13577
13482
  }
13578
13483
  function getFrameDuration(samplerate) {
@@ -14635,7 +14540,7 @@ class SampleAesDecrypter {
14635
14540
  });
14636
14541
  }
14637
14542
  decryptBuffer(encryptedData) {
14638
- return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
14543
+ return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
14639
14544
  }
14640
14545
 
14641
14546
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -16552,24 +16457,12 @@ class MP4Remuxer {
16552
16457
  inputSamples[0].dts = firstDTS;
16553
16458
  inputSamples[0].pts = firstPTS;
16554
16459
  } else {
16555
- let isPTSOrderRetained = true;
16556
16460
  for (let i = 0; i < inputSamples.length; i++) {
16557
- if (inputSamples[i].dts > firstPTS && isPTSOrderRetained) {
16461
+ if (inputSamples[i].dts > firstPTS) {
16558
16462
  break;
16559
16463
  }
16560
- const prevPTS = inputSamples[i].pts;
16561
16464
  inputSamples[i].dts -= delta;
16562
16465
  inputSamples[i].pts -= delta;
16563
-
16564
- // check to see if this sample's PTS order has changed
16565
- // relative to the next one
16566
- if (i < inputSamples.length - 1) {
16567
- const nextSamplePTS = inputSamples[i + 1].pts;
16568
- const currentSamplePTS = inputSamples[i].pts;
16569
- const currentOrder = nextSamplePTS <= currentSamplePTS;
16570
- const prevOrder = nextSamplePTS <= prevPTS;
16571
- isPTSOrderRetained = currentOrder == prevOrder;
16572
- }
16573
16466
  }
16574
16467
  }
16575
16468
  logger.log(`Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(firstPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
@@ -16850,7 +16743,7 @@ class MP4Remuxer {
16850
16743
  logger.warn(`[mp4-remuxer]: Injecting ${missing} audio frame @ ${(nextPts / inputTimeScale).toFixed(3)}s due to ${Math.round(1000 * delta / inputTimeScale)} ms gap.`);
16851
16744
  for (let j = 0; j < missing; j++) {
16852
16745
  const newStamp = Math.max(nextPts, 0);
16853
- let fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
16746
+ let fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
16854
16747
  if (!fillFrame) {
16855
16748
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
16856
16749
  fillFrame = sample.unit.subarray();
@@ -16978,7 +16871,7 @@ class MP4Remuxer {
16978
16871
  // samples count of this segment's duration
16979
16872
  const nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
16980
16873
  // silent frame
16981
- const silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
16874
+ const silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
16982
16875
  logger.warn('[mp4-remuxer]: remux empty Audio');
16983
16876
  // Can't remux if we can't generate a silent frame...
16984
16877
  if (!silentFrame) {
@@ -17369,15 +17262,13 @@ class Transmuxer {
17369
17262
  initSegmentData
17370
17263
  } = transmuxConfig;
17371
17264
  const keyData = getEncryptionType(uintData, decryptdata);
17372
- if (keyData && isFullSegmentEncryption(keyData.method)) {
17265
+ if (keyData && keyData.method === 'AES-128') {
17373
17266
  const decrypter = this.getDecrypter();
17374
- const aesMode = getAesModeFromFullSegmentMethod(keyData.method);
17375
-
17376
17267
  // Software decryption is synchronous; webCrypto is not
17377
17268
  if (decrypter.isSync()) {
17378
17269
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
17379
17270
  // data is handled in the flush() call
17380
- let decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
17271
+ let decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
17381
17272
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
17382
17273
  const loadingParts = chunkMeta.part > -1;
17383
17274
  if (loadingParts) {
@@ -17389,7 +17280,7 @@ class Transmuxer {
17389
17280
  }
17390
17281
  uintData = new Uint8Array(decryptedData);
17391
17282
  } else {
17392
- this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(decryptedData => {
17283
+ this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(decryptedData => {
17393
17284
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
17394
17285
  // the decrypted data has been transmuxed
17395
17286
  const result = this.push(decryptedData, null, chunkMeta);
@@ -18043,7 +17934,14 @@ class TransmuxerInterface {
18043
17934
  this.observer = new EventEmitter();
18044
17935
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
18045
17936
  this.observer.on(Events.ERROR, forwardMessage);
18046
- const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
17937
+ const MediaSource = getMediaSource(config.preferManagedMediaSource) || {
17938
+ isTypeSupported: () => false
17939
+ };
17940
+ const m2tsTypeSupported = {
17941
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
17942
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
17943
+ ac3: false
17944
+ };
18047
17945
 
18048
17946
  // navigator.vendor is not always available in Web Worker
18049
17947
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -18307,9 +18205,8 @@ const STALL_MINIMUM_DURATION_MS = 250;
18307
18205
  const MAX_START_GAP_JUMP = 2.0;
18308
18206
  const SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
18309
18207
  const SKIP_BUFFER_RANGE_START = 0.05;
18310
- class GapController extends Logger {
18208
+ class GapController {
18311
18209
  constructor(config, media, fragmentTracker, hls) {
18312
- super('gap-controller', hls.logger);
18313
18210
  this.config = void 0;
18314
18211
  this.media = null;
18315
18212
  this.fragmentTracker = void 0;
@@ -18319,7 +18216,6 @@ class GapController extends Logger {
18319
18216
  this.stalled = null;
18320
18217
  this.moved = false;
18321
18218
  this.seeking = false;
18322
- this.ended = 0;
18323
18219
  this.config = config;
18324
18220
  this.media = media;
18325
18221
  this.fragmentTracker = fragmentTracker;
@@ -18337,7 +18233,7 @@ class GapController extends Logger {
18337
18233
  *
18338
18234
  * @param lastCurrentTime - Previously read playhead position
18339
18235
  */
18340
- poll(lastCurrentTime, activeFrag, levelDetails, state) {
18236
+ poll(lastCurrentTime, activeFrag) {
18341
18237
  const {
18342
18238
  config,
18343
18239
  media,
@@ -18356,7 +18252,6 @@ class GapController extends Logger {
18356
18252
 
18357
18253
  // The playhead is moving, no-op
18358
18254
  if (currentTime !== lastCurrentTime) {
18359
- this.ended = 0;
18360
18255
  this.moved = true;
18361
18256
  if (!seeking) {
18362
18257
  this.nudgeRetry = 0;
@@ -18365,7 +18260,7 @@ class GapController extends Logger {
18365
18260
  // The playhead is now moving, but was previously stalled
18366
18261
  if (this.stallReported) {
18367
18262
  const _stalledDuration = self.performance.now() - stalled;
18368
- this.warn(`playback not stuck anymore @${currentTime}, after ${Math.round(_stalledDuration)}ms`);
18263
+ logger.warn(`playback not stuck anymore @${currentTime}, after ${Math.round(_stalledDuration)}ms`);
18369
18264
  this.stallReported = false;
18370
18265
  }
18371
18266
  this.stalled = null;
@@ -18401,6 +18296,7 @@ class GapController extends Logger {
18401
18296
  // Skip start gaps if we haven't played, but the last poll detected the start of a stall
18402
18297
  // The addition poll gives the browser a chance to jump the gap for us
18403
18298
  if (!this.moved && this.stalled !== null) {
18299
+ var _level$details;
18404
18300
  // There is no playable buffer (seeked, waiting for buffer)
18405
18301
  const isBuffered = bufferInfo.len > 0;
18406
18302
  if (!isBuffered && !nextStart) {
@@ -18412,8 +18308,9 @@ class GapController extends Logger {
18412
18308
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
18413
18309
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
18414
18310
  // that begins over 1 target duration after the video start position.
18415
- const isLive = !!(levelDetails != null && levelDetails.live);
18416
- const maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
18311
+ const level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
18312
+ const isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
18313
+ const maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
18417
18314
  const partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
18418
18315
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
18419
18316
  if (!media.paused) {
@@ -18431,17 +18328,6 @@ class GapController extends Logger {
18431
18328
  }
18432
18329
  const stalledDuration = tnow - stalled;
18433
18330
  if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
18434
- // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
18435
- if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
18436
- if (stalledDuration < 1000 || this.ended) {
18437
- return;
18438
- }
18439
- this.ended = currentTime;
18440
- this.hls.trigger(Events.MEDIA_ENDED, {
18441
- stalled: true
18442
- });
18443
- return;
18444
- }
18445
18331
  // Report stalling after trying to fix
18446
18332
  this._reportStall(bufferInfo);
18447
18333
  if (!this.media) {
@@ -18485,7 +18371,7 @@ class GapController extends Logger {
18485
18371
  // needs to cross some sort of threshold covering all source-buffers content
18486
18372
  // to start playing properly.
18487
18373
  if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
18488
- this.warn('Trying to nudge playhead over buffer-hole');
18374
+ logger.warn('Trying to nudge playhead over buffer-hole');
18489
18375
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
18490
18376
  // We only try to jump the hole if it's under the configured size
18491
18377
  // Reset stalled so to rearm watchdog timer
@@ -18509,7 +18395,7 @@ class GapController extends Logger {
18509
18395
  // Report stalled error once
18510
18396
  this.stallReported = true;
18511
18397
  const error = new Error(`Playback stalling at @${media.currentTime} due to low buffer (${JSON.stringify(bufferInfo)})`);
18512
- this.warn(error.message);
18398
+ logger.warn(error.message);
18513
18399
  hls.trigger(Events.ERROR, {
18514
18400
  type: ErrorTypes.MEDIA_ERROR,
18515
18401
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -18577,7 +18463,7 @@ class GapController extends Logger {
18577
18463
  }
18578
18464
  }
18579
18465
  const targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
18580
- this.warn(`skipping hole, adjusting currentTime from ${currentTime} to ${targetTime}`);
18466
+ logger.warn(`skipping hole, adjusting currentTime from ${currentTime} to ${targetTime}`);
18581
18467
  this.moved = true;
18582
18468
  this.stalled = null;
18583
18469
  media.currentTime = targetTime;
@@ -18618,7 +18504,7 @@ class GapController extends Logger {
18618
18504
  const targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
18619
18505
  // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
18620
18506
  const error = new Error(`Nudging 'currentTime' from ${currentTime} to ${targetTime}`);
18621
- this.warn(error.message);
18507
+ logger.warn(error.message);
18622
18508
  media.currentTime = targetTime;
18623
18509
  hls.trigger(Events.ERROR, {
18624
18510
  type: ErrorTypes.MEDIA_ERROR,
@@ -18628,7 +18514,7 @@ class GapController extends Logger {
18628
18514
  });
18629
18515
  } else {
18630
18516
  const error = new Error(`Playhead still not moving while enough data buffered @${currentTime} after ${config.nudgeMaxRetry} nudges`);
18631
- this.error(error.message);
18517
+ logger.error(error.message);
18632
18518
  hls.trigger(Events.ERROR, {
18633
18519
  type: ErrorTypes.MEDIA_ERROR,
18634
18520
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -18643,7 +18529,7 @@ const TICK_INTERVAL = 100; // how often to tick in ms
18643
18529
 
18644
18530
  class StreamController extends BaseStreamController {
18645
18531
  constructor(hls, fragmentTracker, keyLoader) {
18646
- super(hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN);
18532
+ super(hls, fragmentTracker, keyLoader, '[stream-controller]', PlaylistLevelType.MAIN);
18647
18533
  this.audioCodecSwap = false;
18648
18534
  this.gapController = null;
18649
18535
  this.level = -1;
@@ -18651,43 +18537,27 @@ class StreamController extends BaseStreamController {
18651
18537
  this.altAudio = false;
18652
18538
  this.audioOnly = false;
18653
18539
  this.fragPlaying = null;
18540
+ this.onvplaying = null;
18541
+ this.onvseeked = null;
18654
18542
  this.fragLastKbps = 0;
18655
18543
  this.couldBacktrack = false;
18656
18544
  this.backtrackFragment = null;
18657
18545
  this.audioCodecSwitch = false;
18658
18546
  this.videoBuffer = null;
18659
- this.onMediaPlaying = () => {
18660
- // tick to speed up FRAG_CHANGED triggering
18661
- this.tick();
18662
- };
18663
- this.onMediaSeeked = () => {
18664
- const media = this.media;
18665
- const currentTime = media ? media.currentTime : null;
18666
- if (isFiniteNumber(currentTime)) {
18667
- this.log(`Media seeked to ${currentTime.toFixed(3)}`);
18668
- }
18669
-
18670
- // If seeked was issued before buffer was appended do not tick immediately
18671
- const bufferInfo = this.getMainFwdBufferInfo();
18672
- if (bufferInfo === null || bufferInfo.len === 0) {
18673
- this.warn(`Main forward buffer length on "seeked" event ${bufferInfo ? bufferInfo.len : 'empty'})`);
18674
- return;
18675
- }
18676
-
18677
- // tick to speed up FRAG_CHANGED triggering
18678
- this.tick();
18679
- };
18680
- this.registerListeners();
18547
+ this._registerListeners();
18681
18548
  }
18682
- registerListeners() {
18683
- super.registerListeners();
18549
+ _registerListeners() {
18684
18550
  const {
18685
18551
  hls
18686
18552
  } = this;
18553
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
18554
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
18555
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
18687
18556
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
18688
18557
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
18689
18558
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
18690
18559
  hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
18560
+ hls.on(Events.ERROR, this.onError, this);
18691
18561
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
18692
18562
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
18693
18563
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -18695,14 +18565,17 @@ class StreamController extends BaseStreamController {
18695
18565
  hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
18696
18566
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
18697
18567
  }
18698
- unregisterListeners() {
18699
- super.unregisterListeners();
18568
+ _unregisterListeners() {
18700
18569
  const {
18701
18570
  hls
18702
18571
  } = this;
18572
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
18573
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
18574
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
18703
18575
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
18704
18576
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
18705
18577
  hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
18578
+ hls.off(Events.ERROR, this.onError, this);
18706
18579
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
18707
18580
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
18708
18581
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -18711,9 +18584,7 @@ class StreamController extends BaseStreamController {
18711
18584
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
18712
18585
  }
18713
18586
  onHandlerDestroying() {
18714
- // @ts-ignore
18715
- this.onMediaPlaying = this.onMediaSeeked = null;
18716
- this.unregisterListeners();
18587
+ this._unregisterListeners();
18717
18588
  super.onHandlerDestroying();
18718
18589
  }
18719
18590
  startLoad(startPosition) {
@@ -19040,17 +18911,20 @@ class StreamController extends BaseStreamController {
19040
18911
  onMediaAttached(event, data) {
19041
18912
  super.onMediaAttached(event, data);
19042
18913
  const media = data.media;
19043
- media.addEventListener('playing', this.onMediaPlaying);
19044
- media.addEventListener('seeked', this.onMediaSeeked);
18914
+ this.onvplaying = this.onMediaPlaying.bind(this);
18915
+ this.onvseeked = this.onMediaSeeked.bind(this);
18916
+ media.addEventListener('playing', this.onvplaying);
18917
+ media.addEventListener('seeked', this.onvseeked);
19045
18918
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
19046
18919
  }
19047
18920
  onMediaDetaching() {
19048
18921
  const {
19049
18922
  media
19050
18923
  } = this;
19051
- if (media) {
19052
- media.removeEventListener('playing', this.onMediaPlaying);
19053
- media.removeEventListener('seeked', this.onMediaSeeked);
18924
+ if (media && this.onvplaying && this.onvseeked) {
18925
+ media.removeEventListener('playing', this.onvplaying);
18926
+ media.removeEventListener('seeked', this.onvseeked);
18927
+ this.onvplaying = this.onvseeked = null;
19054
18928
  this.videoBuffer = null;
19055
18929
  }
19056
18930
  this.fragPlaying = null;
@@ -19060,6 +18934,27 @@ class StreamController extends BaseStreamController {
19060
18934
  }
19061
18935
  super.onMediaDetaching();
19062
18936
  }
18937
+ onMediaPlaying() {
18938
+ // tick to speed up FRAG_CHANGED triggering
18939
+ this.tick();
18940
+ }
18941
+ onMediaSeeked() {
18942
+ const media = this.media;
18943
+ const currentTime = media ? media.currentTime : null;
18944
+ if (isFiniteNumber(currentTime)) {
18945
+ this.log(`Media seeked to ${currentTime.toFixed(3)}`);
18946
+ }
18947
+
18948
+ // If seeked was issued before buffer was appended do not tick immediately
18949
+ const bufferInfo = this.getMainFwdBufferInfo();
18950
+ if (bufferInfo === null || bufferInfo.len === 0) {
18951
+ this.warn(`Main forward buffer length on "seeked" event ${bufferInfo ? bufferInfo.len : 'empty'})`);
18952
+ return;
18953
+ }
18954
+
18955
+ // tick to speed up FRAG_CHANGED triggering
18956
+ this.tick();
18957
+ }
19063
18958
  onManifestLoading() {
19064
18959
  // reset buffer on manifest loading
19065
18960
  this.log('Trigger BUFFER_RESET');
@@ -19351,10 +19246,8 @@ class StreamController extends BaseStreamController {
19351
19246
  }
19352
19247
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
19353
19248
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
19354
- const state = this.state;
19355
- const activeFrag = state !== State.IDLE ? this.fragCurrent : null;
19356
- const levelDetails = this.getLevelDetails();
19357
- gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
19249
+ const activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
19250
+ gapController.poll(this.lastCurrentTime, activeFrag);
19358
19251
  }
19359
19252
  this.lastCurrentTime = media.currentTime;
19360
19253
  }
@@ -19792,7 +19685,7 @@ class Hls {
19792
19685
  * Get the video-dev/hls.js package version.
19793
19686
  */
19794
19687
  static get version() {
19795
- return "1.5.2-0.canary.9934";
19688
+ return "1.5.3";
19796
19689
  }
19797
19690
 
19798
19691
  /**
@@ -19855,10 +19748,6 @@ class Hls {
19855
19748
  * The configuration object provided on player instantiation.
19856
19749
  */
19857
19750
  this.userConfig = void 0;
19858
- /**
19859
- * The logger functions used by this player instance, configured on player instantiation.
19860
- */
19861
- this.logger = void 0;
19862
19751
  this.coreComponents = void 0;
19863
19752
  this.networkControllers = void 0;
19864
19753
  this.started = false;
@@ -19878,11 +19767,11 @@ class Hls {
19878
19767
  this._media = null;
19879
19768
  this.url = null;
19880
19769
  this.triggeringException = void 0;
19881
- const logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
19882
- const config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
19770
+ enableLogs(userConfig.debug || false, 'Hls instance');
19771
+ const config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
19883
19772
  this.userConfig = userConfig;
19884
19773
  if (config.progressive) {
19885
- enableStreamingMode(config, logger);
19774
+ enableStreamingMode(config);
19886
19775
  }
19887
19776
 
19888
19777
  // core controllers and network loaders
@@ -19981,7 +19870,7 @@ class Hls {
19981
19870
  try {
19982
19871
  return this.emit(event, event, eventObject);
19983
19872
  } catch (error) {
19984
- this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
19873
+ logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
19985
19874
  // Prevent recursion in error event handlers that throw #5497
19986
19875
  if (!this.triggeringException) {
19987
19876
  this.triggeringException = true;
@@ -20007,7 +19896,7 @@ class Hls {
20007
19896
  * Dispose of the instance
20008
19897
  */
20009
19898
  destroy() {
20010
- this.logger.log('destroy');
19899
+ logger.log('destroy');
20011
19900
  this.trigger(Events.DESTROYING, undefined);
20012
19901
  this.detachMedia();
20013
19902
  this.removeAllListeners();
@@ -20028,7 +19917,7 @@ class Hls {
20028
19917
  * Attaches Hls.js to a media element
20029
19918
  */
20030
19919
  attachMedia(media) {
20031
- this.logger.log('attachMedia');
19920
+ logger.log('attachMedia');
20032
19921
  this._media = media;
20033
19922
  this.trigger(Events.MEDIA_ATTACHING, {
20034
19923
  media: media
@@ -20039,7 +19928,7 @@ class Hls {
20039
19928
  * Detach Hls.js from the media
20040
19929
  */
20041
19930
  detachMedia() {
20042
- this.logger.log('detachMedia');
19931
+ logger.log('detachMedia');
20043
19932
  this.trigger(Events.MEDIA_DETACHING, undefined);
20044
19933
  this._media = null;
20045
19934
  }
@@ -20056,7 +19945,7 @@ class Hls {
20056
19945
  });
20057
19946
  this._autoLevelCapping = -1;
20058
19947
  this._maxHdcpLevel = null;
20059
- this.logger.log(`loadSource:${loadingSource}`);
19948
+ logger.log(`loadSource:${loadingSource}`);
20060
19949
  if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
20061
19950
  this.detachMedia();
20062
19951
  this.attachMedia(media);
@@ -20075,7 +19964,7 @@ class Hls {
20075
19964
  * Defaults to -1 (None: starts from earliest point)
20076
19965
  */
20077
19966
  startLoad(startPosition = -1) {
20078
- this.logger.log(`startLoad(${startPosition})`);
19967
+ logger.log(`startLoad(${startPosition})`);
20079
19968
  this.started = true;
20080
19969
  this.networkControllers.forEach(controller => {
20081
19970
  controller.startLoad(startPosition);
@@ -20086,7 +19975,7 @@ class Hls {
20086
19975
  * Stop loading of any stream data.
20087
19976
  */
20088
19977
  stopLoad() {
20089
- this.logger.log('stopLoad');
19978
+ logger.log('stopLoad');
20090
19979
  this.started = false;
20091
19980
  this.networkControllers.forEach(controller => {
20092
19981
  controller.stopLoad();
@@ -20122,7 +20011,7 @@ class Hls {
20122
20011
  * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
20123
20012
  */
20124
20013
  swapAudioCodec() {
20125
- this.logger.log('swapAudioCodec');
20014
+ logger.log('swapAudioCodec');
20126
20015
  this.streamController.swapAudioCodec();
20127
20016
  }
20128
20017
 
@@ -20133,7 +20022,7 @@ class Hls {
20133
20022
  * Automatic recovery of media-errors by this process is configurable.
20134
20023
  */
20135
20024
  recoverMediaError() {
20136
- this.logger.log('recoverMediaError');
20025
+ logger.log('recoverMediaError');
20137
20026
  const media = this._media;
20138
20027
  this.detachMedia();
20139
20028
  if (media) {
@@ -20163,7 +20052,7 @@ class Hls {
20163
20052
  * 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.
20164
20053
  */
20165
20054
  set currentLevel(newLevel) {
20166
- this.logger.log(`set currentLevel:${newLevel}`);
20055
+ logger.log(`set currentLevel:${newLevel}`);
20167
20056
  this.levelController.manualLevel = newLevel;
20168
20057
  this.streamController.immediateLevelSwitch();
20169
20058
  }
@@ -20182,7 +20071,7 @@ class Hls {
20182
20071
  * @param newLevel - Pass -1 for automatic level selection
20183
20072
  */
20184
20073
  set nextLevel(newLevel) {
20185
- this.logger.log(`set nextLevel:${newLevel}`);
20074
+ logger.log(`set nextLevel:${newLevel}`);
20186
20075
  this.levelController.manualLevel = newLevel;
20187
20076
  this.streamController.nextLevelSwitch();
20188
20077
  }
@@ -20201,7 +20090,7 @@ class Hls {
20201
20090
  * @param newLevel - Pass -1 for automatic level selection
20202
20091
  */
20203
20092
  set loadLevel(newLevel) {
20204
- this.logger.log(`set loadLevel:${newLevel}`);
20093
+ logger.log(`set loadLevel:${newLevel}`);
20205
20094
  this.levelController.manualLevel = newLevel;
20206
20095
  }
20207
20096
 
@@ -20232,7 +20121,7 @@ class Hls {
20232
20121
  * Sets "first-level", see getter.
20233
20122
  */
20234
20123
  set firstLevel(newLevel) {
20235
- this.logger.log(`set firstLevel:${newLevel}`);
20124
+ logger.log(`set firstLevel:${newLevel}`);
20236
20125
  this.levelController.firstLevel = newLevel;
20237
20126
  }
20238
20127
 
@@ -20257,7 +20146,7 @@ class Hls {
20257
20146
  * (determined from download of first segment)
20258
20147
  */
20259
20148
  set startLevel(newLevel) {
20260
- this.logger.log(`set startLevel:${newLevel}`);
20149
+ logger.log(`set startLevel:${newLevel}`);
20261
20150
  // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
20262
20151
  if (newLevel !== -1) {
20263
20152
  newLevel = Math.max(newLevel, this.minAutoLevel);
@@ -20332,7 +20221,7 @@ class Hls {
20332
20221
  */
20333
20222
  set autoLevelCapping(newLevel) {
20334
20223
  if (this._autoLevelCapping !== newLevel) {
20335
- this.logger.log(`set autoLevelCapping:${newLevel}`);
20224
+ logger.log(`set autoLevelCapping:${newLevel}`);
20336
20225
  this._autoLevelCapping = newLevel;
20337
20226
  this.levelController.checkMaxAutoUpdated();
20338
20227
  }