PageSourceSearch

https://docs.paykeeper.ru/wp-content/plugins/plyr-hls//deps/hls/hls.light.js

js paykeeper.ru collected 2026-10-02 02:33:55 UTC 866,303 bytes, 22,133 lines download raw bytes

vendor: 4,853 bytes, lines 1-134
1(function __HLS_WORKER_BUNDLE__(__IN_WORKER__){
2(function (global, factory) {
3  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4  typeof define === 'function' && define.amd ? define(factory) :
5  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Hls = factory());
6})(this, (function () { 'use strict';
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 _defineProperties(e, r) {
16    for (var t = 0; t < r.length; t++) {
17      var o = r[t];
18      o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
19    }
20  }
21  function _createClass(e, r, t) {
22    return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
23      writable: !1
24    }), e;
25  }
26  function _defineProperty(e, r, t) {
27    return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
28      value: t,
29      enumerable: !0,
30      configurable: !0,
31      writable: !0
32    }) : e[r] = t, e;
33  }
34  function _extends() {
35    return _extends = Object.assign ? Object.assign.bind() : function (n) {
36      for (var e = 1; e < arguments.length; e++) {
37        var t = arguments[e];
38        for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
39      }
40      return n;
41    }, _extends.apply(null, arguments);
42  }
43  function _getPrototypeOf(t) {
44    return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
45      return t.__proto__ || Object.getPrototypeOf(t);
46    }, _getPrototypeOf(t);
47  }
48  function _inheritsLoose(t, o) {
49    t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o);
50  }
51  function _isNativeFunction(t) {
52    try {
53      return -1 !== Function.toString.call(t).indexOf("[native code]");
54    } catch (n) {
55      return "function" == typeof t;
56    }
57  }
58  function _isNativeReflectConstruct() {
59    try {
60      var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
61    } catch (t) {}
62    return (_isNativeReflectConstruct = function () {
63      return !!t;
64    })();
65  }
66  function ownKeys(e, r) {
67    var t = Object.keys(e);
68    if (Object.getOwnPropertySymbols) {
69      var o = Object.getOwnPropertySymbols(e);
70      r && (o = o.filter(function (r) {
71        return Object.getOwnPropertyDescriptor(e, r).enumerable;
72      })), t.push.apply(t, o);
73    }
74    return t;
75  }
76  function _objectSpread2(e) {
77    for (var r = 1; r < arguments.length; r++) {
78      var t = null != arguments[r] ? arguments[r] : {};
79      r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
80        _defineProperty(e, r, t[r]);
81      }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
82        Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
83      });
84    }
85    return e;
86  }
87  function _setPrototypeOf(t, e) {
88    return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
89      return t.__proto__ = e, t;
90    }, _setPrototypeOf(t, e);
91  }
92  function _toPrimitive(t, r) {
93    if ("object" != typeof t || !t) return t;
94    var e = t[Symbol.toPrimitive];
95    if (void 0 !== e) {
96      var i = e.call(t, r || "default");
97      if ("object" != typeof i) return i;
98      throw new TypeError("@@toPrimitive must return a primitive value.");
99    }
100    return ("string" === r ? String : Number)(t);
101  }
102  function _toPropertyKey(t) {
103    var i = _toPrimitive(t, "string");
104    return "symbol" == typeof i ? i : i + "";
105  }
106  function _wrapNativeSuper(t) {
107    var r = "function" == typeof Map ? new Map() : void 0;
108    return _wrapNativeSuper = function (t) {
109      if (null === t || !_isNativeFunction(t)) return t;
110      if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function");
111      if (void 0 !== r) {
112        if (r.has(t)) return r.get(t);
113        r.set(t, Wrapper);
114      }
115      function Wrapper() {
116        return _construct(t, arguments, _getPrototypeOf(this).constructor);
117      }
118      return Wrapper.prototype = Object.create(t.prototype, {
119        constructor: {
120          value: Wrapper,
121          enumerable: !1,
122          writable: !0,
123          configurable: !0
124        }
125      }), _setPrototypeOf(Wrapper, t);
126    }, _wrapNativeSuper(t);
127  }
128
129  function getDefaultExportFromCjs (x) {
130  	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
131  }
132
133  var urlToolkit = {exports: {}};
134
vendor: 7,947 bytes, lines 135-318
135  (function (module, exports) {
136  	// see https://tools.ietf.org/html/rfc1808
137
138  	(function (root) {
139  	  var URL_REGEX =
140  	    /^(?=((?:[a-zA-Z0-9+\-.]+:)?))\1(?=((?:\/\/[^\/?#]*)?))\2(?=((?:(?:[^?#\/]*\/)*[^;?#\/]*)?))\3((?:;[^?#]*)?)(\?[^#]*)?(#[^]*)?$/;
141  	  var FIRST_SEGMENT_REGEX = /^(?=([^\/?#]*))\1([^]*)$/;
142  	  var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g;
143  	  var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g;
144
145  	  var URLToolkit = {
146  	    // If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or //
147  	    // E.g
148  	    // With opts.alwaysNormalize = false (default, spec compliant)
149  	    // http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g
150  	    // With opts.alwaysNormalize = true (not spec compliant)
151  	    // http://a.com/b/cd + /e/f/../g => http://a.com/e/g
152  	    buildAbsoluteURL: function (baseURL, relativeURL, opts) {
153  	      opts = opts || {};
154  	      // remove any remaining space and CRLF
155  	      baseURL = baseURL.trim();
156  	      relativeURL = relativeURL.trim();
157  	      if (!relativeURL) {
158  	        // 2a) If the embedded URL is entirely empty, it inherits the
159  	        // entire base URL (i.e., is set equal to the base URL)
160  	        // and we are done.
161  	        if (!opts.alwaysNormalize) {
162  	          return baseURL;
163  	        }
164  	        var basePartsForNormalise = URLToolkit.parseURL(baseURL);
165  	        if (!basePartsForNormalise) {
166  	          throw new Error('Error trying to parse base URL.');
167  	        }
168  	        basePartsForNormalise.path = URLToolkit.normalizePath(
169  	          basePartsForNormalise.path
170  	        );
171  	        return URLToolkit.buildURLFromParts(basePartsForNormalise);
172  	      }
173  	      var relativeParts = URLToolkit.parseURL(relativeURL);
174  	      if (!relativeParts) {
175  	        throw new Error('Error trying to parse relative URL.');
176  	      }
177  	      if (relativeParts.scheme) {
178  	        // 2b) If the embedded URL starts with a scheme name, it is
179  	        // interpreted as an absolute URL and we are done.
180  	        if (!opts.alwaysNormalize) {
181  	          return relativeURL;
182  	        }
183  	        relativeParts.path = URLToolkit.normalizePath(relativeParts.path);
184  	        return URLToolkit.buildURLFromParts(relativeParts);
185  	      }
186  	      var baseParts = URLToolkit.parseURL(baseURL);
187  	      if (!baseParts) {
188  	        throw new Error('Error trying to parse base URL.');
189  	      }
190  	      if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') {
191  	        // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc
192  	        // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a'
193  	        var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path);
194  	        baseParts.netLoc = pathParts[1];
195  	        baseParts.path = pathParts[2];
196  	      }
197  	      if (baseParts.netLoc && !baseParts.path) {
198  	        baseParts.path = '/';
199  	      }
200  	      var builtParts = {
201  	        // 2c) Otherwise, the embedded URL inherits the scheme of
202  	        // the base URL.
203  	        scheme: baseParts.scheme,
204  	        netLoc: relativeParts.netLoc,
205  	        path: null,
206  	        params: relativeParts.params,
207  	        query: relativeParts.query,
208  	        fragment: relativeParts.fragment,
209  	      };
210  	      if (!relativeParts.netLoc) {
211  	        // 3) If the embedded URL's <net_loc> is non-empty, we skip to
212  	        // Step 7.  Otherwise, the embedded URL inherits the <net_loc>
213  	        // (if any) of the base URL.
214  	        builtParts.netLoc = baseParts.netLoc;
215  	        // 4) If the embedded URL path is preceded by a slash "/", the
216  	        // path is not relative and we skip to Step 7.
217  	        if (relativeParts.path[0] !== '/') {
218  	          if (!relativeParts.path) {
219  	            // 5) If the embedded URL path is empty (and not preceded by a
220  	            // slash), then the embedded URL inherits the base URL path
221  	            builtParts.path = baseParts.path;
222  	            // 5a) if the embedded URL's <params> is non-empty, we skip to
223  	            // step 7; otherwise, it inherits the <params> of the base
224  	            // URL (if any) and
225  	            if (!relativeParts.params) {
226  	              builtParts.params = baseParts.params;
227  	              // 5b) if the embedded URL's <query> is non-empty, we skip to
228  	              // step 7; otherwise, it inherits the <query> of the base
229  	              // URL (if any) and we skip to step 7.
230  	              if (!relativeParts.query) {
231  	                builtParts.query = baseParts.query;
232  	              }
233  	            }
234  	          } else {
235  	            // 6) The last segment of the base URL's path (anything
236  	            // following the rightmost slash "/", or the entire path if no
237  	            // slash is present) is removed and the embedded URL's path is
238  	            // appended in its place.
239  	            var baseURLPath = baseParts.path;
240  	            var newPath =
241  	              baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) +
242  	              relativeParts.path;
243  	            builtParts.path = URLToolkit.normalizePath(newPath);
244  	          }
245  	        }
246  	      }
247  	      if (builtParts.path === null) {
248  	        builtParts.path = opts.alwaysNormalize
249  	          ? URLToolkit.normalizePath(relativeParts.path)
250  	          : relativeParts.path;
251  	      }
252  	      return URLToolkit.buildURLFromParts(builtParts);
253  	    },
254  	    parseURL: function (url) {
255  	      var parts = URL_REGEX.exec(url);
256  	      if (!parts) {
257  	        return null;
258  	      }
259  	      return {
260  	        scheme: parts[1] || '',
261  	        netLoc: parts[2] || '',
262  	        path: parts[3] || '',
263  	        params: parts[4] || '',
264  	        query: parts[5] || '',
265  	        fragment: parts[6] || '',
266  	      };
267  	    },
268  	    normalizePath: function (path) {
269  	      // The following operations are
270  	      // then applied, in order, to the new path:
271  	      // 6a) All occurrences of "./", where "." is a complete path
272  	      // segment, are removed.
273  	      // 6b) If the path ends with "." as a complete path segment,
274  	      // that "." is removed.
275  	      path = path.split('').reverse().join('').replace(SLASH_DOT_REGEX, '');
276  	      // 6c) All occurrences of "<segment>/../", where <segment> is a
277  	      // complete path segment not equal to "..", are removed.
278  	      // Removal of these path segments is performed iteratively,
279  	      // removing the leftmost matching pattern on each iteration,
280  	      // until no matching pattern remains.
281  	      // 6d) If the path ends with "<segment>/..", where <segment> is a
282  	      // complete path segment not equal to "..", that
283  	      // "<segment>/.." is removed.
284  	      while (
285  	        path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, '')).length
286  	      ) {}
287  	      return path.split('').reverse().join('');
288  	    },
289  	    buildURLFromParts: function (parts) {
290  	      return (
291  	        parts.scheme +
292  	        parts.netLoc +
293  	        parts.path +
294  	        parts.params +
295  	        parts.query +
296  	        parts.fragment
297  	      );
298  	    },
299  	  };
300
301  	  module.exports = URLToolkit;
302  	})(); 
303  } (urlToolkit));
304
305  var urlToolkitExports = urlToolkit.exports;
306
307  // https://caniuse.com/mdn-javascript_builtins_number_isfinite
308  var isFiniteNumber = Number.isFinite || function (value) {
309    return typeof value === 'number' && isFinite(value);
310  };
311
312  // https://caniuse.com/mdn-javascript_builtins_number_issafeinteger
313  var isSafeInteger = Number.isSafeInteger || function (value) {
314    return typeof value === 'number' && Math.abs(value) <= MAX_SAFE_INTEGER;
315  };
316  var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
317
318  var Events = /*#__PURE__*/function (Events) {
319    Events["MEDIA_ATTACHING"] = "hlsMediaAttaching";
320    Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
321    Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
322    Events["MEDIA_DETACHED"] = "hlsMediaDetached";
323    Events["MEDIA_ENDED"] = "hlsMediaEnded";
324    Events["BUFFER_RESET"] = "hlsBufferReset";
325    Events["BUFFER_CODECS"] = "hlsBufferCodecs";
326    Events["BUFFER_CREATED"] = "hlsBufferCreated";
327    Events["BUFFER_APPENDING"] = "hlsBufferAppending";
328    Events["BUFFER_APPENDED"] = "hlsBufferAppended";
329    Events["BUFFER_EOS"] = "hlsBufferEos";
330    Events["BUFFER_FLUSHING"] = "hlsBufferFlushing";
331    Events["BUFFER_FLUSHED"] = "hlsBufferFlushed";
332    Events["MANIFEST_LOADING"] = "hlsManifestLoading";
333    Events["MANIFEST_LOADED"] = "hlsManifestLoaded";
334    Events["MANIFEST_PARSED"] = "hlsManifestParsed";
335    Events["LEVEL_SWITCHING"] = "hlsLevelSwitching";
336    Events["LEVEL_SWITCHED"] = "hlsLevelSwitched";
337    Events["LEVEL_LOADING"] = "hlsLevelLoading";
338    Events["LEVEL_LOADED"] = "hlsLevelLoaded";
339    Events["LEVEL_UPDATED"] = "hlsLevelUpdated";
340    Events["LEVEL_PTS_UPDATED"] = "hlsLevelPtsUpdated";
341    Events["LEVELS_UPDATED"] = "hlsLevelsUpdated";
342    Events["AUDIO_TRACKS_UPDATED"] = "hlsAudioTracksUpdated";
343    Events["AUDIO_TRACK_SWITCHING"] = "hlsAudioTrackSwitching";
344    Events["AUDIO_TRACK_SWITCHED"] = "hlsAudioTrackSwitched";
345    Events["AUDIO_TRACK_LOADING"] = "hlsAudioTrackLoading";
346    Events["AUDIO_TRACK_LOADED"] = "hlsAudioTrackLoaded";
347    Events["SUBTITLE_TRACKS_UPDATED"] = "hlsSubtitleTracksUpdated";
348    Events["SUBTITLE_TRACKS_CLEARED"] = "hlsSubtitleTracksCleared";
349    Events["SUBTITLE_TRACK_SWITCH"] = "hlsSubtitleTrackSwitch";
350    Events["SUBTITLE_TRACK_LOADING"] = "hlsSubtitleTrackLoading";
351    Events["SUBTITLE_TRACK_LOADED"] = "hlsSubtitleTrackLoaded";
352    Events["SUBTITLE_FRAG_PROCESSED"] = "hlsSubtitleFragProcessed";
353    Events["CUES_PARSED"] = "hlsCuesParsed";
354    Events["NON_NATIVE_TEXT_TRACKS_FOUND"] = "hlsNonNativeTextTracksFound";
355    Events["INIT_PTS_FOUND"] = "hlsInitPtsFound";
356    Events["FRAG_LOADING"] = "hlsFragLoading";
357    Events["FRAG_LOAD_EMERGENCY_ABORTED"] = "hlsFragLoadEmergencyAborted";
358    Events["FRAG_LOADED"] = "hlsFragLoaded";
359    Events["FRAG_DECRYPTED"] = "hlsFragDecrypted";
360    Events["FRAG_PARSING_INIT_SEGMENT"] = "hlsFragParsingInitSegment";
361    Events["FRAG_PARSING_USERDATA"] = "hlsFragParsingUserdata";
362    Events["FRAG_PARSING_METADATA"] = "hlsFragParsingMetadata";
363    Events["FRAG_PARSED"] = "hlsFragParsed";
364    Events["FRAG_BUFFERED"] = "hlsFragBuffered";
365    Events["FRAG_CHANGED"] = "hlsFragChanged";
366    Events["FPS_DROP"] = "hlsFpsDrop";
367    Events["FPS_DROP_LEVEL_CAPPING"] = "hlsFpsDropLevelCapping";
368    Events["MAX_AUTO_LEVEL_UPDATED"] = "hlsMaxAutoLevelUpdated";
369    Events["ERROR"] = "hlsError";
370    Events["DESTROYING"] = "hlsDestroying";
371    Events["KEY_LOADING"] = "hlsKeyLoading";
372    Events["KEY_LOADED"] = "hlsKeyLoaded";
373    Events["LIVE_BACK_BUFFER_REACHED"] = "hlsLiveBackBufferReached";
374    Events["BACK_BUFFER_REACHED"] = "hlsBackBufferReached";
375    Events["STEERING_MANIFEST_LOADED"] = "hlsSteeringManifestLoaded";
376    return Events;
377  }({});
378
379  /**
380   * Defines each Event type and payload by Event name. Used in {@link hls.js#HlsEventEmitter} to strongly type the event listener API.
381   */
382
383  var ErrorTypes = /*#__PURE__*/function (ErrorTypes) {
384    ErrorTypes["NETWORK_ERROR"] = "networkError";
385    ErrorTypes["MEDIA_ERROR"] = "mediaError";
386    ErrorTypes["KEY_SYSTEM_ERROR"] = "keySystemError";
387    ErrorTypes["MUX_ERROR"] = "muxError";
388    ErrorTypes["OTHER_ERROR"] = "otherError";
389    return ErrorTypes;
390  }({});
391  var ErrorDetails = /*#__PURE__*/function (ErrorDetails) {
392    ErrorDetails["KEY_SYSTEM_NO_KEYS"] = "keySystemNoKeys";
393    ErrorDetails["KEY_SYSTEM_NO_ACCESS"] = "keySystemNoAccess";
394    ErrorDetails["KEY_SYSTEM_NO_SESSION"] = "keySystemNoSession";
395    ErrorDetails["KEY_SYSTEM_NO_CONFIGURED_LICENSE"] = "keySystemNoConfiguredLicense";
396    ErrorDetails["KEY_SYSTEM_LICENSE_REQUEST_FAILED"] = "keySystemLicenseRequestFailed";
397    ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED"] = "keySystemServerCertificateRequestFailed";
398    ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_UPDATE_FAILED"] = "keySystemServerCertificateUpdateFailed";
399    ErrorDetails["KEY_SYSTEM_SESSION_UPDATE_FAILED"] = "keySystemSessionUpdateFailed";
400    ErrorDetails["KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED"] = "keySystemStatusOutputRestricted";
401    ErrorDetails["KEY_SYSTEM_STATUS_INTERNAL_ERROR"] = "keySystemStatusInternalError";
402    ErrorDetails["MANIFEST_LOAD_ERROR"] = "manifestLoadError";
403    ErrorDetails["MANIFEST_LOAD_TIMEOUT"] = "manifestLoadTimeOut";
404    ErrorDetails["MANIFEST_PARSING_ERROR"] = "manifestParsingError";
405    ErrorDetails["MANIFEST_INCOMPATIBLE_CODECS_ERROR"] = "manifestIncompatibleCodecsError";
406    ErrorDetails["LEVEL_EMPTY_ERROR"] = "levelEmptyError";
407    ErrorDetails["LEVEL_LOAD_ERROR"] = "levelLoadError";
408    ErrorDetails["LEVEL_LOAD_TIMEOUT"] = "levelLoadTimeOut";
409    ErrorDetails["LEVEL_PARSING_ERROR"] = "levelParsingError";
410    ErrorDetails["LEVEL_SWITCH_ERROR"] = "levelSwitchError";
411    ErrorDetails["AUDIO_TRACK_LOAD_ERROR"] = "audioTrackLoadError";
412    ErrorDetails["AUDIO_TRACK_LOAD_TIMEOUT"] = "audioTrackLoadTimeOut";
413    ErrorDetails["SUBTITLE_LOAD_ERROR"] = "subtitleTrackLoadError";
414    ErrorDetails["SUBTITLE_TRACK_LOAD_TIMEOUT"] = "subtitleTrackLoadTimeOut";
415    ErrorDetails["FRAG_LOAD_ERROR"] = "fragLoadError";
416    ErrorDetails["FRAG_LOAD_TIMEOUT"] = "fragLoadTimeOut";
417    ErrorDetails["FRAG_DECRYPT_ERROR"] = "fragDecryptError";
418    ErrorDetails["FRAG_PARSING_ERROR"] = "fragParsingError";
419    ErrorDetails["FRAG_GAP"] = "fragGap";
vendor: 4,332 bytes, lines 420-535
420    ErrorDetails["REMUX_ALLOC_ERROR"] = "remuxAllocError";
421    ErrorDetails["KEY_LOAD_ERROR"] = "keyLoadError";
422    ErrorDetails["KEY_LOAD_TIMEOUT"] = "keyLoadTimeOut";
423    ErrorDetails["BUFFER_ADD_CODEC_ERROR"] = "bufferAddCodecError";
424    ErrorDetails["BUFFER_INCOMPATIBLE_CODECS_ERROR"] = "bufferIncompatibleCodecsError";
425    ErrorDetails["BUFFER_APPEND_ERROR"] = "bufferAppendError";
426    ErrorDetails["BUFFER_APPENDING_ERROR"] = "bufferAppendingError";
427    ErrorDetails["BUFFER_STALLED_ERROR"] = "bufferStalledError";
428    ErrorDetails["BUFFER_FULL_ERROR"] = "bufferFullError";
429    ErrorDetails["BUFFER_SEEK_OVER_HOLE"] = "bufferSeekOverHole";
430    ErrorDetails["BUFFER_NUDGE_ON_STALL"] = "bufferNudgeOnStall";
431    ErrorDetails["INTERNAL_EXCEPTION"] = "internalException";
432    ErrorDetails["INTERNAL_ABORTED"] = "aborted";
433    ErrorDetails["ATTACH_MEDIA_ERROR"] = "attachMediaError";
434    ErrorDetails["UNKNOWN"] = "unknown";
435    return ErrorDetails;
436  }({});
437
438  var Logger = function Logger(label, logger) {
439    this.trace = void 0;
440    this.debug = void 0;
441    this.log = void 0;
442    this.warn = void 0;
443    this.info = void 0;
444    this.error = void 0;
445    var lb = "[" + label + "]:";
446    this.trace = noop;
447    this.debug = logger.debug.bind(null, lb);
448    this.log = logger.log.bind(null, lb);
449    this.warn = logger.warn.bind(null, lb);
450    this.info = logger.info.bind(null, lb);
451    this.error = logger.error.bind(null, lb);
452  };
453  var noop = function noop() {};
454  var fakeLogger = {
455    trace: noop,
456    debug: noop,
457    log: noop,
458    warn: noop,
459    info: noop,
460    error: noop
461  };
462  function createLogger() {
463    return _extends({}, fakeLogger);
464  }
465
466  // let lastCallTime;
467  // function formatMsgWithTimeInfo(type, msg) {
468  //   const now = Date.now();
469  //   const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
470  //   lastCallTime = now;
471  //   msg = (new Date(now)).toISOString() + ' | [' +  type + '] > ' + msg + ' ( ' + diff + ' ms )';
472  //   return msg;
473  // }
474
475  function consolePrintFn(type, id) {
476    var func = self.console[type];
477    return func ? func.bind(self.console, ('') + "[" + type + "] >") : noop;
478  }
479  function getLoggerFn(key, debugConfig, id) {
480    return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key);
481  }
482  var exportedLogger = createLogger();
483  function enableLogs(debugConfig, context, id) {
484    // check that console is available
485    var newLogger = createLogger();
486    if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
487      var keys = [
488      // Remove out from list here to hard-disable a log-level
489      // 'trace',
490      'debug', 'log', 'info', 'warn', 'error'];
491      keys.forEach(function (key) {
492        newLogger[key] = getLoggerFn(key, debugConfig);
493      });
494      // Some browsers don't allow to use bind on console object anyway
495      // fallback to default if needed
496      try {
497        newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + undefined);
498      } catch (e) {
499        /* log fn threw an exception. All logger methods are no-ops. */
500        return createLogger();
501      }
502      // global exported logger uses the same functions as new logger without `id`
503      keys.forEach(function (key) {
504        exportedLogger[key] = getLoggerFn(key, debugConfig);
505      });
506    } else {
507      // Reset global exported logger
508      _extends(exportedLogger, newLogger);
509    }
510    return newLogger;
511  }
512  var logger = exportedLogger;
513
514  var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/;
515  var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g;
516
517  // adapted from https://github.com/kanongil/node-m3u8parse/blob/master/attrlist.js
518  var AttrList = /*#__PURE__*/function () {
519    function AttrList(attrs, parsed) {
520      if (typeof attrs === 'string') {
521        attrs = AttrList.parseAttrList(attrs, parsed);
522      }
523      _extends(this, attrs);
524    }
525    var _proto = AttrList.prototype;
526    _proto.decimalInteger = function decimalInteger(attrName) {
527      var intValue = parseInt(this[attrName], 10);
528      if (intValue > Number.MAX_SAFE_INTEGER) {
529        return Infinity;
530      }
531      return intValue;
532    };
533    _proto.hexadecimalInteger = function hexadecimalInteger(attrName) {
534      if (this[attrName]) {
535        var stringValue = (this[attrName] || '0x').slice(2);
vendor: 3,810 bytes, lines 536-643
536        stringValue = (stringValue.length & 1 ? '0' : '') + stringValue;
537        var value = new Uint8Array(stringValue.length / 2);
538        for (var i = 0; i < stringValue.length / 2; i++) {
539          value[i] = parseInt(stringValue.slice(i * 2, i * 2 + 2), 16);
540        }
541        return value;
542      } else {
543        return null;
544      }
545    };
546    _proto.hexadecimalIntegerAsNumber = function hexadecimalIntegerAsNumber(attrName) {
547      var intValue = parseInt(this[attrName], 16);
548      if (intValue > Number.MAX_SAFE_INTEGER) {
549        return Infinity;
550      }
551      return intValue;
552    };
553    _proto.decimalFloatingPoint = function decimalFloatingPoint(attrName) {
554      return parseFloat(this[attrName]);
555    };
556    _proto.optionalFloat = function optionalFloat(attrName, defaultValue) {
557      var value = this[attrName];
558      return value ? parseFloat(value) : defaultValue;
559    };
560    _proto.enumeratedString = function enumeratedString(attrName) {
561      return this[attrName];
562    };
563    _proto.enumeratedStringList = function enumeratedStringList(attrName, dict) {
564      var attrValue = this[attrName];
565      return (attrValue ? attrValue.split(/[ ,]+/) : []).reduce(function (result, identifier) {
566        result[identifier.toLowerCase()] = true;
567        return result;
568      }, dict);
569    };
570    _proto.bool = function bool(attrName) {
571      return this[attrName] === 'YES';
572    };
573    _proto.decimalResolution = function decimalResolution(attrName) {
574      var res = DECIMAL_RESOLUTION_REGEX.exec(this[attrName]);
575      if (res === null) {
576        return undefined;
577      }
578      return {
579        width: parseInt(res[1], 10),
580        height: parseInt(res[2], 10)
581      };
582    };
583    AttrList.parseAttrList = function parseAttrList(input, parsed) {
584      var match;
585      var attrs = {};
586      var quote = '"';
587      ATTR_LIST_REGEX.lastIndex = 0;
588      while ((match = ATTR_LIST_REGEX.exec(input)) !== null) {
589        var name = match[1].trim();
590        var value = match[2];
591        var quotedString = value.indexOf(quote) === 0 && value.lastIndexOf(quote) === value.length - 1;
592        var hexadecimalSequence = false;
593        if (quotedString) {
594          value = value.slice(1, -1);
595        } else {
596          switch (name) {
597            case 'IV':
598            case 'SCTE35-CMD':
599            case 'SCTE35-IN':
600            case 'SCTE35-OUT':
601              hexadecimalSequence = true;
602          }
603        }
604        if (parsed && (quotedString || hexadecimalSequence)) ; else if (!hexadecimalSequence && !quotedString) {
605          switch (name) {
606            case 'CLOSED-CAPTIONS':
607              if (value === 'NONE') {
608                break;
609              }
610            // falls through
611            case 'ALLOWED-CPC':
612            case 'CLASS':
613            case 'ASSOC-LANGUAGE':
614            case 'AUDIO':
615            case 'BYTERANGE':
616            case 'CHANNELS':
617            case 'CHARACTERISTICS':
618            case 'CODECS':
619            case 'DATA-ID':
620            case 'END-DATE':
621            case 'GROUP-ID':
622            case 'ID':
623            case 'IMPORT':
624            case 'INSTREAM-ID':
625            case 'KEYFORMAT':
626            case 'KEYFORMATVERSIONS':
627            case 'LANGUAGE':
628            case 'NAME':
629            case 'PATHWAY-ID':
630            case 'QUERYPARAM':
631            case 'RECENTLY-REMOVED-DATERANGES':
632            case 'SERVER-URI':
633            case 'STABLE-RENDITION-ID':
634            case 'STABLE-VARIANT-ID':
635            case 'START-DATE':
636            case 'SUBTITLES':
637            case 'SUPPLEMENTAL-CODECS':
638            case 'URI':
639            case 'VALUE':
640            case 'VIDEO':
641            case 'X-ASSET-LIST':
642            case 'X-ASSET-URI':
643              // Since we are not checking tag:attribute combination, just warn rather than ignoring attribute
vendor: 10,398 bytes, lines 644-928
644              logger.warn(input + ": attribute " + name + " is missing quotes");
645            // continue;
646          }
647        }
648        attrs[name] = value;
649      }
650      return attrs;
651    };
652    return _createClass(AttrList, [{
653      key: "clientAttrs",
654      get: function get() {
655        return Object.keys(this).filter(function (attr) {
656          return attr.substring(0, 2) === 'X-';
657        });
658      }
659    }]);
660  }();
661
662  // Avoid exporting const enum so that these values can be inlined
663
664  var CLASS_INTERSTITIAL = 'com.apple.hls.interstitial';
665  function isDateRangeCueAttribute(attrName) {
666    return attrName !== "ID" && attrName !== "CLASS" && attrName !== "CUE" && attrName !== "START-DATE" && attrName !== "DURATION" && attrName !== "END-DATE" && attrName !== "END-ON-NEXT";
667  }
668  function isSCTE35Attribute(attrName) {
669    return attrName === "SCTE35-OUT" || attrName === "SCTE35-IN" || attrName === "SCTE35-CMD";
670  }
671  var DateRange = /*#__PURE__*/function () {
672    function DateRange(dateRangeAttr, dateRangeWithSameId, tagCount) {
673      var _dateRangeWithSameId$;
674      if (tagCount === void 0) {
675        tagCount = 0;
676      }
677      this.attr = void 0;
678      this.tagAnchor = void 0;
679      this.tagOrder = void 0;
680      this._startDate = void 0;
681      this._endDate = void 0;
682      this._cue = void 0;
683      this._badValueForSameId = void 0;
684      this.tagAnchor = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagAnchor) || null;
685      this.tagOrder = (_dateRangeWithSameId$ = dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagOrder) != null ? _dateRangeWithSameId$ : tagCount;
686      if (dateRangeWithSameId) {
687        var previousAttr = dateRangeWithSameId.attr;
688        for (var key in previousAttr) {
689          if (Object.prototype.hasOwnProperty.call(dateRangeAttr, key) && dateRangeAttr[key] !== previousAttr[key]) {
690            logger.warn("DATERANGE tag attribute: \"" + key + "\" does not match for tags with ID: \"" + dateRangeAttr.ID + "\"");
691            this._badValueForSameId = key;
692            break;
693          }
694        }
695        // Merge DateRange tags with the same ID
696        dateRangeAttr = _extends(new AttrList({}), previousAttr, dateRangeAttr);
697      }
698      this.attr = dateRangeAttr;
699      this._startDate = dateRangeWithSameId ? dateRangeWithSameId.startDate : new Date(dateRangeAttr["START-DATE"]);
700      if ("END-DATE" in this.attr) {
701        var endDate = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.endDate) || new Date(this.attr["END-DATE"]);
702        if (isFiniteNumber(endDate.getTime())) {
703          this._endDate = endDate;
704        }
705      }
706    }
707    return _createClass(DateRange, [{
708      key: "id",
709      get: function get() {
710        return this.attr.ID;
711      }
712    }, {
713      key: "class",
714      get: function get() {
715        return this.attr.CLASS;
716      }
717    }, {
718      key: "cue",
719      get: function get() {
720        var _cue = this._cue;
721        if (_cue === undefined) {
722          return this._cue = this.attr.enumeratedStringList(this.attr.CUE ? 'CUE' : 'X-CUE', {
723            pre: false,
724            post: false,
725            once: false
726          });
727        }
728        return _cue;
729      }
730    }, {
731      key: "startTime",
732      get: function get() {
733        var tagAnchor = this.tagAnchor;
734        // eslint-disable-next-line @typescript-eslint/prefer-optional-chain
735        if (tagAnchor === null || tagAnchor.programDateTime === null) {
736          logger.warn("Expected tagAnchor Fragment with PDT set for DateRange \"" + this.id + "\": " + tagAnchor);
737          return NaN;
738        }
739        return tagAnchor.start + (this.startDate.getTime() - tagAnchor.programDateTime) / 1000;
740      }
741    }, {
742      key: "startDate",
743      get: function get() {
744        return this._startDate;
745      }
746    }, {
747      key: "endDate",
748      get: function get() {
749        if (this._endDate) {
750          return this._endDate;
751        }
752        var duration = this.duration;
753        if (duration !== null) {
754          return new Date(this._startDate.getTime() + duration * 1000);
755        }
756        return null;
757      }
758    }, {
759      key: "duration",
760      get: function get() {
761        if ("DURATION" in this.attr) {
762          var duration = this.attr.decimalFloatingPoint("DURATION");
763          if (isFiniteNumber(duration)) {
764            return duration;
765          }
766        } else if (this._endDate) {
767          return (this._endDate.getTime() - this._startDate.getTime()) / 1000;
768        }
769        return null;
770      }
771    }, {
772      key: "plannedDuration",
773      get: function get() {
774        if ("PLANNED-DURATION" in this.attr) {
775          return this.attr.decimalFloatingPoint("PLANNED-DURATION");
776        }
777        return null;
778      }
779    }, {
780      key: "endOnNext",
781      get: function get() {
782        return this.attr.bool("END-ON-NEXT");
783      }
784    }, {
785      key: "isInterstitial",
786      get: function get() {
787        return this.class === CLASS_INTERSTITIAL;
788      }
789    }, {
790      key: "isValid",
791      get: function get() {
792        return !!this.id && !this._badValueForSameId && isFiniteNumber(this.startDate.getTime()) && (this.duration === null || this.duration >= 0) && (!this.endOnNext || !!this.class) && (!this.attr.CUE || !this.cue.pre && !this.cue.post || this.cue.pre !== this.cue.post) && (!this.isInterstitial || 'X-ASSET-URI' in this.attr || 'X-ASSET-LIST' in this.attr);
793      }
794    }]);
795  }();
796
797  var LoadStats = function LoadStats() {
798    this.aborted = false;
799    this.loaded = 0;
800    this.retry = 0;
801    this.total = 0;
802    this.chunkCount = 0;
803    this.bwEstimate = 0;
804    this.loading = {
805      start: 0,
806      first: 0,
807      end: 0
808    };
809    this.parsing = {
810      start: 0,
811      end: 0
812    };
813    this.buffering = {
814      start: 0,
815      first: 0,
816      end: 0
817    };
818  };
819
820  var ElementaryStreamTypes = {
821    AUDIO: "audio",
822    VIDEO: "video",
823    AUDIOVIDEO: "audiovideo"
824  };
825  var BaseSegment = /*#__PURE__*/function () {
826    function BaseSegment(baseurl) {
827      var _this$elementaryStrea;
828      this._byteRange = null;
829      this._url = null;
830      // baseurl is the URL to the playlist
831      this.baseurl = void 0;
832      // relurl is the portion of the URL that comes from inside the playlist.
833      this.relurl = void 0;
834      // Holds the types of data this fragment supports
835      this.elementaryStreams = (_this$elementaryStrea = {}, _this$elementaryStrea[ElementaryStreamTypes.AUDIO] = null, _this$elementaryStrea[ElementaryStreamTypes.VIDEO] = null, _this$elementaryStrea[ElementaryStreamTypes.AUDIOVIDEO] = null, _this$elementaryStrea);
836      this.baseurl = baseurl;
837    }
838
839    // setByteRange converts a EXT-X-BYTERANGE attribute into a two element array
840    var _proto = BaseSegment.prototype;
841    _proto.setByteRange = function setByteRange(value, previous) {
842      var params = value.split('@', 2);
843      var start;
844      if (params.length === 1) {
845        start = (previous == null ? void 0 : previous.byteRangeEndOffset) || 0;
846      } else {
847        start = parseInt(params[1]);
848      }
849      this._byteRange = [start, parseInt(params[0]) + start];
850    };
851    return _createClass(BaseSegment, [{
852      key: "byteRange",
853      get: function get() {
854        if (!this._byteRange) {
855          return [];
856        }
857        return this._byteRange;
858      }
859    }, {
860      key: "byteRangeStartOffset",
861      get: function get() {
862        return this.byteRange[0];
863      }
864    }, {
865      key: "byteRangeEndOffset",
866      get: function get() {
867        return this.byteRange[1];
868      }
869    }, {
870      key: "url",
871      get: function get() {
872        if (!this._url && this.baseurl && this.relurl) {
873          this._url = urlToolkitExports.buildAbsoluteURL(this.baseurl, this.relurl, {
874            alwaysNormalize: true
875          });
876        }
877        return this._url || '';
878      },
879      set: function set(value) {
880        this._url = value;
881      }
882    }]);
883  }();
884  /**
885   * Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}.
886   */
887  var Fragment = /*#__PURE__*/function (_BaseSegment2) {
888    function Fragment(type, baseurl) {
889      var _this;
890      _this = _BaseSegment2.call(this, baseurl) || this;
891      _this._decryptdata = null;
892      _this.rawProgramDateTime = null;
893      _this.programDateTime = null;
894      _this.tagList = [];
895      // EXTINF has to be present for a m3u8 to be considered valid
896      _this.duration = 0;
897      // sn notates the sequence number for a segment, and if set to a string can be 'initSegment'
898      _this.sn = 0;
899      // levelkeys are the EXT-X-KEY tags that apply to this segment for decryption
900      // core difference from the private field _decryptdata is the lack of the initialized IV
901      // _decryptdata will set the IV for this segment based on the segment number in the fragment
902      _this.levelkeys = void 0;
903      // A string representing the fragment type
904      _this.type = void 0;
905      // A reference to the loader. Set while the fragment is loading, and removed afterwards. Used to abort fragment loading
906      _this.loader = null;
907      // A reference to the key loader. Set while the key is loading, and removed afterwards. Used to abort key loading
908      _this.keyLoader = null;
909      // The level/track index to which the fragment belongs
910      _this.level = -1;
911      // The continuity counter of the fragment
912      _this.cc = 0;
913      // The starting Presentation Time Stamp (PTS) of the fragment. Set after transmux complete.
914      _this.startPTS = void 0;
915      // The ending Presentation Time Stamp (PTS) of the fragment. Set after transmux complete.
916      _this.endPTS = void 0;
917      // The starting Decode Time Stamp (DTS) of the fragment. Set after transmux complete.
918      _this.startDTS = void 0;
919      // The ending Decode Time Stamp (DTS) of the fragment. Set after transmux complete.
920      _this.endDTS = void 0;
921      // The start time of the fragment, as listed in the manifest. Updated after transmux complete.
922      _this.start = 0;
923      // Set by `updateFragPTSDTS` in level-helper
924      _this.deltaPTS = void 0;
925      // The maximum starting Presentation Time Stamp (audio/video PTS) of the fragment. Set after transmux complete.
926      _this.maxStartPTS = void 0;
927      // The minimum ending Presentation Time Stamp (audio/video PTS) of the fragment. Set after transmux complete.
928      _this.minEndPTS = void 0;
929      // Load/parse timing information
930      _this.stats = new LoadStats();
931      // Init Segment bytes (unset for media segments)
932      _this.data = void 0;
933      // A flag indicating whether the segment was downloaded in order to test bitrate, and was not buffered
934      _this.bitrateTest = false;
935      // #EXTINF  segment title
936      _this.title = null;
937      // The Media Initialization Section for this segment
938      _this.initSegment = null;
939      // Fragment is the last fragment in the media playlist
940      _this.endList = void 0;
941      // Fragment is marked by an EXT-X-GAP tag indicating that it does not contain media data and should not be loaded
942      _this.gap = void 0;
943      // Deprecated
944      _this.urlId = 0;
945      _this.type = type;
946      return _this;
947    }
948    _inheritsLoose(Fragment, _BaseSegment2);
949    var _proto2 = Fragment.prototype;
950    _proto2.setKeyFormat = function setKeyFormat(keyFormat) {
951      if (this.levelkeys) {
952        var key = this.levelkeys[keyFormat];
953        if (key && !this._decryptdata) {
954          this._decryptdata = key.getDecryptData(this.sn);
955        }
956      }
957    };
958    _proto2.abortRequests = function abortRequests() {
959      var _this$loader, _this$keyLoader;
960      (_this$loader = this.loader) == null ? void 0 : _this$loader.abort();
961      (_this$keyLoader = this.keyLoader) == null ? void 0 : _this$keyLoader.abort();
962    };
963    _proto2.setElementaryStreamInfo = function setElementaryStreamInfo(type, startPTS, endPTS, startDTS, endDTS, partial) {
964      if (partial === void 0) {
965        partial = false;
966      }
967      var elementaryStreams = this.elementaryStreams;
968      var info = elementaryStreams[type];
969      if (!info) {
970        elementaryStreams[type] = {
971          startPTS: startPTS,
972          endPTS: endPTS,
973          startDTS: startDTS,
974          endDTS: endDTS,
975          partial: partial
976        };
977        return;
978      }
979      info.startPTS = Math.min(info.startPTS, startPTS);
980      info.endPTS = Math.max(info.endPTS, endPTS);
981      info.startDTS = Math.min(info.startDTS, startDTS);
982      info.endDTS = Math.max(info.endDTS, endDTS);
983    };
984    _proto2.clearElementaryStreamInfo = function clearElementaryStreamInfo() {
985      var elementaryStreams = this.elementaryStreams;
986      elementaryStreams[ElementaryStreamTypes.AUDIO] = null;
987      elementaryStreams[ElementaryStreamTypes.VIDEO] = null;
988      elementaryStreams[ElementaryStreamTypes.AUDIOVIDEO] = null;
989    };
990    return _createClass(Fragment, [{
991      key: "decryptdata",
992      get: function get() {
993        var levelkeys = this.levelkeys;
994        if (!levelkeys && !this._decryptdata) {
995          return null;
996        }
997        if (!this._decryptdata && this.levelkeys && !this.levelkeys.NONE) {
998          var key = this.levelkeys.identity;
999          if (key) {
1000            this._decryptdata = key.getDecryptData(this.sn);
1001          } else {
1002            var keyFormats = Object.keys(this.levelkeys);
1003            if (keyFormats.length === 1) {
1004              return this._decryptdata = this.levelkeys[keyFormats[0]].getDecryptData(this.sn);
1005            }
1006          }
1007        }
1008        return this._decryptdata;
1009      }
1010    }, {
1011      key: "end",
1012      get: function get() {
1013        return this.start + this.duration;
1014      }
1015    }, {
1016      key: "endProgramDateTime",
1017      get: function get() {
1018        if (this.programDateTime === null) {
1019          return null;
1020        }
1021        if (!isFiniteNumber(this.programDateTime)) {
1022          return null;
1023        }
1024        var duration = !isFiniteNumber(this.duration) ? 0 : this.duration;
1025        return this.programDateTime + duration * 1000;
1026      }
1027    }, {
1028      key: "encrypted",
1029      get: function get() {
1030        var _this$_decryptdata;
1031        // At the m3u8-parser level we need to add support for manifest signalled keyformats
1032        // when we want the fragment to start reporting that it is encrypted.
1033        // Currently, keyFormat will only be set for identity keys
1034        if ((_this$_decryptdata = this._decryptdata) != null && _this$_decryptdata.encrypted) {
1035          return true;
1036        } else if (this.levelkeys) {
1037          var keyFormats = Object.keys(this.levelkeys);
1038          var len = keyFormats.length;
1039          if (len > 1 || len === 1 && this.levelkeys[keyFormats[0]].encrypted) {
1040            return true;
1041          }
1042        }
1043        return false;
vendor: 4,554 bytes, lines 1044-1181
1044      }
1045    }]);
1046  }(BaseSegment);
1047
1048  /**
1049   * Object representing parsed data from an HLS Partial Segment. Found in {@link hls.js#LevelDetails.partList}.
1050   */
1051  var Part = /*#__PURE__*/function (_BaseSegment3) {
1052    function Part(partAttrs, frag, baseurl, index, previous) {
1053      var _this2;
1054      _this2 = _BaseSegment3.call(this, baseurl) || this;
1055      _this2.fragOffset = 0;
1056      _this2.duration = 0;
1057      _this2.gap = false;
1058      _this2.independent = false;
1059      _this2.relurl = void 0;
1060      _this2.fragment = void 0;
1061      _this2.index = void 0;
1062      _this2.stats = new LoadStats();
1063      _this2.duration = partAttrs.decimalFloatingPoint('DURATION');
1064      _this2.gap = partAttrs.bool('GAP');
1065      _this2.independent = partAttrs.bool('INDEPENDENT');
1066      _this2.relurl = partAttrs.enumeratedString('URI');
1067      _this2.fragment = frag;
1068      _this2.index = index;
1069      var byteRange = partAttrs.enumeratedString('BYTERANGE');
1070      if (byteRange) {
1071        _this2.setByteRange(byteRange, previous);
1072      }
1073      if (previous) {
1074        _this2.fragOffset = previous.fragOffset + previous.duration;
1075      }
1076      return _this2;
1077    }
1078    _inheritsLoose(Part, _BaseSegment3);
1079    return _createClass(Part, [{
1080      key: "start",
1081      get: function get() {
1082        return this.fragment.start + this.fragOffset;
1083      }
1084    }, {
1085      key: "end",
1086      get: function get() {
1087        return this.start + this.duration;
1088      }
1089    }, {
1090      key: "loaded",
1091      get: function get() {
1092        var elementaryStreams = this.elementaryStreams;
1093        return !!(elementaryStreams.audio || elementaryStreams.video || elementaryStreams.audiovideo);
1094      }
1095    }]);
1096  }(BaseSegment);
1097
1098  var DEFAULT_TARGET_DURATION = 10;
1099
1100  /**
1101   * Object representing parsed data from an HLS Media Playlist. Found in {@link hls.js#Level.details}.
1102   */
1103  var LevelDetails = /*#__PURE__*/function () {
1104    function LevelDetails(baseUrl) {
1105      this.PTSKnown = false;
1106      this.alignedSliding = false;
1107      this.averagetargetduration = void 0;
1108      this.endCC = 0;
1109      this.endSN = 0;
1110      this.fragments = void 0;
1111      this.fragmentHint = void 0;
1112      this.partList = null;
1113      this.dateRanges = void 0;
1114      this.dateRangeTagCount = 0;
1115      this.live = true;
1116      this.ageHeader = 0;
1117      this.advancedDateTime = void 0;
1118      this.updated = true;
1119      this.advanced = true;
1120      this.availabilityDelay = void 0;
1121      // Manifest reload synchronization
1122      this.misses = 0;
1123      this.startCC = 0;
1124      this.startSN = 0;
1125      this.startTimeOffset = null;
1126      this.targetduration = 0;
1127      this.totalduration = 0;
1128      this.type = null;
1129      this.url = void 0;
1130      this.m3u8 = '';
1131      this.version = null;
1132      this.canBlockReload = false;
1133      this.canSkipUntil = 0;
1134      this.canSkipDateRanges = false;
1135      this.skippedSegments = 0;
1136      this.recentlyRemovedDateranges = void 0;
1137      this.partHoldBack = 0;
1138      this.holdBack = 0;
1139      this.partTarget = 0;
1140      this.preloadHint = void 0;
1141      this.renditionReports = void 0;
1142      this.tuneInGoal = 0;
1143      this.deltaUpdateFailed = void 0;
1144      this.driftStartTime = 0;
1145      this.driftEndTime = 0;
1146      this.driftStart = 0;
1147      this.driftEnd = 0;
1148      this.encryptedFragments = void 0;
1149      this.playlistParsingError = null;
1150      this.variableList = null;
1151      this.hasVariableRefs = false;
1152      this.fragments = [];
1153      this.encryptedFragments = [];
1154      this.dateRanges = {};
1155      this.url = baseUrl;
1156    }
1157    var _proto = LevelDetails.prototype;
1158    _proto.reloaded = function reloaded(previous) {
1159      if (!previous) {
1160        this.advanced = true;
1161        this.updated = true;
1162        return;
1163      }
1164      var partSnDiff = this.lastPartSn - previous.lastPartSn;
1165      var partIndexDiff = this.lastPartIndex - previous.lastPartIndex;
1166      this.updated = this.endSN !== previous.endSN || !!partIndexDiff || !!partSnDiff || !this.live;
1167      this.advanced = this.endSN > previous.endSN || partSnDiff > 0 || partSnDiff === 0 && partIndexDiff > 0;
1168      if (this.updated || this.advanced) {
1169        this.misses = Math.floor(previous.misses * 0.6);
1170      } else {
1171        this.misses = previous.misses + 1;
1172      }
1173      this.availabilityDelay = previous.availabilityDelay;
1174    };
1175    return _createClass(LevelDetails, [{
1176      key: "hasProgramDateTime",
1177      get: function get() {
1178        if (this.fragments.length) {
1179          return isFiniteNumber(this.fragments[this.fragments.length - 1].programDateTime);
1180        }
1181        return false;
vendor: 4,887 bytes, lines 1182-1348
1182      }
1183    }, {
1184      key: "levelTargetDuration",
1185      get: function get() {
1186        return this.averagetargetduration || this.targetduration || DEFAULT_TARGET_DURATION;
1187      }
1188    }, {
1189      key: "drift",
1190      get: function get() {
1191        var runTime = this.driftEndTime - this.driftStartTime;
1192        if (runTime > 0) {
1193          var runDuration = this.driftEnd - this.driftStart;
1194          return runDuration * 1000 / runTime;
1195        }
1196        return 1;
1197      }
1198    }, {
1199      key: "edge",
1200      get: function get() {
1201        return this.partEnd || this.fragmentEnd;
1202      }
1203    }, {
1204      key: "partEnd",
1205      get: function get() {
1206        var _this$partList;
1207        if ((_this$partList = this.partList) != null && _this$partList.length) {
1208          return this.partList[this.partList.length - 1].end;
1209        }
1210        return this.fragmentEnd;
1211      }
1212    }, {
1213      key: "fragmentEnd",
1214      get: function get() {
1215        var _this$fragments;
1216        if ((_this$fragments = this.fragments) != null && _this$fragments.length) {
1217          return this.fragments[this.fragments.length - 1].end;
1218        }
1219        return 0;
1220      }
1221    }, {
1222      key: "age",
1223      get: function get() {
1224        if (this.advancedDateTime) {
1225          return Math.max(Date.now() - this.advancedDateTime, 0) / 1000;
1226        }
1227        return 0;
1228      }
1229    }, {
1230      key: "lastPartIndex",
1231      get: function get() {
1232        var _this$partList2;
1233        if ((_this$partList2 = this.partList) != null && _this$partList2.length) {
1234          return this.partList[this.partList.length - 1].index;
1235        }
1236        return -1;
1237      }
1238    }, {
1239      key: "lastPartSn",
1240      get: function get() {
1241        var _this$partList3;
1242        if ((_this$partList3 = this.partList) != null && _this$partList3.length) {
1243          return this.partList[this.partList.length - 1].fragment.sn;
1244        }
1245        return this.endSN;
1246      }
1247    }]);
1248  }();
1249
1250  var DecrypterAesMode = {
1251    cbc: 0,
1252    ctr: 1
1253  };
1254
1255  function isFullSegmentEncryption(method) {
1256    return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
1257  }
1258  function getAesModeFromFullSegmentMethod(method) {
1259    switch (method) {
1260      case 'AES-128':
1261      case 'AES-256':
1262        return DecrypterAesMode.cbc;
1263      case 'AES-256-CTR':
1264        return DecrypterAesMode.ctr;
1265      default:
1266        throw new Error("invalid full segment method " + method);
1267    }
1268  }
1269
1270  // This file is inserted as a shim for modules which we do not want to include into the distro.
1271  // This replacement is done in the "alias" plugin of the rollup config.
1272  var empty = undefined;
1273  var HevcVideoParser = /*@__PURE__*/getDefaultExportFromCjs(empty);
1274
1275  function sliceUint8(array, start, end) {
1276    // @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
1277    // It always exists in the TypeScript definition so fails, but it fails at runtime on IE11.
1278    return Uint8Array.prototype.slice ? array.slice(start, end) : new Uint8Array(Array.prototype.slice.call(array, start, end));
1279  }
1280
1281  // http://stackoverflow.com/questions/8936984/uint8array-to-string-in-javascript/22373197
1282  // http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt
1283  /* utf.js - UTF-8 <=> UTF-16 convertion
1284   *
1285   * Copyright (C) 1999 Masanao Izumo <[email protected]>
1286   * Version: 1.0
1287   * LastModified: Dec 25 1999
1288   * This library is free.  You can redistribute it and/or modify it.
1289   */
1290  /**
1291   * Converts a UTF-8 array to a string.
1292   *
1293   * @param array - The UTF-8 array to convert
1294   *
1295   * @returns The string
1296   *
1297   * @group Utils
1298   *
1299   * @beta
1300   */
1301  function utf8ArrayToStr(array, exitOnNull) {
1302    if (exitOnNull === void 0) {
1303      exitOnNull = false;
1304    }
1305    if (typeof TextDecoder !== 'undefined') {
1306      var decoder = new TextDecoder('utf-8');
1307      var decoded = decoder.decode(array);
1308      if (exitOnNull) {
1309        // grab up to the first null
1310        var idx = decoded.indexOf('\0');
1311        return idx !== -1 ? decoded.substring(0, idx) : decoded;
1312      }
1313      // remove any null characters
1314      return decoded.replace(/\0/g, '');
1315    }
1316    var len = array.length;
1317    var c;
1318    var char2;
1319    var char3;
1320    var out = '';
1321    var i = 0;
1322    while (i < len) {
1323      c = array[i++];
1324      if (c === 0x00 && exitOnNull) {
1325        return out;
1326      } else if (c === 0x00 || c === 0x03) {
1327        // If the character is 3 (END_OF_TEXT) or 0 (NULL) then skip it
1328        continue;
1329      }
1330      switch (c >> 4) {
1331        case 0:
1332        case 1:
1333        case 2:
1334        case 3:
1335        case 4:
1336        case 5:
1337        case 6:
1338        case 7:
1339          // 0xxxxxxx
1340          out += String.fromCharCode(c);
1341          break;
1342        case 12:
1343        case 13:
1344          // 110x xxxx   10xx xxxx
1345          char2 = array[i++];
1346          out += String.fromCharCode((c & 0x1f) << 6 | char2 & 0x3f);
1347          break;
1348        case 14:
vendor: 5,614 bytes, lines 1349-1532
1349          // 1110 xxxx  10xx xxxx  10xx xxxx
1350          char2 = array[i++];
1351          char3 = array[i++];
1352          out += String.fromCharCode((c & 0x0f) << 12 | (char2 & 0x3f) << 6 | (char3 & 0x3f) << 0);
1353          break;
1354      }
1355    }
1356    return out;
1357  }
1358
1359  /**
1360   *  hex dump helper class
1361   */
1362
1363  var Hex = {
1364    hexDump: function hexDump(array) {
1365      var str = '';
1366      for (var i = 0; i < array.length; i++) {
1367        var h = array[i].toString(16);
1368        if (h.length < 2) {
1369          h = '0' + h;
1370        }
1371        str += h;
1372      }
1373      return str;
1374    }
1375  };
1376
1377  var UINT32_MAX$1 = Math.pow(2, 32) - 1;
1378  var push = [].push;
1379
1380  // We are using fixed track IDs for driving the MP4 remuxer
1381  // instead of following the TS PIDs.
1382  // There is no reason not to do this and some browsers/SourceBuffer-demuxers
1383  // may not like if there are TrackID "switches"
1384  // See https://github.com/video-dev/hls.js/issues/1331
1385  // Here we are mapping our internal track types to constant MP4 track IDs
1386  // With MSE currently one can only have one track of each, and we are muxing
1387  // whatever video/audio rendition in them.
1388  var RemuxerTrackIdConfig = {
1389    video: 1,
1390    audio: 2,
1391    id3: 3,
1392    text: 4
1393  };
1394  function bin2str(data) {
1395    return String.fromCharCode.apply(null, data);
1396  }
1397  function readUint16(buffer, offset) {
1398    var val = buffer[offset] << 8 | buffer[offset + 1];
1399    return val < 0 ? 65536 + val : val;
1400  }
1401  function readUint32(buffer, offset) {
1402    var val = readSint32(buffer, offset);
1403    return val < 0 ? 4294967296 + val : val;
1404  }
1405  function readUint64(buffer, offset) {
1406    var result = readUint32(buffer, offset);
1407    result *= Math.pow(2, 32);
1408    result += readUint32(buffer, offset + 4);
1409    return result;
1410  }
1411  function readSint32(buffer, offset) {
1412    return buffer[offset] << 24 | buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3];
1413  }
1414  function writeUint32(buffer, offset, value) {
1415    buffer[offset] = value >> 24;
1416    buffer[offset + 1] = value >> 16 & 0xff;
1417    buffer[offset + 2] = value >> 8 & 0xff;
1418    buffer[offset + 3] = value & 0xff;
1419  }
1420
1421  // Find "moof" box
1422  function hasMoofData(data) {
1423    var end = data.byteLength;
1424    for (var i = 0; i < end;) {
1425      var size = readUint32(data, i);
1426      if (size > 8 && data[i + 4] === 0x6d && data[i + 5] === 0x6f && data[i + 6] === 0x6f && data[i + 7] === 0x66) {
1427        return true;
1428      }
1429      i = size > 1 ? i + size : end;
1430    }
1431    return false;
1432  }
1433
1434  // Find the data for a box specified by its path
1435  function findBox(data, path) {
1436    var results = [];
1437    if (!path.length) {
1438      // short-circuit the search for empty paths
1439      return results;
1440    }
1441    var end = data.byteLength;
1442    for (var i = 0; i < end;) {
1443      var size = readUint32(data, i);
1444      var type = bin2str(data.subarray(i + 4, i + 8));
1445      var endbox = size > 1 ? i + size : end;
1446      if (type === path[0]) {
1447        if (path.length === 1) {
1448          // this is the end of the path and we've found the box we were
1449          // looking for
1450          results.push(data.subarray(i + 8, endbox));
1451        } else {
1452          // recursively search for the next box along the path
1453          var subresults = findBox(data.subarray(i + 8, endbox), path.slice(1));
1454          if (subresults.length) {
1455            push.apply(results, subresults);
1456          }
1457        }
1458      }
1459      i = endbox;
1460    }
1461
1462    // we've finished searching all of data
1463    return results;
1464  }
1465  function parseSegmentIndex(sidx) {
1466    var references = [];
1467    var version = sidx[0];
1468
1469    // set initial offset, we skip the reference ID (not needed)
1470    var index = 8;
1471    var timescale = readUint32(sidx, index);
1472    index += 4;
1473    var earliestPresentationTime = 0;
1474    var firstOffset = 0;
1475    if (version === 0) {
1476      earliestPresentationTime = readUint32(sidx, index);
1477      firstOffset = readUint32(sidx, index + 4);
1478      index += 8;
1479    } else {
1480      earliestPresentationTime = readUint64(sidx, index);
1481      firstOffset = readUint64(sidx, index + 8);
1482      index += 16;
1483    }
1484
1485    // skip reserved
1486    index += 2;
1487    var startByte = sidx.length + firstOffset;
1488    var referencesCount = readUint16(sidx, index);
1489    index += 2;
1490    for (var i = 0; i < referencesCount; i++) {
1491      var referenceIndex = index;
1492      var referenceInfo = readUint32(sidx, referenceIndex);
1493      referenceIndex += 4;
1494      var referenceSize = referenceInfo & 0x7fffffff;
1495      var referenceType = (referenceInfo & 0x80000000) >>> 31;
1496      if (referenceType === 1) {
1497        logger.warn('SIDX has hierarchical references (not supported)');
1498        return null;
1499      }
1500      var subsegmentDuration = readUint32(sidx, referenceIndex);
1501      referenceIndex += 4;
1502      references.push({
1503        referenceSize: referenceSize,
1504        subsegmentDuration: subsegmentDuration,
1505        // unscaled
1506        info: {
1507          duration: subsegmentDuration / timescale,
1508          start: startByte,
1509          end: startByte + referenceSize - 1
1510        }
1511      });
1512      startByte += referenceSize;
1513
1514      // Skipping 1 bit for |startsWithSap|, 3 bits for |sapType|, and 28 bits
1515      // for |sapDelta|.
1516      referenceIndex += 4;
1517
1518      // skip to next ref
1519      index = referenceIndex;
1520    }
1521    return {
1522      earliestPresentationTime: earliestPresentationTime,
1523      timescale: timescale,
1524      version: version,
1525      referencesCount: referencesCount,
1526      references: references
1527    };
1528  }
1529
1530  /**
1531   * Parses an MP4 initialization segment and extracts stream type and
1532   * timescale values for any declared tracks. Timescale values indicate the
1533   * number of clock ticks per second to assume for time-based values
1534   * elsewhere in the MP4.
1535   *
1536   * To determine the start time of an MP4, you need two pieces of
1537   * information: the timescale unit and the earliest base media decode
1538   * time. Multiple timescales can be specified within an MP4 but the
1539   * base media decode time is always expressed in the timescale from
1540   * the media header box for the track:
1541   * ```
1542   * moov > trak > mdia > mdhd.timescale
1543   * moov > trak > mdia > hdlr
1544   * ```
1545   * @param initSegment the bytes of the init segment
1546   * @returns a hash of track type to timescale values or null if
1547   * the init segment is malformed.
1548   */
1549
1550  function parseInitSegment(initSegment) {
1551    var result = [];
1552    var traks = findBox(initSegment, ['moov', 'trak']);
1553    for (var i = 0; i < traks.length; i++) {
1554      var trak = traks[i];
1555      var tkhd = findBox(trak, ['tkhd'])[0];
1556      if (tkhd) {
1557        var version = tkhd[0];
1558        var trackId = readUint32(tkhd, version === 0 ? 12 : 20);
1559        var mdhd = findBox(trak, ['mdia', 'mdhd'])[0];
1560        if (mdhd) {
1561          version = mdhd[0];
1562          var timescale = readUint32(mdhd, version === 0 ? 12 : 20);
1563          var hdlr = findBox(trak, ['mdia', 'hdlr'])[0];
1564          if (hdlr) {
1565            var hdlrType = bin2str(hdlr.subarray(8, 12));
1566            var type = {
1567              soun: ElementaryStreamTypes.AUDIO,
1568              vide: ElementaryStreamTypes.VIDEO
1569            }[hdlrType];
1570            if (type) {
1571              // Parse codec details
1572              var stsd = findBox(trak, ['mdia', 'minf', 'stbl', 'stsd'])[0];
1573              var stsdData = parseStsd(stsd);
1574              result[trackId] = {
1575                timescale: timescale,
1576                type: type
1577              };
1578              result[type] = _objectSpread2({
1579                timescale: timescale,
1580                id: trackId
1581              }, stsdData);
1582            }
1583          }
1584        }
1585      }
1586    }
1587    var trex = findBox(initSegment, ['moov', 'mvex', 'trex']);
1588    trex.forEach(function (trex) {
1589      var trackId = readUint32(trex, 4);
1590      var track = result[trackId];
1591      if (track) {
1592        track.default = {
1593          duration: readUint32(trex, 12),
1594          flags: readUint32(trex, 20)
1595        };
1596      }
1597    });
1598    return result;
1599  }
1600  function parseStsd(stsd) {
1601    var sampleEntries = stsd.subarray(8);
1602    var sampleEntriesEnd = sampleEntries.subarray(8 + 78);
1603    var fourCC = bin2str(sampleEntries.subarray(4, 8));
1604    var codec = fourCC;
1605    var encrypted = fourCC === 'enca' || fourCC === 'encv';
1606    if (encrypted) {
1607      var encBox = findBox(sampleEntries, [fourCC])[0];
1608      var encBoxChildren = encBox.subarray(fourCC === 'enca' ? 28 : 78);
1609      var sinfs = findBox(encBoxChildren, ['sinf']);
vendor: 6,551 bytes, lines 1610-1781
1610      sinfs.forEach(function (sinf) {
1611        var schm = findBox(sinf, ['schm'])[0];
1612        if (schm) {
1613          var scheme = bin2str(schm.subarray(4, 8));
1614          if (scheme === 'cbcs' || scheme === 'cenc') {
1615            var frma = findBox(sinf, ['frma'])[0];
1616            if (frma) {
1617              // for encrypted content codec fourCC will be in frma
1618              codec = bin2str(frma);
1619            }
1620          }
1621        }
1622      });
1623    }
1624    switch (codec) {
1625      case 'avc1':
1626      case 'avc2':
1627      case 'avc3':
1628      case 'avc4':
1629        {
1630          // extract profile + compatibility + level out of avcC box
1631          var avcCBox = findBox(sampleEntriesEnd, ['avcC'])[0];
1632          codec += '.' + toHex(avcCBox[1]) + toHex(avcCBox[2]) + toHex(avcCBox[3]);
1633          break;
1634        }
1635      case 'mp4a':
1636        {
1637          var codecBox = findBox(sampleEntries, [fourCC])[0];
1638          var esdsBox = findBox(codecBox.subarray(28), ['esds'])[0];
1639          if (esdsBox && esdsBox.length > 7) {
1640            var i = 4;
1641            // ES Descriptor tag
1642            if (esdsBox[i++] !== 0x03) {
1643              break;
1644            }
1645            i = skipBERInteger(esdsBox, i);
1646            i += 2; // skip es_id;
1647            var flags = esdsBox[i++];
1648            if (flags & 0x80) {
1649              i += 2; // skip dependency es_id
1650            }
1651            if (flags & 0x40) {
1652              i += esdsBox[i++]; // skip URL
1653            }
1654            // Decoder config descriptor
1655            if (esdsBox[i++] !== 0x04) {
1656              break;
1657            }
1658            i = skipBERInteger(esdsBox, i);
1659            var objectType = esdsBox[i++];
1660            if (objectType === 0x40) {
1661              codec += '.' + toHex(objectType);
1662            } else {
1663              break;
1664            }
1665            i += 12;
1666            // Decoder specific info
1667            if (esdsBox[i++] !== 0x05) {
1668              break;
1669            }
1670            i = skipBERInteger(esdsBox, i);
1671            var firstByte = esdsBox[i++];
1672            var audioObjectType = (firstByte & 0xf8) >> 3;
1673            if (audioObjectType === 31) {
1674              audioObjectType += 1 + ((firstByte & 0x7) << 3) + ((esdsBox[i] & 0xe0) >> 5);
1675            }
1676            codec += '.' + audioObjectType;
1677          }
1678          break;
1679        }
1680      case 'hvc1':
1681      case 'hev1':
1682        {
1683          var hvcCBox = findBox(sampleEntriesEnd, ['hvcC'])[0];
1684          var profileByte = hvcCBox[1];
1685          var profileSpace = ['', 'A', 'B', 'C'][profileByte >> 6];
1686          var generalProfileIdc = profileByte & 0x1f;
1687          var profileCompat = readUint32(hvcCBox, 2);
1688          var tierFlag = (profileByte & 0x20) >> 5 ? 'H' : 'L';
1689          var levelIDC = hvcCBox[12];
1690          var constraintIndicator = hvcCBox.subarray(6, 12);
1691          codec += '.' + profileSpace + generalProfileIdc;
1692          codec += '.' + profileCompat.toString(16).toUpperCase();
1693          codec += '.' + tierFlag + levelIDC;
1694          var constraintString = '';
1695          for (var _i = constraintIndicator.length; _i--;) {
1696            var _byte = constraintIndicator[_i];
1697            if (_byte || constraintString) {
1698              var encodedByte = _byte.toString(16).toUpperCase();
1699              constraintString = '.' + encodedByte + constraintString;
1700            }
1701          }
1702          codec += constraintString;
1703          break;
1704        }
1705      case 'dvh1':
1706      case 'dvhe':
1707        {
1708          var dvcCBox = findBox(sampleEntriesEnd, ['dvcC'])[0];
1709          var profile = dvcCBox[2] >> 1 & 0x7f;
1710          var level = dvcCBox[2] << 5 & 0x20 | dvcCBox[3] >> 3 & 0x1f;
1711          codec += '.' + addLeadingZero(profile) + '.' + addLeadingZero(level);
1712          break;
1713        }
1714      case 'vp09':
1715        {
1716          var vpcCBox = findBox(sampleEntriesEnd, ['vpcC'])[0];
1717          var _profile = vpcCBox[4];
1718          var _level = vpcCBox[5];
1719          var bitDepth = vpcCBox[6] >> 4 & 0x0f;
1720          codec += '.' + addLeadingZero(_profile) + '.' + addLeadingZero(_level) + '.' + addLeadingZero(bitDepth);
1721          break;
1722        }
1723      case 'av01':
1724        {
1725          var av1CBox = findBox(sampleEntriesEnd, ['av1C'])[0];
1726          var _profile2 = av1CBox[1] >>> 5;
1727          var _level2 = av1CBox[1] & 0x1f;
1728          var _tierFlag = av1CBox[2] >>> 7 ? 'H' : 'M';
1729          var highBitDepth = (av1CBox[2] & 0x40) >> 6;
1730          var twelveBit = (av1CBox[2] & 0x20) >> 5;
1731          var _bitDepth = _profile2 === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8;
1732          var monochrome = (av1CBox[2] & 0x10) >> 4;
1733          var chromaSubsamplingX = (av1CBox[2] & 0x08) >> 3;
1734          var chromaSubsamplingY = (av1CBox[2] & 0x04) >> 2;
1735          var chromaSamplePosition = av1CBox[2] & 0x03;
1736          // TODO: parse color_description_present_flag
1737          // default it to BT.709/limited range for now
1738          // more info https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax
1739          var colorPrimaries = 1;
1740          var transferCharacteristics = 1;
1741          var matrixCoefficients = 1;
1742          var videoFullRangeFlag = 0;
1743          codec += '.' + _profile2 + '.' + addLeadingZero(_level2) + _tierFlag + '.' + addLeadingZero(_bitDepth) + '.' + monochrome + '.' + chromaSubsamplingX + chromaSubsamplingY + chromaSamplePosition + '.' + addLeadingZero(colorPrimaries) + '.' + addLeadingZero(transferCharacteristics) + '.' + addLeadingZero(matrixCoefficients) + '.' + videoFullRangeFlag;
1744          break;
1745        }
1746    }
1747    return {
1748      codec: codec,
1749      encrypted: encrypted
1750    };
1751  }
1752  function skipBERInteger(bytes, i) {
1753    var limit = i + 5;
1754    while (bytes[i++] & 0x80 && i < limit) {
1755      /* do nothing */
1756    }
1757    return i;
1758  }
1759  function toHex(x) {
1760    return ('0' + x.toString(16).toUpperCase()).slice(-2);
1761  }
1762  function addLeadingZero(num) {
1763    return (num < 10 ? '0' : '') + num;
1764  }
1765  function patchEncyptionData(initSegment, decryptdata) {
1766    if (!initSegment || !decryptdata) {
1767      return initSegment;
1768    }
1769    var keyId = decryptdata.keyId;
1770    if (keyId && decryptdata.isCommonEncryption) {
1771      var traks = findBox(initSegment, ['moov', 'trak']);
1772      traks.forEach(function (trak) {
1773        var stsd = findBox(trak, ['mdia', 'minf', 'stbl', 'stsd'])[0];
1774
1775        // skip the sample entry count
1776        var sampleEntries = stsd.subarray(8);
1777        var encBoxes = findBox(sampleEntries, ['enca']);
1778        var isAudio = encBoxes.length > 0;
1779        if (!isAudio) {
1780          encBoxes = findBox(sampleEntries, ['encv']);
1781        }
1782        encBoxes.forEach(function (enc) {
1783          var encBoxChildren = isAudio ? enc.subarray(28) : enc.subarray(78);
1784          var sinfBoxes = findBox(encBoxChildren, ['sinf']);
1785          sinfBoxes.forEach(function (sinf) {
1786            var tenc = parseSinf(sinf);
1787            if (tenc) {
1788              // Look for default key id (keyID offset is always 8 within the tenc box):
1789              var tencKeyId = tenc.subarray(8, 24);
1790              if (!tencKeyId.some(function (b) {
1791                return b !== 0;
1792              })) {
1793                logger.log("[eme] Patching keyId in 'enc" + (isAudio ? 'a' : 'v') + ">sinf>>tenc' box: " + Hex.hexDump(tencKeyId) + " -> " + Hex.hexDump(keyId));
1794                tenc.set(keyId, 8);
1795              }
1796            }
1797          });
1798        });
1799      });
1800    }
1801    return initSegment;
1802  }
1803  function parseSinf(sinf) {
1804    var schm = findBox(sinf, ['schm'])[0];
1805    if (schm) {
1806      var scheme = bin2str(schm.subarray(4, 8));
1807      if (scheme === 'cbcs' || scheme === 'cenc') {
1808        return findBox(sinf, ['schi', 'tenc'])[0];
1809      }
1810    }
1811    return null;
1812  }
1813
1814  /**
1815   * Determine the base media decode start time, in seconds, for an MP4
1816   * fragment. If multiple fragments are specified, the earliest time is
1817   * returned.
1818   *
1819   * The base media decode time can be parsed from track fragment
1820   * metadata:
1821   * ```
1822   * moof > traf > tfdt.baseMediaDecodeTime
1823   * ```
1824   * It requires the timescale value from the mdhd to interpret.
1825   *
1826   * @param initData - a hash of track type to timescale values
1827   * @param fmp4 - the bytes of the mp4 fragment
1828   * @returns the earliest base media decode start time for the
1829   * fragment, in seconds
1830   */
1831  function getStartDTS(initData, fmp4) {
1832    // we need info from two children of each track fragment box
1833    return findBox(fmp4, ['moof', 'traf']).reduce(function (result, traf) {
1834      var tfdt = findBox(traf, ['tfdt'])[0];
1835      var version = tfdt[0];
1836      var start = findBox(traf, ['tfhd']).reduce(function (result, tfhd) {
1837        // get the track id from the tfhd
1838        var id = readUint32(tfhd, 4);
1839        var track = initData[id];
1840        if (track) {
1841          var baseTime = readUint32(tfdt, 4);
1842          if (version === 1) {
1843            // If value is too large, assume signed 64-bit. Negative track fragment decode times are invalid, but they exist in the wild.
1844            // This prevents large values from being used for initPTS, which can cause playlist sync issues.
1845            // https://github.com/video-dev/hls.js/issues/5303
1846            if (baseTime === UINT32_MAX$1) {
1847              logger.warn("[mp4-demuxer]: Ignoring assumed invalid signed 64-bit track fragment decode time");
1848              return result;
1849            }
1850            baseTime *= UINT32_MAX$1 + 1;
1851            baseTime += readUint32(tfdt, 8);
1852          }
1853          // assume a 90kHz clock if no timescale was specified
1854          var scale = track.timescale || 90e3;
1855          // convert base time to seconds
1856          var startTime = baseTime / scale;
1857          if (isFiniteNumber(startTime) && (result === null || startTime < result)) {
1858            return startTime;
1859          }
1860        }
1861        return result;
1862      }, null);
1863      if (start !== null && isFiniteNumber(start) && (result === null || start < result)) {
1864        return start;
1865      }
1866      return result;
1867    }, null);
1868  }
1869
1870  /*
1871    For Reference:
1872    aligned(8) class TrackFragmentHeaderBox
1873             extends FullBox(‘tfhd’, 0, tf_flags){
1874       unsigned int(32)  track_ID;
1875       // all the following are optional fields
1876       unsigned int(64)  base_data_offset;
1877       unsigned int(32)  sample_description_index;
1878       unsigned int(32)  default_sample_duration;
1879       unsigned int(32)  default_sample_size;
1880       unsigned int(32)  default_sample_flags
1881    }
1882   */
1883  function getDuration(data, initData) {
1884    var rawDuration = 0;
1885    var videoDuration = 0;
1886    var audioDuration = 0;
1887    var trafs = findBox(data, ['moof', 'traf']);
1888    for (var i = 0; i < trafs.length; i++) {
1889      var traf = trafs[i];
1890      // There is only one tfhd & trun per traf
1891      // This is true for CMAF style content, and we should perhaps check the ftyp
1892      // and only look for a single trun then, but for ISOBMFF we should check
1893      // for multiple track runs.
1894      var tfhd = findBox(traf, ['tfhd'])[0];
1895      // get the track id from the tfhd
1896      var id = readUint32(tfhd, 4);
1897      var track = initData[id];
1898      if (!track) {
1899        continue;
1900      }
1901      var trackDefault = track.default;
1902      var tfhdFlags = readUint32(tfhd, 0) | (trackDefault == null ? void 0 : trackDefault.flags);
1903      var sampleDuration = trackDefault == null ? void 0 : trackDefault.duration;
1904      if (tfhdFlags & 0x000008) {
1905        // 0x000008 indicates the presence of the default_sample_duration field
1906        if (tfhdFlags & 0x000002) {
1907          // 0x000002 indicates the presence of the sample_description_index field, which precedes default_sample_duration
1908          // If present, the default_sample_duration exists at byte offset 12
1909          sampleDuration = readUint32(tfhd, 12);
1910        } else {
1911          // Otherwise, the duration is at byte offset 8
1912          sampleDuration = readUint32(tfhd, 8);
1913        }
1914      }
1915      // assume a 90kHz clock if no timescale was specified
1916      var timescale = track.timescale || 90e3;
1917      var truns = findBox(traf, ['trun']);
1918      for (var j = 0; j < truns.length; j++) {
1919        rawDuration = computeRawDurationFromSamples(truns[j]);
1920        if (!rawDuration && sampleDuration) {
1921          var sampleCount = readUint32(truns[j], 4);
1922          rawDuration = sampleDuration * sampleCount;
1923        }
1924        if (track.type === ElementaryStreamTypes.VIDEO) {
1925          videoDuration += rawDuration / timescale;
1926        } else if (track.type === ElementaryStreamTypes.AUDIO) {
1927          audioDuration += rawDuration / timescale;
1928        }
1929      }
1930    }
1931    if (videoDuration === 0 && audioDuration === 0) {
1932      // If duration samples are not available in the traf use sidx subsegment_duration
1933      var sidxMinStart = Infinity;
1934      var sidxMaxEnd = 0;
1935      var sidxDuration = 0;
1936      var sidxs = findBox(data, ['sidx']);
1937      for (var _i2 = 0; _i2 < sidxs.length; _i2++) {
1938        var sidx = parseSegmentIndex(sidxs[_i2]);
1939        if (sidx != null && sidx.references) {
1940          sidxMinStart = Math.min(sidxMinStart, sidx.earliestPresentationTime / sidx.timescale);
1941          var subSegmentDuration = sidx.references.reduce(function (dur, ref) {
1942            return dur + ref.info.duration || 0;
1943          }, 0);
1944          sidxMaxEnd = Math.max(sidxMaxEnd, subSegmentDuration + sidx.earliestPresentationTime / sidx.timescale);
1945          sidxDuration = sidxMaxEnd - sidxMinStart;
1946        }
1947      }
1948      if (sidxDuration && isFiniteNumber(sidxDuration)) {
1949        return sidxDuration;
1950      }
1951    }
1952    if (videoDuration) {
1953      return videoDuration;
1954    }
1955    return audioDuration;
1956  }
1957
1958  /*
1959    For Reference:
1960    aligned(8) class TrackRunBox
1961             extends FullBox(‘trun’, version, tr_flags) {
1962       unsigned int(32)  sample_count;
1963       // the following are optional fields
1964       signed int(32) data_offset;
1965       unsigned int(32)  first_sample_flags;
1966       // all fields in the following array are optional
1967       {
1968          unsigned int(32)  sample_duration;
1969          unsigned int(32)  sample_size;
1970          unsigned int(32)  sample_flags
1971          if (version == 0)
1972             { unsigned int(32)
1973          else
1974             { signed int(32)
1975       }[ sample_count ]
1976    }
1977   */
1978  function computeRawDurationFromSamples(trun) {
1979    var flags = readUint32(trun, 0);
1980    // Flags are at offset 0, non-optional sample_count is at offset 4. Therefore we start 8 bytes in.
1981    // Each field is an int32, which is 4 bytes
1982    var offset = 8;
1983    // data-offset-present flag
1984    if (flags & 0x000001) {
1985      offset += 4;
1986    }
1987    // first-sample-flags-present flag
1988    if (flags & 0x000004) {
1989      offset += 4;
1990    }
1991    var duration = 0;
1992    var sampleCount = readUint32(trun, 4);
1993    for (var i = 0; i < sampleCount; i++) {
1994      // sample-duration-present flag
1995      if (flags & 0x000100) {
1996        var sampleDuration = readUint32(trun, offset);
1997        duration += sampleDuration;
1998        offset += 4;
1999      }
2000      // sample-size-present flag
2001      if (flags & 0x000200) {
2002        offset += 4;
2003      }
2004      // sample-flags-present flag
2005      if (flags & 0x000400) {
2006        offset += 4;
2007      }
2008      // sample-composition-time-offsets-present flag
2009      if (flags & 0x000800) {
2010        offset += 4;
2011      }
2012    }
2013    return duration;
2014  }
2015  function offsetStartDTS(initData, fmp4, timeOffset) {
2016    findBox(fmp4, ['moof', 'traf']).forEach(function (traf) {
vendor: 5,525 bytes, lines 2017-2155
2017      findBox(traf, ['tfhd']).forEach(function (tfhd) {
2018        // get the track id from the tfhd
2019        var id = readUint32(tfhd, 4);
2020        var track = initData[id];
2021        if (!track) {
2022          return;
2023        }
2024        // assume a 90kHz clock if no timescale was specified
2025        var timescale = track.timescale || 90e3;
2026        // get the base media decode time from the tfdt
2027        findBox(traf, ['tfdt']).forEach(function (tfdt) {
2028          var version = tfdt[0];
2029          var offset = timeOffset * timescale;
2030          if (offset) {
2031            var baseMediaDecodeTime = readUint32(tfdt, 4);
2032            if (version === 0) {
2033              baseMediaDecodeTime -= offset;
2034              baseMediaDecodeTime = Math.max(baseMediaDecodeTime, 0);
2035              writeUint32(tfdt, 4, baseMediaDecodeTime);
2036            } else {
2037              baseMediaDecodeTime *= Math.pow(2, 32);
2038              baseMediaDecodeTime += readUint32(tfdt, 8);
2039              baseMediaDecodeTime -= offset;
2040              baseMediaDecodeTime = Math.max(baseMediaDecodeTime, 0);
2041              var upper = Math.floor(baseMediaDecodeTime / (UINT32_MAX$1 + 1));
2042              var lower = Math.floor(baseMediaDecodeTime % (UINT32_MAX$1 + 1));
2043              writeUint32(tfdt, 4, upper);
2044              writeUint32(tfdt, 8, lower);
2045            }
2046          }
2047        });
2048      });
2049    });
2050  }
2051
2052  // TODO: Check if the last moof+mdat pair is part of the valid range
2053  function segmentValidRange(data) {
2054    var segmentedRange = {
2055      valid: null,
2056      remainder: null
2057    };
2058    var moofs = findBox(data, ['moof']);
2059    if (moofs.length < 2) {
2060      segmentedRange.remainder = data;
2061      return segmentedRange;
2062    }
2063    var last = moofs[moofs.length - 1];
2064    // Offset by 8 bytes; findBox offsets the start by as much
2065    segmentedRange.valid = sliceUint8(data, 0, last.byteOffset - 8);
2066    segmentedRange.remainder = sliceUint8(data, last.byteOffset - 8);
2067    return segmentedRange;
2068  }
2069  function appendUint8Array(data1, data2) {
2070    var temp = new Uint8Array(data1.length + data2.length);
2071    temp.set(data1);
2072    temp.set(data2, data1.length);
2073    return temp;
2074  }
2075  function parseSamples(timeOffset, track) {
2076    var seiSamples = [];
2077    var videoData = track.samples;
2078    var timescale = track.timescale;
2079    var trackId = track.id;
2080    var isHEVCFlavor = false;
2081    var moofs = findBox(videoData, ['moof']);
2082    moofs.map(function (moof) {
2083      var moofOffset = moof.byteOffset - 8;
2084      var trafs = findBox(moof, ['traf']);
2085      trafs.map(function (traf) {
2086        // get the base media decode time from the tfdt
2087        var baseTime = findBox(traf, ['tfdt']).map(function (tfdt) {
2088          var version = tfdt[0];
2089          var result = readUint32(tfdt, 4);
2090          if (version === 1) {
2091            result *= Math.pow(2, 32);
2092            result += readUint32(tfdt, 8);
2093          }
2094          return result / timescale;
2095        })[0];
2096        if (baseTime !== undefined) {
2097          timeOffset = baseTime;
2098        }
2099        return findBox(traf, ['tfhd']).map(function (tfhd) {
2100          var id = readUint32(tfhd, 4);
2101          var tfhdFlags = readUint32(tfhd, 0) & 0xffffff;
2102          var baseDataOffsetPresent = (tfhdFlags & 0x000001) !== 0;
2103          var sampleDescriptionIndexPresent = (tfhdFlags & 0x000002) !== 0;
2104          var defaultSampleDurationPresent = (tfhdFlags & 0x000008) !== 0;
2105          var defaultSampleDuration = 0;
2106          var defaultSampleSizePresent = (tfhdFlags & 0x000010) !== 0;
2107          var defaultSampleSize = 0;
2108          var defaultSampleFlagsPresent = (tfhdFlags & 0x000020) !== 0;
2109          var tfhdOffset = 8;
2110          if (id === trackId) {
2111            if (baseDataOffsetPresent) {
2112              tfhdOffset += 8;
2113            }
2114            if (sampleDescriptionIndexPresent) {
2115              tfhdOffset += 4;
2116            }
2117            if (defaultSampleDurationPresent) {
2118              defaultSampleDuration = readUint32(tfhd, tfhdOffset);
2119              tfhdOffset += 4;
2120            }
2121            if (defaultSampleSizePresent) {
2122              defaultSampleSize = readUint32(tfhd, tfhdOffset);
2123              tfhdOffset += 4;
2124            }
2125            if (defaultSampleFlagsPresent) {
2126              tfhdOffset += 4;
2127            }
2128            if (track.type === 'video') {
2129              isHEVCFlavor = isHEVC(track.codec);
2130            }
2131            findBox(traf, ['trun']).map(function (trun) {
2132              var version = trun[0];
2133              var flags = readUint32(trun, 0) & 0xffffff;
2134              var dataOffsetPresent = (flags & 0x000001) !== 0;
2135              var dataOffset = 0;
2136              var firstSampleFlagsPresent = (flags & 0x000004) !== 0;
2137              var sampleDurationPresent = (flags & 0x000100) !== 0;
2138              var sampleDuration = 0;
2139              var sampleSizePresent = (flags & 0x000200) !== 0;
2140              var sampleSize = 0;
2141              var sampleFlagsPresent = (flags & 0x000400) !== 0;
2142              var sampleCompositionOffsetsPresent = (flags & 0x000800) !== 0;
2143              var compositionOffset = 0;
2144              var sampleCount = readUint32(trun, 4);
2145              var trunOffset = 8; // past version, flags, and sample count
2146
2147              if (dataOffsetPresent) {
2148                dataOffset = readUint32(trun, trunOffset);
2149                trunOffset += 4;
2150              }
2151              if (firstSampleFlagsPresent) {
2152                trunOffset += 4;
2153              }
2154              var sampleOffset = dataOffset + moofOffset;
2155              for (var ix = 0;
vendor: 9,763 bytes, lines 2155-2447
2155 ix < sampleCount; ix++) {
2156                if (sampleDurationPresent) {
2157                  sampleDuration = readUint32(trun, trunOffset);
2158                  trunOffset += 4;
2159                } else {
2160                  sampleDuration = defaultSampleDuration;
2161                }
2162                if (sampleSizePresent) {
2163                  sampleSize = readUint32(trun, trunOffset);
2164                  trunOffset += 4;
2165                } else {
2166                  sampleSize = defaultSampleSize;
2167                }
2168                if (sampleFlagsPresent) {
2169                  trunOffset += 4;
2170                }
2171                if (sampleCompositionOffsetsPresent) {
2172                  if (version === 0) {
2173                    compositionOffset = readUint32(trun, trunOffset);
2174                  } else {
2175                    compositionOffset = readSint32(trun, trunOffset);
2176                  }
2177                  trunOffset += 4;
2178                }
2179                if (track.type === ElementaryStreamTypes.VIDEO) {
2180                  var naluTotalSize = 0;
2181                  while (naluTotalSize < sampleSize) {
2182                    var naluSize = readUint32(videoData, sampleOffset);
2183                    sampleOffset += 4;
2184                    if (isSEIMessage(isHEVCFlavor, videoData[sampleOffset])) {
2185                      var data = videoData.subarray(sampleOffset, sampleOffset + naluSize);
2186                      parseSEIMessageFromNALu(data, isHEVCFlavor ? 2 : 1, timeOffset + compositionOffset / timescale, seiSamples);
2187                    }
2188                    sampleOffset += naluSize;
2189                    naluTotalSize += naluSize + 4;
2190                  }
2191                }
2192                timeOffset += sampleDuration / timescale;
2193              }
2194            });
2195          }
2196        });
2197      });
2198    });
2199    return seiSamples;
2200  }
2201  function isHEVC(codec) {
2202    if (!codec) {
2203      return false;
2204    }
2205    var delimit = codec.indexOf('.');
2206    var baseCodec = delimit < 0 ? codec : codec.substring(0, delimit);
2207    return baseCodec === 'hvc1' || baseCodec === 'hev1' ||
2208    // Dolby Vision
2209    baseCodec === 'dvh1' || baseCodec === 'dvhe';
2210  }
2211  function isSEIMessage(isHEVCFlavor, naluHeader) {
2212    if (isHEVCFlavor) {
2213      var naluType = naluHeader >> 1 & 0x3f;
2214      return naluType === 39 || naluType === 40;
2215    } else {
2216      var _naluType = naluHeader & 0x1f;
2217      return _naluType === 6;
2218    }
2219  }
2220  function parseSEIMessageFromNALu(unescapedData, headerSize, pts, samples) {
2221    var data = discardEPB(unescapedData);
2222    var seiPtr = 0;
2223    // skip nal header
2224    seiPtr += headerSize;
2225    var payloadType = 0;
2226    var payloadSize = 0;
2227    var b = 0;
2228    while (seiPtr < data.length) {
2229      payloadType = 0;
2230      do {
2231        if (seiPtr >= data.length) {
2232          break;
2233        }
2234        b = data[seiPtr++];
2235        payloadType += b;
2236      } while (b === 0xff);
2237
2238      // Parse payload size.
2239      payloadSize = 0;
2240      do {
2241        if (seiPtr >= data.length) {
2242          break;
2243        }
2244        b = data[seiPtr++];
2245        payloadSize += b;
2246      } while (b === 0xff);
2247      var leftOver = data.length - seiPtr;
2248      // Create a variable to process the payload
2249      var payPtr = seiPtr;
2250
2251      // Increment the seiPtr to the end of the payload
2252      if (payloadSize < leftOver) {
2253        seiPtr += payloadSize;
2254      } else if (payloadSize > leftOver) {
2255        // Some type of corruption has happened?
2256        logger.error("Malformed SEI payload. " + payloadSize + " is too small, only " + leftOver + " bytes left to parse.");
2257        // We might be able to parse some data, but let's be safe and ignore it.
2258        break;
2259      }
2260      if (payloadType === 4) {
2261        var countryCode = data[payPtr++];
2262        if (countryCode === 181) {
2263          var providerCode = readUint16(data, payPtr);
2264          payPtr += 2;
2265          if (providerCode === 49) {
2266            var userStructure = readUint32(data, payPtr);
2267            payPtr += 4;
2268            if (userStructure === 0x47413934) {
2269              var userDataType = data[payPtr++];
2270
2271              // Raw CEA-608 bytes wrapped in CEA-708 packet
2272              if (userDataType === 3) {
2273                var firstByte = data[payPtr++];
2274                var totalCCs = 0x1f & firstByte;
2275                var enabled = 0x40 & firstByte;
2276                var totalBytes = enabled ? 2 + totalCCs * 3 : 0;
2277                var byteArray = new Uint8Array(totalBytes);
2278                if (enabled) {
2279                  byteArray[0] = firstByte;
2280                  for (var i = 1; i < totalBytes; i++) {
2281                    byteArray[i] = data[payPtr++];
2282                  }
2283                }
2284                samples.push({
2285                  type: userDataType,
2286                  payloadType: payloadType,
2287                  pts: pts,
2288                  bytes: byteArray
2289                });
2290              }
2291            }
2292          }
2293        }
2294      } else if (payloadType === 5) {
2295        if (payloadSize > 16) {
2296          var uuidStrArray = [];
2297          for (var _i3 = 0; _i3 < 16; _i3++) {
2298            var _b = data[payPtr++].toString(16);
2299            uuidStrArray.push(_b.length == 1 ? '0' + _b : _b);
2300            if (_i3 === 3 || _i3 === 5 || _i3 === 7 || _i3 === 9) {
2301              uuidStrArray.push('-');
2302            }
2303          }
2304          var length = payloadSize - 16;
2305          var userDataBytes = new Uint8Array(length);
2306          for (var _i4 = 0; _i4 < length; _i4++) {
2307            userDataBytes[_i4] = data[payPtr++];
2308          }
2309          samples.push({
2310            payloadType: payloadType,
2311            pts: pts,
2312            uuid: uuidStrArray.join(''),
2313            userData: utf8ArrayToStr(userDataBytes),
2314            userDataBytes: userDataBytes
2315          });
2316        }
2317      }
2318    }
2319  }
2320
2321  /**
2322   * remove Emulation Prevention bytes from a RBSP
2323   */
2324  function discardEPB(data) {
2325    var length = data.byteLength;
2326    var EPBPositions = [];
2327    var i = 1;
2328
2329    // Find all `Emulation Prevention Bytes`
2330    while (i < length - 2) {
2331      if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0x03) {
2332        EPBPositions.push(i + 2);
2333        i += 2;
2334      } else {
2335        i++;
2336      }
2337    }
2338
2339    // If no Emulation Prevention Bytes were found just return the original
2340    // array
2341    if (EPBPositions.length === 0) {
2342      return data;
2343    }
2344
2345    // Create a new array to hold the NAL unit data
2346    var newLength = length - EPBPositions.length;
2347    var newData = new Uint8Array(newLength);
2348    var sourceIndex = 0;
2349    for (i = 0; i < newLength; sourceIndex++, i++) {
2350      if (sourceIndex === EPBPositions[0]) {
2351        // Skip this byte
2352        sourceIndex++;
2353        // Remove this position index
2354        EPBPositions.shift();
2355      }
2356      newData[i] = data[sourceIndex];
2357    }
2358    return newData;
2359  }
2360  function parseEmsg(data) {
2361    var version = data[0];
2362    var schemeIdUri = '';
2363    var value = '';
2364    var timeScale = 0;
2365    var presentationTimeDelta = 0;
2366    var presentationTime = 0;
2367    var eventDuration = 0;
2368    var id = 0;
2369    var offset = 0;
2370    if (version === 0) {
2371      while (bin2str(data.subarray(offset, offset + 1)) !== '\0') {
2372        schemeIdUri += bin2str(data.subarray(offset, offset + 1));
2373        offset += 1;
2374      }
2375      schemeIdUri += bin2str(data.subarray(offset, offset + 1));
2376      offset += 1;
2377      while (bin2str(data.subarray(offset, offset + 1)) !== '\0') {
2378        value += bin2str(data.subarray(offset, offset + 1));
2379        offset += 1;
2380      }
2381      value += bin2str(data.subarray(offset, offset + 1));
2382      offset += 1;
2383      timeScale = readUint32(data, 12);
2384      presentationTimeDelta = readUint32(data, 16);
2385      eventDuration = readUint32(data, 20);
2386      id = readUint32(data, 24);
2387      offset = 28;
2388    } else if (version === 1) {
2389      offset += 4;
2390      timeScale = readUint32(data, offset);
2391      offset += 4;
2392      var leftPresentationTime = readUint32(data, offset);
2393      offset += 4;
2394      var rightPresentationTime = readUint32(data, offset);
2395      offset += 4;
2396      presentationTime = Math.pow(2, 32) * leftPresentationTime + rightPresentationTime;
2397      if (!isSafeInteger(presentationTime)) {
2398        presentationTime = Number.MAX_SAFE_INTEGER;
2399        logger.warn('Presentation time exceeds safe integer limit and wrapped to max safe integer in parsing emsg box');
2400      }
2401      eventDuration = readUint32(data, offset);
2402      offset += 4;
2403      id = readUint32(data, offset);
2404      offset += 4;
2405      while (bin2str(data.subarray(offset, offset + 1)) !== '\0') {
2406        schemeIdUri += bin2str(data.subarray(offset, offset + 1));
2407        offset += 1;
2408      }
2409      schemeIdUri += bin2str(data.subarray(offset, offset + 1));
2410      offset += 1;
2411      while (bin2str(data.subarray(offset, offset + 1)) !== '\0') {
2412        value += bin2str(data.subarray(offset, offset + 1));
2413        offset += 1;
2414      }
2415      value += bin2str(data.subarray(offset, offset + 1));
2416      offset += 1;
2417    }
2418    var payload = data.subarray(offset, data.byteLength);
2419    return {
2420      schemeIdUri: schemeIdUri,
2421      value: value,
2422      timeScale: timeScale,
2423      presentationTime: presentationTime,
2424      presentationTimeDelta: presentationTimeDelta,
2425      eventDuration: eventDuration,
2426      id: id,
2427      payload: payload
2428    };
2429  }
2430
2431  var LevelKey = /*#__PURE__*/function () {
2432    function LevelKey(method, uri, format, formatversions, iv) {
2433      if (formatversions === void 0) {
2434        formatversions = [1];
2435      }
2436      if (iv === void 0) {
2437        iv = null;
2438      }
2439      this.uri = void 0;
2440      this.method = void 0;
2441      this.keyFormat = void 0;
2442      this.keyFormatVersions = void 0;
2443      this.encrypted = void 0;
2444      this.isCommonEncryption = void 0;
2445      this.iv = null;
2446      this.key = null;
2447      this.keyId = null;
2448      this.pssh = null;
2449      this.method = method;
2450      this.uri = uri;
2451      this.keyFormat = format;
2452      this.keyFormatVersions = formatversions;
2453      this.iv = iv;
2454      this.encrypted = method ? method !== 'NONE' : false;
2455      this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2456    }
2457    LevelKey.clearKeyUriToKeyIdMap = function clearKeyUriToKeyIdMap() {
2458    };
2459    var _proto = LevelKey.prototype;
2460    _proto.isSupported = function isSupported() {
2461      // If it's Segment encryption or No encryption, just select that key system
2462      if (this.method) {
2463        if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2464          return true;
2465        }
2466        if (this.keyFormat === 'identity') {
2467          // Maintain support for clear SAMPLE-AES with MPEG-3 TS
2468          return this.method === 'SAMPLE-AES';
2469        }
2470      }
2471      return false;
2472    };
2473    _proto.getDecryptData = function getDecryptData(sn) {
2474      if (!this.encrypted || !this.uri) {
2475        return null;
2476      }
2477      if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2478        if (typeof sn !== 'number') {
2479          // We are fetching decryption data for a initialization segment
2480          // If the segment was encrypted with AES-128/256
2481          // It must have an IV defined. We cannot substitute the Segment Number in.
2482          logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2483
2484          // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2485          sn = 0;
2486        }
2487        var iv = createInitializationVector(sn);
2488        var decryptdata = new LevelKey(this.method, this.uri, 'identity', this.keyFormatVersions, iv);
2489        return decryptdata;
2490      }
2491      {
2492        return this;
2493      }
2494    };
2495    return LevelKey;
2496  }();
2497  function createInitializationVector(segmentNumber) {
2498    var uint8View = new Uint8Array(16);
2499    for (var i = 12; i < 16; i++) {
2500      uint8View[i] = segmentNumber >> 8 * (15 - i) & 0xff;
2501    }
2502    return uint8View;
2503  }
2504
2505  /**
2506   * MediaSource helper
2507   */
2508
2509  function getMediaSource(preferManagedMediaSource) {
2510    if (preferManagedMediaSource === void 0) {
2511      preferManagedMediaSource = true;
2512    }
2513    if (typeof self === 'undefined') return undefined;
2514    var mms = (preferManagedMediaSource || !self.MediaSource) && self.ManagedMediaSource;
2515    return mms || self.MediaSource || self.WebKitMediaSource;
2516  }
2517  function isManagedMediaSource(source) {
2518    return typeof self !== 'undefined' && source === self.ManagedMediaSource;
2519  }
2520
2521  // from http://mp4ra.org/codecs.html
2522  // values indicate codec selection preference (lower is higher priority)
2523  var sampleEntryCodesISO = {
2524    audio: {
2525      a3ds: 1,
2526      'ac-3': 0.95,
2527      'ac-4': 1,
2528      alac: 0.9,
2529      alaw: 1,
2530      dra1: 1,
2531      'dts+': 1,
2532      'dts-': 1,
2533      dtsc: 1,
2534      dtse: 1,
2535      dtsh: 1,
2536      'ec-3': 0.9,
2537      enca: 1,
2538      fLaC: 0.9,
2539      // MP4-RA listed codec entry for FLAC
2540      flac: 0.9,
2541      // legacy browser codec name for FLAC
2542      FLAC: 0.9,
2543      // some manifests may list "FLAC" with Apple's tools
2544      g719: 1,
2545      g726: 1,
2546      m4ae: 1,
2547      mha1: 1,
2548      mha2: 1,
2549      mhm1: 1,
2550      mhm2: 1,
2551      mlpa: 1,
2552      mp4a: 1,
2553      'raw ': 1,
2554      Opus: 1,
2555      opus: 1,
2556      // browsers expect this to be lowercase despite MP4RA says 'Opus'
2557      samr: 1,
2558      sawb: 1,
2559      sawp: 1,
2560      sevc: 1,
2561      sqcp: 1,
2562      ssmv: 1,
2563      twos: 1,
2564      ulaw: 1
2565    },
2566    video: {
2567      avc1: 1,
2568      avc2: 1,
2569      avc3: 1,
2570      avc4: 1,
2571      avcp: 1,
2572      av01: 0.8,
2573      drac: 1,
2574      dva1: 1,
2575      dvav: 1,
2576      dvh1: 0.7,
2577      dvhe: 0.7,
2578      encv: 1,
2579      hev1: 0.75,
2580      hvc1: 0.75,
2581      mjp2: 1,
2582      mp4v: 1,
2583      mvc1: 1,
2584      mvc2: 1,
2585      mvc3: 1,
2586      mvc4: 1,
2587      resv: 1,
2588      rv60: 1,
2589      s263: 1,
2590      svc1: 1,
2591      svc2: 1,
2592      'vc-1': 1,
2593      vp08: 1,
2594      vp09: 0.9
2595    },
2596    text: {
2597      stpp: 1,
2598      wvtt: 1
2599    }
2600  };
2601  function isCodecType(codec, type) {
2602    var typeCodes = sampleEntryCodesISO[type];
2603    return !!typeCodes && !!typeCodes[codec.slice(0, 4)];
2604  }
2605  function areCodecsMediaSourceSupported(codecs, type, preferManagedMediaSource) {
2606    if (preferManagedMediaSource === void 0) {
2607      preferManagedMediaSource = true;
2608    }
2609    return !codecs.split(',').some(function (codec) {
2610      return !isCodecMediaSourceSupported(codec, type, preferManagedMediaSource);
2611    });
2612  }
2613  function isCodecMediaSourceSupported(codec, type, preferManagedMediaSource) {
2614    var _MediaSource$isTypeSu;
2615    if (preferManagedMediaSource === void 0) {
2616      preferManagedMediaSource = true;
2617    }
2618    var MediaSource = getMediaSource(preferManagedMediaSource);
2619    return (_MediaSource$isTypeSu = MediaSource == null ? void 0 : MediaSource.isTypeSupported(mimeTypeForCodec(codec, type))) != null ? _MediaSource$isTypeSu : false;
2620  }
2621  function mimeTypeForCodec(codec, type) {
2622    return type + "/mp4;codecs=\"" + codec + "\"";
2623  }
2624  function videoCodecPreferenceValue(videoCodec) {
2625    if (videoCodec) {
2626      var fourCC = videoCodec.substring(0, 4);
2627      return sampleEntryCodesISO.video[fourCC];
2628    }
2629    return 2;
2630  }
2631  function codecsSetSelectionPreferenceValue(codecSet) {
2632    return codecSet.split(',').reduce(function (num, fourCC) {
2633      var preferenceValue = sampleEntryCodesISO.video[fourCC];
2634      if (preferenceValue) {
2635        return (preferenceValue * 2 + num) / (num ? 3 : 2);
2636      }
2637      return (sampleEntryCodesISO.audio[fourCC] + num) / (num ? 2 : 1);
2638    }, 0);
2639  }
2640  var CODEC_COMPATIBLE_NAMES = {};
2641  function getCodecCompatibleNameLower(lowerCaseCodec, preferManagedMediaSource) {
2642    if (preferManagedMediaSource === void 0) {
2643      preferManagedMediaSource = true;
2644    }
2645    if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2646      return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2647    }
2648    var codecsToCheck = {
2649      // Idealy fLaC and Opus would be first (spec-compliant) but
2650      // some browsers will report that fLaC is supported then fail.
2651      // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2652      flac: ['flac', 'fLaC', 'FLAC'],
2653      opus: ['opus', 'Opus'],
2654      // Replace audio codec info if browser does not support mp4a.40.34,
2655      // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
2656      'mp4a.40.34': ['mp3']
2657    }[lowerCaseCodec];
2658    for (var i = 0; i < codecsToCheck.length; i++) {
2659      var _getMediaSource;
2660      if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2661        CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2662        return codecsToCheck[i];
2663      } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2664        return '';
2665      }
2666    }
2667    return lowerCaseCodec;
2668  }
2669  var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2670  function getCodecCompatibleName(codec, preferManagedMediaSource) {
2671    if (preferManagedMediaSource === void 0) {
2672      preferManagedMediaSource = true;
2673    }
2674    return codec.replace(AUDIO_CODEC_REGEXP, function (m) {
2675      return getCodecCompatibleNameLower(m.toLowerCase(), preferManagedMediaSource);
2676    });
2677  }
2678  function pickMostCompleteCodecName(parsedCodec, levelCodec) {
2679    // Parsing of mp4a codecs strings in mp4-tools from media is incomplete as of d8c6c7a
2680    // so use level codec is parsed codec is unavailable or incomplete
2681    if (parsedCodec && parsedCodec !== 'mp4a') {
2682      return parsedCodec;
2683    }
2684    return levelCodec ? levelCodec.split(',')[0] : levelCodec;
2685  }
2686  function convertAVC1ToAVCOTI(codec) {
2687    // Convert avc1 codec string from RFC-4281 to RFC-6381 for MediaSource.isTypeSupported
2688    // Examples: avc1.66.30 to avc1.42001e and avc1.77.30,avc1.66.30 to avc1.4d001e,avc1.42001e.
2689    var codecs = codec.split(',');
2690    for (var i = 0; i < codecs.length; i++) {
2691      var avcdata = codecs[i].split('.');
2692      if (avcdata.length > 2) {
2693        var result = avcdata.shift() + '.';
2694        result += parseInt(avcdata.shift()).toString(16);
2695        result += ('000' + parseInt(avcdata.shift()).toString(16)).slice(-4);
2696        codecs[i] = result;
2697      }
2698    }
2699    return codecs.join(',');
2700  }
2701  function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2702    var MediaSource = getMediaSource(preferManagedMediaSource) || {
vendor: 8,127 bytes, lines 2703-2904
2703      isTypeSupported: function isTypeSupported() {
2704        return false;
2705      }
2706    };
2707    return {
2708      mpeg: MediaSource.isTypeSupported('audio/mpeg'),
2709      mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
2710      ac3: false
2711    };
2712  }
2713
2714  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;
2715  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
2716  var IS_MEDIA_PLAYLIST = /^#EXT(?:INF|-X-TARGETDURATION):/m; // Handle empty Media Playlist (first EXTINF not signaled, but TARGETDURATION present)
2717
2718  var LEVEL_PLAYLIST_REGEX_FAST = new RegExp([/#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*)\s+)?/.source,
2719  // duration (#EXTINF:<duration>,<title>), group 1 => duration, group 2 => title
2720  /(?!#) *(\S[^\r\n]*)/.source,
2721  // segment URI, group 3 => the URI (note newline is not eaten)
2722  /#EXT-X-BYTERANGE:*(.+)/.source,
2723  // next segment's byterange, group 4 => range spec (x@y)
2724  /#EXT-X-PROGRAM-DATE-TIME:(.+)/.source,
2725  // next segment's program date/time group 5 => the datetime spec
2726  /#.*/.source // All other non-segment oriented tags will match with all groups empty
2727  ].join('|'), 'g');
2728  var LEVEL_PLAYLIST_REGEX_SLOW = new RegExp([/#(EXTM3U)/.source, /#EXT-X-(DATERANGE|DEFINE|KEY|MAP|PART|PART-INF|PLAYLIST-TYPE|PRELOAD-HINT|RENDITION-REPORT|SERVER-CONTROL|SKIP|START):(.+)/.source, /#EXT-X-(BITRATE|DISCONTINUITY-SEQUENCE|MEDIA-SEQUENCE|TARGETDURATION|VERSION): *(\d+)/.source, /#EXT-X-(DISCONTINUITY|ENDLIST|GAP|INDEPENDENT-SEGMENTS)/.source, /(#)([^:]*):(.*)/.source, /(#)(.*)(?:.*)\r?\n?/.source].join('|'));
2729  var M3U8Parser = /*#__PURE__*/function () {
2730    function M3U8Parser() {}
2731    M3U8Parser.findGroup = function findGroup(groups, mediaGroupId) {
2732      for (var i = 0; i < groups.length; i++) {
2733        var group = groups[i];
2734        if (group.id === mediaGroupId) {
2735          return group;
2736        }
2737      }
2738    };
2739    M3U8Parser.resolve = function resolve(url, baseUrl) {
2740      return urlToolkitExports.buildAbsoluteURL(baseUrl, url, {
2741        alwaysNormalize: true
2742      });
2743    };
2744    M3U8Parser.isMediaPlaylist = function isMediaPlaylist(str) {
2745      return IS_MEDIA_PLAYLIST.test(str);
2746    };
2747    M3U8Parser.parseMasterPlaylist = function parseMasterPlaylist(string, baseurl) {
2748      var hasVariableRefs = false;
2749      var parsed = {
2750        contentSteering: null,
2751        levels: [],
2752        playlistParsingError: null,
2753        sessionData: null,
2754        sessionKeys: null,
2755        startTimeOffset: null,
2756        variableList: null,
2757        hasVariableRefs: hasVariableRefs
2758      };
2759      var levelsWithKnownCodecs = [];
2760      MASTER_PLAYLIST_REGEX.lastIndex = 0;
2761      var result;
2762      while ((result = MASTER_PLAYLIST_REGEX.exec(string)) != null) {
2763        if (result[1]) {
2764          var _level$unknownCodecs;
2765          // '#EXT-X-STREAM-INF' is found, parse level tag  in group 1
2766          var attrs = new AttrList(result[1], parsed);
2767          var uri = result[2];
2768          var level = {
2769            attrs: attrs,
2770            bitrate: attrs.decimalInteger('BANDWIDTH') || attrs.decimalInteger('AVERAGE-BANDWIDTH'),
2771            name: attrs.NAME,
2772            url: M3U8Parser.resolve(uri, baseurl)
2773          };
2774          var resolution = attrs.decimalResolution('RESOLUTION');
2775          if (resolution) {
2776            level.width = resolution.width;
2777            level.height = resolution.height;
2778          }
2779          setCodecs(attrs.CODECS, level);
2780          if (!((_level$unknownCodecs = level.unknownCodecs) != null && _level$unknownCodecs.length)) {
2781            levelsWithKnownCodecs.push(level);
2782          }
2783          parsed.levels.push(level);
2784        } else if (result[3]) {
2785          var tag = result[3];
2786          var attributes = result[4];
2787          switch (tag) {
2788            case 'SESSION-DATA':
2789              {
2790                // #EXT-X-SESSION-DATA
2791                var sessionAttrs = new AttrList(attributes, parsed);
2792                var dataId = sessionAttrs['DATA-ID'];
2793                if (dataId) {
2794                  if (parsed.sessionData === null) {
2795                    parsed.sessionData = {};
2796                  }
2797                  parsed.sessionData[dataId] = sessionAttrs;
2798                }
2799                break;
2800              }
2801            case 'SESSION-KEY':
2802              {
2803                // #EXT-X-SESSION-KEY
2804                var sessionKey = parseKey(attributes, baseurl, parsed);
2805                if (sessionKey.encrypted && sessionKey.isSupported()) {
2806                  if (parsed.sessionKeys === null) {
2807                    parsed.sessionKeys = [];
2808                  }
2809                  parsed.sessionKeys.push(sessionKey);
2810                } else {
2811                  logger.warn("[Keys] Ignoring invalid EXT-X-SESSION-KEY tag: \"" + attributes + "\"");
2812                }
2813                break;
2814              }
2815            case 'DEFINE':
2816              {
2817                break;
2818              }
2819            case 'CONTENT-STEERING':
2820              {
2821                // #EXT-X-CONTENT-STEERING
2822                var contentSteeringAttributes = new AttrList(attributes, parsed);
2823                parsed.contentSteering = {
2824                  uri: M3U8Parser.resolve(contentSteeringAttributes['SERVER-URI'], baseurl),
2825                  pathwayId: contentSteeringAttributes['PATHWAY-ID'] || '.'
2826                };
2827                break;
2828              }
2829            case 'START':
2830              {
2831                // #EXT-X-START
2832                parsed.startTimeOffset = parseStartTimeOffset(attributes);
2833                break;
2834              }
2835          }
2836        }
2837      }
2838      // Filter out levels with unknown codecs if it does not remove all levels
2839      var stripUnknownCodecLevels = levelsWithKnownCodecs.length > 0 && levelsWithKnownCodecs.length < parsed.levels.length;
2840      parsed.levels = stripUnknownCodecLevels ? levelsWithKnownCodecs : parsed.levels;
2841      if (parsed.levels.length === 0) {
2842        parsed.playlistParsingError = new Error('no levels found in manifest');
2843      }
2844      return parsed;
2845    };
2846    M3U8Parser.parseMasterPlaylistMedia = function parseMasterPlaylistMedia(string, baseurl, parsed) {
2847      var result;
2848      var results = {};
2849      var levels = parsed.levels;
2850      var groupsByType = {
2851        AUDIO: levels.map(function (level) {
2852          return {
2853            id: level.attrs.AUDIO,
2854            audioCodec: level.audioCodec
2855          };
2856        }),
2857        SUBTITLES: levels.map(function (level) {
2858          return {
2859            id: level.attrs.SUBTITLES,
2860            textCodec: level.textCodec
2861          };
2862        }),
2863        'CLOSED-CAPTIONS': []
2864      };
2865      var id = 0;
2866      MASTER_PLAYLIST_MEDIA_REGEX.lastIndex = 0;
2867      while ((result = MASTER_PLAYLIST_MEDIA_REGEX.exec(string)) !== null) {
2868        var attrs = new AttrList(result[1], parsed);
2869        var type = attrs.TYPE;
2870        if (type) {
2871          var groups = groupsByType[type];
2872          var medias = results[type] || [];
2873          results[type] = medias;
2874          var lang = attrs.LANGUAGE;
2875          var assocLang = attrs['ASSOC-LANGUAGE'];
2876          var channels = attrs.CHANNELS;
2877          var characteristics = attrs.CHARACTERISTICS;
2878          var instreamId = attrs['INSTREAM-ID'];
2879          var media = {
2880            attrs: attrs,
2881            bitrate: 0,
2882            id: id++,
2883            groupId: attrs['GROUP-ID'] || '',
2884            name: attrs.NAME || lang || '',
2885            type: type,
2886            default: attrs.bool('DEFAULT'),
2887            autoselect: attrs.bool('AUTOSELECT'),
2888            forced: attrs.bool('FORCED'),
2889            lang: lang,
2890            url: attrs.URI ? M3U8Parser.resolve(attrs.URI, baseurl) : ''
2891          };
2892          if (assocLang) {
2893            media.assocLang = assocLang;
2894          }
2895          if (channels) {
2896            media.channels = channels;
2897          }
2898          if (characteristics) {
2899            media.characteristics = characteristics;
2900          }
2901          if (instreamId) {
2902            media.instreamId = instreamId;
2903          }
2904          if (groups != null && groups.length) {
2905            // If there are audio or text groups signalled in the manifest, let's look for a matching codec string for this track
2906            // If we don't find the track signalled, lets use the first audio groups codec we have
2907            // Acting as a best guess
2908            var groupCodec = M3U8Parser.findGroup(groups, media.groupId) || groups[0];
2909            assignCodec(media, groupCodec, 'audioCodec');
2910            assignCodec(media, groupCodec, 'textCodec');
2911          }
2912          medias.push(media);
2913        }
2914      }
2915      return results;
2916    };
2917    M3U8Parser.parseLevelPlaylist = function parseLevelPlaylist(string, baseurl, id, type, levelUrlId, multivariantVariableList) {
2918      var level = new LevelDetails(baseurl);
2919      var fragments = level.fragments;
2920      var programDateTimes = [];
2921      // The most recent init segment seen (applies to all subsequent segments)
2922      var currentInitSegment = null;
2923      var currentSN = 0;
2924      var currentPart = 0;
2925      var totalduration = 0;
2926      var discontinuityCounter = 0;
2927      var prevFrag = null;
2928      var frag = new Fragment(type, baseurl);
2929      var result;
2930      var i;
2931      var levelkeys;
2932      var firstPdtIndex = -1;
2933      var createNextFrag = false;
2934      var nextByteRange = null;
2935      LEVEL_PLAYLIST_REGEX_FAST.lastIndex = 0;
2936      level.m3u8 = string;
2937      level.hasVariableRefs = false;
2938      while ((result = LEVEL_PLAYLIST_REGEX_FAST.exec(string)) !== null) {
2939        if (createNextFrag) {
2940          createNextFrag = false;
2941          frag = new Fragment(type, baseurl);
2942          // setup the next fragment for part loading
2943          frag.start = totalduration;
2944          frag.sn = currentSN;
2945          frag.cc = discontinuityCounter;
2946          frag.level = id;
2947          if (currentInitSegment) {
2948            frag.initSegment = currentInitSegment;
2949            frag.rawProgramDateTime = currentInitSegment.rawProgramDateTime;
2950            currentInitSegment.rawProgramDateTime = null;
2951            if (nextByteRange) {
2952              frag.setByteRange(nextByteRange);
2953              nextByteRange = null;
2954            }
2955          }
2956        }
2957        var duration = result[1];
2958        if (duration) {
2959          // INF
2960          frag.duration = parseFloat(duration);
2961          // avoid sliced strings    https://github.com/video-dev/hls.js/issues/939
2962          var title = (' ' + result[2]).slice(1);
2963          frag.title = title || null;
2964          frag.tagList.push(title ? ['INF', duration, title] : ['INF', duration]);
2965        } else if (result[3]) {
2966          // url
2967          if (isFiniteNumber(frag.duration)) {
2968            frag.start = totalduration;
2969            if (levelkeys) {
2970              setFragLevelKeys(frag, levelkeys, level);
2971            }
2972            frag.sn = currentSN;
2973            frag.level = id;
2974            frag.cc = discontinuityCounter;
2975            fragments.push(frag);
2976            // avoid sliced strings    https://github.com/video-dev/hls.js/issues/939
2977            var uri = (' ' + result[3]).slice(1);
2978            frag.relurl = uri;
2979            assignProgramDateTime(frag, prevFrag, programDateTimes);
2980            prevFrag = frag;
2981            totalduration += frag.duration;
2982            currentSN++;
2983            currentPart = 0;
2984            createNextFrag = true;
2985          }
2986        } else if (result[4]) {
2987          // X-BYTERANGE
2988          var data = (' ' + result[4]).slice(1);
2989          if (prevFrag) {
2990            frag.setByteRange(data, prevFrag);
2991          } else {
2992            frag.setByteRange(data);
2993          }
2994        } else if (result[5]) {
2995          // PROGRAM-DATE-TIME
2996          // avoid sliced strings    https://github.com/video-dev/hls.js/issues/939
2997          frag.rawProgramDateTime = (' ' + result[5]).slice(1);
2998          frag.tagList.push(['PROGRAM-DATE-TIME', frag.rawProgramDateTime]);
2999          if (firstPdtIndex === -1) {
3000            firstPdtIndex = fragments.length;
3001          }
3002        } else {
3003          result = result[0].match(LEVEL_PLAYLIST_REGEX_SLOW);
3004          if (!result) {
3005            logger.warn('No matches on slow regex match for level playlist!');
3006            continue;
3007          }
3008          for (i = 1; i < result.length; i++) {
3009            if (typeof result[i] !== 'undefined') {
3010              break;
3011            }
3012          }
3013
3014          // avoid sliced strings    https://github.com/video-dev/hls.js/issues/939
3015          var tag = (' ' + result[i]).slice(1);
3016          var value1 = (' ' + result[i + 1]).slice(1);
3017          var value2 = result[i + 2] ? (' ' + result[i + 2]).slice(1) : '';
3018          switch (tag) {
3019            case 'PLAYLIST-TYPE':
3020              level.type = value1.toUpperCase();
3021              break;
3022            case 'MEDIA-SEQUENCE':
3023              currentSN = level.startSN = parseInt(value1);
3024              break;
3025            case 'SKIP':
3026              {
3027                if (level.skippedSegments) {
3028                  level.playlistParsingError = new Error("#EXT-X-SKIP MUST NOT appear more than once in a Playlist");
3029                }
3030                var skipAttrs = new AttrList(value1, level);
3031                var skippedSegments = skipAttrs.decimalInteger('SKIPPED-SEGMENTS');
3032                if (isFiniteNumber(skippedSegments)) {
3033                  level.skippedSegments += skippedSegments;
3034                  // This will result in fragments[] containing undefined values, which we will fill in with `mergeDetails`
3035                  for (var _i = skippedSegments; _i--;) {
3036                    fragments.push(null);
3037                  }
3038                  currentSN += skippedSegments;
3039                }
3040                var recentlyRemovedDateranges = skipAttrs.enumeratedString('RECENTLY-REMOVED-DATERANGES');
3041                if (recentlyRemovedDateranges) {
3042                  level.recentlyRemovedDateranges = (level.recentlyRemovedDateranges || []).concat(recentlyRemovedDateranges.split('\t'));
3043                }
3044                break;
3045              }
3046            case 'TARGETDURATION':
3047              level.targetduration = Math.max(parseInt(value1), 1);
3048              break;
3049            case 'VERSION':
vendor: 20,004 bytes, lines 3050-3563
3050              level.version = parseInt(value1);
3051              break;
3052            case 'INDEPENDENT-SEGMENTS':
3053            case 'EXTM3U':
3054              break;
3055            case 'ENDLIST':
3056              level.live = false;
3057              break;
3058            case '#':
3059              if (value1 || value2) {
3060                frag.tagList.push(value2 ? [value1, value2] : [value1]);
3061              }
3062              break;
3063            case 'DISCONTINUITY':
3064              discontinuityCounter++;
3065              frag.tagList.push(['DIS']);
3066              break;
3067            case 'GAP':
3068              frag.gap = true;
3069              frag.tagList.push([tag]);
3070              break;
3071            case 'BITRATE':
3072              frag.tagList.push([tag, value1]);
3073              break;
3074            case 'DATERANGE':
3075              {
3076                var dateRangeAttr = new AttrList(value1, level);
3077                var dateRange = new DateRange(dateRangeAttr, level.dateRanges[dateRangeAttr.ID], level.dateRangeTagCount);
3078                level.dateRangeTagCount++;
3079                if (dateRange.isValid || level.skippedSegments) {
3080                  level.dateRanges[dateRange.id] = dateRange;
3081                } else {
3082                  logger.warn("Ignoring invalid DATERANGE tag: \"" + value1 + "\"");
3083                }
3084                // Add to fragment tag list for backwards compatibility (< v1.2.0)
3085                frag.tagList.push(['EXT-X-DATERANGE', value1]);
3086                break;
3087              }
3088            case 'DEFINE':
3089              {
3090                break;
3091              }
3092            case 'DISCONTINUITY-SEQUENCE':
3093              discontinuityCounter = parseInt(value1);
3094              break;
3095            case 'KEY':
3096              {
3097                var levelKey = parseKey(value1, baseurl, level);
3098                if (levelKey.isSupported()) {
3099                  if (levelKey.method === 'NONE') {
3100                    levelkeys = undefined;
3101                    break;
3102                  }
3103                  if (!levelkeys) {
3104                    levelkeys = {};
3105                  }
3106                  if (levelkeys[levelKey.keyFormat]) {
3107                    levelkeys = _extends({}, levelkeys);
3108                  }
3109                  levelkeys[levelKey.keyFormat] = levelKey;
3110                } else {
3111                  logger.warn("[Keys] Ignoring invalid EXT-X-KEY tag: \"" + value1 + "\"");
3112                }
3113                break;
3114              }
3115            case 'START':
3116              level.startTimeOffset = parseStartTimeOffset(value1);
3117              break;
3118            case 'MAP':
3119              {
3120                var mapAttrs = new AttrList(value1, level);
3121                if (frag.duration) {
3122                  // Initial segment tag is after segment duration tag.
3123                  //   #EXTINF: 6.0
3124                  //   #EXT-X-MAP:URI="init.mp4
3125                  var init = new Fragment(type, baseurl);
3126                  setInitSegment(init, mapAttrs, id, levelkeys);
3127                  currentInitSegment = init;
3128                  frag.initSegment = currentInitSegment;
3129                  if (currentInitSegment.rawProgramDateTime && !frag.rawProgramDateTime) {
3130                    frag.rawProgramDateTime = currentInitSegment.rawProgramDateTime;
3131                  }
3132                } else {
3133                  // Initial segment tag is before segment duration tag
3134                  // Handle case where EXT-X-MAP is declared after EXT-X-BYTERANGE
3135                  var end = frag.byteRangeEndOffset;
3136                  if (end) {
3137                    var start = frag.byteRangeStartOffset;
3138                    nextByteRange = end - start + "@" + start;
3139                  } else {
3140                    nextByteRange = null;
3141                  }
3142                  setInitSegment(frag, mapAttrs, id, levelkeys);
3143                  currentInitSegment = frag;
3144                  createNextFrag = true;
3145                }
3146                currentInitSegment.cc = discontinuityCounter;
3147                break;
3148              }
3149            case 'SERVER-CONTROL':
3150              {
3151                var serverControlAttrs = new AttrList(value1);
3152                level.canBlockReload = serverControlAttrs.bool('CAN-BLOCK-RELOAD');
3153                level.canSkipUntil = serverControlAttrs.optionalFloat('CAN-SKIP-UNTIL', 0);
3154                level.canSkipDateRanges = level.canSkipUntil > 0 && serverControlAttrs.bool('CAN-SKIP-DATERANGES');
3155                level.partHoldBack = serverControlAttrs.optionalFloat('PART-HOLD-BACK', 0);
3156                level.holdBack = serverControlAttrs.optionalFloat('HOLD-BACK', 0);
3157                break;
3158              }
3159            case 'PART-INF':
3160              {
3161                var partInfAttrs = new AttrList(value1);
3162                level.partTarget = partInfAttrs.decimalFloatingPoint('PART-TARGET');
3163                break;
3164              }
3165            case 'PART':
3166              {
3167                var partList = level.partList;
3168                if (!partList) {
3169                  partList = level.partList = [];
3170                }
3171                var previousFragmentPart = currentPart > 0 ? partList[partList.length - 1] : undefined;
3172                var index = currentPart++;
3173                var partAttrs = new AttrList(value1, level);
3174                var part = new Part(partAttrs, frag, baseurl, index, previousFragmentPart);
3175                partList.push(part);
3176                frag.duration += part.duration;
3177                break;
3178              }
3179            case 'PRELOAD-HINT':
3180              {
3181                var preloadHintAttrs = new AttrList(value1, level);
3182                level.preloadHint = preloadHintAttrs;
3183                break;
3184              }
3185            case 'RENDITION-REPORT':
3186              {
3187                var renditionReportAttrs = new AttrList(value1, level);
3188                level.renditionReports = level.renditionReports || [];
3189                level.renditionReports.push(renditionReportAttrs);
3190                break;
3191              }
3192            default:
3193              logger.warn("line parsed but not handled: " + result);
3194              break;
3195          }
3196        }
3197      }
3198      if (prevFrag && !prevFrag.relurl) {
3199        fragments.pop();
3200        totalduration -= prevFrag.duration;
3201        if (level.partList) {
3202          level.fragmentHint = prevFrag;
3203        }
3204      } else if (level.partList) {
3205        assignProgramDateTime(frag, prevFrag, programDateTimes);
3206        frag.cc = discontinuityCounter;
3207        level.fragmentHint = frag;
3208        if (levelkeys) {
3209          setFragLevelKeys(frag, levelkeys, level);
3210        }
3211      }
3212      var fragmentLength = fragments.length;
3213      var firstFragment = fragments[0];
3214      var lastFragment = fragments[fragmentLength - 1];
3215      totalduration += level.skippedSegments * level.targetduration;
3216      if (totalduration > 0 && fragmentLength && lastFragment) {
3217        level.averagetargetduration = totalduration / fragmentLength;
3218        var lastSn = lastFragment.sn;
3219        level.endSN = lastSn !== 'initSegment' ? lastSn : 0;
3220        if (!level.live) {
3221          lastFragment.endList = true;
3222        }
3223        if (firstFragment) {
3224          level.startCC = firstFragment.cc;
3225        }
3226        /**
3227         * Backfill any missing PDT values
3228         * "If the first EXT-X-PROGRAM-DATE-TIME tag in a Playlist appears after
3229         * one or more Media Segment URIs, the client SHOULD extrapolate
3230         * backward from that tag (using EXTINF durations and/or media
3231         * timestamps) to associate dates with those segments."
3232         * We have already extrapolated forward, but all fragments up to the first instance of PDT do not have their PDTs
3233         * computed.
3234         */
3235        if (firstPdtIndex > 0) {
3236          backfillProgramDateTimes(fragments, firstPdtIndex);
3237          if (firstFragment) {
3238            programDateTimes.unshift(firstFragment);
3239          }
3240        }
3241      } else {
3242        level.endSN = 0;
3243        level.startCC = 0;
3244      }
3245      if (level.fragmentHint) {
3246        totalduration += level.fragmentHint.duration;
3247      }
3248      level.totalduration = totalduration;
3249      if (programDateTimes.length && level.dateRangeTagCount && firstFragment) {
3250        mapDateRanges(programDateTimes, level);
3251      }
3252      level.endCC = discontinuityCounter;
3253      return level;
3254    };
3255    return M3U8Parser;
3256  }();
3257  function mapDateRanges(programDateTimes, details) {
3258    // Make sure DateRanges are mapped to a ProgramDateTime tag that applies a date to a segment that overlaps with its start date
3259    var programDateTimeCount = programDateTimes.length;
3260    var lastProgramDateTime = programDateTimes[programDateTimeCount - 1];
3261    var playlistEnd = details.live ? Infinity : details.totalduration;
3262    var dateRangeIds = Object.keys(details.dateRanges);
3263    for (var i = dateRangeIds.length; i--;) {
3264      var dateRange = details.dateRanges[dateRangeIds[i]];
3265      var startDateTime = dateRange.startDate.getTime();
3266      dateRange.tagAnchor = lastProgramDateTime;
3267      for (var j = programDateTimeCount; j--;) {
3268        var fragIndex = findFragmentWithStartDate(details, startDateTime, programDateTimes, j, playlistEnd);
3269        if (fragIndex !== -1) {
3270          dateRange.tagAnchor = details.fragments[fragIndex];
3271          break;
3272        }
3273      }
3274    }
3275  }
3276  function findFragmentWithStartDate(details, startDateTime, programDateTimes, index, endTime) {
3277    var pdtFragment = programDateTimes[index];
3278    if (pdtFragment) {
3279      var _programDateTimes;
3280      // find matching range between PDT tags
3281      var durationBetweenPdt = (((_programDateTimes = programDateTimes[index + 1]) == null ? void 0 : _programDateTimes.start) || endTime) - pdtFragment.start;
3282      var pdtStart = pdtFragment.programDateTime;
3283      if ((startDateTime >= pdtStart || index === 0) && startDateTime <= pdtStart + durationBetweenPdt * 1000) {
3284        // map to fragment with date-time range
3285        var startIndex = programDateTimes[index].sn - details.startSN;
3286        var fragments = details.fragments;
3287        if (fragments.length > programDateTimes.length) {
3288          var endSegment = programDateTimes[index + 1] || fragments[fragments.length - 1];
3289          var endIndex = endSegment.sn - details.startSN;
3290          for (var i = endIndex; i > startIndex; i--) {
3291            var fragStartDateTime = fragments[i].programDateTime;
3292            if (startDateTime >= fragStartDateTime && startDateTime < fragStartDateTime + fragments[i].duration * 1000) {
3293              return i;
3294            }
3295          }
3296        }
3297        return startIndex;
3298      }
3299    }
3300    return -1;
3301  }
3302  function parseKey(keyTagAttributes, baseurl, parsed) {
3303    var _keyAttrs$METHOD, _keyAttrs$KEYFORMAT;
3304    // https://tools.ietf.org/html/rfc8216#section-4.3.2.4
3305    var keyAttrs = new AttrList(keyTagAttributes, parsed);
3306    var decryptmethod = (_keyAttrs$METHOD = keyAttrs.METHOD) != null ? _keyAttrs$METHOD : '';
3307    var decrypturi = keyAttrs.URI;
3308    var decryptiv = keyAttrs.hexadecimalInteger('IV');
3309    var decryptkeyformatversions = keyAttrs.KEYFORMATVERSIONS;
3310    // From RFC: This attribute is OPTIONAL; its absence indicates an implicit value of "identity".
3311    var decryptkeyformat = (_keyAttrs$KEYFORMAT = keyAttrs.KEYFORMAT) != null ? _keyAttrs$KEYFORMAT : 'identity';
3312    if (decrypturi && keyAttrs.IV && !decryptiv) {
3313      logger.error("Invalid IV: " + keyAttrs.IV);
3314    }
3315    // If decrypturi is a URI with a scheme, then baseurl will be ignored
3316    // No uri is allowed when METHOD is NONE
3317    var resolvedUri = decrypturi ? M3U8Parser.resolve(decrypturi, baseurl) : '';
3318    var keyFormatVersions = (decryptkeyformatversions ? decryptkeyformatversions : '1').split('/').map(Number).filter(Number.isFinite);
3319    return new LevelKey(decryptmethod, resolvedUri, decryptkeyformat, keyFormatVersions, decryptiv);
3320  }
3321  function parseStartTimeOffset(startAttributes) {
3322    var startAttrs = new AttrList(startAttributes);
3323    var startTimeOffset = startAttrs.decimalFloatingPoint('TIME-OFFSET');
3324    if (isFiniteNumber(startTimeOffset)) {
3325      return startTimeOffset;
3326    }
3327    return null;
3328  }
3329  function setCodecs(codecsAttributeValue, level) {
3330    var codecs = (codecsAttributeValue || '').split(/[ ,]+/).filter(function (c) {
3331      return c;
3332    });
3333    ['video', 'audio', 'text'].forEach(function (type) {
3334      var filtered = codecs.filter(function (codec) {
3335        return isCodecType(codec, type);
3336      });
3337      if (filtered.length) {
3338        // Comma separated list of all codecs for type
3339        level[type + "Codec"] = filtered.join(',');
3340        // Remove known codecs so that only unknownCodecs are left after iterating through each type
3341        codecs = codecs.filter(function (codec) {
3342          return filtered.indexOf(codec) === -1;
3343        });
3344      }
3345    });
3346    level.unknownCodecs = codecs;
3347  }
3348  function assignCodec(media, groupItem, codecProperty) {
3349    var codecValue = groupItem[codecProperty];
3350    if (codecValue) {
3351      media[codecProperty] = codecValue;
3352    }
3353  }
3354  function backfillProgramDateTimes(fragments, firstPdtIndex) {
3355    var fragPrev = fragments[firstPdtIndex];
3356    for (var i = firstPdtIndex; i--;) {
3357      var frag = fragments[i];
3358      // Exit on delta-playlist skipped segments
3359      if (!frag) {
3360        return;
3361      }
3362      frag.programDateTime = fragPrev.programDateTime - frag.duration * 1000;
3363      fragPrev = frag;
3364    }
3365  }
3366  function assignProgramDateTime(frag, prevFrag, programDateTimes) {
3367    if (frag.rawProgramDateTime) {
3368      frag.programDateTime = Date.parse(frag.rawProgramDateTime);
3369      if (!isFiniteNumber(frag.programDateTime)) {
3370        frag.programDateTime = null;
3371        frag.rawProgramDateTime = null;
3372        return;
3373      }
3374      programDateTimes.push(frag);
3375    } else if (prevFrag != null && prevFrag.programDateTime) {
3376      frag.programDateTime = prevFrag.endProgramDateTime;
3377    }
3378  }
3379  function setInitSegment(frag, mapAttrs, id, levelkeys) {
3380    frag.relurl = mapAttrs.URI;
3381    if (mapAttrs.BYTERANGE) {
3382      frag.setByteRange(mapAttrs.BYTERANGE);
3383    }
3384    frag.level = id;
3385    frag.sn = 'initSegment';
3386    if (levelkeys) {
3387      frag.levelkeys = levelkeys;
3388    }
3389    frag.initSegment = null;
3390  }
3391  function setFragLevelKeys(frag, levelkeys, level) {
3392    frag.levelkeys = levelkeys;
3393    var encryptedFragments = level.encryptedFragments;
3394    if ((!encryptedFragments.length || encryptedFragments[encryptedFragments.length - 1].levelkeys !== levelkeys) && Object.keys(levelkeys).some(function (format) {
3395      return levelkeys[format].isCommonEncryption;
3396    })) {
3397      encryptedFragments.push(frag);
3398    }
3399  }
3400
3401  var PlaylistContextType = {
3402    MANIFEST: "manifest",
3403    LEVEL: "level",
3404    AUDIO_TRACK: "audioTrack",
3405    SUBTITLE_TRACK: "subtitleTrack"
3406  };
3407  var PlaylistLevelType = {
3408    MAIN: "main",
3409    AUDIO: "audio",
3410    SUBTITLE: "subtitle"
3411  };
3412
3413  function mapContextToLevelType(context) {
3414    var type = context.type;
3415    switch (type) {
3416      case PlaylistContextType.AUDIO_TRACK:
3417        return PlaylistLevelType.AUDIO;
3418      case PlaylistContextType.SUBTITLE_TRACK:
3419        return PlaylistLevelType.SUBTITLE;
3420      default:
3421        return PlaylistLevelType.MAIN;
3422    }
3423  }
3424  function getResponseUrl(response, context) {
3425    var url = response.url;
3426    // responseURL not supported on some browsers (it is used to detect URL redirection)
3427    // data-uri mode also not supported (but no need to detect redirection)
3428    if (url === undefined || url.indexOf('data:') === 0) {
3429      // fallback to initial URL
3430      url = context.url;
3431    }
3432    return url;
3433  }
3434  var PlaylistLoader = /*#__PURE__*/function () {
3435    function PlaylistLoader(hls) {
3436      this.hls = void 0;
3437      this.loaders = Object.create(null);
3438      this.variableList = null;
3439      this.hls = hls;
3440      this.registerListeners();
3441    }
3442    var _proto = PlaylistLoader.prototype;
3443    _proto.startLoad = function startLoad(startPosition) {};
3444    _proto.stopLoad = function stopLoad() {
3445      this.destroyInternalLoaders();
3446    };
3447    _proto.registerListeners = function registerListeners() {
3448      var hls = this.hls;
3449      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
3450      hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
3451      hls.on(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
3452      hls.on(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
3453    };
3454    _proto.unregisterListeners = function unregisterListeners() {
3455      var hls = this.hls;
3456      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
3457      hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
3458      hls.off(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
3459      hls.off(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
3460    }
3461
3462    /**
3463     * Returns defaults or configured loader-type overloads (pLoader and loader config params)
3464     */;
3465    _proto.createInternalLoader = function createInternalLoader(context) {
3466      var config = this.hls.config;
3467      var PLoader = config.pLoader;
3468      var Loader = config.loader;
3469      var InternalLoader = PLoader || Loader;
3470      var loader = new InternalLoader(config);
3471      this.loaders[context.type] = loader;
3472      return loader;
3473    };
3474    _proto.getInternalLoader = function getInternalLoader(context) {
3475      return this.loaders[context.type];
3476    };
3477    _proto.resetInternalLoader = function resetInternalLoader(contextType) {
3478      if (this.loaders[contextType]) {
3479        delete this.loaders[contextType];
3480      }
3481    }
3482
3483    /**
3484     * Call `destroy` on all internal loader instances mapped (one per context type)
3485     */;
3486    _proto.destroyInternalLoaders = function destroyInternalLoaders() {
3487      for (var contextType in this.loaders) {
3488        var loader = this.loaders[contextType];
3489        if (loader) {
3490          loader.destroy();
3491        }
3492        this.resetInternalLoader(contextType);
3493      }
3494    };
3495    _proto.destroy = function destroy() {
3496      this.variableList = null;
3497      this.unregisterListeners();
3498      this.destroyInternalLoaders();
3499    };
3500    _proto.onManifestLoading = function onManifestLoading(event, data) {
3501      var url = data.url;
3502      this.variableList = null;
3503      this.load({
3504        id: null,
3505        level: 0,
3506        responseType: 'text',
3507        type: PlaylistContextType.MANIFEST,
3508        url: url,
3509        deliveryDirectives: null
3510      });
3511    };
3512    _proto.onLevelLoading = function onLevelLoading(event, data) {
3513      var id = data.id,
3514        level = data.level,
3515        pathwayId = data.pathwayId,
3516        url = data.url,
3517        deliveryDirectives = data.deliveryDirectives;
3518      this.load({
3519        id: id,
3520        level: level,
3521        pathwayId: pathwayId,
3522        responseType: 'text',
3523        type: PlaylistContextType.LEVEL,
3524        url: url,
3525        deliveryDirectives: deliveryDirectives
3526      });
3527    };
3528    _proto.onAudioTrackLoading = function onAudioTrackLoading(event, data) {
3529      var id = data.id,
3530        groupId = data.groupId,
3531        url = data.url,
3532        deliveryDirectives = data.deliveryDirectives;
3533      this.load({
3534        id: id,
3535        groupId: groupId,
3536        level: null,
3537        responseType: 'text',
3538        type: PlaylistContextType.AUDIO_TRACK,
3539        url: url,
3540        deliveryDirectives: deliveryDirectives
3541      });
3542    };
3543    _proto.onSubtitleTrackLoading = function onSubtitleTrackLoading(event, data) {
3544      var id = data.id,
3545        groupId = data.groupId,
3546        url = data.url,
3547        deliveryDirectives = data.deliveryDirectives;
3548      this.load({
3549        id: id,
3550        groupId: groupId,
3551        level: null,
3552        responseType: 'text',
3553        type: PlaylistContextType.SUBTITLE_TRACK,
3554        url: url,
3555        deliveryDirectives: deliveryDirectives
3556      });
3557    };
3558    _proto.load = function load(context) {
3559      var _context$deliveryDire,
3560        _this = this;
3561      var config = this.hls.config;
3562
3563      // logger.debug(`[playlist-loader]: Loading playlist of type ${context.type}, level: ${context.level}
3563, id: ${context.id}`);
3564
3565      // Check if a loader for this context already exists
3566      var loader = this.getInternalLoader(context);
3567      if (loader) {
3568        var loaderContext = loader.context;
3569        if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
3570          // same URL can't overlap
3571          this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
3572          return;
3573        }
3574        this.hls.logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
3575        loader.abort();
3576      }
3577
3578      // apply different configs for retries depending on
3579      // context (manifest, level, audio/subs playlist)
3580      var loadPolicy;
3581      if (context.type === PlaylistContextType.MANIFEST) {
3582        loadPolicy = config.manifestLoadPolicy.default;
3583      } else {
3584        loadPolicy = _extends({}, config.playlistLoadPolicy.default, {
3585          timeoutRetry: null,
3586          errorRetry: null
3587        });
3588      }
3589      loader = this.createInternalLoader(context);
3590
3591      // Override level/track timeout for LL-HLS requests
3592      // (the default of 10000ms is counter productive to blocking playlist reload requests)
3593      if (isFiniteNumber((_context$deliveryDire = context.deliveryDirectives) == null ? void 0 : _context$deliveryDire.part)) {
3594        var levelDetails;
3595        if (context.type === PlaylistContextType.LEVEL && context.level !== null) {
3596          levelDetails = this.hls.levels[context.level].details;
3597        } else if (context.type === PlaylistContextType.AUDIO_TRACK && context.id !== null) {
3598          levelDetails = this.hls.audioTracks[context.id].details;
3599        } else if (context.type === PlaylistContextType.SUBTITLE_TRACK && context.id !== null) {
3600          levelDetails = this.hls.subtitleTracks[context.id].details;
3601        }
3602        if (levelDetails) {
3603          var partTarget = levelDetails.partTarget;
3604          var targetDuration = levelDetails.targetduration;
3605          if (partTarget && targetDuration) {
3606            var maxLowLatencyPlaylistRefresh = Math.max(partTarget * 3, targetDuration * 0.8) * 1000;
3607            loadPolicy = _extends({}, loadPolicy, {
3608              maxTimeToFirstByteMs: Math.min(maxLowLatencyPlaylistRefresh, loadPolicy.maxTimeToFirstByteMs),
3609              maxLoadTimeMs: Math.min(maxLowLatencyPlaylistRefresh, loadPolicy.maxTimeToFirstByteMs)
3610            });
3611          }
3612        }
3613      }
3614      var legacyRetryCompatibility = loadPolicy.errorRetry || loadPolicy.timeoutRetry || {};
3615      var loaderConfig = {
3616        loadPolicy: loadPolicy,
3617        timeout: loadPolicy.maxLoadTimeMs,
3618        maxRetry: legacyRetryCompatibility.maxNumRetry || 0,
3619        retryDelay: legacyRetryCompatibility.retryDelayMs || 0,
3620        maxRetryDelay: legacyRetryCompatibility.maxRetryDelayMs || 0
3621      };
3622      var loaderCallbacks = {
3623        onSuccess: function onSuccess(response, stats, context, networkDetails) {
3624          var loader = _this.getInternalLoader(context);
3625          _this.resetInternalLoader(context.type);
3626          var string = response.data;
3627
3628          // Validate if it is an M3U8 at all
3629          if (string.indexOf('#EXTM3U') !== 0) {
3630            _this.handleManifestParsingError(response, context, new Error('no EXTM3U delimiter'), networkDetails || null, stats);
3631            return;
3632          }
3633          stats.parsing.start = performance.now();
3634          if (M3U8Parser.isMediaPlaylist(string)) {
3635            _this.handleTrackOrLevelPlaylist(response, stats, context, networkDetails || null, loader);
3636          } else {
3637            _this.handleMasterPlaylist(response, stats, context, networkDetails);
3638          }
3639        },
3640        onError: function onError(response, context, networkDetails, stats) {
3641          _this.handleNetworkError(context, networkDetails, false, response, stats);
3642        },
3643        onTimeout: function onTimeout(stats, context, networkDetails) {
3644          _this.handleNetworkError(context, networkDetails, true, undefined, stats);
3645        }
3646      };
3647
3648      // logger.debug(`[playlist-loader]: Calling internal loader delegate for URL: ${context.url}`);
3649
3650      loader.load(context, loaderConfig, loaderCallbacks);
3651    };
3652    _proto.handleMasterPlaylist = function handleMasterPlaylist(response, stats, context, networkDetails) {
3653      var hls = this.hls;
3654      var string = response.data;
3655      var url = getResponseUrl(response, context);
3656      var parsedResult = M3U8Parser.parseMasterPlaylist(string, url);
3657      if (parsedResult.playlistParsingError) {
3658        this.handleManifestParsingError(response, context, parsedResult.playlistParsingError, networkDetails, stats);
3659        return;
3660      }
3661      var contentSteering = parsedResult.contentSteering,
3662        levels = parsedResult.levels,
3663        sessionData = parsedResult.sessionData,
3664        sessionKeys = parsedResult.sessionKeys,
3665        startTimeOffset = parsedResult.startTimeOffset,
3666        variableList = parsedResult.variableList;
3667      this.variableList = variableList;
3668      var _M3U8Parser$parseMast = M3U8Parser.parseMasterPlaylistMedia(string, url, parsedResult),
3669        _M3U8Parser$parseMast2 = _M3U8Parser$parseMast.AUDIO,
3670        audioTracks = _M3U8Parser$parseMast2 === void 0 ? [] : _M3U8Parser$parseMast2,
3671        subtitles = _M3U8Parser$parseMast.SUBTITLES,
3672        captions = _M3U8Parser$parseMast['CLOSED-CAPTIONS'];
3673      if (audioTracks.length) {
3674        // check if we have found an audio track embedded in main playlist (audio track without URI attribute)
3675        var embeddedAudioFound = audioTracks.some(function (audioTrack) {
3676          return !audioTrack.url;
3677        });
3678
3679        // if no embedded audio track defined, but audio codec signaled in quality level,
3680        // we need to signal this main audio track this could happen with playlists with
3681        // alt audio rendition in which quality levels (main)
3682        // contains both audio+video. but with mixed audio track not signaled
3683        if (!embeddedAudioFound && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
3684          this.hls.logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
3685          audioTracks.unshift({
3686            type: 'main',
3687            name: 'main',
3688            groupId: 'main',
3689            default: false,
3690            autoselect: false,
3691            forced: false,
3692            id: -1,
3693            attrs: new AttrList({}),
3694            bitrate: 0,
3695            url: ''
3696          });
3697        }
3698      }
3699      hls.trigger(Events.MANIFEST_LOADED, {
3700        levels: levels,
3701        audioTracks: audioTracks,
3702        subtitles: subtitles,
3703        captions: captions,
3704        contentSteering: contentSteering,
3705        url: url,
3706        stats: stats,
3707        networkDetails: networkDetails,
3708        sessionData: sessionData,
3709        sessionKeys: sessionKeys,
3710        startTimeOffset: startTimeOffset,
3711        variableList: variableList
3712      });
3713    };
3714    _proto.handleTrackOrLevelPlaylist = function handleTrackOrLevelPlaylist(response, stats, context, networkDetails, loader) {
3715      var hls = this.hls;
vendor: 4,236 bytes, lines 3716-3820
3716      var id = context.id,
3717        level = context.level,
3718        type = context.type;
3719      var url = getResponseUrl(response, context);
3720      var levelId = isFiniteNumber(level) ? level : isFiniteNumber(id) ? id : 0;
3721      var levelType = mapContextToLevelType(context);
3722      var levelDetails = M3U8Parser.parseLevelPlaylist(response.data, url, levelId, levelType, 0, this.variableList);
3723
3724      // We have done our first request (Manifest-type) and receive
3725      // not a master playlist but a chunk-list (track/level)
3726      // We fire the manifest-loaded event anyway with the parsed level-details
3727      // by creating a single-level structure for it.
3728      if (type === PlaylistContextType.MANIFEST) {
3729        var singleLevel = {
3730          attrs: new AttrList({}),
3731          bitrate: 0,
3732          details: levelDetails,
3733          name: '',
3734          url: url
3735        };
3736        hls.trigger(Events.MANIFEST_LOADED, {
3737          levels: [singleLevel],
3738          audioTracks: [],
3739          url: url,
3740          stats: stats,
3741          networkDetails: networkDetails,
3742          sessionData: null,
3743          sessionKeys: null,
3744          contentSteering: null,
3745          startTimeOffset: null,
3746          variableList: null
3747        });
3748      }
3749
3750      // save parsing time
3751      stats.parsing.end = performance.now();
3752
3753      // extend the context with the new levelDetails property
3754      context.levelDetails = levelDetails;
3755      this.handlePlaylistLoaded(levelDetails, response, stats, context, networkDetails, loader);
3756    };
3757    _proto.handleManifestParsingError = function handleManifestParsingError(response, context, error, networkDetails, stats) {
3758      this.hls.trigger(Events.ERROR, {
3759        type: ErrorTypes.NETWORK_ERROR,
3760        details: ErrorDetails.MANIFEST_PARSING_ERROR,
3761        fatal: context.type === PlaylistContextType.MANIFEST,
3762        url: response.url,
3763        err: error,
3764        error: error,
3765        reason: error.message,
3766        response: response,
3767        context: context,
3768        networkDetails: networkDetails,
3769        stats: stats
3770      });
3771    };
3772    _proto.handleNetworkError = function handleNetworkError(context, networkDetails, timeout, response, stats) {
3773      if (timeout === void 0) {
3774        timeout = false;
3775      }
3776      var message = "A network " + (timeout ? 'timeout' : 'error' + (response ? ' (status ' + response.code + ')' : '')) + " occurred while loading " + context.type;
3777      if (context.type === PlaylistContextType.LEVEL) {
3778        message += ": " + context.level + " id: " + context.id;
3779      } else if (context.type === PlaylistContextType.AUDIO_TRACK || context.type === PlaylistContextType.SUBTITLE_TRACK) {
3780        message += " id: " + context.id + " group-id: \"" + context.groupId + "\"";
3781      }
3782      var error = new Error(message);
3783      this.hls.logger.warn("[playlist-loader]: " + message);
3784      var details = ErrorDetails.UNKNOWN;
3785      var fatal = false;
3786      var loader = this.getInternalLoader(context);
3787      switch (context.type) {
3788        case PlaylistContextType.MANIFEST:
3789          details = timeout ? ErrorDetails.MANIFEST_LOAD_TIMEOUT : ErrorDetails.MANIFEST_LOAD_ERROR;
3790          fatal = true;
3791          break;
3792        case PlaylistContextType.LEVEL:
3793          details = timeout ? ErrorDetails.LEVEL_LOAD_TIMEOUT : ErrorDetails.LEVEL_LOAD_ERROR;
3794          fatal = false;
3795          break;
3796        case PlaylistContextType.AUDIO_TRACK:
3797          details = timeout ? ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT : ErrorDetails.AUDIO_TRACK_LOAD_ERROR;
3798          fatal = false;
3799          break;
3800        case PlaylistContextType.SUBTITLE_TRACK:
3801          details = timeout ? ErrorDetails.SUBTITLE_TRACK_LOAD_TIMEOUT : ErrorDetails.SUBTITLE_LOAD_ERROR;
3802          fatal = false;
3803          break;
3804      }
3805      if (loader) {
3806        this.resetInternalLoader(context.type);
3807      }
3808      var errorData = {
3809        type: ErrorTypes.NETWORK_ERROR,
3810        details: details,
3811        fatal: fatal,
3812        url: context.url,
3813        loader: loader,
3814        context: context,
3815        error: error,
3816        networkDetails: networkDetails,
3817        stats: stats
3818      };
3819      if (response) {
3820        var url = (networkDetails == null ? void 0 : networkDetails.url) || context.url;
3821        errorData.response = _objectSpread2({
3822          url: url,
3823          data: undefined
3824        }, response);
3825      }
3826      this.hls.trigger(Events.ERROR, errorData);
3827    };
3828    _proto.handlePlaylistLoaded = function handlePlaylistLoaded(levelDetails, response, stats, context, networkDetails, loader) {
3829      var hls = this.hls;
3830      var type = context.type,
3831        level = context.level,
3832        id = context.id,
3833        groupId = context.groupId,
3834        deliveryDirectives = context.deliveryDirectives;
3835      var url = getResponseUrl(response, context);
3836      var parent = mapContextToLevelType(context);
3837      var levelIndex = typeof context.level === 'number' && parent === PlaylistLevelType.MAIN ? level : undefined;
3838      if (!levelDetails.fragments.length) {
3839        var _error = new Error('No Segments found in Playlist');
3840        hls.trigger(Events.ERROR, {
3841          type: ErrorTypes.NETWORK_ERROR,
3842          details: ErrorDetails.LEVEL_EMPTY_ERROR,
3843          fatal: false,
3844          url: url,
3845          error: _error,
3846          reason: _error.message,
3847          response: response,
3848          context: context,
3849          level: levelIndex,
3850          parent: parent,
3851          networkDetails: networkDetails,
3852          stats: stats
3853        });
3854        return;
3855      }
3856      if (!levelDetails.targetduration) {
3857        levelDetails.playlistParsingError = new Error('Missing Target Duration');
3858      }
3859      var error = levelDetails.playlistParsingError;
3860      if (error) {
3861        hls.trigger(Events.ERROR, {
3862          type: ErrorTypes.NETWORK_ERROR,
3863          details: ErrorDetails.LEVEL_PARSING_ERROR,
3864          fatal: false,
3865          url: url,
3866          error: error,
3867          reason: error.message,
3868          response: response,
3869          context: context,
3870          level: levelIndex,
3871          parent: parent,
3872          networkDetails: networkDetails,
3873          stats: stats
3874        });
3875        return;
3876      }
3877      if (levelDetails.live && loader) {
3878        if (loader.getCacheAge) {
3879          levelDetails.ageHeader = loader.getCacheAge() || 0;
3880        }
3881        if (!loader.getCacheAge || isNaN(levelDetails.ageHeader)) {
3882          levelDetails.ageHeader = 0;
3883        }
3884      }
3885      switch (type) {
3886        case PlaylistContextType.MANIFEST:
3887        case PlaylistContextType.LEVEL:
3888          hls.trigger(Events.LEVEL_LOADED, {
3889            details: levelDetails,
3890            level: levelIndex || 0,
3891            id: id || 0,
3892            stats: stats,
3893            networkDetails: networkDetails,
3894            deliveryDirectives: deliveryDirectives
3895          });
3896          break;
3897        case PlaylistContextType.AUDIO_TRACK:
3898          hls.trigger(Events.AUDIO_TRACK_LOADED, {
3899            details: levelDetails,
3900            id: id || 0,
3901            groupId: groupId || '',
3902            stats: stats,
3903            networkDetails: networkDetails,
3904            deliveryDirectives: deliveryDirectives
3905          });
3906          break;
3907        case PlaylistContextType.SUBTITLE_TRACK:
3908          hls.trigger(Events.SUBTITLE_TRACK_LOADED, {
3909            details: levelDetails,
3910            id: id || 0,
3911            groupId: groupId || '',
3912            stats: stats,
3913            networkDetails: networkDetails,
3914            deliveryDirectives: deliveryDirectives
3915          });
3916          break;
3917      }
3918    };
3919    return PlaylistLoader;
3920  }();
3921
3922  function sendAddTrackEvent(track, videoEl) {
3923    var event;
3924    try {
3925      event = new Event('addtrack');
3926    } catch (err) {
3927      // for IE11
3928      event = document.createEvent('Event');
3929      event.initEvent('addtrack', false, false);
3930    }
3931    event.track = track;
3932    videoEl.dispatchEvent(event);
3933  }
3934  function clearCurrentCues(track) {
3935    // When track.mode is disabled, track.cues will be null.
3936    // To guarantee the removal of cues, we need to temporarily
3937    // change the mode to hidden
3938    var mode = track.mode;
3939    if (mode === 'disabled') {
3940      track.mode = 'hidden';
3941    }
3942    if (track.cues) {
3943      for (var i = track.cues.length; i--;) {
3944        track.removeCue(track.cues[i]);
3945      }
3946    }
3947    if (mode === 'disabled') {
3948      track.mode = mode;
3949    }
3950  }
3951  function removeCuesInRange(track, start, end, predicate) {
3952    var mode = track.mode;
3953    if (mode === 'disabled') {
3954      track.mode = 'hidden';
3955    }
3956    if (track.cues && track.cues.length > 0) {
3957      var cues = getCuesInRange(track.cues, start, end);
3958      for (var i = 0; i < cues.length; i++) {
3959        if (!predicate || predicate(cues[i])) {
3960          track.removeCue(cues[i]);
3961        }
3962      }
3963    }
3964    if (mode === 'disabled') {
3965      track.mode = mode;
3966    }
3967  }
3968
3969  // Find first cue starting after given time.
3970  // Modified version of binary search O(log(n)).
3971  function getFirstCueIndexAfterTime(cues, time) {
3972    // If first cue starts after time, start there
3973    if (time < cues[0].startTime) {
3974      return 0;
3975    }
3976    // If the last cue ends before time there is no overlap
3977    var len = cues.length - 1;
3978    if (time > cues[len].endTime) {
3979      return -1;
3980    }
3981    var left = 0;
3982    var right = len;
3983    while (left <= right) {
3984      var mid = Math.floor((right + left) / 2);
3985      if (time < cues[mid].startTime) {
3986        right = mid - 1;
3987      } else if (time > cues[mid].startTime && left < len) {
3988        left = mid + 1;
3989      } else {
3990        // If it's not lower or higher, it must be equal.
3991        return mid;
3992      }
3993    }
3994    // At this point, left and right have swapped.
3995    // No direct match was found, left or right element must be the closest. Check which one has the smallest diff.
3996    return cues[left].startTime - time < time - cues[right].startTime ? left : right;
3997  }
3998  function getCuesInRange(cues, start, end) {
3999    var cuesFound = [];
4000    var firstCueInRange = getFirstCueIndexAfterTime(cues, start);
4001    if (firstCueInRange > -1) {
4002      for (var i = firstCueInRange, len = cues.length; i < len; i++) {
4003        var cue = cues[i];
4004        if (cue.startTime >= start && cue.endTime <= end) {
4005          cuesFound.push(cue);
4006        } else if (cue.startTime > end) {
4007          return cuesFound;
4008        }
4009      }
4010    }
4011    return cuesFound;
4012  }
4013
4014  var MetadataSchema = {
4015    audioId3: "org.id3",
4016    dateRange: "com.apple.quicktime.HLS",
4017    emsg: "https://aomedia.org/emsg/ID3"
4018  };
4019
4020  /**
4021   * Decode an ID3 PRIV frame.
4022   *
4023   * @param frame - the ID3 PRIV frame
4024   *
4025   * @returns The decoded ID3 PRIV frame
4026   *
4027   * @internal
4028   *
4029   * @group ID3
4030   */
4031  function decodeId3PrivFrame(frame) {
4032    /*
4033    Format: <text string>\0<binary data>
4034    */
vendor: 12,153 bytes, lines 4035-4478
4035    if (frame.size < 2) {
4036      return undefined;
4037    }
4038    var owner = utf8ArrayToStr(frame.data, true);
4039    var privateData = new Uint8Array(frame.data.subarray(owner.length + 1));
4040    return {
4041      key: frame.type,
4042      info: owner,
4043      data: privateData.buffer
4044    };
4045  }
4046
4047  /**
4048   * Decodes an ID3 text frame
4049   *
4050   * @param frame - the ID3 text frame
4051   *
4052   * @returns The decoded ID3 text frame
4053   *
4054   * @internal
4055   *
4056   * @group ID3
4057   */
4058  function decodeId3TextFrame(frame) {
4059    if (frame.size < 2) {
4060      return undefined;
4061    }
4062    if (frame.type === 'TXXX') {
4063      /*
4064      Format:
4065      [0]   = {Text Encoding}
4066      [1-?] = {Description}\0{Value}
4067      */
4068      var index = 1;
4069      var description = utf8ArrayToStr(frame.data.subarray(index), true);
4070      index += description.length + 1;
4071      var value = utf8ArrayToStr(frame.data.subarray(index));
4072      return {
4073        key: frame.type,
4074        info: description,
4075        data: value
4076      };
4077    }
4078    /*
4079    Format:
4080    [0]   = {Text Encoding}
4081    [1-?] = {Value}
4082    */
4083    var text = utf8ArrayToStr(frame.data.subarray(1));
4084    return {
4085      key: frame.type,
4086      info: '',
4087      data: text
4088    };
4089  }
4090
4091  /**
4092   * Decode a URL frame
4093   *
4094   * @param frame - the ID3 URL frame
4095   *
4096   * @returns The decoded ID3 URL frame
4097   *
4098   * @internal
4099   *
4100   * @group ID3
4101   */
4102  function decodeId3UrlFrame(frame) {
4103    if (frame.type === 'WXXX') {
4104      /*
4105      Format:
4106      [0]   = {Text Encoding}
4107      [1-?] = {Description}\0{URL}
4108      */
4109      if (frame.size < 2) {
4110        return undefined;
4111      }
4112      var index = 1;
4113      var description = utf8ArrayToStr(frame.data.subarray(index), true);
4114      index += description.length + 1;
4115      var value = utf8ArrayToStr(frame.data.subarray(index));
4116      return {
4117        key: frame.type,
4118        info: description,
4119        data: value
4120      };
4121    }
4122    /*
4123    Format:
4124    [0-?] = {URL}
4125    */
4126    var url = utf8ArrayToStr(frame.data);
4127    return {
4128      key: frame.type,
4129      info: '',
4130      data: url
4131    };
4132  }
4133
4134  function toUint8(data, offset, length) {
4135    if (offset === void 0) {
4136      offset = 0;
4137    }
4138    if (length === void 0) {
4139      length = Infinity;
4140    }
4141    return view(data, offset, length, Uint8Array);
4142  }
4143  function view(data, offset, length, Type) {
4144    var buffer = unsafeGetArrayBuffer(data);
4145    var bytesPerElement = 1;
4146    if ('BYTES_PER_ELEMENT' in Type) {
4147      bytesPerElement = Type.BYTES_PER_ELEMENT;
4148    }
4149    // Absolute end of the |data| view within |buffer|.
4150    var dataOffset = isArrayBufferView(data) ? data.byteOffset : 0;
4151    var dataEnd = (dataOffset + data.byteLength) / bytesPerElement;
4152    // Absolute start of the result within |buffer|.
4153    var rawStart = (dataOffset + offset) / bytesPerElement;
4154    var start = Math.floor(Math.max(0, Math.min(rawStart, dataEnd)));
4155    // Absolute end of the result within |buffer|.
4156    var end = Math.floor(Math.min(start + Math.max(length, 0), dataEnd));
4157    return new Type(buffer, start, end - start);
4158  }
4159  function unsafeGetArrayBuffer(view) {
4160    if (view instanceof ArrayBuffer) {
4161      return view;
4162    } else {
4163      return view.buffer;
4164    }
4165  }
4166  function isArrayBufferView(obj) {
4167    return obj && obj.buffer instanceof ArrayBuffer && obj.byteLength !== undefined && obj.byteOffset !== undefined;
4168  }
4169
4170  function toArrayBuffer(view) {
4171    if (view instanceof ArrayBuffer) {
4172      return view;
4173    } else {
4174      if (view.byteOffset == 0 && view.byteLength == view.buffer.byteLength) {
4175        // This is a TypedArray over the whole buffer.
4176        return view.buffer;
4177      }
4178      // This is a 'view' on the buffer.  Create a new buffer that only contains
4179      // the data.  Note that since this isn't an ArrayBuffer, the 'new' call
4180      // will allocate a new buffer to hold the copy.
4181      return new Uint8Array(view).buffer;
4182    }
4183  }
4184
4185  function decodeId3ImageFrame(frame) {
4186    var metadataFrame = {
4187      key: frame.type,
4188      description: '',
4189      data: '',
4190      mimeType: null,
4191      pictureType: null
4192    };
4193    var utf8Encoding = 0x03;
4194    if (frame.size < 2) {
4195      return undefined;
4196    }
4197    if (frame.data[0] !== utf8Encoding) {
4198      console.log('Ignore frame with unrecognized character ' + 'encoding');
4199      return undefined;
4200    }
4201    var mimeTypeEndIndex = frame.data.subarray(1).indexOf(0);
4202    if (mimeTypeEndIndex === -1) {
4203      return undefined;
4204    }
4205    var mimeType = utf8ArrayToStr(toUint8(frame.data, 1, mimeTypeEndIndex));
4206    var pictureType = frame.data[2 + mimeTypeEndIndex];
4207    var descriptionEndIndex = frame.data.subarray(3 + mimeTypeEndIndex).indexOf(0);
4208    if (descriptionEndIndex === -1) {
4209      return undefined;
4210    }
4211    var description = utf8ArrayToStr(toUint8(frame.data, 3 + mimeTypeEndIndex, descriptionEndIndex));
4212    var data;
4213    if (mimeType === '-->') {
4214      data = utf8ArrayToStr(toUint8(frame.data, 4 + mimeTypeEndIndex + descriptionEndIndex));
4215    } else {
4216      data = toArrayBuffer(frame.data.subarray(4 + mimeTypeEndIndex + descriptionEndIndex));
4217    }
4218    metadataFrame.mimeType = mimeType;
4219    metadataFrame.pictureType = pictureType;
4220    metadataFrame.description = description;
4221    metadataFrame.data = data;
4222    return metadataFrame;
4223  }
4224
4225  /**
4226   * Decode an ID3 frame.
4227   *
4228   * @param frame - the ID3 frame
4229   *
4230   * @returns The decoded ID3 frame
4231   *
4232   * @internal
4233   *
4234   * @group ID3
4235   */
4236  function decodeId3Frame(frame) {
4237    if (frame.type === 'PRIV') {
4238      return decodeId3PrivFrame(frame);
4239    } else if (frame.type[0] === 'W') {
4240      return decodeId3UrlFrame(frame);
4241    } else if (frame.type === 'APIC') {
4242      return decodeId3ImageFrame(frame);
4243    }
4244    return decodeId3TextFrame(frame);
4245  }
4246
4247  /**
4248   * Read ID3 size
4249   *
4250   * @param data - The data to read from
4251   * @param offset - The offset at which to start reading
4252   *
4253   * @returns The size
4254   *
4255   * @internal
4256   *
4257   * @group ID3
4258   */
4259  function readId3Size(data, offset) {
4260    var size = 0;
4261    size = (data[offset] & 0x7f) << 21;
4262    size |= (data[offset + 1] & 0x7f) << 14;
4263    size |= (data[offset + 2] & 0x7f) << 7;
4264    size |= data[offset + 3] & 0x7f;
4265    return size;
4266  }
4267
4268  /**
4269   * Returns the data of an ID3 frame.
4270   *
4271   * @param data - The data to read from
4272   *
4273   * @returns The data of the ID3 frame
4274   *
4275   * @internal
4276   *
4277   * @group ID3
4278   */
4279  function getId3FrameData(data) {
4280    /*
4281    Frame ID       $xx xx xx xx (four characters)
4282    Size           $xx xx xx xx
4283    Flags          $xx xx
4284    */
4285    var type = String.fromCharCode(data[0], data[1], data[2], data[3]);
4286    var size = readId3Size(data, 4);
4287    // skip frame id, size, and flags
4288    var offset = 10;
4289    return {
4290      type: type,
4291      size: size,
4292      data: data.subarray(offset, offset + size)
4293    };
4294  }
4295
4296  /**
4297   * Returns true if an ID3 footer can be found at offset in data
4298   *
4299   * @param data - The data to search in
4300   * @param offset - The offset at which to start searching
4301   *
4302   * @returns `true` if an ID3 footer is found
4303   *
4304   * @internal
4305   *
4306   * @group ID3
4307   */
4308  function isId3Footer(data, offset) {
4309    /*
4310     * The footer is a copy of the header, but with a different identifier
4311     */
4312    if (offset + 10 <= data.length) {
4313      // look for '3DI' identifier
4314      if (data[offset] === 0x33 && data[offset + 1] === 0x44 && data[offset + 2] === 0x49) {
4315        // check version is within range
4316        if (data[offset + 3] < 0xff && data[offset + 4] < 0xff) {
4317          // check size is within range
4318          if (data[offset + 6] < 0x80 && data[offset + 7] < 0x80 && data[offset + 8] < 0x80 && data[offset + 9] < 0x80) {
4319            return true;
4320          }
4321        }
4322      }
4323    }
4324    return false;
4325  }
4326
4327  /**
4328   * Returns true if an ID3 header can be found at offset in data
4329   *
4330   * @param data - The data to search in
4331   * @param offset - The offset at which to start searching
4332   *
4333   * @returns `true` if an ID3 header is found
4334   *
4335   * @internal
4336   *
4337   * @group ID3
4338   */
4339  function isId3Header(data, offset) {
4340    /*
4341     * http://id3.org/id3v2.3.0
4342     * [0]     = 'I'
4343     * [1]     = 'D'
4344     * [2]     = '3'
4345     * [3,4]   = {Version}
4346     * [5]     = {Flags}
4347     * [6-9]   = {ID3 Size}
4348     *
4349     * An ID3v2 tag can be detected with the following pattern:
4350     *  $49 44 33 yy yy xx zz zz zz zz
4351     * Where yy is less than $FF, xx is the 'flags' byte and zz is less than $80
4352     */
4353    if (offset + 10 <= data.length) {
4354      // look for 'ID3' identifier
4355      if (data[offset] === 0x49 && data[offset + 1] === 0x44 && data[offset + 2] === 0x33) {
4356        // check version is within range
4357        if (data[offset + 3] < 0xff && data[offset + 4] < 0xff) {
4358          // check size is within range
4359          if (data[offset + 6] < 0x80 && data[offset + 7] < 0x80 && data[offset + 8] < 0x80 && data[offset + 9] < 0x80) {
4360            return true;
4361          }
4362        }
4363      }
4364    }
4365    return false;
4366  }
4367
4368  var HEADER_FOOTER_SIZE = 10;
4369  var FRAME_SIZE = 10;
4370  /**
4371   * Returns an array of ID3 frames found in all the ID3 tags in the id3Data
4372   *
4373   * @param id3Data - The ID3 data containing one or more ID3 tags
4374   *
4375   * @returns Array of ID3 frame objects
4376   *
4377   * @group ID3
4378   *
4379   * @beta
4380   */
4381  function getId3Frames(id3Data) {
4382    var offset = 0;
4383    var frames = [];
4384    while (isId3Header(id3Data, offset)) {
4385      var size = readId3Size(id3Data, offset + 6);
4386      if (id3Data[offset + 5] >> 6 & 1) {
4387        // skip extended header
4388        offset += HEADER_FOOTER_SIZE;
4389      }
4390      // skip past ID3 header
4391      offset += HEADER_FOOTER_SIZE;
4392      var end = offset + size;
4393      // loop through frames in the ID3 tag
4394      while (offset + FRAME_SIZE < end) {
4395        var frameData = getId3FrameData(id3Data.subarray(offset));
4396        var frame = decodeId3Frame(frameData);
4397        if (frame) {
4398          frames.push(frame);
4399        }
4400        // skip frame header and frame data
4401        offset += frameData.size + HEADER_FOOTER_SIZE;
4402      }
4403      if (isId3Footer(id3Data, offset)) {
4404        offset += HEADER_FOOTER_SIZE;
4405      }
4406    }
4407    return frames;
4408  }
4409
4410  /**
4411   * Returns true if the ID3 frame is an Elementary Stream timestamp frame
4412   *
4413   * @param frame - the ID3 frame
4414   *
4415   * @returns `true` if the ID3 frame is an Elementary Stream timestamp frame
4416   *
4417   * @internal
4418   *
4419   * @group ID3
4420   */
4421  function isId3TimestampFrame(frame) {
4422    return frame && frame.key === 'PRIV' && frame.info === 'com.apple.streaming.transportStreamTimestamp';
4423  }
4424
4425  var MIN_CUE_DURATION = 0.25;
4426  function getCueClass() {
4427    if (typeof self === 'undefined') return undefined;
4428    return self.VTTCue || self.TextTrackCue;
4429  }
4430  function createCueWithDataFields(Cue, startTime, endTime, data, type) {
4431    var cue = new Cue(startTime, endTime, '');
4432    try {
4433      cue.value = data;
4434      if (type) {
4435        cue.type = type;
4436      }
4437    } catch (e) {
4438      cue = new Cue(startTime, endTime, JSON.stringify(type ? _objectSpread2({
4439        type: type
4440      }, data) : data));
4441    }
4442    return cue;
4443  }
4444
4445  // VTTCue latest draft allows an infinite duration, fallback
4446  // to MAX_VALUE if necessary
4447  var MAX_CUE_ENDTIME = function () {
4448    var Cue = getCueClass();
4449    try {
4450      Cue && new Cue(0, Number.POSITIVE_INFINITY, '');
4451    } catch (e) {
4452      return Number.MAX_VALUE;
4453    }
4454    return Number.POSITIVE_INFINITY;
4455  }();
4456  function hexToArrayBuffer(str) {
4457    return Uint8Array.from(str.replace(/^0x/, '').replace(/([\da-fA-F]{2}) ?/g, '0x$1 ').replace(/ +$/, '').split(' ')).buffer;
4458  }
4459  var ID3TrackController = /*#__PURE__*/function () {
4460    function ID3TrackController(hls) {
4461      this.hls = void 0;
4462      this.id3Track = null;
4463      this.media = null;
4464      this.dateRangeCuesAppended = {};
4465      this.hls = hls;
4466      this._registerListeners();
4467    }
4468    var _proto = ID3TrackController.prototype;
4469    _proto.destroy = function destroy() {
4470      this._unregisterListeners();
4471      this.id3Track = null;
4472      this.media = null;
4473      this.dateRangeCuesAppended = {};
4474      // @ts-ignore
4475      this.hls = null;
4476    };
4477    _proto._registerListeners = function _registerListeners() {
4478      var hls = this.hls;
vendor: 5,855 bytes, lines 4479-4628
4479      hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
4480      hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
4481      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
4482      hls.on(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
4483      hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
4484      hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
4485      hls.on(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
4486    };
4487    _proto._unregisterListeners = function _unregisterListeners() {
4488      var hls = this.hls;
4489      hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
4490      hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
4491      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
4492      hls.off(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
4493      hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
4494      hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
4495      hls.off(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
4496    }
4497
4498    // Add ID3 metatadata text track.
4499    ;
4500    _proto.onMediaAttached = function onMediaAttached(event, data) {
4501      this.media = data.media;
4502    };
4503    _proto.onMediaDetaching = function onMediaDetaching() {
4504      if (this.id3Track) {
4505        clearCurrentCues(this.id3Track);
4506        this.id3Track = null;
4507      }
4508      this.media = null;
4509      this.dateRangeCuesAppended = {};
4510    };
4511    _proto.onManifestLoading = function onManifestLoading() {
4512      this.dateRangeCuesAppended = {};
4513    };
4514    _proto.createTrack = function createTrack(media) {
4515      var track = this.getID3Track(media.textTracks);
4516      track.mode = 'hidden';
4517      return track;
4518    };
4519    _proto.getID3Track = function getID3Track(textTracks) {
4520      if (!this.media) {
4521        return;
4522      }
4523      for (var i = 0; i < textTracks.length; i++) {
4524        var textTrack = textTracks[i];
4525        if (textTrack.kind === 'metadata' && textTrack.label === 'id3') {
4526          // send 'addtrack' when reusing the textTrack for metadata,
4527          // same as what we do for captions
4528          sendAddTrackEvent(textTrack, this.media);
4529          return textTrack;
4530        }
4531      }
4532      return this.media.addTextTrack('metadata', 'id3');
4533    };
4534    _proto.onFragParsingMetadata = function onFragParsingMetadata(event, data) {
4535      if (!this.media) {
4536        return;
4537      }
4538      var _this$hls$config = this.hls.config,
4539        enableEmsgMetadataCues = _this$hls$config.enableEmsgMetadataCues,
4540        enableID3MetadataCues = _this$hls$config.enableID3MetadataCues;
4541      if (!enableEmsgMetadataCues && !enableID3MetadataCues) {
4542        return;
4543      }
4544      var samples = data.samples;
4545
4546      // create track dynamically
4547      if (!this.id3Track) {
4548        this.id3Track = this.createTrack(this.media);
4549      }
4550      var Cue = getCueClass();
4551      if (!Cue) {
4552        return;
4553      }
4554      for (var i = 0; i < samples.length; i++) {
4555        var type = samples[i].type;
4556        if (type === MetadataSchema.emsg && !enableEmsgMetadataCues || !enableID3MetadataCues) {
4557          continue;
4558        }
4559        var frames = getId3Frames(samples[i].data);
4560        if (frames) {
4561          var startTime = samples[i].pts;
4562          var endTime = startTime + samples[i].duration;
4563          if (endTime > MAX_CUE_ENDTIME) {
4564            endTime = MAX_CUE_ENDTIME;
4565          }
4566          var timeDiff = endTime - startTime;
4567          if (timeDiff <= 0) {
4568            endTime = startTime + MIN_CUE_DURATION;
4569          }
4570          for (var j = 0; j < frames.length; j++) {
4571            var frame = frames[j];
4572            // Safari doesn't put the timestamp frame in the TextTrack
4573            if (!isId3TimestampFrame(frame)) {
4574              // add a bounds to any unbounded cues
4575              this.updateId3CueEnds(startTime, type);
4576              var cue = createCueWithDataFields(Cue, startTime, endTime, frame, type);
4577              if (cue) {
4578                this.id3Track.addCue(cue);
4579              }
4580            }
4581          }
4582        }
4583      }
4584    };
4585    _proto.updateId3CueEnds = function updateId3CueEnds(startTime, type) {
4586      var _this$id3Track;
4587      var cues = (_this$id3Track = this.id3Track) == null ? void 0 : _this$id3Track.cues;
4588      if (cues) {
4589        for (var i = cues.length; i--;) {
4590          var cue = cues[i];
4591          if (cue.type === type && cue.startTime < startTime && cue.endTime === MAX_CUE_ENDTIME) {
4592            cue.endTime = startTime;
4593          }
4594        }
4595      }
4596    };
4597    _proto.onBufferFlushing = function onBufferFlushing(event, _ref) {
4598      var startOffset = _ref.startOffset,
4599        endOffset = _ref.endOffset,
4600        type = _ref.type;
4601      var id3Track = this.id3Track,
4602        hls = this.hls;
4603      if (!hls) {
4604        return;
4605      }
4606      var _hls$config = hls.config,
4607        enableEmsgMetadataCues = _hls$config.enableEmsgMetadataCues,
4608        enableID3MetadataCues = _hls$config.enableID3MetadataCues;
4609      if (id3Track && (enableEmsgMetadataCues || enableID3MetadataCues)) {
4610        var predicate;
4611        if (type === 'audio') {
4612          predicate = function predicate(cue) {
4613            return cue.type === MetadataSchema.audioId3 && enableID3MetadataCues;
4614          };
4615        } else if (type === 'video') {
4616          predicate = function predicate(cue) {
4617            return cue.type === MetadataSchema.emsg && enableEmsgMetadataCues;
4618          };
4619        } else {
4620          predicate = function predicate(cue) {
4621            return cue.type === MetadataSchema.audioId3 && enableID3MetadataCues || cue.type === MetadataSchema.emsg && enableEmsgMetadataCues;
4622          };
4623        }
4624        removeCuesInRange(id3Track, startOffset, endOffset, predicate);
4625      }
4626    };
4627    _proto.onLevelUpdated = function onLevelUpdated(event, _ref2) {
4628      var details = _ref2.details;
4629      this.updateDateRangeCues(details, true);
4630    };
4631    _proto.onLevelPtsUpdated = function onLevelPtsUpdated(event, data) {
4632      if (Math.abs(data.drift) > 0.01) {
4633        this.updateDateRangeCues(data.details);
4634      }
4635    };
4636    _proto.updateDateRangeCues = function updateDateRangeCues(details, removeOldCues) {
4637      var _this = this;
4638      if (!this.media || !details.hasProgramDateTime || !this.hls.config.enableDateRangeMetadataCues) {
4639        return;
4640      }
4641      var dateRangeCuesAppended = this.dateRangeCuesAppended,
4642        id3Track = this.id3Track;
4643      var dateRanges = details.dateRanges;
4644      var ids = Object.keys(dateRanges);
4645      // Remove cues from track not found in details.dateRanges
4646      if (id3Track && removeOldCues) {
4647        var idsToRemove = Object.keys(dateRangeCuesAppended).filter(function (id) {
4648          return !ids.includes(id);
4649        });
4650        var _loop = function _loop() {
4651          var id = idsToRemove[i];
4652          Object.keys(dateRangeCuesAppended[id].cues).forEach(function (key) {
4653            id3Track.removeCue(dateRangeCuesAppended[id].cues[key]);
4654          });
4655          delete dateRangeCuesAppended[id];
4656        };
4657        for (var i = idsToRemove.length; i--;) {
4658          _loop();
4659        }
4660      }
4661      // Exit if the playlist does not have Date Ranges or does not have Program Date Time
4662      var lastFragment = details.fragments[details.fragments.length - 1];
4663      if (ids.length === 0 || !isFiniteNumber(lastFragment == null ? void 0 : lastFragment.programDateTime)) {
4664        return;
4665      }
4666      if (!this.id3Track) {
4667        this.id3Track = this.createTrack(this.media);
4668      }
4669      var Cue = getCueClass();
4670      var _loop2 = function _loop2() {
4671        var id = ids[_i];
4672        var dateRange = dateRanges[id];
4673        var startTime = dateRange.startTime;
4674
4675        // Process DateRanges to determine end-time (known DURATION, END-DATE, or END-ON-NEXT)
4676        var appendedDateRangeCues = dateRangeCuesAppended[id];
4677        var cues = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.cues) || {};
4678        var durationKnown = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.durationKnown) || false;
4679        var endTime = MAX_CUE_ENDTIME;
4680        var duration = dateRange.duration,
4681          endDate = dateRange.endDate;
4682        if (endDate && duration !== null) {
4683          endTime = startTime + duration;
4684          durationKnown = true;
4685        } else if (dateRange.endOnNext && !durationKnown) {
4686          var nextDateRangeWithSameClass = ids.reduce(function (candidateDateRange, id) {
4687            if (id !== dateRange.id) {
4688              var otherDateRange = dateRanges[id];
4689              if (otherDateRange.class === dateRange.class && otherDateRange.startDate > dateRange.startDate && (!candidateDateRange || dateRange.startDate < candidateDateRange.startDate)) {
4690                return otherDateRange;
4691              }
4692            }
4693            return candidateDateRange;
4694          }, null);
4695          if (nextDateRangeWithSameClass) {
4696            endTime = nextDateRangeWithSameClass.startTime;
4697            durationKnown = true;
4698          }
4699        }
4700
4701        // Create TextTrack Cues for each MetadataGroup Item (select DateRange attribute)
4702        // This is to emulate Safari HLS playback handling of DateRange tags
4703        var attributes = Object.keys(dateRange.attr);
4704        for (var j = 0; j < attributes.length; j++) {
4705          var key = attributes[j];
4706          if (!isDateRangeCueAttribute(key)) {
4707            continue;
4708          }
4709          var cue = cues[key];
4710          if (cue) {
4711            if (durationKnown && !appendedDateRangeCues.durationKnown) {
4712              cue.endTime = endTime;
4713            } else if (Math.abs(cue.startTime - startTime) > 0.01) {
4714              cue.startTime = startTime;
4715              cue.endTime = endTime;
4716            }
4717          } else if (Cue) {
4718            var data = dateRange.attr[key];
4719            if (isSCTE35Attribute(key)) {
4720              data = hexToArrayBuffer(data);
4721            }
4722            var _cue = createCueWithDataFields(Cue, startTime, endTime, {
4723              key: key,
4724              data: data
4725            }, MetadataSchema.dateRange);
4726            if (_cue) {
4727              _cue.id = id;
4728              _this.id3Track.addCue(_cue);
4729              cues[key] = _cue;
4730            }
4731          }
4732        }
4733
4734        // Keep track of processed DateRanges by ID for updating cues with new DateRange tag attributes
4735        dateRangeCuesAppended[id] = {
4736          cues: cues,
4737          dateRange: dateRange,
4738          durationKnown: durationKnown
4739        };
4740      };
4741      for (var _i = 0; _i < ids.length; _i++) {
4742        _loop2();
4743      }
4744    };
4745    return ID3TrackController;
4746  }();
4747
4748  var LatencyController = /*#__PURE__*/function () {
4749    function LatencyController(hls) {
4750      var _this = this;
4751      this.hls = void 0;
4752      this.config = void 0;
4753      this.media = null;
4754      this.levelDetails = null;
4755      this.currentTime = 0;
4756      this.stallCount = 0;
4757      this._latency = null;
4758      this._targetLatencyUpdated = false;
vendor: 12,681 bytes, lines 4759-5101
4759      this.onTimeupdate = function () {
4760        var media = _this.media,
4761          levelDetails = _this.levelDetails;
4762        if (!media || !levelDetails) {
4763          return;
4764        }
4765        _this.currentTime = media.currentTime;
4766        var latency = _this.computeLatency();
4767        if (latency === null) {
4768          return;
4769        }
4770        _this._latency = latency;
4771
4772        // Adapt playbackRate to meet target latency in low-latency mode
4773        var _this$config = _this.config,
4774          lowLatencyMode = _this$config.lowLatencyMode,
4775          maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4776        if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4777          return;
4778        }
4779        var targetLatency = _this.targetLatency;
4780        if (targetLatency === null) {
4781          return;
4782        }
4783        var distanceFromTarget = latency - targetLatency;
4784        // Only adjust playbackRate when within one target duration of targetLatency
4785        // and more than one second from under-buffering.
4786        // Playback further than one target duration from target can be considered DVR playback.
4787        var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
4788        var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4789        if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
4790          var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4791          var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
4792          media.playbackRate = Math.min(max, Math.max(1, rate));
4793        } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4794          media.playbackRate = 1;
4795        }
4796      };
4797      this.hls = hls;
4798      this.config = hls.config;
4799      this.registerListeners();
4800    }
4801    var _proto = LatencyController.prototype;
4802    _proto.destroy = function destroy() {
4803      this.unregisterListeners();
4804      this.onMediaDetaching();
4805      this.levelDetails = null;
4806      // @ts-ignore
4807      this.hls = null;
4808    };
4809    _proto.registerListeners = function registerListeners() {
4810      this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
4811      this.hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
4812      this.hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
4813      this.hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
4814      this.hls.on(Events.ERROR, this.onError, this);
4815    };
4816    _proto.unregisterListeners = function unregisterListeners() {
4817      this.hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
4818      this.hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
4819      this.hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
4820      this.hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
4821      this.hls.off(Events.ERROR, this.onError, this);
4822    };
4823    _proto.onMediaAttached = function onMediaAttached(event, data) {
4824      this.media = data.media;
4825      this.media.addEventListener('timeupdate', this.onTimeupdate);
4826    };
4827    _proto.onMediaDetaching = function onMediaDetaching() {
4828      if (this.media) {
4829        this.media.removeEventListener('timeupdate', this.onTimeupdate);
4830        this.media = null;
4831      }
4832    };
4833    _proto.onManifestLoading = function onManifestLoading() {
4834      this.levelDetails = null;
4835      this._latency = null;
4836      this.stallCount = 0;
4837    };
4838    _proto.onLevelUpdated = function onLevelUpdated(event, _ref) {
4839      var details = _ref.details;
4840      this.levelDetails = details;
4841      if (details.advanced) {
4842        this.onTimeupdate();
4843      }
4844      if (!details.live && this.media) {
4845        this.media.removeEventListener('timeupdate', this.onTimeupdate);
4846      }
4847    };
4848    _proto.onError = function onError(event, data) {
4849      var _this$levelDetails;
4850      if (data.details !== ErrorDetails.BUFFER_STALLED_ERROR) {
4851        return;
4852      }
4853      this.stallCount++;
4854      if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
4855        this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
4856      }
4857    };
4858    _proto.estimateLiveEdge = function estimateLiveEdge() {
4859      var levelDetails = this.levelDetails;
4860      if (levelDetails === null) {
4861        return null;
4862      }
4863      return levelDetails.edge + levelDetails.age;
4864    };
4865    _proto.computeLatency = function computeLatency() {
4866      var liveEdge = this.estimateLiveEdge();
4867      if (liveEdge === null) {
4868        return null;
4869      }
4870      return liveEdge - this.currentTime;
4871    };
4872    return _createClass(LatencyController, [{
4873      key: "latency",
4874      get: function get() {
4875        return this._latency || 0;
4876      }
4877    }, {
4878      key: "maxLatency",
4879      get: function get() {
4880        var config = this.config,
4881          levelDetails = this.levelDetails;
4882        if (config.liveMaxLatencyDuration !== undefined) {
4883          return config.liveMaxLatencyDuration;
4884        }
4885        return levelDetails ? config.liveMaxLatencyDurationCount * levelDetails.targetduration : 0;
4886      }
4887    }, {
4888      key: "targetLatency",
4889      get: function get() {
4890        var levelDetails = this.levelDetails;
4891        if (levelDetails === null) {
4892          return null;
4893        }
4894        var holdBack = levelDetails.holdBack,
4895          partHoldBack = levelDetails.partHoldBack,
4896          targetduration = levelDetails.targetduration;
4897        var _this$config2 = this.config,
4898          liveSyncDuration = _this$config2.liveSyncDuration,
4899          liveSyncDurationCount = _this$config2.liveSyncDurationCount,
4900          lowLatencyMode = _this$config2.lowLatencyMode;
4901        var userConfig = this.hls.userConfig;
4902        var targetLatency = lowLatencyMode ? partHoldBack || holdBack : holdBack;
4903        if (this._targetLatencyUpdated || userConfig.liveSyncDuration || userConfig.liveSyncDurationCount || targetLatency === 0) {
4904          targetLatency = liveSyncDuration !== undefined ? liveSyncDuration : liveSyncDurationCount * targetduration;
4905        }
4906        var maxLiveSyncOnStallIncrease = targetduration;
4907        return targetLatency + Math.min(this.stallCount * this.config.liveSyncOnStallIncrease, maxLiveSyncOnStallIncrease);
4908      },
4909      set: function set(latency) {
4910        this.stallCount = 0;
4911        this.config.liveSyncDuration = latency;
4912        this._targetLatencyUpdated = true;
4913      }
4914    }, {
4915      key: "liveSyncPosition",
4916      get: function get() {
4917        var liveEdge = this.estimateLiveEdge();
4918        var targetLatency = this.targetLatency;
4919        var levelDetails = this.levelDetails;
4920        if (liveEdge === null || targetLatency === null || levelDetails === null) {
4921          return null;
4922        }
4923        var edge = levelDetails.edge;
4924        var syncPosition = liveEdge - targetLatency - this.edgeStalled;
4925        var min = edge - levelDetails.totalduration;
4926        var max = edge - (this.config.lowLatencyMode && levelDetails.partTarget || levelDetails.targetduration);
4927        return Math.min(Math.max(min, syncPosition), max);
4928      }
4929    }, {
4930      key: "drift",
4931      get: function get() {
4932        var levelDetails = this.levelDetails;
4933        if (levelDetails === null) {
4934          return 1;
4935        }
4936        return levelDetails.drift;
4937      }
4938    }, {
4939      key: "edgeStalled",
4940      get: function get() {
4941        var levelDetails = this.levelDetails;
4942        if (levelDetails === null) {
4943          return 0;
4944        }
4945        var maxLevelUpdateAge = (this.config.lowLatencyMode && levelDetails.partTarget || levelDetails.targetduration) * 3;
4946        return Math.max(levelDetails.age - maxLevelUpdateAge, 0);
4947      }
4948    }, {
4949      key: "forwardBufferLength",
4950      get: function get() {
4951        var media = this.media,
4952          levelDetails = this.levelDetails;
4953        if (!media || !levelDetails) {
4954          return 0;
4955        }
4956        var bufferedRanges = media.buffered.length;
4957        return (bufferedRanges ? media.buffered.end(bufferedRanges - 1) : levelDetails.edge) - this.currentTime;
4958      }
4959    }]);
4960  }();
4961
4962  var HdcpLevels = ['NONE', 'TYPE-0', 'TYPE-1', null];
4963  function isHdcpLevel(value) {
4964    return HdcpLevels.indexOf(value) > -1;
4965  }
4966  var VideoRangeValues = ['SDR', 'PQ', 'HLG'];
4967  function isVideoRange(value) {
4968    return !!value && VideoRangeValues.indexOf(value) > -1;
4969  }
4970  var HlsSkip = {
4971    No: "",
4972    Yes: "YES",
4973    v2: "v2"
4974  };
4975  function getSkipValue(details) {
4976    var canSkipUntil = details.canSkipUntil,
4977      canSkipDateRanges = details.canSkipDateRanges,
4978      age = details.age;
4979    // A Client SHOULD NOT request a Playlist Delta Update unless it already
4980    // has a version of the Playlist that is no older than one-half of the Skip Boundary.
4981    // @see: https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.3.7
4982    var playlistRecentEnough = age < canSkipUntil / 2;
4983    if (canSkipUntil && playlistRecentEnough) {
4984      if (canSkipDateRanges) {
4985        return HlsSkip.v2;
4986      }
4987      return HlsSkip.Yes;
4988    }
4989    return HlsSkip.No;
4990  }
4991  var HlsUrlParameters = /*#__PURE__*/function () {
4992    function HlsUrlParameters(msn, part, skip) {
4993      this.msn = void 0;
4994      this.part = void 0;
4995      this.skip = void 0;
4996      this.msn = msn;
4997      this.part = part;
4998      this.skip = skip;
4999    }
5000    var _proto = HlsUrlParameters.prototype;
5001    _proto.addDirectives = function addDirectives(uri) {
5002      var url = new self.URL(uri);
5003      if (this.msn !== undefined) {
5004        url.searchParams.set('_HLS_msn', this.msn.toString());
5005      }
5006      if (this.part !== undefined) {
5007        url.searchParams.set('_HLS_part', this.part.toString());
5008      }
5009      if (this.skip) {
5010        url.searchParams.set('_HLS_skip', this.skip);
5011      }
5012      return url.href;
5013    };
5014    return HlsUrlParameters;
5015  }();
5016  var Level = /*#__PURE__*/function () {
5017    function Level(data) {
5018      this._attrs = void 0;
5019      this.audioCodec = void 0;
5020      this.bitrate = void 0;
5021      this.codecSet = void 0;
5022      this.url = void 0;
5023      this.frameRate = void 0;
5024      this.height = void 0;
5025      this.id = void 0;
5026      this.name = void 0;
5027      this.videoCodec = void 0;
5028      this.width = void 0;
5029      this.details = void 0;
5030      this.fragmentError = 0;
5031      this.loadError = 0;
5032      this.loaded = void 0;
5033      this.realBitrate = 0;
5034      this.supportedPromise = void 0;
5035      this.supportedResult = void 0;
5036      this._avgBitrate = 0;
5037      this._audioGroups = void 0;
5038      this._subtitleGroups = void 0;
5039      // Deprecated (retained for backwards compatibility)
5040      this._urlId = 0;
5041      this.url = [data.url];
5042      this._attrs = [data.attrs];
5043      this.bitrate = data.bitrate;
5044      if (data.details) {
5045        this.details = data.details;
5046      }
5047      this.id = data.id || 0;
5048      this.name = data.name;
5049      this.width = data.width || 0;
5050      this.height = data.height || 0;
5051      this.frameRate = data.attrs.optionalFloat('FRAME-RATE', 0);
5052      this._avgBitrate = data.attrs.decimalInteger('AVERAGE-BANDWIDTH');
5053      this.audioCodec = data.audioCodec;
5054      this.videoCodec = data.videoCodec;
5055      this.codecSet = [data.videoCodec, data.audioCodec].filter(function (c) {
5056        return !!c;
5057      }).map(function (s) {
5058        return s.substring(0, 4);
5059      }).join(',');
5060      this.addGroupId('audio', data.attrs.AUDIO);
5061      this.addGroupId('text', data.attrs.SUBTITLES);
5062    }
5063    var _proto2 = Level.prototype;
5064    _proto2.hasAudioGroup = function hasAudioGroup(groupId) {
5065      return hasGroup(this._audioGroups, groupId);
5066    };
5067    _proto2.hasSubtitleGroup = function hasSubtitleGroup(groupId) {
5068      return hasGroup(this._subtitleGroups, groupId);
5069    };
5070    _proto2.addGroupId = function addGroupId(type, groupId) {
5071      if (!groupId) {
5072        return;
5073      }
5074      if (type === 'audio') {
5075        var audioGroups = this._audioGroups;
5076        if (!audioGroups) {
5077          audioGroups = this._audioGroups = [];
5078        }
5079        if (audioGroups.indexOf(groupId) === -1) {
5080          audioGroups.push(groupId);
5081        }
5082      } else if (type === 'text') {
5083        var subtitleGroups = this._subtitleGroups;
5084        if (!subtitleGroups) {
5085          subtitleGroups = this._subtitleGroups = [];
5086        }
5087        if (subtitleGroups.indexOf(groupId) === -1) {
5088          subtitleGroups.push(groupId);
5089        }
5090      }
5091    }
5092
5093    // Deprecated methods (retained for backwards compatibility)
5094    ;
5095    _proto2.addFallback = function addFallback() {};
5096    return _createClass(Level, [{
5097      key: "maxBitrate",
5098      get: function get() {
5099        return Math.max(this.realBitrate, this.bitrate);
5100      }
5101    }, {
vendor: 4,142 bytes, lines 5102-5237
5102      key: "averageBitrate",
5103      get: function get() {
5104        return this._avgBitrate || this.realBitrate || this.bitrate;
5105      }
5106    }, {
5107      key: "attrs",
5108      get: function get() {
5109        return this._attrs[0];
5110      }
5111    }, {
5112      key: "codecs",
5113      get: function get() {
5114        return this.attrs.CODECS || '';
5115      }
5116    }, {
5117      key: "pathwayId",
5118      get: function get() {
5119        return this.attrs['PATHWAY-ID'] || '.';
5120      }
5121    }, {
5122      key: "videoRange",
5123      get: function get() {
5124        return this.attrs['VIDEO-RANGE'] || 'SDR';
5125      }
5126    }, {
5127      key: "score",
5128      get: function get() {
5129        return this.attrs.optionalFloat('SCORE', 0);
5130      }
5131    }, {
5132      key: "uri",
5133      get: function get() {
5134        return this.url[0] || '';
5135      }
5136    }, {
5137      key: "audioGroups",
5138      get: function get() {
5139        return this._audioGroups;
5140      }
5141    }, {
5142      key: "subtitleGroups",
5143      get: function get() {
5144        return this._subtitleGroups;
5145      }
5146    }, {
5147      key: "urlId",
5148      get: function get() {
5149        return 0;
5150      },
5151      set: function set(value) {}
5152    }, {
5153      key: "audioGroupIds",
5154      get: function get() {
5155        return this.audioGroups ? [this.audioGroupId] : undefined;
5156      }
5157    }, {
5158      key: "textGroupIds",
5159      get: function get() {
5160        return this.subtitleGroups ? [this.textGroupId] : undefined;
5161      }
5162    }, {
5163      key: "audioGroupId",
5164      get: function get() {
5165        var _this$audioGroups;
5166        return (_this$audioGroups = this.audioGroups) == null ? void 0 : _this$audioGroups[0];
5167      }
5168    }, {
5169      key: "textGroupId",
5170      get: function get() {
5171        var _this$subtitleGroups;
5172        return (_this$subtitleGroups = this.subtitleGroups) == null ? void 0 : _this$subtitleGroups[0];
5173      }
5174    }]);
5175  }();
5176  function hasGroup(groups, groupId) {
5177    if (!groupId || !groups) {
5178      return false;
5179    }
5180    return groups.indexOf(groupId) !== -1;
5181  }
5182
5183  function updateFromToPTS(fragFrom, fragTo) {
5184    var fragToPTS = fragTo.startPTS;
5185    // if we know startPTS[toIdx]
5186    if (isFiniteNumber(fragToPTS)) {
5187      // update fragment duration.
5188      // it helps to fix drifts between playlist reported duration and fragment real duration
5189      var duration = 0;
5190      var frag;
5191      if (fragTo.sn > fragFrom.sn) {
5192        duration = fragToPTS - fragFrom.start;
5193        frag = fragFrom;
5194      } else {
5195        duration = fragFrom.start - fragToPTS;
5196        frag = fragTo;
5197      }
5198      if (frag.duration !== duration) {
5199        frag.duration = duration;
5200      }
5201      // we dont know startPTS[toIdx]
5202    } else if (fragTo.sn > fragFrom.sn) {
5203      var contiguous = fragFrom.cc === fragTo.cc;
5204      // TODO: With part-loading end/durations we need to confirm the whole fragment is loaded before using (or setting) minEndPTS
5205      if (contiguous && fragFrom.minEndPTS) {
5206        fragTo.start = fragFrom.start + (fragFrom.minEndPTS - fragFrom.start);
5207      } else {
5208        fragTo.start = fragFrom.start + fragFrom.duration;
5209      }
5210    } else {
5211      fragTo.start = Math.max(fragFrom.start - fragTo.duration, 0);
5212    }
5213  }
5214  function updateFragPTSDTS(details, frag, startPTS, endPTS, startDTS, endDTS) {
5215    var parsedMediaDuration = endPTS - startPTS;
5216    if (parsedMediaDuration <= 0) {
5217      logger.warn('Fragment should have a positive duration', frag);
5218      endPTS = startPTS + frag.duration;
5219      endDTS = startDTS + frag.duration;
5220    }
5221    var maxStartPTS = startPTS;
5222    var minEndPTS = endPTS;
5223    var fragStartPts = frag.startPTS;
5224    var fragEndPts = frag.endPTS;
5225    if (isFiniteNumber(fragStartPts)) {
5226      // delta PTS between audio and video
5227      var deltaPTS = Math.abs(fragStartPts - startPTS);
5228      if (!isFiniteNumber(frag.deltaPTS)) {
5229        frag.deltaPTS = deltaPTS;
5230      } else {
5231        frag.deltaPTS = Math.max(deltaPTS, frag.deltaPTS);
5232      }
5233      maxStartPTS = Math.max(startPTS, fragStartPts);
5234      startPTS = Math.min(startPTS, fragStartPts);
5235      startDTS = Math.min(startDTS, frag.startDTS);
5236      minEndPTS = Math.min(endPTS, fragEndPts);
5237      endPTS = Math.max(endPTS, fragEndPts);
5238      endDTS = Math.max(endDTS, frag.endDTS);
5239    }
5240    var drift = startPTS - frag.start;
5241    if (frag.start !== 0) {
5242      frag.start = startPTS;
5243    }
5244    frag.duration = endPTS - frag.start;
5245    frag.startPTS = startPTS;
5246    frag.maxStartPTS = maxStartPTS;
5247    frag.startDTS = startDTS;
5248    frag.endPTS = endPTS;
5249    frag.minEndPTS = minEndPTS;
5250    frag.endDTS = endDTS;
5251    var sn = frag.sn;
5252    // exit if sn out of range
5253    if (!details || sn < details.startSN || sn > details.endSN) {
5254      return 0;
5255    }
5256    var i;
5257    var fragIdx = sn - details.startSN;
5258    var fragments = details.fragments;
5259    // update frag reference in fragments array
5260    // rationale is that fragments array might not contain this frag object.
5261    // this will happen if playlist has been refreshed between frag loading and call to updateFragPTSDTS()
5262    // if we don't update frag, we won't be able to propagate PTS info on the playlist
5263    // resulting in invalid sliding computation
5264    fragments[fragIdx] = frag;
5265    // adjust fragment PTS/duration from seqnum-1 to frag 0
5266    for (i = fragIdx; i > 0; i--) {
5267      updateFromToPTS(fragments[i], fragments[i - 1]);
5268    }
5269
5270    // adjust fragment PTS/duration from seqnum to last frag
5271    for (i = fragIdx; i < fragments.length - 1; i++) {
5272      updateFromToPTS(fragments[i], fragments[i + 1]);
5273    }
5274    if (details.fragmentHint) {
5275      updateFromToPTS(fragments[fragments.length - 1], details.fragmentHint);
5276    }
5277    details.PTSKnown = details.alignedSliding = true;
5278    return drift;
5279  }
5280  function mergeDetails(oldDetails, newDetails) {
5281    // Track the last initSegment processed. Initialize it to the last one on the timeline.
5282    var currentInitSegment = null;
5283    var oldFragments = oldDetails.fragments;
5284    for (var i = oldFragments.length - 1; i >= 0; i--) {
5285      var oldInit = oldFragments[i].initSegment;
5286      if (oldInit) {
5287        currentInitSegment = oldInit;
5288        break;
5289      }
5290    }
5291    if (oldDetails.fragmentHint) {
5292      // prevent PTS and duration from being adjusted on the next hint
5293      delete oldDetails.fragmentHint.endPTS;
5294    }
5295    // check if old/new playlists have fragments in common
5296    // loop through overlapping SN and update startPTS , cc, and duration if any found
5297    var ccOffset = 0;
5298    var PTSFrag;
5299    mapFragmentIntersection(oldDetails, newDetails, function (oldFrag, newFrag) {
5300      if (oldFrag.relurl) {
5301        // Do not compare CC if the old fragment has no url. This is a level.fragmentHint used by LL-HLS parts.
5302        // It maybe be off by 1 if it was created before any parts or discontinuity tags were appended to the end
5303        // of the playlist.
5304        ccOffset = oldFrag.cc - newFrag.cc;
5305      }
5306      if (isFiniteNumber(oldFrag.startPTS) && isFiniteNumber(oldFrag.endPTS)) {
5307        newFrag.start = newFrag.startPTS = oldFrag.startPTS;
5308        newFrag.startDTS = oldFrag.startDTS;
5309        newFrag.maxStartPTS = oldFrag.maxStartPTS;
5310        newFrag.endPTS = oldFrag.endPTS;
5311        newFrag.endDTS = oldFrag.endDTS;
5312        newFrag.minEndPTS = oldFrag.minEndPTS;
5313        newFrag.duration = oldFrag.endPTS - oldFrag.startPTS;
5314        if (newFrag.duration) {
5315          PTSFrag = newFrag;
5316        }
5317
5318        // PTS is known when any segment has startPTS and endPTS
5319        newDetails.PTSKnown = newDetails.alignedSliding = true;
5320      }
5321      newFrag.elementaryStreams = oldFrag.elementaryStreams;
5322      newFrag.loader = oldFrag.loader;
5323      newFrag.stats = oldFrag.stats;
5324      if (oldFrag.initSegment) {
5325        newFrag.initSegment = oldFrag.initSegment;
5326        currentInitSegment = oldFrag.initSegment;
5327      }
5328    });
5329    var fragmentsToCheck = newDetails.fragmentHint ? newDetails.fragments.concat(newDetails.fragmentHint) : newDetails.fragments;
5330    if (currentInitSegment) {
5331      fragmentsToCheck.forEach(function (frag) {
5332        var _currentInitSegment;
5333        if (frag && (!frag.initSegment || frag.initSegment.relurl === ((_currentInitSegment = currentInitSegment) == null ? void 0 : _currentInitSegment.relurl))) {
5334          frag.initSegment = currentInitSegment;
5335        }
5336      });
5337    }
5338    if (newDetails.skippedSegments) {
5339      newDetails.deltaUpdateFailed = newDetails.fragments.some(function (frag) {
5340        return !frag;
5341      });
5342      if (newDetails.deltaUpdateFailed) {
5343        logger.warn('[level-helper] Previous playlist missing segments ski
vendor: 9,069 bytes, lines 5343-5579
5343pped in delta playlist');
5344        for (var _i = newDetails.skippedSegments; _i--;) {
5345          newDetails.fragments.shift();
5346        }
5347        newDetails.startSN = newDetails.fragments[0].sn;
5348        newDetails.startCC = newDetails.fragments[0].cc;
5349      } else {
5350        if (newDetails.canSkipDateRanges) {
5351          newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails);
5352        }
5353        var programDateTimes = oldDetails.fragments.filter(function (frag) {
5354          return frag.rawProgramDateTime;
5355        });
5356        if (oldDetails.hasProgramDateTime && !newDetails.hasProgramDateTime) {
5357          for (var _i2 = 1; _i2 < fragmentsToCheck.length; _i2++) {
5358            if (fragmentsToCheck[_i2].programDateTime === null) {
5359              assignProgramDateTime(fragmentsToCheck[_i2], fragmentsToCheck[_i2 - 1], programDateTimes);
5360            }
5361          }
5362        }
5363        mapDateRanges(programDateTimes, newDetails);
5364      }
5365    }
5366    var newFragments = newDetails.fragments;
5367    if (ccOffset) {
5368      logger.warn('discontinuity sliding from playlist, take drift into account');
5369      for (var _i3 = 0; _i3 < newFragments.length; _i3++) {
5370        newFragments[_i3].cc += ccOffset;
5371      }
5372    }
5373    if (newDetails.skippedSegments) {
5374      newDetails.startCC = newDetails.fragments[0].cc;
5375    }
5376
5377    // Merge parts
5378    mapPartIntersection(oldDetails.partList, newDetails.partList, function (oldPart, newPart) {
5379      newPart.elementaryStreams = oldPart.elementaryStreams;
5380      newPart.stats = oldPart.stats;
5381    });
5382
5383    // if at least one fragment contains PTS info, recompute PTS information for all fragments
5384    if (PTSFrag) {
5385      updateFragPTSDTS(newDetails, PTSFrag, PTSFrag.startPTS, PTSFrag.endPTS, PTSFrag.startDTS, PTSFrag.endDTS);
5386    } else {
5387      // ensure that delta is within oldFragments range
5388      // also adjust sliding in case delta is 0 (we could have old=[50-60] and new=old=[50-61])
5389      // in that case we also need to adjust start offset of all fragments
5390      adjustSliding(oldDetails, newDetails);
5391    }
5392    if (newFragments.length) {
5393      newDetails.totalduration = newDetails.edge - newFragments[0].start;
5394    }
5395    newDetails.driftStartTime = oldDetails.driftStartTime;
5396    newDetails.driftStart = oldDetails.driftStart;
5397    var advancedDateTime = newDetails.advancedDateTime;
5398    if (newDetails.advanced && advancedDateTime) {
5399      var edge = newDetails.edge;
5400      if (!newDetails.driftStart) {
5401        newDetails.driftStartTime = advancedDateTime;
5402        newDetails.driftStart = edge;
5403      }
5404      newDetails.driftEndTime = advancedDateTime;
5405      newDetails.driftEnd = edge;
5406    } else {
5407      newDetails.driftEndTime = oldDetails.driftEndTime;
5408      newDetails.driftEnd = oldDetails.driftEnd;
5409      newDetails.advancedDateTime = oldDetails.advancedDateTime;
5410    }
5411  }
5412  function mergeDateRanges(oldDateRanges, newDetails) {
5413    var deltaDateRanges = newDetails.dateRanges,
5414      recentlyRemovedDateranges = newDetails.recentlyRemovedDateranges;
5415    var dateRanges = _extends({}, oldDateRanges);
5416    if (recentlyRemovedDateranges) {
5417      recentlyRemovedDateranges.forEach(function (id) {
5418        delete dateRanges[id];
5419      });
5420    }
5421    var mergeIds = Object.keys(dateRanges);
5422    var mergeCount = mergeIds.length;
5423    if (mergeCount) {
5424      Object.keys(deltaDateRanges).forEach(function (id) {
5425        var mergedDateRange = dateRanges[id];
5426        var dateRange = new DateRange(deltaDateRanges[id].attr, mergedDateRange);
5427        if (dateRange.isValid) {
5428          dateRanges[id] = dateRange;
5429          if (!mergedDateRange) {
5430            dateRange.tagOrder += mergeCount;
5431          }
5432        } else {
5433          logger.warn("Ignoring invalid Playlist Delta Update DATERANGE tag: \"" + JSON.stringify(deltaDateRanges[id].attr) + "\"");
5434        }
5435      });
5436    }
5437    return dateRanges;
5438  }
5439  function mapPartIntersection(oldParts, newParts, intersectionFn) {
5440    if (oldParts && newParts) {
5441      var delta = 0;
5442      for (var i = 0, len = oldParts.length; i <= len; i++) {
5443        var _oldPart = oldParts[i];
5444        var _newPart = newParts[i + delta];
5445        if (_oldPart && _newPart && _oldPart.index === _newPart.index && _oldPart.fragment.sn === _newPart.fragment.sn) {
5446          intersectionFn(_oldPart, _newPart);
5447        } else {
5448          delta--;
5449        }
5450      }
5451    }
5452  }
5453  function mapFragmentIntersection(oldDetails, newDetails, intersectionFn) {
5454    var skippedSegments = newDetails.skippedSegments;
5455    var start = Math.max(oldDetails.startSN, newDetails.startSN) - newDetails.startSN;
5456    var end = (oldDetails.fragmentHint ? 1 : 0) + (skippedSegments ? newDetails.endSN : Math.min(oldDetails.endSN, newDetails.endSN)) - newDetails.startSN;
5457    var delta = newDetails.startSN - oldDetails.startSN;
5458    var newFrags = newDetails.fragmentHint ? newDetails.fragments.concat(newDetails.fragmentHint) : newDetails.fragments;
5459    var oldFrags = oldDetails.fragmentHint ? oldDetails.fragments.concat(oldDetails.fragmentHint) : oldDetails.fragments;
5460    for (var i = start; i <= end; i++) {
5461      var _oldFrag = oldFrags[delta + i];
5462      var _newFrag = newFrags[i];
5463      if (skippedSegments && !_newFrag && _oldFrag) {
5464        // Fill in skipped segments in delta playlist
5465        _newFrag = newDetails.fragments[i] = _oldFrag;
5466      }
5467      if (_oldFrag && _newFrag) {
5468        intersectionFn(_oldFrag, _newFrag);
5469      }
5470    }
5471  }
5472  function adjustSliding(oldDetails, newDetails) {
5473    var delta = newDetails.startSN + newDetails.skippedSegments - oldDetails.startSN;
5474    var oldFragments = oldDetails.fragments;
5475    if (delta < 0 || delta >= oldFragments.length) {
5476      return;
5477    }
5478    addSliding(newDetails, oldFragments[delta].start);
5479  }
5480  function addSliding(details, start) {
5481    if (start) {
5482      var fragments = details.fragments;
5483      for (var i = details.skippedSegments; i < fragments.length; i++) {
5484        fragments[i].start += start;
5485      }
5486      if (details.fragmentHint) {
5487        details.fragmentHint.start += start;
5488      }
5489    }
5490  }
5491  function computeReloadInterval(newDetails, distanceToLiveEdgeMs) {
5492    if (distanceToLiveEdgeMs === void 0) {
5493      distanceToLiveEdgeMs = Infinity;
5494    }
5495    var reloadInterval = 1000 * newDetails.targetduration;
5496    if (newDetails.updated) {
5497      // Use last segment duration when shorter than target duration and near live edge
5498      var fragments = newDetails.fragments;
5499      var liveEdgeMaxTargetDurations = 4;
5500      if (fragments.length && reloadInterval * liveEdgeMaxTargetDurations > distanceToLiveEdgeMs) {
5501        var lastSegmentDuration = fragments[fragments.length - 1].duration * 1000;
5502        if (lastSegmentDuration < reloadInterval) {
5503          reloadInterval = lastSegmentDuration;
5504        }
5505      }
5506    } else {
5507      // estimate = 'miss half average';
5508      // follow HLS Spec, If the client reloads a Playlist file and finds that it has not
5509      // changed then it MUST wait for a period of one-half the target
5510      // duration before retrying.
5511      reloadInterval /= 2;
5512    }
5513    return Math.round(reloadInterval);
5514  }
5515  function getFragmentWithSN(details, sn, fragCurrent) {
5516    if (!details) {
5517      return null;
5518    }
5519    var fragment = details.fragments[sn - details.startSN];
5520    if (fragment) {
5521      return fragment;
5522    }
5523    fragment = details.fragmentHint;
5524    if (fragment && fragment.sn === sn) {
5525      return fragment;
5526    }
5527    if (sn < details.startSN && fragCurrent && fragCurrent.sn === sn) {
5528      return fragCurrent;
5529    }
5530    return null;
5531  }
5532  function getPartWith(details, sn, partIndex) {
5533    if (!details) {
5534      return null;
5535    }
5536    return findPart(details.partList, sn, partIndex);
5537  }
5538  function findPart(partList, sn, partIndex) {
5539    if (partList) {
5540      for (var i = partList.length; i--;) {
5541        var part = partList[i];
5542        if (part.index === partIndex && part.fragment.sn === sn) {
5543          return part;
5544        }
5545      }
5546    }
5547    return null;
5548  }
5549  function reassignFragmentLevelIndexes(levels) {
5550    levels.forEach(function (level, index) {
5551      var details = level.details;
5552      if (details != null && details.fragments) {
5553        details.fragments.forEach(function (fragment) {
5554          fragment.level = index;
5555        });
5556      }
5557    });
5558  }
5559
5560  function isTimeoutError(error) {
5561    switch (error.details) {
5562      case ErrorDetails.FRAG_LOAD_TIMEOUT:
5563      case ErrorDetails.KEY_LOAD_TIMEOUT:
5564      case ErrorDetails.LEVEL_LOAD_TIMEOUT:
5565      case ErrorDetails.MANIFEST_LOAD_TIMEOUT:
5566        return true;
5567    }
5568    return false;
5569  }
5570  function getRetryConfig(loadPolicy, error) {
5571    var isTimeout = isTimeoutError(error);
5572    return loadPolicy.default[(isTimeout ? 'timeout' : 'error') + "Retry"];
5573  }
5574  function getRetryDelay(retryConfig, retryCount) {
5575    // exponential backoff capped to max retry delay
5576    var backoffFactor = retryConfig.backoff === 'linear' ? 1 : Math.pow(2, retryCount);
5577    return Math.min(backoffFactor * retryConfig.retryDelayMs, retryConfig.maxRetryDelayMs);
5578  }
5579  function getLoaderConfigWithoutReties(loderConfig) {
vendor: 13,909 bytes, lines 5580-5895
5580    return _objectSpread2(_objectSpread2({}, loderConfig), {
5581      errorRetry: null,
5582      timeoutRetry: null
5583    });
5584  }
5585  function shouldRetry(retryConfig, retryCount, isTimeout, loaderResponse) {
5586    if (!retryConfig) {
5587      return false;
5588    }
5589    var httpStatus = loaderResponse == null ? void 0 : loaderResponse.code;
5590    var retry = retryCount < retryConfig.maxNumRetry && (retryForHttpStatus(httpStatus) || !!isTimeout);
5591    return retryConfig.shouldRetry ? retryConfig.shouldRetry(retryConfig, retryCount, isTimeout, loaderResponse, retry) : retry;
5592  }
5593  function retryForHttpStatus(httpStatus) {
5594    // Do not retry on status 4xx, status 0 (CORS error), or undefined (decrypt/gap/parse error)
5595    return httpStatus === 0 && navigator.onLine === false || !!httpStatus && (httpStatus < 400 || httpStatus > 499);
5596  }
5597
5598  var BinarySearch = {
5599    /**
5600     * Searches for an item in an array which matches a certain condition.
5601     * This requires the condition to only match one item in the array,
5602     * and for the array to be ordered.
5603     *
5604     * @param list The array to search.
5605     * @param comparisonFn
5606     *      Called and provided a candidate item as the first argument.
5607     *      Should return:
5608     *          > -1 if the item should be located at a lower index than the provided item.
5609     *          > 1 if the item should be located at a higher index than the provided item.
5610     *          > 0 if the item is the item you're looking for.
5611     *
5612     * @returns the object if found, otherwise returns null
5613     */
5614    search: function search(list, comparisonFn) {
5615      var minIndex = 0;
5616      var maxIndex = list.length - 1;
5617      var currentIndex = null;
5618      var currentElement = null;
5619      while (minIndex <= maxIndex) {
5620        currentIndex = (minIndex + maxIndex) / 2 | 0;
5621        currentElement = list[currentIndex];
5622        var comparisonResult = comparisonFn(currentElement);
5623        if (comparisonResult > 0) {
5624          minIndex = currentIndex + 1;
5625        } else if (comparisonResult < 0) {
5626          maxIndex = currentIndex - 1;
5627        } else {
5628          return currentElement;
5629        }
5630      }
5631      return null;
5632    }
5633  };
5634
5635  /**
5636   * Returns first fragment whose endPdt value exceeds the given PDT, or null.
5637   * @param fragments - The array of candidate fragments
5638   * @param PDTValue - The PDT value which must be exceeded
5639   * @param maxFragLookUpTolerance - The amount of time that a fragment's start/end can be within in order to be considered contiguous
5640   */
5641  function findFragmentByPDT(fragments, PDTValue, maxFragLookUpTolerance) {
5642    if (PDTValue === null || !Array.isArray(fragments) || !fragments.length || !isFiniteNumber(PDTValue)) {
5643      return null;
5644    }
5645
5646    // if less than start
5647    var startPDT = fragments[0].programDateTime;
5648    if (PDTValue < (startPDT || 0)) {
5649      return null;
5650    }
5651    var endPDT = fragments[fragments.length - 1].endProgramDateTime;
5652    if (PDTValue >= (endPDT || 0)) {
5653      return null;
5654    }
5655    maxFragLookUpTolerance = maxFragLookUpTolerance || 0;
5656    for (var seg = 0; seg < fragments.length; ++seg) {
5657      var frag = fragments[seg];
5658      if (pdtWithinToleranceTest(PDTValue, maxFragLookUpTolerance, frag)) {
5659        return frag;
5660      }
5661    }
5662    return null;
5663  }
5664
5665  /**
5666   * Finds a fragment based on the SN of the previous fragment; or based on the needs of the current buffer.
5667   * This method compensates for small buffer gaps by applying a tolerance to the start of any candidate fragment, thus
5668   * breaking any traps which would cause the same fragment to be continuously selected within a small range.
5669   * @param fragPrevious - The last frag successfully appended
5670   * @param fragments - The array of candidate fragments
5671   * @param bufferEnd - The end of the contiguous buffered range the playhead is currently within
5672   * @param maxFragLookUpTolerance - The amount of time that a fragment's start/end can be within in order to be considered contiguous
5673   * @returns a matching fragment or null
5674   */
5675  function findFragmentByPTS(fragPrevious, fragments, bufferEnd, maxFragLookUpTolerance, nextFragLookupTolerance) {
5676    if (bufferEnd === void 0) {
5677      bufferEnd = 0;
5678    }
5679    if (maxFragLookUpTolerance === void 0) {
5680      maxFragLookUpTolerance = 0;
5681    }
5682    if (nextFragLookupTolerance === void 0) {
5683      nextFragLookupTolerance = 0.005;
5684    }
5685    var fragNext = null;
5686    if (fragPrevious) {
5687      fragNext = fragments[1 + fragPrevious.sn - fragments[0].sn] || null;
5688      // check for buffer-end rounding error
5689      var bufferEdgeError = fragPrevious.endDTS - bufferEnd;
5690      if (bufferEdgeError > 0 && bufferEdgeError < 0.0000015) {
5691        bufferEnd += 0.0000015;
5692      }
5693      if (fragNext && fragPrevious.level !== fragNext.level && fragNext.end <= fragPrevious.end) {
5694        fragNext = fragments[2 + fragPrevious.sn - fragments[0].sn] || null;
5695      }
5696    } else if (bufferEnd === 0 && fragments[0].start === 0) {
5697      fragNext = fragments[0];
5698    }
5699    // Prefer the next fragment if it's within tolerance
5700    if (fragNext && ((!fragPrevious || fragPrevious.level === fragNext.level) && fragmentWithinToleranceTest(bufferEnd, maxFragLookUpTolerance, fragNext) === 0 || fragmentWithinFastStartSwitch(fragNext, fragPrevious, Math.min(nextFragLookupTolerance, maxFragLookUpTolerance)))) {
5701      return fragNext;
5702    }
5703    // We might be seeking past the tolerance so find the best match
5704    var foundFragment = BinarySearch.search(fragments, fragmentWithinToleranceTest.bind(null, bufferEnd, maxFragLookUpTolerance));
5705    if (foundFragment && (foundFragment !== fragPrevious || !fragNext)) {
5706      return foundFragment;
5707    }
5708    // If no match was found return the next fragment after fragPrevious, or null
5709    return fragNext;
5710  }
5711  function fragmentWithinFastStartSwitch(fragNext, fragPrevious, nextFragLookupTolerance) {
5712    if (fragPrevious && fragPrevious.start === 0 && fragPrevious.level < fragNext.level && (fragPrevious.endPTS || 0) > 0) {
5713      var firstDuration = fragPrevious.tagList.reduce(function (duration, tag) {
5714        if (tag[0] === 'INF') {
5715          duration += parseFloat(tag[1]);
5716        }
5717        return duration;
5718      }, nextFragLookupTolerance);
5719      return fragNext.start <= firstDuration;
5720    }
5721    return false;
5722  }
5723
5724  /**
5725   * The test function used by the findFragmentBySn's BinarySearch to look for the best match to the current buffer conditions.
5726   * @param candidate - The fragment to test
5727   * @param bufferEnd - The end of the current buffered range the playhead is currently within
5728   * @param maxFragLookUpTolerance - The amount of time that a fragment's start can be within in order to be considered contiguous
5729   * @returns 0 if it matches, 1 if too low, -1 if too high
5730   */
5731  function fragmentWithinToleranceTest(bufferEnd, maxFragLookUpTolerance, candidate) {
5732    if (bufferEnd === void 0) {
5733      bufferEnd = 0;
5734    }
5735    if (maxFragLookUpTolerance === void 0) {
5736      maxFragLookUpTolerance = 0;
5737    }
5738    // eagerly accept an accurate match (no tolerance)
5739    if (candidate.start <= bufferEnd && candidate.start + candidate.duration > bufferEnd) {
5740      return 0;
5741    }
5742    // offset should be within fragment boundary - config.maxFragLookUpTolerance
5743    // this is to cope with situations like
5744    // bufferEnd = 9.991
5745    // frag[Ø] : [0,10]
5746    // frag[1] : [10,20]
5747    // bufferEnd is within frag[0] range ... although what we are expecting is to return frag[1] here
5748    //              frag start               frag start+duration
5749    //                  |-----------------------------|
5750    //              <--->                         <--->
5751    //  ...--------><-----------------------------><---------....
5752    // previous frag         matching fragment         next frag
5753    //  return -1             return 0                 return 1
5754    // logger.log(`level/sn/start/end/bufEnd:${level}/${candidate.sn}/${candidate.start}/${(candidate.start+candidate.duration)}/${bufferEnd}`);
5755    // Set the lookup tolerance to be small enough to detect the current segment - ensures we don't skip over very small segments
5756    var candidateLookupTolerance = Math.min(maxFragLookUpTolerance, candidate.duration + (candidate.deltaPTS ? candidate.deltaPTS : 0));
5757    if (candidate.start + candidate.duration - candidateLookupTolerance <= bufferEnd) {
5758      return 1;
5759    } else if (candidate.start - candidateLookupTolerance > bufferEnd && candidate.start) {
5760      // if maxFragLookUpTolerance will have negative value then don't return -1 for first element
5761      return -1;
5762    }
5763    return 0;
5764  }
5765
5766  /**
5767   * The test function used by the findFragmentByPdt's BinarySearch to look for the best match to the current buffer conditions.
5768   * This function tests the candidate's program date time values, as represented in Unix time
5769   * @param candidate - The fragment to test
5770   * @param pdtBufferEnd - The Unix time representing the end of the current buffered range
5771   * @param maxFragLookUpTolerance - The amount of time that a fragment's start can be within in order to be considered contiguous
5772   * @returns true if contiguous, false otherwise
5773   */
5774  function pdtWithinToleranceTest(pdtBufferEnd, maxFragLookUpTolerance, candidate) {
5775    var candidateLookupTolerance = Math.min(maxFragLookUpTolerance, candidate.duration + (candidate.deltaPTS ? candidate.deltaPTS : 0)) * 1000;
5776
5777    // endProgramDateTime can be null, default to zero
5778    var endProgramDateTime = candidate.endProgramDateTime || 0;
5779    return endProgramDateTime - candidateLookupTolerance > pdtBufferEnd;
5780  }
5781  function findFragWithCC(fragments, cc) {
5782    return BinarySearch.search(fragments, function (candidate) {
5783      if (candidate.cc < cc) {
5784        return 1;
5785      } else if (candidate.cc > cc) {
5786        return -1;
5787      } else {
5788        return 0;
5789      }
5790    });
5791  }
5792
5793  var NetworkErrorAction = {
5794    DoNothing: 0,
5795    SendEndCallback: 1,
5796    SendAlternateToPenaltyBox: 2,
5797    RemoveAlternatePermanently: 3,
5798    InsertDiscontinuity: 4,
5799    RetryRequest: 5
5800  };
5801  var ErrorActionFlags = {
5802    None: 0,
5803    MoveAllAlternatesMatchingHost: 1,
5804    MoveAllAlternatesMatchingHDCP: 2,
5805    SwitchToSDR: 4
5806  }; // Reserved for future use
5807  var ErrorController = /*#__PURE__*/function (_Logger) {
5808    function ErrorController(hls) {
5809      var _this;
5810      _this = _Logger.call(this, 'error-controller', hls.logger) || this;
5811      _this.hls = void 0;
5812      _this.playlistError = 0;
5813      _this.penalizedRenditions = {};
5814      _this.hls = hls;
5815      _this.registerListeners();
5816      return _this;
5817    }
5818    _inheritsLoose(ErrorController, _Logger);
5819    var _proto = ErrorController.prototype;
5820    _proto.registerListeners = function registerListeners() {
5821      var hls = this.hls;
5822      hls.on(Events.ERROR, this.onError, this);
5823      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
5824      hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
5825    };
5826    _proto.unregisterListeners = function unregisterListeners() {
5827      var hls = this.hls;
5828      if (!hls) {
5829        return;
5830      }
5831      hls.off(Events.ERROR, this.onError, this);
5832      hls.off(Events.ERROR, this.onErrorOut, this);
5833      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
5834      hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
5835    };
5836    _proto.destroy = function destroy() {
5837      this.unregisterListeners();
5838      // @ts-ignore
5839      this.hls = null;
5840      this.penalizedRenditions = {};
5841    };
5842    _proto.startLoad = function startLoad(startPosition) {};
5843    _proto.stopLoad = function stopLoad() {
5844      this.playlistError = 0;
5845    };
5846    _proto.getVariantLevelIndex = function getVariantLevelIndex(frag) {
5847      return (frag == null ? void 0 : frag.type) === PlaylistLevelType.MAIN ? frag.level : this.hls.loadLevel;
5848    };
5849    _proto.onManifestLoading = function onManifestLoading() {
5850      this.playlistError = 0;
5851      this.penalizedRenditions = {};
5852    };
5853    _proto.onLevelUpdated = function onLevelUpdated() {
5854      this.playlistError = 0;
5855    };
5856    _proto.onError = function onError(event, data) {
5857      var _data$frag;
5858      if (data.fatal) {
5859        return;
5860      }
5861      var hls = this.hls;
5862      var context = data.context;
5863      switch (data.details) {
5864        case ErrorDetails.FRAG_LOAD_ERROR:
5865        case ErrorDetails.FRAG_LOAD_TIMEOUT:
5866        case ErrorDetails.KEY_LOAD_ERROR:
5867        case ErrorDetails.KEY_LOAD_TIMEOUT:
5868          data.errorAction = this.getFragRetryOrSwitchAction(data);
5869          return;
5870        case ErrorDetails.FRAG_PARSING_ERROR:
5871          // ignore empty segment errors marked as gap
5872          if ((_data$frag = data.frag) != null && _data$frag.gap) {
5873            data.errorAction = createDoNothingErrorAction();
5874            return;
5875          }
5876        // falls through
5877        case ErrorDetails.FRAG_GAP:
5878        case ErrorDetails.FRAG_DECRYPT_ERROR:
5879          {
5880            // Switch level if possible, otherwise allow retry count to reach max error retries
5881            data.errorAction = this.getFragRetryOrSwitchAction(data);
5882            data.errorAction.action = NetworkErrorAction.SendAlternateToPenaltyBox;
5883            return;
5884          }
5885        case ErrorDetails.LEVEL_EMPTY_ERROR:
5886        case ErrorDetails.LEVEL_PARSING_ERROR:
5887          {
5888            var _data$context, _data$context$levelDe;
5889            // Only retry when empty and live
5890            var levelIndex = data.parent === PlaylistLevelType.MAIN ? data.level : hls.loadLevel;
5891            if (data.details === ErrorDetails.LEVEL_EMPTY_ERROR && !!((_data$context = data.context) != null && (_data$context$levelDe = _data$context.levelDetails) != null && _data$context$levelDe.live)) {
5892              data.errorAction = this.getPlaylistRetryOrSwitchAction(data, levelIndex);
5893            } else {
5894              // Escalate to fatal if not retrying or switching
5895              data.levelRetry = false;
vendor: 12,675 bytes, lines 5896-6155
5896              data.errorAction = this.getLevelSwitchAction(data, levelIndex);
5897            }
5898          }
5899          return;
5900        case ErrorDetails.LEVEL_LOAD_ERROR:
5901        case ErrorDetails.LEVEL_LOAD_TIMEOUT:
5902          if (typeof (context == null ? void 0 : context.level) === 'number') {
5903            data.errorAction = this.getPlaylistRetryOrSwitchAction(data, context.level);
5904          }
5905          return;
5906        case ErrorDetails.AUDIO_TRACK_LOAD_ERROR:
5907        case ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT:
5908        case ErrorDetails.SUBTITLE_LOAD_ERROR:
5909        case ErrorDetails.SUBTITLE_TRACK_LOAD_TIMEOUT:
5910          if (context) {
5911            var level = hls.levels[hls.loadLevel];
5912            if (level && (context.type === PlaylistContextType.AUDIO_TRACK && level.hasAudioGroup(context.groupId) || context.type === PlaylistContextType.SUBTITLE_TRACK && level.hasSubtitleGroup(context.groupId))) {
5913              // Perform Pathway switch or Redundant failover if possible for fastest recovery
5914              // otherwise allow playlist retry count to reach max error retries
5915              data.errorAction = this.getPlaylistRetryOrSwitchAction(data, hls.loadLevel);
5916              data.errorAction.action = NetworkErrorAction.SendAlternateToPenaltyBox;
5917              data.errorAction.flags = ErrorActionFlags.MoveAllAlternatesMatchingHost;
5918              return;
5919            }
5920          }
5921          return;
5922        case ErrorDetails.KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED:
5923          {
5924            var _level = hls.levels[hls.loadLevel];
5925            var restrictedHdcpLevel = _level == null ? void 0 : _level.attrs['HDCP-LEVEL'];
5926            if (restrictedHdcpLevel) {
5927              data.errorAction = {
5928                action: NetworkErrorAction.SendAlternateToPenaltyBox,
5929                flags: ErrorActionFlags.MoveAllAlternatesMatchingHDCP,
5930                hdcpLevel: restrictedHdcpLevel
5931              };
5932            } else {
5933              this.keySystemError(data);
5934            }
5935          }
5936          return;
5937        case ErrorDetails.BUFFER_ADD_CODEC_ERROR:
5938        case ErrorDetails.REMUX_ALLOC_ERROR:
5939        case ErrorDetails.BUFFER_APPEND_ERROR:
5940          // Buffer-controller can set errorAction when append errors can be ignored or resolved locally
5941          if (!data.errorAction) {
5942            var _data$level;
5943            data.errorAction = this.getLevelSwitchAction(data, (_data$level = data.level) != null ? _data$level : hls.loadLevel);
5944          }
5945          return;
5946        case ErrorDetails.INTERNAL_EXCEPTION:
5947        case ErrorDetails.BUFFER_APPENDING_ERROR:
5948        case ErrorDetails.BUFFER_FULL_ERROR:
5949        case ErrorDetails.LEVEL_SWITCH_ERROR:
5950        case ErrorDetails.BUFFER_STALLED_ERROR:
5951        case ErrorDetails.BUFFER_SEEK_OVER_HOLE:
5952        case ErrorDetails.BUFFER_NUDGE_ON_STALL:
5953          data.errorAction = createDoNothingErrorAction();
5954          return;
5955      }
5956      if (data.type === ErrorTypes.KEY_SYSTEM_ERROR) {
5957        this.keySystemError(data);
5958      }
5959    };
5960    _proto.keySystemError = function keySystemError(data) {
5961      var levelIndex = this.getVariantLevelIndex(data.frag);
5962      // Do not retry level. Escalate to fatal if switching levels fails.
5963      data.levelRetry = false;
5964      data.errorAction = this.getLevelSwitchAction(data, levelIndex);
5965    };
5966    _proto.getPlaylistRetryOrSwitchAction = function getPlaylistRetryOrSwitchAction(data, levelIndex) {
5967      var hls = this.hls;
5968      var retryConfig = getRetryConfig(hls.config.playlistLoadPolicy, data);
5969      var retryCount = this.playlistError++;
5970      var retry = shouldRetry(retryConfig, retryCount, isTimeoutError(data), data.response);
5971      if (retry) {
5972        return {
5973          action: NetworkErrorAction.RetryRequest,
5974          flags: ErrorActionFlags.None,
5975          retryConfig: retryConfig,
5976          retryCount: retryCount
5977        };
5978      }
5979      var errorAction = this.getLevelSwitchAction(data, levelIndex);
5980      if (retryConfig) {
5981        errorAction.retryConfig = retryConfig;
5982        errorAction.retryCount = retryCount;
5983      }
5984      return errorAction;
5985    };
5986    _proto.getFragRetryOrSwitchAction = function getFragRetryOrSwitchAction(data) {
5987      var hls = this.hls;
5988      // Share fragment error count accross media options (main, audio, subs)
5989      // This allows for level based rendition switching when media option assets fail
5990      var variantLevelIndex = this.getVariantLevelIndex(data.frag);
5991      var level = hls.levels[variantLevelIndex];
5992      var _hls$config = hls.config,
5993        fragLoadPolicy = _hls$config.fragLoadPolicy,
5994        keyLoadPolicy = _hls$config.keyLoadPolicy;
5995      var retryConfig = getRetryConfig(data.details.startsWith('key') ? keyLoadPolicy : fragLoadPolicy, data);
5996      var fragmentErrors = hls.levels.reduce(function (acc, level) {
5997        return acc + level.fragmentError;
5998      }, 0);
5999      // Switch levels when out of retried or level index out of bounds
6000      if (level) {
6001        if (data.details !== ErrorDetails.FRAG_GAP) {
6002          level.fragmentError++;
6003        }
6004        var retry = shouldRetry(retryConfig, fragmentErrors, isTimeoutError(data), data.response);
6005        if (retry) {
6006          return {
6007            action: NetworkErrorAction.RetryRequest,
6008            flags: ErrorActionFlags.None,
6009            retryConfig: retryConfig,
6010            retryCount: fragmentErrors
6011          };
6012        }
6013      }
6014      // Reach max retry count, or Missing level reference
6015      // Switch to valid index
6016      var errorAction = this.getLevelSwitchAction(data, variantLevelIndex);
6017      // Add retry details to allow skipping of FRAG_PARSING_ERROR
6018      if (retryConfig) {
6019        errorAction.retryConfig = retryConfig;
6020        errorAction.retryCount = fragmentErrors;
6021      }
6022      return errorAction;
6023    };
6024    _proto.getLevelSwitchAction = function getLevelSwitchAction(data, levelIndex) {
6025      var hls = this.hls;
6026      if (levelIndex === null || levelIndex === undefined) {
6027        levelIndex = hls.loadLevel;
6028      }
6029      var level = this.hls.levels[levelIndex];
6030      if (level) {
6031        var _data$frag2, _data$context2;
6032        var errorDetails = data.details;
6033        level.loadError++;
6034        if (errorDetails === ErrorDetails.BUFFER_APPEND_ERROR) {
6035          level.fragmentError++;
6036        }
6037        // Search for next level to retry
6038        var nextLevel = -1;
6039        var levels = hls.levels,
6040          loadLevel = hls.loadLevel,
6041          minAutoLevel = hls.minAutoLevel,
6042          maxAutoLevel = hls.maxAutoLevel;
6043        if (!hls.autoLevelEnabled) {
6044          hls.loadLevel = -1;
6045        }
6046        var fragErrorType = (_data$frag2 = data.frag) == null ? void 0 : _data$frag2.type;
6047        // Find alternate audio codec if available on audio codec error
6048        var isAudioCodecError = fragErrorType === PlaylistLevelType.AUDIO && errorDetails === ErrorDetails.FRAG_PARSING_ERROR || data.sourceBufferName === 'audio' && (errorDetails === ErrorDetails.BUFFER_ADD_CODEC_ERROR || errorDetails === ErrorDetails.BUFFER_APPEND_ERROR);
6049        var findAudioCodecAlternate = isAudioCodecError && levels.some(function (_ref) {
6050          var audioCodec = _ref.audioCodec;
6051          return level.audioCodec !== audioCodec;
6052        });
6053        // Find alternate video codec if available on video codec error
6054        var isVideoCodecError = data.sourceBufferName === 'video' && (errorDetails === ErrorDetails.BUFFER_ADD_CODEC_ERROR || errorDetails === ErrorDetails.BUFFER_APPEND_ERROR);
6055        var findVideoCodecAlternate = isVideoCodecError && levels.some(function (_ref2) {
6056          var codecSet = _ref2.codecSet,
6057            audioCodec = _ref2.audioCodec;
6058          return level.codecSet !== codecSet && level.audioCodec === audioCodec;
6059        });
6060        var _ref3 = (_data$context2 = data.context) != null ? _data$context2 : {},
6061          playlistErrorType = _ref3.type,
6062          playlistErrorGroupId = _ref3.groupId;
6063        var _loop = function _loop() {
6064            var candidate = (i + loadLevel) % levels.length;
6065            if (candidate !== loadLevel && candidate >= minAutoLevel && candidate <= maxAutoLevel && levels[candidate].loadError === 0) {
6066              var _level$audioGroups, _level$subtitleGroups;
6067              var levelCandidate = levels[candidate];
6068              // Skip level switch if GAP tag is found in next level at same position
6069              if (errorDetails === ErrorDetails.FRAG_GAP && fragErrorType === PlaylistLevelType.MAIN && data.frag) {
6070                var levelDetails = levels[candidate].details;
6071                if (levelDetails) {
6072                  var fragCandidate = findFragmentByPTS(data.frag, levelDetails.fragments, data.frag.start);
6073                  if (fragCandidate != null && fragCandidate.gap) {
6074                    return 0; // continue
6075                  }
6076                }
6077              } else if (playlistErrorType === PlaylistContextType.AUDIO_TRACK && levelCandidate.hasAudioGroup(playlistErrorGroupId) || playlistErrorType === PlaylistContextType.SUBTITLE_TRACK && levelCandidate.hasSubtitleGroup(playlistErrorGroupId)) {
6078                // For audio/subs playlist errors find another group ID or fallthrough to redundant fail-over
6079                return 0; // continue
6080              } else if (fragErrorType === PlaylistLevelType.AUDIO && (_level$audioGroups = level.audioGroups) != null && _level$audioGroups.some(function (groupId) {
6081                return levelCandidate.hasAudioGroup(groupId);
6082              }) || fragErrorType === PlaylistLevelType.SUBTITLE && (_level$subtitleGroups = level.subtitleGroups) != null && _level$subtitleGroups.some(function (groupId) {
6083                return levelCandidate.hasSubtitleGroup(groupId);
6084              }) || findAudioCodecAlternate && level.audioCodec === levelCandidate.audioCodec || !findAudioCodecAlternate && level.audioCodec !== levelCandidate.audioCodec || findVideoCodecAlternate && level.codecSet === levelCandidate.codecSet) {
6085                // For video/audio/subs frag errors find another group ID or fallthrough to redundant fail-over
6086                return 0; // continue
6087              }
6088              nextLevel = candidate;
6089              return 1; // break
6090            }
6091          },
6092          _ret;
6093        for (var i = levels.length; i--;) {
6094          _ret = _loop();
6095          if (_ret === 0) continue;
6096          if (_ret === 1) break;
6097        }
6098        if (nextLevel > -1 && hls.loadLevel !== nextLevel) {
6099          data.levelRetry = true;
6100          this.playlistError = 0;
6101          return {
6102            action: NetworkErrorAction.SendAlternateToPenaltyBox,
6103            flags: ErrorActionFlags.None,
6104            nextAutoLevel: nextLevel
6105          };
6106        }
6107      }
6108      // No levels to switch / Manual level selection / Level not found
6109      // Resolve with Pathway switch, Redundant fail-over, or stay on lowest Level
6110      return {
6111        action: NetworkErrorAction.SendAlternateToPenaltyBox,
6112        flags: ErrorActionFlags.MoveAllAlternatesMatchingHost
6113      };
6114    };
6115    _proto.onErrorOut = function onErrorOut(event, data) {
6116      var _data$errorAction;
6117      switch ((_data$errorAction = data.errorAction) == null ? void 0 : _data$errorAction.action) {
6118        case NetworkErrorAction.DoNothing:
6119          break;
6120        case NetworkErrorAction.SendAlternateToPenaltyBox:
6121          this.sendAlternateToPenaltyBox(data);
6122          if (!data.errorAction.resolved && data.details !== ErrorDetails.FRAG_GAP) {
6123            data.fatal = true;
6124          } else if (/MediaSource readyState: ended/.test(data.error.message)) {
6125            this.warn("MediaSource ended after \"" + data.sourceBufferName + "\" sourceBuffer append error. Attempting to recover from media error.");
6126            this.hls.recoverMediaError();
6127          }
6128          break;
6129      }
6130      if (data.fatal) {
6131        this.hls.stopLoad();
6132        return;
6133      }
6134    };
6135    _proto.sendAlternateToPenaltyBox = function sendAlternateToPenaltyBox(data) {
6136      var hls = this.hls;
6137      var errorAction = data.errorAction;
6138      if (!errorAction) {
6139        return;
6140      }
6141      var flags = errorAction.flags,
6142        hdcpLevel = errorAction.hdcpLevel,
6143        nextAutoLevel = errorAction.nextAutoLevel;
6144      switch (flags) {
6145        case ErrorActionFlags.None:
6146          this.switchLevel(data, nextAutoLevel);
6147          break;
6148        case ErrorActionFlags.MoveAllAlternatesMatchingHDCP:
6149          if (hdcpLevel) {
6150            hls.maxHdcpLevel = HdcpLevels[HdcpLevels.indexOf(hdcpLevel) - 1];
6151            errorAction.resolved = true;
6152          }
6153          this.warn("Restricting playback to HDCP-LEVEL of \"" + hls.maxHdcpLevel + "\" or lower");
6154          break;
6155      }
vendor: 4,393 bytes, lines 6156-6268
6156      // If not resolved by previous actions try to switch to next level
6157      if (!errorAction.resolved) {
6158        this.switchLevel(data, nextAutoLevel);
6159      }
6160    };
6161    _proto.switchLevel = function switchLevel(data, levelIndex) {
6162      if (levelIndex !== undefined && data.errorAction) {
6163        this.warn("switching to level " + levelIndex + " after " + data.details);
6164        this.hls.nextAutoLevel = levelIndex;
6165        data.errorAction.resolved = true;
6166        // Stream controller is responsible for this but won't switch on false start
6167        this.hls.nextLoadLevel = this.hls.nextAutoLevel;
6168      }
6169    };
6170    return ErrorController;
6171  }(Logger);
6172  function createDoNothingErrorAction(resolved) {
6173    var errorAction = {
6174      action: NetworkErrorAction.DoNothing,
6175      flags: ErrorActionFlags.None
6176    };
6177    return errorAction;
6178  }
6179
6180  var BasePlaylistController = /*#__PURE__*/function (_Logger) {
6181    function BasePlaylistController(hls, logPrefix) {
6182      var _this;
6183      _this = _Logger.call(this, logPrefix, hls.logger) || this;
6184      _this.hls = void 0;
6185      _this.timer = -1;
6186      _this.requestScheduled = -1;
6187      _this.canLoad = false;
6188      _this.hls = hls;
6189      return _this;
6190    }
6191    _inheritsLoose(BasePlaylistController, _Logger);
6192    var _proto = BasePlaylistController.prototype;
6193    _proto.destroy = function destroy() {
6194      this.clearTimer();
6195      // @ts-ignore
6196      this.hls = this.log = this.warn = null;
6197    };
6198    _proto.clearTimer = function clearTimer() {
6199      if (this.timer !== -1) {
6200        self.clearTimeout(this.timer);
6201        this.timer = -1;
6202      }
6203    };
6204    _proto.startLoad = function startLoad() {
6205      this.canLoad = true;
6206      this.requestScheduled = -1;
6207      this.loadPlaylist();
6208    };
6209    _proto.stopLoad = function stopLoad() {
6210      this.canLoad = false;
6211      this.clearTimer();
6212    };
6213    _proto.switchParams = function switchParams(playlistUri, previous, current) {
6214      var renditionReports = previous == null ? void 0 : previous.renditionReports;
6215      if (renditionReports) {
6216        var foundIndex = -1;
6217        for (var i = 0; i < renditionReports.length; i++) {
6218          var attr = renditionReports[i];
6219          var uri = void 0;
6220          try {
6221            uri = new self.URL(attr.URI, previous.url).href;
6222          } catch (error) {
6223            this.warn("Could not construct new URL for Rendition Report: " + error);
6224            uri = attr.URI || '';
6225          }
6226          // Use exact match. Otherwise, the last partial match, if any, will be used
6227          // (Playlist URI includes a query string that the Rendition Report does not)
6228          if (uri === playlistUri) {
6229            foundIndex = i;
6230            break;
6231          } else if (uri === playlistUri.substring(0, uri.length)) {
6232            foundIndex = i;
6233          }
6234        }
6235        if (foundIndex !== -1) {
6236          var _attr = renditionReports[foundIndex];
6237          var msn = parseInt(_attr['LAST-MSN']) || (previous == null ? void 0 : previous.lastPartSn);
6238          var part = parseInt(_attr['LAST-PART']) || (previous == null ? void 0 : previous.lastPartIndex);
6239          if (this.hls.config.lowLatencyMode) {
6240            var currentGoal = Math.min(previous.age - previous.partTarget, previous.targetduration);
6241            if (part >= 0 && currentGoal > previous.partTarget) {
6242              part += 1;
6243            }
6244          }
6245          var skip = current && getSkipValue(current);
6246          return new HlsUrlParameters(msn, part >= 0 ? part : undefined, skip);
6247        }
6248      }
6249    };
6250    _proto.loadPlaylist = function loadPlaylist(hlsUrlParameters) {
6251      if (this.requestScheduled === -1) {
6252        this.requestScheduled = self.performance.now();
6253      }
6254      // Loading is handled by the subclasses
6255    };
6256    _proto.shouldLoadPlaylist = function shouldLoadPlaylist(playlist) {
6257      return this.canLoad && !!playlist && !!playlist.url && (!playlist.details || playlist.details.live);
6258    };
6259    _proto.shouldReloadPlaylist = function shouldReloadPlaylist(playlist) {
6260      return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
6261    };
6262    _proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
6263      var _this2 = this;
6264      var details = data.details,
6265        stats = data.stats;
6266
6267      // Set last updated date-time
6268      var now = self.performance.now();
6269      var elapsed = stats.loading.first ? Math.max(0, now - stats.loading.first) : 0;
6270      details.advancedDateTime = Date.now() - elapsed;
6271
6272      // if current playlist is a live playlist, arm a timer to reload it
6273      if (details.live || previousDetails != null && previousDetails.live) {
6274        details.reloaded(previousDetails);
6275        if (previousDetails) {
6276          this.log("live playlist " + index + " " + (details.advanced ? 'REFRESHED ' + details.lastPartSn + '-' + details.lastPartIndex : details.updated ? 'UPDATED' : 'MISSED'));
6277        }
6278        // Merge live playlists to adjust fragment starts and fill in delta playlist skipped segments
6279        if (previousDetails && details.fragments.length > 0) {
6280          mergeDetails(previousDetails, details);
6281        }
6282        if (!this.canLoad || !details.live) {
6283          return;
6284        }
6285        var deliveryDirectives;
6286        var msn = undefined;
6287        var part = undefined;
6288        if (details.canBlockReload && details.endSN && details.advanced) {
6289          // Load level with LL-HLS delivery directives
6290          var lowLatencyMode = this.hls.config.lowLatencyMode;
6291          var lastPartSn = details.lastPartSn;
6292          var endSn = details.endSN;
6293          var lastPartIndex = details.lastPartIndex;
6294          var hasParts = lastPartIndex !== -1;
6295          var lastPart = lastPartSn === endSn;
6296          // When low latency mode is disabled, we'll skip part requests once the last part index is found
6297          var nextSnStartIndex = lowLatencyMode ? 0 : lastPartIndex;
6298          if (hasParts) {
6299            msn = lastPart ? endSn + 1 : lastPartSn;
6300            part = lastPart ? nextSnStartIndex : lastPartIndex + 1;
6301          } else {
6302            msn = endSn + 1;
6303          }
6304          // Low-Latency CDN Tune-in: "age" header and time since load indicates we're behind by more than one part
6305          // Update directives to obtain the Playlist that has the estimated additional duration of media
6306          var lastAdvanced = details.age;
6307          var cdnAge = lastAdvanced + details.ageHeader;
6308          var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
6309          if (currentGoal > 0) {
6310            if (cdnAge > details.targetduration * 3) {
6311              // Omit segment and part directives when the last response was more than 3 target durations ago,
6312              this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
6313              msn = undefined;
6314              part = undefined;
6315            } else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
6316              // If we attempted to get the next or latest playlist update, but currentGoal increased,
6317              // then we either can't catchup, or the "age" header cannot be trusted.
6318              this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
6319              currentGoal = 0;
6320            } else {
6321              var segments = Math.floor(currentGoal / details.targetduration);
6322              msn += segments;
6323              if (part !== undefined) {
6324                var parts = Math.round(currentGoal % details.targetduration / details.partTarget);
6325                part += parts;
6326              }
6327              this.log("CDN Tune-in age: " + details.ageHeader + "s last advanced " + lastAdvanced.toFixed(2) + "s goal: " + currentGoal + " skip sn " + segments + " to part " + part);
6328            }
6329            details.tuneInGoal = currentGoal;
6330          }
6331          deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part);
6332          if (lowLatencyMode || !lastPart) {
6333            this.loadPlaylist(deliveryDirectives);
6334            return;
6335          }
6336        } else if (details.canBlockReload || details.canSkipUntil) {
6337          deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part);
6338        }
6339        var bufferInfo = this.hls.mainForwardBufferInfo;
6340        var position = bufferInfo ? bufferInfo.end - bufferInfo.len : 0;
6341        var distanceToLiveEdgeMs = (details.edge - position) * 1000;
6342        var reloadInterval = computeReloadInterval(details, distanceToLiveEdgeMs);
6343        if (details.updated && now > this.requestScheduled + reloadInterval) {
6344          this.requestScheduled = stats.loading.start;
6345        }
6346        if (msn !== undefined && details.canBlockReload) {
6347          this.requestScheduled = stats.loading.first + reloadInterval - (details.partTarget * 1000 || 1000);
6348        } else if (this.requestScheduled === -1 || this.requestScheduled + reloadInterval < now) {
6349          this.requestScheduled = now;
6350        } else if (this.requestScheduled - now <= 0) {
6351          this.requestScheduled += reloadInterval;
6352        }
vendor: 9,358 bytes, lines 6353-6590
6353        var estimatedTimeUntilUpdate = this.requestScheduled - now;
6354        estimatedTimeUntilUpdate = Math.max(0, estimatedTimeUntilUpdate);
6355        this.log("reload live playlist " + index + " in " + Math.round(estimatedTimeUntilUpdate) + " ms");
6356        // this.log(
6357        //   `live reload ${details.updated ? 'REFRESHED' : 'MISSED'}
6358        // reload in ${estimatedTimeUntilUpdate / 1000}
6359        // round trip ${(stats.loading.end - stats.loading.start) / 1000}
6360        // diff ${
6361        //   (reloadInterval -
6362        //     (estimatedTimeUntilUpdate +
6363        //       stats.loading.end -
6364        //       stats.loading.start)) /
6365        //   1000
6366        // }
6367        // reload interval ${reloadInterval / 1000}
6368        // target duration ${details.targetduration}
6369        // distance to edge ${distanceToLiveEdgeMs / 1000}`
6370        // );
6371
6372        this.timer = self.setTimeout(function () {
6373          return _this2.loadPlaylist(deliveryDirectives);
6374        }, estimatedTimeUntilUpdate);
6375      } else {
6376        this.clearTimer();
6377      }
6378    };
6379    _proto.getDeliveryDirectives = function getDeliveryDirectives(details, previousDeliveryDirectives, msn, part) {
6380      var skip = getSkipValue(details);
6381      if (previousDeliveryDirectives != null && previousDeliveryDirectives.skip && details.deltaUpdateFailed) {
6382        msn = previousDeliveryDirectives.msn;
6383        part = previousDeliveryDirectives.part;
6384        skip = HlsSkip.No;
6385      }
6386      return new HlsUrlParameters(msn, part, skip);
6387    };
6388    _proto.checkRetry = function checkRetry(errorEvent) {
6389      var _this3 = this;
6390      var errorDetails = errorEvent.details;
6391      var isTimeout = isTimeoutError(errorEvent);
6392      var errorAction = errorEvent.errorAction;
6393      var _ref = errorAction || {},
6394        action = _ref.action,
6395        _ref$retryCount = _ref.retryCount,
6396        retryCount = _ref$retryCount === void 0 ? 0 : _ref$retryCount,
6397        retryConfig = _ref.retryConfig;
6398      var retry = !!errorAction && !!retryConfig && (action === NetworkErrorAction.RetryRequest || !errorAction.resolved && action === NetworkErrorAction.SendAlternateToPenaltyBox);
6399      if (retry) {
6400        var _errorEvent$context;
6401        this.requestScheduled = -1;
6402        if (retryCount >= retryConfig.maxNumRetry) {
6403          return false;
6404        }
6405        if (isTimeout && (_errorEvent$context = errorEvent.context) != null && _errorEvent$context.deliveryDirectives) {
6406          // The LL-HLS request already timed out so retry immediately
6407          this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" without delivery-directives");
6408          this.loadPlaylist();
6409        } else {
6410          var delay = getRetryDelay(retryConfig, retryCount);
6411          // Schedule level/track reload
6412          this.timer = self.setTimeout(function () {
6413            return _this3.loadPlaylist();
6414          }, delay);
6415          this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
6416        }
6417        // `levelRetry = true` used to inform other controllers that a retry is happening
6418        errorEvent.levelRetry = true;
6419        errorAction.resolved = true;
6420      }
6421      return retry;
6422    };
6423    return BasePlaylistController;
6424  }(Logger);
6425
6426  /*
6427   * compute an Exponential Weighted moving average
6428   * - https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
6429   *  - heavily inspired from shaka-player
6430   */
6431  var EWMA = /*#__PURE__*/function () {
6432    //  About half of the estimated value will be from the last |halfLife| samples by weight.
6433    function EWMA(halfLife, estimate, weight) {
6434      if (estimate === void 0) {
6435        estimate = 0;
6436      }
6437      if (weight === void 0) {
6438        weight = 0;
6439      }
6440      this.halfLife = void 0;
6441      this.alpha_ = void 0;
6442      this.estimate_ = void 0;
6443      this.totalWeight_ = void 0;
6444      this.halfLife = halfLife;
6445      // Larger values of alpha expire historical data more slowly.
6446      this.alpha_ = halfLife ? Math.exp(Math.log(0.5) / halfLife) : 0;
6447      this.estimate_ = estimate;
6448      this.totalWeight_ = weight;
6449    }
6450    var _proto = EWMA.prototype;
6451    _proto.sample = function sample(weight, value) {
6452      var adjAlpha = Math.pow(this.alpha_, weight);
6453      this.estimate_ = value * (1 - adjAlpha) + adjAlpha * this.estimate_;
6454      this.totalWeight_ += weight;
6455    };
6456    _proto.getTotalWeight = function getTotalWeight() {
6457      return this.totalWeight_;
6458    };
6459    _proto.getEstimate = function getEstimate() {
6460      if (this.alpha_) {
6461        var zeroFactor = 1 - Math.pow(this.alpha_, this.totalWeight_);
6462        if (zeroFactor) {
6463          return this.estimate_ / zeroFactor;
6464        }
6465      }
6466      return this.estimate_;
6467    };
6468    return EWMA;
6469  }();
6470
6471  /*
6472   * EWMA Bandwidth Estimator
6473   *  - heavily inspired from shaka-player
6474   * Tracks bandwidth samples and estimates available bandwidth.
6475   * Based on the minimum of two exponentially-weighted moving averages with
6476   * different half-lives.
6477   */
6478
6479  var EwmaBandWidthEstimator = /*#__PURE__*/function () {
6480    function EwmaBandWidthEstimator(slow, fast, defaultEstimate, defaultTTFB) {
6481      if (defaultTTFB === void 0) {
6482        defaultTTFB = 100;
6483      }
6484      this.defaultEstimate_ = void 0;
6485      this.minWeight_ = void 0;
6486      this.minDelayMs_ = void 0;
6487      this.slow_ = void 0;
6488      this.fast_ = void 0;
6489      this.defaultTTFB_ = void 0;
6490      this.ttfb_ = void 0;
6491      this.defaultEstimate_ = defaultEstimate;
6492      this.minWeight_ = 0.001;
6493      this.minDelayMs_ = 50;
6494      this.slow_ = new EWMA(slow);
6495      this.fast_ = new EWMA(fast);
6496      this.defaultTTFB_ = defaultTTFB;
6497      this.ttfb_ = new EWMA(slow);
6498    }
6499    var _proto = EwmaBandWidthEstimator.prototype;
6500    _proto.update = function update(slow, fast) {
6501      var slow_ = this.slow_,
6502        fast_ = this.fast_,
6503        ttfb_ = this.ttfb_;
6504      if (slow_.halfLife !== slow) {
6505        this.slow_ = new EWMA(slow, slow_.getEstimate(), slow_.getTotalWeight());
6506      }
6507      if (fast_.halfLife !== fast) {
6508        this.fast_ = new EWMA(fast, fast_.getEstimate(), fast_.getTotalWeight());
6509      }
6510      if (ttfb_.halfLife !== slow) {
6511        this.ttfb_ = new EWMA(slow, ttfb_.getEstimate(), ttfb_.getTotalWeight());
6512      }
6513    };
6514    _proto.sample = function sample(durationMs, numBytes) {
6515      durationMs = Math.max(durationMs, this.minDelayMs_);
6516      var numBits = 8 * numBytes;
6517      // weight is duration in seconds
6518      var durationS = durationMs / 1000;
6519      // value is bandwidth in bits/s
6520      var bandwidthInBps = numBits / durationS;
6521      this.fast_.sample(durationS, bandwidthInBps);
6522      this.slow_.sample(durationS, bandwidthInBps);
6523    };
6524    _proto.sampleTTFB = function sampleTTFB(ttfb) {
6525      // weight is frequency curve applied to TTFB in seconds
6526      // (longer times have less weight with expected input under 1 second)
6527      var seconds = ttfb / 1000;
6528      var weight = Math.sqrt(2) * Math.exp(-Math.pow(seconds, 2) / 2);
6529      this.ttfb_.sample(weight, Math.max(ttfb, 5));
6530    };
6531    _proto.canEstimate = function canEstimate() {
6532      return this.fast_.getTotalWeight() >= this.minWeight_;
6533    };
6534    _proto.getEstimate = function getEstimate() {
6535      if (this.canEstimate()) {
6536        // console.log('slow estimate:'+ Math.round(this.slow_.getEstimate()));
6537        // console.log('fast estimate:'+ Math.round(this.fast_.getEstimate()));
6538        // Take the minimum of these two estimates.  This should have the effect of
6539        // adapting down quickly, but up more slowly.
6540        return Math.min(this.fast_.getEstimate(), this.slow_.getEstimate());
6541      } else {
6542        return this.defaultEstimate_;
6543      }
6544    };
6545    _proto.getEstimateTTFB = function getEstimateTTFB() {
6546      if (this.ttfb_.getTotalWeight() >= this.minWeight_) {
6547        return this.ttfb_.getEstimate();
6548      } else {
6549        return this.defaultTTFB_;
6550      }
6551    };
6552    _proto.destroy = function destroy() {};
6553    return EwmaBandWidthEstimator;
6554  }();
6555
6556  /**
6557   * @returns Whether we can detect and validate HDR capability within the window context
6558   */
6559  function isHdrSupported() {
6560    if (typeof matchMedia === 'function') {
6561      var mediaQueryList = matchMedia('(dynamic-range: high)');
6562      var badQuery = matchMedia('bad query');
6563      if (mediaQueryList.media !== badQuery.media) {
6564        return mediaQueryList.matches === true;
6565      }
6566    }
6567    return false;
6568  }
6569
6570  /**
6571   * Sanitizes inputs to return the active video selection options for HDR/SDR.
6572   * When both inputs are null:
6573   *
6574   *    `{ preferHDR: false, allowedVideoRanges: [] }`
6575   *
6576   * When `currentVideoRange` non-null, maintain the active range:
6577   *
6578   *    `{ preferHDR: currentVideoRange !== 'SDR', allowedVideoRanges: [currentVideoRange] }`
6579   *
6580   * When VideoSelectionOption non-null:
6581   *
6582   *  - Allow all video ranges if `allowedVideoRanges` unspecified.
6583   *  - If `preferHDR` is non-null use the value to filter `allowedVideoRanges`.
6584   *  - Else check window for HDR support and set `preferHDR` to the result.
6585   *
6586   * @param currentVideoRange
6587   * @param videoPreference
6588   */
6589  function getVideoSelectionOptions(currentVideoRange, videoPreference) {
6590    var preferHDR = false;
vendor: 14,621 bytes, lines 6591-6906
6591    var allowedVideoRanges = [];
6592    if (currentVideoRange) {
6593      preferHDR = currentVideoRange !== 'SDR';
6594      allowedVideoRanges = [currentVideoRange];
6595    }
6596    if (videoPreference) {
6597      allowedVideoRanges = videoPreference.allowedVideoRanges || VideoRangeValues.slice(0);
6598      var allowAutoPreferHDR = allowedVideoRanges.join('') !== 'SDR' && !videoPreference.videoCodec;
6599      preferHDR = videoPreference.preferHDR !== undefined ? videoPreference.preferHDR : allowAutoPreferHDR && isHdrSupported();
6600      if (!preferHDR) {
6601        allowedVideoRanges = ['SDR'];
6602      }
6603    }
6604    return {
6605      preferHDR: preferHDR,
6606      allowedVideoRanges: allowedVideoRanges
6607    };
6608  }
6609
6610  function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPreference, videoPreference) {
6611    var codecSets = Object.keys(codecTiers);
6612    var channelsPreference = audioPreference == null ? void 0 : audioPreference.channels;
6613    var audioCodecPreference = audioPreference == null ? void 0 : audioPreference.audioCodec;
6614    var videoCodecPreference = videoPreference == null ? void 0 : videoPreference.videoCodec;
6615    var preferStereo = channelsPreference && parseInt(channelsPreference) === 2;
6616    // Use first level set to determine stereo, and minimum resolution and framerate
6617    var hasStereo = false;
6618    var hasCurrentVideoRange = false;
6619    var minHeight = Infinity;
6620    var minFramerate = Infinity;
6621    var minBitrate = Infinity;
6622    var minIndex = Infinity;
6623    var selectedScore = 0;
6624    var videoRanges = [];
6625    var _getVideoSelectionOpt = getVideoSelectionOptions(currentVideoRange, videoPreference),
6626      preferHDR = _getVideoSelectionOpt.preferHDR,
6627      allowedVideoRanges = _getVideoSelectionOpt.allowedVideoRanges;
6628    var _loop = function _loop() {
6629      var tier = codecTiers[codecSets[i]];
6630      hasStereo || (hasStereo = tier.channels[2] > 0);
6631      minHeight = Math.min(minHeight, tier.minHeight);
6632      minFramerate = Math.min(minFramerate, tier.minFramerate);
6633      minBitrate = Math.min(minBitrate, tier.minBitrate);
6634      var matchingVideoRanges = allowedVideoRanges.filter(function (range) {
6635        return tier.videoRanges[range] > 0;
6636      });
6637      if (matchingVideoRanges.length > 0) {
6638        hasCurrentVideoRange = true;
6639      }
6640    };
6641    for (var i = codecSets.length; i--;) {
6642      _loop();
6643    }
6644    minHeight = isFiniteNumber(minHeight) ? minHeight : 0;
6645    minFramerate = isFiniteNumber(minFramerate) ? minFramerate : 0;
6646    var maxHeight = Math.max(1080, minHeight);
6647    var maxFramerate = Math.max(30, minFramerate);
6648    minBitrate = isFiniteNumber(minBitrate) ? minBitrate : currentBw;
6649    currentBw = Math.max(minBitrate, currentBw);
6650    // If there are no variants with matching preference, set currentVideoRange to undefined
6651    if (!hasCurrentVideoRange) {
6652      currentVideoRange = undefined;
6653    }
6654    var hasMultipleSets = codecSets.length > 1;
6655    var codecSet = codecSets.reduce(function (selected, candidate) {
6656      // Remove candiates which do not meet bitrate, default audio, stereo or channels preference, 1080p or lower, 30fps or lower, or SDR/HDR selection if present
6657      var candidateTier = codecTiers[candidate];
6658      if (candidate === selected) {
6659        return selected;
6660      }
6661      videoRanges = hasCurrentVideoRange ? allowedVideoRanges.filter(function (range) {
6662        return candidateTier.videoRanges[range] > 0;
6663      }) : [];
6664      if (hasMultipleSets) {
6665        if (candidateTier.minBitrate > currentBw) {
6666          logStartCodecCandidateIgnored(candidate, "min bitrate of " + candidateTier.minBitrate + " > current estimate of " + currentBw);
6667          return selected;
6668        }
6669        if (!candidateTier.hasDefaultAudio) {
6670          logStartCodecCandidateIgnored(candidate, "no renditions with default or auto-select sound found");
6671          return selected;
6672        }
6673        if (audioCodecPreference && candidate.indexOf(audioCodecPreference.substring(0, 4)) % 5 !== 0) {
6674          logStartCodecCandidateIgnored(candidate, "audio codec preference \"" + audioCodecPreference + "\" not found");
6675          return selected;
6676        }
6677        if (channelsPreference && !preferStereo) {
6678          if (!candidateTier.channels[channelsPreference]) {
6679            logStartCodecCandidateIgnored(candidate, "no renditions with " + channelsPreference + " channel sound found (channels options: " + Object.keys(candidateTier.channels) + ")");
6680            return selected;
6681          }
6682        } else if ((!audioCodecPreference || preferStereo) && hasStereo && candidateTier.channels['2'] === 0) {
6683          logStartCodecCandidateIgnored(candidate, "no renditions with stereo sound found");
6684          return selected;
6685        }
6686        if (candidateTier.minHeight > maxHeight) {
6687          logStartCodecCandidateIgnored(candidate, "min resolution of " + candidateTier.minHeight + " > maximum of " + maxHeight);
6688          return selected;
6689        }
6690        if (candidateTier.minFramerate > maxFramerate) {
6691          logStartCodecCandidateIgnored(candidate, "min framerate of " + candidateTier.minFramerate + " > maximum of " + maxFramerate);
6692          return selected;
6693        }
6694        if (!videoRanges.some(function (range) {
6695          return candidateTier.videoRanges[range] > 0;
6696        })) {
6697          logStartCodecCandidateIgnored(candidate, "no variants with VIDEO-RANGE of " + JSON.stringify(videoRanges) + " found");
6698          return selected;
6699        }
6700        if (videoCodecPreference && candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0) {
6701          logStartCodecCandidateIgnored(candidate, "video codec preference \"" + videoCodecPreference + "\" not found");
6702          return selected;
6703        }
6704        if (candidateTier.maxScore < selectedScore) {
6705          logStartCodecCandidateIgnored(candidate, "max score of " + candidateTier.maxScore + " < selected max of " + selectedScore);
6706          return selected;
6707        }
6708      }
6709      // Remove candiates with less preferred codecs or more errors
6710      if (selected && (codecsSetSelectionPreferenceValue(candidate) >= codecsSetSelectionPreferenceValue(selected) || candidateTier.fragmentError > codecTiers[selected].fragmentError)) {
6711        return selected;
6712      }
6713      minIndex = candidateTier.minIndex;
6714      selectedScore = candidateTier.maxScore;
6715      return candidate;
6716    }, undefined);
6717    return {
6718      codecSet: codecSet,
6719      videoRanges: videoRanges,
6720      preferHDR: preferHDR,
6721      minFramerate: minFramerate,
6722      minBitrate: minBitrate,
6723      minIndex: minIndex
6724    };
6725  }
6726  function logStartCodecCandidateIgnored(codeSet, reason) {
6727    logger.log("[abr] start candidates with \"" + codeSet + "\" ignored because " + reason);
6728  }
6729  function getAudioTracksByGroup(allAudioTracks) {
6730    return allAudioTracks.reduce(function (audioTracksByGroup, track) {
6731      var trackGroup = audioTracksByGroup.groups[track.groupId];
6732      if (!trackGroup) {
6733        trackGroup = audioTracksByGroup.groups[track.groupId] = {
6734          tracks: [],
6735          channels: {
6736            2: 0
6737          },
6738          hasDefault: false,
6739          hasAutoSelect: false
6740        };
6741      }
6742      trackGroup.tracks.push(track);
6743      var channelsKey = track.channels || '2';
6744      trackGroup.channels[channelsKey] = (trackGroup.channels[channelsKey] || 0) + 1;
6745      trackGroup.hasDefault = trackGroup.hasDefault || track.default;
6746      trackGroup.hasAutoSelect = trackGroup.hasAutoSelect || track.autoselect;
6747      if (trackGroup.hasDefault) {
6748        audioTracksByGroup.hasDefaultAudio = true;
6749      }
6750      if (trackGroup.hasAutoSelect) {
6751        audioTracksByGroup.hasAutoSelectAudio = true;
6752      }
6753      return audioTracksByGroup;
6754    }, {
6755      hasDefaultAudio: false,
6756      hasAutoSelectAudio: false,
6757      groups: {}
6758    });
6759  }
6760  function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
6761    return levels.slice(minAutoLevel, maxAutoLevel + 1).reduce(function (tiers, level, index) {
6762      if (!level.codecSet) {
6763        return tiers;
6764      }
6765      var audioGroups = level.audioGroups;
6766      var tier = tiers[level.codecSet];
6767      if (!tier) {
6768        tiers[level.codecSet] = tier = {
6769          minBitrate: Infinity,
6770          minHeight: Infinity,
6771          minFramerate: Infinity,
6772          minIndex: index,
6773          maxScore: 0,
6774          videoRanges: {
6775            SDR: 0
6776          },
6777          channels: {
6778            '2': 0
6779          },
6780          hasDefaultAudio: !audioGroups,
6781          fragmentError: 0
6782        };
6783      }
6784      tier.minBitrate = Math.min(tier.minBitrate, level.bitrate);
6785      var lesserWidthOrHeight = Math.min(level.height, level.width);
6786      tier.minHeight = Math.min(tier.minHeight, lesserWidthOrHeight);
6787      tier.minFramerate = Math.min(tier.minFramerate, level.frameRate);
6788      tier.minIndex = Math.min(tier.minIndex, index);
6789      tier.maxScore = Math.max(tier.maxScore, level.score);
6790      tier.fragmentError += level.fragmentError;
6791      tier.videoRanges[level.videoRange] = (tier.videoRanges[level.videoRange] || 0) + 1;
6792      return tiers;
6793    }, {});
6794  }
6795
6796  var AbrController = /*#__PURE__*/function (_Logger) {
6797    function AbrController(_hls) {
6798      var _this;
6799      _this = _Logger.call(this, 'abr', _hls.logger) || this;
6800      _this.hls = void 0;
6801      _this.lastLevelLoadSec = 0;
6802      _this.lastLoadedFragLevel = -1;
6803      _this.firstSelection = -1;
6804      _this._nextAutoLevel = -1;
6805      _this.nextAutoLevelKey = '';
6806      _this.audioTracksByGroup = null;
6807      _this.codecTiers = null;
6808      _this.timer = -1;
6809      _this.fragCurrent = null;
6810      _this.partCurrent = null;
6811      _this.bitrateTestDelay = 0;
6812      _this.bwEstimator = void 0;
6813      /*
6814          This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
6815          quickly enough to prevent underbuffering
6816        */
6817      _this._abandonRulesCheck = function () {
6818        var _this2 = _this,
6819          frag = _this2.fragCurrent,
6820          part = _this2.partCurrent,
6821          hls = _this2.hls;
6822        var autoLevelEnabled = hls.autoLevelEnabled,
6823          media = hls.media;
6824        if (!frag || !media) {
6825          return;
6826        }
6827        var now = performance.now();
6828        var stats = part ? part.stats : frag.stats;
6829        var duration = part ? part.duration : frag.duration;
6830        var timeLoading = now - stats.loading.start;
6831        var minAutoLevel = hls.minAutoLevel;
6832        // If frag loading is aborted, complete, or from lowest level, stop timer and return
6833        if (stats.aborted || stats.loaded && stats.loaded === stats.total || frag.level <= minAutoLevel) {
6834          _this.clearTimer();
6835          // reset forced auto level value so that next level will be selected
6836          _this._nextAutoLevel = -1;
6837          return;
6838        }
6839
6840        // This check only runs if we're in ABR mode and actually playing
6841        if (!autoLevelEnabled || media.paused || !media.playbackRate || !media.readyState) {
6842          return;
6843        }
6844        var bufferInfo = hls.mainForwardBufferInfo;
6845        if (bufferInfo === null) {
6846          return;
6847        }
6848        var ttfbEstimate = _this.bwEstimator.getEstimateTTFB();
6849        var playbackRate = Math.abs(media.playbackRate);
6850        // To maintain stable adaptive playback, only begin monitoring frag loading after half or more of its playback duration has passed
6851        if (timeLoading <= Math.max(ttfbEstimate, 1000 * (duration / (playbackRate * 2)))) {
6852          return;
6853        }
6854
6855        // bufferStarvationDelay is an estimate of the amount time (in seconds) it will take to exhaust the buffer
6856        var bufferStarvationDelay = bufferInfo.len / playbackRate;
6857        var ttfb = stats.loading.first ? stats.loading.first - stats.loading.start : -1;
6858        var loadedFirstByte = stats.loaded && ttfb > -1;
6859        var bwEstimate = _this.getBwEstimate();
6860        var levels = hls.levels;
6861        var level = levels[frag.level];
6862        var expectedLen = stats.total || Math.max(stats.loaded, Math.round(duration * level.averageBitrate / 8));
6863        var timeStreaming = loadedFirstByte ? timeLoading - ttfb : timeLoading;
6864        if (timeStreaming < 1 && loadedFirstByte) {
6865          timeStreaming = Math.min(timeLoading, stats.loaded * 8 / bwEstimate);
6866        }
6867        var loadRate = loadedFirstByte ? stats.loaded * 1000 / timeStreaming : 0;
6868        // fragLoadDelay is an estimate of the time (in seconds) it will take to buffer the remainder of the fragment
6869        var fragLoadedDelay = loadRate ? (expectedLen - stats.loaded) / loadRate : expectedLen * 8 / bwEstimate + ttfbEstimate / 1000;
6870        // Only downswitch if the time to finish loading the current fragment is greater than the amount of buffer left
6871        if (fragLoadedDelay <= bufferStarvationDelay) {
6872          return;
6873        }
6874        var bwe = loadRate ? loadRate * 8 : bwEstimate;
6875        var fragLevelNextLoadedDelay = Number.POSITIVE_INFINITY;
6876        var nextLoadLevel;
6877        // Iterate through lower level and try to find the largest one that avoids rebuffering
6878        for (nextLoadLevel = frag.level - 1; nextLoadLevel > minAutoLevel; nextLoadLevel--) {
6879          // compute time to load next fragment at lower level
6880          // 8 = bits per byte (bps/Bps)
6881          var levelNextBitrate = levels[nextLoadLevel].maxBitrate;
6882          fragLevelNextLoadedDelay = _this.getTimeToLoadFrag(ttfbEstimate / 1000, bwe, duration * levelNextBitrate, !levels[nextLoadLevel].details);
6883          if (fragLevelNextLoadedDelay < bufferStarvationDelay) {
6884            break;
6885          }
6886        }
6887        // Only emergency switch down if it takes less time to load a new fragment at lowest level instead of continuing
6888        // to load the current one
6889        if (fragLevelNextLoadedDelay >= fragLoadedDelay) {
6890          return;
6891        }
6892
6893        // if estimated load time of new segment is completely unreasonable, ignore and do not emergency switch down
6894        if (fragLevelNextLoadedDelay > duration * 10) {
6895          return;
6896        }
6897        hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel;
6898        if (loadedFirstByte) {
6899          // If there has been loading progress, sample bandwidth using loading time offset by minimum TTFB time
6900          _this.bwEstimator.sample(timeLoading - Math.min(ttfbEstimate, ttfb), stats.loaded);
6901        } else {
6902          // If there has been no loading progress, sample TTFB
6903          _this.bwEstimator.sampleTTFB(timeLoading);
6904        }
6905        var nextLoadLevelBitrate = levels[nextLoadLevel].maxBitrate;
6906        if (_this.getBwEstimate() * _this.hls.config.abrBandWidthUpFactor >
vendor: 15,769 bytes, lines 6906-7237
6906 nextLoadLevelBitrate) {
6907          _this.resetEstimator(nextLoadLevelBitrate);
6908        }
6909        _this.clearTimer();
6910        _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");
6911        hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
6912          frag: frag,
6913          part: part,
6914          stats: stats
6915        });
6916      };
6917      _this.hls = _hls;
6918      _this.bwEstimator = _this.initEstimator();
6919      _this.registerListeners();
6920      return _this;
6921    }
6922    _inheritsLoose(AbrController, _Logger);
6923    var _proto = AbrController.prototype;
6924    _proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
6925      if (abrEwmaDefaultEstimate) {
6926        this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6927        this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
6928      }
6929      this.firstSelection = -1;
6930      this.bwEstimator = this.initEstimator();
6931    };
6932    _proto.initEstimator = function initEstimator() {
6933      var config = this.hls.config;
6934      return new EwmaBandWidthEstimator(config.abrEwmaSlowVoD, config.abrEwmaFastVoD, config.abrEwmaDefaultEstimate);
6935    };
6936    _proto.registerListeners = function registerListeners() {
6937      var hls = this.hls;
6938      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
6939      hls.on(Events.FRAG_LOADING, this.onFragLoading, this);
6940      hls.on(Events.FRAG_LOADED, this.onFragLoaded, this);
6941      hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
6942      hls.on(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
6943      hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
6944      hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
6945      hls.on(Events.MAX_AUTO_LEVEL_UPDATED, this.onMaxAutoLevelUpdated, this);
6946      hls.on(Events.ERROR, this.onError, this);
6947    };
6948    _proto.unregisterListeners = function unregisterListeners() {
6949      var hls = this.hls;
6950      if (!hls) {
6951        return;
6952      }
6953      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
6954      hls.off(Events.FRAG_LOADING, this.onFragLoading, this);
6955      hls.off(Events.FRAG_LOADED, this.onFragLoaded, this);
6956      hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
6957      hls.off(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
6958      hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
6959      hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
6960      hls.off(Events.MAX_AUTO_LEVEL_UPDATED, this.onMaxAutoLevelUpdated, this);
6961      hls.off(Events.ERROR, this.onError, this);
6962    };
6963    _proto.destroy = function destroy() {
6964      this.unregisterListeners();
6965      this.clearTimer();
6966      // @ts-ignore
6967      this.hls = this._abandonRulesCheck = null;
6968      this.fragCurrent = this.partCurrent = null;
6969    };
6970    _proto.onManifestLoading = function onManifestLoading(event, data) {
6971      this.lastLoadedFragLevel = -1;
6972      this.firstSelection = -1;
6973      this.lastLevelLoadSec = 0;
6974      this.fragCurrent = this.partCurrent = null;
6975      this.onLevelsUpdated();
6976      this.clearTimer();
6977    };
6978    _proto.onLevelsUpdated = function onLevelsUpdated() {
6979      if (this.lastLoadedFragLevel > -1 && this.fragCurrent) {
6980        this.lastLoadedFragLevel = this.fragCurrent.level;
6981      }
6982      this._nextAutoLevel = -1;
6983      this.onMaxAutoLevelUpdated();
6984      this.codecTiers = null;
6985      this.audioTracksByGroup = null;
6986    };
6987    _proto.onMaxAutoLevelUpdated = function onMaxAutoLevelUpdated() {
6988      this.firstSelection = -1;
6989      this.nextAutoLevelKey = '';
6990    };
6991    _proto.onFragLoading = function onFragLoading(event, data) {
6992      var frag = data.frag;
6993      if (this.ignoreFragment(frag)) {
6994        return;
6995      }
6996      if (!frag.bitrateTest) {
6997        var _data$part;
6998        this.fragCurrent = frag;
6999        this.partCurrent = (_data$part = data.part) != null ? _data$part : null;
7000      }
7001      this.clearTimer();
7002      this.timer = self.setInterval(this._abandonRulesCheck, 100);
7003    };
7004    _proto.onLevelSwitching = function onLevelSwitching(event, data) {
7005      this.clearTimer();
7006    };
7007    _proto.onError = function onError(event, data) {
7008      if (data.fatal) {
7009        return;
7010      }
7011      switch (data.details) {
7012        case ErrorDetails.BUFFER_ADD_CODEC_ERROR:
7013        case ErrorDetails.BUFFER_APPEND_ERROR:
7014          // Reset last loaded level so that a new selection can be made after calling recoverMediaError
7015          this.lastLoadedFragLevel = -1;
7016          this.firstSelection = -1;
7017          break;
7018        case ErrorDetails.FRAG_LOAD_TIMEOUT:
7019          {
7020            var frag = data.frag;
7021            var fragCurrent = this.fragCurrent,
7022              part = this.partCurrent;
7023            if (frag && fragCurrent && frag.sn === fragCurrent.sn && frag.level === fragCurrent.level) {
7024              var now = performance.now();
7025              var stats = part ? part.stats : frag.stats;
7026              var timeLoading = now - stats.loading.start;
7027              var ttfb = stats.loading.first ? stats.loading.first - stats.loading.start : -1;
7028              var loadedFirstByte = stats.loaded && ttfb > -1;
7029              if (loadedFirstByte) {
7030                var ttfbEstimate = this.bwEstimator.getEstimateTTFB();
7031                this.bwEstimator.sample(timeLoading - Math.min(ttfbEstimate, ttfb), stats.loaded);
7032              } else {
7033                this.bwEstimator.sampleTTFB(timeLoading);
7034              }
7035            }
7036            break;
7037          }
7038      }
7039    };
7040    _proto.getTimeToLoadFrag = function getTimeToLoadFrag(timeToFirstByteSec, bandwidth, fragSizeBits, isSwitch) {
7041      var fragLoadSec = timeToFirstByteSec + fragSizeBits / bandwidth;
7042      var playlistLoadSec = isSwitch ? this.lastLevelLoadSec : 0;
7043      return fragLoadSec + playlistLoadSec;
7044    };
7045    _proto.onLevelLoaded = function onLevelLoaded(event, data) {
7046      var config = this.hls.config;
7047      var loading = data.stats.loading;
7048      var timeLoadingMs = loading.end - loading.start;
7049      if (isFiniteNumber(timeLoadingMs)) {
7050        this.lastLevelLoadSec = timeLoadingMs / 1000;
7051      }
7052      if (data.details.live) {
7053        this.bwEstimator.update(config.abrEwmaSlowLive, config.abrEwmaFastLive);
7054      } else {
7055        this.bwEstimator.update(config.abrEwmaSlowVoD, config.abrEwmaFastVoD);
7056      }
7057    };
7058    _proto.onFragLoaded = function onFragLoaded(event, _ref) {
7059      var frag = _ref.frag,
7060        part = _ref.part;
7061      var stats = part ? part.stats : frag.stats;
7062      if (frag.type === PlaylistLevelType.MAIN) {
7063        this.bwEstimator.sampleTTFB(stats.loading.first - stats.loading.start);
7064      }
7065      if (this.ignoreFragment(frag)) {
7066        return;
7067      }
7068      // stop monitoring bw once frag loaded
7069      this.clearTimer();
7070      // reset forced auto level value so that next level will be selected
7071      if (frag.level === this._nextAutoLevel) {
7072        this._nextAutoLevel = -1;
7073      }
7074      this.firstSelection = -1;
7075
7076      // compute level average bitrate
7077      if (this.hls.config.abrMaxWithRealBitrate) {
7078        var duration = part ? part.duration : frag.duration;
7079        var level = this.hls.levels[frag.level];
7080        var loadedBytes = (level.loaded ? level.loaded.bytes : 0) + stats.loaded;
7081        var loadedDuration = (level.loaded ? level.loaded.duration : 0) + duration;
7082        level.loaded = {
7083          bytes: loadedBytes,
7084          duration: loadedDuration
7085        };
7086        level.realBitrate = Math.round(8 * loadedBytes / loadedDuration);
7087      }
7088      if (frag.bitrateTest) {
7089        var fragBufferedData = {
7090          stats: stats,
7091          frag: frag,
7092          part: part,
7093          id: frag.type
7094        };
7095        this.onFragBuffered(Events.FRAG_BUFFERED, fragBufferedData);
7096        frag.bitrateTest = false;
7097      } else {
7098        // store level id after successful fragment load for playback
7099        this.lastLoadedFragLevel = frag.level;
7100      }
7101    };
7102    _proto.onFragBuffered = function onFragBuffered(event, data) {
7103      var frag = data.frag,
7104        part = data.part;
7105      var stats = part != null && part.stats.loaded ? part.stats : frag.stats;
7106      if (stats.aborted) {
7107        return;
7108      }
7109      if (this.ignoreFragment(frag)) {
7110        return;
7111      }
7112      // Use the difference between parsing and request instead of buffering and request to compute fragLoadingProcessing;
7113      // rationale is that buffer appending only happens once media is attached. This can happen when config.startFragPrefetch
7114      // is used. If we used buffering in that case, our BW estimate sample will be very large.
7115      var processingMs = stats.parsing.end - stats.loading.start - Math.min(stats.loading.first - stats.loading.start, this.bwEstimator.getEstimateTTFB());
7116      this.bwEstimator.sample(processingMs, stats.loaded);
7117      stats.bwEstimate = this.getBwEstimate();
7118      if (frag.bitrateTest) {
7119        this.bitrateTestDelay = processingMs / 1000;
7120      } else {
7121        this.bitrateTestDelay = 0;
7122      }
7123    };
7124    _proto.ignoreFragment = function ignoreFragment(frag) {
7125      // Only count non-alt-audio frags which were actually buffered in our BW calculations
7126      return frag.type !== PlaylistLevelType.MAIN || frag.sn === 'initSegment';
7127    };
7128    _proto.clearTimer = function clearTimer() {
7129      if (this.timer > -1) {
7130        self.clearInterval(this.timer);
7131        this.timer = -1;
7132      }
7133    };
7134    _proto.getAutoLevelKey = function getAutoLevelKey() {
7135      return this.getBwEstimate() + "_" + this.getStarvationDelay().toFixed(2);
7136    };
7137    _proto.getNextABRAutoLevel = function getNextABRAutoLevel() {
7138      var fragCurrent = this.fragCurrent,
7139        partCurrent = this.partCurrent,
7140        hls = this.hls;
7141      if (hls.levels.length <= 1) {
7142        return hls.loadLevel;
7143      }
7144      var maxAutoLevel = hls.maxAutoLevel,
7145        config = hls.config,
7146        minAutoLevel = hls.minAutoLevel;
7147      var currentFragDuration = partCurrent ? partCurrent.duration : fragCurrent ? fragCurrent.duration : 0;
7148      var avgbw = this.getBwEstimate();
7149      // bufferStarvationDelay is the wall-clock time left until the playback buffer is exhausted.
7150      var bufferStarvationDelay = this.getStarvationDelay();
7151      var bwFactor = config.abrBandWidthFactor;
7152      var bwUpFactor = config.abrBandWidthUpFactor;
7153
7154      // First, look to see if we can find a level matching with our avg bandwidth AND that could also guarantee no rebuffering at all
7155      if (bufferStarvationDelay) {
7156        var _bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, 0, bwFactor, bwUpFactor);
7157        if (_bestLevel >= 0) {
7158          return _bestLevel;
7159        }
7160      }
7161      // not possible to get rid of rebuffering... try to find level that will guarantee less than maxStarvationDelay of rebuffering
7162      var maxStarvationDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxStarvationDelay) : config.maxStarvationDelay;
7163      if (!bufferStarvationDelay) {
7164        // in case buffer is empty, let's check if previous fragment was loaded to perform a bitrate test
7165        var bitrateTestDelay = this.bitrateTestDelay;
7166        if (bitrateTestDelay) {
7167          // if it is the case, then we need to adjust our max starvation delay using maxLoadingDelay config value
7168          // max video loading delay used in  automatic start level selection :
7169          // in that mode ABR controller will ensure that video loading time (ie the time to fetch the first fragment at lowest quality level +
7170          // the time to fetch the fragment at the appropriate quality level is less than ```maxLoadingDelay``` )
7171          // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
7172          var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
7173          maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
7174          this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
7175          // don't use conservative factor on bitrate test
7176          bwFactor = bwUpFactor = 1;
7177        }
7178      }
7179      var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
7180      this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
7181      if (bestLevel > -1) {
7182        return bestLevel;
7183      }
7184      // If no matching level found, see if min auto level would be a better option
7185      var minLevel = hls.levels[minAutoLevel];
7186      var autoLevel = hls.levels[hls.loadLevel];
7187      if ((minLevel == null ? void 0 : minLevel.bitrate) < (autoLevel == null ? void 0 : autoLevel.bitrate)) {
7188        return minAutoLevel;
7189      }
7190      // or if bitrate is not lower, continue to use loadLevel
7191      return hls.loadLevel;
7192    };
7193    _proto.getStarvationDelay = function getStarvationDelay() {
7194      var hls = this.hls;
7195      var media = hls.media;
7196      if (!media) {
7197        return Infinity;
7198      }
7199      // playbackRate is the absolute value of the playback rate; if media.playbackRate is 0, we use 1 to load as
7200      // if we're playing back at the normal rate.
7201      var playbackRate = media && media.playbackRate !== 0 ? Math.abs(media.playbackRate) : 1.0;
7202      var bufferInfo = hls.mainForwardBufferInfo;
7203      return (bufferInfo ? bufferInfo.len : 0) / playbackRate;
7204    };
7205    _proto.getBwEstimate = function getBwEstimate() {
7206      return this.bwEstimator.canEstimate() ? this.bwEstimator.getEstimate() : this.hls.config.abrEwmaDefaultEstimate;
7207    };
7208    _proto.findBestLevel = function findBestLevel(currentBw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor) {
7209      var _level$details,
7210        _this3 = this;
7211      var maxFetchDuration = bufferStarvationDelay + maxStarvationDelay;
7212      var lastLoadedFragLevel = this.lastLoadedFragLevel;
7213      var selectionBaseLevel = lastLoadedFragLevel === -1 ? this.hls.firstLevel : lastLoadedFragLevel;
7214      var fragCurrent = this.fragCurrent,
7215        partCurrent = this.partCurrent;
7216      var _this$hls = this.hls,
7217        levels = _this$hls.levels,
7218        allAudioTracks = _this$hls.allAudioTracks,
7219        loadLevel = _this$hls.loadLevel,
7220        config = _this$hls.config;
7221      if (levels.length === 1) {
7222        return 0;
7223      }
7224      var level = levels[selectionBaseLevel];
7225      var live = !!(level != null && (_level$details = level.details) != null && _level$details.live);
7226      var firstSelection = loadLevel === -1 || lastLoadedFragLevel === -1;
7227      var currentCodecSet;
7228      var currentVideoRange = 'SDR';
7229      var currentFrameRate = (level == null ? void 0 : level.frameRate) || 0;
7230      var audioPreference = config.audioPreference,
7231        videoPreference = config.videoPreference;
7232      var audioTracksByGroup = this.audioTracksByGroup || (this.audioTracksByGroup = getAudioTracksByGroup(allAudioTracks));
7233      var minStartIndex = -1;
7234      if (firstSelection) {
7235        if (this.firstSelection !== -1) {
7236          return this.firstSelection;
7237        }
7238        var codecTiers = this.codecTiers || (this.codecTiers = getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel));
7239        var startTier = getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPreference, videoPreference);
7240        var codecSet = startTier.codecSet,
7241          videoRanges = startTier.videoRanges,
7242          minFramerate = startTier.minFramerate,
7243          minBitrate = startTier.minBitrate,
7244          minIndex = startTier.minIndex,
7245          preferHDR = startTier.preferHDR;
7246        minStartIndex = minIndex;
7247        currentCodecSet = codecSet;
7248        currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
7249        currentFrameRate = minFramerate;
7250        currentBw = Math.max(currentBw, minBitrate);
7251        this.log("picked start tier " + JSON.stringify(startTier));
7252      } else {
7253        currentCodecSet = level == null ? void 0 : level.codecSet;
7254        currentVideoRange = level == null ? void 0 : level.videoRange;
7255      }
7256      var currentFragDuration = partCurrent ? partCurrent.duration : fragCurrent ? fragCurrent.duration : 0;
7257      var ttfbEstimateSec = this.bwEstimator.getEstimateTTFB() / 1000;
7258      var levelsSkipped = [];
7259      var _loop = function _loop() {
7260          var _levelInfo$supportedR;
7261          var levelInfo = levels[i];
7262          var upSwitch = i > selectionBaseLevel;
7263          if (!levelInfo) {
7264            return 0; // continue
7265          }
7266
7267          // skip candidates which change codec-family or video-range,
7268          // and which decrease or increase frame-rate for up and down-switch respectfully
7269          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)) {
7270            if (!firstSelection || i !== minStartIndex) {
7271              levelsSkipped.push(i);
7272              return 0; // continue
7273            }
7274          }
7275          var levelDetails = levelInfo.details;
7276          var avgDuration = (partCurrent ? levelDetails == null ? void 0 : levelDetails.partTarget : levelDetails == null ? void 0 : levelDetails.averagetargetduration) || currentFragDuration;
7277          var adjustedbw;
7278          // follow algorithm captured from stagefright :
7279          // https://android.googlesource.com/platform/frameworks/av/+/master/media/libstagefright/httplive/LiveSession.cpp
7280          // Pick the highest bandwidth stream below or equal to estimated bandwidth.
7281          // consider only 80% of the available bandwidth, but if we are switching up,
7282          // be even more conservative (70%) to avoid overestimating and immediately
7283          // switching back.
7284          if (!upSwitch) {
7285            adjustedbw = bwFactor * currentBw;
7286          } else {
7287            adjustedbw = bwUpFactor * currentBw;
7288          }
7289
7290          // Use average bitrate when starvation delay (buffer length) is gt or eq two segment durations and rebuffering is not expected (maxStarvationDelay > 0)
7291          var bitrate = currentFragDuration && bufferStarvationDelay >= currentFragDuration * 2 && maxStarvationDelay === 0 ? levels[i].averageBitrate : levels[i].maxBitrate;
7292          var fetchDuration = _this3.getTimeToLoadFrag(ttfbEstimateSec, adjustedbw, bitrate * avgDuration, levelDetails === undefined);
7293          var canSwitchWithinTolerance =
vendor: 12,074 bytes, lines 7294-7593
7294          // if adjusted bw is greater than level bitrate AND
7295          adjustedbw >= bitrate && (
7296          // no level change, or new level has no error history
7297          i === lastLoadedFragLevel || levelInfo.loadError === 0 && levelInfo.fragmentError === 0) && (
7298          // fragment fetchDuration unknown OR live stream OR fragment fetchDuration less than max allowed fetch duration, then this level matches
7299          // we don't account for max Fetch Duration for live streams, this is to avoid switching down when near the edge of live sliding window ...
7300          // special case to support startLevel = -1 (bitrateTest) on live streams : in that case we should not exit loop so that findBestLevel will return -1
7301          fetchDuration <= ttfbEstimateSec || !isFiniteNumber(fetchDuration) || live && !_this3.bitrateTestDelay || fetchDuration < maxFetchDuration);
7302          if (canSwitchWithinTolerance) {
7303            var forcedAutoLevel = _this3.forcedAutoLevel;
7304            if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
7305              if (levelsSkipped.length) {
7306                _this3.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);
7307              }
7308              _this3.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:" + levelInfo.codecSet + " videoRange:" + levelInfo.videoRange + " hls.loadLevel:" + loadLevel);
7309            }
7310            if (firstSelection) {
7311              _this3.firstSelection = i;
7312            }
7313            // as we are looping from highest to lowest, this will return the best achievable quality level
7314            return {
7315              v: i
7316            };
7317          }
7318        },
7319        _ret;
7320      for (var i = maxAutoLevel; i >= minAutoLevel; i--) {
7321        _ret = _loop();
7322        if (_ret === 0) continue;
7323        if (_ret) return _ret.v;
7324      }
7325      // not enough time budget even with quality level 0 ... rebuffering might happen
7326      return -1;
7327    };
7328    return _createClass(AbrController, [{
7329      key: "firstAutoLevel",
7330      get: function get() {
7331        var _this$hls2 = this.hls,
7332          maxAutoLevel = _this$hls2.maxAutoLevel,
7333          minAutoLevel = _this$hls2.minAutoLevel;
7334        var bwEstimate = this.getBwEstimate();
7335        var maxStartDelay = this.hls.config.maxStarvationDelay;
7336        var abrAutoLevel = this.findBestLevel(bwEstimate, minAutoLevel, maxAutoLevel, 0, maxStartDelay, 1, 1);
7337        if (abrAutoLevel > -1) {
7338          return abrAutoLevel;
7339        }
7340        var firstLevel = this.hls.firstLevel;
7341        var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
7342        this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
7343        return clamped;
7344      }
7345    }, {
7346      key: "forcedAutoLevel",
7347      get: function get() {
7348        if (this.nextAutoLevelKey) {
7349          return -1;
7350        }
7351        return this._nextAutoLevel;
7352      }
7353
7354      // return next auto level
7355    }, {
7356      key: "nextAutoLevel",
7357      get: function get() {
7358        var forcedAutoLevel = this.forcedAutoLevel;
7359        var bwEstimator = this.bwEstimator;
7360        var useEstimate = bwEstimator.canEstimate();
7361        var loadedFirstFrag = this.lastLoadedFragLevel > -1;
7362        // in case next auto level has been forced, and bw not available or not reliable, return forced value
7363        if (forcedAutoLevel !== -1 && (!useEstimate || !loadedFirstFrag || this.nextAutoLevelKey === this.getAutoLevelKey())) {
7364          return forcedAutoLevel;
7365        }
7366
7367        // compute next level using ABR logic
7368        var nextABRAutoLevel = useEstimate && loadedFirstFrag ? this.getNextABRAutoLevel() : this.firstAutoLevel;
7369
7370        // use forced auto level while it hasn't errored more than ABR selection
7371        if (forcedAutoLevel !== -1) {
7372          var levels = this.hls.levels;
7373          if (levels.length > Math.max(forcedAutoLevel, nextABRAutoLevel) && levels[forcedAutoLevel].loadError <= levels[nextABRAutoLevel].loadError) {
7374            return forcedAutoLevel;
7375          }
7376        }
7377
7378        // save result until state has changed
7379        this._nextAutoLevel = nextABRAutoLevel;
7380        this.nextAutoLevelKey = this.getAutoLevelKey();
7381        return nextABRAutoLevel;
7382      },
7383      set: function set(nextLevel) {
7384        var _this$hls3 = this.hls,
7385          maxAutoLevel = _this$hls3.maxAutoLevel,
7386          minAutoLevel = _this$hls3.minAutoLevel;
7387        var value = Math.min(Math.max(nextLevel, minAutoLevel), maxAutoLevel);
7388        if (this._nextAutoLevel !== value) {
7389          this.nextAutoLevelKey = '';
7390          this._nextAutoLevel = value;
7391        }
7392      }
7393    }]);
7394  }(Logger);
7395
7396  /**
7397   * Provides methods dealing with buffer length retrieval for example.
7398   *
7399   * In general, a helper around HTML5 MediaElement TimeRanges gathered from `buffered` property.
7400   *
7401   * Also @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/buffered
7402   */
7403
7404  var noopBuffered = {
7405    length: 0,
7406    start: function start() {
7407      return 0;
7408    },
7409    end: function end() {
7410      return 0;
7411    }
7412  };
7413  var BufferHelper = /*#__PURE__*/function () {
7414    function BufferHelper() {}
7415    /**
7416     * Return true if `media`'s buffered include `position`
7417     */
7418    BufferHelper.isBuffered = function isBuffered(media, position) {
7419      if (media) {
7420        var buffered = BufferHelper.getBuffered(media);
7421        for (var i = buffered.length; i--;) {
7422          if (position >= buffered.start(i) && position <= buffered.end(i)) {
7423            return true;
7424          }
7425        }
7426      }
7427      return false;
7428    };
7429    BufferHelper.bufferInfo = function bufferInfo(media, pos, maxHoleDuration) {
7430      if (media) {
7431        var vbuffered = BufferHelper.getBuffered(media);
7432        if (vbuffered.length) {
7433          var buffered = [];
7434          for (var i = 0; i < vbuffered.length; i++) {
7435            buffered.push({
7436              start: vbuffered.start(i),
7437              end: vbuffered.end(i)
7438            });
7439          }
7440          return BufferHelper.bufferedInfo(buffered, pos, maxHoleDuration);
7441        }
7442      }
7443      return {
7444        len: 0,
7445        start: pos,
7446        end: pos,
7447        nextStart: undefined
7448      };
7449    };
7450    BufferHelper.bufferedInfo = function bufferedInfo(buffered, pos, maxHoleDuration) {
7451      pos = Math.max(0, pos);
7452      // sort on buffer.start/smaller end (IE does not always return sorted buffered range)
7453      buffered.sort(function (a, b) {
7454        return a.start - b.start || b.end - a.end;
7455      });
7456      var buffered2 = [];
7457      if (maxHoleDuration) {
7458        // there might be some small holes between buffer time range
7459        // consider that holes smaller than maxHoleDuration are irrelevant and build another
7460        // buffer time range representations that discards those holes
7461        for (var i = 0; i < buffered.length; i++) {
7462          var buf2len = buffered2.length;
7463          if (buf2len) {
7464            var buf2end = buffered2[buf2len - 1].end;
7465            // if small hole (value between 0 or maxHoleDuration ) or overlapping (negative)
7466            if (buffered[i].start - buf2end < maxHoleDuration) {
7467              // merge overlapping time ranges
7468              // update lastRange.end only if smaller than item.end
7469              // e.g.  [ 1, 15] with  [ 2,8] => [ 1,15] (no need to modify lastRange.end)
7470              // whereas [ 1, 8] with  [ 2,15] => [ 1,15] ( lastRange should switch from [1,8] to [1,15])
7471              if (buffered[i].end > buf2end) {
7472                buffered2[buf2len - 1].end = buffered[i].end;
7473              }
7474            } else {
7475              // big hole
7476              buffered2.push(buffered[i]);
7477            }
7478          } else {
7479            // first value
7480            buffered2.push(buffered[i]);
7481          }
7482        }
7483      } else {
7484        buffered2 = buffered;
7485      }
7486      var bufferLen = 0;
7487
7488      // bufferStartNext can possibly be undefined based on the conditional logic below
7489      var bufferStartNext;
7490
7491      // bufferStart and bufferEnd are buffer boundaries around current video position
7492      var bufferStart = pos;
7493      var bufferEnd = pos;
7494      for (var _i = 0; _i < buffered2.length; _i++) {
7495        var start = buffered2[_i].start;
7496        var end = buffered2[_i].end;
7497        // logger.log('buf start/end:' + buffered.start(i) + '/' + buffered.end(i));
7498        if (pos + maxHoleDuration >= start && pos < end) {
7499          // play position is inside this buffer TimeRange, retrieve end of buffer position and buffer length
7500          bufferStart = start;
7501          bufferEnd = end;
7502          bufferLen = bufferEnd - pos;
7503        } else if (pos + maxHoleDuration < start) {
7504          bufferStartNext = start;
7505          break;
7506        }
7507      }
7508      return {
7509        len: bufferLen,
7510        start: bufferStart || 0,
7511        end: bufferEnd || 0,
7512        nextStart: bufferStartNext
7513      };
7514    }
7515
7516    /**
7517     * Safe method to get buffered property.
7518     * SourceBuffer.buffered may throw if SourceBuffer is removed from it's MediaSource
7519     */;
7520    BufferHelper.getBuffered = function getBuffered(media) {
7521      try {
7522        return media.buffered || noopBuffered;
7523      } catch (e) {
7524        logger.log('failed to get media.buffered', e);
7525        return noopBuffered;
7526      }
7527    };
7528    return BufferHelper;
7529  }();
7530
7531  var BufferOperationQueue = /*#__PURE__*/function () {
7532    function BufferOperationQueue(sourceBufferReference) {
7533      this.buffers = void 0;
7534      this.queues = {
7535        video: [],
7536        audio: [],
7537        audiovideo: []
7538      };
7539      this.buffers = sourceBufferReference;
7540    }
7541    var _proto = BufferOperationQueue.prototype;
7542    _proto.append = function append(operation, type, pending) {
7543      var queue = this.queues[type];
7544      queue.push(operation);
7545      if (queue.length === 1 && !pending) {
7546        this.executeNext(type);
7547      }
7548    };
7549    _proto.appendBlocker = function appendBlocker(type) {
7550      var _this = this;
7551      return new Promise(function (resolve) {
7552        var operation = {
7553          execute: resolve,
7554          onStart: function onStart() {},
7555          onComplete: function onComplete() {},
7556          onError: function onError() {}
7557        };
7558        _this.append(operation, type);
7559      });
7560    };
7561    _proto.unblockAudio = function unblockAudio(op) {
7562      var queue = this.queues.audio;
7563      if (queue[0] === op) {
7564        this.shiftAndExecuteNext('audio');
7565      }
7566    };
7567    _proto.executeNext = function executeNext(type) {
7568      var queue = this.queues[type];
7569      if (queue.length) {
7570        var operation = queue[0];
7571        try {
7572          // Operations are expected to result in an 'updateend' event being fired. If not, the queue will lock. Operations
7573          // which do not end with this event must call _onSBUpdateEnd manually
7574          operation.execute();
7575        } catch (error) {
7576          logger.warn("[buffer-operation-queue]: Exception executing \"" + type + "\" SourceBuffer operation: " + error);
7577          operation.onError(error);
7578
7579          // Only shift the current operation off, otherwise the updateend handler will do this for us
7580          var sb = this.buffers[type];
7581          if (!(sb != null && sb.updating)) {
7582            this.shiftAndExecuteNext(type);
7583          }
7584        }
7585      }
7586    };
7587    _proto.shiftAndExecuteNext = function shiftAndExecuteNext(type) {
7588      this.queues[type].shift();
7589      this.executeNext(type);
7590    };
7591    _proto.current = function current(type) {
7592      return this.queues[type][0];
7593    };
vendor: 4,650 bytes, lines 7594-7711
7594    return BufferOperationQueue;
7595  }();
7596
7597  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
7598  var BufferController = /*#__PURE__*/function (_Logger) {
7599    function BufferController(hls, fragmentTracker) {
7600      var _this;
7601      _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
7602      // The level details used to determine duration, target-duration and live
7603      _this.details = null;
7604      // cache the self generated object url to detect hijack of video tag
7605      _this._objectUrl = null;
7606      // A queue of buffer operations which require the SourceBuffer to not be updating upon execution
7607      _this.operationQueue = void 0;
7608      // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
7609      _this.listeners = void 0;
7610      _this.hls = void 0;
7611      _this.fragmentTracker = void 0;
7612      // The number of BUFFER_CODEC events received before any sourceBuffers are created
7613      _this.bufferCodecEventsExpected = 0;
7614      // The total number of BUFFER_CODEC events received
7615      _this._bufferCodecEventsTotal = 0;
7616      // A reference to the attached media element
7617      _this.media = null;
7618      // A reference to the active media source
7619      _this.mediaSource = null;
7620      // Last MP3 audio chunk appended
7621      _this.lastMpegAudioChunk = null;
7622      // Audio fragment blocked from appending until corresponding video appends or context changes
7623      _this.blockedAudioAppend = null;
7624      // Keep track of video append position for unblocking audio
7625      _this.lastVideoAppendEnd = 0;
7626      _this.appendSource = void 0;
7627      // counters
7628      _this.appendErrors = {
7629        audio: 0,
7630        video: 0,
7631        audiovideo: 0
7632      };
7633      _this.tracks = {};
7634      _this.pendingTracks = {};
7635      _this.sourceBuffer = void 0;
7636      _this._onEndStreaming = function (event) {
7637        if (!_this.hls) {
7638          return;
7639        }
7640        _this.hls.pauseBuffering();
7641      };
7642      _this._onStartStreaming = function (event) {
7643        if (!_this.hls) {
7644          return;
7645        }
7646        _this.hls.resumeBuffering();
7647      };
7648      // Keep as arrow functions so that we can directly reference these functions directly as event listeners
7649      _this._onMediaSourceOpen = function () {
7650        var _this2 = _this,
7651          media = _this2.media,
7652          mediaSource = _this2.mediaSource;
7653        _this.log('Media source opened');
7654        if (media) {
7655          media.removeEventListener('emptied', _this._onMediaEmptied);
7656          var durationAndRange = _this.getDurationAndRange();
7657          if (durationAndRange) {
7658            _this.updateMediaSource(durationAndRange);
7659          }
7660          _this.hls.trigger(Events.MEDIA_ATTACHED, {
7661            media: media,
7662            mediaSource: mediaSource
7663          });
7664        }
7665        if (mediaSource) {
7666          // once received, don't listen anymore to sourceopen event
7667          mediaSource.removeEventListener('sourceopen', _this._onMediaSourceOpen);
7668        }
7669        _this.checkPendingTracks();
7670      };
7671      _this._onMediaSourceClose = function () {
7672        _this.log('Media source closed');
7673      };
7674      _this._onMediaSourceEnded = function () {
7675        _this.log('Media source ended');
7676      };
7677      _this._onMediaEmptied = function () {
7678        var _this3 = _this,
7679          mediaSrc = _this3.mediaSrc,
7680          _objectUrl = _this3._objectUrl;
7681        if (mediaSrc !== _objectUrl) {
7682          _this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7683        }
7684      };
7685      _this.hls = hls;
7686      _this.fragmentTracker = fragmentTracker;
7687      _this.appendSource = isManagedMediaSource(getMediaSource(hls.config.preferManagedMediaSource));
7688      _this._initSourceBuffer();
7689      _this.registerListeners();
7690      return _this;
7691    }
7692    _inheritsLoose(BufferController, _Logger);
7693    var _proto = BufferController.prototype;
7694    _proto.hasSourceTypes = function hasSourceTypes() {
7695      return this.getSourceBufferTypes().length > 0 || Object.keys(this.pendingTracks).length > 0;
7696    };
7697    _proto.destroy = function destroy() {
7698      this.unregisterListeners();
7699      this.details = null;
7700      this.lastMpegAudioChunk = null;
7701      // @ts-ignore
7702      this.hls = this.fragmentTracker = null;
7703      // @ts-ignore
7704      this._onMediaSourceOpen = this._onMediaSourceClose = null;
7705      // @ts-ignore
7706      this._onMediaSourceEnded = null;
7707      // @ts-ignore
7708      this._onStartStreaming = this._onEndStreaming = null;
7709    };
7710    _proto.registerListeners = function registerListeners() {
7711      var hls = this.hls;
7712      hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
7713      hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
7714      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
7715      hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
7716      hls.on(Events.BUFFER_RESET, this.onBufferReset, this);
7717      hls.on(Events.BUFFER_APPENDING, this.onBufferAppending, this);
7718      hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this);
7719      hls.on(Events.BUFFER_EOS, this.onBufferEos, this);
7720      hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
7721      hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
7722      hls.on(Events.FRAG_PARSED, this.onFragParsed, this);
7723      hls.on(Events.FRAG_CHANGED, this.onFragChanged, this);
7724      hls.on(Events.ERROR, this.onError, this);
7725    };
7726    _proto.unregisterListeners = function unregisterListeners() {
7727      var hls = this.hls;
7728      hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
7729      hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
7730      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
7731      hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
7732      hls.off(Events.BUFFER_RESET, this.onBufferReset, this);
7733      hls.off(Events.BUFFER_APPENDING, this.onBufferAppending, this);
7734      hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this);
7735      hls.off(Events.BUFFER_EOS, this.onBufferEos, this);
7736      hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
7737      hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
7738      hls.off(Events.FRAG_PARSED, this.onFragParsed, this);
7739      hls.off(Events.FRAG_CHANGED, this.onFragChanged, this);
7740      hls.off(Events.ERROR, this.onError, this);
7741    };
7742    _proto._initSourceBuffer = function _initSourceBuffer() {
7743      this.sourceBuffer = {};
7744      this.operationQueue = new BufferOperationQueue(this.sourceBuffer);
7745      this.listeners = {
7746        audio: [],
7747        video: [],
7748        audiovideo: []
7749      };
7750      this.resetAppendErrors();
7751      this.lastMpegAudioChunk = null;
7752      this.blockedAudioAppend = null;
7753      this.lastVideoAppendEnd = 0;
7754    };
7755    _proto.onManifestLoading = function onManifestLoading() {
7756      this.bufferCodecEventsExpected = this._bufferCodecEventsTotal = 0;
7757      this.details = null;
7758    };
7759    _proto.onManifestParsed = function onManifestParsed(event, data) {
7760      // in case of alt audio 2 BUFFER_CODECS events will be triggered, one per stream controller
7761      // sourcebuffers will be created all at once when the expected nb of tracks will be reached
7762      // in case alt audio is not used, only one BUFFER_CODEC event will be fired from main stream controller
7763      // it will contain the expected nb of source buffers, no need to compute it
7764      var codecEvents = 2;
7765      if (data.audio && !data.video || !data.altAudio || !false) {
7766        codecEvents = 1;
7767      }
7768      this.bufferCodecEventsExpected = this._bufferCodecEventsTotal = codecEvents;
7769      this.log(this.bufferCodecEventsExpected + " bufferCodec event(s) expected");
7770    };
7771    _proto.onMediaAttaching = function onMediaAttaching(event, data) {
7772      var media = this.media = data.media;
7773      var MediaSource = getMediaSource(this.appendSource);
7774      if (media && MediaSource) {
7775        var _ms$constructor;
7776        var ms = this.mediaSource = new MediaSource();
7777        this.log("created media source: " + ((_ms$constructor = ms.constructor) == null ? void 0 : _ms$constructor.name));
7778        // MediaSource listeners are arrow functions with a lexical scope, and do not need to be bound
7779        ms.addEventListener('sourceopen', this._onMediaSourceOpen);
7780        ms.addEventListener('sourceended', this._onMediaSourceEnded);
7781        ms.addEventListener('sourceclose', this._onMediaSourceClose);
7782        if (this.appendSource) {
7783          ms.addEventListener('startstreaming', this._onStartStreaming);
7784          ms.addEventListener('endstreaming', this._onEndStreaming);
7785        }
7786
7787        // cache the locally generated object url
7788        var objectUrl = this._objectUrl = self.URL.createObjectURL(ms);
7789        // link video and media Source
7790        if (this.appendSource) {
7791          try {
7792            media.removeAttribute('src');
7793            // ManagedMediaSource will not open without disableRemotePlayback set to false or source alternatives
7794            var MMS = self.ManagedMediaSource;
7795            media.disableRemotePlayback = media.disableRemotePlayback || MMS && ms instanceof MMS;
7796            removeSourceChildren(media);
7797            addSource(media, objectUrl);
7798            media.load();
7799          } catch (error) {
7800            media.src = objectUrl;
7801          }
7802        } else {
7803          media.src = objectUrl;
7804        }
7805        media.addEventListener('emptied', this._onMediaEmptied);
7806      }
7807    };
7808    _proto.onMediaDetaching = function onMediaDetaching() {
7809      var media = this.media,
7810        mediaSource = this.mediaSource,
7811        _objectUrl = this._objectUrl;
7812      if (mediaSource) {
7813        this.log('media source detaching');
7814        if (mediaSource.readyState === 'open') {
7815          try {
7816            // endOfStream could trigger exception if any sourcebuffer is in updating state
7817            // we don't really care about checking sourcebuffer state here,
7818            // as we are anyway detaching the MediaSource
7819            // let's just avoid this exception to propagate
7820            mediaSource.endOfStream();
7821          } catch (err) {
7822            this.warn("onMediaDetaching: " + err.message + " while calling endOfStream");
7823          }
7824        }
7825        // Clean up the SourceBuffers by invoking onBufferReset
7826        this.onBufferReset();
7827        mediaSource.removeEventListener('sourceopen', this._onMediaSourceOpen);
7828        mediaSource.removeEventListener('sourceended', this._onMediaSourceEnded);
7829        mediaSource.removeEventListener('sourceclose', this._onMediaSourceClose);
7830        if (this.appendSource) {
7831          mediaSource.removeEventListener('startstreaming', this._onStartStreaming);
7832          mediaSource.removeEventListener('endstreaming', this._onEndStreaming);
7833        }
7834        this.mediaSource = null;
7835        this._objectUrl = null;
7836      }
7837
7838      // Detach properly the MediaSource from the HTMLMediaElement as
7839      // suggested in https://github.com/w3c/media-source/issues/53.
7840      if (media) {
7841        media.removeEventListener('emptied', this._onMediaEmptied);
7842        if (_objectUrl) {
7843          self.URL.revokeObjectURL(_objectUrl);
7844        }
7845
7846        // clean up video tag src only if it's our own url. some external libraries might
7847        // hijack the video tag and change its 'src' without destroying the Hls instance first
7848        if (this.mediaSrc === _objectUrl) {
7849          media.removeAttribute('src');
7850          if (this.appendSource) {
7851            removeSourceChildren(media);
7852          }
7853          media.load();
7854        } else {
7855          this.warn('media|source.src was changed by a third party - skip cleanup');
7856        }
7857        this.media = null;
7858      }
7859      this.bufferCodecEventsExpected = this._bufferCodecEventsTotal;
7860      this.pendingTracks = {};
7861      this.tracks = {};
7862      this.hls.trigger(Events.MEDIA_DETACHED, undefined);
7863    };
7864    _proto.onBufferReset = function onBufferReset() {
7865      var _this4 = this;
7866      this.getSourceBufferTypes().forEach(function (type) {
7867        _this4.resetBuffer(type);
7868      });
7869      this._initSourceBuffer();
7870      this.hls.resumeBuffering();
7871    };
7872    _proto.resetBuffer = function resetBuffer(type) {
7873      var sb = this.sourceBuffer[type];
7874      try {
7875        if (sb) {
7876          var _this$mediaSource;
7877          this.removeBufferListeners(type);
7878          // Synchronously remove the SB from the map before the next call in order to prevent an async function from
7879          // accessing it
7880          this.sourceBuffer[type] = undefined;
7881          if ((_this$mediaSource = this.mediaSource) != null && _this$mediaSource.sourceBuffers.length) {
7882            this.mediaSource.removeSourceBuffer(sb);
7883          }
7884        }
7885      } catch (err) {
7886        this.warn("onBufferReset " + type, err);
7887      }
7888    };
7889    _proto.onBufferCodecs = function onBufferCodecs(event, data) {
7890      var _this5 = this;
7891      var sourceBufferCount = this.getSourceBufferTypes().length;
7892      var trackNames = Object.keys(data);
7893      trackNames.forEach(function (trackName) {
7894        if (sourceBufferCount) {
7895          var _track$buffer;
7896          // check if SourceBuffer codec needs to change
7897          var track = _this5.tracks[trackName];
7898          if (track && typeof ((_track$buffer = track.buffer) == null ? void 0 : _track$buffer.changeType) === 'function') {
7899            var _trackCodec;
7900            var _data$trackName = data[trackName],
7901              id = _data$trackName.id,
7902              codec = _data$trackName.codec,
7903              levelCodec = _data$trackName.levelCodec,
7904              container = _data$trackName.container,
7905              metadata = _data$trackName.metadata;
7906            var currentCodecFull = pickMostCompleteCodecName(track.codec, track.levelCodec);
7907            var currentCodec = currentCodecFull == null ? void 0 : currentCodecFull.replace(VIDEO_CODEC_PROFILE_REPLACE, '$1');
7908            var trackCodec = pickMostCompleteCodecName(codec, levelCodec);
7909            var nextCodec = (_trackCodec = trackCodec) == null ? void 0 : _trackCodec.replace(VIDEO_CODEC_PROFILE_REPLACE, '$1');
7910            if (trackCodec && currentCodec !== nextCodec) {
7911              if (trackName.slice(0, 5) === 'audio') {
7912                trackCodec = getCodecCompatibleName(trackCodec, _this5.appendSource);
7913              }
7914              var mimeType = container + ";codecs=" + trackCodec;
7915              _this5.appendChangeType(trackName, mimeType);
7916              _this5.log("switching codec " + currentCodecFull + " to " + trackCodec);
7917              _this5.tracks[trackName] = {
7918                buffer: track.buffer,
7919                codec: codec,
7920                container: container,
7921                levelCodec: levelCodec,
7922                metadata: metadata,
7923                id: id
7924              };
7925            }
7926          }
7927        } else {
7928          // if source buffer(s) not created yet, appended buffer tracks in this.pendingTracks
7929          _this5.pendingTracks[trackName] = data[trackName];
7930        }
7931      });
7932
7933      // if sourcebuffers already created, do nothing ...
7934      if (sourceBufferCount) {
7935        return;
7936      }
7937      var bufferCodecEventsExpected = Math.max(this.bufferCodecEventsExpected - 1, 0);
7938      if (this.bufferCodecEventsExpected !== bufferCodecEventsExpected) {
7939        this.log(bufferCodecEventsExpected + " bufferCodec event(s) expected " + trackNames.join(','));
7940        this.bufferCodecEventsExpected = bufferCodecEventsExpected;
7941      }
7942      if (this.mediaSource && this.mediaSource.readyState === 'open') {
7943        this.checkPendingTracks();
7944      }
7945    };
7946    _proto.appendChangeType = function appendChangeType(type, mimeType) {
7947      var _this6 = this;
7948      var operationQueue = this.operationQueue;
7949      var operation = {
7950        execute: function execute() {
7951          var sb = _this6.sourceBuffer[type];
7952          if (sb) {
7953            _this6.log("changing " + type + " sourceBuffer type to " + mimeType);
7954            sb.changeType(mimeType);
7955          }
7956          operationQueue.shiftAndExecuteNext(type);
7957        },
7958        onStart: function onStart() {},
7959        onComplete: function onComplete() {},
7960        onError: function onError(error) {
7961          _this6.warn("Failed to change " + type + " SourceBuffer type", error);
7962        }
7963      };
7964      operationQueue.append(operation, type, !!this.pendingTracks[type]);
7965    };
7966    _proto.blockAudio = function blockAudio(partOrFrag) {
7967      var _this$fragmentTracker,
7968        _this7 = this;
7969      var pStart = partOrFrag.start;
7970      var pTime = pStart + partOrFrag.duration * 0.05;
7971      var atGap = ((_this$fragmentTracker = this.fragmentTracker.getAppendedFrag(pStart, PlaylistLevelType.MAIN)) == null ? void 0 : _this$fragmentTracker.ga
7971p) === true;
7972      if (atGap) {
7973        return;
7974      }
7975      var op = {
7976        execute: function execute() {
7977          var _this7$fragmentTracke;
7978          if (_this7.lastVideoAppendEnd > pTime || _this7.sourceBuffer.video && BufferHelper.isBuffered(_this7.sourceBuffer.video, pTime) || ((_this7$fragmentTracke = _this7.fragmentTracker.getAppendedFrag(pTime, PlaylistLevelType.MAIN)) == null ? void 0 : _this7$fragmentTracke.gap) === true) {
7979            _this7.blockedAudioAppend = null;
7980            _this7.operationQueue.shiftAndExecuteNext('audio');
7981          }
7982        },
7983        onStart: function onStart() {},
7984        onComplete: function onComplete() {},
7985        onError: function onError() {}
7986      };
7987      this.blockedAudioAppend = {
7988        op: op,
7989        frag: partOrFrag
7990      };
7991      this.operationQueue.append(op, 'audio', true);
7992    };
7993    _proto.unblockAudio = function unblockAudio() {
7994      var blockedAudioAppend = this.blockedAudioAppend;
7995      if (blockedAudioAppend) {
7996        this.blockedAudioAppend = null;
7997        this.operationQueue.unblockAudio(blockedAudioAppend.op);
7998      }
7999    };
8000    _proto.onBufferAppending = function onBufferAppending(event, eventData) {
8001      var _this8 = this;
8002      var operationQueue = this.operationQueue,
8003        tracks = this.tracks;
8004      var data = eventData.data,
8005        type = eventData.type,
8006        parent = eventData.parent,
8007        frag = eventData.frag,
8008        part = eventData.part,
8009        chunkMeta = eventData.chunkMeta;
8010      var chunkStats = chunkMeta.buffering[type];
8011      var sn = frag.sn;
8012      var bufferAppendingStart = self.performance.now();
8013      chunkStats.start = bufferAppendingStart;
8014      var fragBuffering = frag.stats.buffering;
8015      var partBuffering = part ? part.stats.buffering : null;
8016      if (fragBuffering.start === 0) {
8017        fragBuffering.start = bufferAppendingStart;
8018      }
8019      if (partBuffering && partBuffering.start === 0) {
8020        partBuffering.start = bufferAppendingStart;
8021      }
8022
8023      // TODO: Only update timestampOffset when audio/mpeg fragment or part is not contiguous with previously appended
8024      // Adjusting `SourceBuffer.timestampOffset` (desired point in the timeline where the next frames should be appended)
8025      // in Chrome browser when we detect MPEG audio container and time delta between level PTS and `SourceBuffer.timestampOffset`
8026      // is greater than 100ms (this is enough to handle seek for VOD or level change for LIVE videos).
8027      // More info here: https://github.com/video-dev/hls.js/issues/332#issuecomment-257986486
8028      var audioTrack = tracks.audio;
8029      var checkTimestampOffset = false;
8030      if (type === 'audio' && (audioTrack == null ? void 0 : audioTrack.container) === 'audio/mpeg') {
8031        checkTimestampOffset = !this.lastMpegAudioChunk || chunkMeta.id === 1 || this.lastMpegAudioChunk.sn !== chunkMeta.sn;
8032        this.lastMpegAudioChunk = chunkMeta;
8033      }
8034
8035      // Block audio append until overlapping video append
8036      var videoSb = this.sourceBuffer.video;
8037      if (videoSb && sn !== 'initSegment') {
8038        var partOrFrag = part || frag;
8039        var blockedAudioAppend = this.blockedAudioAppend;
8040        if (type === 'audio' && parent !== 'main' && !this.blockedAudioAppend) {
8041          var pStart = partOrFrag.start;
8042          var pTime = pStart + partOrFrag.duration * 0.05;
8043          var vbuffered = videoSb.buffered;
8044          var vappending = this.operationQueue.current('video');
8045          if (!vbuffered.length && !vappending) {
8046            // wait for video before appending audio
8047            this.blockAudio(partOrFrag);
8048          } else if (!vappending && !BufferHelper.isBuffered(videoSb, pTime) && this.lastVideoAppendEnd < pTime) {
8049            // audio is ahead of video
8050            this.blockAudio(partOrFrag);
8051          }
8052        } else if (type === 'video') {
8053          var videoAppendEnd = partOrFrag.end;
8054          if (blockedAudioAppend) {
8055            var audioStart = blockedAudioAppend.frag.start;
8056            if (videoAppendEnd > audioStart || videoAppendEnd < this.lastVideoAppendEnd || BufferHelper.isBuffered(videoSb, audioStart)) {
8057              this.unblockAudio();
8058            }
8059          }
8060          this.lastVideoAppendEnd = videoAppendEnd;
8061        }
8062      }
8063      var fragStart = (part || frag).start;
8064      var operation = {
8065        execute: function execute() {
8066          chunkStats.executeStart = self.performance.now();
8067          if (checkTimestampOffset) {
8068            var sb = _this8.sourceBuffer[type];
8069            if (sb) {
8070              var delta = fragStart - sb.timestampOffset;
8071              if (Math.abs(delta) >= 0.1) {
8072                _this8.log("Updating audio SourceBuffer timestampOffset to " + fragStart + " (delta: " + delta + ") sn: " + sn + ")");
8073                sb.timestampOffset = fragStart;
8074              }
8075            }
8076          }
8077          _this8.appendExecutor(data, type);
8078        },
8079        onStart: function onStart() {
8080          // logger.debug(`[buffer-controller]: ${type} SourceBuffer updatestart`);
8081        },
8082        onComplete: function onComplete() {
8083          // logger.debug(`[buffer-controller]: ${type} SourceBuffer updateend`);
8084          var end = self.performance.now();
8085          chunkStats.executeEnd = chunkStats.end = end;
8086          if (fragBuffering.first === 0) {
8087            fragBuffering.first = end;
8088          }
8089          if (partBuffering && partBuffering.first === 0) {
8090            partBuffering.first = end;
8091          }
8092          var sourceBuffer = _this8.sourceBuffer;
8093          var timeRanges = {};
8094          for (var _type in sourceBuffer) {
8095            timeRanges[_type] = BufferHelper.getBuffered(sourceBuffer[_type]);
8096          }
8097          _this8.appendErrors[type] = 0;
8098          if (type === 'audio' || type === 'video') {
8099            _this8.appendErrors.audiovideo = 0;
8100          } else {
8101            _this8.appendErrors.audio = 0;
8102            _this8.appendErrors.video = 0;
8103          }
8104          _this8.hls.trigger(Events.BUFFER_APPENDED, {
8105            type: type,
8106            frag: frag,
8107            part: part,
8108            chunkMeta: chunkMeta,
8109            parent: frag.type,
8110            timeRanges: timeRanges
8111          });
8112        },
8113        onError: function onError(error) {
8114          // in case any error occured while appending, put back segment in segments table
8115          var event = {
8116            type: ErrorTypes.MEDIA_ERROR,
8117            parent: frag.type,
8118            details: ErrorDetails.BUFFER_APPEND_ERROR,
8119            sourceBufferName: type,
8120            frag: frag,
8121            part: part,
8122            chunkMeta: chunkMeta,
8123            error: error,
8124            err: error,
8125            fatal: false
8126          };
8127          if (error.code === DOMException.QUOTA_EXCEEDED_ERR) {
8128            // QuotaExceededError: http://www.w3.org/TR/html5/infrastructure.html#quotaexceedederror
8129            // let's stop appending any segments, and report BUFFER_FULL_ERROR error
8130            event.details = ErrorDetails.BUFFER_FULL_ERROR;
8131          } else {
8132            var appendErrorCount = ++_this8.appendErrors[type];
8133            event.details = ErrorDetails.BUFFER_APPEND_ERROR;
8134            /* with UHD content, we could get loop of quota exceeded error until
8135              browser is able to evict some data from sourcebuffer. Retrying can help recover.
8136            */
8137            _this8.warn("Failed " + appendErrorCount + "/" + _this8.hls.config.appendErrorMaxRetry + " times to append segment in \"" + type + "\" sourceBuffer");
8138            if (appendErrorCount >= _this8.hls.config.appendErrorMaxRetry) {
8139              event.fatal = true;
8140            }
8141          }
8142          _this8.hls.trigger(Events.ERROR, event);
8143        }
8144      };
8145      operationQueue.append(operation, type, !!this.pendingTracks[type]);
8146    };
8147    _proto.getFlushOp = function getFlushOp(type, start, end) {
8148      var _this9 = this;
8149      return {
8150        execute: function execute() {
8151          _this9.removeExecutor(type, start, end);
8152        },
8153        onStart: function onStart() {
8154          // logger.debug(`[buffer-controller]: Started flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
8155        },
8156        onComplete: function onComplete() {
8157          // logger.debug(`[buffer-controller]: Finished flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
8158          _this9.hls.trigger(Events.BUFFER_FLUSHED, {
8159            type: type
8160          });
8161        },
8162        onError: function onError(error) {
8163          _this9.warn("Failed to remove from " + type + " SourceBuffer", error);
8164        }
8165      };
8166    };
8167    _proto.onBufferFlushing = function onBufferFlushing(event, data) {
8168      var _this10 = this;
8169      var operationQueue = this.operationQueue;
8170      var type = data.type,
8171        startOffset = data.startOffset,
8172        endOffset = data.endOffset;
8173      if (type) {
8174        operationQueue.append(this.getFlushOp(type, startOffset, endOffset), type);
8175      } else {
8176        this.getSourceBufferTypes().forEach(function (sbType) {
8177          operationQueue.append(_this10.getFlushOp(sbType, startOffset, endOffset), sbType);
8178        });
8179      }
8180    };
8181    _proto.onFragParsed = function onFragParsed(event, data) {
8182      var _this11 = this;
8183      var frag = data.frag,
8184        part = data.part;
8185      var buffersAppendedTo = [];
8186      var elementaryStreams = part ? part.elementaryStreams : frag.elementaryStreams;
8187      if (elementaryStreams[ElementaryStreamTypes.AUDIOVIDEO]) {
8188        buffersAppendedTo.push('audiovideo');
8189      } else {
8190        if (elementaryStreams[ElementaryStreamTypes.AUDIO]) {
8191          buffersAppendedTo.push('audio');
8192        }
8193        if (elementaryStreams[ElementaryStreamTypes.VIDEO]) {
8194          buffersAppendedTo.push('video');
8195        }
8196      }
8197      var onUnblocked = function onUnblocked() {
8198        var now = self.performance.now();
8199        frag.stats.buffering.end = now;
8200        if (part) {
8201          part.stats.buffering.end = now;
8202        }
8203        var stats = part ? part.stats : frag.stats;
8204        _this11.hls.trigger(Events.FRAG_BUFFERED, {
8205          frag: frag,
8206          part: part,
8207          stats: stats,
8208          id: frag.type
8209        });
8210      };
8211      if (buffersAppendedTo.length === 0) {
8212        this.warn("Fragments must have at least one ElementaryStreamType set. type: " + frag.type + " level: " + frag.level + " sn: " + frag.sn);
8213      }
8214      this.blockBuffers(onUnblocked, buffersAppendedTo);
8215    };
8216    _proto.onFragChanged = function onFragChanged(event, data) {
8217      this.trimBuffers();
8218    }
8219
8220    // on BUFFER_EOS mark matching sourcebuffer(s) as ended and trigger checkEos()
8221    // an undefined data.type will mark all buffers as EOS.
8222    ;
8223    _proto.onBufferEos = function onBufferEos(event, data) {
8224      var _this12 = this;
8225      if (data.type === 'video') {
8226        this.unblockAudio();
8227      }
8228      var ended = this.getSourceBufferTypes().reduce(function (acc, type) {
8229        var sb = _this12.sourceBuffer[type];
8230        if (sb && (!data.type || data.type === type)) {
8231          sb.ending = true;
8232          if (!sb.ended) {
8233            sb.ended = true;
8234            _this12.log(type + " sourceBuffer now EOS");
8235          }
8236        }
8237        return acc && !!(!sb || sb.ended);
8238      }, true);
8239      if (ended) {
8240        this.log("Queueing mediaSource.endOfStream()");
8241        this.blockBuffers(function () {
8242          _this12.getSourceBufferTypes().forEach(function (type) {
8243            var sb = _this12.sourceBuffer[type];
8244            if (sb) {
8245              sb.ending = false;
8246            }
8247          });
8248          var mediaSource = _this12.mediaSource;
8249          if (!mediaSource || mediaSource.readyState !== 'open') {
8250            if (mediaSource) {
8251              _this12.log("Could not call mediaSource.endOfStream(). mediaSource.readyState: " + mediaSource.readyState);
8252            }
8253            return;
8254          }
8255          _this12.log("Calling mediaSource.endOfStream()");
8256          // Allow this to throw and be caught by the enqueueing function
8257          mediaSource.endOfStream();
8258        });
8259      }
8260    };
8261    _proto.onLevelUpdated = function onLevelUpdated(event, _ref) {
8262      var _this13 = this;
8263      var details = _ref.details;
8264      if (!details.fragments.length) {
8265        return;
8266      }
8267      this.details = details;
8268      var durationAndRange = this.getDurationAndRange();
8269      if (!durationAndRange) {
8270        return;
8271      }
8272      if (this.getSourceBufferTypes().length) {
8273        this.blockBuffers(function () {
8274          return _this13.updateMediaSource(durationAndRange);
8275        });
8276      } else {
8277        this.updateMediaSource(durationAndRange);
8278      }
8279    };
8280    _proto.onError = function onError(event, data) {
8281      if (data.details === ErrorDetails.BUFFER_APPEND_ERROR && data.frag) {
8282        var _data$errorAction;
8283        var nextAutoLevel = (_data$errorAction = data.errorAction) == null ? void 0 : _data$errorAction.nextAutoLevel;
8284        if (isFiniteNumber(nextAutoLevel) && nextAutoLevel !== data.frag.level) {
8285          this.resetAppendErrors();
8286        }
8287      }
8288    };
8289    _proto.resetAppendErrors = function resetAppendErrors() {
8290      this.appendErrors = {
8291        audio: 0,
8292        video: 0,
8293        audiovideo: 0
8294      };
8295    };
8296    _proto.trimBuffers = function trimBuffers() {
8297      var hls = this.hls,
8298        details = this.details,
8299        media = this.media;
8300      if (!media || details === null) {
8301        return;
8302      }
8303      var sourceBufferTypes = this.getSourceBufferTypes();
8304      if (!sourceBufferTypes.length) {
8305        return;
8306      }
8307      var config = hls.config;
8308      var currentTime = media.currentTime;
8309      var targetDuration = details.levelTargetDuration;
8310
8311      // Support for deprecated liveBackBufferLength
8312      var backBufferLength = details.live && config.liveBackBufferLength !== null ? config.liveBackBufferLength : config.backBufferLength;
8313      if (isFiniteNumber(backBufferLength) && backBufferLength > 0) {
8314        var maxBackBufferLength = Math.max(backBufferLength, targetDuration);
8315        var targetBackBufferPosition = Math.floor(currentTime / targetDuration) * targetDuration - maxBackBufferLength;
8316        this.flushBackBuffer(currentTime, targetDuration, targetBackBufferPosition);
8317      }
8318      if (isFiniteNumber(config.frontBufferFlushThreshold) && config.frontBufferFlushThreshold > 0) {
8319        var frontBufferLength = Math.max(config.maxBufferLength, config.frontBufferFlushThreshold);
8320        var maxFrontBufferLength = Math.max(frontBufferLength, targetDuration);
8321        var targetFrontBufferPosition = Math.floor(currentTime / targetDuration) * targetDuration + maxFrontBufferLength;
8322        this.flushFrontBuffer(currentTime, targetDuration, targetFrontBufferPosition);
8323      }
8324    };
8325    _proto.flushBackBuffer = function flushBackBuffer(currentTime, targetDuration, targetBackBufferPosition) {
8326      var _this14 = this;
8327      var details = this.details,
8328        sourceBuffer = this.sourceBuffer;
8329      var sourceBufferTypes = this.getSourceBufferTypes();
8330      sourceBufferTypes.forEach(function (type) {
8331        var sb = sourceBuffer[type];
8332        if (sb) {
8333          var buffered = BufferHelper.getBuffered(sb);
8334          // when target buffer start exceeds actual buffer start
8335          if (buffered.length > 0 && targetBackBufferPosition > buffered.start(0)) {
8336            _this14.hls.trigger(Events.BACK_BUFFER_REACHED, {
8337              bufferEnd: targetBackBufferPosition
8338            });
8339
8340            // Support for deprecated event:
8341            if (details != null && details.live) {
8342              _this14.hls.trigger(Events.LIVE_BACK_BUFFER_REACHED, {
8343                bufferEnd: targetBackBufferPosition
8344              });
8345            } else if (sb.ended && buffered.end(buffered.length - 1) - currentTime < targetDuration * 2) {
8346              _this14.log("Cannot flush " + type + " back buffer while SourceBuffer is in ended state");
8347              return;
8348            }
8349            _this14.hls.trigger(Events.BUFFER_FLUSHING, {
8350              startOffset: 0,
8351              endOffset: targetBackBufferPosition,
8352              type: type
8353            });
8354          }
8355        }
8356      });
8357    };
8358    _proto.flushFrontBuffer = function flushFrontBuffer(currentTime, targetDuration, targetFrontBufferPosition) {
8359      var _this15 = this;
8360      var sourceBuffer = this.sourceBuffer;
8361      var sourceBufferTypes = this.getSourceBufferTypes();
8362      sourceBufferTypes.forEach(function (type) {
8363        var sb = sourceBuffer[type];
8364        if (sb) {
8365          var buffered = BufferHelper.getBuffered(sb);
8366          var numBufferedRanges = buffered.length;
8367          // The buffer is either empty or contiguous
8368          if (numBufferedRanges < 2) {
8369            return;
8370          }
8371          var bufferStart = buffered.start(numBufferedRanges - 1);
8372          var bufferEnd = buffered.end(numBufferedRanges - 1);
8373          // No flush if we can tolerate the current buffer length or the current buffer range we would flush is contiguous with current position
8374          if (targetFrontBufferPosition > bufferStart || currentTime >= bufferStart && currentTime <= bufferEnd) {
8375            return;
8376          } else if (sb.ended && currentTime - bufferEnd < 2 * targetDuration) {
8377            _this15.log("Cannot flush " + type + " front buffer while SourceBuffer is in ended state");
8378            return;
8379          }
8380          _this15.hls.trigger(Events.BUFFER_FLUSHING, {
8381            startOffset: bufferStart,
8382            endOffset: Infinity,
8383            type: type
8384          });
8385        }
8386      });
8387    }
8388
8389    /**
8390     * Update Media Source duration to current level duration or override to Infinity if configuration parameter
8391     * 'liveDurationInfinity` is set to `true`
8392     * More details: https://github.com/video-dev/hls.js/issues/355
8393     */;
8394    _proto.getDurationAndRange = function getDurationAndRange() {
8395      if (!this.details || !this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
8396        return null;
8397      }
8398      var details = this.details,
8399        hls = this.hls,
8400        media = this.media,
8401        mediaSource = this.mediaSource;
8402      var levelDuration = details.fragments[0].start + details.totalduration;
8403      var mediaDuration = media.duration;
8404      var msDuration = isFiniteNumber(mediaSource.duration) ? mediaSource.duration : 0;
8405      if (details.live && hls.config.liveDurationInfinity) {
8406        // Override duration to Infinity
8407        mediaSource.duration = Infinity;
8408        var len = details.fragments.length;
8409        if (len && details.live && !!mediaSource.setLiveSeekableRange) {
8410          var start = Math.max(0, details.fragments[0].start);
8411          var end = Math.max(start, start + details.totalduration);
8412          return {
8413            duration: Infinity,
8414            start: start,
8415            end: end
8416          };
8417        }
8418        return {
8419          duration: Infinity
8420        };
8421      } else if (levelDuration > msDuration && levelDuration > mediaDuration || !isFiniteNumber(mediaDuration)) {
8422        return {
8423          duration: levelDuration
8424        };
8425      }
8426      return null;
8427    };
8428    _proto.updateMediaSource = function updateMediaSource(_ref2) {
8429      var duration = _ref2.duration,
8430        start = _ref2.start,
8431        end = _ref2.end;
8432      if (!this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
8433        return;
8434      }
8435      if (isFiniteNumber(duration)) {
8436        this.log("Updating Media Source duration to " + duration.toFixed(3));
8437      }
8438      this.mediaSource.duration = duration;
8439      if (start !== undefined && end !== undefined) {
8440        this.log("Media Source duration is set to " + this.mediaSource.duration + ". Setting seekable range to " + start + "-" + end + ".");
8441        this.mediaSource.setLiveSeekableRange(start, end);
8442      }
8443    };
8444    _proto.checkPendingTracks = function checkPendingTracks() {
8445      var bufferCodecEventsExpected = this.bufferCodecEventsExpected,
8446        operationQueue = this.operationQueue,
8447        pendingTracks = this.pendingTracks;
8448
8449      // Check if we've received all of the expected bufferCodec events. When none remain, create all the sourceBuffers at once.
8450      // This is important because the MSE spec allows implementations to throw QuotaExceededErrors if creating new sourceBuffers after
8451      // data has been appended to existing ones.
8452      // 2 tracks is the max (one for audio, one for video). If we've reach this max go ahead and create the buffers.
8453      var pendingTracksCount = Object.keys(pendingTracks).length;
8454      if (pendingTracksCount && (!bufferCodecEventsExpected || pendingTracksCount === 2 || 'audiovideo' in pendingTracks)) {
8455        // ok, let's create them now !
8456        this.createSourceBuffers(pendingTracks);
8457        this.pendingTracks = {};
8458        // append any pending segments now !
8459        var buffers = this.getSourceBufferTypes();
8460        if (buffers.length) {
8461          this.hls.trigger(Events.BUFFER_CREATED, {
8462            tracks: this.tracks
8463          });
8464          buffers.forEach(function (type) {
8465            operationQueue.executeNext(type);
8466          });
8467        } else {
8468          var error = new Error('could not create source buffer for media codec(s)');
8469          this.hls.trigger(Events.ERROR, {
8470            type: ErrorTypes.MEDIA_ERROR,
8471            details: ErrorDetails.BUFFER_INCOMPATIBLE_CODECS_ERROR,
8472            fatal: true,
8473            error: error,
8474            reason: error.message
8475          });
8476        }
8477      }
8478    };
8479    _proto.createSourceBuffers = function createSourceBuffers(tracks) {
8480      var _this16 = this;
8481      var sourceBuffer = this.sourceBuffer,
8482        mediaSource = this.mediaSource;
8483      if (!mediaSource) {
8484        throw Error('createSourceBuffers called when mediaSource was null');
8485      }
8486      var _loop = function _loop(trackName) {
8487        if (!sourceBuffer[trackName]) {
8488          var _track$levelCodec;
8489          var track = tracks[trackName];
8490          if (!track) {
8491            throw Error("source buffer exists for track " + trackName + ", however track does not");
8492          }
8493          // use levelCodec as first priority unless it contains multiple comma-separated codec values
8494          var codec = ((_track$levelCodec = track.levelCodec) == null ? void 0 : _track$levelCodec.indexOf(',')) === -1 ? track.levelCodec : track.codec;
8495          if (codec) {
8496            if (trackName.slice(0, 5) === 'audio') {
8497              codec = getCodecCompatibleName(codec, _this16.appendSource);
8498            }
8499          }
8500          var mimeType = track.container + ";codecs=" + codec;
8501          _this16.log("creating sourceBuffer(" + mimeType + ")");
8502          try {
8503            var sb = sourceBuffer[trackName] = mediaSource.addSourceBuffer(mimeType);
8504            var sbName = trackName;
8505            _this16.addBufferListener(sbName, 'updatestart', _this16._onSBUpdateStart);
8506            _this16.addBufferListener(sbName, 'updateend', _this16._onSBUpdateEnd);
8507            _this16.addBufferListener(sbName, 'error', _this16._onSBUpdateError);
8508            // ManagedSourceBuffer bufferedchange event
8509            if (_this16.appendSource) {
8510              _this16.addBufferListener(sbName, 'bufferedchange', function (type, event) {
8511                // If media was ejected check for a change. Added ranges are redundant with changes on 'updateend' event.
8512                var removedRanges = event.removedRanges;
8513                if (removedRanges != null && removedRanges.length) {
8514                  _this16.hls.trigger(Events.BUFFER_FLUSHED, {
8515                    type: trackName
8516                  });
8517                }
8518              });
8519            }
8520            _this16.tracks[trackName] = {
8521              buffer: sb,
8522              codec: codec,
8523              container: track.container,
8524              levelCodec: track.levelCodec,
8525              metadata: track.metadata,
8526              id: track.id
8527            };
8528          } catch (err) {
8529            _this16.error("error while trying to add sourceBuffer: " + err.message);
8530            _this16.hls.trigger(Events.ERROR, {
8531              type: ErrorTypes.MEDIA_ERROR,
8532              details: ErrorDetails.BUFFER_ADD_CODEC_ERROR,
8533              fatal: false,
8534              error: err,
8535              sourceBufferName: trackName,
8536              mimeType: mimeType
8537            });
8538          }
8539        }
8540      };
8541      for (var trackName in tracks) {
8542        _loop(trackName);
8543      }
8544    };
8545    _proto._onSBUpdateStart = function _onSBUpdateStart(type) {
8546      var operationQueue = this.operationQueue;
8547      var operation = operationQueue.current(type);
8548      operation.onStart();
8549    };
8550    _proto._onSBUpdateEnd = function _onSBUpdateEnd(type) {
8551      var _this$mediaSource2;
8552      if (((_this$mediaSource2 = this.mediaSource) == null ? void 0 : _this$mediaSource2.readyState) === 'closed') {
8553        this.resetBuffer(type);
8554        return;
8555      }
8556      var operationQueue = this.operationQueue;
8557      var operation = operationQueue.current(type);
8558      operation.onComplete();
8559      operationQueue.shiftAndExecuteNext(type);
8560    };
8561    _proto._onSBUpdateError = function _onSBUpdateError(type, event) {
8562      var _this$mediaSource3;
8563      var error = new Error(type + " SourceBuffer error. MediaSource readyState: " + ((_this$mediaSource3 = this.mediaSource) == null ? void 0 : _this$mediaSource3.readyState));
8564      this.error("" + error, event);
8565      // according to http://www.w3.org/TR/media-source/#sourcebuffer-append-error
8566      // SourceBuffer errors are not necessarily fatal; if so, the HTMLMediaElement will fire an error event
8567      this.hls.trigger(Events.ERROR, {
8568        type: ErrorTypes.MEDIA_ERROR,
8569        details: ErrorDetails.BUFFER_APPENDING_ERROR,
8570        sourceBufferName: type,
8571        error: error,
8572        fatal: false
8573      });
8574      // updateend is always fired after error, so we'll allow that to shift the current operation off of the queue
8575      var operation = this.operationQueue.current(type);
8576      if (operation) {
8577        operation.onError(error);
8578      }
8579    }
8580
8581    // This method must result in an updateend event; if remove is not called, _onSBUpdateEnd must be called manually
8582    ;
8583    _proto.removeExecutor = function removeExecutor(type, startOffset, endOffset) {
8584      var media = this.media,
8585        mediaSource = this.mediaSource,
8586        operationQueue = this.operationQueue,
8587        sourceBuffer = this.sourceBuffer;
8588      var sb = sourceBuffer[type];
8589      if (!media || !mediaSource || !sb) {
8590        this.warn("Attempting to remove from the " + type + " SourceBuffer, but it does not exist");
8591        operationQueue.shiftAndExecuteNext(type);
8592        return;
8593      }
8594      var mediaDuration = isFiniteNumber(media.duration) ? media.duration : Infinity;
8595      var msDuration = isFiniteNumber(mediaSource.duration) ? mediaSource.duration : Infinity;
8596      var removeStart = Math.max(0, startOffset);
8597      var removeEnd = Math.min(endOffset, mediaDuration, msDuration);
8598      if (removeEnd > removeStart && (!sb.ending || sb.ended)) {
8599        sb.ended = false;
8600        this.log("Removing [" + removeStart + "," + removeEnd + "] from the " + type + " SourceBuffer");
8601        sb.remove(removeStart, removeEnd);
8602      } else {
8603        // Cycle the queue
8604        operationQueue.shiftAndExecuteNext(type);
8605      }
8606    }
8607
8608    // This method must result in an updateend event; if append is not called, _onSBUpdateEnd must be called manually
8609    ;
8610    _proto.appendExecutor = function appendExecutor(data, type) {
8611      var sb = this.sourceBuffer[type];
8612      if (!sb) {
8613        if (!this.pendingTracks[type]) {
8614          throw new Error("Attempting to append to the " + type + " SourceBuffer, but it does not exist");
8615        }
8616        return;
8617      }
8618      sb.ending = false;
8619      sb.ended = false;
8620      sb.appendBuffer(data);
8621    }
8622
8623    // Enqueues an operation to each SourceBuffer queue which, upon execution, resolves a promise. When all promises
8624    // resolve, the onUnblocked function is executed. Functions calling this method do not need to unblock the queue
8625    // upon completion, since we already do it here
8626    ;
8627    _proto.blockBuffers = function blockBuffers(onUnblocked, buffers) {
8628      var _this17 = this;
8629      if (buffers === void 0) {
8630        buffers = this.getSourceBufferTypes();
8631      }
8632      if (!buffers.length) {
8633        this.log('Blocking operation requested, but no SourceBuffers exist');
8634        Promise.resolve().then(onUnblocked);
8635        return;
8636      }
8637      var operationQueue = this.operationQueue;
8638
8639      // logger.debug(`[buffer-controller]: Blocking ${buffers} SourceBuffer`);
8640      var blockingOperations = buffers.map(function (type) {
8641        return operationQueue.appendBlocker(type);
8642      });
8643      var audioBlocked = buffers.length > 1 && !!this.blockedAudioAppend;
8644      if (audioBlocked) {
8645        this.unblockAudio();
8646      }
8647      Promise.all(blockingOperations).then(function (result) {
8648        // logger.debug(`[buffer-controller]: Blocking operation resolved; unblocking ${buffers} SourceBuffer`);
8649        onUnblocked();
8650        buffers.forEach(function (type, i) {
8651          var sb = _this17.sourceBuffer[type];
8652          // Only cycle the queue if the SB is not updating. There's a bug in Chrome which sets the SB updating flag to
8653          // true when changing the MediaSource duration (https://bugs.chromium.org/p/chromium/issues/detail?id=959359&can=2&q=mediasource%20duration)
8654          // While this is a workaround, it's probably useful to have around
8655          if (!(sb != null && sb.updating)) {
8656            operationQueue.shiftAndExecuteNext(type);
8657          }
8658        });
8659      });
8660    };
8661    _proto.getSourceBufferTypes = function getSourceBufferTypes() {
8662      return Object.keys(this.sourceBuffer);
8663    };
8664    _proto.addBufferListener = function addBufferListener(type, event, fn) {
8665      var buffer = this.sourceBuffer[type];
8666      if (!buffer) {
8667        return;
8668      }
8669      var listener = fn.bind(this, type);
8670      this.listeners[type].push({
8671        event: event,
8672        listener: listener
8673      });
8674      buffer.addEventListener(event, listener);
8675    };
8676    _proto.removeBufferListeners = function removeBufferListeners(type) {
8677      var buffer = this.sourceBuffer[type];
8678      if (!buffer) {
8679        return;
8680      }
8681      this.listeners[type].forEach(function (l) {
8682        buffer.removeEventListener(l.event, l.listener);
8683      });
8684    };
8685    return _createClass(BufferController, [{
8686      key: "mediaSrc",
8687      get: function get() {
8688        var _this$media, _this$media$querySele;
8689        var media = ((_this$media = this.media) == null ? void 0 : (_this$media$querySele = _this$media.querySelector) == null ? void 0 : _this$media$querySele.call(_this$media, 'source')) || this.media;
8690        return media == null ? void 0 : media.src;
8691      }
8692    }]);
8693  }(Logger);
8694  function removeSourceChildren(node) {
8695    var sourceChildren = node.querySelectorAll('source');
8696    [].slice.call(sourceChildren).forEach(function (source) {
8697      node.removeChild(source);
8698    });
8699  }
8700  function addSource(media, url) {
8701    var source = self.document.createElement('source');
8702    source.type = 'video/mp4';
8703    source.src = url;
8704    media.appendChild(source);
8705  }
8706
8707  var CapLevelController = /*#__PURE__*/function () {
8708    function CapLevelController(hls) {
8709      this.hls = void 0;
8710      this.autoLevelCapping = void 0;
8711      this.firstLevel = void 0;
8712      this.media = void 0;
8713      this.restrictedLevels = void 0;
8714      this.timer = void 0;
8715      this.clientRect = void 0;
8716      this.streamController = void 0;
8717      this.hls = hls;
8718      this.autoLevelCapping = Number.POSITIVE_INFINITY;
8719      this.firstLevel = -1;
8720      this.media = null;
8721      this.restrictedLevels = [];
8722      this.timer = undefined;
8723      this.clientRect = null;
8724      this.registerListeners();
8725    }
8726    var _proto = CapLevelController.prototype;
8727    _proto.setStreamController = function setStreamController(streamController) {
8728      this.streamController = streamController;
8729    };
8730    _proto.destroy = function destroy() {
8731      if (this.hls) {
8732        this.unregisterListener();
8733      }
8734      if (this.timer) {
8735        this.stopCapping();
8736      }
8737      this.media = null;
8738      this.clientRect = null;
8739      // @ts-ignore
8740      this.hls = this.streamController = null;
8741    };
8742    _proto.registerListeners = function registerListeners() {
8743      var hls = this.hls;
8744      hls.on(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this);
8745      hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
8746      hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
8747      hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
8748      hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this);
8749      hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
8750    };
8751    _proto.unregisterListener = function unregisterListener() {
8752      var hls = this.hls;
8753      hls.off(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this);
8754      hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
8755      hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
8756      hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
8757      hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this);
8758      hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
8759    };
8760    _proto.onFpsDropLevelCapping = function onFpsDropLevelCapping(event, data) {
8761      // Don't add a restricted level more than once
8762      var level = this.hls.levels[data.droppedLevel];
8763      if (this.isLevelAllowed(level)) {
8764        this.restrictedLevels.push({
8765          bitrate: level.bitrate,
8766          height: level.height,
8767          width: level.width
8768        });
8769      }
8770    };
8771    _proto.onMediaAttaching = function onMediaAttaching(event, data) {
8772      this.media = data.media instanceof HTMLVideoElement ? data.media : null;
8773      this.clientRect = null;
8774      if (this.timer && this.hls.levels.length) {
8775        this.detectPlayerSize();
8776      }
8777    };
8778    _proto.onManifestParsed = function onManifestParsed(event, data) {
8779      var hls = this.hls;
8780      this.restrictedLevels = [];
8781      this.firstLevel = data.firstLevel;
8782      if (hls.config.capLevelToPlayerSize && data.video) {
8783        // Start capping immediately if the manifest has signaled video codecs
8784        this.startCapping();
8785      }
8786    };
8787    _proto.onLevelsUpdated = function onLevelsUpdated(event, data) {
8788      if (this.timer && isFiniteNumber(this.autoLevelCapping)) {
8789        this.detectPlayerSize();
8790      }
8791    }
8792
8793    // Only activate capping when playing a video stream; otherwise, multi-bitrate audio-only streams will be restricted
8794    // to the first level
8795    ;
8796    _proto.onBufferCodecs = function onBufferCodecs(event, data) {
8797      var hls = this.hls;
8798      if (hls.config.capLevelToPlayerSize && data.video) {
8799        // If the manifest did not signal a video codec capping has been deferred until we're certain video is present
8800        this.startCapping();
8801      }
8802    };
8803    _proto.onMediaDetaching = function onMediaDetaching() {
8804      this.stopCapping();
8805      this.media = null;
8806    };
8807    _proto.detectPlayerSize = function detectPlayerSize() {
8808      if (this.media) {
8809        if (this.mediaHeight <= 0 || this.mediaWidth <= 0) {
8810          this.clientRect = null;
8811          return;
8812        }
8813        var levels = this.hls.levels;
8814        if (levels.length) {
8815          var hls = this.hls;
8816          var maxLevel = this.getMaxLevel(levels.length - 1);
8817          if (maxLevel !== this.autoLevelCapping) {
8818            hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8819          }
8820          hls.autoLevelCapping = maxLevel;
8821          if (hls.autoLevelEnabled && hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
8822            // if auto level capping has a higher value for the previous one, flush the buffer using nextLevelSwitch
8823            // usually happen when the user go to the fullscreen mode.
8824            this.streamController.nextLevelSwitch();
8825          }
8826          this.autoLevelCapping = hls.autoLevelCapping;
8827        }
8828      }
8829    }
8830
8831    /*
8832     * returns level should be the one with the dimensions equal or greater than the media (player) dimensions (so the video will be downscaled)
8833     */;
8834    _proto.getMaxLevel = function getMaxLevel(capLevelIndex) {
8835      var _this = this;
8836      var levels = this.hls.levels;
8837      if (!levels.length) {
8838        return -1;
8839      }
vendor: 4,275 bytes, lines 8840-8951
8840      var validLevels = levels.filter(function (level, index) {
8841        return _this.isLevelAllowed(level) && index <= capLevelIndex;
8842      });
8843      this.clientRect = null;
8844      return CapLevelController.getMaxLevelByMediaSize(validLevels, this.mediaWidth, this.mediaHeight);
8845    };
8846    _proto.startCapping = function startCapping() {
8847      if (this.timer) {
8848        // Don't reset capping if started twice; this can happen if the manifest signals a video codec
8849        return;
8850      }
8851      this.autoLevelCapping = Number.POSITIVE_INFINITY;
8852      self.clearInterval(this.timer);
8853      this.timer = self.setInterval(this.detectPlayerSize.bind(this), 1000);
8854      this.detectPlayerSize();
8855    };
8856    _proto.stopCapping = function stopCapping() {
8857      this.restrictedLevels = [];
8858      this.firstLevel = -1;
8859      this.autoLevelCapping = Number.POSITIVE_INFINITY;
8860      if (this.timer) {
8861        self.clearInterval(this.timer);
8862        this.timer = undefined;
8863      }
8864    };
8865    _proto.getDimensions = function getDimensions() {
8866      if (this.clientRect) {
8867        return this.clientRect;
8868      }
8869      var media = this.media;
8870      var boundsRect = {
8871        width: 0,
8872        height: 0
8873      };
8874      if (media) {
8875        var clientRect = media.getBoundingClientRect();
8876        boundsRect.width = clientRect.width;
8877        boundsRect.height = clientRect.height;
8878        if (!boundsRect.width && !boundsRect.height) {
8879          // When the media element has no width or height (equivalent to not being in the DOM),
8880          // then use its width and height attributes (media.width, media.height)
8881          boundsRect.width = clientRect.right - clientRect.left || media.width || 0;
8882          boundsRect.height = clientRect.bottom - clientRect.top || media.height || 0;
8883        }
8884      }
8885      this.clientRect = boundsRect;
8886      return boundsRect;
8887    };
8888    _proto.isLevelAllowed = function isLevelAllowed(level) {
8889      var restrictedLevels = this.restrictedLevels;
8890      return !restrictedLevels.some(function (restrictedLevel) {
8891        return level.bitrate === restrictedLevel.bitrate && level.width === restrictedLevel.width && level.height === restrictedLevel.height;
8892      });
8893    };
8894    CapLevelController.getMaxLevelByMediaSize = function getMaxLevelByMediaSize(levels, width, height) {
8895      if (!(levels != null && levels.length)) {
8896        return -1;
8897      }
8898
8899      // Levels can have the same dimensions but differing bandwidths - since levels are ordered, we can look to the next
8900      // to determine whether we've chosen the greatest bandwidth for the media's dimensions
8901      var atGreatestBandwidth = function atGreatestBandwidth(curLevel, nextLevel) {
8902        if (!nextLevel) {
8903          return true;
8904        }
8905        return curLevel.width !== nextLevel.width || curLevel.height !== nextLevel.height;
8906      };
8907
8908      // If we run through the loop without breaking, the media's dimensions are greater than every level, so default to
8909      // the max level
8910      var maxLevelIndex = levels.length - 1;
8911      // Prevent changes in aspect-ratio from causing capping to toggle back and forth
8912      var squareSize = Math.max(width, height);
8913      for (var i = 0; i < levels.length; i += 1) {
8914        var level = levels[i];
8915        if ((level.width >= squareSize || level.height >= squareSize) && atGreatestBandwidth(level, levels[i + 1])) {
8916          maxLevelIndex = i;
8917          break;
8918        }
8919      }
8920      return maxLevelIndex;
8921    };
8922    return _createClass(CapLevelController, [{
8923      key: "mediaWidth",
8924      get: function get() {
8925        return this.getDimensions().width * this.contentScaleFactor;
8926      }
8927    }, {
8928      key: "mediaHeight",
8929      get: function get() {
8930        return this.getDimensions().height * this.contentScaleFactor;
8931      }
8932    }, {
8933      key: "contentScaleFactor",
8934      get: function get() {
8935        var pixelRatio = 1;
8936        if (!this.hls.config.ignoreDevicePixelRatio) {
8937          try {
8938            pixelRatio = self.devicePixelRatio;
8939          } catch (e) {
8940            /* no-op */
8941          }
8942        }
8943        return pixelRatio;
8944      }
8945    }]);
8946  }();
8947
8948  var FPSController = /*#__PURE__*/function () {
8949    function FPSController(hls) {
8950      this.hls = void 0;
8951      this.isVideoPlaybackQualityAvailable = false;
vendor: 4,598 bytes, lines 8952-9061
8952      this.timer = void 0;
8953      this.media = null;
8954      this.lastTime = void 0;
8955      this.lastDroppedFrames = 0;
8956      this.lastDecodedFrames = 0;
8957      // stream controller must be provided as a dependency!
8958      this.streamController = void 0;
8959      this.hls = hls;
8960      this.registerListeners();
8961    }
8962    var _proto = FPSController.prototype;
8963    _proto.setStreamController = function setStreamController(streamController) {
8964      this.streamController = streamController;
8965    };
8966    _proto.registerListeners = function registerListeners() {
8967      this.hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
8968      this.hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
8969    };
8970    _proto.unregisterListeners = function unregisterListeners() {
8971      this.hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
8972      this.hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
8973    };
8974    _proto.destroy = function destroy() {
8975      if (this.timer) {
8976        clearInterval(this.timer);
8977      }
8978      this.unregisterListeners();
8979      this.isVideoPlaybackQualityAvailable = false;
8980      this.media = null;
8981    };
8982    _proto.onMediaAttaching = function onMediaAttaching(event, data) {
8983      var config = this.hls.config;
8984      if (config.capLevelOnFPSDrop) {
8985        var media = data.media instanceof self.HTMLVideoElement ? data.media : null;
8986        this.media = media;
8987        if (media && typeof media.getVideoPlaybackQuality === 'function') {
8988          this.isVideoPlaybackQualityAvailable = true;
8989        }
8990        self.clearInterval(this.timer);
8991        this.timer = self.setInterval(this.checkFPSInterval.bind(this), config.fpsDroppedMonitoringPeriod);
8992      }
8993    };
8994    _proto.onMediaDetaching = function onMediaDetaching() {
8995      this.media = null;
8996    };
8997    _proto.checkFPS = function checkFPS(video, decodedFrames, droppedFrames) {
8998      var currentTime = performance.now();
8999      if (decodedFrames) {
9000        if (this.lastTime) {
9001          var currentPeriod = currentTime - this.lastTime;
9002          var currentDropped = droppedFrames - this.lastDroppedFrames;
9003          var currentDecoded = decodedFrames - this.lastDecodedFrames;
9004          var droppedFPS = 1000 * currentDropped / currentPeriod;
9005          var hls = this.hls;
9006          hls.trigger(Events.FPS_DROP, {
9007            currentDropped: currentDropped,
9008            currentDecoded: currentDecoded,
9009            totalDroppedFrames: droppedFrames
9010          });
9011          if (droppedFPS > 0) {
9012            // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
9013            if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
9014              var currentLevel = hls.currentLevel;
9015              hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
9016              if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
9017                currentLevel = currentLevel - 1;
9018                hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
9019                  level: currentLevel,
9020                  droppedLevel: hls.currentLevel
9021                });
9022                hls.autoLevelCapping = currentLevel;
9023                this.streamController.nextLevelSwitch();
9024              }
9025            }
9026          }
9027        }
9028        this.lastTime = currentTime;
9029        this.lastDroppedFrames = droppedFrames;
9030        this.lastDecodedFrames = decodedFrames;
9031      }
9032    };
9033    _proto.checkFPSInterval = function checkFPSInterval() {
9034      var video = this.media;
9035      if (video) {
9036        if (this.isVideoPlaybackQualityAvailable) {
9037          var videoPlaybackQuality = video.getVideoPlaybackQuality();
9038          this.checkFPS(video, videoPlaybackQuality.totalVideoFrames, videoPlaybackQuality.droppedVideoFrames);
9039        } else {
9040          // HTMLVideoElement doesn't include the webkit types
9041          this.checkFPS(video, video.webkitDecodedFrameCount, video.webkitDroppedFrameCount);
9042        }
9043      }
9044    };
9045    return FPSController;
9046  }();
9047
9048  var PATHWAY_PENALTY_DURATION_MS = 300000;
9049  var ContentSteeringController = /*#__PURE__*/function (_Logger) {
9050    function ContentSteeringController(hls) {
9051      var _this;
9052      _this = _Logger.call(this, 'content-steering', hls.logger) || this;
9053      _this.hls = void 0;
9054      _this.loader = null;
9055      _this.uri = null;
9056      _this.pathwayId = '.';
9057      _this._pathwayPriority = null;
9058      _this.timeToLoad = 300;
9059      _this.reloadTimer = -1;
9060      _this.updated = 0;
9061      _this.started = false;
vendor: 5,899 bytes, lines 9062-9212
9062      _this.enabled = true;
9063      _this.levels = null;
9064      _this.audioTracks = null;
9065      _this.subtitleTracks = null;
9066      _this.penalizedPathways = {};
9067      _this.hls = hls;
9068      _this.registerListeners();
9069      return _this;
9070    }
9071    _inheritsLoose(ContentSteeringController, _Logger);
9072    var _proto = ContentSteeringController.prototype;
9073    _proto.registerListeners = function registerListeners() {
9074      var hls = this.hls;
9075      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
9076      hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
9077      hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
9078      hls.on(Events.ERROR, this.onError, this);
9079    };
9080    _proto.unregisterListeners = function unregisterListeners() {
9081      var hls = this.hls;
9082      if (!hls) {
9083        return;
9084      }
9085      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
9086      hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
9087      hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
9088      hls.off(Events.ERROR, this.onError, this);
9089    };
9090    _proto.pathways = function pathways() {
9091      return (this.levels || []).reduce(function (pathways, level) {
9092        if (pathways.indexOf(level.pathwayId) === -1) {
9093          pathways.push(level.pathwayId);
9094        }
9095        return pathways;
9096      }, []);
9097    };
9098    _proto.startLoad = function startLoad() {
9099      this.started = true;
9100      this.clearTimeout();
9101      if (this.enabled && this.uri) {
9102        if (this.updated) {
9103          var ttl = this.timeToLoad * 1000 - (performance.now() - this.updated);
9104          if (ttl > 0) {
9105            this.scheduleRefresh(this.uri, ttl);
9106            return;
9107          }
9108        }
9109        this.loadSteeringManifest(this.uri);
9110      }
9111    };
9112    _proto.stopLoad = function stopLoad() {
9113      this.started = false;
9114      if (this.loader) {
9115        this.loader.destroy();
9116        this.loader = null;
9117      }
9118      this.clearTimeout();
9119    };
9120    _proto.clearTimeout = function clearTimeout() {
9121      if (this.reloadTimer !== -1) {
9122        self.clearTimeout(this.reloadTimer);
9123        this.reloadTimer = -1;
9124      }
9125    };
9126    _proto.destroy = function destroy() {
9127      this.unregisterListeners();
9128      this.stopLoad();
9129      // @ts-ignore
9130      this.hls = null;
9131      this.levels = this.audioTracks = this.subtitleTracks = null;
9132    };
9133    _proto.removeLevel = function removeLevel(levelToRemove) {
9134      var levels = this.levels;
9135      if (levels) {
9136        this.levels = levels.filter(function (level) {
9137          return level !== levelToRemove;
9138        });
9139      }
9140    };
9141    _proto.onManifestLoading = function onManifestLoading() {
9142      this.stopLoad();
9143      this.enabled = true;
9144      this.timeToLoad = 300;
9145      this.updated = 0;
9146      this.uri = null;
9147      this.pathwayId = '.';
9148      this.levels = this.audioTracks = this.subtitleTracks = null;
9149    };
9150    _proto.onManifestLoaded = function onManifestLoaded(event, data) {
9151      var contentSteering = data.contentSteering;
9152      if (contentSteering === null) {
9153        return;
9154      }
9155      this.pathwayId = contentSteering.pathwayId;
9156      this.uri = contentSteering.uri;
9157      if (this.started) {
9158        this.startLoad();
9159      }
9160    };
9161    _proto.onManifestParsed = function onManifestParsed(event, data) {
9162      this.audioTracks = data.audioTracks;
9163      this.subtitleTracks = data.subtitleTracks;
9164    };
9165    _proto.onError = function onError(event, data) {
9166      var errorAction = data.errorAction;
9167      if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox && errorAction.flags === ErrorActionFlags.MoveAllAlternatesMatchingHost) {
9168        var levels = this.levels;
9169        var pathwayPriority = this._pathwayPriority;
9170        var errorPathway = this.pathwayId;
9171        if (data.context) {
9172          var _data$context = data.context,
9173            groupId = _data$context.groupId,
9174            pathwayId = _data$context.pathwayId,
9175            type = _data$context.type;
9176          if (groupId && levels) {
9177            errorPathway = this.getPathwayForGroupId(groupId, type, errorPathway);
9178          } else if (pathwayId) {
9179            errorPathway = pathwayId;
9180          }
9181        }
9182        if (!(errorPathway in this.penalizedPathways)) {
9183          this.penalizedPathways[errorPathway] = performance.now();
9184        }
9185        if (!pathwayPriority && levels) {
9186          // If PATHWAY-PRIORITY was not provided, list pathways for error handling
9187          pathwayPriority = this.pathways();
9188        }
9189        if (pathwayPriority && pathwayPriority.length > 1) {
9190          this.updatePathwayPriority(pathwayPriority);
9191          errorAction.resolved = this.pathwayId !== errorPathway;
9192        }
9193        if (!errorAction.resolved) {
9194          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));
9195        }
9196      }
9197    };
9198    _proto.filterParsedLevels = function filterParsedLevels(levels) {
9199      // Filter levels to only include those that are in the initial pathway
9200      this.levels = levels;
9201      var pathwayLevels = this.getLevelsForPathway(this.pathwayId);
9202      if (pathwayLevels.length === 0) {
9203        var pathwayId = levels[0].pathwayId;
9204        this.log("No levels found in Pathway " + this.pathwayId + ". Setting initial Pathway to \"" + pathwayId + "\"");
9205        pathwayLevels = this.getLevelsForPathway(pathwayId);
9206        this.pathwayId = pathwayId;
9207      }
9208      if (pathwayLevels.length !== levels.length) {
9209        this.log("Found " + pathwayLevels.length + "/" + levels.length + " levels in Pathway \"" + this.pathwayId + "\"");
9210        return pathwayLevels;
9211      }
9212      return l
vendor: 11,507 bytes, lines 9212-9488
9212evels;
9213    };
9214    _proto.getLevelsForPathway = function getLevelsForPathway(pathwayId) {
9215      if (this.levels === null) {
9216        return [];
9217      }
9218      return this.levels.filter(function (level) {
9219        return pathwayId === level.pathwayId;
9220      });
9221    };
9222    _proto.updatePathwayPriority = function updatePathwayPriority(pathwayPriority) {
9223      this._pathwayPriority = pathwayPriority;
9224      var levels;
9225
9226      // Evaluate if we should remove the pathway from the penalized list
9227      var penalizedPathways = this.penalizedPathways;
9228      var now = performance.now();
9229      Object.keys(penalizedPathways).forEach(function (pathwayId) {
9230        if (now - penalizedPathways[pathwayId] > PATHWAY_PENALTY_DURATION_MS) {
9231          delete penalizedPathways[pathwayId];
9232        }
9233      });
9234      for (var i = 0; i < pathwayPriority.length; i++) {
9235        var pathwayId = pathwayPriority[i];
9236        if (pathwayId in penalizedPathways) {
9237          continue;
9238        }
9239        if (pathwayId === this.pathwayId) {
9240          return;
9241        }
9242        var selectedIndex = this.hls.nextLoadLevel;
9243        var selectedLevel = this.hls.levels[selectedIndex];
9244        levels = this.getLevelsForPathway(pathwayId);
9245        if (levels.length > 0) {
9246          this.log("Setting Pathway to \"" + pathwayId + "\"");
9247          this.pathwayId = pathwayId;
9248          reassignFragmentLevelIndexes(levels);
9249          this.hls.trigger(Events.LEVELS_UPDATED, {
9250            levels: levels
9251          });
9252          // Set LevelController's level to trigger LEVEL_SWITCHING which loads playlist if needed
9253          var levelAfterChange = this.hls.levels[selectedIndex];
9254          if (selectedLevel && levelAfterChange && this.levels) {
9255            if (levelAfterChange.attrs['STABLE-VARIANT-ID'] !== selectedLevel.attrs['STABLE-VARIANT-ID'] && levelAfterChange.bitrate !== selectedLevel.bitrate) {
9256              this.log("Unstable Pathways change from bitrate " + selectedLevel.bitrate + " to " + levelAfterChange.bitrate);
9257            }
9258            this.hls.nextLoadLevel = selectedIndex;
9259          }
9260          break;
9261        }
9262      }
9263    };
9264    _proto.getPathwayForGroupId = function getPathwayForGroupId(groupId, type, defaultPathway) {
9265      var levels = this.getLevelsForPathway(defaultPathway).concat(this.levels || []);
9266      for (var i = 0; i < levels.length; i++) {
9267        if (type === PlaylistContextType.AUDIO_TRACK && levels[i].hasAudioGroup(groupId) || type === PlaylistContextType.SUBTITLE_TRACK && levels[i].hasSubtitleGroup(groupId)) {
9268          return levels[i].pathwayId;
9269        }
9270      }
9271      return defaultPathway;
9272    };
9273    _proto.clonePathways = function clonePathways(pathwayClones) {
9274      var _this2 = this;
9275      var levels = this.levels;
9276      if (!levels) {
9277        return;
9278      }
9279      var audioGroupCloneMap = {};
9280      var subtitleGroupCloneMap = {};
9281      pathwayClones.forEach(function (pathwayClone) {
9282        var cloneId = pathwayClone.ID,
9283          baseId = pathwayClone['BASE-ID'],
9284          uriReplacement = pathwayClone['URI-REPLACEMENT'];
9285        if (levels.some(function (level) {
9286          return level.pathwayId === cloneId;
9287        })) {
9288          return;
9289        }
9290        var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
9291          var attributes = new AttrList(baseLevel.attrs);
9292          attributes['PATHWAY-ID'] = cloneId;
9293          var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
9294          var clonedSubtitleGroupId = attributes.SUBTITLES && attributes.SUBTITLES + "_clone_" + cloneId;
9295          if (clonedAudioGroupId) {
9296            audioGroupCloneMap[attributes.AUDIO] = clonedAudioGroupId;
9297            attributes.AUDIO = clonedAudioGroupId;
9298          }
9299          if (clonedSubtitleGroupId) {
9300            subtitleGroupCloneMap[attributes.SUBTITLES] = clonedSubtitleGroupId;
9301            attributes.SUBTITLES = clonedSubtitleGroupId;
9302          }
9303          var url = performUriReplacement(baseLevel.uri, attributes['STABLE-VARIANT-ID'], 'PER-VARIANT-URIS', uriReplacement);
9304          var clonedLevel = new Level({
9305            attrs: attributes,
9306            audioCodec: baseLevel.audioCodec,
9307            bitrate: baseLevel.bitrate,
9308            height: baseLevel.height,
9309            name: baseLevel.name,
9310            url: url,
9311            videoCodec: baseLevel.videoCodec,
9312            width: baseLevel.width
9313          });
9314          if (baseLevel.audioGroups) {
9315            for (var i = 1; i < baseLevel.audioGroups.length; i++) {
9316              clonedLevel.addGroupId('audio', baseLevel.audioGroups[i] + "_clone_" + cloneId);
9317            }
9318          }
9319          if (baseLevel.subtitleGroups) {
9320            for (var _i = 1; _i < baseLevel.subtitleGroups.length; _i++) {
9321              clonedLevel.addGroupId('text', baseLevel.subtitleGroups[_i] + "_clone_" + cloneId);
9322            }
9323          }
9324          return clonedLevel;
9325        });
9326        levels.push.apply(levels, clonedVariants);
9327        cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
9328        cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
9329      });
9330    };
9331    _proto.loadSteeringManifest = function loadSteeringManifest(uri) {
9332      var _this3 = this;
9333      var config = this.hls.config;
9334      var Loader = config.loader;
9335      if (this.loader) {
9336        this.loader.destroy();
9337      }
9338      this.loader = new Loader(config);
9339      var url;
9340      try {
9341        url = new self.URL(uri);
9342      } catch (error) {
9343        this.enabled = false;
9344        this.log("Failed to parse Steering Manifest URI: " + uri);
9345        return;
9346      }
9347      if (url.protocol !== 'data:') {
9348        var throughput = (this.hls.bandwidthEstimate || config.abrEwmaDefaultEstimate) | 0;
9349        url.searchParams.set('_HLS_pathway', this.pathwayId);
9350        url.searchParams.set('_HLS_throughput', '' + throughput);
9351      }
9352      var context = {
9353        responseType: 'json',
9354        url: url.href
9355      };
9356      var loadPolicy = config.steeringManifestLoadPolicy.default;
9357      var legacyRetryCompatibility = loadPolicy.errorRetry || loadPolicy.timeoutRetry || {};
9358      var loaderConfig = {
9359        loadPolicy: loadPolicy,
9360        timeout: loadPolicy.maxLoadTimeMs,
9361        maxRetry: legacyRetryCompatibility.maxNumRetry || 0,
9362        retryDelay: legacyRetryCompatibility.retryDelayMs || 0,
9363        maxRetryDelay: legacyRetryCompatibility.maxRetryDelayMs || 0
9364      };
9365      var callbacks = {
9366        onSuccess: function onSuccess(response, stats, context, networkDetails) {
9367          _this3.log("Loaded steering manifest: \"" + url + "\"");
9368          var steeringData = response.data;
9369          if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
9370            _this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
9371            return;
9372          }
9373          _this3.updated = performance.now();
9374          _this3.timeToLoad = steeringData.TTL;
9375          var reloadUri = steeringData['RELOAD-URI'],
9376            pathwayClones = steeringData['PATHWAY-CLONES'],
9377            pathwayPriority = steeringData['PATHWAY-PRIORITY'];
9378          if (reloadUri) {
9379            try {
9380              _this3.uri = new self.URL(reloadUri, url).href;
9381            } catch (error) {
9382              _this3.enabled = false;
9383              _this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
9384              return;
9385            }
9386          }
9387          _this3.scheduleRefresh(_this3.uri || context.url);
9388          if (pathwayClones) {
9389            _this3.clonePathways(pathwayClones);
9390          }
9391          var loadedSteeringData = {
9392            steeringManifest: steeringData,
9393            url: url.toString()
9394          };
9395          _this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
9396          if (pathwayPriority) {
9397            _this3.updatePathwayPriority(pathwayPriority);
9398          }
9399        },
9400        onError: function onError(error, context, networkDetails, stats) {
9401          _this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
9402          _this3.stopLoad();
9403          if (error.code === 410) {
9404            _this3.enabled = false;
9405            _this3.log("Steering manifest " + context.url + " no longer available");
9406            return;
9407          }
9408          var ttl = _this3.timeToLoad * 1000;
9409          if (error.code === 429) {
9410            var loader = _this3.loader;
9411            if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
9412              var retryAfter = loader.getResponseHeader('Retry-After');
9413              if (retryAfter) {
9414                ttl = parseFloat(retryAfter) * 1000;
9415              }
9416            }
9417            _this3.log("Steering manifest " + context.url + " rate limited");
9418            return;
9419          }
9420          _this3.scheduleRefresh(_this3.uri || context.url, ttl);
9421        },
9422        onTimeout: function onTimeout(stats, context, networkDetails) {
9423          _this3.log("Timeout loading steering manifest (" + context.url + ")");
9424          _this3.scheduleRefresh(_this3.uri || context.url);
9425        }
9426      };
9427      this.log("Requesting steering manifest: " + url);
9428      this.loader.load(context, loaderConfig, callbacks);
9429    };
9430    _proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
9431      var _this4 = this;
9432      if (ttlMs === void 0) {
9433        ttlMs = this.timeToLoad * 1000;
9434      }
9435      this.clearTimeout();
9436      this.reloadTimer = self.setTimeout(function () {
9437        var _this4$hls;
9438        var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
9439        if (media && !media.ended) {
9440          _this4.loadSteeringManifest(uri);
9441          return;
9442        }
9443        _this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
9444      }, ttlMs);
9445    };
9446    return _createClass(ContentSteeringController, [{
9447      key: "pathwayPriority",
9448      get: function get() {
9449        return this._pathwayPriority;
9450      },
9451      set: function set(pathwayPriority) {
9452        this.updatePathwayPriority(pathwayPriority);
9453      }
9454    }]);
9455  }(Logger);
9456  function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
9457    if (!tracks) {
9458      return;
9459    }
9460    Object.keys(groupCloneMap).forEach(function (audioGroupId) {
9461      var clonedTracks = tracks.filter(function (track) {
9462        return track.groupId === audioGroupId;
9463      }).map(function (track) {
9464        var clonedTrack = _extends({}, track);
9465        clonedTrack.details = undefined;
9466        clonedTrack.attrs = new AttrList(clonedTrack.attrs);
9467        clonedTrack.url = clonedTrack.attrs.URI = performUriReplacement(track.url, track.attrs['STABLE-RENDITION-ID'], 'PER-RENDITION-URIS', uriReplacement);
9468        clonedTrack.groupId = clonedTrack.attrs['GROUP-ID'] = groupCloneMap[audioGroupId];
9469        clonedTrack.attrs['PATHWAY-ID'] = cloneId;
9470        return clonedTrack;
9471      });
9472      tracks.push.apply(tracks, clonedTracks);
9473    });
9474  }
9475  function performUriReplacement(uri, stableId, perOptionKey, uriReplacement) {
9476    var host = uriReplacement.HOST,
9477      params = uriReplacement.PARAMS,
9478      perOptionUris = uriReplacement[perOptionKey];
9479    var perVariantUri;
9480    if (stableId) {
9481      perVariantUri = perOptionUris == null ? void 0 : perOptionUris[stableId];
9482      if (perVariantUri) {
9483        uri = perVariantUri;
9484      }
9485    }
9486    var url = new self.URL(uri);
9487    if (host && !perVariantUri) {
9488      url.host
vendor: 19,122 bytes, lines 9488-10005
9488 = host;
9489    }
9490    if (params) {
9491      Object.keys(params).sort().forEach(function (key) {
9492        if (key) {
9493          url.searchParams.set(key, params[key]);
9494        }
9495      });
9496    }
9497    return url.href;
9498  }
9499
9500  var AGE_HEADER_LINE_REGEX = /^age:\s*[\d.]+\s*$/im;
9501  var XhrLoader = /*#__PURE__*/function () {
9502    function XhrLoader(config) {
9503      this.xhrSetup = void 0;
9504      this.requestTimeout = void 0;
9505      this.retryTimeout = void 0;
9506      this.retryDelay = void 0;
9507      this.config = null;
9508      this.callbacks = null;
9509      this.context = null;
9510      this.loader = null;
9511      this.stats = void 0;
9512      this.xhrSetup = config ? config.xhrSetup || null : null;
9513      this.stats = new LoadStats();
9514      this.retryDelay = 0;
9515    }
9516    var _proto = XhrLoader.prototype;
9517    _proto.destroy = function destroy() {
9518      this.callbacks = null;
9519      this.abortInternal();
9520      this.loader = null;
9521      this.config = null;
9522      this.context = null;
9523      this.xhrSetup = null;
9524    };
9525    _proto.abortInternal = function abortInternal() {
9526      var loader = this.loader;
9527      self.clearTimeout(this.requestTimeout);
9528      self.clearTimeout(this.retryTimeout);
9529      if (loader) {
9530        loader.onreadystatechange = null;
9531        loader.onprogress = null;
9532        if (loader.readyState !== 4) {
9533          this.stats.aborted = true;
9534          loader.abort();
9535        }
9536      }
9537    };
9538    _proto.abort = function abort() {
9539      var _this$callbacks;
9540      this.abortInternal();
9541      if ((_this$callbacks = this.callbacks) != null && _this$callbacks.onAbort) {
9542        this.callbacks.onAbort(this.stats, this.context, this.loader);
9543      }
9544    };
9545    _proto.load = function load(context, config, callbacks) {
9546      if (this.stats.loading.start) {
9547        throw new Error('Loader can only be used once.');
9548      }
9549      this.stats.loading.start = self.performance.now();
9550      this.context = context;
9551      this.config = config;
9552      this.callbacks = callbacks;
9553      this.loadInternal();
9554    };
9555    _proto.loadInternal = function loadInternal() {
9556      var _this = this;
9557      var config = this.config,
9558        context = this.context;
9559      if (!config || !context) {
9560        return;
9561      }
9562      var xhr = this.loader = new self.XMLHttpRequest();
9563      var stats = this.stats;
9564      stats.loading.first = 0;
9565      stats.loaded = 0;
9566      stats.aborted = false;
9567      var xhrSetup = this.xhrSetup;
9568      if (xhrSetup) {
9569        Promise.resolve().then(function () {
9570          if (_this.loader !== xhr || _this.stats.aborted) return;
9571          return xhrSetup(xhr, context.url);
9572        }).catch(function (error) {
9573          if (_this.loader !== xhr || _this.stats.aborted) return;
9574          xhr.open('GET', context.url, true);
9575          return xhrSetup(xhr, context.url);
9576        }).then(function () {
9577          if (_this.loader !== xhr || _this.stats.aborted) return;
9578          _this.openAndSendXhr(xhr, context, config);
9579        }).catch(function (error) {
9580          // IE11 throws an exception on xhr.open if attempting to access an HTTP resource over HTTPS
9581          _this.callbacks.onError({
9582            code: xhr.status,
9583            text: error.message
9584          }, context, xhr, stats);
9585          return;
9586        });
9587      } else {
9588        this.openAndSendXhr(xhr, context, config);
9589      }
9590    };
9591    _proto.openAndSendXhr = function openAndSendXhr(xhr, context, config) {
9592      if (!xhr.readyState) {
9593        xhr.open('GET', context.url, true);
9594      }
9595      var headers = context.headers;
9596      var _config$loadPolicy = config.loadPolicy,
9597        maxTimeToFirstByteMs = _config$loadPolicy.maxTimeToFirstByteMs,
9598        maxLoadTimeMs = _config$loadPolicy.maxLoadTimeMs;
9599      if (headers) {
9600        for (var header in headers) {
9601          xhr.setRequestHeader(header, headers[header]);
9602        }
9603      }
9604      if (context.rangeEnd) {
9605        xhr.setRequestHeader('Range', 'bytes=' + context.rangeStart + '-' + (context.rangeEnd - 1));
9606      }
9607      xhr.onreadystatechange = this.readystatechange.bind(this);
9608      xhr.onprogress = this.loadprogress.bind(this);
9609      xhr.responseType = context.responseType;
9610      // setup timeout before we perform request
9611      self.clearTimeout(this.requestTimeout);
9612      config.timeout = maxTimeToFirstByteMs && isFiniteNumber(maxTimeToFirstByteMs) ? maxTimeToFirstByteMs : maxLoadTimeMs;
9613      this.requestTimeout = self.setTimeout(this.loadtimeout.bind(this), config.timeout);
9614      xhr.send();
9615    };
9616    _proto.readystatechange = function readystatechange() {
9617      var context = this.context,
9618        xhr = this.loader,
9619        stats = this.stats;
9620      if (!context || !xhr) {
9621        return;
9622      }
9623      var readyState = xhr.readyState;
9624      var config = this.config;
9625
9626      // don't proceed if xhr has been aborted
9627      if (stats.aborted) {
9628        return;
9629      }
9630
9631      // >= HEADERS_RECEIVED
9632      if (readyState >= 2) {
9633        if (stats.loading.first === 0) {
9634          stats.loading.first = Math.max(self.performance.now(), stats.loading.start);
9635          // readyState >= 2 AND readyState !==4 (readyState = HEADERS_RECEIVED || LOADING) rearm timeout as xhr not finished yet
9636          if (config.timeout !== config.loadPolicy.maxLoadTimeMs) {
9637            self.clearTimeout(this.requestTimeout);
9638            config.timeout = config.loadPolicy.maxLoadTimeMs;
9639            this.requestTimeout = self.setTimeout(this.loadtimeout.bind(this), config.loadPolicy.maxLoadTimeMs - (stats.loading.first - stats.loading.start));
9640          }
9641        }
9642        if (readyState === 4) {
9643          self.clearTimeout(this.requestTimeout);
9644          xhr.onreadystatechange = null;
9645          xhr.onprogress = null;
9646          var _status = xhr.status;
9647          // http status between 200 to 299 are all successful
9648          var useResponse = xhr.responseType !== 'text';
9649          if (_status >= 200 && _status < 300 && (useResponse && xhr.response || xhr.responseText !== null)) {
9650            stats.loading.end = Math.max(self.performance.now(), stats.loading.first);
9651            var data = useResponse ? xhr.response : xhr.responseText;
9652            var len = xhr.responseType === 'arraybuffer' ? data.byteLength : data.length;
9653            stats.loaded = stats.total = len;
9654            stats.bwEstimate = stats.total * 8000 / (stats.loading.end - stats.loading.first);
9655            if (!this.callbacks) {
9656              return;
9657            }
9658            var onProgress = this.callbacks.onProgress;
9659            if (onProgress) {
9660              onProgress(stats, context, data, xhr);
9661            }
9662            if (!this.callbacks) {
9663              return;
9664            }
9665            var response = {
9666              url: xhr.responseURL,
9667              data: data,
9668              code: _status
9669            };
9670            this.callbacks.onSuccess(response, stats, context, xhr);
9671          } else {
9672            var retryConfig = config.loadPolicy.errorRetry;
9673            var retryCount = stats.retry;
9674            // if max nb of retries reached or if http status between 400 and 499 (such error cannot be recovered, retrying is useless), return error
9675            var _response = {
9676              url: context.url,
9677              data: undefined,
9678              code: _status
9679            };
9680            if (shouldRetry(retryConfig, retryCount, false, _response)) {
9681              this.retry(retryConfig);
9682            } else {
9683              logger.error(_status + " while loading " + context.url);
9684              this.callbacks.onError({
9685                code: _status,
9686                text: xhr.statusText
9687              }, context, xhr, stats);
9688            }
9689          }
9690        }
9691      }
9692    };
9693    _proto.loadtimeout = function loadtimeout() {
9694      if (!this.config) return;
9695      var retryConfig = this.config.loadPolicy.timeoutRetry;
9696      var retryCount = this.stats.retry;
9697      if (shouldRetry(retryConfig, retryCount, true)) {
9698        this.retry(retryConfig);
9699      } else {
9700        var _this$context;
9701        logger.warn("timeout while loading " + ((_this$context = this.context) == null ? void 0 : _this$context.url));
9702        var callbacks = this.callbacks;
9703        if (callbacks) {
9704          this.abortInternal();
9705          callbacks.onTimeout(this.stats, this.context, this.loader);
9706        }
9707      }
9708    };
9709    _proto.retry = function retry(retryConfig) {
9710      var context = this.context,
9711        stats = this.stats;
9712      this.retryDelay = getRetryDelay(retryConfig, stats.retry);
9713      stats.retry++;
9714      logger.warn((status ? 'HTTP Status ' + status : 'Timeout') + " while loading " + (context == null ? void 0 : context.url) + ", retrying " + stats.retry + "/" + retryConfig.maxNumRetry + " in " + this.retryDelay + "ms");
9715      // abort and reset internal state
9716      this.abortInternal();
9717      this.loader = null;
9718      // schedule retry
9719      self.clearTimeout(this.retryTimeout);
9720      this.retryTimeout = self.setTimeout(this.loadInternal.bind(this), this.retryDelay);
9721    };
9722    _proto.loadprogress = function loadprogress(event) {
9723      var stats = this.stats;
9724      stats.loaded = event.loaded;
9725      if (event.lengthComputable) {
9726        stats.total = event.total;
9727      }
9728    };
9729    _proto.getCacheAge = function getCacheAge() {
9730      var result = null;
9731      if (this.loader && AGE_HEADER_LINE_REGEX.test(this.loader.getAllResponseHeaders())) {
9732        var ageHeader = this.loader.getResponseHeader('age');
9733        result = ageHeader ? parseFloat(ageHeader) : null;
9734      }
9735      return result;
9736    };
9737    _proto.getResponseHeader = function getResponseHeader(name) {
9738      if (this.loader && new RegExp("^" + name + ":\\s*[\\d.]+\\s*$", 'im').test(this.loader.getAllResponseHeaders())) {
9739        return this.loader.getResponseHeader(name);
9740      }
9741      return null;
9742    };
9743    return XhrLoader;
9744  }();
9745
9746  var ChunkCache = /*#__PURE__*/function () {
9747    function ChunkCache() {
9748      this.chunks = [];
9749      this.dataLength = 0;
9750    }
9751    var _proto = ChunkCache.prototype;
9752    _proto.push = function push(chunk) {
9753      this.chunks.push(chunk);
9754      this.dataLength += chunk.length;
9755    };
9756    _proto.flush = function flush() {
9757      var chunks = this.chunks,
9758        dataLength = this.dataLength;
9759      var result;
9760      if (!chunks.length) {
9761        return new Uint8Array(0);
9762      } else if (chunks.length === 1) {
9763        result = chunks[0];
9764      } else {
9765        result = concatUint8Arrays(chunks, dataLength);
9766      }
9767      this.reset();
9768      return result;
9769    };
9770    _proto.reset = function reset() {
9771      this.chunks.length = 0;
9772      this.dataLength = 0;
9773    };
9774    return ChunkCache;
9775  }();
9776  function concatUint8Arrays(chunks, dataLength) {
9777    var result = new Uint8Array(dataLength);
9778    var offset = 0;
9779    for (var i = 0; i < chunks.length; i++) {
9780      var chunk = chunks[i];
9781      result.set(chunk, offset);
9782      offset += chunk.length;
9783    }
9784    return result;
9785  }
9786
9787  function fetchSupported() {
9788    if (
9789    // @ts-ignore
9790    self.fetch && self.AbortController && self.ReadableStream && self.Request) {
9791      try {
9792        new self.ReadableStream({}); // eslint-disable-line no-new
9793        return true;
9794      } catch (e) {
9795        /* noop */
9796      }
9797    }
9798    return false;
9799  }
9800  var BYTERANGE = /(\d+)-(\d+)\/(\d+)/;
9801  var FetchLoader = /*#__PURE__*/function () {
9802    function FetchLoader(config /* HlsConfig */) {
9803      this.fetchSetup = void 0;
9804      this.requestTimeout = void 0;
9805      this.request = null;
9806      this.response = null;
9807      this.controller = void 0;
9808      this.context = null;
9809      this.config = null;
9810      this.callbacks = null;
9811      this.stats = void 0;
9812      this.loader = null;
9813      this.fetchSetup = config.fetchSetup || getRequest;
9814      this.controller = new self.AbortController();
9815      this.stats = new LoadStats();
9816    }
9817    var _proto = FetchLoader.prototype;
9818    _proto.destroy = function destroy() {
9819      this.loader = this.callbacks = this.context = this.config = this.request = null;
9820      this.abortInternal();
9821      this.response = null;
9822      // @ts-ignore
9823      this.fetchSetup = this.controller = this.stats = null;
9824    };
9825    _proto.abortInternal = function abortInternal() {
9826      if (this.controller && !this.stats.loading.end) {
9827        this.stats.aborted = true;
9828        this.controller.abort();
9829      }
9830    };
9831    _proto.abort = function abort() {
9832      var _this$callbacks;
9833      this.abortInternal();
9834      if ((_this$callbacks = this.callbacks) != null && _this$callbacks.onAbort) {
9835        this.callbacks.onAbort(this.stats, this.context, this.response);
9836      }
9837    };
9838    _proto.load = function load(context, config, callbacks) {
9839      var _this = this;
9840      var stats = this.stats;
9841      if (stats.loading.start) {
9842        throw new Error('Loader can only be used once.');
9843      }
9844      stats.loading.start = self.performance.now();
9845      var initParams = getRequestParameters(context, this.controller.signal);
9846      var onProgress = callbacks.onProgress;
9847      var isArrayBuffer = context.responseType === 'arraybuffer';
9848      var LENGTH = isArrayBuffer ? 'byteLength' : 'length';
9849      var _config$loadPolicy = config.loadPolicy,
9850        maxTimeToFirstByteMs = _config$loadPolicy.maxTimeToFirstByteMs,
9851        maxLoadTimeMs = _config$loadPolicy.maxLoadTimeMs;
9852      this.context = context;
9853      this.config = config;
9854      this.callbacks = callbacks;
9855      this.request = this.fetchSetup(context, initParams);
9856      self.clearTimeout(this.requestTimeout);
9857      config.timeout = maxTimeToFirstByteMs && isFiniteNumber(maxTimeToFirstByteMs) ? maxTimeToFirstByteMs : maxLoadTimeMs;
9858      this.requestTimeout = self.setTimeout(function () {
9859        _this.abortInternal();
9860        callbacks.onTimeout(stats, context, _this.response);
9861      }, config.timeout);
9862      self.fetch(this.request).then(function (response) {
9863        _this.response = _this.loader = response;
9864        var first = Math.max(self.performance.now(), stats.loading.start);
9865        self.clearTimeout(_this.requestTimeout);
9866        config.timeout = maxLoadTimeMs;
9867        _this.requestTimeout = self.setTimeout(function () {
9868          _this.abortInternal();
9869          callbacks.onTimeout(stats, context, _this.response);
9870        }, maxLoadTimeMs - (first - stats.loading.start));
9871        if (!response.ok) {
9872          var status = response.status,
9873            statusText = response.statusText;
9874          throw new FetchError(statusText || 'fetch, bad network response', status, response);
9875        }
9876        stats.loading.first = first;
9877        stats.total = getContentLength(response.headers) || stats.total;
9878        if (onProgress && isFiniteNumber(config.highWaterMark)) {
9879          return _this.loadProgressively(response, stats, context, config.highWaterMark, onProgress);
9880        }
9881        if (isArrayBuffer) {
9882          return response.arrayBuffer();
9883        }
9884        if (context.responseType === 'json') {
9885          return response.json();
9886        }
9887        return response.text();
9888      }).then(function (responseData) {
9889        var response = _this.response;
9890        if (!response) {
9891          throw new Error('loader destroyed');
9892        }
9893        self.clearTimeout(_this.requestTimeout);
9894        stats.loading.end = Math.max(self.performance.now(), stats.loading.first);
9895        var total = responseData[LENGTH];
9896        if (total) {
9897          stats.loaded = stats.total = total;
9898        }
9899        var loaderResponse = {
9900          url: response.url,
9901          data: responseData,
9902          code: response.status
9903        };
9904        if (onProgress && !isFiniteNumber(config.highWaterMark)) {
9905          onProgress(stats, context, responseData, response);
9906        }
9907        callbacks.onSuccess(loaderResponse, stats, context, response);
9908      }).catch(function (error) {
9909        self.clearTimeout(_this.requestTimeout);
9910        if (stats.aborted) {
9911          return;
9912        }
9913        // CORS errors result in an undefined code. Set it to 0 here to align with XHR's behavior
9914        // when destroying, 'error' itself can be undefined
9915        var code = !error ? 0 : error.code || 0;
9916        var text = !error ? null : error.message;
9917        callbacks.onError({
9918          code: code,
9919          text: text
9920        }, context, error ? error.details : null, stats);
9921      });
9922    };
9923    _proto.getCacheAge = function getCacheAge() {
9924      var result = null;
9925      if (this.response) {
9926        var ageHeader = this.response.headers.get('age');
9927        result = ageHeader ? parseFloat(ageHeader) : null;
9928      }
9929      return result;
9930    };
9931    _proto.getResponseHeader = function getResponseHeader(name) {
9932      return this.response ? this.response.headers.get(name) : null;
9933    };
9934    _proto.loadProgressively = function loadProgressively(response, stats, context, highWaterMark, onProgress) {
9935      if (highWaterMark === void 0) {
9936        highWaterMark = 0;
9937      }
9938      var chunkCache = new ChunkCache();
9939      var reader = response.body.getReader();
9940      var _pump = function pump() {
9941        return reader.read().then(function (data) {
9942          if (data.done) {
9943            if (chunkCache.dataLength) {
9944              onProgress(stats, context, chunkCache.flush(), response);
9945            }
9946            return Promise.resolve(new ArrayBuffer(0));
9947          }
9948          var chunk = data.value;
9949          var len = chunk.length;
9950          stats.loaded += len;
9951          if (len < highWaterMark || chunkCache.dataLength) {
9952            // The current chunk is too small to to be emitted or the cache already has data
9953            // Push it to the cache
9954            chunkCache.push(chunk);
9955            if (chunkCache.dataLength >= highWaterMark) {
9956              // flush in order to join the typed arrays
9957              onProgress(stats, context, chunkCache.flush(), response);
9958            }
9959          } else {
9960            // If there's nothing cached already, and the chache is large enough
9961            // just emit the progress event
9962            onProgress(stats, context, chunk, response);
9963          }
9964          return _pump();
9965        }).catch(function () {
9966          /* aborted */
9967          return Promise.reject();
9968        });
9969      };
9970      return _pump();
9971    };
9972    return FetchLoader;
9973  }();
9974  function getRequestParameters(context, signal) {
9975    var initParams = {
9976      method: 'GET',
9977      mode: 'cors',
9978      credentials: 'same-origin',
9979      signal: signal,
9980      headers: new self.Headers(_extends({}, context.headers))
9981    };
9982    if (context.rangeEnd) {
9983      initParams.headers.set('Range', 'bytes=' + context.rangeStart + '-' + String(context.rangeEnd - 1));
9984    }
9985    return initParams;
9986  }
9987  function getByteRangeLength(byteRangeHeader) {
9988    var result = BYTERANGE.exec(byteRangeHeader);
9989    if (result) {
9990      return parseInt(result[2]) - parseInt(result[1]) + 1;
9991    }
9992  }
9993  function getContentLength(headers) {
9994    var contentRange = headers.get('Content-Range');
9995    if (contentRange) {
9996      var byteRangeLength = getByteRangeLength(contentRange);
9997      if (isFiniteNumber(byteRangeLength)) {
9998        return byteRangeLength;
9999      }
10000    }
10001    var contentLength = headers.get('Content-Length');
10002    if (contentLength) {
10003      return parseInt(contentLength);
10004    }
10005  }
vendor: 5,236 bytes, lines 10006-10180
10006  function getRequest(context, initParams) {
10007    return new self.Request(context.url, initParams);
10008  }
10009  var FetchError = /*#__PURE__*/function (_Error) {
10010    function FetchError(message, code, details) {
10011      var _this2;
10012      _this2 = _Error.call(this, message) || this;
10013      _this2.code = void 0;
10014      _this2.details = void 0;
10015      _this2.code = code;
10016      _this2.details = details;
10017      return _this2;
10018    }
10019    _inheritsLoose(FetchError, _Error);
10020    return FetchError;
10021  }( /*#__PURE__*/_wrapNativeSuper(Error));
10022
10023  /**
10024   * @deprecated use fragLoadPolicy.default
10025   */
10026
10027  /**
10028   * @deprecated use manifestLoadPolicy.default and playlistLoadPolicy.default
10029   */
10030
10031  var defaultLoadPolicy = {
10032    maxTimeToFirstByteMs: 8000,
10033    maxLoadTimeMs: 20000,
10034    timeoutRetry: null,
10035    errorRetry: null
10036  };
10037
10038  /**
10039   * @ignore
10040   * If possible, keep hlsDefaultConfig shallow
10041   * It is cloned whenever a new Hls instance is created, by keeping the config
10042   * shallow the properties are cloned, and we don't end up manipulating the default
10043   */
10044  var hlsDefaultConfig = _objectSpread2(_objectSpread2({
10045    autoStartLoad: true,
10046    // used by stream-controller
10047    startPosition: -1,
10048    // used by stream-controller
10049    defaultAudioCodec: undefined,
10050    // used by stream-controller
10051    debug: false,
10052    // used by logger
10053    capLevelOnFPSDrop: false,
10054    // used by fps-controller
10055    capLevelToPlayerSize: false,
10056    // used by cap-level-controller
10057    ignoreDevicePixelRatio: false,
10058    // used by cap-level-controller
10059    preferManagedMediaSource: true,
10060    initialLiveManifestSize: 1,
10061    // used by stream-controller
10062    maxBufferLength: 30,
10063    // used by stream-controller
10064    backBufferLength: Infinity,
10065    // used by buffer-controller
10066    frontBufferFlushThreshold: Infinity,
10067    maxBufferSize: 60 * 1000 * 1000,
10068    // used by stream-controller
10069    maxBufferHole: 0.1,
10070    // used by stream-controller
10071    highBufferWatchdogPeriod: 2,
10072    // used by stream-controller
10073    nudgeOffset: 0.1,
10074    // used by stream-controller
10075    nudgeMaxRetry: 3,
10076    // used by stream-controller
10077    maxFragLookUpTolerance: 0.25,
10078    // used by stream-controller
10079    liveSyncDurationCount: 3,
10080    // used by latency-controller
10081    liveSyncOnStallIncrease: 1,
10082    // used by latency-controller
10083    liveMaxLatencyDurationCount: Infinity,
10084    // used by latency-controller
10085    liveSyncDuration: undefined,
10086    // used by latency-controller
10087    liveMaxLatencyDuration: undefined,
10088    // used by latency-controller
10089    maxLiveSyncPlaybackRate: 1,
10090    // used by latency-controller
10091    liveDurationInfinity: false,
10092    // used by buffer-controller
10093    /**
10094     * @deprecated use backBufferLength
10095     */
10096    liveBackBufferLength: null,
10097    // used by buffer-controller
10098    maxMaxBufferLength: 600,
10099    // used by stream-controller
10100    enableWorker: true,
10101    // used by transmuxer
10102    workerPath: null,
10103    // used by transmuxer
10104    enableSoftwareAES: true,
10105    // used by decrypter
10106    startLevel: undefined,
10107    // used by level-controller
10108    startFragPrefetch: false,
10109    // used by stream-controller
10110    fpsDroppedMonitoringPeriod: 5000,
10111    // used by fps-controller
10112    fpsDroppedMonitoringThreshold: 0.2,
10113    // used by fps-controller
10114    appendErrorMaxRetry: 3,
10115    // used by buffer-controller
10116    loader: XhrLoader,
10117    // loader: FetchLoader,
10118    fLoader: undefined,
10119    // used by fragment-loader
10120    pLoader: undefined,
10121    // used by playlist-loader
10122    xhrSetup: undefined,
10123    // used by xhr-loader
10124    licenseXhrSetup: undefined,
10125    // used by eme-controller
10126    licenseResponseCallback: undefined,
10127    // used by eme-controller
10128    abrController: AbrController,
10129    bufferController: BufferController,
10130    capLevelController: CapLevelController,
10131    errorController: ErrorController,
10132    fpsController: FPSController,
10133    stretchShortVideoTrack: false,
10134    // used by mp4-remuxer
10135    maxAudioFramesDrift: 1,
10136    // used by mp4-remuxer
10137    forceKeyFrameOnDiscontinuity: true,
10138    // used by ts-demuxer
10139    abrEwmaFastLive: 3,
10140    // used by abr-controller
10141    abrEwmaSlowLive: 9,
10142    // used by abr-controller
10143    abrEwmaFastVoD: 3,
10144    // used by abr-controller
10145    abrEwmaSlowVoD: 9,
10146    // used by abr-controller
10147    abrEwmaDefaultEstimate: 5e5,
10148    // 500 kbps  // used by abr-controller
10149    abrEwmaDefaultEstimateMax: 5e6,
10150    // 5 mbps
10151    abrBandWidthFactor: 0.95,
10152    // used by abr-controller
10153    abrBandWidthUpFactor: 0.7,
10154    // used by abr-controller
10155    abrMaxWithRealBitrate: false,
10156    // used by abr-controller
10157    maxStarvationDelay: 4,
10158    // used by abr-controller
10159    maxLoadingDelay: 4,
10160    // used by abr-controller
10161    minAutoBitrate: 0,
10162    // used by hls
10163    emeEnabled: false,
10164    // used by eme-controller
10165    widevineLicenseUrl: undefined,
10166    // used by eme-controller
10167    drmSystems: {},
10168    // used by eme-controller
10169    drmSystemOptions: {},
10170    // used by eme-controller
10171    requestMediaKeySystemAccessFunc: null,
10172    // used by eme-controller
10173    testBandwidth: true,
10174    progressive: false,
10175    lowLatencyMode: true,
10176    cmcd: undefined,
10177    enableDateRangeMetadataCues: true,
10178    enableEmsgMetadataCues: true,
10179    enableID3MetadataCues: true,
10180    useMediaCapabilities: false,
10181    certLoadPolicy: {
10182      default: defaultLoadPolicy
10183    },
10184    keyLoadPolicy: {
10185      default: {
10186        maxTimeToFirstByteMs: 8000,
10187        maxLoadTimeMs: 20000,
10188        timeoutRetry: {
10189          maxNumRetry: 1,
10190          retryDelayMs: 1000,
10191          maxRetryDelayMs: 20000,
10192          backoff: 'linear'
10193        },
10194        errorRetry: {
10195          maxNumRetry: 8,
10196          retryDelayMs: 1000,
10197          maxRetryDelayMs: 20000,
10198          backoff: 'linear'
10199        }
10200      }
10201    },
10202    manifestLoadPolicy: {
10203      default: {
10204        maxTimeToFirstByteMs: Infinity,
10205        maxLoadTimeMs: 20000,
10206        timeoutRetry: {
10207          maxNumRetry: 2,
10208          retryDelayMs: 0,
10209          maxRetryDelayMs: 0
10210        },
10211        errorRetry: {
10212          maxNumRetry: 1,
10213          retryDelayMs: 1000,
10214          maxRetryDelayMs: 8000
10215        }
10216      }
10217    },
10218    playlistLoadPolicy: {
10219      default: {
10220        maxTimeToFirstByteMs: 10000,
10221        maxLoadTimeMs: 20000,
10222        timeoutRetry: {
10223          maxNumRetry: 2,
10224          retryDelayMs: 0,
10225          maxRetryDelayMs: 0
10226        },
10227        errorRetry: {
10228          maxNumRetry: 2,
10229          retryDelayMs: 1000,
10230          maxRetryDelayMs: 8000
10231        }
10232      }
10233    },
10234    fragLoadPolicy: {
10235      default: {
10236        maxTimeToFirstByteMs: 10000,
10237        maxLoadTimeMs: 120000,
10238        timeoutRetry: {
10239          maxNumRetry: 4,
10240          retryDelayMs: 0,
10241          maxRetryDelayMs: 0
10242        },
10243        errorRetry: {
10244          maxNumRetry: 6,
10245          retryDelayMs: 1000,
10246          maxRetryDelayMs: 8000
10247        }
10248      }
10249    },
10250    steeringManifestLoadPolicy: {
10251      default: {
10252        maxTimeToFirstByteMs: 10000,
10253        maxLoadTimeMs: 20000,
10254        timeoutRetry: {
10255          maxNumRetry: 2,
10256          retryDelayMs: 0,
10257          maxRetryDelayMs: 0
10258        },
10259        errorRetry: {
10260          maxNumRetry: 1,
10261          retryDelayMs: 1000,
10262          maxRetryDelayMs: 8000
10263        }
10264      } 
10265    },
vendor: 4,717 bytes, lines 10266-10374
10266    // These default settings are deprecated in favor of the above policies
10267    // and are maintained for backwards compatibility
10268    manifestLoadingTimeOut: 10000,
10269    manifestLoadingMaxRetry: 1,
10270    manifestLoadingRetryDelay: 1000,
10271    manifestLoadingMaxRetryTimeout: 64000,
10272    levelLoadingTimeOut: 10000,
10273    levelLoadingMaxRetry: 4,
10274    levelLoadingRetryDelay: 1000,
10275    levelLoadingMaxRetryTimeout: 64000,
10276    fragLoadingTimeOut: 20000,
10277    fragLoadingMaxRetry: 6,
10278    fragLoadingRetryDelay: 1000,
10279    fragLoadingMaxRetryTimeout: 64000
10280  }, timelineConfig()), {}, {
10281    subtitleStreamController: undefined,
10282    subtitleTrackController: undefined,
10283    timelineController: undefined,
10284    audioStreamController: undefined,
10285    audioTrackController: undefined,
10286    emeController: undefined,
10287    cmcdController: undefined,
10288    contentSteeringController: ContentSteeringController 
10289  });
10290  function timelineConfig() {
10291    return {
10292      cueHandler: HevcVideoParser,
10293      // used by timeline-controller
10294      enableWebVTT: false,
10295      // used by timeline-controller
10296      enableIMSC1: false,
10297      // used by timeline-controller
10298      enableCEA708Captions: false,
10299      // used by timeline-controller
10300      captionsTextTrack1Label: 'English',
10301      // used by timeline-controller
10302      captionsTextTrack1LanguageCode: 'en',
10303      // used by timeline-controller
10304      captionsTextTrack2Label: 'Spanish',
10305      // used by timeline-controller
10306      captionsTextTrack2LanguageCode: 'es',
10307      // used by timeline-controller
10308      captionsTextTrack3Label: 'Unknown CC',
10309      // used by timeline-controller
10310      captionsTextTrack3LanguageCode: '',
10311      // used by timeline-controller
10312      captionsTextTrack4Label: 'Unknown CC',
10313      // used by timeline-controller
10314      captionsTextTrack4LanguageCode: '',
10315      // used by timeline-controller
10316      renderTextTracksNatively: true
10317    };
10318  }
10319
10320  /**
10321   * @ignore
10322   */
10323  function mergeConfig(defaultConfig, userConfig, logger) {
10324    if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
10325      throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
10326    }
10327    if (userConfig.liveMaxLatencyDurationCount !== undefined && (userConfig.liveSyncDurationCount === undefined || userConfig.liveMaxLatencyDurationCount <= userConfig.liveSyncDurationCount)) {
10328      throw new Error('Illegal hls.js config: "liveMaxLatencyDurationCount" must be greater than "liveSyncDurationCount"');
10329    }
10330    if (userConfig.liveMaxLatencyDuration !== undefined && (userConfig.liveSyncDuration === undefined || userConfig.liveMaxLatencyDuration <= userConfig.liveSyncDuration)) {
10331      throw new Error('Illegal hls.js config: "liveMaxLatencyDuration" must be greater than "liveSyncDuration"');
10332    }
10333    var defaultsCopy = deepCpy(defaultConfig);
10334
10335    // Backwards compatibility with deprecated config values
10336    var deprecatedSettingTypes = ['manifest', 'level', 'frag'];
10337    var deprecatedSettings = ['TimeOut', 'MaxRetry', 'RetryDelay', 'MaxRetryTimeout'];
10338    deprecatedSettingTypes.forEach(function (type) {
10339      var policyName = (type === 'level' ? 'playlist' : type) + "LoadPolicy";
10340      var policyNotSet = userConfig[policyName] === undefined;
10341      var report = [];
10342      deprecatedSettings.forEach(function (setting) {
10343        var deprecatedSetting = type + "Loading" + setting;
10344        var value = userConfig[deprecatedSetting];
10345        if (value !== undefined && policyNotSet) {
10346          report.push(deprecatedSetting);
10347          var settings = defaultsCopy[policyName].default;
10348          userConfig[policyName] = {
10349            default: settings
10350          };
10351          switch (setting) {
10352            case 'TimeOut':
10353              settings.maxLoadTimeMs = value;
10354              settings.maxTimeToFirstByteMs = value;
10355              break;
10356            case 'MaxRetry':
10357              settings.errorRetry.maxNumRetry = value;
10358              settings.timeoutRetry.maxNumRetry = value;
10359              break;
10360            case 'RetryDelay':
10361              settings.errorRetry.retryDelayMs = value;
10362              settings.timeoutRetry.retryDelayMs = value;
10363              break;
10364            case 'MaxRetryTimeout':
10365              settings.errorRetry.maxRetryDelayMs = value;
10366              settings.timeoutRetry.maxRetryDelayMs = value;
10367              break;
10368          }
10369        }
10370      });
10371      if (report.length) {
10372        logger.warn("hls.js config: \"" + report.join('", "') + "\" setting(s) are deprecated, use \"" + policyName + "\": " + JSON.stringify(userConfig[policyName]));
10373      }
10374    });
vendor: 5,169 bytes, lines 10375-10502
10375    return _objectSpread2(_objectSpread2({}, defaultsCopy), userConfig);
10376  }
10377  function deepCpy(obj) {
10378    if (obj && typeof obj === 'object') {
10379      if (Array.isArray(obj)) {
10380        return obj.map(deepCpy);
10381      }
10382      return Object.keys(obj).reduce(function (result, key) {
10383        result[key] = deepCpy(obj[key]);
10384        return result;
10385      }, {});
10386    }
10387    return obj;
10388  }
10389
10390  /**
10391   * @ignore
10392   */
10393  function enableStreamingMode(config, logger) {
10394    var currentLoader = config.loader;
10395    if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
10396      // If a developer has configured their own loader, respect that choice
10397      logger.log('[config]: Custom loader detected, cannot enable progressive streaming');
10398      config.progressive = false;
10399    } else {
10400      var canStreamProgressively = fetchSupported();
10401      if (canStreamProgressively) {
10402        config.loader = FetchLoader;
10403        config.progressive = true;
10404        config.enableSoftwareAES = true;
10405        logger.log('[config]: Progressive streaming enabled, using FetchLoader');
10406      }
10407    }
10408  }
10409
10410  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
10411    function LevelController(hls, contentSteeringController) {
10412      var _this;
10413      _this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
10414      _this._levels = [];
10415      _this._firstLevel = -1;
10416      _this._maxAutoLevel = -1;
10417      _this._startLevel = void 0;
10418      _this.currentLevel = null;
10419      _this.currentLevelIndex = -1;
10420      _this.manualLevelIndex = -1;
10421      _this.steering = void 0;
10422      _this.onParsedComplete = void 0;
10423      _this.steering = contentSteeringController;
10424      _this._registerListeners();
10425      return _this;
10426    }
10427    _inheritsLoose(LevelController, _BasePlaylistControll);
10428    var _proto = LevelController.prototype;
10429    _proto._registerListeners = function _registerListeners() {
10430      var hls = this.hls;
10431      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
10432      hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
10433      hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
10434      hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
10435      hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
10436      hls.on(Events.ERROR, this.onError, this);
10437    };
10438    _proto._unregisterListeners = function _unregisterListeners() {
10439      var hls = this.hls;
10440      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
10441      hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
10442      hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
10443      hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
10444      hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
10445      hls.off(Events.ERROR, this.onError, this);
10446    };
10447    _proto.destroy = function destroy() {
10448      this._unregisterListeners();
10449      this.steering = null;
10450      this.resetLevels();
10451      _BasePlaylistControll.prototype.destroy.call(this);
10452    };
10453    _proto.stopLoad = function stopLoad() {
10454      var levels = this._levels;
10455
10456      // clean up live level details to force reload them, and reset load errors
10457      levels.forEach(function (level) {
10458        level.loadError = 0;
10459        level.fragmentError = 0;
10460      });
10461      _BasePlaylistControll.prototype.stopLoad.call(this);
10462    };
10463    _proto.resetLevels = function resetLevels() {
10464      this._startLevel = undefined;
10465      this.manualLevelIndex = -1;
10466      this.currentLevelIndex = -1;
10467      this.currentLevel = null;
10468      this._levels = [];
10469      this._maxAutoLevel = -1;
10470    };
10471    _proto.onManifestLoading = function onManifestLoading(event, data) {
10472      this.resetLevels();
10473    };
10474    _proto.onManifestLoaded = function onManifestLoaded(event, data) {
10475      var preferManagedMediaSource = this.hls.config.preferManagedMediaSource;
10476      var levels = [];
10477      var redundantSet = {};
10478      var generatePathwaySet = {};
10479      var resolutionFound = false;
10480      var videoCodecFound = false;
10481      var audioCodecFound = false;
10482      data.levels.forEach(function (levelParsed) {
10483        var _videoCodec;
10484        var attributes = levelParsed.attrs;
10485        var audioCodec = levelParsed.audioCodec,
10486          videoCodec = levelParsed.videoCodec;
10487        if (audioCodec) {
10488          // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
10489          levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
10490        }
10491        if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
10492          videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
10493        }
10494
10495        // only keep levels with supported audio/video codecs
10496        var width = levelParsed.width,
10497          height = levelParsed.height,
10498          unknownCodecs = levelParsed.unknownCodecs;
10499        resolutionFound || (resolutionFound = !!(width && height));
10500        videoCodecFound || (videoCodecFound = !!videoCodec);
10501        audioCodecFound || (audioCodecFound = !!audioCodec);
10502        if (unknownCodecs != null && unknownCodecs.length || audioCodec && !areCodecsMediaSourceSupp
10502orted(audioCodec, 'audio', preferManagedMediaSource) || videoCodec && !areCodecsMediaSourceSupported(videoCodec, 'video', preferManagedMediaSource)) {
10503          return;
10504        }
10505        var CODECS = attributes.CODECS,
10506          FRAMERATE = attributes['FRAME-RATE'],
10507          HDCP = attributes['HDCP-LEVEL'],
10508          PATHWAY = attributes['PATHWAY-ID'],
10509          RESOLUTION = attributes.RESOLUTION,
10510          VIDEO_RANGE = attributes['VIDEO-RANGE'];
10511        var contentSteeringPrefix = (PATHWAY || '.') + "-";
10512        var levelKey = "" + contentSteeringPrefix + levelParsed.bitrate + "-" + RESOLUTION + "-" + FRAMERATE + "-" + CODECS + "-" + VIDEO_RANGE + "-" + HDCP;
10513        if (!redundantSet[levelKey]) {
10514          var level = new Level(levelParsed);
10515          redundantSet[levelKey] = level;
10516          generatePathwaySet[levelKey] = 1;
10517          levels.push(level);
10518        } else if (redundantSet[levelKey].uri !== levelParsed.url && !levelParsed.attrs['PATHWAY-ID']) {
10519          // Assign Pathway IDs to Redundant Streams (default Pathways is ".". Redundant Streams "..", "...", and so on.)
10520          // Content Steering controller to handles Pathway fallback on error
10521          var pathwayCount = generatePathwaySet[levelKey] += 1;
10522          levelParsed.attrs['PATHWAY-ID'] = new Array(pathwayCount + 1).join('.');
10523          var _level = new Level(levelParsed);
10524          redundantSet[levelKey] = _level;
10525          levels.push(_level);
10526        } else {
10527          redundantSet[levelKey].addGroupId('audio', attributes.AUDIO);
10528          redundantSet[levelKey].addGroupId('text', attributes.SUBTITLES);
10529        }
10530      });
10531      this.filterAndSortMediaOptions(levels, data, resolutionFound, videoCodecFound, audioCodecFound);
10532    };
10533    _proto.filterAndSortMediaOptions = function filterAndSortMediaOptions(filteredLevels, data, resolutionFound, videoCodecFound, audioCodecFound) {
10534      var _this2 = this;
10535      var audioTracks = [];
10536      var subtitleTracks = [];
10537      var levels = filteredLevels;
10538
10539      // remove audio-only and invalid video-range levels if we also have levels with video codecs or RESOLUTION signalled
10540      if ((resolutionFound || videoCodecFound) && audioCodecFound) {
10541        levels = levels.filter(function (_ref) {
10542          var videoCodec = _ref.videoCodec,
10543            videoRange = _ref.videoRange,
10544            width = _ref.width,
10545            height = _ref.height;
10546          return (!!videoCodec || !!(width && height)) && isVideoRange(videoRange);
10547        });
10548      }
10549      if (levels.length === 0) {
10550        // Dispatch error after MANIFEST_LOADED is done propagating
10551        Promise.resolve().then(function () {
10552          if (_this2.hls) {
10553            if (data.levels.length) {
10554              _this2.warn("One or more CODECS in variant not supported: " + JSON.stringify(data.levels[0].attrs));
10555            }
10556            var error = new Error('no level with compatible codecs found in manifest');
10557            _this2.hls.trigger(Events.ERROR, {
10558              type: ErrorTypes.MEDIA_ERROR,
10559              details: ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR,
10560              fatal: true,
10561              url: data.url,
10562              error: error,
10563              reason: error.message
10564            });
10565          }
10566        });
10567        return;
10568      }
10569      if (data.audioTracks) {
10570        var preferManagedMediaSource = this.hls.config.preferManagedMediaSource;
10571        audioTracks = data.audioTracks.filter(function (track) {
10572          return !track.audioCodec || areCodecsMediaSourceSupported(track.audioCodec, 'audio', preferManagedMediaSource);
10573        });
10574        // Assign ids after filtering as array indices by group-id
10575        assignTrackIdsByGroup(audioTracks);
10576      }
10577      if (data.subtitles) {
10578        subtitleTracks = data.subtitles;
10579        assignTrackIdsByGroup(subtitleTracks);
10580      }
10581      // start bitrate is the first bitrate of the manifest
10582      var unsortedLevels = levels.slice(0);
10583      // sort levels from lowest to highest
10584      levels.sort(function (a, b) {
10585        if (a.attrs['HDCP-LEVEL'] !== b.attrs['HDCP-LEVEL']) {
10586          return (a.attrs['HDCP-LEVEL'] || '') > (b.attrs['HDCP-LEVEL'] || '') ? 1 : -1;
10587        }
10588        // sort on height before bitrate for cap-level-controller
10589        if (resolutionFound && a.height !== b.height) {
10590          return a.height - b.height;
10591        }
10592        if (a.frameRate !== b.frameRate) {
10593          return a.frameRate - b.frameRate;
10594        }
10595        if (a.videoRange !== b.videoRange) {
10596          return VideoRangeValues.indexOf(a.videoRange) - VideoRangeValues.indexOf(b.videoRange);
10597        }
10598        if (a.videoCodec !== b.videoCodec) {
10599          var valueA = videoCodecPreferenceValue(a.videoCodec);
10600          var valueB = videoCodecPreferenceValue(b.videoCodec);
10601          if (valueA !== valueB) {
10602            return valueB - valueA;
10603          }
10604        }
vendor: 7,116 bytes, lines 10605-10774
10605        if (a.uri === b.uri && a.codecSet !== b.codecSet) {
10606          var _valueA = codecsSetSelectionPreferenceValue(a.codecSet);
10607          var _valueB = codecsSetSelectionPreferenceValue(b.codecSet);
10608          if (_valueA !== _valueB) {
10609            return _valueB - _valueA;
10610          }
10611        }
10612        if (a.averageBitrate !== b.averageBitrate) {
10613          return a.averageBitrate - b.averageBitrate;
10614        }
10615        return 0;
10616      });
10617      var firstLevelInPlaylist = unsortedLevels[0];
10618      if (this.steering) {
10619        levels = this.steering.filterParsedLevels(levels);
10620        if (levels.length !== unsortedLevels.length) {
10621          for (var i = 0; i < unsortedLevels.length; i++) {
10622            if (unsortedLevels[i].pathwayId === levels[0].pathwayId) {
10623              firstLevelInPlaylist = unsortedLevels[i];
10624              break;
10625            }
10626          }
10627        }
10628      }
10629      this._levels = levels;
10630
10631      // find index of first level in sorted levels
10632      for (var _i = 0; _i < levels.length; _i++) {
10633        if (levels[_i] === firstLevelInPlaylist) {
10634          var _this$hls$userConfig;
10635          this._firstLevel = _i;
10636          var firstLevelBitrate = firstLevelInPlaylist.bitrate;
10637          var bandwidthEstimate = this.hls.bandwidthEstimate;
10638          this.log("manifest loaded, " + levels.length + " level(s) found, first bitrate: " + firstLevelBitrate);
10639          // Update default bwe to first variant bitrate as long it has not been configured or set
10640          if (((_this$hls$userConfig = this.hls.userConfig) == null ? void 0 : _this$hls$userConfig.abrEwmaDefaultEstimate) === undefined) {
10641            var startingBwEstimate = Math.min(firstLevelBitrate, this.hls.config.abrEwmaDefaultEstimateMax);
10642            if (startingBwEstimate > bandwidthEstimate && bandwidthEstimate === hlsDefaultConfig.abrEwmaDefaultEstimate) {
10643              this.hls.bandwidthEstimate = startingBwEstimate;
10644            }
10645          }
10646          break;
10647        }
10648      }
10649
10650      // Audio is only alternate if manifest include a URI along with the audio group tag,
10651      // and this is not an audio-only stream where levels contain audio-only
10652      var audioOnly = audioCodecFound && !videoCodecFound;
10653      var edata = {
10654        levels: levels,
10655        audioTracks: audioTracks,
10656        subtitleTracks: subtitleTracks,
10657        sessionData: data.sessionData,
10658        sessionKeys: data.sessionKeys,
10659        firstLevel: this._firstLevel,
10660        stats: data.stats,
10661        audio: audioCodecFound,
10662        video: videoCodecFound,
10663        altAudio: !audioOnly && audioTracks.some(function (t) {
10664          return !!t.url;
10665        })
10666      };
10667      this.hls.trigger(Events.MANIFEST_PARSED, edata);
10668
10669      // Initiate loading after all controllers have received MANIFEST_PARSED
10670      if (this.hls.config.autoStartLoad || this.hls.forceStartLoad) {
10671        this.hls.startLoad(this.hls.config.startPosition);
10672      }
10673    };
10674    _proto.onError = function onError(event, data) {
10675      if (data.fatal || !data.context) {
10676        return;
10677      }
10678      if (data.context.type === PlaylistContextType.LEVEL && data.context.level === this.level) {
10679        this.checkRetry(data);
10680      }
10681    }
10682
10683    // reset errors on the successful load of a fragment
10684    ;
10685    _proto.onFragBuffered = function onFragBuffered(event, _ref2) {
10686      var frag = _ref2.frag;
10687      if (frag !== undefined && frag.type === PlaylistLevelType.MAIN) {
10688        var el = frag.elementaryStreams;
10689        if (!Object.keys(el).some(function (type) {
10690          return !!el[type];
10691        })) {
10692          return;
10693        }
10694        var level = this._levels[frag.level];
10695        if (level != null && level.loadError) {
10696          this.log("Resetting level error count of " + level.loadError + " on frag buffered");
10697          level.loadError = 0;
10698        }
10699      }
10700    };
10701    _proto.onLevelLoaded = function onLevelLoaded(event, data) {
10702      var _data$deliveryDirecti2;
10703      var level = data.level,
10704        details = data.details;
10705      var curLevel = this._levels[level];
10706      if (!curLevel) {
10707        var _data$deliveryDirecti;
10708        this.warn("Invalid level index " + level);
10709        if ((_data$deliveryDirecti = data.deliveryDirectives) != null && _data$deliveryDirecti.skip) {
10710          details.deltaUpdateFailed = true;
10711        }
10712        return;
10713      }
10714
10715      // only process level loaded events matching with expected level
10716      if (level === this.currentLevelIndex) {
10717        // reset level load error counter on successful level loaded only if there is no issues with fragments
10718        if (curLevel.fragmentError === 0) {
10719          curLevel.loadError = 0;
10720        }
10721        // Ignore matching details populated by loading a Media Playlist directly
10722        var previousDetails = curLevel.details;
10723        if (previousDetails === data.details && previousDetails.advanced) {
10724          previousDetails = undefined;
10725        }
10726        this.playlistLoaded(level, data, previousDetails);
10727      } else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
10728        // received a delta playlist update that cannot be merged
10729        details.deltaUpdateFailed = true;
10730      }
10731    };
10732    _proto.loadPlaylist = function loadPlaylist(hlsUrlParameters) {
10733      _BasePlaylistControll.prototype.loadPlaylist.call(this);
10734      var currentLevelIndex = this.currentLevelIndex;
10735      var currentLevel = this.currentLevel;
10736      if (currentLevel && this.shouldLoadPlaylist(currentLevel)) {
10737        var url = currentLevel.uri;
10738        if (hlsUrlParameters) {
10739          try {
10740            url = hlsUrlParameters.addDirectives(url);
10741          } catch (error) {
10742            this.warn("Could not construct new URL with HLS Delivery Directives: " + error);
10743          }
10744        }
10745        var pathwayId = currentLevel.attrs['PATHWAY-ID'];
10746        this.log("Loading level index " + currentLevelIndex + ((hlsUrlParameters == null ? void 0 : hlsUrlParameters.msn) !== undefined ? ' at sn ' + hlsUrlParameters.msn + ' part ' + hlsUrlParameters.part : '') + " with" + (pathwayId ? ' Pathway ' + pathwayId : '') + " " + url);
10747
10748        // console.log('Current audio track group ID:', this.hls.audioTracks[this.hls.audioTrack].groupId);
10749        // console.log('New video quality level audio group id:', levelObject.attrs.AUDIO, level);
10750        this.clearTimer();
10751        this.hls.trigger(Events.LEVEL_LOADING, {
10752          url: url,
10753          level: currentLevelIndex,
10754          pathwayId: currentLevel.attrs['PATHWAY-ID'],
10755          id: 0,
10756          // Deprecated Level urlId
10757          deliveryDirectives: hlsUrlParameters || null
10758        });
10759      }
10760    };
10761    _proto.removeLevel = function removeLevel(levelIndex) {
10762      var _this3 = this,
10763        _this$currentLevel;
10764      var levels = this._levels.filter(function (level, index) {
10765        if (index !== levelIndex) {
10766          return true;
10767        }
10768        if (_this3.steering) {
10769          _this3.steering.removeLevel(level);
10770        }
10771        if (level === _this3.currentLevel) {
10772          _this3.currentLevel = null;
10773          _this3.currentLevelIndex = -1;
10774          if (level.details) {
vendor: 4,616 bytes, lines 10775-10893
10775            level.details.fragments.forEach(function (f) {
10776              return f.level = -1;
10777            });
10778          }
10779        }
10780        return false;
10781      });
10782      reassignFragmentLevelIndexes(levels);
10783      this._levels = levels;
10784      if (this.currentLevelIndex > -1 && (_this$currentLevel = this.currentLevel) != null && _this$currentLevel.details) {
10785        this.currentLevelIndex = this.currentLevel.details.fragments[0].level;
10786      }
10787      this.hls.trigger(Events.LEVELS_UPDATED, {
10788        levels: levels
10789      });
10790    };
10791    _proto.onLevelsUpdated = function onLevelsUpdated(event, _ref3) {
10792      var levels = _ref3.levels;
10793      this._levels = levels;
10794    };
10795    _proto.checkMaxAutoUpdated = function checkMaxAutoUpdated() {
10796      var _this$hls = this.hls,
10797        autoLevelCapping = _this$hls.autoLevelCapping,
10798        maxAutoLevel = _this$hls.maxAutoLevel,
10799        maxHdcpLevel = _this$hls.maxHdcpLevel;
10800      if (this._maxAutoLevel !== maxAutoLevel) {
10801        this._maxAutoLevel = maxAutoLevel;
10802        this.hls.trigger(Events.MAX_AUTO_LEVEL_UPDATED, {
10803          autoLevelCapping: autoLevelCapping,
10804          levels: this.levels,
10805          maxAutoLevel: maxAutoLevel,
10806          minAutoLevel: this.hls.minAutoLevel,
10807          maxHdcpLevel: maxHdcpLevel
10808        });
10809      }
10810    };
10811    return _createClass(LevelController, [{
10812      key: "levels",
10813      get: function get() {
10814        if (this._levels.length === 0) {
10815          return null;
10816        }
10817        return this._levels;
10818      }
10819    }, {
10820      key: "level",
10821      get: function get() {
10822        return this.currentLevelIndex;
10823      },
10824      set: function set(newLevel) {
10825        var levels = this._levels;
10826        if (levels.length === 0) {
10827          return;
10828        }
10829        // check if level idx is valid
10830        if (newLevel < 0 || newLevel >= levels.length) {
10831          // invalid level id given, trigger error
10832          var error = new Error('invalid level idx');
10833          var fatal = newLevel < 0;
10834          this.hls.trigger(Events.ERROR, {
10835            type: ErrorTypes.OTHER_ERROR,
10836            details: ErrorDetails.LEVEL_SWITCH_ERROR,
10837            level: newLevel,
10838            fatal: fatal,
10839            error: error,
10840            reason: error.message
10841          });
10842          if (fatal) {
10843            return;
10844          }
10845          newLevel = Math.min(newLevel, levels.length - 1);
10846        }
10847        var lastLevelIndex = this.currentLevelIndex;
10848        var lastLevel = this.currentLevel;
10849        var lastPathwayId = lastLevel ? lastLevel.attrs['PATHWAY-ID'] : undefined;
10850        var level = levels[newLevel];
10851        var pathwayId = level.attrs['PATHWAY-ID'];
10852        this.currentLevelIndex = newLevel;
10853        this.currentLevel = level;
10854        if (lastLevelIndex === newLevel && level.details && lastLevel && lastPathwayId === pathwayId) {
10855          return;
10856        }
10857        this.log("Switching to level " + newLevel + " (" + (level.height ? level.height + 'p ' : '') + (level.videoRange ? level.videoRange + ' ' : '') + (level.codecSet ? level.codecSet + ' ' : '') + "@" + level.bitrate + ")" + (pathwayId ? ' with Pathway ' + pathwayId : '') + " from level " + lastLevelIndex + (lastPathwayId ? ' with Pathway ' + lastPathwayId : ''));
10858        var levelSwitchingData = {
10859          level: newLevel,
10860          attrs: level.attrs,
10861          details: level.details,
10862          bitrate: level.bitrate,
10863          averageBitrate: level.averageBitrate,
10864          maxBitrate: level.maxBitrate,
10865          realBitrate: level.realBitrate,
10866          width: level.width,
10867          height: level.height,
10868          codecSet: level.codecSet,
10869          audioCodec: level.audioCodec,
10870          videoCodec: level.videoCodec,
10871          audioGroups: level.audioGroups,
10872          subtitleGroups: level.subtitleGroups,
10873          loaded: level.loaded,
10874          loadError: level.loadError,
10875          fragmentError: level.fragmentError,
10876          name: level.name,
10877          id: level.id,
10878          uri: level.uri,
10879          url: level.url,
10880          urlId: 0,
10881          audioGroupIds: level.audioGroupIds,
10882          textGroupIds: level.textGroupIds
10883        };
10884        this.hls.trigger(Events.LEVEL_SWITCHING, levelSwitchingData);
10885        // check if we need to load playlist for this level
10886        var levelDetails = level.details;
10887        if (!levelDetails || levelDetails.live) {
10888          // level not retrieved yet, or live playlist we need to (re)load it
10889          var hlsUrlParameters = this.switchParams(level.uri, lastLevel == null ? void 0 : lastLevel.details, levelDetails);
10890          this.loadPlaylist(hlsUrlParameters);
10891        }
10892      }
10893    }, {
vendor: 6,583 bytes, lines 10894-11077
10894      key: "manualLevel",
10895      get: function get() {
10896        return this.manualLevelIndex;
10897      },
10898      set: function set(newLevel) {
10899        this.manualLevelIndex = newLevel;
10900        if (this._startLevel === undefined) {
10901          this._startLevel = newLevel;
10902        }
10903        if (newLevel !== -1) {
10904          this.level = newLevel;
10905        }
10906      }
10907    }, {
10908      key: "firstLevel",
10909      get: function get() {
10910        return this._firstLevel;
10911      },
10912      set: function set(newLevel) {
10913        this._firstLevel = newLevel;
10914      }
10915    }, {
10916      key: "startLevel",
10917      get: function get() {
10918        // Setting hls.startLevel (this._startLevel) overrides config.startLevel
10919        if (this._startLevel === undefined) {
10920          var configStartLevel = this.hls.config.startLevel;
10921          if (configStartLevel !== undefined) {
10922            return configStartLevel;
10923          }
10924          return this.hls.firstAutoLevel;
10925        }
10926        return this._startLevel;
10927      },
10928      set: function set(newLevel) {
10929        this._startLevel = newLevel;
10930      }
10931    }, {
10932      key: "pathwayPriority",
10933      get: function get() {
10934        if (this.steering) {
10935          return this.steering.pathwayPriority;
10936        }
10937        return null;
10938      },
10939      set: function set(pathwayPriority) {
10940        if (this.steering) {
10941          var pathwaysList = this.steering.pathways();
10942          var filteredPathwayPriority = pathwayPriority.filter(function (pathwayId) {
10943            return pathwaysList.indexOf(pathwayId) !== -1;
10944          });
10945          if (pathwayPriority.length < 1) {
10946            this.warn("pathwayPriority " + pathwayPriority + " should contain at least one pathway from list: " + pathwaysList);
10947            return;
10948          }
10949          this.steering.pathwayPriority = filteredPathwayPriority;
10950        }
10951      }
10952    }, {
10953      key: "nextLoadLevel",
10954      get: function get() {
10955        if (this.manualLevelIndex !== -1) {
10956          return this.manualLevelIndex;
10957        } else {
10958          return this.hls.nextAutoLevel;
10959        }
10960      },
10961      set: function set(nextLevel) {
10962        this.level = nextLevel;
10963        if (this.manualLevelIndex === -1) {
10964          this.hls.nextAutoLevel = nextLevel;
10965        }
10966      }
10967    }]);
10968  }(BasePlaylistController);
10969  function assignTrackIdsByGroup(tracks) {
10970    var groups = {};
10971    tracks.forEach(function (track) {
10972      var groupId = track.groupId || '';
10973      track.id = groups[groupId] = groups[groupId] || 0;
10974      groups[groupId]++;
10975    });
10976  }
10977
10978  var FragmentState = {
10979    NOT_LOADED: "NOT_LOADED",
10980    APPENDING: "APPENDING",
10981    PARTIAL: "PARTIAL",
10982    OK: "OK"
10983  };
10984  var FragmentTracker = /*#__PURE__*/function () {
10985    function FragmentTracker(hls) {
10986      this.activePartLists = Object.create(null);
10987      this.endListFragments = Object.create(null);
10988      this.fragments = Object.create(null);
10989      this.timeRanges = Object.create(null);
10990      this.bufferPadding = 0.2;
10991      this.hls = void 0;
10992      this.hasGaps = false;
10993      this.hls = hls;
10994      this._registerListeners();
10995    }
10996    var _proto = FragmentTracker.prototype;
10997    _proto._registerListeners = function _registerListeners() {
10998      var hls = this.hls;
10999      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
11000      hls.on(Events.BUFFER_APPENDED, this.onBufferAppended, this);
11001      hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
11002      hls.on(Events.FRAG_LOADED, this.onFragLoaded, this);
11003    };
11004    _proto._unregisterListeners = function _unregisterListeners() {
11005      var hls = this.hls;
11006      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
11007      hls.off(Events.BUFFER_APPENDED, this.onBufferAppended, this);
11008      hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
11009      hls.off(Events.FRAG_LOADED, this.onFragLoaded, this);
11010    };
11011    _proto.destroy = function destroy() {
11012      this._unregisterListeners();
11013      // @ts-ignore
11014      this.fragments =
11015      // @ts-ignore
11016      this.activePartLists =
11017      // @ts-ignore
11018      this.endListFragments = this.timeRanges = null;
11019    }
11020
11021    /**
11022     * Return a Fragment or Part with an appended range that matches the position and levelType
11023     * Otherwise, return null
11024     */;
11025    _proto.getAppendedFrag = function getAppendedFrag(position, levelType) {
11026      var activeParts = this.activePartLists[levelType];
11027      if (activeParts) {
11028        for (var i = activeParts.length; i--;) {
11029          var activePart = activeParts[i];
11030          if (!activePart) {
11031            break;
11032          }
11033          var appendedPTS = activePart.end;
11034          if (activePart.start <= position && appendedPTS !== null && position <= appendedPTS) {
11035            return activePart;
11036          }
11037        }
11038      }
11039      return this.getBufferedFrag(position, levelType);
11040    }
11041
11042    /**
11043     * Return a buffered Fragment that matches the position and levelType.
11044     * A buffered Fragment is one whose loading, parsing and appending is done (completed or "partial" meaning aborted).
11045     * If not found any Fragment, return null
11046     */;
11047    _proto.getBufferedFrag = function getBufferedFrag(position, levelType) {
11048      return this.getFragAtPos(position, levelType, true);
11049    };
11050    _proto.getFragAtPos = function getFragAtPos(position, levelType, buffered) {
11051      var fragments = this.fragments;
11052      var keys = Object.keys(fragments);
11053      for (var i = keys.length; i--;) {
11054        var fragmentEntity = fragments[keys[i]];
11055        if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && (!buffered || fragmentEntity.buffered)) {
11056          var frag = fragmentEntity.body;
11057          if (frag.start <= position && position <= frag.end) {
11058            return frag;
11059          }
11060        }
11061      }
11062      return null;
11063    }
11064
11065    /**
11066     * Partial fragments effected by coded frame eviction will be removed
11067     * The browser will unload parts of the buffer to free up memory for new buffer data
11068     * Fragments will need to be reloaded when the buffer is freed up, removing partial fragments will allow them to reload(since there might be parts that are still playable)
11069     */;
11070    _proto.detectEvictedFragments = function detectEvictedFragments(elementaryStream, timeRange, playlistType, appendedPart, removeAppending) {
11071      var _this = this;
11072      if (this.timeRanges) {
11073        this.timeRanges[elementaryStream] = timeRange;
11074      }
11075      // Check if any flagged fragments have been unloaded
11076      // excluding anything newer than appendedPartSn
11077      var appendedPartSn = (appendedPart == null ? void 0 : appendedPart.fragment.sn) || -1;
vendor: 5,361 bytes, lines 11078-11223
11078      Object.keys(this.fragments).forEach(function (key) {
11079        var fragmentEntity = _this.fragments[key];
11080        if (!fragmentEntity) {
11081          return;
11082        }
11083        if (appendedPartSn >= fragmentEntity.body.sn) {
11084          return;
11085        }
11086        if (!fragmentEntity.buffered && (!fragmentEntity.loaded || removeAppending)) {
11087          if (fragmentEntity.body.type === playlistType) {
11088            _this.removeFragment(fragmentEntity.body);
11089          }
11090          return;
11091        }
11092        var esData = fragmentEntity.range[elementaryStream];
11093        if (!esData) {
11094          return;
11095        }
11096        if (esData.time.length === 0) {
11097          _this.removeFragment(fragmentEntity.body);
11098          return;
11099        }
11100        esData.time.some(function (time) {
11101          var isNotBuffered = !_this.isTimeBuffered(time.startPTS, time.endPTS, timeRange);
11102          if (isNotBuffered) {
11103            // Unregister partial fragment as it needs to load again to be reused
11104            _this.removeFragment(fragmentEntity.body);
11105          }
11106          return isNotBuffered;
11107        });
11108      });
11109    }
11110
11111    /**
11112     * Checks if the fragment passed in is loaded in the buffer properly
11113     * Partially loaded fragments will be registered as a partial fragment
11114     */;
11115    _proto.detectPartialFragments = function detectPartialFragments(data) {
11116      var _this2 = this;
11117      var timeRanges = this.timeRanges;
11118      if (!timeRanges || data.frag.sn === 'initSegment') {
11119        return;
11120      }
11121      var frag = data.frag;
11122      var fragKey = getFragmentKey(frag);
11123      var fragmentEntity = this.fragments[fragKey];
11124      if (!fragmentEntity || fragmentEntity.buffered && frag.gap) {
11125        return;
11126      }
11127      var isFragHint = !frag.relurl;
11128      Object.keys(timeRanges).forEach(function (elementaryStream) {
11129        var streamInfo = frag.elementaryStreams[elementaryStream];
11130        if (!streamInfo) {
11131          return;
11132        }
11133        var timeRange = timeRanges[elementaryStream];
11134        var partial = isFragHint || streamInfo.partial === true;
11135        fragmentEntity.range[elementaryStream] = _this2.getBufferedTimes(frag, data.part, partial, timeRange);
11136      });
11137      fragmentEntity.loaded = null;
11138      if (Object.keys(fragmentEntity.range).length) {
11139        fragmentEntity.buffered = true;
11140        var endList = fragmentEntity.body.endList = frag.endList || fragmentEntity.body.endList;
11141        if (endList) {
11142          this.endListFragments[fragmentEntity.body.type] = fragmentEntity;
11143        }
11144        if (!isPartial(fragmentEntity)) {
11145          // Remove older fragment parts from lookup after frag is tracked as buffered
11146          this.removeParts(frag.sn - 1, frag.type);
11147        }
11148      } else {
11149        // remove fragment if nothing was appended
11150        this.removeFragment(fragmentEntity.body);
11151      }
11152    };
11153    _proto.removeParts = function removeParts(snToKeep, levelType) {
11154      var activeParts = this.activePartLists[levelType];
11155      if (!activeParts) {
11156        return;
11157      }
11158      this.activePartLists[levelType] = activeParts.filter(function (part) {
11159        return part.fragment.sn >= snToKeep;
11160      });
11161    };
11162    _proto.fragBuffered = function fragBuffered(frag, force) {
11163      var fragKey = getFragmentKey(frag);
11164      var fragmentEntity = this.fragments[fragKey];
11165      if (!fragmentEntity && force) {
11166        fragmentEntity = this.fragments[fragKey] = {
11167          body: frag,
11168          appendedPTS: null,
11169          loaded: null,
11170          buffered: false,
11171          range: Object.create(null)
11172        };
11173        if (frag.gap) {
11174          this.hasGaps = true;
11175        }
11176      }
11177      if (fragmentEntity) {
11178        fragmentEntity.loaded = null;
11179        fragmentEntity.buffered = true;
11180      }
11181    };
11182    _proto.getBufferedTimes = function getBufferedTimes(fragment, part, partial, timeRange) {
11183      var buffered = {
11184        time: [],
11185        partial: partial
11186      };
11187      var startPTS = fragment.start;
11188      var endPTS = fragment.end;
11189      var minEndPTS = fragment.minEndPTS || endPTS;
11190      var maxStartPTS = fragment.maxStartPTS || startPTS;
11191      for (var i = 0; i < timeRange.length; i++) {
11192        var startTime = timeRange.start(i) - this.bufferPadding;
11193        var endTime = timeRange.end(i) + this.bufferPadding;
11194        if (maxStartPTS >= startTime && minEndPTS <= endTime) {
11195          // Fragment is entirely contained in buffer
11196          // No need to check the other timeRange times since it's completely playable
11197          buffered.time.push({
11198            startPTS: Math.max(startPTS, timeRange.start(i)),
11199            endPTS: Math.min(endPTS, timeRange.end(i))
11200          });
11201          break;
11202        } else if (startPTS < endTime && endPTS > startTime) {
11203          var start = Math.max(startPTS, timeRange.start(i));
11204          var end = Math.min(endPTS, timeRange.end(i));
11205          if (end > start) {
11206            buffered.partial = true;
11207            // Check for intersection with buffer
11208            // Get playable sections of the fragment
11209            buffered.time.push({
11210              startPTS: start,
11211              endPTS: end
11212            });
11213          }
11214        } else if (endPTS <= startTime) {
11215          // No need to check the rest of the timeRange as it is in order
11216          break;
11217        }
11218      }
11219      return buffered;
11220    }
11221
11222    /**
11223     * Gets the partial fragment for a certain time�
vendor: 5,501 bytes, lines 11223-11375
11223
11224     */;
11225    _proto.getPartialFragment = function getPartialFragment(time) {
11226      var bestFragment = null;
11227      var timePadding;
11228      var startTime;
11229      var endTime;
11230      var bestOverlap = 0;
11231      var bufferPadding = this.bufferPadding,
11232        fragments = this.fragments;
11233      Object.keys(fragments).forEach(function (key) {
11234        var fragmentEntity = fragments[key];
11235        if (!fragmentEntity) {
11236          return;
11237        }
11238        if (isPartial(fragmentEntity)) {
11239          startTime = fragmentEntity.body.start - bufferPadding;
11240          endTime = fragmentEntity.body.end + bufferPadding;
11241          if (time >= startTime && time <= endTime) {
11242            // Use the fragment that has the most padding from start and end time
11243            timePadding = Math.min(time - startTime, endTime - time);
11244            if (bestOverlap <= timePadding) {
11245              bestFragment = fragmentEntity.body;
11246              bestOverlap = timePadding;
11247            }
11248          }
11249        }
11250      });
11251      return bestFragment;
11252    };
11253    _proto.isEndListAppended = function isEndListAppended(type) {
11254      var lastFragmentEntity = this.endListFragments[type];
11255      return lastFragmentEntity !== undefined && (lastFragmentEntity.buffered || isPartial(lastFragmentEntity));
11256    };
11257    _proto.getState = function getState(fragment) {
11258      var fragKey = getFragmentKey(fragment);
11259      var fragmentEntity = this.fragments[fragKey];
11260      if (fragmentEntity) {
11261        if (!fragmentEntity.buffered) {
11262          return FragmentState.APPENDING;
11263        } else if (isPartial(fragmentEntity)) {
11264          return FragmentState.PARTIAL;
11265        } else {
11266          return FragmentState.OK;
11267        }
11268      }
11269      return FragmentState.NOT_LOADED;
11270    };
11271    _proto.isTimeBuffered = function isTimeBuffered(startPTS, endPTS, timeRange) {
11272      var startTime;
11273      var endTime;
11274      for (var i = 0; i < timeRange.length; i++) {
11275        startTime = timeRange.start(i) - this.bufferPadding;
11276        endTime = timeRange.end(i) + this.bufferPadding;
11277        if (startPTS >= startTime && endPTS <= endTime) {
11278          return true;
11279        }
11280        if (endPTS <= startTime) {
11281          // No need to check the rest of the timeRange as it is in order
11282          return false;
11283        }
11284      }
11285      return false;
11286    };
11287    _proto.onManifestLoading = function onManifestLoading() {
11288      this.removeAllFragments();
11289    };
11290    _proto.onFragLoaded = function onFragLoaded(event, data) {
11291      // don't track initsegment (for which sn is not a number)
11292      // don't track frags used for bitrateTest, they're irrelevant.
11293      if (data.frag.sn === 'initSegment' || data.frag.bitrateTest) {
11294        return;
11295      }
11296      var frag = data.frag;
11297      // Fragment entity `loaded` FragLoadedData is null when loading parts
11298      var loaded = data.part ? null : data;
11299      var fragKey = getFragmentKey(frag);
11300      this.fragments[fragKey] = {
11301        body: frag,
11302        appendedPTS: null,
11303        loaded: loaded,
11304        buffered: false,
11305        range: Object.create(null)
11306      };
11307    };
11308    _proto.onBufferAppended = function onBufferAppended(event, data) {
11309      var frag = data.frag,
11310        part = data.part,
11311        timeRanges = data.timeRanges,
11312        type = data.type;
11313      if (frag.sn === 'initSegment') {
11314        return;
11315      }
11316      var playlistType = frag.type;
11317      if (part) {
11318        var activeParts = this.activePartLists[playlistType];
11319        if (!activeParts) {
11320          this.activePartLists[playlistType] = activeParts = [];
11321        }
11322        activeParts.push(part);
11323      }
11324      // Store the latest timeRanges loaded in the buffer
11325      this.timeRanges = timeRanges;
11326      var timeRange = timeRanges[type];
11327      this.detectEvictedFragments(type, timeRange, playlistType, part);
11328    };
11329    _proto.onFragBuffered = function onFragBuffered(event, data) {
11330      this.detectPartialFragments(data);
11331    };
11332    _proto.hasFragment = function hasFragment(fragment) {
11333      var fragKey = getFragmentKey(fragment);
11334      return !!this.fragments[fragKey];
11335    };
11336    _proto.hasFragments = function hasFragments(type) {
11337      var fragments = this.fragments;
11338      var keys = Object.keys(fragments);
11339      if (!type) {
11340        return keys.length > 0;
11341      }
11342      for (var i = keys.length; i--;) {
11343        var fragmentEntity = fragments[keys[i]];
11344        if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === type) {
11345          return true;
11346        }
11347      }
11348      return false;
11349    };
11350    _proto.hasParts = function hasParts(type) {
11351      var _this$activePartLists;
11352      return !!((_this$activePartLists = this.activePartLists[type]) != null && _this$activePartLists.length);
11353    };
11354    _proto.removeFragmentsInRange = function removeFragmentsInRange(start, end, playlistType, withGapOnly, unbufferedOnly) {
11355      var _this3 = this;
11356      if (withGapOnly && !this.hasGaps) {
11357        return;
11358      }
11359      Object.keys(this.fragments).forEach(function (key) {
11360        var fragmentEntity = _this3.fragments[key];
11361        if (!fragmentEntity) {
11362          return;
11363        }
11364        var frag = fragmentEntity.body;
11365        if (frag.type !== playlistType || withGapOnly && !frag.gap) {
11366          return;
11367        }
11368        if (frag.start < end && frag.end > start && (fragmentEntity.buffered || unbufferedOnly)) {
11369          _this3.removeFragment(frag);
11370        }
11371      });
11372    };
11373    _proto.removeFragment = function removeFragment(fragment) {
11374      var fragKey = getFragmentKey(fragment);
11375      fragment.
vendor: 3,509 bytes, lines 11375-11467
11375stats.loaded = 0;
11376      fragment.clearElementaryStreamInfo();
11377      var activeParts = this.activePartLists[fragment.type];
11378      if (activeParts) {
11379        var snToRemove = fragment.sn;
11380        this.activePartLists[fragment.type] = activeParts.filter(function (part) {
11381          return part.fragment.sn !== snToRemove;
11382        });
11383      }
11384      delete this.fragments[fragKey];
11385      if (fragment.endList) {
11386        delete this.endListFragments[fragment.type];
11387      }
11388    };
11389    _proto.removeAllFragments = function removeAllFragments() {
11390      this.fragments = Object.create(null);
11391      this.endListFragments = Object.create(null);
11392      this.activePartLists = Object.create(null);
11393      this.hasGaps = false;
11394    };
11395    return FragmentTracker;
11396  }();
11397  function isPartial(fragmentEntity) {
11398    var _fragmentEntity$range, _fragmentEntity$range2, _fragmentEntity$range3;
11399    return fragmentEntity.buffered && (fragmentEntity.body.gap || ((_fragmentEntity$range = fragmentEntity.range.video) == null ? void 0 : _fragmentEntity$range.partial) || ((_fragmentEntity$range2 = fragmentEntity.range.audio) == null ? void 0 : _fragmentEntity$range2.partial) || ((_fragmentEntity$range3 = fragmentEntity.range.audiovideo) == null ? void 0 : _fragmentEntity$range3.partial));
11400  }
11401  function getFragmentKey(fragment) {
11402    return fragment.type + "_" + fragment.level + "_" + fragment.sn;
11403  }
11404
11405  var MIN_CHUNK_SIZE = Math.pow(2, 17); // 128kb
11406  var FragmentLoader = /*#__PURE__*/function () {
11407    function FragmentLoader(config) {
11408      this.config = void 0;
11409      this.loader = null;
11410      this.partLoadTimeout = -1;
11411      this.config = config;
11412    }
11413    var _proto = FragmentLoader.prototype;
11414    _proto.destroy = function destroy() {
11415      if (this.loader) {
11416        this.loader.destroy();
11417        this.loader = null;
11418      }
11419    };
11420    _proto.abort = function abort() {
11421      if (this.loader) {
11422        // Abort the loader for current fragment. Only one may load at any given time
11423        this.loader.abort();
11424      }
11425    };
11426    _proto.load = function load(frag, _onProgress) {
11427      var _this = this;
11428      var url = frag.url;
11429      if (!url) {
11430        return Promise.reject(new LoadError({
11431          type: ErrorTypes.NETWORK_ERROR,
11432          details: ErrorDetails.FRAG_LOAD_ERROR,
11433          fatal: false,
11434          frag: frag,
11435          error: new Error("Fragment does not have a " + (url ? 'part list' : 'url')),
11436          networkDetails: null
11437        }));
11438      }
11439      this.abort();
11440      var config = this.config;
11441      var FragmentILoader = config.fLoader;
11442      var DefaultILoader = config.loader;
11443      return new Promise(function (resolve, reject) {
11444        if (_this.loader) {
11445          _this.loader.destroy();
11446        }
11447        if (frag.gap) {
11448          if (frag.tagList.some(function (tags) {
11449            return tags[0] === 'GAP';
11450          })) {
11451            reject(createGapLoadError(frag));
11452            return;
11453          } else {
11454            // Reset temporary treatment as GAP tag
11455            frag.gap = false;
11456          }
11457        }
11458        var loader = _this.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config);
11459        var loaderContext = createLoaderContext(frag);
11460        frag.loader = loader;
11461        var loadPolicy = getLoaderConfigWithoutReties(config.fragLoadPolicy.default);
11462        var loaderConfig = {
11463          loadPolicy: loadPolicy,
11464          timeout: loadPolicy.maxLoadTimeMs,
11465          maxRetry: 0,
11466          retryDelay: 0,
11467          maxRetryDelay: 0,
vendor: 2,671 bytes, lines 11468-11537
11468          highWaterMark: frag.sn === 'initSegment' ? Infinity : MIN_CHUNK_SIZE
11469        };
11470        // Assign frag stats to the loader's stats reference
11471        frag.stats = loader.stats;
11472        loader.load(loaderContext, loaderConfig, {
11473          onSuccess: function onSuccess(response, stats, context, networkDetails) {
11474            _this.resetLoader(frag, loader);
11475            var payload = response.data;
11476            if (context.resetIV && frag.decryptdata) {
11477              frag.decryptdata.iv = new Uint8Array(payload.slice(0, 16));
11478              payload = payload.slice(16);
11479            }
11480            resolve({
11481              frag: frag,
11482              part: null,
11483              payload: payload,
11484              networkDetails: networkDetails
11485            });
11486          },
11487          onError: function onError(response, context, networkDetails, stats) {
11488            _this.resetLoader(frag, loader);
11489            reject(new LoadError({
11490              type: ErrorTypes.NETWORK_ERROR,
11491              details: ErrorDetails.FRAG_LOAD_ERROR,
11492              fatal: false,
11493              frag: frag,
11494              response: _objectSpread2({
11495                url: url,
11496                data: undefined
11497              }, response),
11498              error: new Error("HTTP Error " + response.code + " " + response.text),
11499              networkDetails: networkDetails,
11500              stats: stats
11501            }));
11502          },
11503          onAbort: function onAbort(stats, context, networkDetails) {
11504            _this.resetLoader(frag, loader);
11505            reject(new LoadError({
11506              type: ErrorTypes.NETWORK_ERROR,
11507              details: ErrorDetails.INTERNAL_ABORTED,
11508              fatal: false,
11509              frag: frag,
11510              error: new Error('Aborted'),
11511              networkDetails: networkDetails,
11512              stats: stats
11513            }));
11514          },
11515          onTimeout: function onTimeout(stats, context, networkDetails) {
11516            _this.resetLoader(frag, loader);
11517            reject(new LoadError({
11518              type: ErrorTypes.NETWORK_ERROR,
11519              details: ErrorDetails.FRAG_LOAD_TIMEOUT,
11520              fatal: false,
11521              frag: frag,
11522              error: new Error("Timeout after " + loaderConfig.timeout + "ms"),
11523              networkDetails: networkDetails,
11524              stats: stats
11525            }));
11526          },
11527          onProgress: function onProgress(stats, context, data, networkDetails) {
11528            if (_onProgress) {
11529              _onProgress({
11530                frag: frag,
11531                part: null,
11532                payload: data,
11533                networkDetails: networkDetails
11534              });
11535            }
11536          }
11537        }
vendor: 7,045 bytes, lines 11537-11731
11537);
11538      });
11539    };
11540    _proto.loadPart = function loadPart(frag, part, onProgress) {
11541      var _this2 = this;
11542      this.abort();
11543      var config = this.config;
11544      var FragmentILoader = config.fLoader;
11545      var DefaultILoader = config.loader;
11546      return new Promise(function (resolve, reject) {
11547        if (_this2.loader) {
11548          _this2.loader.destroy();
11549        }
11550        if (frag.gap || part.gap) {
11551          reject(createGapLoadError(frag, part));
11552          return;
11553        }
11554        var loader = _this2.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config);
11555        var loaderContext = createLoaderContext(frag, part);
11556        frag.loader = loader;
11557        // Should we define another load policy for parts?
11558        var loadPolicy = getLoaderConfigWithoutReties(config.fragLoadPolicy.default);
11559        var loaderConfig = {
11560          loadPolicy: loadPolicy,
11561          timeout: loadPolicy.maxLoadTimeMs,
11562          maxRetry: 0,
11563          retryDelay: 0,
11564          maxRetryDelay: 0,
11565          highWaterMark: MIN_CHUNK_SIZE
11566        };
11567        // Assign part stats to the loader's stats reference
11568        part.stats = loader.stats;
11569        loader.load(loaderContext, loaderConfig, {
11570          onSuccess: function onSuccess(response, stats, context, networkDetails) {
11571            _this2.resetLoader(frag, loader);
11572            _this2.updateStatsFromPart(frag, part);
11573            var partLoadedData = {
11574              frag: frag,
11575              part: part,
11576              payload: response.data,
11577              networkDetails: networkDetails
11578            };
11579            onProgress(partLoadedData);
11580            resolve(partLoadedData);
11581          },
11582          onError: function onError(response, context, networkDetails, stats) {
11583            _this2.resetLoader(frag, loader);
11584            reject(new LoadError({
11585              type: ErrorTypes.NETWORK_ERROR,
11586              details: ErrorDetails.FRAG_LOAD_ERROR,
11587              fatal: false,
11588              frag: frag,
11589              part: part,
11590              response: _objectSpread2({
11591                url: loaderContext.url,
11592                data: undefined
11593              }, response),
11594              error: new Error("HTTP Error " + response.code + " " + response.text),
11595              networkDetails: networkDetails,
11596              stats: stats
11597            }));
11598          },
11599          onAbort: function onAbort(stats, context, networkDetails) {
11600            frag.stats.aborted = part.stats.aborted;
11601            _this2.resetLoader(frag, loader);
11602            reject(new LoadError({
11603              type: ErrorTypes.NETWORK_ERROR,
11604              details: ErrorDetails.INTERNAL_ABORTED,
11605              fatal: false,
11606              frag: frag,
11607              part: part,
11608              error: new Error('Aborted'),
11609              networkDetails: networkDetails,
11610              stats: stats
11611            }));
11612          },
11613          onTimeout: function onTimeout(stats, context, networkDetails) {
11614            _this2.resetLoader(frag, loader);
11615            reject(new LoadError({
11616              type: ErrorTypes.NETWORK_ERROR,
11617              details: ErrorDetails.FRAG_LOAD_TIMEOUT,
11618              fatal: false,
11619              frag: frag,
11620              part: part,
11621              error: new Error("Timeout after " + loaderConfig.timeout + "ms"),
11622              networkDetails: networkDetails,
11623              stats: stats
11624            }));
11625          }
11626        });
11627      });
11628    };
11629    _proto.updateStatsFromPart = function updateStatsFromPart(frag, part) {
11630      var fragStats = frag.stats;
11631      var partStats = part.stats;
11632      var partTotal = partStats.total;
11633      fragStats.loaded += partStats.loaded;
11634      if (partTotal) {
11635        var estTotalParts = Math.round(frag.duration / part.duration);
11636        var estLoadedParts = Math.min(Math.round(fragStats.loaded / partTotal), estTotalParts);
11637        var estRemainingParts = estTotalParts - estLoadedParts;
11638        var estRemainingBytes = estRemainingParts * Math.round(fragStats.loaded / estLoadedParts);
11639        fragStats.total = fragStats.loaded + estRemainingBytes;
11640      } else {
11641        fragStats.total = Math.max(fragStats.loaded, fragStats.total);
11642      }
11643      var fragLoading = fragStats.loading;
11644      var partLoading = partStats.loading;
11645      if (fragLoading.start) {
11646        // add to fragment loader latency
11647        fragLoading.first += partLoading.first - partLoading.start;
11648      } else {
11649        fragLoading.start = partLoading.start;
11650        fragLoading.first = partLoading.first;
11651      }
11652      fragLoading.end = partLoading.end;
11653    };
11654    _proto.resetLoader = function resetLoader(frag, loader) {
11655      frag.loader = null;
11656      if (this.loader === loader) {
11657        self.clearTimeout(this.partLoadTimeout);
11658        this.loader = null;
11659      }
11660      loader.destroy();
11661    };
11662    return FragmentLoader;
11663  }();
11664  function createLoaderContext(frag, part) {
11665    if (part === void 0) {
11666      part = null;
11667    }
11668    var segment = part || frag;
11669    var loaderContext = {
11670      frag: frag,
11671      part: part,
11672      responseType: 'arraybuffer',
11673      url: segment.url,
11674      headers: {},
11675      rangeStart: 0,
11676      rangeEnd: 0
11677    };
11678    var start = segment.byteRangeStartOffset;
11679    var end = segment.byteRangeEndOffset;
11680    if (isFiniteNumber(start) && isFiniteNumber(end)) {
11681      var _frag$decryptdata;
11682      var byteRangeStart = start;
11683      var byteRangeEnd = end;
11684      if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
11685        // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
11686        // has the unencrypted size specified in the range.
11687        // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
11688        var fragmentLen = end - start;
11689        if (fragmentLen % 16) {
11690          byteRangeEnd = end + (16 - fragmentLen % 16);
11691        }
11692        if (start !== 0) {
11693          loaderContext.resetIV = true;
11694          byteRangeStart = start - 16;
11695        }
11696      }
11697      loaderContext.rangeStart = byteRangeStart;
11698      loaderContext.rangeEnd = byteRangeEnd;
11699    }
11700    return loaderContext;
11701  }
11702  function createGapLoadError(frag, part) {
11703    var error = new Error("GAP " + (frag.gap ? 'tag' : 'attribute') + " found");
11704    var errorData = {
11705      type: ErrorTypes.MEDIA_ERROR,
11706      details: ErrorDetails.FRAG_GAP,
11707      fatal: false,
11708      frag: frag,
11709      error: error,
11710      networkDetails: null
11711    };
11712    if (part) {
11713      errorData.part = part;
11714    }
11715    (part ? part : frag).stats.aborted = true;
11716    return new LoadError(errorData);
11717  }
11718  function isMethodFullSegmentAesCbc(method) {
11719    return method === 'AES-128' || method === 'AES-256';
11720  }
11721  var LoadError = /*#__PURE__*/function (_Error) {
11722    function LoadError(data) {
11723      var _this3;
11724      _this3 = _Error.call(this, data.error.message) || this;
11725      _this3.data = void 0;
11726      _this3.data = data;
11727      return _this3;
11728    }
11729    _inheritsLoose(LoadError, _Error);
11730    return LoadError;
11731  }(
11731 /*#__PURE__*/_wrapNativeSuper(Error));
11732
11733  var KeyLoader = /*#__PURE__*/function () {
11734    function KeyLoader(config) {
11735      this.config = void 0;
11736      this.keyUriToKeyInfo = {};
11737      this.emeController = null;
11738      this.config = config;
11739    }
11740    var _proto = KeyLoader.prototype;
11741    _proto.abort = function abort(type) {
11742      for (var uri in this.keyUriToKeyInfo) {
11743        var loader = this.keyUriToKeyInfo[uri].loader;
11744        if (loader) {
11745          var _loader$context;
11746          if (type && type !== ((_loader$context = loader.context) == null ? void 0 : _loader$context.frag.type)) {
11747            return;
11748          }
11749          loader.abort();
11750        }
11751      }
11752    };
11753    _proto.detach = function detach() {
11754      for (var uri in this.keyUriToKeyInfo) {
11755        var keyInfo = this.keyUriToKeyInfo[uri];
11756        // Remove cached EME keys on detach
11757        if (keyInfo.mediaKeySessionContext || keyInfo.decryptdata.isCommonEncryption) {
11758          delete this.keyUriToKeyInfo[uri];
11759        }
11760      }
11761    };
11762    _proto.destroy = function destroy() {
11763      this.detach();
11764      for (var uri in this.keyUriToKeyInfo) {
11765        var loader = this.keyUriToKeyInfo[uri].loader;
11766        if (loader) {
11767          loader.destroy();
11768        }
11769      }
11770      this.keyUriToKeyInfo = {};
11771    };
11772    _proto.createKeyLoadError = function createKeyLoadError(frag, details, error, networkDetails, response) {
11773      if (details === void 0) {
11774        details = ErrorDetails.KEY_LOAD_ERROR;
11775      }
11776      return new LoadError({
11777        type: ErrorTypes.NETWORK_ERROR,
11778        details: details,
11779        fatal: false,
11780        frag: frag,
11781        response: response,
11782        error: error,
11783        networkDetails: networkDetails
11784      });
11785    };
11786    _proto.loadClear = function loadClear(loadingFrag, encryptedFragments) {
11787      var _this = this;
11788      if (this.emeController && this.config.emeEnabled) {
11789        // access key-system with nearest key on start (loaidng frag is unencrypted)
11790        var sn = loadingFrag.sn,
11791          cc = loadingFrag.cc;
11792        var _loop = function _loop() {
11793          var frag = encryptedFragments[i];
11794          if (cc <= frag.cc && (sn === 'initSegment' || frag.sn === 'initSegment' || sn < frag.sn)) {
11795            _this.emeController.selectKeySystemFormat(frag).then(function (keySystemFormat) {
11796              frag.setKeyFormat(keySystemFormat);
11797            });
11798            return 1; // break
11799          }
11800        };
11801        for (var i = 0; i < encryptedFragments.length; i++) {
11802          if (_loop()) break;
11803        }
11804      }
11805    };
11806    _proto.load = function load(frag) {
11807      var _this2 = this;
11808      if (!frag.decryptdata && frag.encrypted && this.emeController) {
11809        // Multiple keys, but none selected, resolve in eme-controller
11810        return this.emeController.selectKeySystemFormat(frag).then(function (keySystemFormat) {
11811          return _this2.loadInternal(frag, keySystemFormat);
11812        });
11813      }
11814      return this.loadInternal(frag);
11815    };
11816    _proto.loadInternal = function loadInternal(frag, keySystemFormat) {
11817      var _keyInfo, _keyInfo2;
11818      if (keySystemFormat) {
11819        frag.setKeyFormat(keySystemFormat);
11820      }
11821      var decryptdata = frag.decryptdata;
11822      if (!decryptdata) {
11823        var error = new Error(keySystemFormat ? "Expected frag.decryptdata to be defined after setting format " + keySystemFormat : 'Missing decryption data on fragment in onKeyLoading');
11824        return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, error));
11825      }
11826      var uri = decryptdata.uri;
11827      if (!uri) {
11828        return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Invalid key URI: \"" + uri + "\"")));
11829      }
11830      var keyInfo = this.keyUriToKeyInfo[uri];
11831      if ((_keyInfo = keyInfo) != null && _keyInfo.decryptdata.key) {
11832        decryptdata.key = keyInfo.decryptdata.key;
11833        return Promise.resolve({
11834          frag: frag,
11835          keyInfo: keyInfo
11836        });
11837      }
11838      // Return key load promise as long as it does not have a mediakey session with an unusable key status
vendor: 8,958 bytes, lines 11839-12052
11839      if ((_keyInfo2 = keyInfo) != null && _keyInfo2.keyLoadPromise) {
11840        var _keyInfo$mediaKeySess;
11841        switch ((_keyInfo$mediaKeySess = keyInfo.mediaKeySessionContext) == null ? void 0 : _keyInfo$mediaKeySess.keyStatus) {
11842          case undefined:
11843          case 'status-pending':
11844          case 'usable':
11845          case 'usable-in-future':
11846            return keyInfo.keyLoadPromise.then(function (keyLoadedData) {
11847              // Return the correct fragment with updated decryptdata key and loaded keyInfo
11848              decryptdata.key = keyLoadedData.keyInfo.decryptdata.key;
11849              return {
11850                frag: frag,
11851                keyInfo: keyInfo
11852              };
11853            });
11854        }
11855        // If we have a key session and status and it is not pending or usable, continue
11856        // This will go back to the eme-controller for expired keys to get a new keyLoadPromise
11857      }
11858
11859      // Load the key or return the loading promise
11860      keyInfo = this.keyUriToKeyInfo[uri] = {
11861        decryptdata: decryptdata,
11862        keyLoadPromise: null,
11863        loader: null,
11864        mediaKeySessionContext: null
11865      };
11866      switch (decryptdata.method) {
11867        case 'ISO-23001-7':
11868        case 'SAMPLE-AES':
11869        case 'SAMPLE-AES-CENC':
11870        case 'SAMPLE-AES-CTR':
11871          if (decryptdata.keyFormat === 'identity') {
11872            // loadKeyHTTP handles http(s) and data URLs
11873            return this.loadKeyHTTP(keyInfo, frag);
11874          }
11875          return this.loadKeyEME(keyInfo, frag);
11876        case 'AES-128':
11877        case 'AES-256':
11878        case 'AES-256-CTR':
11879          return this.loadKeyHTTP(keyInfo, frag);
11880        default:
11881          return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
11882      }
11883    };
11884    _proto.loadKeyEME = function loadKeyEME(keyInfo, frag) {
11885      var keyLoadedData = {
11886        frag: frag,
11887        keyInfo: keyInfo
11888      };
11889      if (this.emeController && this.config.emeEnabled) {
11890        var keySessionContextPromise = this.emeController.loadKey(keyLoadedData);
11891        if (keySessionContextPromise) {
11892          return (keyInfo.keyLoadPromise = keySessionContextPromise.then(function (keySessionContext) {
11893            keyInfo.mediaKeySessionContext = keySessionContext;
11894            return keyLoadedData;
11895          })).catch(function (error) {
11896            // Remove promise for license renewal or retry
11897            keyInfo.keyLoadPromise = null;
11898            throw error;
11899          });
11900        }
11901      }
11902      return Promise.resolve(keyLoadedData);
11903    };
11904    _proto.loadKeyHTTP = function loadKeyHTTP(keyInfo, frag) {
11905      var _this3 = this;
11906      var config = this.config;
11907      var Loader = config.loader;
11908      var keyLoader = new Loader(config);
11909      frag.keyLoader = keyInfo.loader = keyLoader;
11910      return keyInfo.keyLoadPromise = new Promise(function (resolve, reject) {
11911        var loaderContext = {
11912          keyInfo: keyInfo,
11913          frag: frag,
11914          responseType: 'arraybuffer',
11915          url: keyInfo.decryptdata.uri
11916        };
11917
11918        // maxRetry is 0 so that instead of retrying the same key on the same variant multiple times,
11919        // key-loader will trigger an error and rely on stream-controller to handle retry logic.
11920        // this will also align retry logic with fragment-loader
11921        var loadPolicy = config.keyLoadPolicy.default;
11922        var loaderConfig = {
11923          loadPolicy: loadPolicy,
11924          timeout: loadPolicy.maxLoadTimeMs,
11925          maxRetry: 0,
11926          retryDelay: 0,
11927          maxRetryDelay: 0
11928        };
11929        var loaderCallbacks = {
11930          onSuccess: function onSuccess(response, stats, context, networkDetails) {
11931            var frag = context.frag,
11932              keyInfo = context.keyInfo,
11933              uri = context.url;
11934            if (!frag.decryptdata || keyInfo !== _this3.keyUriToKeyInfo[uri]) {
11935              return reject(_this3.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error('after key load, decryptdata unset or changed'), networkDetails));
11936            }
11937            keyInfo.decryptdata.key = frag.decryptdata.key = new Uint8Array(response.data);
11938
11939            // detach fragment key loader on load success
11940            frag.keyLoader = null;
11941            keyInfo.loader = null;
11942            resolve({
11943              frag: frag,
11944              keyInfo: keyInfo
11945            });
11946          },
11947          onError: function onError(response, context, networkDetails, stats) {
11948            _this3.resetLoader(context);
11949            reject(_this3.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("HTTP Error " + response.code + " loading key " + response.text), networkDetails, _objectSpread2({
11950              url: loaderContext.url,
11951              data: undefined
11952            }, response)));
11953          },
11954          onTimeout: function onTimeout(stats, context, networkDetails) {
11955            _this3.resetLoader(context);
11956            reject(_this3.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_TIMEOUT, new Error('key loading timed out'), networkDetails));
11957          },
11958          onAbort: function onAbort(stats, context, networkDetails) {
11959            _this3.resetLoader(context);
11960            reject(_this3.createKeyLoadError(frag, ErrorDetails.INTERNAL_ABORTED, new Error('key loading aborted'), networkDetails));
11961          }
11962        };
11963        keyLoader.load(loaderContext, loaderConfig, loaderCallbacks);
11964      });
11965    };
11966    _proto.resetLoader = function resetLoader(context) {
11967      var frag = context.frag,
11968        keyInfo = context.keyInfo,
11969        uri = context.url;
11970      var loader = keyInfo.loader;
11971      if (frag.keyLoader === loader) {
11972        frag.keyLoader = null;
11973        keyInfo.loader = null;
11974      }
11975      delete this.keyUriToKeyInfo[uri];
11976      if (loader) {
11977        loader.destroy();
11978      }
11979    };
11980    return KeyLoader;
11981  }();
11982
11983  /**
11984   * @ignore
11985   * Sub-class specialization of EventHandler base class.
11986   *
11987   * TaskLoop allows to schedule a task function being called (optionnaly repeatedly) on the main loop,
11988   * scheduled asynchroneously, avoiding recursive calls in the same tick.
11989   *
11990   * The task itself is implemented in `doTick`. It can be requested and called for single execution
11991   * using the `tick` method.
11992   *
11993   * It will be assured that the task execution method (`tick`) only gets called once per main loop "tick",
11994   * no matter how often it gets requested for execution. Execution in further ticks will be scheduled accordingly.
11995   *
11996   * If further execution requests have already been scheduled on the next tick, it can be checked with `hasNextTick`,
11997   * and cancelled with `clearNextTick`.
11998   *
11999   * The task can be scheduled as an interval repeatedly with a period as parameter (see `setInterval`, `clearInterval`).
12000   *
12001   * Sub-classes need to implement the `doTick` method which will effectively have the task execution routine.
12002   *
12003   * Further explanations:
12004   *
12005   * The baseclass has a `tick` method that will schedule the doTick call. It may be called synchroneously
12006   * only for a stack-depth of one. On re-entrant calls, sub-sequent calls are scheduled for next main loop ticks.
12007   *
12008   * When the task execution (`tick` method) is called in re-entrant way this is detected and
12009   * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
12010   * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
12011   */
12012  var TaskLoop = /*#__PURE__*/function (_Logger) {
12013    function TaskLoop(label, logger) {
12014      var _this;
12015      _this = _Logger.call(this, label, logger) || this;
12016      _this._boundTick = void 0;
12017      _this._tickTimer = null;
12018      _this._tickInterval = null;
12019      _this._tickCallCount = 0;
12020      _this._boundTick = _this.tick.bind(_this);
12021      return _this;
12022    }
12023    _inheritsLoose(TaskLoop, _Logger);
12024    var _proto = TaskLoop.prototype;
12025    _proto.destroy = function destroy() {
12026      this.onHandlerDestroying();
12027      this.onHandlerDestroyed();
12028    };
12029    _proto.onHandlerDestroying = function onHandlerDestroying() {
12030      // clear all timers before unregistering from event bus
12031      this.clearNextTick();
12032      this.clearInterval();
12033    };
12034    _proto.onHandlerDestroyed = function onHandlerDestroyed() {};
12035    _proto.hasInterval = function hasInterval() {
12036      return !!this._tickInterval;
12037    };
12038    _proto.hasNextTick = function hasNextTick() {
12039      return !!this._tickTimer;
12040    }
12041
12042    /**
12043     * @param millis - Interval time (ms)
12044     * @eturns True when interval has been scheduled, false when already scheduled (no effect)
12045     */;
12046    _proto.setInterval = function setInterval(millis) {
12047      if (!this._tickInterval) {
12048        this._tickCallCount = 0;
12049        this._tickInterval = self.setInterval(this._boundTick, millis);
12050        return true;
12051      }
12052      return false;
vendor: 4,298 bytes, lines 12053-12198
12053    }
12054
12055    /**
12056     * @returns True when interval was cleared, false when none was set (no effect)
12057     */;
12058    _proto.clearInterval = function clearInterval() {
12059      if (this._tickInterval) {
12060        self.clearInterval(this._tickInterval);
12061        this._tickInterval = null;
12062        return true;
12063      }
12064      return false;
12065    }
12066
12067    /**
12068     * @returns True when timeout was cleared, false when none was set (no effect)
12069     */;
12070    _proto.clearNextTick = function clearNextTick() {
12071      if (this._tickTimer) {
12072        self.clearTimeout(this._tickTimer);
12073        this._tickTimer = null;
12074        return true;
12075      }
12076      return false;
12077    }
12078
12079    /**
12080     * Will call the subclass doTick implementation in this main loop tick
12081     * or in the next one (via setTimeout(,0)) in case it has already been called
12082     * in this tick (in case this is a re-entrant call).
12083     */;
12084    _proto.tick = function tick() {
12085      this._tickCallCount++;
12086      if (this._tickCallCount === 1) {
12087        this.doTick();
12088        // re-entrant call to tick from previous doTick call stack
12089        // -> schedule a call on the next main loop iteration to process this task processing request
12090        if (this._tickCallCount > 1) {
12091          // make sure only one timer exists at any time at max
12092          this.tickImmediate();
12093        }
12094        this._tickCallCount = 0;
12095      }
12096    };
12097    _proto.tickImmediate = function tickImmediate() {
12098      this.clearNextTick();
12099      this._tickTimer = self.setTimeout(this._boundTick, 0);
12100    }
12101
12102    /**
12103     * For subclass to implement task logic
12104     * @abstract
12105     */;
12106    _proto.doTick = function doTick() {};
12107    return TaskLoop;
12108  }(Logger);
12109
12110  var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
12111    if (size === void 0) {
12112      size = 0;
12113    }
12114    if (part === void 0) {
12115      part = -1;
12116    }
12117    if (partial === void 0) {
12118      partial = false;
12119    }
12120    this.level = void 0;
12121    this.sn = void 0;
12122    this.part = void 0;
12123    this.id = void 0;
12124    this.size = void 0;
12125    this.partial = void 0;
12126    this.transmuxing = getNewPerformanceTiming();
12127    this.buffering = {
12128      audio: getNewPerformanceTiming(),
12129      video: getNewPerformanceTiming(),
12130      audiovideo: getNewPerformanceTiming()
12131    };
12132    this.level = level;
12133    this.sn = sn;
12134    this.id = id;
12135    this.size = size;
12136    this.part = part;
12137    this.partial = partial;
12138  };
12139  function getNewPerformanceTiming() {
12140    return {
12141      start: 0,
12142      executeStart: 0,
12143      executeEnd: 0,
12144      end: 0
12145    };
12146  }
12147
12148  function findFirstFragWithCC(fragments, cc) {
12149    for (var i = 0, len = fragments.length; i < len; i++) {
12150      var _fragments$i;
12151      if (((_fragments$i = fragments[i]) == null ? void 0 : _fragments$i.cc) === cc) {
12152        return fragments[i];
12153      }
12154    }
12155    return null;
12156  }
12157  function shouldAlignOnDiscontinuities(refDetails, details) {
12158    if (refDetails) {
12159      if (details.startCC < refDetails.endCC && details.endCC > refDetails.startCC) {
12160        return true;
12161      }
12162    }
12163    return false;
12164  }
12165  function adjustFragmentStart(frag, sliding) {
12166    if (frag) {
12167      var start = frag.start + sliding;
12168      frag.start = frag.startPTS = start;
12169      frag.endPTS = start + frag.duration;
12170    }
12171  }
12172  function adjustSlidingStart(sliding, details) {
12173    // Update segments
12174    var fragments = details.fragments;
12175    for (var i = 0, len = fragments.length; i < len; i++) {
12176      adjustFragmentStart(fragments[i], sliding);
12177    }
12178    // Update LL-HLS parts at the end of the playlist
12179    if (details.fragmentHint) {
12180      adjustFragmentStart(details.fragmentHint, sliding);
12181    }
12182    details.alignedSliding = true;
12183  }
12184
12185  /**
12186   * Using the parameters of the last level, this function computes PTS' of the new fragments so that they form a
12187   * contiguous stream with the last fragments.
12188   * The PTS of a fragment lets Hls.js know where it fits into a stream - by knowing every PTS, we know which fragment to
12189   * download at any given time. PTS is normally computed when the fragment is demuxed, so taking this step saves us time
12190   * and an extra download.
12191   * @param lastFrag
12192   * @param lastLevel
12193   * @param details
12194   */
12195  function alignStream(lastFrag, switchDetails, details) {
12196    if (!switchDetails) {
12197      return;
12198    }
vendor: 5,294 bytes, lines 12199-12322
12199    alignDiscontinuities(details, switchDetails);
12200    if (!details.alignedSliding && switchDetails) {
12201      // If the PTS wasn't figured out via discontinuity sequence that means there was no CC increase within the level.
12202      // Aligning via Program Date Time should therefore be reliable, since PDT should be the same within the same
12203      // discontinuity sequence.
12204      alignMediaPlaylistByPDT(details, switchDetails);
12205    }
12206    if (!details.alignedSliding && switchDetails && !details.skippedSegments) {
12207      // Try to align on sn so that we pick a better start fragment.
12208      // Do not perform this on playlists with delta updates as this is only to align levels on switch
12209      // and adjustSliding only adjusts fragments after skippedSegments.
12210      adjustSliding(switchDetails, details);
12211    }
12212  }
12213
12214  /**
12215   * Ajust the start of fragments in `details` by the difference in time between fragments of the latest
12216   * shared discontinuity sequence change.
12217   * @param lastLevel - The details of the last loaded level
12218   * @param details - The details of the new level
12219   */
12220  function alignDiscontinuities(details, refDetails) {
12221    if (!shouldAlignOnDiscontinuities(refDetails, details)) {
12222      return;
12223    }
12224    var targetCC = Math.min(refDetails.endCC, details.endCC);
12225    var refFrag = findFirstFragWithCC(refDetails.fragments, targetCC);
12226    var frag = findFirstFragWithCC(details.fragments, targetCC);
12227    if (!refFrag || !frag) {
12228      return;
12229    }
12230    logger.log("Aligning playlist at start of dicontinuity sequence " + targetCC);
12231    var delta = refFrag.start - frag.start;
12232    adjustSlidingStart(delta, details);
12233  }
12234
12235  /**
12236   * Ensures appropriate time-alignment between renditions based on PDT.
12237   * This function assumes the timelines represented in `refDetails` are accurate, including the PDTs
12238   * for the last discontinuity sequence number shared by both playlists when present,
12239   * and uses the "wallclock"/PDT timeline as a cross-reference to `details`, adjusting the presentation
12240   * times/timelines of `details` accordingly.
12241   * Given the asynchronous nature of fetches and initial loads of live `main` and audio/subtitle tracks,
12242   * the primary purpose of this function is to ensure the "local timelines" of audio/subtitle tracks
12243   * are aligned to the main/video timeline, using PDT as the cross-reference/"anchor" that should
12244   * be consistent across playlists, per the HLS spec.
12245   * @param details - The details of the rendition you'd like to time-align (e.g. an audio rendition).
12246   * @param refDetails - The details of the reference rendition with start and PDT times for alignment.
12247   */
12248  function alignMediaPlaylistByPDT(details, refDetails) {
12249    if (!details.hasProgramDateTime || !refDetails.hasProgramDateTime) {
12250      return;
12251    }
12252    var fragments = details.fragments;
12253    var refFragments = refDetails.fragments;
12254    if (!fragments.length || !refFragments.length) {
12255      return;
12256    }
12257
12258    // Calculate a delta to apply to all fragments according to the delta in PDT times and start times
12259    // of a fragment in the reference details, and a fragment in the target details of the same discontinuity.
12260    // If a fragment of the same discontinuity was not found use the middle fragment of both.
12261    var refFrag;
12262    var frag;
12263    var targetCC = Math.min(refDetails.endCC, details.endCC);
12264    if (refDetails.startCC < targetCC && details.startCC < targetCC) {
12265      refFrag = findFirstFragWithCC(refFragments, targetCC);
12266      frag = findFirstFragWithCC(fragments, targetCC);
12267    }
12268    if (!refFrag || !frag) {
12269      refFrag = refFragments[Math.floor(refFragments.length / 2)];
12270      frag = findFirstFragWithCC(fragments, refFrag.cc) || fragments[Math.floor(fragments.length / 2)];
12271    }
12272    var refPDT = refFrag.programDateTime;
12273    var targetPDT = frag.programDateTime;
12274    if (!refPDT || !targetPDT) {
12275      return;
12276    }
12277    var delta = (targetPDT - refPDT) / 1000 - (frag.start - refFrag.start);
12278    adjustSlidingStart(delta, details);
12279  }
12280
12281  var AESCrypto = /*#__PURE__*/function () {
12282    function AESCrypto(subtle, iv, aesMode) {
12283      this.subtle = void 0;
12284      this.aesIV = void 0;
12285      this.aesMode = void 0;
12286      this.subtle = subtle;
12287      this.aesIV = iv;
12288      this.aesMode = aesMode;
12289    }
12290    var _proto = AESCrypto.prototype;
12291    _proto.decrypt = function decrypt(data, key) {
12292      switch (this.aesMode) {
12293        case DecrypterAesMode.cbc:
12294          return this.subtle.decrypt({
12295            name: 'AES-CBC',
12296            iv: this.aesIV
12297          }, key, data);
12298        case DecrypterAesMode.ctr:
12299          return this.subtle.decrypt({
12300            name: 'AES-CTR',
12301            counter: this.aesIV,
12302            length: 64
12303          },
12304          //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
12305          key, data);
12306        default:
12307          throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
12308      }
12309    };
12310    return AESCrypto;
12311  }();
12312
12313  var FastAESKey = /*#__PURE__*/function () {
12314    function FastAESKey(subtle, key, aesMode) {
12315      this.subtle = void 0;
12316      this.key = void 0;
12317      this.aesMode = void 0;
12318      this.subtle = subtle;
12319      this.key = key;
12320      this.aesMode = aesMode;
12321    }
12322    var _proto = FastAESKey.prototype;
vendor: 9,796 bytes, lines 12323-12580
12323    _proto.expandKey = function expandKey() {
12324      var subtleAlgoName = getSubtleAlgoName(this.aesMode);
12325      return this.subtle.importKey('raw', this.key, {
12326        name: subtleAlgoName
12327      }, false, ['encrypt', 'decrypt']);
12328    };
12329    return FastAESKey;
12330  }();
12331  function getSubtleAlgoName(aesMode) {
12332    switch (aesMode) {
12333      case DecrypterAesMode.cbc:
12334        return 'AES-CBC';
12335      case DecrypterAesMode.ctr:
12336        return 'AES-CTR';
12337      default:
12338        throw new Error("[FastAESKey] invalid aes mode " + aesMode);
12339    }
12340  }
12341
12342  // PKCS7
12343  function removePadding(array) {
12344    var outputBytes = array.byteLength;
12345    var paddingBytes = outputBytes && new DataView(array.buffer).getUint8(outputBytes - 1);
12346    if (paddingBytes) {
12347      return sliceUint8(array, 0, outputBytes - paddingBytes);
12348    }
12349    return array;
12350  }
12351  var AESDecryptor = /*#__PURE__*/function () {
12352    function AESDecryptor() {
12353      this.rcon = [0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
12354      this.subMix = [new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256)];
12355      this.invSubMix = [new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256)];
12356      this.sBox = new Uint32Array(256);
12357      this.invSBox = new Uint32Array(256);
12358      this.key = new Uint32Array(0);
12359      this.ksRows = 0;
12360      this.keySize = 0;
12361      this.keySchedule = void 0;
12362      this.invKeySchedule = void 0;
12363      this.initTable();
12364    }
12365
12366    // Using view.getUint32() also swaps the byte order.
12367    var _proto = AESDecryptor.prototype;
12368    _proto.uint8ArrayToUint32Array_ = function uint8ArrayToUint32Array_(arrayBuffer) {
12369      var view = new DataView(arrayBuffer);
12370      var newArray = new Uint32Array(4);
12371      for (var i = 0; i < 4; i++) {
12372        newArray[i] = view.getUint32(i * 4);
12373      }
12374      return newArray;
12375    };
12376    _proto.initTable = function initTable() {
12377      var sBox = this.sBox;
12378      var invSBox = this.invSBox;
12379      var subMix = this.subMix;
12380      var subMix0 = subMix[0];
12381      var subMix1 = subMix[1];
12382      var subMix2 = subMix[2];
12383      var subMix3 = subMix[3];
12384      var invSubMix = this.invSubMix;
12385      var invSubMix0 = invSubMix[0];
12386      var invSubMix1 = invSubMix[1];
12387      var invSubMix2 = invSubMix[2];
12388      var invSubMix3 = invSubMix[3];
12389      var d = new Uint32Array(256);
12390      var x = 0;
12391      var xi = 0;
12392      var i = 0;
12393      for (i = 0; i < 256; i++) {
12394        if (i < 128) {
12395          d[i] = i << 1;
12396        } else {
12397          d[i] = i << 1 ^ 0x11b;
12398        }
12399      }
12400      for (i = 0; i < 256; i++) {
12401        var sx = xi ^ xi << 1 ^ xi << 2 ^ xi << 3 ^ xi << 4;
12402        sx = sx >>> 8 ^ sx & 0xff ^ 0x63;
12403        sBox[x] = sx;
12404        invSBox[sx] = x;
12405
12406        // Compute multiplication
12407        var x2 = d[x];
12408        var x4 = d[x2];
12409        var x8 = d[x4];
12410
12411        // Compute sub/invSub bytes, mix columns tables
12412        var t = d[sx] * 0x101 ^ sx * 0x1010100;
12413        subMix0[x] = t << 24 | t >>> 8;
12414        subMix1[x] = t << 16 | t >>> 16;
12415        subMix2[x] = t << 8 | t >>> 24;
12416        subMix3[x] = t;
12417
12418        // Compute inv sub bytes, inv mix columns tables
12419        t = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
12420        invSubMix0[sx] = t << 24 | t >>> 8;
12421        invSubMix1[sx] = t << 16 | t >>> 16;
12422        invSubMix2[sx] = t << 8 | t >>> 24;
12423        invSubMix3[sx] = t;
12424
12425        // Compute next counter
12426        if (!x) {
12427          x = xi = 1;
12428        } else {
12429          x = x2 ^ d[d[d[x8 ^ x2]]];
12430          xi ^= d[d[xi]];
12431        }
12432      }
12433    };
12434    _proto.expandKey = function expandKey(keyBuffer) {
12435      // convert keyBuffer to Uint32Array
12436      var key = this.uint8ArrayToUint32Array_(keyBuffer);
12437      var sameKey = true;
12438      var offset = 0;
12439      while (offset < key.length && sameKey) {
12440        sameKey = key[offset] === this.key[offset];
12441        offset++;
12442      }
12443      if (sameKey) {
12444        return;
12445      }
12446      this.key = key;
12447      var keySize = this.keySize = key.length;
12448      if (keySize !== 4 && keySize !== 6 && keySize !== 8) {
12449        throw new Error('Invalid aes key size=' + keySize);
12450      }
12451      var ksRows = this.ksRows = (keySize + 6 + 1) * 4;
12452      var ksRow;
12453      var invKsRow;
12454      var keySchedule = this.keySchedule = new Uint32Array(ksRows);
12455      var invKeySchedule = this.invKeySchedule = new Uint32Array(ksRows);
12456      var sbox = this.sBox;
12457      var rcon = this.rcon;
12458      var invSubMix = this.invSubMix;
12459      var invSubMix0 = invSubMix[0];
12460      var invSubMix1 = invSubMix[1];
12461      var invSubMix2 = invSubMix[2];
12462      var invSubMix3 = invSubMix[3];
12463      var prev;
12464      var t;
12465      for (ksRow = 0; ksRow < ksRows; ksRow++) {
12466        if (ksRow < keySize) {
12467          prev = keySchedule[ksRow] = key[ksRow];
12468          continue;
12469        }
12470        t = prev;
12471        if (ksRow % keySize === 0) {
12472          // Rot word
12473          t = t << 8 | t >>> 24;
12474
12475          // Sub word
12476          t = sbox[t >>> 24] << 24 | sbox[t >>> 16 & 0xff] << 16 | sbox[t >>> 8 & 0xff] << 8 | sbox[t & 0xff];
12477
12478          // Mix Rcon
12479          t ^= rcon[ksRow / keySize | 0] << 24;
12480        } else if (keySize > 6 && ksRow % keySize === 4) {
12481          // Sub word
12482          t = sbox[t >>> 24] << 24 | sbox[t >>> 16 & 0xff] << 16 | sbox[t >>> 8 & 0xff] << 8 | sbox[t & 0xff];
12483        }
12484        keySchedule[ksRow] = prev = (keySchedule[ksRow - keySize] ^ t) >>> 0;
12485      }
12486      for (invKsRow = 0; invKsRow < ksRows; invKsRow++) {
12487        ksRow = ksRows - invKsRow;
12488        if (invKsRow & 3) {
12489          t = keySchedule[ksRow];
12490        } else {
12491          t = keySchedule[ksRow - 4];
12492        }
12493        if (invKsRow < 4 || ksRow <= 4) {
12494          invKeySchedule[invKsRow] = t;
12495        } else {
12496          invKeySchedule[invKsRow] = invSubMix0[sbox[t >>> 24]] ^ invSubMix1[sbox[t >>> 16 & 0xff]] ^ invSubMix2[sbox[t >>> 8 & 0xff]] ^ invSubMix3[sbox[t & 0xff]];
12497        }
12498        invKeySchedule[invKsRow] = invKeySchedule[invKsRow] >>> 0;
12499      }
12500    }
12501
12502    // Adding this as a method greatly improves performance.
12503    ;
12504    _proto.networkToHostOrderSwap = function networkToHostOrderSwap(word) {
12505      return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;
12506    };
12507    _proto.decrypt = function decrypt(inputArrayBuffer, offset, aesIV) {
12508      var nRounds = this.keySize + 6;
12509      var invKeySchedule = this.invKeySchedule;
12510      var invSBOX = this.invSBox;
12511      var invSubMix = this.invSubMix;
12512      var invSubMix0 = invSubMix[0];
12513      var invSubMix1 = invSubMix[1];
12514      var invSubMix2 = invSubMix[2];
12515      var invSubMix3 = invSubMix[3];
12516      var initVector = this.uint8ArrayToUint32Array_(aesIV);
12517      var initVector0 = initVector[0];
12518      var initVector1 = initVector[1];
12519      var initVector2 = initVector[2];
12520      var initVector3 = initVector[3];
12521      var inputInt32 = new Int32Array(inputArrayBuffer);
12522      var outputInt32 = new Int32Array(inputInt32.length);
12523      var t0, t1, t2, t3;
12524      var s0, s1, s2, s3;
12525      var inputWords0, inputWords1, inputWords2, inputWords3;
12526      var ksRow, i;
12527      var swapWord = this.networkToHostOrderSwap;
12528      while (offset < inputInt32.length) {
12529        inputWords0 = swapWord(inputInt32[offset]);
12530        inputWords1 = swapWord(inputInt32[offset + 1]);
12531        inputWords2 = swapWord(inputInt32[offset + 2]);
12532        inputWords3 = swapWord(inputInt32[offset + 3]);
12533        s0 = inputWords0 ^ invKeySchedule[0];
12534        s1 = inputWords3 ^ invKeySchedule[1];
12535        s2 = inputWords2 ^ invKeySchedule[2];
12536        s3 = inputWords1 ^ invKeySchedule[3];
12537        ksRow = 4;
12538
12539        // Iterate through the rounds of decryption
12540        for (i = 1; i < nRounds; i++) {
12541          t0 = invSubMix0[s0 >>> 24] ^ invSubMix1[s1 >> 16 & 0xff] ^ invSubMix2[s2 >> 8 & 0xff] ^ invSubMix3[s3 & 0xff] ^ invKeySchedule[ksRow];
12542          t1 = invSubMix0[s1 >>> 24] ^ invSubMix1[s2 >> 16 & 0xff] ^ invSubMix2[s3 >> 8 & 0xff] ^ invSubMix3[s0 & 0xff] ^ invKeySchedule[ksRow + 1];
12543          t2 = invSubMix0[s2 >>> 24] ^ invSubMix1[s3 >> 16 & 0xff] ^ invSubMix2[s0 >> 8 & 0xff] ^ invSubMix3[s1 & 0xff] ^ invKeySchedule[ksRow + 2];
12544          t3 = invSubMix0[s3 >>> 24] ^ invSubMix1[s0 >> 16 & 0xff] ^ invSubMix2[s1 >> 8 & 0xff] ^ invSubMix3[s2 & 0xff] ^ invKeySchedule[ksRow + 3];
12545          // Update state
12546          s0 = t0;
12547          s1 = t1;
12548          s2 = t2;
12549          s3 = t3;
12550          ksRow = ksRow + 4;
12551        }
12552
12553        // Shift rows, sub bytes, add round key
12554        t0 = invSBOX[s0 >>> 24] << 24 ^ invSBOX[s1 >> 16 & 0xff] << 16 ^ invSBOX[s2 >> 8 & 0xff] << 8 ^ invSBOX[s3 & 0xff] ^ invKeySchedule[ksRow];
12555        t1 = invSBOX[s1 >>> 24] << 24 ^ invSBOX[s2 >> 16 & 0xff] << 16 ^ invSBOX[s3 >> 8 & 0xff] << 8 ^ invSBOX[s0 & 0xff] ^ invKeySchedule[ksRow + 1];
12556        t2 = invSBOX[s2 >>> 24] << 24 ^ invSBOX[s3 >> 16 & 0xff] << 16 ^ invSBOX[s0 >> 8 & 0xff] << 8 ^ invSBOX[s1 & 0xff] ^ invKeySchedule[ksRow + 2];
12557        t3 = invSBOX[s3 >>> 24] << 24 ^ invSBOX[s0 >> 16 & 0xff] << 16 ^ invSBOX[s1 >> 8 & 0xff] << 8 ^ invSBOX[s2 & 0xff] ^ invKeySchedule[ksRow + 3];
12558
12559        // Write
12560        outputInt32[offset] = swapWord(t0 ^ initVector0);
12561        outputInt32[offset + 1] = swapWord(t3 ^ initVector1);
12562        outputInt32[offset + 2] = swapWord(t2 ^ initVector2);
12563        outputInt32[offset + 3] = swapWord(t1 ^ initVector3);
12564
12565        // reset initVector to last 4 unsigned int
12566        initVector0 = inputWords0;
12567        initVector1 = inputWords1;
12568        initVector2 = inputWords2;
12569        initVector3 = inputWords3;
12570        offset = offset + 4;
12571      }
12572      return outputInt32.buffer;
12573    };
12574    return AESDecryptor;
12575  }();
12576
12577  var CHUNK_SIZE = 16; // 16 bytes, 128 bits
12578  var Decrypter = /*#__PURE__*/function () {
12579    function Decrypter(config, _temp) {
12580      var _ref = _temp === void 0 ? {}
vendor: 52,804 bytes, lines 12580-13787
12580 : _temp,
12581        _ref$removePKCS7Paddi = _ref.removePKCS7Padding,
12582        removePKCS7Padding = _ref$removePKCS7Paddi === void 0 ? true : _ref$removePKCS7Paddi;
12583      this.logEnabled = true;
12584      this.removePKCS7Padding = void 0;
12585      this.subtle = null;
12586      this.softwareDecrypter = null;
12587      this.key = null;
12588      this.fastAesKey = null;
12589      this.remainderData = null;
12590      this.currentIV = null;
12591      this.currentResult = null;
12592      this.useSoftware = void 0;
12593      this.enableSoftwareAES = void 0;
12594      this.enableSoftwareAES = config.enableSoftwareAES;
12595      this.removePKCS7Padding = removePKCS7Padding;
12596      // built in decryptor expects PKCS7 padding
12597      if (removePKCS7Padding) {
12598        try {
12599          var browserCrypto = self.crypto;
12600          if (browserCrypto) {
12601            this.subtle = browserCrypto.subtle || browserCrypto.webkitSubtle;
12602          }
12603        } catch (e) {
12604          /* no-op */
12605        }
12606      }
12607      this.useSoftware = !this.subtle;
12608    }
12609    var _proto = Decrypter.prototype;
12610    _proto.destroy = function destroy() {
12611      this.subtle = null;
12612      this.softwareDecrypter = null;
12613      this.key = null;
12614      this.fastAesKey = null;
12615      this.remainderData = null;
12616      this.currentIV = null;
12617      this.currentResult = null;
12618    };
12619    _proto.isSync = function isSync() {
12620      return this.useSoftware;
12621    };
12622    _proto.flush = function flush() {
12623      var currentResult = this.currentResult,
12624        remainderData = this.remainderData;
12625      if (!currentResult || remainderData) {
12626        this.reset();
12627        return null;
12628      }
12629      var data = new Uint8Array(currentResult);
12630      this.reset();
12631      if (this.removePKCS7Padding) {
12632        return removePadding(data);
12633      }
12634      return data;
12635    };
12636    _proto.reset = function reset() {
12637      this.currentResult = null;
12638      this.currentIV = null;
12639      this.remainderData = null;
12640      if (this.softwareDecrypter) {
12641        this.softwareDecrypter = null;
12642      }
12643    };
12644    _proto.decrypt = function decrypt(data, key, iv, aesMode) {
12645      var _this = this;
12646      if (this.useSoftware) {
12647        return new Promise(function (resolve, reject) {
12648          _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
12649          var decryptResult = _this.flush();
12650          if (decryptResult) {
12651            resolve(decryptResult.buffer);
12652          } else {
12653            reject(new Error('[softwareDecrypt] Failed to decrypt data'));
12654          }
12655        });
12656      }
12657      return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
12658    }
12659
12660    // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
12661    // data is handled in the flush() call
12662    ;
12663    _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
12664      var currentIV = this.currentIV,
12665        currentResult = this.currentResult,
12666        remainderData = this.remainderData;
12667      if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
12668        logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
12669        return null;
12670      }
12671      this.logOnce('JS AES decrypt');
12672      // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
12673      // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
12674      // the end on flush(), but by that time we have already received all bytes for the segment.
12675      // Progressive decryption does not work with WebCrypto
12676
12677      if (remainderData) {
12678        data = appendUint8Array(remainderData, data);
12679        this.remainderData = null;
12680      }
12681
12682      // Byte length must be a multiple of 16 (AES-128 = 128 bit blocks = 16 bytes)
12683      var currentChunk = this.getValidChunk(data);
12684      if (!currentChunk.length) {
12685        return null;
12686      }
12687      if (currentIV) {
12688        iv = currentIV;
12689      }
12690      var softwareDecrypter = this.softwareDecrypter;
12691      if (!softwareDecrypter) {
12692        softwareDecrypter = this.softwareDecrypter = new AESDecryptor();
12693      }
12694      softwareDecrypter.expandKey(key);
12695      var result = currentResult;
12696      this.currentResult = softwareDecrypter.decrypt(currentChunk.buffer, 0, iv);
12697      this.currentIV = sliceUint8(currentChunk, -16).buffer;
12698      if (!result) {
12699        return null;
12700      }
12701      return result;
12702    };
12703    _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
12704      var _this2 = this;
12705      if (this.key !== key || !this.fastAesKey) {
12706        if (!this.subtle) {
12707          return Promise.resolve(this.onWebCryptoError(data, key, iv, aesMode));
12708        }
12709        this.key = key;
12710        this.fastAesKey = new FastAESKey(this.subtle, key, aesMode);
12711      }
12712      return this.fastAesKey.expandKey().then(function (aesKey) {
12713        // decrypt using web crypto
12714        if (!_this2.subtle) {
12715          return Promise.reject(new Error('web crypto not initialized'));
12716        }
12717        _this2.logOnce('WebCrypto AES decrypt');
12718        var crypto = new AESCrypto(_this2.subtle, new Uint8Array(iv), aesMode);
12719        return crypto.decrypt(data.buffer, aesKey);
12720      }).catch(function (err) {
12721        logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
12722        return _this2.onWebCryptoError(data, key, iv, aesMode);
12723      });
12724    };
12725    _proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
12726      var enableSoftwareAES = this.enableSoftwareAES;
12727      if (enableSoftwareAES) {
12728        this.useSoftware = true;
12729        this.logEnabled = true;
12730        this.softwareDecrypt(data, key, iv, aesMode);
12731        var decryptResult = this.flush();
12732        if (decryptResult) {
12733          return decryptResult.buffer;
12734        }
12735      }
12736      throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
12737    };
12738    _proto.getValidChunk = function getValidChunk(data) {
12739      var currentChunk = data;
12740      var splitPoint = data.length - data.length % CHUNK_SIZE;
12741      if (splitPoint !== data.length) {
12742        currentChunk = sliceUint8(data, 0, splitPoint);
12743        this.remainderData = sliceUint8(data, splitPoint);
12744      }
12745      return currentChunk;
12746    };
12747    _proto.logOnce = function logOnce(msg) {
12748      if (!this.logEnabled) {
12749        return;
12750      }
12751      logger.log("[decrypter]: " + msg);
12752      this.logEnabled = false;
12753    };
12754    return Decrypter;
12755  }();
12756
12757  /**
12758   *  TimeRanges to string helper
12759   */
12760
12761  var TimeRanges = {
12762    toString: function toString(r) {
12763      var log = '';
12764      var len = r.length;
12765      for (var i = 0; i < len; i++) {
12766        log += "[" + r.start(i).toFixed(3) + "-" + r.end(i).toFixed(3) + "]";
12767      }
12768      return log;
12769    }
12770  };
12771
12772  var State = {
12773    STOPPED: 'STOPPED',
12774    IDLE: 'IDLE',
12775    KEY_LOADING: 'KEY_LOADING',
12776    FRAG_LOADING: 'FRAG_LOADING',
12777    FRAG_LOADING_WAITING_RETRY: 'FRAG_LOADING_WAITING_RETRY',
12778    WAITING_TRACK: 'WAITING_TRACK',
12779    PARSING: 'PARSING',
12780    PARSED: 'PARSED',
12781    ENDED: 'ENDED',
12782    ERROR: 'ERROR',
12783    WAITING_INIT_PTS: 'WAITING_INIT_PTS',
12784    WAITING_LEVEL: 'WAITING_LEVEL'
12785  };
12786  var BaseStreamController = /*#__PURE__*/function (_TaskLoop) {
12787    function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
12788      var _this;
12789      _this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
12790      _this.hls = void 0;
12791      _this.fragPrevious = null;
12792      _this.fragCurrent = null;
12793      _this.fragmentTracker = void 0;
12794      _this.transmuxer = null;
12795      _this._state = State.STOPPED;
12796      _this.playlistType = void 0;
12797      _this.media = null;
12798      _this.mediaBuffer = null;
12799      _this.config = void 0;
12800      _this.bitrateTest = false;
12801      _this.lastCurrentTime = 0;
12802      _this.nextLoadPosition = 0;
12803      _this.startPosition = 0;
12804      _this.startTimeOffset = null;
12805      _this.loadedmetadata = false;
12806      _this.retryDate = 0;
12807      _this.levels = null;
12808      _this.fragmentLoader = void 0;
12809      _this.keyLoader = void 0;
12810      _this.levelLastLoaded = null;
12811      _this.startFragRequested = false;
12812      _this.decrypter = void 0;
12813      _this.initPTS = [];
12814      _this.buffering = true;
12815      _this.loadingParts = false;
12816      _this.loopSn = void 0;
12817      _this.onMediaSeeking = function () {
12818        var _this2 = _this,
12819          config = _this2.config,
12820          fragCurrent = _this2.fragCurrent,
12821          media = _this2.media,
12822          mediaBuffer = _this2.mediaBuffer,
12823          state = _this2.state;
12824        var currentTime = media ? media.currentTime : 0;
12825        var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12826        _this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12827        if (_this.state === State.ENDED) {
12828          _this.resetLoadingState();
12829        } else if (fragCurrent) {
12830          // Seeking while frag load is in progress
12831          var tolerance = config.maxFragLookUpTolerance;
12832          var fragStartOffset = fragCurrent.start - tolerance;
12833          var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12834          // if seeking out of buffered range or into new one
12835          if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12836            var pastFragment = currentTime > fragEndOffset;
12837            // if the seek position is outside the current fragment range
12838            if (currentTime < fragStartOffset || pastFragment) {
12839              if (pastFragment && fragCurrent.loader) {
12840                _this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12841                fragCurrent.abortRequests();
12842                _this.resetLoadingState();
12843              }
12844              _this.fragPrevious = null;
12845            }
12846          }
12847        }
12848        if (media) {
12849          // Remove gap fragments
12850          _this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
12851
12852          // Don't set lastCurrentTime with backward seeks (allows for frag selection with strict tolerances)
12853          var lastCurrentTime = _this.lastCurrentTime;
12854          if (currentTime > lastCurrentTime) {
12855            _this.lastCurrentTime = currentTime;
12856          }
12857          if (!_this.loadingParts) {
12858            var bufferEnd = Math.max(bufferInfo.end, currentTime);
12859            var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
12860            if (shouldLoadParts) {
12861              _this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
12862              _this.loadingParts = shouldLoadParts;
12863            }
12864          }
12865        }
12866
12867        // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12868        if (!_this.loadedmetadata && !bufferInfo.len) {
12869          _this.nextLoadPosition = _this.startPosition = currentTime;
12870        }
12871
12872        // Async tick to speed up processing
12873        _this.tickImmediate();
12874      };
12875      _this.onMediaEnded = function () {
12876        // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12877        _this.startPosition = _this.lastCurrentTime = 0;
12878        if (_this.playlistType === PlaylistLevelType.MAIN) {
12879          _this.hls.trigger(Events.MEDIA_ENDED, {
12880            stalled: false
12881          });
12882        }
12883      };
12884      _this.playlistType = playlistType;
12885      _this.hls = hls;
12886      _this.fragmentLoader = new FragmentLoader(hls.config);
12887      _this.keyLoader = keyLoader;
12888      _this.fragmentTracker = fragmentTracker;
12889      _this.config = hls.config;
12890      _this.decrypter = new Decrypter(hls.config);
12891      return _this;
12892    }
12893    _inheritsLoose(BaseStreamController, _TaskLoop);
12894    var _proto = BaseStreamController.prototype;
12895    _proto.registerListeners = function registerListeners() {
12896      var hls = this.hls;
12897      hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12898      hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12899      hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12900      hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12901      hls.on(Events.ERROR, this.onError, this);
12902    };
12903    _proto.unregisterListeners = function unregisterListeners() {
12904      var hls = this.hls;
12905      hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12906      hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12907      hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12908      hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12909      hls.off(Events.ERROR, this.onError, this);
12910    };
12911    _proto.doTick = function doTick() {
12912      this.onTickEnd();
12913    };
12914    _proto.onTickEnd = function onTickEnd() {}
12915
12916    // eslint-disable-next-line @typescript-eslint/no-unused-vars
12917    ;
12918    _proto.startLoad = function startLoad(startPosition) {};
12919    _proto.stopLoad = function stopLoad() {
12920      if (this.state === State.STOPPED) {
12921        return;
12922      }
12923      this.fragmentLoader.abort();
12924      this.keyLoader.abort(this.playlistType);
12925      var frag = this.fragCurrent;
12926      if (frag != null && frag.loader) {
12927        frag.abortRequests();
12928        this.fragmentTracker.removeFragment(frag);
12929      }
12930      this.resetTransmuxer();
12931      this.fragCurrent = null;
12932      this.fragPrevious = null;
12933      this.clearInterval();
12934      this.clearNextTick();
12935      this.state = State.STOPPED;
12936    };
12937    _proto.pauseBuffering = function pauseBuffering() {
12938      this.buffering = false;
12939    };
12940    _proto.resumeBuffering = function resumeBuffering() {
12941      this.buffering = true;
12942    };
12943    _proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
12944      // If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
12945      // of nothing loading/loaded return false
12946      if (levelDetails.live || bufferInfo.nextStart || !bufferInfo.end || !this.media) {
12947        return false;
12948      }
12949      var partList = levelDetails.partList;
12950      // Since the last part isn't guaranteed to correspond to the last playlist segment for Low-Latency HLS,
12951      // check instead if the last part is buffered.
12952      if (partList != null && partList.length) {
12953        var lastPart = partList[partList.length - 1];
12954
12955        // Checking the midpoint of the part for potential margin of error and related issues.
12956        // NOTE: Technically I believe parts could yield content that is < the computed duration (including potential a duration of 0)
12957        // and still be spec-compliant, so there may still be edge cases here. Likewise, there could be issues in end of stream
12958        // part mismatches for independent audio and video playlists/segments.
12959        var lastPartBuffered = BufferHelper.isBuffered(this.media, lastPart.start + lastPart.duration / 2);
12960        return lastPartBuffered;
12961      }
12962      var playlistType = levelDetails.fragments[levelDetails.fragments.length - 1].type;
12963      return this.fragmentTracker.isEndListAppended(playlistType);
12964    };
12965    _proto.getLevelDetails = function getLevelDetails() {
12966      if (this.levels && this.levelLastLoaded !== null) {
12967        var _this$levelLastLoaded;
12968        return (_this$levelLastLoaded = this.levelLastLoaded) == null ? void 0 : _this$levelLastLoaded.details;
12969      }
12970    };
12971    _proto.onMediaAttached = function onMediaAttached(event, data) {
12972      var media = this.media = this.mediaBuffer = data.media;
12973      media.addEventListener('seeking', this.onMediaSeeking);
12974      media.addEventListener('ended', this.onMediaEnded);
12975      var config = this.config;
12976      if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12977        this.startLoad(config.startPosition);
12978      }
12979    };
12980    _proto.onMediaDetaching = function onMediaDetaching() {
12981      var media = this.media;
12982      if (media != null && media.ended) {
12983        this.log('MSE detaching and video ended, reset startPosition');
12984        this.startPosition = this.lastCurrentTime = 0;
12985      }
12986
12987      // remove video listeners
12988      if (media) {
12989        media.removeEventListener('seeking', this.onMediaSeeking);
12990        media.removeEventListener('ended', this.onMediaEnded);
12991      }
12992      if (this.keyLoader) {
12993        this.keyLoader.detach();
12994      }
12995      this.media = this.mediaBuffer = null;
12996      this.loopSn = undefined;
12997      this.startFragRequested = this.loadedmetadata = this.loadingParts = false;
12998      this.fragmentTracker.removeAllFragments();
12999      this.stopLoad();
13000    };
13001    _proto.onManifestLoading = function onManifestLoading() {
13002      this.initPTS = [];
13003      this.levels = this.levelLastLoaded = this.fragCurrent = null;
13004      this.lastCurrentTime = this.startPosition = 0;
13005      this.startFragRequested = false;
13006    };
13007    _proto.onError = function onError(event, data) {};
13008    _proto.onManifestLoaded = function onManifestLoaded(event, data) {
13009      this.startTimeOffset = data.startTimeOffset;
13010    };
13011    _proto.onHandlerDestroying = function onHandlerDestroying() {
13012      this.stopLoad();
13013      if (this.transmuxer) {
13014        this.transmuxer.destroy();
13015        this.transmuxer = null;
13016      }
13017      _TaskLoop.prototype.onHandlerDestroying.call(this);
13018      // @ts-ignore
13019      this.hls = this.onMediaSeeking = this.onMediaEnded = null;
13020    };
13021    _proto.onHandlerDestroyed = function onHandlerDestroyed() {
13022      this.state = State.STOPPED;
13023      if (this.fragmentLoader) {
13024        this.fragmentLoader.destroy();
13025      }
13026      if (this.keyLoader) {
13027        this.keyLoader.destroy();
13028      }
13029      if (this.decrypter) {
13030        this.decrypter.destroy();
13031      }
13032      this.hls = this.log = this.warn = this.decrypter = this.keyLoader = this.fragmentLoader = this.fragmentTracker = null;
13033      _TaskLoop.prototype.onHandlerDestroyed.call(this);
13034    };
13035    _proto.loadFragment = function loadFragment(frag, level, targetBufferTime) {
13036      this.startFragRequested = true;
13037      this._loadFragForPlayback(frag, level, targetBufferTime);
13038    };
13039    _proto._loadFragForPlayback = function _loadFragForPlayback(frag, level, targetBufferTime) {
13040      var _this3 = this;
13041      var progressCallback = function progressCallback(data) {
13042        if (_this3.fragContextChanged(frag)) {
13043          _this3.warn("Fragment " + frag.sn + (data.part ? ' p: ' + data.part.index : '') + " of level " + frag.level + " was dropped during download.");
13044          _this3.fragmentTracker.removeFragment(frag);
13045          return;
13046        }
13047        frag.stats.chunkCount++;
13048        _this3._handleFragmentLoadProgress(data);
13049      };
13050      this._doFragLoad(frag, level, targetBufferTime, progressCallback).then(function (data) {
13051        if (!data) {
13052          // if we're here we probably needed to backtrack or are waiting for more parts
13053          return;
13054        }
13055        var state = _this3.state;
13056        if (_this3.fragContextChanged(frag)) {
13057          if (state === State.FRAG_LOADING || !_this3.fragCurrent && state === State.PARSING) {
13058            _this3.fragmentTracker.removeFragment(frag);
13059            _this3.state = State.IDLE;
13060          }
13061          return;
13062        }
13063        if ('payload' in data) {
13064          _this3.log("Loaded " + frag.type + " sn: " + frag.sn + " of " + _this3.playlistLabel() + " " + frag.level);
13065          _this3.hls.trigger(Events.FRAG_LOADED, data);
13066        }
13067
13068        // Pass through the whole payload; controllers not implementing progressive loading receive data from this callback
13069        _this3._handleFragmentLoadComplete(data);
13070      }).catch(function (reason) {
13071        if (_this3.state === State.STOPPED || _this3.state === State.ERROR) {
13072          return;
13073        }
13074        _this3.warn("Frag error: " + ((reason == null ? void 0 : reason.message) || reason));
13075        _this3.resetFragmentLoading(frag);
13076      });
13077    };
13078    _proto.clearTrackerIfNeeded = function clearTrackerIfNeeded(frag) {
13079      var _this$mediaBuffer;
13080      var fragmentTracker = this.fragmentTracker;
13081      var fragState = fragmentTracker.getState(frag);
13082      if (fragState === FragmentState.APPENDING) {
13083        // Lower the max buffer length and try again
13084        var playlistType = frag.type;
13085        var bufferedInfo = this.getFwdBufferInfo(this.mediaBuffer, playlistType);
13086        var minForwardBufferLength = Math.max(frag.duration, bufferedInfo ? bufferedInfo.len : this.config.maxBufferLength);
13087        // If backtracking, always remove from the tracker without reducing max buffer length
13088        var backtrackFragment = this.backtrackFragment;
13089        var backtracked = backtrackFragment ? frag.sn - backtrackFragment.sn : 0;
13090        if (backtracked === 1 || this.reduceMaxBufferLength(minForwardBufferLength, frag.duration)) {
13091          fragmentTracker.removeFragment(frag);
13092        }
13093      } else if (((_this$mediaBuffer = this.mediaBuffer) == null ? void 0 : _this$mediaBuffer.buffered.length) === 0) {
13094        // Stop gap for bad tracker / buffer flush behavior
13095        fragmentTracker.removeAllFragments();
13096      } else if (fragmentTracker.hasParts(frag.type)) {
13097        // In low latency mode, remove fragments for which only some parts were buffered
13098        fragmentTracker.detectPartialFragments({
13099          frag: frag,
13100          part: null,
13101          stats: frag.stats,
13102          id: frag.type
13103        });
13104        if (fragmentTracker.getState(frag) === FragmentState.PARTIAL) {
13105          fragmentTracker.removeFragment(frag);
13106        }
13107      }
13108    };
13109    _proto.checkLiveUpdate = function checkLiveUpdate(details) {
13110      if (details.updated && !details.live) {
13111        // Live stream ended, update fragment tracker
13112        var lastFragment = details.fragments[details.fragments.length - 1];
13113        this.fragmentTracker.detectPartialFragments({
13114          frag: lastFragment,
13115          part: null,
13116          stats: lastFragment.stats,
13117          id: lastFragment.type
13118        });
13119      }
13120      if (!details.fragments[0]) {
13121        details.deltaUpdateFailed = true;
13122      }
13123    };
13124    _proto.flushMainBuffer = function flushMainBuffer(startOffset, endOffset, type) {
13125      if (type === void 0) {
13126        type = null;
13127      }
13128      if (!(startOffset - endOffset)) {
13129        return;
13130      }
13131      // When alternate audio is playing, the audio-stream-controller is responsible for the audio buffer. Otherwise,
13132      // passing a null type flushes both buffers
13133      var flushScope = {
13134        startOffset: startOffset,
13135        endOffset: endOffset,
13136        type: type
13137      };
13138      this.hls.trigger(Events.BUFFER_FLUSHING, flushScope);
13139    };
13140    _proto._loadInitSegment = function _loadInitSegment(frag, level) {
13141      var _this4 = this;
13142      this._doFragLoad(frag, level).then(function (data) {
13143        if (!data || _this4.fragContextChanged(frag) || !_this4.levels) {
13144          throw new Error('init load aborted');
13145        }
13146        return data;
13147      }).then(function (data) {
13148        var hls = _this4.hls;
13149        var payload = data.payload;
13150        var decryptData = frag.decryptdata;
13151
13152        // check to see if the payload needs to be decrypted
13153        if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
13154          var startTime = self.performance.now();
13155          // decrypt init segment data
13156          return _this4.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
13157            hls.trigger(Events.ERROR, {
13158              type: ErrorTypes.MEDIA_ERROR,
13159              details: ErrorDetails.FRAG_DECRYPT_ERROR,
13160              fatal: false,
13161              error: err,
13162              reason: err.message,
13163              frag: frag
13164            });
13165            throw err;
13166          }).then(function (decryptedData) {
13167            var endTime = self.performance.now();
13168            hls.trigger(Events.FRAG_DECRYPTED, {
13169              frag: frag,
13170              payload: decryptedData,
13171              stats: {
13172                tstart: startTime,
13173                tdecrypt: endTime
13174              }
13175            });
13176            data.payload = decryptedData;
13177            return _this4.completeInitSegmentLoad(data);
13178          });
13179        }
13180        return _this4.completeInitSegmentLoad(data);
13181      }).catch(function (reason) {
13182        if (_this4.state === State.STOPPED || _this4.state === State.ERROR) {
13183          return;
13184        }
13185        _this4.warn(reason);
13186        _this4.resetFragmentLoading(frag);
13187      });
13188    };
13189    _proto.completeInitSegmentLoad = function completeInitSegmentLoad(data) {
13190      var levels = this.levels;
13191      if (!levels) {
13192        throw new Error('init load aborted, missing levels');
13193      }
13194      var stats = data.frag.stats;
13195      if (this.state !== State.STOPPED) {
13196        this.state = State.IDLE;
13197      }
13198      data.frag.data = new Uint8Array(data.payload);
13199      stats.parsing.start = stats.buffering.start = self.performance.now();
13200      stats.parsing.end = stats.buffering.end = self.performance.now();
13201      this.tick();
13202    };
13203    _proto.fragContextChanged = function fragContextChanged(frag) {
13204      var fragCurrent = this.fragCurrent;
13205      return !frag || !fragCurrent || frag.sn !== fragCurrent.sn || frag.level !== fragCurrent.level;
13206    };
13207    _proto.fragBufferedComplete = function fragBufferedComplete(frag, part) {
13208      var _this$fragCurrent, _this$fragPrevious;
13209      var media = this.mediaBuffer ? this.mediaBuffer : this.media;
13210      this.log("Buffered " + frag.type + " sn: " + frag.sn + (part ? ' part: ' + part.index : '') + " of " + this.fragInfo(frag) + " > buffer:" + (media ? TimeRanges.toString(BufferHelper.getBuffered(media)) : '(detached)') + ")");
13211      if (frag.sn !== 'initSegment') {
13212        var _this$levels;
13213        if (frag.type !== PlaylistLevelType.SUBTITLE) {
13214          var el = frag.elementaryStreams;
13215          if (!Object.keys(el).some(function (type) {
13216            return !!el[type];
13217          })) {
13218            // empty segment
13219            this.state = State.IDLE;
13220            return;
13221          }
13222        }
13223        var level = (_this$levels = this.levels) == null ? void 0 : _this$levels[frag.level];
13224        if (level != null && level.fragmentError) {
13225          this.log("Resetting level fragment error count of " + level.fragmentError + " on frag buffered");
13226          level.fragmentError = 0;
13227        }
13228      }
13229      this.state = State.IDLE;
13230      if (!media) {
13231        return;
13232      }
13233      if (!this.loadedmetadata && frag.type == PlaylistLevelType.MAIN && media.buffered.length && ((_this$fragCurrent = this.fragCurrent) == null ? void 0 : _this$fragCurrent.sn) === ((_this$fragPrevious = this.fragPrevious) == null ? void 0 : _this$fragPrevious.sn)) {
13234        this.loadedmetadata = true;
13235        this.seekToStartPos();
13236      }
13237      this.tick();
13238    };
13239    _proto.seekToStartPos = function seekToStartPos() {};
13240    _proto._handleFragmentLoadComplete = function _handleFragmentLoadComplete(fragLoadedEndData) {
13241      var transmuxer = this.transmuxer;
13242      if (!transmuxer) {
13243        return;
13244      }
13245      var frag = fragLoadedEndData.frag,
13246        part = fragLoadedEndData.part,
13247        partsLoaded = fragLoadedEndData.partsLoaded;
13248      // If we did not load parts, or loaded all parts, we have complete (not partial) fragment data
13249      var complete = !partsLoaded || partsLoaded.length === 0 || partsLoaded.some(function (fragLoaded) {
13250        return !fragLoaded;
13251      });
13252      var chunkMeta = new ChunkMetadata(frag.level, frag.sn, frag.stats.chunkCount + 1, 0, part ? part.index : -1, !complete);
13253      transmuxer.flush(chunkMeta);
13254    }
13255
13256    // eslint-disable-next-line @typescript-eslint/no-unused-vars
13257    ;
13258    _proto._handleFragmentLoadProgress = function _handleFragmentLoadProgress(frag) {};
13259    _proto._doFragLoad = function _doFragLoad(frag, level, targetBufferTime, progressCallback) {
13260      var _frag$decryptdata,
13261        _this5 = this;
13262      if (targetBufferTime === void 0) {
13263        targetBufferTime = null;
13264      }
13265      this.fragCurrent = frag;
13266      var details = level == null ? void 0 : level.details;
13267      if (!this.levels || !details) {
13268        throw new Error("frag load aborted, missing level" + (details ? '' : ' detail') + "s");
13269      }
13270      var keyLoadingPromise = null;
13271      if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
13272        this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + this.playlistLabel() + " " + frag.level);
13273        this.state = State.KEY_LOADING;
13274        this.fragCurrent = frag;
13275        keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
13276          if (!_this5.fragContextChanged(keyLoadedData.frag)) {
13277            _this5.hls.trigger(Events.KEY_LOADED, keyLoadedData);
13278            if (_this5.state === State.KEY_LOADING) {
13279              _this5.state = State.IDLE;
13280            }
13281            return keyLoadedData;
13282          }
13283        });
13284        this.hls.trigger(Events.KEY_LOADING, {
13285          frag: frag
13286        });
13287        if (this.fragCurrent === null) {
13288          keyLoadingPromise = Promise.reject(new Error("frag load aborted, context changed in KEY_LOADING"));
13289        }
13290      } else if (!frag.encrypted && details.encryptedFragments.length) {
13291        this.keyLoader.loadClear(frag, details.encryptedFragments);
13292      }
13293      var fragPrevious = this.fragPrevious;
13294      if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
13295        var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
13296        if (shouldLoadParts !== this.loadingParts) {
13297          this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
13298          this.loadingParts = shouldLoadParts;
13299        }
13300      }
13301      targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
13302      if (this.loadingParts && frag.sn !== 'initSegment') {
13303        var partList = details.partList;
13304        if (partList && progressCallback) {
13305          if (targetBufferTime > frag.end && details.fragmentHint) {
13306            frag = details.fragmentHint;
13307          }
13308          var partIndex = this.getNextPart(partList, frag, targetBufferTime);
13309          if (partIndex > -1) {
13310            var part = partList[partIndex];
13311            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.playlistLabel() + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
13312            this.nextLoadPosition = part.start + part.duration;
13313            this.state = State.FRAG_LOADING;
13314            var _result;
13315            if (keyLoadingPromise) {
13316              _result = keyLoadingPromise.then(function (keyLoadedData) {
13317                if (!keyLoadedData || _this5.fragContextChanged(keyLoadedData.frag)) {
13318                  return null;
13319                }
13320                return _this5.doFragPartsLoad(frag, part, level, progressCallback);
13321              }).catch(function (error) {
13322                return _this5.handleFragLoadError(error);
13323              });
13324            } else {
13325              _result = this.doFragPartsLoad(frag, part, level, progressCallback).catch(function (error) {
13326                return _this5.handleFragLoadError(error);
13327              });
13328            }
13329            this.hls.trigger(Events.FRAG_LOADING, {
13330              frag: frag,
13331              part: part,
13332              targetBufferTime: targetBufferTime
13333            });
13334            if (this.fragCurrent === null) {
13335              return Promise.reject(new Error("frag load aborted, context changed in FRAG_LOADING parts"));
13336            }
13337            return _result;
13338          } else if (!frag.url || this.loadedEndOfParts(partList, targetBufferTime)) {
13339            // Fragment hint has no parts
13340            return Promise.resolve(null);
13341          }
13342        }
13343      }
13344      if (frag.sn !== 'initSegment' && this.loadingParts) {
13345        this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
13346        this.loadingParts = false;
13347      } else if (!frag.url) {
13348        // Selected fragment hint for part but not loading parts
13349        return Promise.resolve(null);
13350      }
13351      this.log("Loading " + frag.type + " sn: " + frag.sn + " of " + this.fragInfo(frag, false) + ") cc: " + frag.cc + " " + (details ? '[' + details.startSN + '-' + details.endSN + ']' : '') + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
13352      // Don't update nextLoadPosition for fragments which are not buffered
13353      if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
13354        this.nextLoadPosition = frag.start + frag.duration;
13355      }
13356      this.state = State.FRAG_LOADING;
13357
13358      // Load key before streaming fragment data
13359      var dataOnProgress = this.config.progressive;
13360      var result;
13361      if (dataOnProgress && keyLoadingPromise) {
13362        result = keyLoadingPromise.then(function (keyLoadedData) {
13363          if (!keyLoadedData || _this5.fragContextChanged(keyLoadedData == null ? void 0 : keyLoadedData.frag)) {
13364            return null;
13365          }
13366          return _this5.fragmentLoader.load(frag, progressCallback);
13367        }).catch(function (error) {
13368          return _this5.handleFragLoadError(error);
13369        });
13370      } else {
13371        // load unencrypted fragment data with progress event,
13372        // or handle fragment result after key and fragment are finished loading
13373        result = Promise.all([this.fragmentLoader.load(frag, dataOnProgress ? progressCallback : undefined), keyLoadingPromise]).then(function (_ref) {
13374          var fragLoadedData = _ref[0];
13375          if (!dataOnProgress && fragLoadedData && progressCallback) {
13376            progressCallback(fragLoadedData);
13377          }
13378          return fragLoadedData;
13379        }).catch(function (error) {
13380          return _this5.handleFragLoadError(error);
13381        });
13382      }
13383      this.hls.trigger(Events.FRAG_LOADING, {
13384        frag: frag,
13385        targetBufferTime: targetBufferTime
13386      });
13387      if (this.fragCurrent === null) {
13388        return Promise.reject(new Error("frag load aborted, context changed in FRAG_LOADING"));
13389      }
13390      return result;
13391    };
13392    _proto.doFragPartsLoad = function doFragPartsLoad(frag, fromPart, level, progressCallback) {
13393      var _this6 = this;
13394      return new Promise(function (resolve, reject) {
13395        var _level$details;
13396        var partsLoaded = [];
13397        var initialPartList = (_level$details = level.details) == null ? void 0 : _level$details.partList;
13398        var _loadPart = function loadPart(part) {
13399          _this6.fragmentLoader.loadPart(frag, part, progressCallback).then(function (partLoadedData) {
13400            partsLoaded[part.index] = partLoadedData;
13401            var loadedPart = partLoadedData.part;
13402            _this6.hls.trigger(Events.FRAG_LOADED, partLoadedData);
13403            var nextPart = getPartWith(level.details, frag.sn, part.index + 1) || findPart(initialPartList, frag.sn, part.index + 1);
13404            if (nextPart) {
13405              _loadPart(nextPart);
13406            } else {
13407              return resolve({
13408                frag: frag,
13409                part: loadedPart,
13410                partsLoaded: partsLoaded
13411              });
13412            }
13413          }).catch(reject);
13414        };
13415        _loadPart(fromPart);
13416      });
13417    };
13418    _proto.handleFragLoadError = function handleFragLoadError(error) {
13419      if ('data' in error) {
13420        var data = error.data;
13421        if (error.data && data.details === ErrorDetails.INTERNAL_ABORTED) {
13422          this.handleFragLoadAborted(data.frag, data.part);
13423        } else {
13424          this.hls.trigger(Events.ERROR, data);
13425        }
13426      } else {
13427        this.hls.trigger(Events.ERROR, {
13428          type: ErrorTypes.OTHER_ERROR,
13429          details: ErrorDetails.INTERNAL_EXCEPTION,
13430          err: error,
13431          error: error,
13432          fatal: true
13433        });
13434      }
13435      return null;
13436    };
13437    _proto._handleTransmuxerFlush = function _handleTransmuxerFlush(chunkMeta) {
13438      var context = this.getCurrentContext(chunkMeta);
13439      if (!context || this.state !== State.PARSING) {
13440        if (!this.fragCurrent && this.state !== State.STOPPED && this.state !== State.ERROR) {
13441          this.state = State.IDLE;
13442        }
13443        return;
13444      }
13445      var frag = context.frag,
13446        part = context.part,
13447        level = context.level;
13448      var now = self.performance.now();
13449      frag.stats.parsing.end = now;
13450      if (part) {
13451        part.stats.parsing.end = now;
13452      }
13453      // See if part loading should be disabled/enabled based on buffer and playback position.
13454      var levelDetails = this.getLevelDetails();
13455      var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
13456      var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
13457      if (shouldLoadParts !== this.loadingParts) {
13458        this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
13459        this.loadingParts = shouldLoadParts;
13460      }
13461      this.updateLevelTiming(frag, part, level, chunkMeta.partial);
13462    };
13463    _proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
13464      if (this.config.lowLatencyMode) {
13465        if (!details) {
13466          return this.loadingParts;
13467        }
13468        if (details != null && details.partList) {
13469          var _details$fragmentHint;
13470          // Buffer must be ahead of first part + duration of parts after last segment
13471          // and playback must be at or past segment adjacent to part list
13472          var firstPart = details.partList[0];
13473          var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
13474          if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
13475            return true;
13476          }
13477        }
13478      }
13479      return false;
13480    };
13481    _proto.getCurrentContext = function getCurrentContext(chunkMeta) {
13482      var levels = this.levels,
13483        fragCurrent = this.fragCurrent;
13484      var levelIndex = chunkMeta.level,
13485        sn = chunkMeta.sn,
13486        partIndex = chunkMeta.part;
13487      if (!(levels != null && levels[levelIndex])) {
13488        this.warn("Levels object was unset while buffering fragment " + sn + " of level " + levelIndex + ". The current chunk will not be buffered.");
13489        return null;
13490      }
13491      var level = levels[levelIndex];
13492      var levelDetails = level.details;
13493      var part = partIndex > -1 ? getPartWith(levelDetails, sn, partIndex) : null;
13494      var frag = part ? part.fragment : getFragmentWithSN(levelDetails, sn, fragCurrent);
13495      if (!frag) {
13496        return null;
13497      }
13498      if (fragCurrent && fragCurrent !== frag) {
13499        frag.stats = fragCurrent.stats;
13500      }
13501      return {
13502        frag: frag,
13503        part: part,
13504        level: level
13505      };
13506    };
13507    _proto.bufferFragmentData = function bufferFragmentData(data, frag, part, chunkMeta, noBacktracking) {
13508      var _buffer;
13509      if (!data || this.state !== State.PARSING) {
13510        return;
13511      }
13512      var data1 = data.data1,
13513        data2 = data.data2;
13514      var buffer = data1;
13515      if (data1 && data2) {
13516        // Combine the moof + mdat so that we buffer with a single append
13517        buffer = appendUint8Array(data1, data2);
13518      }
13519      if (!((_buffer = buffer) != null && _buffer.length)) {
13520        return;
13521      }
13522      var segment = {
13523        type: data.type,
13524        frag: frag,
13525        part: part,
13526        chunkMeta: chunkMeta,
13527        parent: frag.type,
13528        data: buffer
13529      };
13530      this.hls.trigger(Events.BUFFER_APPENDING, segment);
13531      if (data.dropped && data.independent && !part) {
13532        if (noBacktracking) {
13533          return;
13534        }
13535        // Clear buffer so that we reload previous segments sequentially if required
13536        this.flushBufferGap(frag);
13537      }
13538    };
13539    _proto.flushBufferGap = function flushBufferGap(frag) {
13540      var media = this.media;
13541      if (!media) {
13542        return;
13543      }
13544      // If currentTime is not buffered, clear the back buffer so that we can backtrack as much as needed
13545      if (!BufferHelper.isBuffered(media, media.currentTime)) {
13546        this.flushMainBuffer(0, frag.start);
13547        return;
13548      }
13549      // Remove back-buffer without interrupting playback to allow back tracking
13550      var currentTime = media.currentTime;
13551      var bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
13552      var fragDuration = frag.duration;
13553      var segmentFraction = Math.min(this.config.maxFragLookUpTolerance * 2, fragDuration * 0.25);
13554      var start = Math.max(Math.min(frag.start - segmentFraction, bufferInfo.end - segmentFraction), currentTime + segmentFraction);
13555      if (frag.start - start > segmentFraction) {
13556        this.flushMainBuffer(start, frag.start);
13557      }
13558    };
13559    _proto.getFwdBufferInfo = function getFwdBufferInfo(bufferable, type) {
13560      var _this$media;
13561      var pos = this.getLoadPosition();
13562      if (!isFiniteNumber(pos)) {
13563        return null;
13564      }
13565      var backwardSeek = this.lastCurrentTime > pos;
13566      var maxBufferHole = backwardSeek || (_this$media = this.media) != null && _this$media.paused ? 0 : this.config.maxBufferHole;
13567      return this.getFwdBufferInfoAtPos(bufferable, pos, type, maxBufferHole);
13568    };
13569    _proto.getFwdBufferInfoAtPos = function getFwdBufferInfoAtPos(bufferable, pos, type, maxBufferHole) {
13570      var bufferInfo = BufferHelper.bufferInfo(bufferable, pos, maxBufferHole);
13571      // Workaround flaw in getting forward buffer when maxBufferHole is smaller than gap at current pos
13572      if (bufferInfo.len === 0 && bufferInfo.nextStart !== undefined) {
13573        var bufferedFragAtPos = this.fragmentTracker.getBufferedFrag(pos, type);
13574        if (bufferedFragAtPos && (bufferInfo.nextStart <= bufferedFragAtPos.end || bufferedFragAtPos.gap)) {
13575          return BufferHelper.bufferInfo(bufferable, pos, Math.max(bufferInfo.nextStart, maxBufferHole));
13576        }
13577      }
13578      return bufferInfo;
13579    };
13580    _proto.getMaxBufferLength = function getMaxBufferLength(levelBitrate) {
13581      var config = this.config;
13582      var maxBufLen;
13583      if (levelBitrate) {
13584        maxBufLen = Math.max(8 * config.maxBufferSize / levelBitrate, config.maxBufferLength);
13585      } else {
13586        maxBufLen = config.maxBufferLength;
13587      }
13588      return Math.min(maxBufLen, config.maxMaxBufferLength);
13589    };
13590    _proto.reduceMaxBufferLength = function reduceMaxBufferLength(threshold, fragDuration) {
13591      var config = this.config;
13592      var minLength = Math.max(Math.min(threshold - fragDuration, config.maxBufferLength), fragDuration);
13593      var reducedLength = Math.max(threshold - fragDuration * 3, config.maxMaxBufferLength / 2, minLength);
13594      if (reducedLength >= minLength) {
13595        // reduce max buffer length as it might be too high. we do this to avoid loop flushing ...
13596        config.maxMaxBufferLength = reducedLength;
13597        this.warn("Reduce max buffer length to " + reducedLength + "s");
13598        return true;
13599      }
13600      return false;
13601    };
13602    _proto.getAppendedFrag = function getAppendedFrag(position, playlistType) {
13603      var _this$fragmentTracker;
13604      if (playlistType === void 0) {
13605        playlistType = PlaylistLevelType.MAIN;
13606      }
13607      var fragOrPart = (_this$fragmentTracker = this.fragmentTracker) == null ? void 0 : _this$fragmentTracker.getAppendedFrag(position, playlistType);
13608      if (fragOrPart && 'fragment' in fragOrPart) {
13609        return fragOrPart.fragment;
13610      }
13611      return fragOrPart;
13612    };
13613    _proto.getNextFragment = function getNextFragment(pos, levelDetails) {
13614      var fragments = levelDetails.fragments;
13615      var fragLen = fragments.length;
13616      if (!fragLen) {
13617        return null;
13618      }
13619
13620      // find fragment index, contiguous with end of buffer position
13621      var config = this.config;
13622      var start = fragments[0].start;
13623      var canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
13624      var frag = null;
13625      if (levelDetails.live) {
13626        var initialLiveManifestSize = config.initialLiveManifestSize;
13627        if (fragLen < initialLiveManifestSize) {
13628          this.warn("Not enough fragments to start playback (have: " + fragLen + ", need: " + initialLiveManifestSize + ")");
13629          return null;
13630        }
13631        // The real fragment start times for a live stream are only known after the PTS range for that level is known.
13632        // In order to discover the range, we load the best matching fragment for that level and demux it.
13633        // Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
13634        // we get the fragment matching that start time
13635        if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
13636          if (canLoadParts && !this.loadingParts) {
13637            this.log("LL-Part loading ON for initial live fragment");
13638            this.loadingParts = true;
13639          }
13640          frag = this.getInitialLiveFragment(levelDetails, fragments);
13641          this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
13642        }
13643      } else if (pos <= start) {
13644        // VoD playlist: if loadPosition before start of playlist, load first fragment
13645        frag = fragments[0];
13646      }
13647
13648      // If we haven't run into any special cases already, just load the fragment most closely matching the requested position
13649      if (!frag) {
13650        var end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
13651        frag = this.getFragmentAtPosition(pos, end, levelDetails);
13652      }
13653      return this.mapToInitFragWhenRequired(frag);
13654    };
13655    _proto.isLoopLoading = function isLoopLoading(frag, targetBufferTime) {
13656      var trackerState = this.fragmentTracker.getState(frag);
13657      return (trackerState === FragmentState.OK || trackerState === FragmentState.PARTIAL && !!frag.gap) && this.nextLoadPosition > targetBufferTime;
13658    };
13659    _proto.getNextFragmentLoopLoading = function getNextFragmentLoopLoading(frag, levelDetails, bufferInfo, playlistType, maxBufLen) {
13660      var nextFragment = null;
13661      if (frag.gap) {
13662        nextFragment = this.getNextFragment(this.nextLoadPosition, levelDetails);
13663        if (nextFragment && !nextFragment.gap && bufferInfo.nextStart) {
13664          // Media buffered after GAP tags should not make the next buffer timerange exceed forward buffer length
13665          var nextbufferInfo = this.getFwdBufferInfoAtPos(this.mediaBuffer ? this.mediaBuffer : this.media, bufferInfo.nextStart, playlistType, 0);
13666          if (nextbufferInfo !== null && bufferInfo.len + nextbufferInfo.len >= maxBufLen) {
13667            // Returning here might result in not finding an audio and video candiate to skip to
13668            var sn = nextFragment.sn;
13669            if (this.loopSn !== sn) {
13670              this.log("buffer full after gaps in \"" + playlistType + "\" playlist starting at sn: " + sn);
13671              this.loopSn = sn;
13672            }
13673            return null;
13674          }
13675        }
13676      }
13677      this.loopSn = undefined;
13678      return nextFragment;
13679    };
13680    _proto.mapToInitFragWhenRequired = function mapToInitFragWhenRequired(frag) {
13681      // If an initSegment is present, it must be buffered first
13682      if (frag != null && frag.initSegment && !(frag != null && frag.initSegment.data) && !this.bitrateTest) {
13683        return frag.initSegment;
13684      }
13685      return frag;
13686    };
13687    _proto.getNextPart = function getNextPart(partList, frag, targetBufferTime) {
13688      var nextPart = -1;
13689      var contiguous = false;
13690      var independentAttrOmitted = true;
13691      for (var i = 0, len = partList.length; i < len; i++) {
13692        var part = partList[i];
13693        independentAttrOmitted = independentAttrOmitted && !part.independent;
13694        if (nextPart > -1 && targetBufferTime < part.start) {
13695          break;
13696        }
13697        var loaded = part.loaded;
13698        if (loaded) {
13699          nextPart = -1;
13700        } else if ((contiguous || part.independent || independentAttrOmitted) && part.fragment === frag) {
13701          nextPart = i;
13702        }
13703        contiguous = loaded;
13704      }
13705      return nextPart;
13706    };
13707    _proto.loadedEndOfParts = function loadedEndOfParts(partList, targetBufferTime) {
13708      var lastPart = partList[partList.length - 1];
13709      return lastPart && targetBufferTime > lastPart.start && lastPart.loaded;
13710    }
13711
13712    /*
13713     This method is used find the best matching first fragment for a live playlist. This fragment is used to calculate the
13714     "sliding" of the playlist, which is its offset from the start of playback. After sliding we can compute the real
13715     start and end times for each fragment in the playlist (after which this method will not need to be called).
13716    */;
13717    _proto.getInitialLiveFragment = function getInitialLiveFragment(levelDetails, fragments) {
13718      var fragPrevious = this.fragPrevious;
13719      var frag = null;
13720      if (fragPrevious) {
13721        if (levelDetails.hasProgramDateTime) {
13722          // Prefer using PDT, because it can be accurate enough to choose the correct fragment without knowing the level sliding
13723          this.log("Live playlist, switching playlist, load frag with same PDT: " + fragPrevious.programDateTime);
13724          frag = findFragmentByPDT(fragments, fragPrevious.endProgramDateTime, this.config.maxFragLookUpTolerance);
13725        }
13726        if (!frag) {
13727          // SN does not need to be accurate between renditions, but depending on the packaging it may be so.
13728          var targetSN = fragPrevious.sn + 1;
13729          if (targetSN >= levelDetails.startSN && targetSN <= levelDetails.endSN) {
13730            var fragNext = fragments[targetSN - levelDetails.startSN];
13731            // Ensure that we're staying within the continuity range, since PTS resets upon a new range
13732            if (fragPrevious.cc === fragNext.cc) {
13733              frag = fragNext;
13734              this.log("Live playlist, switching playlist, load frag with next SN: " + frag.sn);
13735            }
13736          }
13737          // It's important to stay within the continuity range if available; otherwise the fragments in the playlist
13738          // will have the wrong start times
13739          if (!frag) {
13740            frag = findFragWithCC(fragments, fragPrevious.cc);
13741            if (frag) {
13742              this.log("Live playlist, switching playlist, load frag with same CC: " + frag.sn);
13743            }
13744          }
13745        }
13746      } else {
13747        // Find a new start fragment when fragPrevious is null
13748        var liveStart = this.hls.liveSyncPosition;
13749        if (liveStart !== null) {
13750          frag = this.getFragmentAtPosition(liveStart, this.bitrateTest ? levelDetails.fragmentEnd : levelDetails.edge, levelDetails);
13751        }
13752      }
13753      return frag;
13754    }
13755
13756    /*
13757    This method finds the best matching fragment given the provided position.
13758     */;
13759    _proto.getFragmentAtPosition = function getFragmentAtPosition(bufferEnd, end, levelDetails) {
13760      var config = this.config;
13761      var fragPrevious = this.fragPrevious;
13762      var fragments = levelDetails.fragments,
13763        endSN = levelDetails.endSN;
13764      var fragmentHint = levelDetails.fragmentHint;
13765      var maxFragLookUpTolerance = config.maxFragLookUpTolerance;
13766      var partList = levelDetails.partList;
13767      var loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
13768      if (loadingParts && fragmentHint && !this.bitrateTest) {
13769        // Include incomplete fragment with parts at end
13770        fragments = fragments.concat(fragmentHint);
13771        endSN = fragmentHint.sn;
13772      }
13773      var frag;
13774      if (bufferEnd < end) {
13775        var _this$media2;
13776        var backwardSeek = bufferEnd < this.lastCurrentTime;
13777        var lookupTolerance = backwardSeek || bufferEnd > end - maxFragLookUpTolerance || (_this$media2 = this.media) != null && _this$media2.paused ? 0 : maxFragLookUpTolerance;
13778        // Remove the tolerance if it would put the bufferEnd past the actual end of stream
13779        // Uses buffer and sequence number to calculate switch segment (required if using EXT-X-DISCONTINUITY-SEQUENCE)
13780        frag = findFragmentByPTS(fragPrevious, fragments, bufferEnd, lookupTolerance);
13781      } else {
13782        // reach end of playlist
13783        frag = fragments[fragments.length - 1];
13784      }
13785      if (frag) {
13786        var curSNIdx = frag.sn - levelDetails.startSN;
13787        // Move fragPrevious forward to support forcing the next fragment to load
13788        // when the buffer catches up to a previously buffered range.
13789        var fragState = this.fragmentTracker.getState(frag);
13790        if (fragState === FragmentState.OK || fragState === FragmentState.PARTIAL && frag.gap) {
13791          fragPrevious = frag;
13792        }
13793        if (fragPrevious && frag.sn === fragPrevious.sn && (!loadingParts || partList[0].fragment.sn > frag.sn)) {
13794          // Force the next fragment to load if the previous one was already selected. This can occasionally happen with
13795          // non-uniform fragment durations
13796          var sameLevel = fragPrevious && frag.level === fragPrevious.level;
13797          if (sameLevel) {
13798            var nextFrag = fragments[curSNIdx + 1];
13799            if (frag.sn < endSN && this.fragmentTracker.getState(nextFrag) !== FragmentState.OK) {
13800              frag = nextFrag;
13801            } else {
13802              frag = null;
13803            }
13804          }
13805        }
13806      }
13807      return frag;
13808    };
13809    _proto.synchronizeToLiveEdge = function synchronizeToLiveEdge(levelDetails) {
13810      var config = this.config,
13811        media = this.media;
13812      if (!media) {
13813        return;
13814      }
13815      var liveSyncPosition = this.hls.liveSyncPosition;
13816      var currentTime = media.currentTime;
13817      var start = levelDetails.fragments[0].start;
13818      var end = levelDetails.edge;
13819      var withinSlidingWindow = currentTime >= start - config.maxFragLookUpTolerance && currentTime <= end;
13820      // Continue if we can seek forward to sync position or if current time is outside of sliding window
13821      if (liveSyncPosition !== null && media.duration > liveSyncPosition && (currentTime < liveSyncPosition || !withinSlidingWindow)) {
13822        // Continue if buffer is starving or if current time is behind max latency
13823        var maxLatency = config.liveMaxLatencyDuration !== undefined ? config.liveMaxLatencyDuration : config.liveMaxLatencyDurationCount * levelDetails.targetduration;
13824        if (!withinSlidingWindow && media.readyState < 4 || currentTime < end - maxLatency) {
13825          if (!this.loadedmetadata) {
13826            this.nextLoadPosition = liveSyncPosition;
13827          }
13828          // Only seek if ready and there is not a significant forward buffer available for playback
13829          if (media.readyState) {
13830            this.warn("Playback: " + currentTime.toFixed(3) + " is located too far from the end of live sliding playlist: " + end + ", reset currentTime to : " + liveSyncPosition.toFixed(3));
13831            media.currentTime = liveSyncPosition;
13832          }
13833        }
13834      }
13835    };
13836    _proto.alignPlaylists = function alignPlaylists(details, previousDetails, switchDetails) {
13837      // FIXME: If not for `shouldAlignOnDiscontinuities` requiring fragPrevious.cc,
13838      //  this could all go in level-helper mergeDetails()
13839      var length = details.fragments.length;
13840      if (!length) {
13841        this.warn("No fragments in live playlist");
13842        return 0;
13843      }
13844      var slidingStart = details.fragments[0].start;
13845      var firstLevelLoad = !previousDetails;
13846      var aligned = details.alignedSliding && isFiniteNumber(slidingStart);
13847      if (firstLevelLoad || !aligned && !slidingStart) {
13848        var fragPrevious = this.fragPrevious;
13849        alignStream(fragPrevious, switchDetails, details);
13850        var alignedSlidingStart = details.fragments[0].start;
13851        this.log("Live playlist sliding: " + alignedSlidingStart.toFixed(2) + " start-sn: " + (previousDetails ? previousDetails.startSN : 'na') + "->" + details.startSN + " prev-sn: " + (fragPrevious ? fragPrevious.sn : 'na') + " fragments: " + length);
13852        return alignedSlidingStart;
13853      }
13854      return slidingStart;
13855    };
13856    _proto.waitForCdnTuneIn = function waitForCdnTuneIn(details) {
13857      // Wait for Low-Latency CDN Tune-in to get an updated playlist
13858      var advancePartLimit = 3;
13859      return details.live && details.canBlockReload && details.partTarget && details.tuneInGoal > Math.max(details.partHoldBack, details.partTarget * advancePartLimit);
13860    };
13861    _proto.setStartPosition = function setStartPosition(details, sliding) {
13862      // compute start position if set to -1. use it straight away if value is defined
13863      var startPosition = this.startPosition;
13864      if (startPosition < sliding) {
13865        startPosition = -1;
13866      }
13867      if (startPosition === -1 || this.lastCurrentTime === -1) {
13868        // Use Playlist EXT-X-START:TIME-OFFSET when set
13869        // Prioritize Multivariant Playlist offset so that main, audio, and subtitle stream-controller start times match
13870        var offsetInMultivariantPlaylist = this.startTimeOffset !== null;
13871        var startTimeOffset = offsetInMultivariantPlaylist ? this.startTimeOffset : details.startTimeOffset;
13872        if (startTimeOffset !== null && isFiniteNumber(startTimeOffset)) {
13873          startPosition = sliding + startTimeOffset;
13874          if (startTimeOffset < 0) {
13875            startPosition += details.edge;
13876          }
13877          startPosition = Math.min(Math.max(sliding, startPosition), sliding + details.totalduration);
13878          this.log("Start time offset " + startTimeOffset + " found in " + (offsetInMultivariantPlaylist ? 'multivariant' : 'media') + " playlist, adjust startPosition to " + startPosition);
13879          this.startPosition = startPosition;
13880        } else if (details.live) {
13881          // Leave this.startPosition at -1, so that we can use `getInitialLiveFragment` logic when startPosition has
13882          // not been specified via the config or an as an argument to startLoad (#3736).
13883          startPosition = this.hls.liveSyncPosition || sliding;
13884        } else {
13885          this.startPosition = startPosition = 0;
13886        }
13887        this.lastCurrentTime = startPosition;
13888      }
13889      this.nextLoadPosition = startPosition;
13890    };
13891    _proto.getLoadPosition = function getLoadPosition() {
13892      var media = this.media;
13893      // if we have not yet loaded any fragment, start loading from start position
13894      var pos = 0;
13895      if (this.loadedmetadata && media) {
13896        pos = media.currentTime;
13897      } else if (this.nextLoadPosition) {
13898        pos = this.nextLoadPosition;
13899      }
13900      return pos;
13901    };
13902    _proto.handleFragLoadAborted = function handleFragLoadAborted(frag, part) {
13903      if (this.transmuxer && frag.sn !== 'initSegment' && frag.stats.aborted) {
13904        this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " was aborted");
13905        this.resetFragmentLoading(frag);
13906      }
13907    };
13908    _proto.resetFragmentLoading = function resetFragmentLoading(frag) {
13909      if (!this.fragCurrent || !this.fragContextChanged(frag) && this.state !== State.FRAG_LOADING_WAITING_RETRY) {
13910        this.state = State.IDLE;
13911      }
13912    };
13913    _proto.onFragmentOrKeyLoadError = function onFragmentOrKeyLoadError(filterType, data) {
13914      if (data.chunkMeta && !data.frag) {
13915        var context = this.getCurrentContext(data.chunkMeta);
13916        if (context) {
13917          data.frag = context.frag;
13918        }
13919      }
13920      var frag = data.frag;
13921      // Handle frag error related to caller's filterType
13922      if (!frag || frag.type !== filterType || !this.levels) {
13923        return;
13924      }
13925      if (this.fragContextChanged(frag)) {
13926        var _this$fragCurrent2;
13927        this.warn("Frag load error must match current frag to retry " + frag.url + " > " + ((_this$fragCurrent2 = this.fragCurrent) == null ? void 0 : _this$fragCurrent2.url));
13928        return;
13929      }
13930      var gapTagEncountered = data.details === ErrorDetails.FRAG_GAP;
13931      if (gapTagEncountered) {
13932        this.fragmentTracker.fragBuffered(frag, true);
13933      }
13934      // keep retrying until the limit will be reached
13935      var errorAction = data.errorAction;
13936      var _ref2 = errorAction || {},
13937        action = _ref2.action,
13938        _ref2$retryCount = _ref2.retryCount,
13939        retryCount = _ref2$retryCount === void 0 ? 0 : _ref2$retryCount,
13940        retryConfig = _ref2.retryConfig;
13941      if (errorAction && action === NetworkErrorAction.RetryRequest && retryConfig) {
13942        this.resetStartWhenNotLoaded(this.levelLastLoaded);
vendor: 4,357 bytes, lines 13943-14033
13943        var delay = getRetryDelay(retryConfig, retryCount);
13944        this.warn("Fragment " + frag.sn + " of " + filterType + " " + frag.level + " errored with " + data.details + ", retrying loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " in " + delay + "ms");
13945        errorAction.resolved = true;
13946        this.retryDate = self.performance.now() + delay;
13947        this.state = State.FRAG_LOADING_WAITING_RETRY;
13948      } else if (retryConfig && errorAction) {
13949        this.resetFragmentErrors(filterType);
13950        if (retryCount < retryConfig.maxNumRetry) {
13951          // Network retry is skipped when level switch is preferred
13952          if (!gapTagEncountered && action !== NetworkErrorAction.RemoveAlternatePermanently) {
13953            errorAction.resolved = true;
13954          }
13955        } else {
13956          this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13957          return;
13958        }
13959      } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
13960        this.state = State.WAITING_LEVEL;
13961      } else {
13962        this.state = State.ERROR;
13963      }
13964      // Perform next async tick sooner to speed up error action resolution
13965      this.tickImmediate();
13966    };
13967    _proto.reduceLengthAndFlushBuffer = function reduceLengthAndFlushBuffer(data) {
13968      // if in appending state
13969      if (this.state === State.PARSING || this.state === State.PARSED) {
13970        var frag = data.frag;
13971        var playlistType = data.parent;
13972        var bufferedInfo = this.getFwdBufferInfo(this.mediaBuffer, playlistType);
13973        // 0.5 : tolerance needed as some browsers stalls playback before reaching buffered end
13974        // reduce max buf len if current position is buffered
13975        var buffered = bufferedInfo && bufferedInfo.len > 0.5;
13976        if (buffered) {
13977          this.reduceMaxBufferLength(bufferedInfo.len, (frag == null ? void 0 : frag.duration) || 10);
13978        }
13979        var flushBuffer = !buffered;
13980        if (flushBuffer) {
13981          // current position is not buffered, but browser is still complaining about buffer full error
13982          // this happens on IE/Edge, refer to https://github.com/video-dev/hls.js/pull/708
13983          // in that case flush the whole audio buffer to recover
13984          this.warn("Buffer full error while media.currentTime is not buffered, flush " + playlistType + " buffer");
13985        }
13986        if (frag) {
13987          this.fragmentTracker.removeFragment(frag);
13988          this.nextLoadPosition = frag.start;
13989        }
13990        this.resetLoadingState();
13991        return flushBuffer;
13992      }
13993      return false;
13994    };
13995    _proto.resetFragmentErrors = function resetFragmentErrors(filterType) {
13996      if (filterType === PlaylistLevelType.AUDIO) {
13997        // Reset current fragment since audio track audio is essential and may not have a fail-over track
13998        this.fragCurrent = null;
13999      }
14000      // Fragment errors that result in a level switch or redundant fail-over
14001      // should reset the stream controller state to idle
14002      if (!this.loadedmetadata) {
14003        this.startFragRequested = false;
14004      }
14005      if (this.state !== State.STOPPED) {
14006        this.state = State.IDLE;
14007      }
14008    };
14009    _proto.afterBufferFlushed = function afterBufferFlushed(media, bufferType, playlistType) {
14010      if (!media) {
14011        return;
14012      }
14013      // After successful buffer flushing, filter flushed fragments from bufferedFrags use mediaBuffered instead of media
14014      // (so that we will check against video.buffered ranges in case of alt audio track)
14015      var bufferedTimeRanges = BufferHelper.getBuffered(media);
14016      this.fragmentTracker.detectEvictedFragments(bufferType, bufferedTimeRanges, playlistType);
14017      if (this.state === State.ENDED) {
14018        this.resetLoadingState();
14019      }
14020    };
14021    _proto.resetLoadingState = function resetLoadingState() {
14022      this.log('Reset loading state');
14023      this.fragCurrent = null;
14024      this.fragPrevious = null;
14025      if (this.state !== State.STOPPED) {
14026        this.state = State.IDLE;
14027      }
14028    };
14029    _proto.resetStartWhenNotLoaded = function resetStartWhenNotLoaded(level) {
14030      // if loadedmetadata is not set, it means that first frag request failed
14031      // in that case, reset startFragRequested flag
14032      if (!this.loadedmetadata) {
14033        this.startFragRequested = false;
14034        var details = level ? level.details : null;
14035        if (details != null && details.live) {
14036          // Update the start position and return to IDLE to recover live start
14037          this.startPosition = -1;
14038          this.setStartPosition(details, 0);
14039          this.resetLoadingState();
14040        } else {
14041          this.nextLoadPosition = this.startPosition;
14042        }
14043      }
14044    };
14045    _proto.resetWhenMissingContext = function resetWhenMissingContext(chunkMeta) {
14046      this.warn("The loading context changed while buffering fragment " + chunkMeta.sn + " of level " + chunkMeta.level + ". This chunk will not be buffered.");
14047      this.removeUnbufferedFrags();
14048      this.resetStartWhenNotLoaded(this.levelLastLoaded);
14049      this.resetLoadingState();
14050    };
14051    _proto.removeUnbufferedFrags = function removeUnbufferedFrags(start) {
14052      if (start === void 0) {
14053        start = 0;
14054      }
14055      this.fragmentTracker.removeFragmentsInRange(start, Infinity, this.playlistType, false, true);
14056    };
14057    _proto.updateLevelTiming = function updateLevelTiming(frag, part, level, partial) {
14058      var _this7 = this,
14059        _this$transmuxer;
14060      var details = level.details;
14061      if (!details) {
14062        this.warn('level.details undefined');
14063        return;
14064      }
14065      var parsed = Object.keys(frag.elementaryStreams).reduce(function (result, type) {
14066        var info = frag.elementaryStreams[type];
14067        if (info) {
14068          var parsedDuration = info.endPTS - info.startPTS;
14069          if (parsedDuration <= 0) {
14070            // Destroy the transmuxer after it's next time offset failed to advance because duration was <= 0.
14071            // The new transmuxer will be configured with a time offset matching the next fragment start,
14072            // preventing the timeline from shifting.
14073            _this7.warn("Could not parse fragment " + frag.sn + " " + type + " duration reliably (" + parsedDuration + ")");
14074            return result || false;
14075          }
14076          var drift = partial ? 0 : updateFragPTSDTS(details, frag, info.startPTS, info.endPTS, info.startDTS, info.endDTS);
14077          _this7.hls.trigger(Events.LEVEL_PTS_UPDATED, {
14078            details: details,
14079            level: level,
14080            drift: drift,
14081            type: type,
14082            frag: frag,
14083            start: info.startPTS,
14084            end: info.endPTS
14085          });
14086          return true;
14087        }
14088        return result;
14089      }, false);
14090      if (!parsed && ((_this$transmuxer = this.transmuxer) == null ? void 0 : _this$transmuxer.error) === null) {
14091        var error = new Error("Found no media in fragment " + frag.sn + " of level " + frag.level + " resetting transmuxer to fallback to playlist timing");
14092        if (level.fragmentError === 0) {
14093          // Mark and track the odd empty segment as a gap to avoid reloading
14094          level.fragmentError++;
14095          frag.gap = true;
14096          this.fragmentTracker.removeFragment(frag);
14097          this.fragmentTracker.fragBuffered(frag, true);
14098        }
14099        this.warn(error.message);
14100        this.hls.trigger(Events.ERROR, {
14101          type: ErrorTypes.MEDIA_ERROR,
14102          details: ErrorDetails.FRAG_PARSING_ERROR,
14103          fatal: false,
14104          error: error,
14105          frag: frag,
14106          reason: "Found no media in msn " + frag.sn + " of level \"" + level.url + "\""
14107        });
14108        if (!this.hls) {
14109          return;
14110        }
14111        this.resetTransmuxer();
14112        // For this error fallthrough. Marking parsed will allow advancing to next fragment.
14113      }
14114      this.state = State.PARSED;
14115      this.log("Parsed " + frag.type + " sn: " + frag.sn + (part ? ' part: ' + part.index : '') + " of " + this.fragInfo(frag) + ")");
14116      this.hls.trigger(Events.FRAG_PARSED, {
14117        frag: frag,
14118        part: part
14119      });
14120    };
14121    _proto.playlistLabel = function playlistLabel() {
14122      return this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track';
14123    };
14124    _proto.fragInfo = function fragInfo(frag, pts) {
14125      var _ref3, _ref4;
14126      if (pts === void 0) {
14127        pts = true;
14128      }
14129      return this.playlistLabel() + " " + frag.level + " (frag:[" + ((_ref3 = pts ? frag.startPTS : frag.start) != null ? _ref3 : NaN).toFixed(3) + "-" + ((_ref4 = pts ? frag.endPTS : frag.end) != null ? _ref4 : NaN).toFixed(3) + "]";
14130    };
14131    _proto.resetTransmuxer = function resetTransmuxer() {
14132      var _this$transmuxer2;
14133      (_this$transmuxer2 = this.transmuxer) == null ? void 0 : _this$transmuxer2.reset();
14134    };
14135    _proto.recoverWorkerError = function recoverWorkerError(data) {
14136      if (data.event === 'demuxerWorker') {
14137        this.fragmentTracker.removeAllFragments();
14138        if (this.transmuxer) {
14139          this.transmuxer.destroy();
14140          this.transmuxer = null;
14141        }
14142        this.resetStartWhenNotLoaded(this.levelLastLoaded);
14143        this.resetLoadingState();
14144      }
14145    };
14146    return _createClass(BaseStreamController, [{
14147      key: "state",
14148      get: function get() {
14149        return this._state;
14150      },
14151      set: function set(nextState) {
14152        var previousState = this._state;
14153        if (previousState !== nextState) {
14154          this._state = nextState;
14155          this.log(previousState + "->" + nextState);
14156        }
14157      }
14158    }]);
14159  }(TaskLoop);
14160
14161  function getSourceBuffer() {
14162    return self.SourceBuffer || self.WebKitSourceBuffer;
14163  }
14164  function isMSESupported() {
14165    var mediaSource = getMediaSource();
14166    if (!mediaSource) {
14167      return false;
vendor: 5,113 bytes, lines 14168-14340
14168    }
14169
14170    // if SourceBuffer is exposed ensure its API is valid
14171    // Older browsers do not expose SourceBuffer globally so checking SourceBuffer.prototype is impossible
14172    var sourceBuffer = getSourceBuffer();
14173    return !sourceBuffer || sourceBuffer.prototype && typeof sourceBuffer.prototype.appendBuffer === 'function' && typeof sourceBuffer.prototype.remove === 'function';
14174  }
14175  function isSupported() {
14176    if (!isMSESupported()) {
14177      return false;
14178    }
14179    var mediaSource = getMediaSource();
14180    return typeof (mediaSource == null ? void 0 : mediaSource.isTypeSupported) === 'function' && (['avc1.42E01E,mp4a.40.2', 'av01.0.01M.08', 'vp09.00.50.08'].some(function (codecsForVideoContainer) {
14181      return mediaSource.isTypeSupported(mimeTypeForCodec(codecsForVideoContainer, 'video'));
14182    }) || ['mp4a.40.2', 'fLaC'].some(function (codecForAudioContainer) {
14183      return mediaSource.isTypeSupported(mimeTypeForCodec(codecForAudioContainer, 'audio'));
14184    }));
14185  }
14186  function changeTypeSupported() {
14187    var _sourceBuffer$prototy;
14188    var sourceBuffer = getSourceBuffer();
14189    return typeof (sourceBuffer == null ? void 0 : (_sourceBuffer$prototy = sourceBuffer.prototype) == null ? void 0 : _sourceBuffer$prototy.changeType) === 'function';
14190  }
14191
14192  function dummyTrack(type, inputTimeScale) {
14193    if (type === void 0) {
14194      type = '';
14195    }
14196    if (inputTimeScale === void 0) {
14197      inputTimeScale = 90000;
14198    }
14199    return {
14200      type: type,
14201      id: -1,
14202      pid: -1,
14203      inputTimeScale: inputTimeScale,
14204      sequenceNumber: -1,
14205      samples: [],
14206      dropped: 0
14207    };
14208  }
14209
14210  /**
14211   * Returns any adjacent ID3 tags found in data starting at offset, as one block of data
14212   *
14213   * @param data - The data to search in
14214   * @param offset - The offset at which to start searching
14215   *
14216   * @returns The block of data containing any ID3 tags found
14217   * or `undefined` if no header is found at the starting offset
14218   *
14219   * @internal
14220   *
14221   * @group ID3
14222   */
14223  function getId3Data(data, offset) {
14224    var front = offset;
14225    var length = 0;
14226    while (isId3Header(data, offset)) {
14227      // ID3 header is 10 bytes
14228      length += 10;
14229      var size = readId3Size(data, offset + 6);
14230      length += size;
14231      if (isId3Footer(data, offset + 10)) {
14232        // ID3 footer is 10 bytes
14233        length += 10;
14234      }
14235      offset += length;
14236    }
14237    if (length > 0) {
14238      return data.subarray(front, front + length);
14239    }
14240    return undefined;
14241  }
14242
14243  /**
14244   * Read a 33 bit timestamp from an ID3 frame.
14245   *
14246   * @param timeStampFrame - the ID3 frame
14247   *
14248   * @returns The timestamp
14249   *
14250   * @internal
14251   *
14252   * @group ID3
14253   */
14254  function readId3Timestamp(timeStampFrame) {
14255    if (timeStampFrame.data.byteLength === 8) {
14256      var data = new Uint8Array(timeStampFrame.data);
14257      // timestamp is 33 bit expressed as a big-endian eight-octet number,
14258      // with the upper 31 bits set to zero.
14259      var pts33Bit = data[3] & 0x1;
14260      var timestamp = (data[4] << 23) + (data[5] << 15) + (data[6] << 7) + data[7];
14261      timestamp /= 45;
14262      if (pts33Bit) {
14263        timestamp += 47721858.84;
14264      } // 2^32 / 90
14265      return Math.round(timestamp);
14266    }
14267    return undefined;
14268  }
14269
14270  /**
14271   * Searches for the Elementary Stream timestamp found in the ID3 data chunk
14272   *
14273   * @param data - Block of data containing one or more ID3 tags
14274   *
14275   * @returns The timestamp
14276   *
14277   * @group ID3
14278   *
14279   * @beta
14280   */
14281  function getId3Timestamp(data) {
14282    var frames = getId3Frames(data);
14283    for (var i = 0; i < frames.length; i++) {
14284      var frame = frames[i];
14285      if (isId3TimestampFrame(frame)) {
14286        return readId3Timestamp(frame);
14287      }
14288    }
14289    return undefined;
14290  }
14291
14292  /**
14293   * Checks if the given data contains an ID3 tag.
14294   *
14295   * @param data - The data to check
14296   * @param offset - The offset at which to start checking
14297   *
14298   * @returns `true` if an ID3 tag is found
14299   *
14300   * @group ID3
14301   *
14302   * @beta
14303   */
14304  function canParseId3(data, offset) {
14305    return isId3Header(data, offset) && readId3Size(data, offset + 6) + 10 <= data.length - offset;
14306  }
14307
14308  var BaseAudioDemuxer = /*#__PURE__*/function () {
14309    function BaseAudioDemuxer() {
14310      this._audioTrack = void 0;
14311      this._id3Track = void 0;
14312      this.frameIndex = 0;
14313      this.cachedData = null;
14314      this.basePTS = null;
14315      this.initPTS = null;
14316      this.lastPTS = null;
14317    }
14318    var _proto = BaseAudioDemuxer.prototype;
14319    _proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) {
14320      this._id3Track = {
14321        type: 'id3',
14322        id: 3,
14323        pid: -1,
14324        inputTimeScale: 90000,
14325        sequenceNumber: 0,
14326        samples: [],
14327        dropped: 0
14328      };
14329    };
14330    _proto.resetTimeStamp = function resetTimeStamp(deaultTimestamp) {
14331      this.initPTS = deaultTimestamp;
14332      this.resetContiguity();
14333    };
14334    _proto.resetContiguity = function resetContiguity() {
14335      this.basePTS = null;
14336      this.lastPTS = null;
14337      this.frameIndex = 0;
14338    };
14339    _proto.canParse = function canParse(data, offset) {
14340      return false;
14341    };
14342    _proto.appendFrame = function appendFrame(track, data, offset) {}
14343
14344    // feed incoming data to the front of the parsing pipeline
14345    ;
14346    _proto.demux = function demux(data, timeOffset) {
14347      if (this.cachedData) {
14348        data = appendUint8Array(this.cachedData, data);
14349        this.cachedData = null;
14350      }
14351      var id3Data = getId3Data(data, 0);
14352      var offset = id3Data ? id3Data.length : 0;
14353      var lastDataIndex;
14354      var track = this._audioTrack;
14355      var id3Track = this._id3Track;
14356      var timestamp = id3Data ? getId3Timestamp(id3Data) : undefined;
14357      var length = data.length;
14358      if (this.basePTS === null || this.frameIndex === 0 && isFiniteNumber(timestamp)) {
14359        this.basePTS = initPTSFn(timestamp, timeOffset, this.initPTS);
14360        this.lastPTS = this.basePTS;
14361      }
14362      if (this.lastPTS === null) {
14363        this.lastPTS = this.basePTS;
14364      }
14365
14366      // more expressive than alternative: id3Data?.length
14367      if (id3Data && id3Data.length > 0) {
14368        id3Track.samples.push({
14369          pts: this.lastPTS,
14370          dts: this.lastPTS,
14371          data: id3Data,
14372          type: MetadataSchema.audioId3,
14373          duration: Number.POSITIVE_INFINITY
14374        });
14375      }
14376      while (offset < length) {
14377        if (this.canParse(data, offset)) {
14378          var frame = this.appendFrame(track, data, offset);
14379          if (frame) {
14380            this.frameIndex++;
14381            this.lastPTS = frame.sample.pts;
14382            offset += frame.length;
14383            lastDataIndex = offset;
14384          } else {
14385            offset = length;
14386          }
14387        } else if (canParseId3(data, offset)) {
14388          // after a canParse, a call to getId3Data *should* always returns some data
14389          id3Data = getId3Data(data, offset);
14390          id3Track.samples.push({
14391            pts: this.lastPTS,
14392            dts: this.lastPTS,
14393            data: id3Data,
14394            type: MetadataSchema.audioId3,
14395            duration: Number.POSITIVE_INFINITY
14396          });
14397          offset += id3Data.length;
14398          lastDataIndex = offset;
14399        } else {
14400          offset++;
14401        }
14402        if (offset === length && lastDataIndex !== length) {
14403          var partialData = sliceUint8(data, lastDataIndex);
14404          if (this.cachedData) {
14405            this.cachedData = appendUint8Array(this.cachedData, partialData);
14406          } else {
14407            this.cachedData = partialData;
14408          }
14409        }
14410      }
14411      return {
14412        audioTrack: track,
14413        videoTrack: dummyTrack(),
14414        id3Track: id3Track,
14415        textTrack: dummyTrack()
14416      };
14417    };
14418    _proto.demuxSampleAes = function demuxSampleAes(data, keyData, timeOffset) {
14419      return Promise.reject(new Error("[" + this + "] This demuxer does not support Sample-AES decryption"));
14420    };
14421    _proto.flush = function flush(timeOffset) {
14422      // Parse cache in case of remaining frames.
14423      var cachedData = this.cachedData;
14424      if (cachedData) {
14425        this.cachedData = null;
14426        this.demux(cachedData, 0);
14427      }
14428      return {
14429        audioTrack: this._audioTrack,
14430        videoTrack: dummyTrack(),
14431        id3Track: this._id3Track,
14432        textTrack: dummyTrack()
14433      };
14434    };
14435    _proto.destroy = function destroy() {
14436      this.cachedData = null;
14437      // @ts-ignore
14438      this._audioTrack = this._id3Track = undefined;
14439    };
14440    return BaseAudioDemuxer;
14441  }();
14442  /**
14443   * Initialize PTS
14444   * <p>
14445   *    use timestamp unless it is undefined, NaN or Infinity
14446   * </p>
14447   */
14448  var initPTSFn = function initPTSFn(timestamp, timeOffset, initPTS) {
14449    if (isFiniteNumber(timestamp)) {
14450      return timestamp * 90;
14451    }
14452    var init90kHz = initPTS ? initPTS.baseTime * 90000 / initPTS.timescale : 0;
14453    return timeOffset * 90000 + init90kHz;
14454  };
14455
14456  /**
14457   * ADTS parser helper
14458   * @link https://wiki.multimedia.cx/index.php?title=ADTS
14459   */
14460  function getAudioConfig(observer, data, offset, audioCodec) {
14461    var adtsObjectType;
14462    var originalAdtsObjectType;
14463    var adtsExtensionSamplingIndex;
14464    var adtsChannelConfig;
14465    var config;
14466    var userAgent = navigator.userAgent.toLowerCase();
14467    var manifestCodec = audioCodec;
14468    var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
14469    // byte 2
14470    adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
14471    var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
14472    if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
14473      var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
14474      observer.emit(Events.ERROR, Events.ERROR, {
14475        type: ErrorTypes.MEDIA_ERROR,
14476        details: ErrorDetails.FRAG_PARSING_ERROR,
14477        fatal: true,
14478        error: error,
14479        reason: error.message
14480      });
14481      return;
14482    }
14483    adtsChannelConfig = (data[offset + 2] & 0x01) << 2;
14484    // byte 3
14485    adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
14486    logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
14487    // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
14488    if (/firefox|palemoon/i.test(userAgent)) {
14489      if (adtsSamplingIndex >= 6) {
14490        adtsObjectType = 5;
14491        config = new Array(4);
14492        // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
14493        // there is a factor 2 between frame sample rate and output sample rate
14494        // multiply frequency by 2 (see table below, equivalent to substract 3)
14495        adtsExtensionSamplingIndex = adtsSamplingIndex - 3;
14496      } else {
14497        adtsObjectType = 2;
14498        config = new Array(2);
14499        adtsExtensionSamplingIndex = adtsSamplingIndex;
14500      }
14501      // Android : always use AAC
14502    } else if (userAgent.indexOf('android') !== -1) {
14503      adtsObjectType = 2;
14504      config = new Array(2);
14505      adtsExtensionSamplingIndex = adtsSamplingIndex;
14506    } else {
14507      /*  for other browsers (Chrome/Vivaldi/Opera ...)
14508          always force audio type to be HE-AAC SBR, as some browsers do not support audio codec switch properly (like Chrome ...)
14509      */
14510      adtsObjectType = 5;
14511      config = new Array(4);
14512      // if (manifest codec is HE-AAC or HE-AACv2) OR (manifest codec not specified AND frequency less than 24kHz)
14513      if (audioCodec && (audioCodec.indexOf('mp4a.40.29') !== -1 || audioCodec.indexOf('mp4a.40.5') !== -1) || !audioCodec && adtsSamplingIndex >= 6) {
14514        // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
14515        // there is a factor 2 between frame sample rate and output sample rate
14516        // multiply frequency by 2 (see table below, equivalent to substract 3)
14517        adtsExtensionSamplingIndex = adtsSamplingIndex - 3;
14518      } else {
14519        // if (manifest codec is AAC) AND (frequency less than 24kHz AND nb channel is 1) OR (manifest codec not specified and mono audio)
14520        // Chrome fails to play back with low frequency AAC LC mono when initialized with HE-AAC.  This is not a problem with stereo.
14521        if (audioCodec && audioCodec.indexOf('mp4a.40.2') !== -1 && (adtsSamplingIndex >= 6 && adtsChannelConfig === 1 || /vivaldi/i.test(userAgent)) || !audioCodec && adtsChannelConfig === 1) {
14522          adtsObjectType = 2;
14523          config = new Array(2);
14524        }
14525        adtsExtensionSamplingIndex = adtsSamplingIndex;
14526      }
14527    }
14528    /* refer to http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config
14529        ISO 14496-3 (AAC).pdf - Table 1.13 — Syntax of AudioSpecificConfig()
14530      Audio Profile / Audio Object Type
vendor: 8,984 bytes, lines 14531-14795
14531      0: Null
14532      1: AAC Main
14533      2: AAC LC (Low Complexity)
14534      3: AAC SSR (Scalable Sample Rate)
14535      4: AAC LTP (Long Term Prediction)
14536      5: SBR (Spectral Band Replication)
14537      6: AAC Scalable
14538     sampling freq
14539      0: 96000 Hz
14540      1: 88200 Hz
14541      2: 64000 Hz
14542      3: 48000 Hz
14543      4: 44100 Hz
14544      5: 32000 Hz
14545      6: 24000 Hz
14546      7: 22050 Hz
14547      8: 16000 Hz
14548      9: 12000 Hz
14549      10: 11025 Hz
14550      11: 8000 Hz
14551      12: 7350 Hz
14552      13: Reserved
14553      14: Reserved
14554      15: frequency is written explictly
14555      Channel Configurations
14556      These are the channel configurations:
14557      0: Defined in AOT Specifc Config
14558      1: 1 channel: front-center
14559      2: 2 channels: front-left, front-right
14560    */
14561    // audioObjectType = profile => profile, the MPEG-4 Audio Object Type minus 1
14562    config[0] = adtsObjectType << 3;
14563    // samplingFrequencyIndex
14564    config[0] |= (adtsSamplingIndex & 0x0e) >> 1;
14565    config[1] |= (adtsSamplingIndex & 0x01) << 7;
14566    // channelConfiguration
14567    config[1] |= adtsChannelConfig << 3;
14568    if (adtsObjectType === 5) {
14569      // adtsExtensionSamplingIndex
14570      config[1] |= (adtsExtensionSamplingIndex & 0x0e) >> 1;
14571      config[2] = (adtsExtensionSamplingIndex & 0x01) << 7;
14572      // adtsObjectType (force to 2, chrome is checking that object type is less than 5 ???
14573      //    https://chromium.googlesource.com/chromium/src.git/+/master/media/formats/mp4/aac.cc
14574      config[2] |= 2 << 2;
14575      config[3] = 0;
14576    }
14577    return {
14578      config: config,
14579      samplerate: adtsSamplingRates[adtsSamplingIndex],
14580      channelCount: adtsChannelConfig,
14581      codec: 'mp4a.40.' + adtsObjectType,
14582      parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
14583      manifestCodec: manifestCodec
14584    };
14585  }
14586  function isHeaderPattern$1(data, offset) {
14587    return data[offset] === 0xff && (data[offset + 1] & 0xf6) === 0xf0;
14588  }
14589  function getHeaderLength(data, offset) {
14590    return data[offset + 1] & 0x01 ? 7 : 9;
14591  }
14592  function getFullFrameLength(data, offset) {
14593    return (data[offset + 3] & 0x03) << 11 | data[offset + 4] << 3 | (data[offset + 5] & 0xe0) >>> 5;
14594  }
14595  function canGetFrameLength(data, offset) {
14596    return offset + 5 < data.length;
14597  }
14598  function isHeader$1(data, offset) {
14599    // Look for ADTS header | 1111 1111 | 1111 X00X | where X can be either 0 or 1
14600    // Layer bits (position 14 and 15) in header should be always 0 for ADTS
14601    // More info https://wiki.multimedia.cx/index.php?title=ADTS
14602    return offset + 1 < data.length && isHeaderPattern$1(data, offset);
14603  }
14604  function canParse$1(data, offset) {
14605    return canGetFrameLength(data, offset) && isHeaderPattern$1(data, offset) && getFullFrameLength(data, offset) <= data.length - offset;
14606  }
14607  function probe$1(data, offset) {
14608    // same as isHeader but we also check that ADTS frame follows last ADTS frame
14609    // or end of data is reached
14610    if (isHeader$1(data, offset)) {
14611      // ADTS header Length
14612      var headerLength = getHeaderLength(data, offset);
14613      if (offset + headerLength >= data.length) {
14614        return false;
14615      }
14616      // ADTS frame Length
14617      var frameLength = getFullFrameLength(data, offset);
14618      if (frameLength <= headerLength) {
14619        return false;
14620      }
14621      var newOffset = offset + frameLength;
14622      return newOffset === data.length || isHeader$1(data, newOffset);
14623    }
14624    return false;
14625  }
14626  function initTrackConfig(track, observer, data, offset, audioCodec) {
14627    if (!track.samplerate) {
14628      var config = getAudioConfig(observer, data, offset, audioCodec);
14629      if (!config) {
14630        return;
14631      }
14632      track.config = config.config;
14633      track.samplerate = config.samplerate;
14634      track.channelCount = config.channelCount;
14635      track.codec = config.codec;
14636      track.manifestCodec = config.manifestCodec;
14637      track.parsedCodec = config.parsedCodec;
14638      logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
14639    }
14640  }
14641  function getFrameDuration(samplerate) {
14642    return 1024 * 90000 / samplerate;
14643  }
14644  function parseFrameHeader(data, offset) {
14645    // The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header
14646    var headerLength = getHeaderLength(data, offset);
14647    if (offset + headerLength <= data.length) {
14648      // retrieve frame size
14649      var frameLength = getFullFrameLength(data, offset) - headerLength;
14650      if (frameLength > 0) {
14651        // logger.log(`AAC frame, offset/length/total/pts:${offset+headerLength}/${frameLength}/${data.byteLength}`);
14652        return {
14653          headerLength: headerLength,
14654          frameLength: frameLength
14655        };
14656      }
14657    }
14658  }
14659  function appendFrame$1(track, data, offset, pts, frameIndex) {
14660    var frameDuration = getFrameDuration(track.samplerate);
14661    var stamp = pts + frameIndex * frameDuration;
14662    var header = parseFrameHeader(data, offset);
14663    var unit;
14664    if (header) {
14665      var frameLength = header.frameLength,
14666        headerLength = header.headerLength;
14667      var _length = headerLength + frameLength;
14668      var missing = Math.max(0, offset + _length - data.length);
14669      // logger.log(`AAC frame ${frameIndex}, pts:${stamp} length@offset/total: ${frameLength}@${offset+headerLength}/${data.byteLength} missing: ${missing}`);
14670      if (missing) {
14671        unit = new Uint8Array(_length - headerLength);
14672        unit.set(data.subarray(offset + headerLength, data.length), 0);
14673      } else {
14674        unit = data.subarray(offset + headerLength, offset + _length);
14675      }
14676      var _sample = {
14677        unit: unit,
14678        pts: stamp
14679      };
14680      if (!missing) {
14681        track.samples.push(_sample);
14682      }
14683      return {
14684        sample: _sample,
14685        length: _length,
14686        missing: missing
14687      };
14688    }
14689    // overflow incomplete header
14690    var length = data.length - offset;
14691    unit = new Uint8Array(length);
14692    unit.set(data.subarray(offset, data.length), 0);
14693    var sample = {
14694      unit: unit,
14695      pts: stamp
14696    };
14697    return {
14698      sample: sample,
14699      length: length,
14700      missing: -1
14701    };
14702  }
14703
14704  /**
14705   *  MPEG parser helper
14706   */
14707
14708  var chromeVersion$1 = null;
14709  var BitratesMap = [32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160];
14710  var SamplingRateMap = [44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000];
14711  var SamplesCoefficients = [
14712  // MPEG 2.5
14713  [0,
14714  // Reserved
14715  72,
14716  // Layer3
14717  144,
14718  // Layer2
14719  12 // Layer1
14720  ],
14721  // Reserved
14722  [0,
14723  // Reserved
14724  0,
14725  // Layer3
14726  0,
14727  // Layer2
14728  0 // Layer1
14729  ],
14730  // MPEG 2
14731  [0,
14732  // Reserved
14733  72,
14734  // Layer3
14735  144,
14736  // Layer2
14737  12 // Layer1
14738  ],
14739  // MPEG 1
14740  [0,
14741  // Reserved
14742  144,
14743  // Layer3
14744  144,
14745  // Layer2
14746  12 // Layer1
14747  ]];
14748  var BytesInSlot = [0,
14749  // Reserved
14750  1,
14751  // Layer3
14752  1,
14753  // Layer2
14754  4 // Layer1
14755  ];
14756  function appendFrame(track, data, offset, pts, frameIndex) {
14757    // Using http://www.datavoyage.com/mpgscript/mpeghdr.htm as a reference
14758    if (offset + 24 > data.length) {
14759      return;
14760    }
14761    var header = parseHeader(data, offset);
14762    if (header && offset + header.frameLength <= data.length) {
14763      var frameDuration = header.samplesPerFrame * 90000 / header.sampleRate;
14764      var stamp = pts + frameIndex * frameDuration;
14765      var sample = {
14766        unit: data.subarray(offset, offset + header.frameLength),
14767        pts: stamp,
14768        dts: stamp
14769      };
14770      track.config = [];
14771      track.channelCount = header.channelCount;
14772      track.samplerate = header.sampleRate;
14773      track.samples.push(sample);
14774      return {
14775        sample: sample,
14776        length: header.frameLength,
14777        missing: 0
14778      };
14779    }
14780  }
14781  function parseHeader(data, offset) {
14782    var mpegVersion = data[offset + 1] >> 3 & 3;
14783    var mpegLayer = data[offset + 1] >> 1 & 3;
14784    var bitRateIndex = data[offset + 2] >> 4 & 15;
14785    var sampleRateIndex = data[offset + 2] >> 2 & 3;
14786    if (mpegVersion !== 1 && bitRateIndex !== 0 && bitRateIndex !== 15 && sampleRateIndex !== 3) {
14787      var paddingBit = data[offset + 2] >> 1 & 1;
14788      var channelMode = data[offset + 3] >> 6;
14789      var columnInBitrates = mpegVersion === 3 ? 3 - mpegLayer : mpegLayer === 3 ? 3 : 4;
14790      var bitRate = BitratesMap[columnInBitrates * 14 + bitRateIndex - 1] * 1000;
14791      var columnInSampleRates = mpegVersion === 3 ? 0 : mpegVersion === 2 ? 1 : 2;
14792      var sampleRate = SamplingRateMap[columnInSampleRates * 3 + sampleRateIndex];
14793      var channelCount = channelMode === 3 ? 1 : 2; // If bits of channel mode are `11` then it is a single channel (Mono)
14794      var sampleCoefficient = SamplesCoefficients[mpegVersion][mpegLayer];
14795      var bytesInSlot = BytesInSlot[mpegLayer];
vendor: 16,679 bytes, lines 14796-15227
14796      var samplesPerFrame = sampleCoefficient * 8 * bytesInSlot;
14797      var frameLength = Math.floor(sampleCoefficient * bitRate / sampleRate + paddingBit) * bytesInSlot;
14798      if (chromeVersion$1 === null) {
14799        var userAgent = navigator.userAgent || '';
14800        var result = userAgent.match(/Chrome\/(\d+)/i);
14801        chromeVersion$1 = result ? parseInt(result[1]) : 0;
14802      }
14803      var needChromeFix = !!chromeVersion$1 && chromeVersion$1 <= 87;
14804      if (needChromeFix && mpegLayer === 2 && bitRate >= 224000 && channelMode === 0) {
14805        // Work around bug in Chromium by setting channelMode to dual-channel (01) instead of stereo (00)
14806        data[offset + 3] = data[offset + 3] | 0x80;
14807      }
14808      return {
14809        sampleRate: sampleRate,
14810        channelCount: channelCount,
14811        frameLength: frameLength,
14812        samplesPerFrame: samplesPerFrame
14813      };
14814    }
14815  }
14816  function isHeaderPattern(data, offset) {
14817    return data[offset] === 0xff && (data[offset + 1] & 0xe0) === 0xe0 && (data[offset + 1] & 0x06) !== 0x00;
14818  }
14819  function isHeader(data, offset) {
14820    // Look for MPEG header | 1111 1111 | 111X XYZX | where X can be either 0 or 1 and Y or Z should be 1
14821    // Layer bits (position 14 and 15) in header should be always different from 0 (Layer I or Layer II or Layer III)
14822    // More info http://www.mp3-tech.org/programmer/frame_header.html
14823    return offset + 1 < data.length && isHeaderPattern(data, offset);
14824  }
14825  function canParse(data, offset) {
14826    var headerSize = 4;
14827    return isHeaderPattern(data, offset) && headerSize <= data.length - offset;
14828  }
14829  function probe(data, offset) {
14830    // same as isHeader but we also check that MPEG frame follows last MPEG frame
14831    // or end of data is reached
14832    if (offset + 1 < data.length && isHeaderPattern(data, offset)) {
14833      // MPEG header Length
14834      var headerLength = 4;
14835      // MPEG frame Length
14836      var header = parseHeader(data, offset);
14837      var frameLength = headerLength;
14838      if (header != null && header.frameLength) {
14839        frameLength = header.frameLength;
14840      }
14841      var newOffset = offset + frameLength;
14842      return newOffset === data.length || isHeader(data, newOffset);
14843    }
14844    return false;
14845  }
14846
14847  var AACDemuxer = /*#__PURE__*/function (_BaseAudioDemuxer) {
14848    function AACDemuxer(observer, config) {
14849      var _this;
14850      _this = _BaseAudioDemuxer.call(this) || this;
14851      _this.observer = void 0;
14852      _this.config = void 0;
14853      _this.observer = observer;
14854      _this.config = config;
14855      return _this;
14856    }
14857    _inheritsLoose(AACDemuxer, _BaseAudioDemuxer);
14858    var _proto = AACDemuxer.prototype;
14859    _proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) {
14860      _BaseAudioDemuxer.prototype.resetInitSegment.call(this, initSegment, audioCodec, videoCodec, trackDuration);
14861      this._audioTrack = {
14862        container: 'audio/adts',
14863        type: 'audio',
14864        id: 2,
14865        pid: -1,
14866        sequenceNumber: 0,
14867        segmentCodec: 'aac',
14868        samples: [],
14869        manifestCodec: audioCodec,
14870        duration: trackDuration,
14871        inputTimeScale: 90000,
14872        dropped: 0
14873      };
14874    }
14875
14876    // Source for probe info - https://wiki.multimedia.cx/index.php?title=ADTS
14877    ;
14878    AACDemuxer.probe = function probe$2(data, logger) {
14879      if (!data) {
14880        return false;
14881      }
14882
14883      // Check for the ADTS sync word
14884      // Look for ADTS header | 1111 1111 | 1111 X00X | where X can be either 0 or 1
14885      // Layer bits (position 14 and 15) in header should be always 0 for ADTS
14886      // More info https://wiki.multimedia.cx/index.php?title=ADTS
14887      var id3Data = getId3Data(data, 0);
14888      var offset = (id3Data == null ? void 0 : id3Data.length) || 0;
14889      if (probe(data, offset)) {
14890        return false;
14891      }
14892      for (var length = data.length; offset < length; offset++) {
14893        if (probe$1(data, offset)) {
14894          logger.log('ADTS sync word found !');
14895          return true;
14896        }
14897      }
14898      return false;
14899    };
14900    _proto.canParse = function canParse(data, offset) {
14901      return canParse$1(data, offset);
14902    };
14903    _proto.appendFrame = function appendFrame(track, data, offset) {
14904      initTrackConfig(track, this.observer, data, offset, track.manifestCodec);
14905      var frame = appendFrame$1(track, data, offset, this.basePTS, this.frameIndex);
14906      if (frame && frame.missing === 0) {
14907        return frame;
14908      }
14909    };
14910    return AACDemuxer;
14911  }(BaseAudioDemuxer);
14912
14913  var emsgSchemePattern = /\/emsg[-/]ID3/i;
14914  var MP4Demuxer = /*#__PURE__*/function () {
14915    function MP4Demuxer(observer, config) {
14916      this.remainderData = null;
14917      this.timeOffset = 0;
14918      this.config = void 0;
14919      this.videoTrack = void 0;
14920      this.audioTrack = void 0;
14921      this.id3Track = void 0;
14922      this.txtTrack = void 0;
14923      this.config = config;
14924    }
14925    var _proto = MP4Demuxer.prototype;
14926    _proto.resetTimeStamp = function resetTimeStamp() {};
14927    _proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) {
14928      var videoTrack = this.videoTrack = dummyTrack('video', 1);
14929      var audioTrack = this.audioTrack = dummyTrack('audio', 1);
14930      var captionTrack = this.txtTrack = dummyTrack('text', 1);
14931      this.id3Track = dummyTrack('id3', 1);
14932      this.timeOffset = 0;
14933      if (!(initSegment != null && initSegment.byteLength)) {
14934        return;
14935      }
14936      var initData = parseInitSegment(initSegment);
14937      if (initData.video) {
14938        var _initData$video = initData.video,
14939          id = _initData$video.id,
14940          timescale = _initData$video.timescale,
14941          codec = _initData$video.codec;
14942        videoTrack.id = id;
14943        videoTrack.timescale = captionTrack.timescale = timescale;
14944        videoTrack.codec = codec;
14945      }
14946      if (initData.audio) {
14947        var _initData$audio = initData.audio,
14948          _id = _initData$audio.id,
14949          _timescale = _initData$audio.timescale,
14950          _codec = _initData$audio.codec;
14951        audioTrack.id = _id;
14952        audioTrack.timescale = _timescale;
14953        audioTrack.codec = _codec;
14954      }
14955      captionTrack.id = RemuxerTrackIdConfig.text;
14956      videoTrack.sampleDuration = 0;
14957      videoTrack.duration = audioTrack.duration = trackDuration;
14958    };
14959    _proto.resetContiguity = function resetContiguity() {
14960      this.remainderData = null;
14961    };
14962    MP4Demuxer.probe = function probe(data) {
14963      return hasMoofData(data);
14964    };
14965    _proto.demux = function demux(data, timeOffset) {
14966      this.timeOffset = timeOffset;
14967      // Load all data into the avc track. The CMAF remuxer will look for the data in the samples object; the rest of the fields do not matter
14968      var videoSamples = data;
14969      var videoTrack = this.videoTrack;
14970      var textTrack = this.txtTrack;
14971      if (this.config.progressive) {
14972        // Split the bytestream into two ranges: one encompassing all data up until the start of the last moof, and everything else.
14973        // This is done to guarantee that we're sending valid data to MSE - when demuxing progressively, we have no guarantee
14974        // that the fetch loader gives us flush moof+mdat pairs. If we push jagged data to MSE, it will throw an exception.
14975        if (this.remainderData) {
14976          videoSamples = appendUint8Array(this.remainderData, data);
14977        }
14978        var segmentedData = segmentValidRange(videoSamples);
14979        this.remainderData = segmentedData.remainder;
14980        videoTrack.samples = segmentedData.valid || new Uint8Array();
14981      } else {
14982        videoTrack.samples = videoSamples;
14983      }
14984      var id3Track = this.extractID3Track(videoTrack, timeOffset);
14985      textTrack.samples = parseSamples(timeOffset, videoTrack);
14986      return {
14987        videoTrack: videoTrack,
14988        audioTrack: this.audioTrack,
14989        id3Track: id3Track,
14990        textTrack: this.txtTrack
14991      };
14992    };
14993    _proto.flush = function flush() {
14994      var timeOffset = this.timeOffset;
14995      var videoTrack = this.videoTrack;
14996      var textTrack = this.txtTrack;
14997      videoTrack.samples = this.remainderData || new Uint8Array();
14998      this.remainderData = null;
14999      var id3Track = this.extractID3Track(videoTrack, this.timeOffset);
15000      textTrack.samples = parseSamples(timeOffset, videoTrack);
15001      return {
15002        videoTrack: videoTrack,
15003        audioTrack: dummyTrack(),
15004        id3Track: id3Track,
15005        textTrack: dummyTrack()
15006      };
15007    };
15008    _proto.extractID3Track = function extractID3Track(videoTrack, timeOffset) {
15009      var id3Track = this.id3Track;
15010      if (videoTrack.samples.length) {
15011        var emsgs = findBox(videoTrack.samples, ['emsg']);
15012        if (emsgs) {
15013          emsgs.forEach(function (data) {
15014            var emsgInfo = parseEmsg(data);
15015            if (emsgSchemePattern.test(emsgInfo.schemeIdUri)) {
15016              var pts = isFiniteNumber(emsgInfo.presentationTime) ? emsgInfo.presentationTime / emsgInfo.timeScale : timeOffset + emsgInfo.presentationTimeDelta / emsgInfo.timeScale;
15017              var duration = emsgInfo.eventDuration === 0xffffffff ? Number.POSITIVE_INFINITY : emsgInfo.eventDuration / emsgInfo.timeScale;
15018              // Safari takes anything <= 0.001 seconds and maps it to Infinity
15019              if (duration <= 0.001) {
15020                duration = Number.POSITIVE_INFINITY;
15021              }
15022              var payload = emsgInfo.payload;
15023              id3Track.samples.push({
15024                data: payload,
15025                len: payload.byteLength,
15026                dts: pts,
15027                pts: pts,
15028                type: MetadataSchema.emsg,
15029                duration: duration
15030              });
15031            }
15032          });
15033        }
15034      }
15035      return id3Track;
15036    };
15037    _proto.demuxSampleAes = function demuxSampleAes(data, keyData, timeOffset) {
15038      return Promise.reject(new Error('The MP4 demuxer does not support SAMPLE-AES decryption'));
15039    };
15040    _proto.destroy = function destroy() {
15041      // @ts-ignore
15042      this.config = null;
15043      this.remainderData = null;
15044      this.videoTrack = this.audioTrack = this.id3Track = this.txtTrack = undefined;
15045    };
15046    return MP4Demuxer;
15047  }();
15048
15049  var getAudioBSID = function getAudioBSID(data, offset) {
15050    // check the bsid to confirm ac-3 | ec-3
15051    var bsid = 0;
15052    var numBits = 5;
15053    offset += numBits;
15054    var temp = new Uint32Array(1); // unsigned 32 bit for temporary storage
15055    var mask = new Uint32Array(1); // unsigned 32 bit mask value
15056    var _byte = new Uint8Array(1); // unsigned 8 bit for temporary storage
15057    while (numBits > 0) {
15058      _byte[0] = data[offset];
15059      // read remaining bits, upto 8 bits at a time
15060      var bits = Math.min(numBits, 8);
15061      var shift = 8 - bits;
15062      mask[0] = 0xff000000 >>> 24 + shift << shift;
15063      temp[0] = (_byte[0] & mask[0]) >> shift;
15064      bsid = !bsid ? temp[0] : bsid << bits | temp[0];
15065      offset += 1;
15066      numBits -= bits;
15067    }
15068    return bsid;
15069  };
15070
15071  var BaseVideoParser = /*#__PURE__*/function () {
15072    function BaseVideoParser() {
15073      this.VideoSample = null;
15074    }
15075    var _proto = BaseVideoParser.prototype;
15076    _proto.createVideoSample = function createVideoSample(key, pts, dts) {
15077      return {
15078        key: key,
15079        frame: false,
15080        pts: pts,
15081        dts: dts,
15082        units: [],
15083        length: 0
15084      };
15085    };
15086    _proto.getLastNalUnit = function getLastNalUnit(samples) {
15087      var _VideoSample;
15088      var VideoSample = this.VideoSample;
15089      var lastUnit;
15090      // try to fallback to previous sample if current one is empty
15091      if (!VideoSample || VideoSample.units.length === 0) {
15092        VideoSample = samples[samples.length - 1];
15093      }
15094      if ((_VideoSample = VideoSample) != null && _VideoSample.units) {
15095        var units = VideoSample.units;
15096        lastUnit = units[units.length - 1];
15097      }
15098      return lastUnit;
15099    };
15100    _proto.pushAccessUnit = function pushAccessUnit(VideoSample, videoTrack) {
15101      if (VideoSample.units.length && VideoSample.frame) {
15102        // if sample does not have PTS/DTS, patch with last sample PTS/DTS
15103        if (VideoSample.pts === undefined) {
15104          var samples = videoTrack.samples;
15105          var nbSamples = samples.length;
15106          if (nbSamples) {
15107            var lastSample = samples[nbSamples - 1];
15108            VideoSample.pts = lastSample.pts;
15109            VideoSample.dts = lastSample.dts;
15110          } else {
15111            // dropping samples, no timestamp found
15112            videoTrack.dropped++;
15113            return;
15114          }
15115        }
15116        videoTrack.samples.push(VideoSample);
15117      }
15118    };
15119    _proto.parseNALu = function parseNALu(track, array, endOfSegment) {
15120      var len = array.byteLength;
15121      var state = track.naluState || 0;
15122      var lastState = state;
15123      var units = [];
15124      var i = 0;
15125      var value;
15126      var overflow;
15127      var unitType;
15128      var lastUnitStart = -1;
15129      var lastUnitType = 0;
15130      // logger.log('PES:' + Hex.hexDump(array));
15131
15132      if (state === -1) {
15133        // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
15134        lastUnitStart = 0;
15135        // NALu type is value read from offset 0
15136        lastUnitType = this.getNALuType(array, 0);
15137        state = 0;
15138        i = 1;
15139      }
15140      while (i < len) {
15141        value = array[i++];
15142        // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
15143        if (!state) {
15144          state = value ? 0 : 1;
15145          continue;
15146        }
15147        if (state === 1) {
15148          state = value ? 0 : 2;
15149          continue;
15150        }
15151        // here we have state either equal to 2 or 3
15152        if (!value) {
15153          state = 3;
15154        } else if (value === 1) {
15155          overflow = i - state - 1;
15156          if (lastUnitStart >= 0) {
15157            var unit = {
15158              data: array.subarray(lastUnitStart, overflow),
15159              type: lastUnitType
15160            };
15161            // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
15162            units.push(unit);
15163          } else {
15164            // lastUnitStart is undefined => this is the first start code found in this PES packet
15165            // first check if start code delimiter is overlapping between 2 PES packets,
15166            // ie it started in last packet (lastState not zero)
15167            // and ended at the beginning of this PES packet (i <= 4 - lastState)
15168            var lastUnit = this.getLastNalUnit(track.samples);
15169            if (lastUnit) {
15170              if (lastState && i <= 4 - lastState) {
15171                // start delimiter overlapping between PES packets
15172                // strip start delimiter bytes from the end of last NAL unit
15173                // check if lastUnit had a state different from zero
15174                if (lastUnit.state) {
15175                  // strip last bytes
15176                  lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
15177                }
15178              }
15179              // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
15180
15181              if (overflow > 0) {
15182                // logger.log('first NALU found with overflow:' + overflow);
15183                lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
15184                lastUnit.state = 0;
15185              }
15186            }
15187          }
15188          // check if we can read unit type
15189          if (i < len) {
15190            unitType = this.getNALuType(array, i);
15191            // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
15192            lastUnitStart = i;
15193            lastUnitType = unitType;
15194            state = 0;
15195          } else {
15196            // not enough byte to read unit type. let's read it on next PES parsing
15197            state = -1;
15198          }
15199        } else {
15200          state = 0;
15201        }
15202      }
15203      if (lastUnitStart >= 0 && state >= 0) {
15204        var _unit = {
15205          data: array.subarray(lastUnitStart, len),
15206          type: lastUnitType,
15207          state: state
15208        };
15209        units.push(_unit);
15210        // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
15211      }
15212      // no NALu found
15213      if (units.length === 0) {
15214        // append pes.data to previous NAL unit
15215        var _lastUnit = this.getLastNalUnit(track.samples);
15216        if (_lastUnit) {
15217          _lastUnit.data = appendUint8Array(_lastUnit.data, array);
15218        }
15219      }
15220      track.naluState = state;
15221      return units;
15222    };
15223    return BaseVideoParser;
15224  }();
15225
15226  /**
15227   * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.�
vendor: 10,677 bytes, lines 15227-15536
15227
15228   */
15229
15230  var ExpGolomb = /*#__PURE__*/function () {
15231    function ExpGolomb(data) {
15232      this.data = void 0;
15233      this.bytesAvailable = void 0;
15234      this.word = void 0;
15235      this.bitsAvailable = void 0;
15236      this.data = data;
15237      // the number of bytes left to examine in this.data
15238      this.bytesAvailable = data.byteLength;
15239      // the current word being examined
15240      this.word = 0; // :uint
15241      // the number of bits left to examine in the current word
15242      this.bitsAvailable = 0; // :uint
15243    }
15244
15245    // ():void
15246    var _proto = ExpGolomb.prototype;
15247    _proto.loadWord = function loadWord() {
15248      var data = this.data;
15249      var bytesAvailable = this.bytesAvailable;
15250      var position = data.byteLength - bytesAvailable;
15251      var workingBytes = new Uint8Array(4);
15252      var availableBytes = Math.min(4, bytesAvailable);
15253      if (availableBytes === 0) {
15254        throw new Error('no bytes available');
15255      }
15256      workingBytes.set(data.subarray(position, position + availableBytes));
15257      this.word = new DataView(workingBytes.buffer).getUint32(0);
15258      // track the amount of this.data that has been processed
15259      this.bitsAvailable = availableBytes * 8;
15260      this.bytesAvailable -= availableBytes;
15261    }
15262
15263    // (count:int):void
15264    ;
15265    _proto.skipBits = function skipBits(count) {
15266      var skipBytes; // :int
15267      count = Math.min(count, this.bytesAvailable * 8 + this.bitsAvailable);
15268      if (this.bitsAvailable > count) {
15269        this.word <<= count;
15270        this.bitsAvailable -= count;
15271      } else {
15272        count -= this.bitsAvailable;
15273        skipBytes = count >> 3;
15274        count -= skipBytes << 3;
15275        this.bytesAvailable -= skipBytes;
15276        this.loadWord();
15277        this.word <<= count;
15278        this.bitsAvailable -= count;
15279      }
15280    }
15281
15282    // (size:int):uint
15283    ;
15284    _proto.readBits = function readBits(size) {
15285      var bits = Math.min(this.bitsAvailable, size); // :uint
15286      var valu = this.word >>> 32 - bits; // :uint
15287      if (size > 32) {
15288        logger.error('Cannot read more than 32 bits at a time');
15289      }
15290      this.bitsAvailable -= bits;
15291      if (this.bitsAvailable > 0) {
15292        this.word <<= bits;
15293      } else if (this.bytesAvailable > 0) {
15294        this.loadWord();
15295      } else {
15296        throw new Error('no bits available');
15297      }
15298      bits = size - bits;
15299      if (bits > 0 && this.bitsAvailable) {
15300        return valu << bits | this.readBits(bits);
15301      } else {
15302        return valu;
15303      }
15304    }
15305
15306    // ():uint
15307    ;
15308    _proto.skipLZ = function skipLZ() {
15309      var leadingZeroCount; // :uint
15310      for (leadingZeroCount = 0; leadingZeroCount < this.bitsAvailable; ++leadingZeroCount) {
15311        if ((this.word & 0x80000000 >>> leadingZeroCount) !== 0) {
15312          // the first bit of working word is 1
15313          this.word <<= leadingZeroCount;
15314          this.bitsAvailable -= leadingZeroCount;
15315          return leadingZeroCount;
15316        }
15317      }
15318      // we exhausted word and still have not found a 1
15319      this.loadWord();
15320      return leadingZeroCount + this.skipLZ();
15321    }
15322
15323    // ():void
15324    ;
15325    _proto.skipUEG = function skipUEG() {
15326      this.skipBits(1 + this.skipLZ());
15327    }
15328
15329    // ():void
15330    ;
15331    _proto.skipEG = function skipEG() {
15332      this.skipBits(1 + this.skipLZ());
15333    }
15334
15335    // ():uint
15336    ;
15337    _proto.readUEG = function readUEG() {
15338      var clz = this.skipLZ(); // :uint
15339      return this.readBits(clz + 1) - 1;
15340    }
15341
15342    // ():int
15343    ;
15344    _proto.readEG = function readEG() {
15345      var valu = this.readUEG(); // :int
15346      if (0x01 & valu) {
15347        // the number is odd if the low order bit is set
15348        return 1 + valu >>> 1; // add 1 to make it even, and divide by 2
15349      } else {
15350        return -1 * (valu >>> 1); // divide by two then make it negative
15351      }
15352    }
15353
15354    // Some convenience functions
15355    // :Boolean
15356    ;
15357    _proto.readBoolean = function readBoolean() {
15358      return this.readBits(1) === 1;
15359    }
15360
15361    // ():int
15362    ;
15363    _proto.readUByte = function readUByte() {
15364      return this.readBits(8);
15365    }
15366
15367    // ():int
15368    ;
15369    _proto.readUShort = function readUShort() {
15370      return this.readBits(16);
15371    }
15372
15373    // ():int
15374    ;
15375    _proto.readUInt = function readUInt() {
15376      return this.readBits(32);
15377    };
15378    return ExpGolomb;
15379  }();
15380
15381  var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
15382    function AvcVideoParser() {
15383      return _BaseVideoParser.apply(this, arguments) || this;
15384    }
15385    _inheritsLoose(AvcVideoParser, _BaseVideoParser);
15386    var _proto = AvcVideoParser.prototype;
15387    _proto.parsePES = function parsePES(track, textTrack, pes, endOfSegment) {
15388      var _this = this;
15389      var units = this.parseNALu(track, pes.data, endOfSegment);
15390      var VideoSample = this.VideoSample;
15391      var push;
15392      var spsfound = false;
15393      // free pes.data to save up some memory
15394      pes.data = null;
15395
15396      // if new NAL units found and last sample still there, let's push ...
15397      // this helps parsing streams with missing AUD (only do this if AUD never found)
15398      if (VideoSample && units.length && !track.audFound) {
15399        this.pushAccessUnit(VideoSample, track);
15400        VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts);
15401      }
15402      units.forEach(function (unit) {
15403        var _VideoSample2, _VideoSample3;
15404        switch (unit.type) {
15405          // NDR
15406          case 1:
15407            {
15408              var iskey = false;
15409              push = true;
15410              var data = unit.data;
15411              // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
15412              if (spsfound && data.length > 4) {
15413                // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
15414                var sliceType = _this.readSliceType(data);
15415                // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
15416                // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
15417                // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
15418                // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
15419                // if (sliceType === 2 || sliceType === 7) {
15420                if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
15421                  iskey = true;
15422                }
15423              }
15424              if (iskey) {
15425                var _VideoSample;
15426                // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
15427                if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
15428                  _this.pushAccessUnit(VideoSample, track);
15429                  VideoSample = _this.VideoSample = null;
15430                }
15431              }
15432              if (!VideoSample) {
15433                VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts);
15434              }
15435              VideoSample.frame = true;
15436              VideoSample.key = iskey;
15437              break;
15438              // IDR
15439            }
15440          case 5:
15441            push = true;
15442            // handle PES not starting with AUD
15443            // if we have frame data already, that cannot belong to the same frame, so force a push
15444            if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
15445              _this.pushAccessUnit(VideoSample, track);
15446              VideoSample = _this.VideoSample = null;
15447            }
15448            if (!VideoSample) {
15449              VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts);
15450            }
15451            VideoSample.key = true;
15452            VideoSample.frame = true;
15453            break;
15454          // SEI
15455          case 6:
15456            {
15457              push = true;
15458              parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
15459              break;
15460              // SPS
15461            }
15462          case 7:
15463            {
15464              var _track$pixelRatio, _track$pixelRatio2;
15465              push = true;
15466              spsfound = true;
15467              var sps = unit.data;
15468              var config = _this.readSPS(sps);
15469              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]) {
15470                track.width = config.width;
15471                track.height = config.height;
15472                track.pixelRatio = config.pixelRatio;
15473                track.sps = [sps];
15474                var codecarray = sps.subarray(1, 4);
15475                var codecstring = 'avc1.';
15476                for (var i = 0; i < 3; i++) {
15477                  var h = codecarray[i].toString(16);
15478                  if (h.length < 2) {
15479                    h = '0' + h;
15480                  }
15481                  codecstring += h;
15482                }
15483                track.codec = codecstring;
15484              }
15485              break;
15486            }
15487          // PPS
15488          case 8:
15489            push = true;
15490            track.pps = [unit.data];
15491            break;
15492          // AUD
15493          case 9:
15494            push = true;
15495            track.audFound = true;
15496            if ((_VideoSample3 = VideoSample) != null && _VideoSample3.frame) {
15497              _this.pushAccessUnit(VideoSample, track);
15498              VideoSample = null;
15499            }
15500            if (!VideoSample) {
15501              VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts);
15502            }
15503            break;
15504          // Filler Data
15505          case 12:
15506            push = true;
15507            break;
15508          default:
15509            push = false;
15510            break;
15511        }
15512        if (VideoSample && push) {
15513          var _units = VideoSample.units;
15514          _units.push(unit);
15515        }
15516      });
15517      // if last PES packet, push samples
15518      if (endOfSegment && VideoSample) {
15519        this.pushAccessUnit(VideoSample, track);
15520        this.VideoSample = null;
15521      }
15522    };
15523    _proto.getNALuType = function getNALuType(data, offset) {
15524      return data[offset] & 0x1f;
15525    };
15526    _proto.readSliceType = function readSliceType(data) {
15527      var eg = new ExpGolomb(data);
15528      // skip NALu type
15529      eg.readUByte();
15530      // discard first_mb_in_slice
15531      eg.readUEG();
15532      // return slice_type
15533      return eg.readUEG();
15534    }
15535
15536    /**
15536
15537     * The scaling list is optionally transmitted as part of a sequence parameter
15538     * set and is not relevant to transmuxing.
15539     * @param count the number of entries in this scaling list
15540     * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
15541     */;
15542    _proto.skipScalingList = function skipScalingList(count, reader) {
15543      var lastScale = 8;
15544      var nextScale = 8;
15545      var deltaScale;
15546      for (var j = 0; j < count; j++) {
15547        if (nextScale !== 0) {
15548          deltaScale = reader.readEG();
15549          nextScale = (lastScale + deltaScale + 256) % 256;
15550        }
15551        lastScale = nextScale === 0 ? lastScale : nextScale;
15552      }
15553    }
15554
15555    /**
15556     * Read a sequence parameter set and return some interesting video
15557     * properties. A sequence parameter set is the H264 metadata that
15558     * describes the properties of upcoming video frames.
15559     * @returns an object with configuration parsed from the
15560     * sequence parameter set, including the dimensions of the
15561     * associated video frames.
15562     */;
15563    _proto.readSPS = function readSPS(sps) {
15564      var eg = new ExpGolomb(sps);
15565      var frameCropLeftOffset = 0;
15566      var frameCropRightOffset = 0;
15567      var frameCropTopOffset = 0;
15568      var frameCropBottomOffset = 0;
15569      var numRefFramesInPicOrderCntCycle;
15570      var scalingListCount;
15571      var i;
15572      var readUByte = eg.readUByte.bind(eg);
15573      var readBits = eg.readBits.bind(eg);
15574      var readUEG = eg.readUEG.bind(eg);
15575      var readBoolean = eg.readBoolean.bind(eg);
15576      var skipBits = eg.skipBits.bind(eg);
15577      var skipEG = eg.skipEG.bind(eg);
15578      var skipUEG = eg.skipUEG.bind(eg);
15579      var skipScalingList = this.skipScalingList.bind(this);
15580      readUByte();
15581      var profileIdc = readUByte(); // profile_idc
15582      readBits(5);
vendor: 13,657 bytes, lines 15582-15952
15582 // profileCompat constraint_set[0-4]_flag, u(5)
15583      skipBits(3); // reserved_zero_3bits u(3),
15584      readUByte(); // level_idc u(8)
15585      skipUEG(); // seq_parameter_set_id
15586      // some profiles have more optional data we don't need
15587      if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
15588        var chromaFormatIdc = readUEG();
15589        if (chromaFormatIdc === 3) {
15590          skipBits(1);
15591        } // separate_colour_plane_flag
15592
15593        skipUEG(); // bit_depth_luma_minus8
15594        skipUEG(); // bit_depth_chroma_minus8
15595        skipBits(1); // qpprime_y_zero_transform_bypass_flag
15596        if (readBoolean()) {
15597          // seq_scaling_matrix_present_flag
15598          scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
15599          for (i = 0; i < scalingListCount; i++) {
15600            if (readBoolean()) {
15601              // seq_scaling_list_present_flag[ i ]
15602              if (i < 6) {
15603                skipScalingList(16, eg);
15604              } else {
15605                skipScalingList(64, eg);
15606              }
15607            }
15608          }
15609        }
15610      }
15611      skipUEG(); // log2_max_frame_num_minus4
15612      var picOrderCntType = readUEG();
15613      if (picOrderCntType === 0) {
15614        readUEG(); // log2_max_pic_order_cnt_lsb_minus4
15615      } else if (picOrderCntType === 1) {
15616        skipBits(1); // delta_pic_order_always_zero_flag
15617        skipEG(); // offset_for_non_ref_pic
15618        skipEG(); // offset_for_top_to_bottom_field
15619        numRefFramesInPicOrderCntCycle = readUEG();
15620        for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
15621          skipEG();
15622        } // offset_for_ref_frame[ i ]
15623      }
15624      skipUEG(); // max_num_ref_frames
15625      skipBits(1); // gaps_in_frame_num_value_allowed_flag
15626      var picWidthInMbsMinus1 = readUEG();
15627      var picHeightInMapUnitsMinus1 = readUEG();
15628      var frameMbsOnlyFlag = readBits(1);
15629      if (frameMbsOnlyFlag === 0) {
15630        skipBits(1);
15631      } // mb_adaptive_frame_field_flag
15632
15633      skipBits(1); // direct_8x8_inference_flag
15634      if (readBoolean()) {
15635        // frame_cropping_flag
15636        frameCropLeftOffset = readUEG();
15637        frameCropRightOffset = readUEG();
15638        frameCropTopOffset = readUEG();
15639        frameCropBottomOffset = readUEG();
15640      }
15641      var pixelRatio = [1, 1];
15642      if (readBoolean()) {
15643        // vui_parameters_present_flag
15644        if (readBoolean()) {
15645          // aspect_ratio_info_present_flag
15646          var aspectRatioIdc = readUByte();
15647          switch (aspectRatioIdc) {
15648            case 1:
15649              pixelRatio = [1, 1];
15650              break;
15651            case 2:
15652              pixelRatio = [12, 11];
15653              break;
15654            case 3:
15655              pixelRatio = [10, 11];
15656              break;
15657            case 4:
15658              pixelRatio = [16, 11];
15659              break;
15660            case 5:
15661              pixelRatio = [40, 33];
15662              break;
15663            case 6:
15664              pixelRatio = [24, 11];
15665              break;
15666            case 7:
15667              pixelRatio = [20, 11];
15668              break;
15669            case 8:
15670              pixelRatio = [32, 11];
15671              break;
15672            case 9:
15673              pixelRatio = [80, 33];
15674              break;
15675            case 10:
15676              pixelRatio = [18, 11];
15677              break;
15678            case 11:
15679              pixelRatio = [15, 11];
15680              break;
15681            case 12:
15682              pixelRatio = [64, 33];
15683              break;
15684            case 13:
15685              pixelRatio = [160, 99];
15686              break;
15687            case 14:
15688              pixelRatio = [4, 3];
15689              break;
15690            case 15:
15691              pixelRatio = [3, 2];
15692              break;
15693            case 16:
15694              pixelRatio = [2, 1];
15695              break;
15696            case 255:
15697              {
15698                pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
15699                break;
15700              }
15701          }
15702        }
15703      }
15704      return {
15705        width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
15706        height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
15707        pixelRatio: pixelRatio
15708      };
15709    };
15710    return AvcVideoParser;
15711  }(BaseVideoParser);
15712
15713  /**
15714   * SAMPLE-AES decrypter
15715   */
15716
15717  var SampleAesDecrypter = /*#__PURE__*/function () {
15718    function SampleAesDecrypter(observer, config, keyData) {
15719      this.keyData = void 0;
15720      this.decrypter = void 0;
15721      this.keyData = keyData;
15722      this.decrypter = new Decrypter(config, {
15723        removePKCS7Padding: false
15724      });
15725    }
15726    var _proto = SampleAesDecrypter.prototype;
15727    _proto.decryptBuffer = function decryptBuffer(encryptedData) {
15728      return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
15729    }
15730
15731    // AAC - encrypt all full 16 bytes blocks starting from offset 16
15732    ;
15733    _proto.decryptAacSample = function decryptAacSample(samples, sampleIndex, callback) {
15734      var _this = this;
15735      var curUnit = samples[sampleIndex].unit;
15736      if (curUnit.length <= 16) {
15737        // No encrypted portion in this sample (first 16 bytes is not
15738        // encrypted, see https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/HLS_Sample_Encryption/Encryption/Encryption.html),
15739        return;
15740      }
15741      var encryptedData = curUnit.subarray(16, curUnit.length - curUnit.length % 16);
15742      var encryptedBuffer = encryptedData.buffer.slice(encryptedData.byteOffset, encryptedData.byteOffset + encryptedData.length);
15743      this.decryptBuffer(encryptedBuffer).then(function (decryptedBuffer) {
15744        var decryptedData = new Uint8Array(decryptedBuffer);
15745        curUnit.set(decryptedData, 16);
15746        if (!_this.decrypter.isSync()) {
15747          _this.decryptAacSamples(samples, sampleIndex + 1, callback);
15748        }
15749      });
15750    };
15751    _proto.decryptAacSamples = function decryptAacSamples(samples, sampleIndex, callback) {
15752      for (;; sampleIndex++) {
15753        if (sampleIndex >= samples.length) {
15754          callback();
15755          return;
15756        }
15757        if (samples[sampleIndex].unit.length < 32) {
15758          continue;
15759        }
15760        this.decryptAacSample(samples, sampleIndex, callback);
15761        if (!this.decrypter.isSync()) {
15762          return;
15763        }
15764      }
15765    }
15766
15767    // AVC - encrypt one 16 bytes block out of ten, starting from offset 32
15768    ;
15769    _proto.getAvcEncryptedData = function getAvcEncryptedData(decodedData) {
15770      var encryptedDataLen = Math.floor((decodedData.length - 48) / 160) * 16 + 16;
15771      var encryptedData = new Int8Array(encryptedDataLen);
15772      var outputPos = 0;
15773      for (var inputPos = 32; inputPos < decodedData.length - 16; inputPos += 160, outputPos += 16) {
15774        encryptedData.set(decodedData.subarray(inputPos, inputPos + 16), outputPos);
15775      }
15776      return encryptedData;
15777    };
15778    _proto.getAvcDecryptedUnit = function getAvcDecryptedUnit(decodedData, decryptedData) {
15779      var uint8DecryptedData = new Uint8Array(decryptedData);
15780      var inputPos = 0;
15781      for (var outputPos = 32; outputPos < decodedData.length - 16; outputPos += 160, inputPos += 16) {
15782        decodedData.set(uint8DecryptedData.subarray(inputPos, inputPos + 16), outputPos);
15783      }
15784      return decodedData;
15785    };
15786    _proto.decryptAvcSample = function decryptAvcSample(samples, sampleIndex, unitIndex, callback, curUnit) {
15787      var _this2 = this;
15788      var decodedData = discardEPB(curUnit.data);
15789      var encryptedData = this.getAvcEncryptedData(decodedData);
15790      this.decryptBuffer(encryptedData.buffer).then(function (decryptedBuffer) {
15791        curUnit.data = _this2.getAvcDecryptedUnit(decodedData, decryptedBuffer);
15792        if (!_this2.decrypter.isSync()) {
15793          _this2.decryptAvcSamples(samples, sampleIndex, unitIndex + 1, callback);
15794        }
15795      });
15796    };
15797    _proto.decryptAvcSamples = function decryptAvcSamples(samples, sampleIndex, unitIndex, callback) {
15798      if (samples instanceof Uint8Array) {
15799        throw new Error('Cannot decrypt samples of type Uint8Array');
15800      }
15801      for (;; sampleIndex++, unitIndex = 0) {
15802        if (sampleIndex >= samples.length) {
15803          callback();
15804          return;
15805        }
15806        var curUnits = samples[sampleIndex].units;
15807        for (;; unitIndex++) {
15808          if (unitIndex >= curUnits.length) {
15809            break;
15810          }
15811          var curUnit = curUnits[unitIndex];
15812          if (curUnit.data.length <= 48 || curUnit.type !== 1 && curUnit.type !== 5) {
15813            continue;
15814          }
15815          this.decryptAvcSample(samples, sampleIndex, unitIndex, callback, curUnit);
15816          if (!this.decrypter.isSync()) {
15817            return;
15818          }
15819        }
15820      }
15821    };
15822    return SampleAesDecrypter;
15823  }();
15824
15825  var PACKET_LENGTH = 188;
15826  var TSDemuxer = /*#__PURE__*/function () {
15827    function TSDemuxer(observer, config, typeSupported, logger) {
15828      this.logger = void 0;
15829      this.observer = void 0;
15830      this.config = void 0;
15831      this.typeSupported = void 0;
15832      this.sampleAes = null;
15833      this.pmtParsed = false;
15834      this.audioCodec = void 0;
15835      this.videoCodec = void 0;
15836      this._pmtId = -1;
15837      this._videoTrack = void 0;
15838      this._audioTrack = void 0;
15839      this._id3Track = void 0;
15840      this._txtTrack = void 0;
15841      this.aacOverFlow = null;
15842      this.remainderData = null;
15843      this.videoParser = void 0;
15844      this.observer = observer;
15845      this.config = config;
15846      this.typeSupported = typeSupported;
15847      this.logger = logger;
15848      this.videoParser = null;
15849    }
15850    TSDemuxer.probe = function probe(data, logger) {
15851      var syncOffset = TSDemuxer.syncOffset(data);
15852      if (syncOffset > 0) {
15853        logger.warn("MPEG2-TS detected but first sync word found @ offset " + syncOffset);
15854      }
15855      return syncOffset !== -1;
15856    };
15857    TSDemuxer.syncOffset = function syncOffset(data) {
15858      var length = data.length;
15859      var scanwindow = Math.min(PACKET_LENGTH * 5, length - PACKET_LENGTH) + 1;
15860      var i = 0;
15861      while (i < scanwindow) {
15862        // a TS init segment should contain at least 2 TS packets: PAT and PMT, each starting with 0x47
15863        var foundPat = false;
15864        var packetStart = -1;
15865        var tsPackets = 0;
15866        for (var j = i; j < length; j += PACKET_LENGTH) {
15867          if (data[j] === 0x47 && (length - j === PACKET_LENGTH || data[j + PACKET_LENGTH] === 0x47)) {
15868            tsPackets++;
15869            if (packetStart === -1) {
15870              packetStart = j;
15871              // First sync word found at offset, increase scan length (#5251)
15872              if (packetStart !== 0) {
15873                scanwindow = Math.min(packetStart + PACKET_LENGTH * 99, data.length - PACKET_LENGTH) + 1;
15874              }
15875            }
15876            if (!foundPat) {
15877              foundPat = parsePID(data, j) === 0;
15878            }
15879            // Sync word found at 0 with 3 packets, or found at offset least 2 packets up to scanwindow (#5501)
15880            if (foundPat && tsPackets > 1 && (packetStart === 0 && tsPackets > 2 || j + PACKET_LENGTH > scanwindow)) {
15881              return packetStart;
15882            }
15883          } else if (tsPackets) {
15884            // Exit if sync word found, but does not contain contiguous packets
15885            return -1;
15886          } else {
15887            break;
15888          }
15889        }
15890        i++;
15891      }
15892      return -1;
15893    }
15894
15895    /**
15896     * Creates a track model internal to demuxer used to drive remuxing input
15897     */;
15898    TSDemuxer.createTrack = function createTrack(type, duration) {
15899      return {
15900        container: type === 'video' || type === 'audio' ? 'video/mp2t' : undefined,
15901        type: type,
15902        id: RemuxerTrackIdConfig[type],
15903        pid: -1,
15904        inputTimeScale: 90000,
15905        sequenceNumber: 0,
15906        samples: [],
15907        dropped: 0,
15908        duration: type === 'audio' ? duration : undefined
15909      };
15910    }
15911
15912    /**
15913     * Initializes a new init segment on the demuxer/remuxer interface. Needed for discontinuities/track-switches (or at stream start)
15914     * Resets all internal track instances of the demuxer.
15915     */;
15916    var _proto = TSDemuxer.prototype;
15917    _proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) {
15918      this.pmtParsed = false;
15919      this._pmtId = -1;
15920      this._videoTrack = TSDemuxer.createTrack('video');
15921      this._videoTrack.duration = trackDuration;
15922      this._audioTrack = TSDemuxer.createTrack('audio', trackDuration);
15923      this._id3Track = TSDemuxer.createTrack('id3');
15924      this._txtTrack = TSDemuxer.createTrack('text');
15925      this._audioTrack.segmentCodec = 'aac';
15926
15927      // flush any partial content
15928      this.aacOverFlow = null;
15929      this.remainderData = null;
15930      this.audioCodec = audioCodec;
15931      this.videoCodec = videoCodec;
15932    };
15933    _proto.resetTimeStamp = function resetTimeStamp() {};
15934    _proto.resetContiguity = function resetContiguity() {
15935      var _audioTrack = this._audioTrack,
15936        _videoTrack = this._videoTrack,
15937        _id3Track = this._id3Track;
15938      if (_audioTrack) {
15939        _audioTrack.pesData = null;
15940      }
15941      if (_videoTrack) {
15942        _videoTrack.pesData = null;
15943      }
15944      if (_id3Track) {
15945        _id3Track.pesData = null;
15946      }
15947      this.aacOverFlow = null;
15948      this.remainderData = null;
15949    };
15950    _proto.demux = function demux(data, timeOffset, isSampleAes, flush) {
15951      if (isSampleAes === void 0) {
15952        isSampleAes = false;
vendor: 21,279 bytes, lines 15953-16539
15953      }
15954      if (flush === void 0) {
15955        flush = false;
15956      }
15957      if (!isSampleAes) {
15958        this.sampleAes = null;
15959      }
15960      var pes;
15961      var videoTrack = this._videoTrack;
15962      var audioTrack = this._audioTrack;
15963      var id3Track = this._id3Track;
15964      var textTrack = this._txtTrack;
15965      var videoPid = videoTrack.pid;
15966      var videoData = videoTrack.pesData;
15967      var audioPid = audioTrack.pid;
15968      var id3Pid = id3Track.pid;
15969      var audioData = audioTrack.pesData;
15970      var id3Data = id3Track.pesData;
15971      var unknownPID = null;
15972      var pmtParsed = this.pmtParsed;
15973      var pmtId = this._pmtId;
15974      var len = data.length;
15975      if (this.remainderData) {
15976        data = appendUint8Array(this.remainderData, data);
15977        len = data.length;
15978        this.remainderData = null;
15979      }
15980      if (len < PACKET_LENGTH && !flush) {
15981        this.remainderData = data;
15982        return {
15983          audioTrack: audioTrack,
15984          videoTrack: videoTrack,
15985          id3Track: id3Track,
15986          textTrack: textTrack
15987        };
15988      }
15989      var syncOffset = Math.max(0, TSDemuxer.syncOffset(data));
15990      len -= (len - syncOffset) % PACKET_LENGTH;
15991      if (len < data.byteLength && !flush) {
15992        this.remainderData = new Uint8Array(data.buffer, len, data.buffer.byteLength - len);
15993      }
15994
15995      // loop through TS packets
15996      var tsPacketErrors = 0;
15997      for (var start = syncOffset; start < len; start += PACKET_LENGTH) {
15998        if (data[start] === 0x47) {
15999          var stt = !!(data[start + 1] & 0x40);
16000          var pid = parsePID(data, start);
16001          var atf = (data[start + 3] & 0x30) >> 4;
16002
16003          // if an adaption field is present, its length is specified by the fifth byte of the TS packet header.
16004          var offset = void 0;
16005          if (atf > 1) {
16006            offset = start + 5 + data[start + 4];
16007            // continue if there is only adaptation field
16008            if (offset === start + PACKET_LENGTH) {
16009              continue;
16010            }
16011          } else {
16012            offset = start + 4;
16013          }
16014          switch (pid) {
16015            case videoPid:
16016              if (stt) {
16017                if (videoData && (pes = parsePES(videoData, this.logger))) {
16018                  if (this.videoParser === null) {
16019                    switch (videoTrack.segmentCodec) {
16020                      case 'avc':
16021                        this.videoParser = new AvcVideoParser();
16022                        break;
16023                    }
16024                  }
16025                  if (this.videoParser !== null) {
16026                    this.videoParser.parsePES(videoTrack, textTrack, pes, false);
16027                  }
16028                }
16029                videoData = {
16030                  data: [],
16031                  size: 0
16032                };
16033              }
16034              if (videoData) {
16035                videoData.data.push(data.subarray(offset, start + PACKET_LENGTH));
16036                videoData.size += start + PACKET_LENGTH - offset;
16037              }
16038              break;
16039            case audioPid:
16040              if (stt) {
16041                if (audioData && (pes = parsePES(audioData, this.logger))) {
16042                  switch (audioTrack.segmentCodec) {
16043                    case 'aac':
16044                      this.parseAACPES(audioTrack, pes);
16045                      break;
16046                    case 'mp3':
16047                      this.parseMPEGPES(audioTrack, pes);
16048                      break;
16049                  }
16050                }
16051                audioData = {
16052                  data: [],
16053                  size: 0
16054                };
16055              }
16056              if (audioData) {
16057                audioData.data.push(data.subarray(offset, start + PACKET_LENGTH));
16058                audioData.size += start + PACKET_LENGTH - offset;
16059              }
16060              break;
16061            case id3Pid:
16062              if (stt) {
16063                if (id3Data && (pes = parsePES(id3Data, this.logger))) {
16064                  this.parseID3PES(id3Track, pes);
16065                }
16066                id3Data = {
16067                  data: [],
16068                  size: 0
16069                };
16070              }
16071              if (id3Data) {
16072                id3Data.data.push(data.subarray(offset, start + PACKET_LENGTH));
16073                id3Data.size += start + PACKET_LENGTH - offset;
16074              }
16075              break;
16076            case 0:
16077              if (stt) {
16078                offset += data[offset] + 1;
16079              }
16080              pmtId = this._pmtId = parsePAT(data, offset);
16081              // this.logger.log('PMT PID:'  + this._pmtId);
16082              break;
16083            case pmtId:
16084              {
16085                if (stt) {
16086                  offset += data[offset] + 1;
16087                }
16088                var parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes, this.observer, this.logger);
16089
16090                // only update track id if track PID found while parsing PMT
16091                // this is to avoid resetting the PID to -1 in case
16092                // track PID transiently disappears from the stream
16093                // this could happen in case of transient missing audio samples for example
16094                // NOTE this is only the PID of the track as found in TS,
16095                // but we are not using this for MP4 track IDs.
16096                videoPid = parsedPIDs.videoPid;
16097                if (videoPid > 0) {
16098                  videoTrack.pid = videoPid;
16099                  videoTrack.segmentCodec = parsedPIDs.segmentVideoCodec;
16100                }
16101                audioPid = parsedPIDs.audioPid;
16102                if (audioPid > 0) {
16103                  audioTrack.pid = audioPid;
16104                  audioTrack.segmentCodec = parsedPIDs.segmentAudioCodec;
16105                }
16106                id3Pid = parsedPIDs.id3Pid;
16107                if (id3Pid > 0) {
16108                  id3Track.pid = id3Pid;
16109                }
16110                if (unknownPID !== null && !pmtParsed) {
16111                  this.logger.warn("MPEG-TS PMT found at " + start + " after unknown PID '" + unknownPID + "'. Backtracking to sync byte @" + syncOffset + " to parse all TS packets.");
16112                  unknownPID = null;
16113                  // we set it to -188, the += 188 in the for loop will reset start to 0
16114                  start = syncOffset - 188;
16115                }
16116                pmtParsed = this.pmtParsed = true;
16117                break;
16118              }
16119            case 0x11:
16120            case 0x1fff:
16121              break;
16122            default:
16123              unknownPID = pid;
16124              break;
16125          }
16126        } else {
16127          tsPacketErrors++;
16128        }
16129      }
16130      if (tsPacketErrors > 0) {
16131        emitParsingError(this.observer, new Error("Found " + tsPacketErrors + " TS packet/s that do not start with 0x47"), undefined, this.logger);
16132      }
16133      videoTrack.pesData = videoData;
16134      audioTrack.pesData = audioData;
16135      id3Track.pesData = id3Data;
16136      var demuxResult = {
16137        audioTrack: audioTrack,
16138        videoTrack: videoTrack,
16139        id3Track: id3Track,
16140        textTrack: textTrack
16141      };
16142      if (flush) {
16143        this.extractRemainingSamples(demuxResult);
16144      }
16145      return demuxResult;
16146    };
16147    _proto.flush = function flush() {
16148      var remainderData = this.remainderData;
16149      this.remainderData = null;
16150      var result;
16151      if (remainderData) {
16152        result = this.demux(remainderData, -1, false, true);
16153      } else {
16154        result = {
16155          videoTrack: this._videoTrack,
16156          audioTrack: this._audioTrack,
16157          id3Track: this._id3Track,
16158          textTrack: this._txtTrack
16159        };
16160      }
16161      this.extractRemainingSamples(result);
16162      if (this.sampleAes) {
16163        return this.decrypt(result, this.sampleAes);
16164      }
16165      return result;
16166    };
16167    _proto.extractRemainingSamples = function extractRemainingSamples(demuxResult) {
16168      var audioTrack = demuxResult.audioTrack,
16169        videoTrack = demuxResult.videoTrack,
16170        id3Track = demuxResult.id3Track,
16171        textTrack = demuxResult.textTrack;
16172      var videoData = videoTrack.pesData;
16173      var audioData = audioTrack.pesData;
16174      var id3Data = id3Track.pesData;
16175      // try to parse last PES packets
16176      var pes;
16177      if (videoData && (pes = parsePES(videoData, this.logger))) {
16178        if (this.videoParser === null) {
16179          switch (videoTrack.segmentCodec) {
16180            case 'avc':
16181              this.videoParser = new AvcVideoParser();
16182              break;
16183          }
16184        }
16185        if (this.videoParser !== null) {
16186          this.videoParser.parsePES(videoTrack, textTrack, pes, true);
16187          videoTrack.pesData = null;
16188        }
16189      } else {
16190        // either avcData null or PES truncated, keep it for next frag parsing
16191        videoTrack.pesData = videoData;
16192      }
16193      if (audioData && (pes = parsePES(audioData, this.logger))) {
16194        switch (audioTrack.segmentCodec) {
16195          case 'aac':
16196            this.parseAACPES(audioTrack, pes);
16197            break;
16198          case 'mp3':
16199            this.parseMPEGPES(audioTrack, pes);
16200            break;
16201        }
16202        audioTrack.pesData = null;
16203      } else {
16204        if (audioData != null && audioData.size) {
16205          this.logger.log('last AAC PES packet truncated,might overlap between fragments');
16206        }
16207
16208        // either audioData null or PES truncated, keep it for next frag parsing
16209        audioTrack.pesData = audioData;
16210      }
16211      if (id3Data && (pes = parsePES(id3Data, this.logger))) {
16212        this.parseID3PES(id3Track, pes);
16213        id3Track.pesData = null;
16214      } else {
16215        // either id3Data null or PES truncated, keep it for next frag parsing
16216        id3Track.pesData = id3Data;
16217      }
16218    };
16219    _proto.demuxSampleAes = function demuxSampleAes(data, keyData, timeOffset) {
16220      var demuxResult = this.demux(data, timeOffset, true, !this.config.progressive);
16221      var sampleAes = this.sampleAes = new SampleAesDecrypter(this.observer, this.config, keyData);
16222      return this.decrypt(demuxResult, sampleAes);
16223    };
16224    _proto.decrypt = function decrypt(demuxResult, sampleAes) {
16225      return new Promise(function (resolve) {
16226        var audioTrack = demuxResult.audioTrack,
16227          videoTrack = demuxResult.videoTrack;
16228        if (audioTrack.samples && audioTrack.segmentCodec === 'aac') {
16229          sampleAes.decryptAacSamples(audioTrack.samples, 0, function () {
16230            if (videoTrack.samples) {
16231              sampleAes.decryptAvcSamples(videoTrack.samples, 0, 0, function () {
16232                resolve(demuxResult);
16233              });
16234            } else {
16235              resolve(demuxResult);
16236            }
16237          });
16238        } else if (videoTrack.samples) {
16239          sampleAes.decryptAvcSamples(videoTrack.samples, 0, 0, function () {
16240            resolve(demuxResult);
16241          });
16242        }
16243      });
16244    };
16245    _proto.destroy = function destroy() {
16246      if (this.observer) {
16247        this.observer.removeAllListeners();
16248      }
16249      // @ts-ignore
16250      this.config = this.logger = this.observer = null;
16251      this.aacOverFlow = this.videoParser = this.remainderData = this.sampleAes = null;
16252      this._videoTrack = this._audioTrack = this._id3Track = this._txtTrack = undefined;
16253    };
16254    _proto.parseAACPES = function parseAACPES(track, pes) {
16255      var startOffset = 0;
16256      var aacOverFlow = this.aacOverFlow;
16257      var data = pes.data;
16258      if (aacOverFlow) {
16259        this.aacOverFlow = null;
16260        var frameMissingBytes = aacOverFlow.missing;
16261        var sampleLength = aacOverFlow.sample.unit.byteLength;
16262        // logger.log(`AAC: append overflowing ${sampleLength} bytes to beginning of new PES`);
16263        if (frameMissingBytes === -1) {
16264          data = appendUint8Array(aacOverFlow.sample.unit, data);
16265        } else {
16266          var frameOverflowBytes = sampleLength - frameMissingBytes;
16267          aacOverFlow.sample.unit.set(data.subarray(0, frameMissingBytes), frameOverflowBytes);
16268          track.samples.push(aacOverFlow.sample);
16269          startOffset = aacOverFlow.missing;
16270        }
16271      }
16272      // look for ADTS header (0xFFFx)
16273      var offset;
16274      var len;
16275      for (offset = startOffset, len = data.length; offset < len - 1; offset++) {
16276        if (isHeader$1(data, offset)) {
16277          break;
16278        }
16279      }
16280      // if ADTS header does not start straight from the beginning of the PES payload, raise an error
16281      if (offset !== startOffset) {
16282        var reason;
16283        var recoverable = offset < len - 1;
16284        if (recoverable) {
16285          reason = "AAC PES did not start with ADTS header,offset:" + offset;
16286        } else {
16287          reason = 'No ADTS header found in AAC PES';
16288        }
16289        emitParsingError(this.observer, new Error(reason), recoverable, this.logger);
16290        if (!recoverable) {
16291          return;
16292        }
16293      }
16294      initTrackConfig(track, this.observer, data, offset, this.audioCodec);
16295      var pts;
16296      if (pes.pts !== undefined) {
16297        pts = pes.pts;
16298      } else if (aacOverFlow) {
16299        // if last AAC frame is overflowing, we should ensure timestamps are contiguous:
16300        // first sample PTS should be equal to last sample PTS + frameDuration
16301        var frameDuration = getFrameDuration(track.samplerate);
16302        pts = aacOverFlow.sample.pts + frameDuration;
16303      } else {
16304        this.logger.warn('[tsdemuxer]: AAC PES unknown PTS');
16305        return;
16306      }
16307
16308      // scan for aac samples
16309      var frameIndex = 0;
16310      var frame;
16311      while (offset < len) {
16312        frame = appendFrame$1(track, data, offset, pts, frameIndex);
16313        offset += frame.length;
16314        if (!frame.missing) {
16315          frameIndex++;
16316          for (; offset < len - 1; offset++) {
16317            if (isHeader$1(data, offset)) {
16318              break;
16319            }
16320          }
16321        } else {
16322          this.aacOverFlow = frame;
16323          break;
16324        }
16325      }
16326    };
16327    _proto.parseMPEGPES = function parseMPEGPES(track, pes) {
16328      var data = pes.data;
16329      var length = data.length;
16330      var frameIndex = 0;
16331      var offset = 0;
16332      var pts = pes.pts;
16333      if (pts === undefined) {
16334        this.logger.warn('[tsdemuxer]: MPEG PES unknown PTS');
16335        return;
16336      }
16337      while (offset < length) {
16338        if (isHeader(data, offset)) {
16339          var frame = appendFrame(track, data, offset, pts, frameIndex);
16340          if (frame) {
16341            offset += frame.length;
16342            frameIndex++;
16343          } else {
16344            // logger.log('Unable to parse Mpeg audio frame');
16345            break;
16346          }
16347        } else {
16348          // nothing found, keep looking
16349          offset++;
16350        }
16351      }
16352    };
16353    _proto.parseAC3PES = function parseAC3PES(track, pes) {
16354    };
16355    _proto.parseID3PES = function parseID3PES(id3Track, pes) {
16356      if (pes.pts === undefined) {
16357        this.logger.warn('[tsdemuxer]: ID3 PES unknown PTS');
16358        return;
16359      }
16360      var id3Sample = _extends({}, pes, {
16361        type: this._videoTrack ? MetadataSchema.emsg : MetadataSchema.audioId3,
16362        duration: Number.POSITIVE_INFINITY
16363      });
16364      id3Track.samples.push(id3Sample);
16365    };
16366    return TSDemuxer;
16367  }();
16368  function parsePID(data, offset) {
16369    // pid is a 13-bit field starting at the last bit of TS[1]
16370    return ((data[offset + 1] & 0x1f) << 8) + data[offset + 2];
16371  }
16372  function parsePAT(data, offset) {
16373    // skip the PSI header and parse the first PMT entry
16374    return (data[offset + 10] & 0x1f) << 8 | data[offset + 11];
16375  }
16376  function parsePMT(data, offset, typeSupported, isSampleAes, observer, logger) {
16377    var result = {
16378      audioPid: -1,
16379      videoPid: -1,
16380      id3Pid: -1,
16381      segmentVideoCodec: 'avc',
16382      segmentAudioCodec: 'aac'
16383    };
16384    var sectionLength = (data[offset + 1] & 0x0f) << 8 | data[offset + 2];
16385    var tableEnd = offset + 3 + sectionLength - 4;
16386    // to determine where the table is, we have to figure out how
16387    // long the program info descriptors are
16388    var programInfoLength = (data[offset + 10] & 0x0f) << 8 | data[offset + 11];
16389    // advance the offset to the first entry in the mapping table
16390    offset += 12 + programInfoLength;
16391    while (offset < tableEnd) {
16392      var pid = parsePID(data, offset);
16393      var esInfoLength = (data[offset + 3] & 0x0f) << 8 | data[offset + 4];
16394      switch (data[offset]) {
16395        case 0xcf:
16396          // SAMPLE-AES AAC
16397          if (!isSampleAes) {
16398            logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC', logger);
16399            break;
16400          }
16401        /* falls through */
16402        case 0x0f:
16403          // ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio)
16404          // logger.log('AAC PID:'  + pid);
16405          if (result.audioPid === -1) {
16406            result.audioPid = pid;
16407          }
16408          break;
16409
16410        // Packetized metadata (ID3)
16411        case 0x15:
16412          // logger.log('ID3 PID:'  + pid);
16413          if (result.id3Pid === -1) {
16414            result.id3Pid = pid;
16415          }
16416          break;
16417        case 0xdb:
16418          // SAMPLE-AES AVC
16419          if (!isSampleAes) {
16420            logEncryptedSamplesFoundInUnencryptedStream('H.264', logger);
16421            break;
16422          }
16423        /* falls through */
16424        case 0x1b:
16425          // ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video)
16426          // logger.log('AVC PID:'  + pid);
16427          if (result.videoPid === -1) {
16428            result.videoPid = pid;
16429            result.segmentVideoCodec = 'avc';
16430          }
16431          break;
16432
16433        // ISO/IEC 11172-3 (MPEG-1 audio)
16434        // or ISO/IEC 13818-3 (MPEG-2 halved sample rate audio)
16435        case 0x03:
16436        case 0x04:
16437          // logger.log('MPEG PID:'  + pid);
16438          if (!typeSupported.mpeg && !typeSupported.mp3) {
16439            logger.log('MPEG audio found, not supported in this browser');
16440          } else if (result.audioPid === -1) {
16441            result.audioPid = pid;
16442            result.segmentAudioCodec = 'mp3';
16443          }
16444          break;
16445        case 0xc1:
16446          // SAMPLE-AES AC3
16447          if (!isSampleAes) {
16448            logEncryptedSamplesFoundInUnencryptedStream('AC-3', logger);
16449            break;
16450          }
16451        /* falls through */
16452        case 0x81:
16453          {
16454            logger.warn('AC-3 in M2TS support not included in build');
16455          }
16456          break;
16457        case 0x06:
16458          // stream_type 6 can mean a lot of different things in case of DVB.
16459          // We need to look at the descriptors. Right now, we're only interested
16460          // in AC-3 audio, so we do the descriptor parsing only when we don't have
16461          // an audio PID yet.
16462          if (result.audioPid === -1 && esInfoLength > 0) {
16463            var parsePos = offset + 5;
16464            var remaining = esInfoLength;
16465            while (remaining > 2) {
16466              var descriptorId = data[parsePos];
16467              switch (descriptorId) {
16468                case 0x6a:
16469                  // DVB Descriptor for AC-3
16470                  {
16471                    logger.warn('AC-3 in M2TS support not included in build');
16472                  }
16473                  break;
16474              }
16475              var descriptorLen = data[parsePos + 1] + 2;
16476              parsePos += descriptorLen;
16477              remaining -= descriptorLen;
16478            }
16479          }
16480          break;
16481        case 0xc2: // SAMPLE-AES EC3
16482        /* falls through */
16483        case 0x87:
16484          emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'), undefined, logger);
16485          return result;
16486        case 0x24:
16487          // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
16488          {
16489            emitParsingError(observer, new Error('Unsupported HEVC in M2TS found'), undefined, logger);
16490            return result;
16491          }
16492      }
16493      // move to the next table entry
16494      // skip past the elementary stream descriptors, if present
16495      offset += esInfoLength + 5;
16496    }
16497    return result;
16498  }
16499  function emitParsingError(observer, error, levelRetry, logger) {
16500    logger.warn("parsing error: " + error.message);
16501    observer.emit(Events.ERROR, Events.ERROR, {
16502      type: ErrorTypes.MEDIA_ERROR,
16503      details: ErrorDetails.FRAG_PARSING_ERROR,
16504      fatal: false,
16505      levelRetry: levelRetry,
16506      error: error,
16507      reason: error.message
16508    });
16509  }
16510  function logEncryptedSamplesFoundInUnencryptedStream(type, logger) {
16511    logger.log(type + " with AES-128-CBC encryption found in unencrypted stream");
16512  }
16513  function parsePES(stream, logger) {
16514    var i = 0;
16515    var frag;
16516    var pesLen;
16517    var pesHdrLen;
16518    var pesPts;
16519    var pesDts;
16520    var data = stream.data;
16521    // safety check
16522    if (!stream || stream.size === 0) {
16523      return null;
16524    }
16525
16526    // we might need up to 19 bytes to read PES header
16527    // if first chunk of data is less than 19 bytes, let's merge it with following ones until we get 19 bytes
16528    // usually only one merge is needed (and this is rare ...)
16529    while (data[0].length < 19 && data.length > 1) {
16530      data[0] = appendUint8Array(data[0], data[1]);
16531      data.splice(1, 1);
16532    }
16533    // retrieve PTS/DTS from first fragment
16534    frag = data[0];
16535    var pesPrefix = (frag[0] << 16) + (frag[1] << 8) + frag[2];
16536    if (pesPrefix === 1) {
16537      pesLen = (frag[4] << 8) + frag[5];
16538      // if PES parsed length is not zero and greater than total received length, stop parsing. PES might be truncated
16539      // minus 6 : PES header size
vendor: 4,104 bytes, lines 16540-16654
16540      if (pesLen && pesLen > stream.size - 6) {
16541        return null;
16542      }
16543      var pesFlags = frag[7];
16544      if (pesFlags & 0xc0) {
16545        /* PES header described here : http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
16546            as PTS / DTS is 33 bit we cannot use bitwise operator in JS,
16547            as Bitwise operators treat their operands as a sequence of 32 bits */
16548        pesPts = (frag[9] & 0x0e) * 536870912 +
16549        // 1 << 29
16550        (frag[10] & 0xff) * 4194304 +
16551        // 1 << 22
16552        (frag[11] & 0xfe) * 16384 +
16553        // 1 << 14
16554        (frag[12] & 0xff) * 128 +
16555        // 1 << 7
16556        (frag[13] & 0xfe) / 2;
16557        if (pesFlags & 0x40) {
16558          pesDts = (frag[14] & 0x0e) * 536870912 +
16559          // 1 << 29
16560          (frag[15] & 0xff) * 4194304 +
16561          // 1 << 22
16562          (frag[16] & 0xfe) * 16384 +
16563          // 1 << 14
16564          (frag[17] & 0xff) * 128 +
16565          // 1 << 7
16566          (frag[18] & 0xfe) / 2;
16567          if (pesPts - pesDts > 60 * 90000) {
16568            logger.warn(Math.round((pesPts - pesDts) / 90000) + "s delta between PTS and DTS, align them");
16569            pesPts = pesDts;
16570          }
16571        } else {
16572          pesDts = pesPts;
16573        }
16574      }
16575      pesHdrLen = frag[8];
16576      // 9 bytes : 6 bytes for PES header + 3 bytes for PES extension
16577      var payloadStartOffset = pesHdrLen + 9;
16578      if (stream.size <= payloadStartOffset) {
16579        return null;
16580      }
16581      stream.size -= payloadStartOffset;
16582      // reassemble PES packet
16583      var pesData = new Uint8Array(stream.size);
16584      for (var j = 0, dataLen = data.length; j < dataLen; j++) {
16585        frag = data[j];
16586        var len = frag.byteLength;
16587        if (payloadStartOffset) {
16588          if (payloadStartOffset > len) {
16589            // trim full frag if PES header bigger than frag
16590            payloadStartOffset -= len;
16591            continue;
16592          } else {
16593            // trim partial frag if PES header smaller than frag
16594            frag = frag.subarray(payloadStartOffset);
16595            len -= payloadStartOffset;
16596            payloadStartOffset = 0;
16597          }
16598        }
16599        pesData.set(frag, i);
16600        i += len;
16601      }
16602      if (pesLen) {
16603        // payload size : remove PES header + PES extension
16604        pesLen -= pesHdrLen + 3;
16605      }
16606      return {
16607        data: pesData,
16608        pts: pesPts,
16609        dts: pesDts,
16610        len: pesLen
16611      };
16612    }
16613    return null;
16614  }
16615
16616  var MP3Demuxer = /*#__PURE__*/function (_BaseAudioDemuxer) {
16617    function MP3Demuxer() {
16618      return _BaseAudioDemuxer.apply(this, arguments) || this;
16619    }
16620    _inheritsLoose(MP3Demuxer, _BaseAudioDemuxer);
16621    var _proto = MP3Demuxer.prototype;
16622    _proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, trackDuration) {
16623      _BaseAudioDemuxer.prototype.resetInitSegment.call(this, initSegment, audioCodec, videoCodec, trackDuration);
16624      this._audioTrack = {
16625        container: 'audio/mpeg',
16626        type: 'audio',
16627        id: 2,
16628        pid: -1,
16629        sequenceNumber: 0,
16630        segmentCodec: 'mp3',
16631        samples: [],
16632        manifestCodec: audioCodec,
16633        duration: trackDuration,
16634        inputTimeScale: 90000,
16635        dropped: 0
16636      };
16637    };
16638    MP3Demuxer.probe = function probe$1(data) {
16639      if (!data) {
16640        return false;
16641      }
16642
16643      // check if data contains ID3 timestamp and MPEG sync word
16644      // Look for MPEG header | 1111 1111 | 111X XYZX | where X can be either 0 or 1 and Y or Z should be 1
16645      // Layer bits (position 14 and 15) in header should be always different from 0 (Layer I or Layer II or Layer III)
16646      // More info http://www.mp3-tech.org/programmer/frame_header.html
16647      var id3Data = getId3Data(data, 0);
16648      var offset = (id3Data == null ? void 0 : id3Data.length) || 0;
16649
16650      // Check for ac-3|ec-3 sync bytes and return false if present
16651      if (id3Data && data[offset] === 0x0b && data[offset + 1] === 0x77 && getId3Timestamp(id3Data) !== undefined &&
16652      // check the bsid to confirm ac-3 or ec-3 (not mp3)
16653      getAudioBSID(data, offset) <= 16) {
16654        return false;
vendor: 10,708 bytes, lines 16655-16941
16655      }
16656      for (var length = data.length; offset < length; offset++) {
16657        if (probe(data, offset)) {
16658          logger.log('MPEG Audio sync word found !');
16659          return true;
16660        }
16661      }
16662      return false;
16663    };
16664    _proto.canParse = function canParse$1(data, offset) {
16665      return canParse(data, offset);
16666    };
16667    _proto.appendFrame = function appendFrame$1(track, data, offset) {
16668      if (this.basePTS === null) {
16669        return;
16670      }
16671      return appendFrame(track, data, offset, this.basePTS, this.frameIndex);
16672    };
16673    return MP3Demuxer;
16674  }(BaseAudioDemuxer);
16675
16676  /**
16677   *  AAC helper
16678   */
16679  var AAC = /*#__PURE__*/function () {
16680    function AAC() {}
16681    AAC.getSilentFrame = function getSilentFrame(codec, channelCount) {
16682      switch (codec) {
16683        case 'mp4a.40.2':
16684          if (channelCount === 1) {
16685            return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x23, 0x80]);
16686          } else if (channelCount === 2) {
16687            return new Uint8Array([0x21, 0x00, 0x49, 0x90, 0x02, 0x19, 0x00, 0x23, 0x80]);
16688          } else if (channelCount === 3) {
16689            return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x8e]);
16690          } else if (channelCount === 4) {
16691            return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x80, 0x2c, 0x80, 0x08, 0x02, 0x38]);
16692          } else if (channelCount === 5) {
16693            return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x38]);
16694          } else if (channelCount === 6) {
16695            return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x00, 0xb2, 0x00, 0x20, 0x08, 0xe0]);
16696          }
16697          break;
16698        // handle HE-AAC below (mp4a.40.5 / mp4a.40.29)
16699        default:
16700          if (channelCount === 1) {
16701            // ffmpeg -y -f lavfi -i "aevalsrc=0:d=0.05" -c:a libfdk_aac -profile:a aac_he -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac
16702            return new Uint8Array([0x1, 0x40, 0x22, 0x80, 0xa3, 0x4e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x1c, 0x6, 0xf1, 0xc1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e]);
16703          } else if (channelCount === 2) {
16704            // ffmpeg -y -f lavfi -i "aevalsrc=0|0:d=0.05" -c:a libfdk_aac -profile:a aac_he_v2 -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac
16705            return new Uint8Array([0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e]);
16706          } else if (channelCount === 3) {
16707            // ffmpeg -y -f lavfi -i "aevalsrc=0|0|0:d=0.05" -c:a libfdk_aac -profile:a aac_he_v2 -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac
16708            return new Uint8Array([0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e]);
16709          }
16710          break;
16711      }
16712      return undefined;
16713    };
16714    return AAC;
16715  }();
16716
16717  /**
16718   * Generate MP4 Box
16719   */
16720
16721  var UINT32_MAX = Math.pow(2, 32) - 1;
16722  var MP4 = /*#__PURE__*/function () {
16723    function MP4() {}
16724    MP4.init = function init() {
16725      MP4.types = {
16726        avc1: [],
16727        // codingname
16728        avcC: [],
16729        hvc1: [],
16730        hvcC: [],
16731        btrt: [],
16732        dinf: [],
16733        dref: [],
16734        esds: [],
16735        ftyp: [],
16736        hdlr: [],
16737        mdat: [],
16738        mdhd: [],
16739        mdia: [],
16740        mfhd: [],
16741        minf: [],
16742        moof: [],
16743        moov: [],
16744        mp4a: [],
16745        '.mp3': [],
16746        dac3: [],
16747        'ac-3': [],
16748        mvex: [],
16749        mvhd: [],
16750        pasp: [],
16751        sdtp: [],
16752        stbl: [],
16753        stco: [],
16754        stsc: [],
16755        stsd: [],
16756        stsz: [],
16757        stts: [],
16758        tfdt: [],
16759        tfhd: [],
16760        traf: [],
16761        trak: [],
16762        trun: [],
16763        trex: [],
16764        tkhd: [],
16765        vmhd: [],
16766        smhd: []
16767      };
16768      var i;
16769      for (i in MP4.types) {
16770        if (MP4.types.hasOwnProperty(i)) {
16771          MP4.types[i] = [i.charCodeAt(0), i.charCodeAt(1), i.charCodeAt(2), i.charCodeAt(3)];
16772        }
16773      }
16774      var videoHdlr = new Uint8Array([0x00,
16775      // version 0
16776      0x00, 0x00, 0x00,
16777      // flags
16778      0x00, 0x00, 0x00, 0x00,
16779      // pre_defined
16780      0x76, 0x69, 0x64, 0x65,
16781      // handler_type: 'vide'
16782      0x00, 0x00, 0x00, 0x00,
16783      // reserved
16784      0x00, 0x00, 0x00, 0x00,
16785      // reserved
16786      0x00, 0x00, 0x00, 0x00,
16787      // reserved
16788      0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler'
16789      ]);
16790      var audioHdlr = new Uint8Array([0x00,
16791      // version 0
16792      0x00, 0x00, 0x00,
16793      // flags
16794      0x00, 0x00, 0x00, 0x00,
16795      // pre_defined
16796      0x73, 0x6f, 0x75, 0x6e,
16797      // handler_type: 'soun'
16798      0x00, 0x00, 0x00, 0x00,
16799      // reserved
16800      0x00, 0x00, 0x00, 0x00,
16801      // reserved
16802      0x00, 0x00, 0x00, 0x00,
16803      // reserved
16804      0x53, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler'
16805      ]);
16806      MP4.HDLR_TYPES = {
16807        video: videoHdlr,
16808        audio: audioHdlr
16809      };
16810      var dref = new Uint8Array([0x00,
16811      // version 0
16812      0x00, 0x00, 0x00,
16813      // flags
16814      0x00, 0x00, 0x00, 0x01,
16815      // entry_count
16816      0x00, 0x00, 0x00, 0x0c,
16817      // entry_size
16818      0x75, 0x72, 0x6c, 0x20,
16819      // 'url' type
16820      0x00,
16821      // version 0
16822      0x00, 0x00, 0x01 // entry_flags
16823      ]);
16824      var stco = new Uint8Array([0x00,
16825      // version
16826      0x00, 0x00, 0x00,
16827      // flags
16828      0x00, 0x00, 0x00, 0x00 // entry_count
16829      ]);
16830      MP4.STTS = MP4.STSC = MP4.STCO = stco;
16831      MP4.STSZ = new Uint8Array([0x00,
16832      // version
16833      0x00, 0x00, 0x00,
16834      // flags
16835      0x00, 0x00, 0x00, 0x00,
16836      // sample_size
16837      0x00, 0x00, 0x00, 0x00 // sample_count
16838      ]);
16839      MP4.VMHD = new Uint8Array([0x00,
16840      // version
16841      0x00, 0x00, 0x01,
16842      // flags
16843      0x00, 0x00,
16844      // graphicsmode
16845      0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // opcolor
16846      ]);
16847      MP4.SMHD = new Uint8Array([0x00,
16848      // version
16849      0x00, 0x00, 0x00,
16850      // flags
16851      0x00, 0x00,
16852      // balance
16853      0x00, 0x00 // reserved
16854      ]);
16855      MP4.STSD = new Uint8Array([0x00,
16856      // version 0
16857      0x00, 0x00, 0x00,
16858      // flags
16859      0x00, 0x00, 0x00, 0x01]); // entry_count
16860
16861      var majorBrand = new Uint8Array([105, 115, 111, 109]); // isom
16862      var avc1Brand = new Uint8Array([97, 118, 99, 49]); // avc1
16863      var minorVersion = new Uint8Array([0, 0, 0, 1]);
16864      MP4.FTYP = MP4.box(MP4.types.ftyp, majorBrand, minorVersion, majorBrand, avc1Brand);
16865      MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref));
16866    };
16867    MP4.box = function box(type) {
16868      var size = 8;
16869      for (var _len = arguments.length, payload = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
16870        payload[_key - 1] = arguments[_key];
16871      }
16872      var i = payload.length;
16873      var len = i;
16874      // calculate the total size we need to allocate
16875      while (i--) {
16876        size += payload[i].byteLength;
16877      }
16878      var result = new Uint8Array(size);
16879      result[0] = size >> 24 & 0xff;
16880      result[1] = size >> 16 & 0xff;
16881      result[2] = size >> 8 & 0xff;
16882      result[3] = size & 0xff;
16883      result.set(type, 4);
16884      // copy the payload into the result
16885      for (i = 0, size = 8; i < len; i++) {
16886        // copy payload[i] array @ offset size
16887        result.set(payload[i], size);
16888        size += payload[i].byteLength;
16889      }
16890      return result;
16891    };
16892    MP4.hdlr = function hdlr(type) {
16893      return MP4.box(MP4.types.hdlr, MP4.HDLR_TYPES[type]);
16894    };
16895    MP4.mdat = function mdat(data) {
16896      return MP4.box(MP4.types.mdat, data);
16897    };
16898    MP4.mdhd = function mdhd(timescale, duration) {
16899      duration *= timescale;
16900      var upperWordDuration = Math.floor(duration / (UINT32_MAX + 1));
16901      var lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1));
16902      return MP4.box(MP4.types.mdhd, new Uint8Array([0x01,
16903      // version 1
16904      0x00, 0x00, 0x00,
16905      // flags
16906      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
16907      // creation_time
16908      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
16909      // modification_time
16910      timescale >> 24 & 0xff, timescale >> 16 & 0xff, timescale >> 8 & 0xff, timescale & 0xff,
16911      // timescale
16912      upperWordDuration >> 24, upperWordDuration >> 16 & 0xff, upperWordDuration >> 8 & 0xff, upperWordDuration & 0xff, lowerWordDuration >> 24, lowerWordDuration >> 16 & 0xff, lowerWordDuration >> 8 & 0xff, lowerWordDuration & 0xff, 0x55, 0xc4,
16913      // 'und' language (undetermined)
16914      0x00, 0x00]));
16915    };
16916    MP4.mdia = function mdia(track) {
16917      return MP4.box(MP4.types.mdia, MP4.mdhd(track.timescale, track.duration), MP4.hdlr(track.type), MP4.minf(track));
16918    };
16919    MP4.mfhd = function mfhd(sequenceNumber) {
16920      return MP4.box(MP4.types.mfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00,
16921      // flags
16922      sequenceNumber >> 24, sequenceNumber >> 16 & 0xff, sequenceNumber >> 8 & 0xff, sequenceNumber & 0xff // sequence_number
16923      ]));
16924    };
16925    MP4.minf = function minf(track) {
16926      if (track.type === 'audio') {
16927        return MP4.box(MP4.types.minf, MP4.box(MP4.types.smhd, MP4.SMHD), MP4.DINF, MP4.stbl(track));
16928      } else {
16929        return MP4.box(MP4.types.minf, MP4.box(MP4.types.vmhd, MP4.VMHD), MP4.DINF, MP4.stbl(track));
16930      }
16931    };
16932    MP4.moof = function moof(sn, baseMediaDecodeTime, track) {
16933      return MP4.box(MP4.types.moof, MP4.mfhd(sn), MP4.traf(track, baseMediaDecodeTime));
16934    };
16935    MP4.moov = function moov(tracks) {
16936      var i = tracks.length;
16937      var boxes = [];
16938      while (i--) {
16939        boxes[i] = MP4.trak(tracks[i]);
16940      }
16941      return MP4.box.apply(null, [MP4.types.moov, MP4.mvhd(tracks[0].timescale, tracks[0].duration
vendor: 5,355 bytes, lines 16941-17087
16941)].concat(boxes).concat(MP4.mvex(tracks)));
16942    };
16943    MP4.mvex = function mvex(tracks) {
16944      var i = tracks.length;
16945      var boxes = [];
16946      while (i--) {
16947        boxes[i] = MP4.trex(tracks[i]);
16948      }
16949      return MP4.box.apply(null, [MP4.types.mvex].concat(boxes));
16950    };
16951    MP4.mvhd = function mvhd(timescale, duration) {
16952      duration *= timescale;
16953      var upperWordDuration = Math.floor(duration / (UINT32_MAX + 1));
16954      var lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1));
16955      var bytes = new Uint8Array([0x01,
16956      // version 1
16957      0x00, 0x00, 0x00,
16958      // flags
16959      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
16960      // creation_time
16961      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
16962      // modification_time
16963      timescale >> 24 & 0xff, timescale >> 16 & 0xff, timescale >> 8 & 0xff, timescale & 0xff,
16964      // timescale
16965      upperWordDuration >> 24, upperWordDuration >> 16 & 0xff, upperWordDuration >> 8 & 0xff, upperWordDuration & 0xff, lowerWordDuration >> 24, lowerWordDuration >> 16 & 0xff, lowerWordDuration >> 8 & 0xff, lowerWordDuration & 0xff, 0x00, 0x01, 0x00, 0x00,
16966      // 1.0 rate
16967      0x01, 0x00,
16968      // 1.0 volume
16969      0x00, 0x00,
16970      // reserved
16971      0x00, 0x00, 0x00, 0x00,
16972      // reserved
16973      0x00, 0x00, 0x00, 0x00,
16974      // reserved
16975      0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
16976      // transformation: unity matrix
16977      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16978      // pre_defined
16979      0xff, 0xff, 0xff, 0xff // next_track_ID
16980      ]);
16981      return MP4.box(MP4.types.mvhd, bytes);
16982    };
16983    MP4.sdtp = function sdtp(track) {
16984      var samples = track.samples || [];
16985      var bytes = new Uint8Array(4 + samples.length);
16986      var i;
16987      var flags;
16988      // leave the full box header (4 bytes) all zero
16989      // write the sample table
16990      for (i = 0; i < samples.length; i++) {
16991        flags = samples[i].flags;
16992        bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy;
16993      }
16994      return MP4.box(MP4.types.sdtp, bytes);
16995    };
16996    MP4.stbl = function stbl(track) {
16997      return MP4.box(MP4.types.stbl, MP4.stsd(track), MP4.box(MP4.types.stts, MP4.STTS), MP4.box(MP4.types.stsc, MP4.STSC), MP4.box(MP4.types.stsz, MP4.STSZ), MP4.box(MP4.types.stco, MP4.STCO));
16998    };
16999    MP4.avc1 = function avc1(track) {
17000      var sps = [];
17001      var pps = [];
17002      var i;
17003      var data;
17004      var len;
17005      // assemble the SPSs
17006
17007      for (i = 0; i < track.sps.length; i++) {
17008        data = track.sps[i];
17009        len = data.byteLength;
17010        sps.push(len >>> 8 & 0xff);
17011        sps.push(len & 0xff);
17012
17013        // SPS
17014        sps = sps.concat(Array.prototype.slice.call(data));
17015      }
17016
17017      // assemble the PPSs
17018      for (i = 0; i < track.pps.length; i++) {
17019        data = track.pps[i];
17020        len = data.byteLength;
17021        pps.push(len >>> 8 & 0xff);
17022        pps.push(len & 0xff);
17023        pps = pps.concat(Array.prototype.slice.call(data));
17024      }
17025      var avcc = MP4.box(MP4.types.avcC, new Uint8Array([0x01,
17026      // version
17027      sps[3],
17028      // profile
17029      sps[4],
17030      // profile compat
17031      sps[5],
17032      // level
17033      0xfc | 3,
17034      // lengthSizeMinusOne, hard-coded to 4 bytes
17035      0xe0 | track.sps.length // 3bit reserved (111) + numOfSequenceParameterSets
17036      ].concat(sps).concat([track.pps.length // numOfPictureParameterSets
17037      ]).concat(pps))); // "PPS"
17038      var width = track.width;
17039      var height = track.height;
17040      var hSpacing = track.pixelRatio[0];
17041      var vSpacing = track.pixelRatio[1];
17042      return MP4.box(MP4.types.avc1, new Uint8Array([0x00, 0x00, 0x00,
17043      // reserved
17044      0x00, 0x00, 0x00,
17045      // reserved
17046      0x00, 0x01,
17047      // data_reference_index
17048      0x00, 0x00,
17049      // pre_defined
17050      0x00, 0x00,
17051      // reserved
17052      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17053      // pre_defined
17054      width >> 8 & 0xff, width & 0xff,
17055      // width
17056      height >> 8 & 0xff, height & 0xff,
17057      // height
17058      0x00, 0x48, 0x00, 0x00,
17059      // horizresolution
17060      0x00, 0x48, 0x00, 0x00,
17061      // vertresolution
17062      0x00, 0x00, 0x00, 0x00,
17063      // reserved
17064      0x00, 0x01,
17065      // frame_count
17066      0x12, 0x64, 0x61, 0x69, 0x6c,
17067      // dailymotion/hls.js
17068      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,
17069      // compressorname
17070      0x00, 0x18,
17071      // depth = 24
17072      0x11, 0x11]),
17073      // pre_defined = -1
17074      avcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
17075      // bufferSizeDB
17076      0x00, 0x2d, 0xc6, 0xc0,
17077      // maxBitrate
17078      0x00, 0x2d, 0xc6, 0xc0])),
17079      // avgBitrate
17080      MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
17081      // hSpacing
17082      hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
17083      // vSpacing
17084      vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
17085    };
17086    MP4.esds = function esds(track) {
17087      var config
vendor: 5,207 bytes, lines 17087-17231
17087len = track.config.length;
17088      return new Uint8Array([0x00,
17089      // version 0
17090      0x00, 0x00, 0x00,
17091      // flags
17092
17093      0x03,
17094      // descriptor_type
17095      0x17 + configlen,
17096      // length
17097      0x00, 0x01,
17098      // es_id
17099      0x00,
17100      // stream_priority
17101
17102      0x04,
17103      // descriptor_type
17104      0x0f + configlen,
17105      // length
17106      0x40,
17107      // codec : mpeg4_audio
17108      0x15,
17109      // stream_type
17110      0x00, 0x00, 0x00,
17111      // buffer_size
17112      0x00, 0x00, 0x00, 0x00,
17113      // maxBitrate
17114      0x00, 0x00, 0x00, 0x00,
17115      // avgBitrate
17116
17117      0x05 // descriptor_type
17118      ].concat([configlen]).concat(track.config).concat([0x06, 0x01, 0x02])); // GASpecificConfig)); // length + audio config descriptor
17119    };
17120    MP4.audioStsd = function audioStsd(track) {
17121      var samplerate = track.samplerate;
17122      return new Uint8Array([0x00, 0x00, 0x00,
17123      // reserved
17124      0x00, 0x00, 0x00,
17125      // reserved
17126      0x00, 0x01,
17127      // data_reference_index
17128      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17129      // reserved
17130      0x00, track.channelCount,
17131      // channelcount
17132      0x00, 0x10,
17133      // sampleSize:16bits
17134      0x00, 0x00, 0x00, 0x00,
17135      // reserved2
17136      samplerate >> 8 & 0xff, samplerate & 0xff,
17137      //
17138      0x00, 0x00]);
17139    };
17140    MP4.mp4a = function mp4a(track) {
17141      return MP4.box(MP4.types.mp4a, MP4.audioStsd(track), MP4.box(MP4.types.esds, MP4.esds(track)));
17142    };
17143    MP4.mp3 = function mp3(track) {
17144      return MP4.box(MP4.types['.mp3'], MP4.audioStsd(track));
17145    };
17146    MP4.ac3 = function ac3(track) {
17147      return MP4.box(MP4.types['ac-3'], MP4.audioStsd(track), MP4.box(MP4.types.dac3, track.config));
17148    };
17149    MP4.stsd = function stsd(track) {
17150      if (track.type === 'audio') {
17151        if (track.segmentCodec === 'mp3' && track.codec === 'mp3') {
17152          return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp3(track));
17153        }
17154        if (track.segmentCodec === 'ac3') {
17155          return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
17156        }
17157        return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
17158      } else if (track.segmentCodec === 'avc') {
17159        return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
17160      } else {
17161        return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
17162      }
17163    };
17164    MP4.tkhd = function tkhd(track) {
17165      var id = track.id;
17166      var duration = track.duration * track.timescale;
17167      var width = track.width;
17168      var height = track.height;
17169      var upperWordDuration = Math.floor(duration / (UINT32_MAX + 1));
17170      var lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1));
17171      return MP4.box(MP4.types.tkhd, new Uint8Array([0x01,
17172      // version 1
17173      0x00, 0x00, 0x07,
17174      // flags
17175      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
17176      // creation_time
17177      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
17178      // modification_time
17179      id >> 24 & 0xff, id >> 16 & 0xff, id >> 8 & 0xff, id & 0xff,
17180      // track_ID
17181      0x00, 0x00, 0x00, 0x00,
17182      // reserved
17183      upperWordDuration >> 24, upperWordDuration >> 16 & 0xff, upperWordDuration >> 8 & 0xff, upperWordDuration & 0xff, lowerWordDuration >> 24, lowerWordDuration >> 16 & 0xff, lowerWordDuration >> 8 & 0xff, lowerWordDuration & 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17184      // reserved
17185      0x00, 0x00,
17186      // layer
17187      0x00, 0x00,
17188      // alternate_group
17189      0x00, 0x00,
17190      // non-audio track volume
17191      0x00, 0x00,
17192      // reserved
17193      0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
17194      // transformation: unity matrix
17195      width >> 8 & 0xff, width & 0xff, 0x00, 0x00,
17196      // width
17197      height >> 8 & 0xff, height & 0xff, 0x00, 0x00 // height
17198      ]));
17199    };
17200    MP4.traf = function traf(track, baseMediaDecodeTime) {
17201      var sampleDependencyTable = MP4.sdtp(track);
17202      var id = track.id;
17203      var upperWordBaseMediaDecodeTime = Math.floor(baseMediaDecodeTime / (UINT32_MAX + 1));
17204      var lowerWordBaseMediaDecodeTime = Math.floor(baseMediaDecodeTime % (UINT32_MAX + 1));
17205      return MP4.box(MP4.types.traf, MP4.box(MP4.types.tfhd, new Uint8Array([0x00,
17206      // version 0
17207      0x00, 0x00, 0x00,
17208      // flags
17209      id >> 24, id >> 16 & 0xff, id >> 8 & 0xff, id & 0xff // track_ID
17210      ])), MP4.box(MP4.types.tfdt, new Uint8Array([0x01,
17211      // version 1
17212      0x00, 0x00, 0x00,
17213      // flags
17214      upperWordBaseMediaDecodeTime >> 24, upperWordBaseMediaDecodeTime >> 16 & 0xff, upperWordBaseMediaDecodeTime >> 8 & 0xff, upperWordBaseMediaDecodeTime & 0xff, lowerWordBaseMediaDecodeTime >> 24, lowerWordBaseMediaDecodeTime >> 16 & 0xff, lowerWordBaseMediaDecodeTime >> 8 & 0xff, lowerWordBaseMediaDecodeTime & 0xff])), MP4.trun(track, sampleDependencyTable.length + 16 +
17215      // tfhd
17216      20 +
17217      // tfdt
17218      8 +
17219      // traf header
17220      16 +
17221      // mfhd
17222      8 +
17223      // moof header
17224      8),
17225      // mdat header
17226      sampleDependencyTable);
17227    }
17228
17229    /**
17230     * Generate a track box.
17231     * @param track a track definition�
vendor: 6,523 bytes, lines 17231-17393
17231
17232     */;
17233    MP4.trak = function trak(track) {
17234      track.duration = track.duration || 0xffffffff;
17235      return MP4.box(MP4.types.trak, MP4.tkhd(track), MP4.mdia(track));
17236    };
17237    MP4.trex = function trex(track) {
17238      var id = track.id;
17239      return MP4.box(MP4.types.trex, new Uint8Array([0x00,
17240      // version 0
17241      0x00, 0x00, 0x00,
17242      // flags
17243      id >> 24, id >> 16 & 0xff, id >> 8 & 0xff, id & 0xff,
17244      // track_ID
17245      0x00, 0x00, 0x00, 0x01,
17246      // default_sample_description_index
17247      0x00, 0x00, 0x00, 0x00,
17248      // default_sample_duration
17249      0x00, 0x00, 0x00, 0x00,
17250      // default_sample_size
17251      0x00, 0x01, 0x00, 0x01 // default_sample_flags
17252      ]));
17253    };
17254    MP4.trun = function trun(track, offset) {
17255      var samples = track.samples || [];
17256      var len = samples.length;
17257      var arraylen = 12 + 16 * len;
17258      var array = new Uint8Array(arraylen);
17259      var i;
17260      var sample;
17261      var duration;
17262      var size;
17263      var flags;
17264      var cts;
17265      offset += 8 + arraylen;
17266      array.set([track.type === 'video' ? 0x01 : 0x00,
17267      // version 1 for video with signed-int sample_composition_time_offset
17268      0x00, 0x0f, 0x01,
17269      // flags
17270      len >>> 24 & 0xff, len >>> 16 & 0xff, len >>> 8 & 0xff, len & 0xff,
17271      // sample_count
17272      offset >>> 24 & 0xff, offset >>> 16 & 0xff, offset >>> 8 & 0xff, offset & 0xff // data_offset
17273      ], 0);
17274      for (i = 0; i < len; i++) {
17275        sample = samples[i];
17276        duration = sample.duration;
17277        size = sample.size;
17278        flags = sample.flags;
17279        cts = sample.cts;
17280        array.set([duration >>> 24 & 0xff, duration >>> 16 & 0xff, duration >>> 8 & 0xff, duration & 0xff,
17281        // sample_duration
17282        size >>> 24 & 0xff, size >>> 16 & 0xff, size >>> 8 & 0xff, size & 0xff,
17283        // sample_size
17284        flags.isLeading << 2 | flags.dependsOn, flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.paddingValue << 1 | flags.isNonSync, flags.degradPrio & 0xf0 << 8, flags.degradPrio & 0x0f,
17285        // sample_flags
17286        cts >>> 24 & 0xff, cts >>> 16 & 0xff, cts >>> 8 & 0xff, cts & 0xff // sample_composition_time_offset
17287        ], 12 + 16 * i);
17288      }
17289      return MP4.box(MP4.types.trun, array);
17290    };
17291    MP4.initSegment = function initSegment(tracks) {
17292      if (!MP4.types) {
17293        MP4.init();
17294      }
17295      var movie = MP4.moov(tracks);
17296      var result = appendUint8Array(MP4.FTYP, movie);
17297      return result;
17298    };
17299    MP4.hvc1 = function hvc1(track) {
17300      var ps = track.params;
17301      var units = [track.vps, track.sps, track.pps];
17302      var NALuLengthSize = 4;
17303      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]);
17304
17305      // compute hvcC size in bytes
17306      var length = config.length;
17307      for (var i = 0; i < units.length; i += 1) {
17308        length += 3;
17309        for (var j = 0; j < units[i].length; j += 1) {
17310          length += 2 + units[i][j].length;
17311        }
17312      }
17313      var hvcC = new Uint8Array(length);
17314      hvcC.set(config, 0);
17315      length = config.length;
17316      // append parameter set units: one vps, one or more sps and pps
17317      var iMax = units.length - 1;
17318      for (var _i = 0; _i < units.length; _i += 1) {
17319        hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
17320        length += 3;
17321        for (var _j = 0; _j < units[_i].length; _j += 1) {
17322          hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
17323          length += 2;
17324          hvcC.set(units[_i][_j], length);
17325          length += units[_i][_j].length;
17326        }
17327      }
17328      var hvcc = MP4.box(MP4.types.hvcC, hvcC);
17329      var width = track.width;
17330      var height = track.height;
17331      var hSpacing = track.pixelRatio[0];
17332      var vSpacing = track.pixelRatio[1];
17333      return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
17334      // reserved
17335      0x00, 0x00, 0x00,
17336      // reserved
17337      0x00, 0x01,
17338      // data_reference_index
17339      0x00, 0x00,
17340      // pre_defined
17341      0x00, 0x00,
17342      // reserved
17343      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17344      // pre_defined
17345      width >> 8 & 0xff, width & 0xff,
17346      // width
17347      height >> 8 & 0xff, height & 0xff,
17348      // height
17349      0x00, 0x48, 0x00, 0x00,
17350      // horizresolution
17351      0x00, 0x48, 0x00, 0x00,
17352      // vertresolution
17353      0x00, 0x00, 0x00, 0x00,
17354      // reserved
17355      0x00, 0x01,
17356      // frame_count
17357      0x12, 0x64, 0x61, 0x69, 0x6c,
17358      // dailymotion/hls.js
17359      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,
17360      // compressorname
17361      0x00, 0x18,
17362      // depth = 24
17363      0x11, 0x11]),
17364      // pre_defined = -1
17365      hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
17366      // bufferSizeDB
17367      0x00, 0x2d, 0xc6, 0xc0,
17368      // maxBitrate
17369      0x00, 0x2d, 0xc6, 0xc0])),
17370      // avgBitrate
17371      MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
17372      // hSpacing
17373      hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
17374      // vSpacing
17375      vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
17376    };
17377    return MP4;
17378  }();
17379  MP4.types = void 0;
17380  MP4.HDLR_TYPES = void 0;
17381  MP4.STTS = void 0;
17382  MP4.STSC = void 0;
17383  MP4.STCO = void 0;
17384  MP4.STSZ = void 0;
17385  MP4.VMHD = void 0;
17386  MP4.SMHD = void 0;
17387  MP4.STSD = void 0;
17388  MP4.FTYP = void 0;
17389  MP4.DINF = void 0;
17390
17391  var MPEG_TS_CLOCK_FREQ_HZ = 90000;
17392  function toTimescaleFromBase(baseTime, destScale, srcBase, round) {
17393    if (
vendor: 3,323 bytes, lines 17393-17477
17393round === void 0) {
17394      round = false;
17395    }
17396    var result = baseTime * destScale * srcBase; // equivalent to `(value * scale) / (1 / base)`
17397    return round ? Math.round(result) : result;
17398  }
17399  function toMsFromMpegTsClock(baseTime, round) {
17400    return toTimescaleFromBase(baseTime, 1000, 1 / MPEG_TS_CLOCK_FREQ_HZ, round);
17401  }
17402
17403  var MAX_SILENT_FRAME_DURATION = 10 * 1000; // 10 seconds
17404  var AAC_SAMPLES_PER_FRAME = 1024;
17405  var MPEG_AUDIO_SAMPLE_PER_FRAME = 1152;
17406  var AC3_SAMPLES_PER_FRAME = 1536;
17407  var chromeVersion = null;
17408  var safariWebkitVersion = null;
17409  var MP4Remuxer = /*#__PURE__*/function () {
17410    function MP4Remuxer(observer, config, typeSupported, logger) {
17411      this.logger = void 0;
17412      this.observer = void 0;
17413      this.config = void 0;
17414      this.typeSupported = void 0;
17415      this.ISGenerated = false;
17416      this._initPTS = null;
17417      this._initDTS = null;
17418      this.nextAvcDts = null;
17419      this.nextAudioPts = null;
17420      this.videoSampleDuration = null;
17421      this.isAudioContiguous = false;
17422      this.isVideoContiguous = false;
17423      this.videoTrackConfig = void 0;
17424      this.observer = observer;
17425      this.config = config;
17426      this.typeSupported = typeSupported;
17427      this.logger = logger;
17428      this.ISGenerated = false;
17429      if (chromeVersion === null) {
17430        var userAgent = navigator.userAgent || '';
17431        var result = userAgent.match(/Chrome\/(\d+)/i);
17432        chromeVersion = result ? parseInt(result[1]) : 0;
17433      }
17434      if (safariWebkitVersion === null) {
17435        var _result = navigator.userAgent.match(/Safari\/(\d+)/i);
17436        safariWebkitVersion = _result ? parseInt(_result[1]) : 0;
17437      }
17438    }
17439    var _proto = MP4Remuxer.prototype;
17440    _proto.destroy = function destroy() {
17441      // @ts-ignore
17442      this.config = this.videoTrackConfig = this._initPTS = this._initDTS = null;
17443    };
17444    _proto.resetTimeStamp = function resetTimeStamp(defaultTimeStamp) {
17445      this.logger.log('[mp4-remuxer]: initPTS & initDTS reset');
17446      this._initPTS = this._initDTS = defaultTimeStamp;
17447    };
17448    _proto.resetNextTimestamp = function resetNextTimestamp() {
17449      this.logger.log('[mp4-remuxer]: reset next timestamp');
17450      this.isVideoContiguous = false;
17451      this.isAudioContiguous = false;
17452    };
17453    _proto.resetInitSegment = function resetInitSegment() {
17454      this.logger.log('[mp4-remuxer]: ISGenerated flag reset');
17455      this.ISGenerated = false;
17456      this.videoTrackConfig = undefined;
17457    };
17458    _proto.getVideoStartPts = function getVideoStartPts(videoSamples) {
17459      var rolloverDetected = false;
17460      var startPTS = videoSamples.reduce(function (minPTS, sample) {
17461        var delta = sample.pts - minPTS;
17462        if (delta < -4294967296) {
17463          // 2^32, see PTSNormalize for reasoning, but we're hitting a rollover here, and we don't want that to impact the timeOffset calculation
17464          rolloverDetected = true;
17465          return normalizePts(minPTS, sample.pts);
17466        } else if (delta > 0) {
17467          return minPTS;
17468        } else {
17469          return sample.pts;
17470        }
17471      }, videoSamples[0].pts);
17472      if (rolloverDetected) {
17473        this.logger.debug('PTS rollover detected');
17474      }
17475      return startPTS;
17476    };
17477    _proto.remux = function remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOff
vendor: 8,504 bytes, lines 17477-17638
17477set, flush, playlistType) {
17478      var video;
17479      var audio;
17480      var initSegment;
17481      var text;
17482      var id3;
17483      var independent;
17484      var audioTimeOffset = timeOffset;
17485      var videoTimeOffset = timeOffset;
17486
17487      // If we're remuxing audio and video progressively, wait until we've received enough samples for each track before proceeding.
17488      // This is done to synchronize the audio and video streams. We know if the current segment will have samples if the "pid"
17489      // parameter is greater than -1. The pid is set when the PMT is parsed, which contains the tracks list.
17490      // However, if the initSegment has already been generated, or we've reached the end of a segment (flush),
17491      // then we can remux one track without waiting for the other.
17492      var hasAudio = audioTrack.pid > -1;
17493      var hasVideo = videoTrack.pid > -1;
17494      var length = videoTrack.samples.length;
17495      var enoughAudioSamples = audioTrack.samples.length > 0;
17496      var enoughVideoSamples = flush && length > 0 || length > 1;
17497      var canRemuxAvc = (!hasAudio || enoughAudioSamples) && (!hasVideo || enoughVideoSamples) || this.ISGenerated || flush;
17498      if (canRemuxAvc) {
17499        if (this.ISGenerated) {
17500          var _videoTrack$pixelRati, _config$pixelRatio, _videoTrack$pixelRati2, _config$pixelRatio2;
17501          var config = this.videoTrackConfig;
17502          if (config && (videoTrack.width !== config.width || videoTrack.height !== config.height || ((_videoTrack$pixelRati = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati[0]) !== ((_config$pixelRatio = config.pixelRatio) == null ? void 0 : _config$pixelRatio[0]) || ((_videoTrack$pixelRati2 = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati2[1]) !== ((_config$pixelRatio2 = config.pixelRatio) == null ? void 0 : _config$pixelRatio2[1])) || !config && enoughVideoSamples || this.nextAudioPts === null && enoughAudioSamples) {
17503            this.resetInitSegment();
17504          }
17505        }
17506        if (!this.ISGenerated) {
17507          initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
17508        }
17509        var isVideoContiguous = this.isVideoContiguous;
17510        var firstKeyFrameIndex = -1;
17511        var firstKeyFramePTS;
17512        if (enoughVideoSamples) {
17513          firstKeyFrameIndex = findKeyframeIndex(videoTrack.samples);
17514          if (!isVideoContiguous && this.config.forceKeyFrameOnDiscontinuity) {
17515            independent = true;
17516            if (firstKeyFrameIndex > 0) {
17517              this.logger.warn("[mp4-remuxer]: Dropped " + firstKeyFrameIndex + " out of " + length + " video samples due to a missing keyframe");
17518              var startPTS = this.getVideoStartPts(videoTrack.samples);
17519              videoTrack.samples = videoTrack.samples.slice(firstKeyFrameIndex);
17520              videoTrack.dropped += firstKeyFrameIndex;
17521              videoTimeOffset += (videoTrack.samples[0].pts - startPTS) / videoTrack.inputTimeScale;
17522              firstKeyFramePTS = videoTimeOffset;
17523            } else if (firstKeyFrameIndex === -1) {
17524              this.logger.warn("[mp4-remuxer]: No keyframe found out of " + length + " video samples");
17525              independent = false;
17526            }
17527          }
17528        }
17529        if (this.ISGenerated) {
17530          if (enoughAudioSamples && enoughVideoSamples) {
17531            // timeOffset is expected to be the offset of the first timestamp of this fragment (first DTS)
17532            // if first audio DTS is not aligned with first video DTS then we need to take that into account
17533            // when providing timeOffset to remuxAudio / remuxVideo. if we don't do that, there might be a permanent / small
17534            // drift between audio and video streams
17535            var _startPTS = this.getVideoStartPts(videoTrack.samples);
17536            var tsDelta = normalizePts(audioTrack.samples[0].pts, _startPTS) - _startPTS;
17537            var audiovideoTimestampDelta = tsDelta / videoTrack.inputTimeScale;
17538            audioTimeOffset += Math.max(0, audiovideoTimestampDelta);
17539            videoTimeOffset += Math.max(0, -audiovideoTimestampDelta);
17540          }
17541
17542          // Purposefully remuxing audio before video, so that remuxVideo can use nextAudioPts, which is calculated in remuxAudio.
17543          if (enoughAudioSamples) {
17544            // if initSegment was generated without audio samples, regenerate it again
17545            if (!audioTrack.samplerate) {
17546              this.logger.warn('[mp4-remuxer]: regenerate InitSegment as audio detected');
17547              initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
17548            }
17549            audio = this.remuxAudio(audioTrack, audioTimeOffset, this.isAudioContiguous, accurateTimeOffset, hasVideo || enoughVideoSamples || playlistType === PlaylistLevelType.AUDIO ? videoTimeOffset : undefined);
17550            if (enoughVideoSamples) {
17551              var audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0;
17552              // if initSegment was generated without video samples, regenerate it again
17553              if (!videoTrack.inputTimeScale) {
17554                this.logger.warn('[mp4-remuxer]: regenerate InitSegment as video detected');
17555                initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
17556              }
17557              video = this.remuxVideo(videoTrack, videoTimeOffset, isVideoContiguous, audioTrackLength);
17558            }
17559          } else if (enoughVideoSamples) {
17560            video = this.remuxVideo(videoTrack, videoTimeOffset, isVideoContiguous, 0);
17561          }
17562          if (video) {
17563            video.firstKeyFrame = firstKeyFrameIndex;
17564            video.independent = firstKeyFrameIndex !== -1;
17565            video.firstKeyFramePTS = firstKeyFramePTS;
17566          }
17567        }
17568      }
17569
17570      // Allow ID3 and text to remux, even if more audio/video samples are required
17571      if (this.ISGenerated && this._initPTS && this._initDTS) {
17572        if (id3Track.samples.length) {
17573          id3 = flushTextTrackMetadataCueSamples(id3Track, timeOffset, this._initPTS, this._initDTS);
17574        }
17575        if (textTrack.samples.length) {
17576          text = flushTextTrackUserdataCueSamples(textTrack, timeOffset, this._initPTS);
17577        }
17578      }
17579      return {
17580        audio: audio,
17581        video: video,
17582        initSegment: initSegment,
17583        independent: independent,
17584        text: text,
17585        id3: id3
17586      };
17587    };
17588    _proto.generateIS = function generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset) {
17589      var audioSamples = audioTrack.samples;
17590      var videoSamples = videoTrack.samples;
17591      var typeSupported = this.typeSupported;
17592      var tracks = {};
17593      var _initPTS = this._initPTS;
17594      var computePTSDTS = !_initPTS || accurateTimeOffset;
17595      var container = 'audio/mp4';
17596      var initPTS;
17597      var initDTS;
17598      var timescale;
17599      if (computePTSDTS) {
17600        initPTS = initDTS = Infinity;
17601      }
17602      if (audioTrack.config && audioSamples.length) {
17603        // let's use audio sampling rate as MP4 time scale.
17604        // rationale is that there is a integer nb of audio frames per audio sample (1024 for AAC)
17605        // using audio sampling rate here helps having an integer MP4 frame duration
17606        // this avoids potential rounding issue and AV sync issue
17607        audioTrack.timescale = audioTrack.samplerate;
17608        switch (audioTrack.segmentCodec) {
17609          case 'mp3':
17610            if (typeSupported.mpeg) {
17611              // Chrome and Safari
17612              container = 'audio/mpeg';
17613              audioTrack.codec = '';
17614            } else if (typeSupported.mp3) {
17615              // Firefox
17616              audioTrack.codec = 'mp3';
17617            }
17618            break;
17619          case 'ac3':
17620            audioTrack.codec = 'ac-3';
17621            break;
17622        }
17623        tracks.audio = {
17624          id: 'audio',
17625          container: container,
17626          codec: audioTrack.codec,
17627          initSegment: audioTrack.segmentCodec === 'mp3' && typeSupported.mpeg ? new Uint8Array(0) : MP4.initSegment([audioTrack]),
17628          metadata: {
17629            channelCount: audioTrack.channelCount
17630          }
17631        };
17632        if (computePTSDTS) {
17633          timescale = audioTrack.inputTimeScale;
17634          if (!_initPTS || timescale !== _initPTS.timescale) {
17635            // remember first PTS of this demuxing context. for audio, PTS = DTS
17636            initPTS = initDTS = audioSamples[0].pts - Math.round(timescale * timeOffset);
17637          } else {
17638            computePTSDTS = false;
17639          }
17640        }
17641      }
17642      if (videoTrack.sps && videoTrack.pps && videoSamples.length) {
17643        // let's use input time scale as MP4 video timescale
17644        // we use input time scale straight away to avoid rounding issues on frame duration / cts computation
17645        videoTrack.timescale = videoTrack.inputTimeScale;
17646        tracks.video = {
17647          id: 'main',
17648          container: 'video/mp4',
17649          codec: videoTrack.codec,
17650          initSegment: MP4.initSegment([videoTrack]),
17651          metadata: {
17652            width: videoTrack.width,
17653            height: videoTrack.height
17654          }
17655        };
17656        if (computePTSDTS) {
17657          timescale = videoTrack.inputTimeScale;
17658          if (!_initPTS || timescale !== _initPTS.timescale) {
17659            var startPTS = this.getVideoStartPts(videoSamples);
17660            var startOffset = Math.round(timescale * timeOffset);
17661            initDTS = Math.min(initDTS, normalizePts(videoSamples[0].dts, startPTS) - startOffset);
17662            initPTS = Math.min(initPTS, startPTS - startOffset);
17663          } else {
17664            computePTSDTS = false;
17665          }
17666        }
17667        this.videoTrackConfig = {
17668          width: videoTrack.width,
17669          height: videoTrack.height,
17670          pixelRatio: videoTrack.pixelRatio
17671        };
17672      }
17673      if (Object.keys(tracks).length) {
17674        this.ISGenerated = true;
17675        if (computePTSDTS) {
17676          this._initPTS = {
17677            baseTime: initPTS,
17678            timescale: timescale
17679          };
17680          this._initDTS = {
17681            baseTime: initDTS,
17682            timescale: timescale
17683          };
17684        } else {
17685          initPTS = timescale = undefined;
17686        }
17687        return {
17688          tracks: tracks,
17689          initPTS: initPTS,
17690          timescale: timescale
17691        };
17692      }
17693    };
17694    _proto.remuxVideo = function remuxVideo(track, timeOffset, contiguous, audioTrackLength) {
17695      var timeScale = track.inputTimeScale;
17696      var inputSamples = track.samples;
17697      var outputSamples = [];
17698      var nbSamples = inputSamples.length;
17699      var initPTS = this._initPTS;
17700      var nextAvcDts = this.nextAvcDts;
17701      var offset = 8;
17702      var mp4SampleDuration = this.videoSampleDuration;
17703      var firstDTS;
17704      var lastDTS;
17705      var minPTS = Number.POSITIVE_INFINITY;
17706      var maxPTS = Number.NEGATIVE_INFINITY;
17707      var sortSamples = false;
17708
17709      // if parsed fragment is contiguous with last one, let's use last DTS value as reference
17710      if (!contiguous || nextAvcDts === null) {
17711        var pts = timeOffset * timeScale;
17712        var cts = inputSamples[0].pts - normalizePts(inputSamples[0].dts, inputSamples[0].pts);
17713        if (chromeVersion && nextAvcDts !== null && Math.abs(pts - cts - nextAvcDts) < 15000) {
17714          // treat as contigous to adjust samples that would otherwise produce video buffer gaps in Chrome
17715          contiguous = true;
17716        } else {
17717          // if not contiguous, let's use target timeOffset
17718          nextAvcDts = pts - cts;
17719        }
17720      }
17721
17722      // PTS is coded on 33bits, and can loop from -2^32 to 2^32
17723      // PTSNormalize will make PTS/DTS value monotonic, we use last known DTS value as reference value
17724      var initTime = initPTS.baseTime * timeScale / initPTS.timescale;
17725      for (var i = 0; i < nbSamples; i++) {
17726        var sample = inputSamples[i];
17727        sample.pts = normalizePts(sample.pts - initTime, nextAvcDts);
17728        sample.dts = normalizePts(sample.dts - initTime, nextAvcDts);
17729        if (sample.dts < inputSamples[i > 0 ? i - 1 : i].dts) {
17730          sortSamples = true;
17731        }
17732      }
17733
17734      // sort video samples by DTS then PTS then demux id order
17735      if (sortSamples) {
17736        inputSamples.sort(function (a, b) {
17737          var deltadts = a.dts - b.dts;
17738          var deltapts = a.pts - b.pts;
17739          return deltadts || deltapts;
17740        });
17741      }
17742
17743      // Get first/last DTS
17744      firstDTS = inputSamples[0].dts;
17745      lastDTS = inputSamples[inputSamples.length - 1].dts;
17746
17747      // Sample duration (as expected by trun MP4 boxes), should be the delta between sample DTS
17748      // set this constant duration as being the avg delta between consecutive DTS.
17749      var inputDuration = lastDTS - firstDTS;
17750      var averageSampleDuration = inputDuration ? Math.round(inputDuration / (nbSamples - 1)) : mp4SampleDuration || track.inputTimeScale / 30;
17751
17752      // if fragment are contiguous, detect hole/overlapping between fragments
17753      if (contiguous) {
17754        // check timestamp continuity across consecutive fragments (this is to remove inter-fragment gap/hole)
17755        var delta = firstDTS - nextAvcDts;
17756        var foundHole = delta > averageSampleDuration;
17757        var foundOverlap = delta < -1;
vendor: 7,699 bytes, lines 17758-17916
17758        if (foundHole || foundOverlap) {
17759          if (foundHole) {
17760            this.logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
17761          } else {
17762            this.logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
17763          }
17764          if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
17765            firstDTS = nextAvcDts;
17766            var firstPTS = inputSamples[0].pts - delta;
17767            if (foundHole) {
17768              inputSamples[0].dts = firstDTS;
17769              inputSamples[0].pts = firstPTS;
17770            } else {
17771              var isPTSOrderRetained = true;
17772              for (var _i = 0; _i < inputSamples.length; _i++) {
17773                if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
17774                  break;
17775                }
17776                var prevPTS = inputSamples[_i].pts;
17777                inputSamples[_i].dts -= delta;
17778                inputSamples[_i].pts -= delta;
17779
17780                // check to see if this sample's PTS order has changed
17781                // relative to the next one
17782                if (_i < inputSamples.length - 1) {
17783                  var nextSamplePTS = inputSamples[_i + 1].pts;
17784                  var currentSamplePTS = inputSamples[_i].pts;
17785                  var currentOrder = nextSamplePTS <= currentSamplePTS;
17786                  var prevOrder = nextSamplePTS <= prevPTS;
17787                  isPTSOrderRetained = currentOrder == prevOrder;
17788                }
17789              }
17790            }
17791            this.logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
17792          }
17793        }
17794      }
17795      firstDTS = Math.max(0, firstDTS);
17796      var nbNalu = 0;
17797      var naluLen = 0;
17798      var dtsStep = firstDTS;
17799      for (var _i2 = 0; _i2 < nbSamples; _i2++) {
17800        // compute total/avc sample length and nb of NAL units
17801        var _sample = inputSamples[_i2];
17802        var units = _sample.units;
17803        var nbUnits = units.length;
17804        var sampleLen = 0;
17805        for (var j = 0; j < nbUnits; j++) {
17806          sampleLen += units[j].data.length;
17807        }
17808        naluLen += sampleLen;
17809        nbNalu += nbUnits;
17810        _sample.length = sampleLen;
17811
17812        // ensure sample monotonic DTS
17813        if (_sample.dts < dtsStep) {
17814          _sample.dts = dtsStep;
17815          dtsStep += averageSampleDuration / 4 | 0 || 1;
17816        } else {
17817          dtsStep = _sample.dts;
17818        }
17819        minPTS = Math.min(_sample.pts, minPTS);
17820        maxPTS = Math.max(_sample.pts, maxPTS);
17821      }
17822      lastDTS = inputSamples[nbSamples - 1].dts;
17823
17824      /* concatenate the video data and construct the mdat in place
17825        (need 8 more bytes to fill length and mpdat type) */
17826      var mdatSize = naluLen + 4 * nbNalu + 8;
17827      var mdat;
17828      try {
17829        mdat = new Uint8Array(mdatSize);
17830      } catch (err) {
17831        this.observer.emit(Events.ERROR, Events.ERROR, {
17832          type: ErrorTypes.MUX_ERROR,
17833          details: ErrorDetails.REMUX_ALLOC_ERROR,
17834          fatal: false,
17835          error: err,
17836          bytes: mdatSize,
17837          reason: "fail allocating video mdat " + mdatSize
17838        });
17839        return;
17840      }
17841      var view = new DataView(mdat.buffer);
17842      view.setUint32(0, mdatSize);
17843      mdat.set(MP4.types.mdat, 4);
17844      var stretchedLastFrame = false;
17845      var minDtsDelta = Number.POSITIVE_INFINITY;
17846      var minPtsDelta = Number.POSITIVE_INFINITY;
17847      var maxDtsDelta = Number.NEGATIVE_INFINITY;
17848      var maxPtsDelta = Number.NEGATIVE_INFINITY;
17849      for (var _i3 = 0; _i3 < nbSamples; _i3++) {
17850        var VideoSample = inputSamples[_i3];
17851        var VideoSampleUnits = VideoSample.units;
17852        var mp4SampleLength = 0;
17853        // convert NALU bitstream to MP4 format (prepend NALU with size field)
17854        for (var _j = 0, _nbUnits = VideoSampleUnits.length; _j < _nbUnits; _j++) {
17855          var unit = VideoSampleUnits[_j];
17856          var unitData = unit.data;
17857          var unitDataLen = unit.data.byteLength;
17858          view.setUint32(offset, unitDataLen);
17859          offset += 4;
17860          mdat.set(unitData, offset);
17861          offset += unitDataLen;
17862          mp4SampleLength += 4 + unitDataLen;
17863        }
17864
17865        // expected sample duration is the Decoding Timestamp diff of consecutive samples
17866        var ptsDelta = void 0;
17867        if (_i3 < nbSamples - 1) {
17868          mp4SampleDuration = inputSamples[_i3 + 1].dts - VideoSample.dts;
17869          ptsDelta = inputSamples[_i3 + 1].pts - VideoSample.pts;
17870        } else {
17871          var config = this.config;
17872          var lastFrameDuration = _i3 > 0 ? VideoSample.dts - inputSamples[_i3 - 1].dts : averageSampleDuration;
17873          ptsDelta = _i3 > 0 ? VideoSample.pts - inputSamples[_i3 - 1].pts : averageSampleDuration;
17874          if (config.stretchShortVideoTrack && this.nextAudioPts !== null) {
17875            // In some cases, a segment's audio track duration may exceed the video track duration.
17876            // Since we've already remuxed audio, and we know how long the audio track is, we look to
17877            // see if the delta to the next segment is longer than maxBufferHole.
17878            // If so, playback would potentially get stuck, so we artificially inflate
17879            // the duration of the last frame to minimize any potential gap between segments.
17880            var gapTolerance = Math.floor(config.maxBufferHole * timeScale);
17881            var deltaToFrameEnd = (audioTrackLength ? minPTS + audioTrackLength * timeScale : this.nextAudioPts) - VideoSample.pts;
17882            if (deltaToFrameEnd > gapTolerance) {
17883              // We subtract lastFrameDuration from deltaToFrameEnd to try to prevent any video
17884              // frame overlap. maxBufferHole should be >> lastFrameDuration anyway.
17885              mp4SampleDuration = deltaToFrameEnd - lastFrameDuration;
17886              if (mp4SampleDuration < 0) {
17887                mp4SampleDuration = lastFrameDuration;
17888              } else {
17889                stretchedLastFrame = true;
17890              }
17891              this.logger.log("[mp4-remuxer]: It is approximately " + deltaToFrameEnd / 90 + " ms to the next segment; using duration " + mp4SampleDuration / 90 + " ms for the last video frame.");
17892            } else {
17893              mp4SampleDuration = lastFrameDuration;
17894            }
17895          } else {
17896            mp4SampleDuration = lastFrameDuration;
17897          }
17898        }
17899        var compositionTimeOffset = Math.round(VideoSample.pts - VideoSample.dts);
17900        minDtsDelta = Math.min(minDtsDelta, mp4SampleDuration);
17901        maxDtsDelta = Math.max(maxDtsDelta, mp4SampleDuration);
17902        minPtsDelta = Math.min(minPtsDelta, ptsDelta);
17903        maxPtsDelta = Math.max(maxPtsDelta, ptsDelta);
17904        outputSamples.push(new Mp4Sample(VideoSample.key, mp4SampleDuration, mp4SampleLength, compositionTimeOffset));
17905      }
17906      if (outputSamples.length) {
17907        if (chromeVersion) {
17908          if (chromeVersion < 70) {
17909            // Chrome workaround, mark first sample as being a Random Access Point (keyframe) to avoid sourcebuffer append issue
17910            // https://code.google.com/p/chromium/issues/detail?id=229412
17911            var flags = outputSamples[0].flags;
17912            flags.dependsOn = 2;
17913            flags.isNonSync = 0;
17914          }
17915        } else if (safariWebkitVersion) {
17916          // Fix for "CNN special report, with CC" in test-streams (Safari browser only
17916)
17917          // Ignore DTS when frame durations are irregular. Safari MSE does not handle this leading to gaps.
17918          if (maxPtsDelta - minPtsDelta < maxDtsDelta - minDtsDelta && averageSampleDuration / maxDtsDelta < 0.025 && outputSamples[0].cts === 0) {
17919            this.logger.warn('Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration.');
17920            var dts = firstDTS;
17921            for (var _i4 = 0, len = outputSamples.length; _i4 < len; _i4++) {
17922              var nextDts = dts + outputSamples[_i4].duration;
17923              var _pts = dts + outputSamples[_i4].cts;
17924              if (_i4 < len - 1) {
17925                var nextPts = nextDts + outputSamples[_i4 + 1].cts;
17926                outputSamples[_i4].duration = nextPts - _pts;
17927              } else {
17928                outputSamples[_i4].duration = _i4 ? outputSamples[_i4 - 1].duration : averageSampleDuration;
17929              }
17930              outputSamples[_i4].cts = 0;
17931              dts = nextDts;
17932            }
17933          }
17934        }
17935      }
17936      // next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
17937      mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
17938      this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
17939      this.videoSampleDuration = mp4SampleDuration;
17940      this.isVideoContiguous = true;
17941      var moof = MP4.moof(track.sequenceNumber++, firstDTS, _extends({}, track, {
17942        samples: outputSamples
17943      }));
17944      var type = 'video';
17945      var data = {
17946        data1: moof,
17947        data2: mdat,
17948        startPTS: minPTS / timeScale,
17949        endPTS: (maxPTS + mp4SampleDuration) / timeScale,
17950        startDTS: firstDTS / timeScale,
17951        endDTS: nextAvcDts / timeScale,
17952        type: type,
17953        hasAudio: false,
17954        hasVideo: true,
17955        nb: outputSamples.length,
17956        dropped: track.dropped
17957      };
17958      track.samples = [];
17959      track.dropped = 0;
17960      return data;
17961    };
17962    _proto.getSamplesPerFrame = function getSamplesPerFrame(track) {
17963      switch (track.segmentCodec) {
17964        case 'mp3':
17965          return MPEG_AUDIO_SAMPLE_PER_FRAME;
17966        case 'ac3':
17967          return AC3_SAMPLES_PER_FRAME;
17968        default:
17969          return AAC_SAMPLES_PER_FRAME;
17970      }
17971    };
17972    _proto.remuxAudio = function remuxAudio(track, timeOffset, contiguous, accurateTimeOffset, videoTimeOffset) {
17973      var inputTimeScale = track.inputTimeScale;
17974      var mp4timeScale = track.samplerate ? track.samplerate : inputTimeScale;
17975      var scaleFactor = inputTimeScale / mp4timeScale;
17976      var mp4SampleDuration = this.getSamplesPerFrame(track);
17977      var inputSampleDuration = mp4SampleDuration * scaleFactor;
17978      var initPTS = this._initPTS;
17979      var rawMPEG = track.segmentCodec === 'mp3' && this.typeSupported.mpeg;
17980      var outputSamples = [];
17981      var alignedWithVideo = videoTimeOffset !== undefined;
17982      var inputSamples = track.samples;
17983      var offset = rawMPEG ? 0 : 8;
17984      var nextAudioPts = this.nextAudioPts || -1;
17985
17986      // window.audioSamples ? window.audioSamples.push(inputSamples.map(s => s.pts)) : (window.audioSamples = [inputSamples.map(s => s.pts)]);
17987
17988      // for audio samples, also consider consecutive fragments as being contiguous (even if a level switch occurs),
17989      // for sake of clarity:
17990      // consecutive fragments are frags with
17991      //  - less than 100ms gaps between new time offset (if accurate) and next expected PTS OR
17992      //  - less than 20 audio frames distance
17993      // contiguous fragments are consecutive fragments from same quality level (same level, new SN = old SN + 1)
17994      // this helps ensuring audio continuity
17995      // and this also avoids audio glitches/cut when switching quality, or reporting wrong duration on first audio frame
17996      var timeOffsetMpegTS = timeOffset * inputTimeScale;
17997      var initTime = initPTS.baseTime * inputTimeScale / initPTS.timescale;
17998      this.isAudioContiguous = contiguous = contiguous || inputSamples.length && nextAudioPts >
vendor: 6,304 bytes, lines 17998-18120
17998 0 && (accurateTimeOffset && Math.abs(timeOffsetMpegTS - nextAudioPts) < 9000 || Math.abs(normalizePts(inputSamples[0].pts - initTime, timeOffsetMpegTS) - nextAudioPts) < 20 * inputSampleDuration);
17999
18000      // compute normalized PTS
18001      inputSamples.forEach(function (sample) {
18002        sample.pts = normalizePts(sample.pts - initTime, timeOffsetMpegTS);
18003      });
18004      if (!contiguous || nextAudioPts < 0) {
18005        // filter out sample with negative PTS that are not playable anyway
18006        // if we don't remove these negative samples, they will shift all audio samples forward.
18007        // leading to audio overlap between current / next fragment
18008        inputSamples = inputSamples.filter(function (sample) {
18009          return sample.pts >= 0;
18010        });
18011
18012        // in case all samples have negative PTS, and have been filtered out, return now
18013        if (!inputSamples.length) {
18014          return;
18015        }
18016        if (videoTimeOffset === 0) {
18017          // Set the start to 0 to match video so that start gaps larger than inputSampleDuration are filled with silence
18018          nextAudioPts = 0;
18019        } else if (accurateTimeOffset && !alignedWithVideo) {
18020          // When not seeking, not live, and LevelDetails.PTSKnown, use fragment start as predicted next audio PTS
18021          nextAudioPts = Math.max(0, timeOffsetMpegTS);
18022        } else {
18023          // if frags are not contiguous and if we cant trust time offset, let's use first sample PTS as next audio PTS
18024          nextAudioPts = inputSamples[0].pts;
18025        }
18026      }
18027
18028      // If the audio track is missing samples, the frames seem to get "left-shifted" within the
18029      // resulting mp4 segment, causing sync issues and leaving gaps at the end of the audio segment.
18030      // In an effort to prevent this from happening, we inject frames here where there are gaps.
18031      // When possible, we inject a silent frame; when that's not possible, we duplicate the last
18032      // frame.
18033
18034      if (track.segmentCodec === 'aac') {
18035        var maxAudioFramesDrift = this.config.maxAudioFramesDrift;
18036        for (var i = 0, nextPts = nextAudioPts; i < inputSamples.length; i++) {
18037          // First, let's see how far off this frame is from where we expect it to be
18038          var sample = inputSamples[i];
18039          var pts = sample.pts;
18040          var delta = pts - nextPts;
18041          var duration = Math.abs(1000 * delta / inputTimeScale);
18042
18043          // When remuxing with video, if we're overlapping by more than a duration, drop this sample to stay in sync
18044          if (delta <= -maxAudioFramesDrift * inputSampleDuration && alignedWithVideo) {
18045            if (i === 0) {
18046              this.logger.warn("Audio frame @ " + (pts / inputTimeScale).toFixed(3) + "s overlaps nextAudioPts by " + Math.round(1000 * delta / inputTimeScale) + " ms.");
18047              this.nextAudioPts = nextAudioPts = nextPts = pts;
18048            }
18049          } // eslint-disable-line brace-style
18050
18051          // Insert missing frames if:
18052          // 1: We're more than maxAudioFramesDrift frame away
18053          // 2: Not more than MAX_SILENT_FRAME_DURATION away
18054          // 3: currentTime (aka nextPtsNorm) is not 0
18055          // 4: remuxing with video (videoTimeOffset !== undefined)
18056          else if (delta >= maxAudioFramesDrift * inputSampleDuration && duration < MAX_SILENT_FRAME_DURATION && alignedWithVideo) {
18057            var missing = Math.round(delta / inputSampleDuration);
18058            // Adjust nextPts so that silent samples are aligned with media pts. This will prevent media samples from
18059            // later being shifted if nextPts is based on timeOffset and delta is not a multiple of inputSampleDuration.
18060            nextPts = pts - missing * inputSampleDuration;
18061            if (nextPts < 0) {
18062              missing--;
18063              nextPts += inputSampleDuration;
18064            }
18065            if (i === 0) {
18066              this.nextAudioPts = nextAudioPts = nextPts;
18067            }
18068            this.logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
18069            for (var j = 0; j < missing; j++) {
18070              var newStamp = Math.max(nextPts, 0);
18071              var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
18072              if (!fillFrame) {
18073                this.logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
18074                fillFrame = sample.unit.subarray();
18075              }
18076              inputSamples.splice(i, 0, {
18077                unit: fillFrame,
18078                pts: newStamp
18079              });
18080              nextPts += inputSampleDuration;
18081              i++;
18082            }
18083          }
18084          sample.pts = nextPts;
18085          nextPts += inputSampleDuration;
18086        }
18087      }
18088      var firstPTS = null;
18089      var lastPTS = null;
18090      var mdat;
18091      var mdatSize = 0;
18092      var sampleLength = inputSamples.length;
18093      while (sampleLength--) {
18094        mdatSize += inputSamples[sampleLength].unit.byteLength;
18095      }
18096      for (var _j2 = 0, _nbSamples = inputSamples.length; _j2 < _nbSamples; _j2++) {
18097        var audioSample = inputSamples[_j2];
18098        var unit = audioSample.unit;
18099        var _pts2 = audioSample.pts;
18100        if (lastPTS !== null) {
18101          // If we have more than one sample, set the duration of the sample to the "real" duration; the PTS diff with
18102          // the previous sample
18103          var prevSample = outputSamples[_j2 - 1];
18104          prevSample.duration = Math.round((_pts2 - lastPTS) / scaleFactor);
18105        } else {
18106          if (contiguous && track.segmentCodec === 'aac') {
18107            // set PTS/DTS to expected PTS/DTS
18108            _pts2 = nextAudioPts;
18109          }
18110          // remember first PTS of our audioSamples
18111          firstPTS = _pts2;
18112          if (mdatSize > 0) {
18113            /* concatenate the audio data and construct the mdat in place
18114              (need 8 more bytes to fill length and mdat type) */
18115            mdatSize += offset;
18116            try {
18117              mdat = new Uint8Array(mdatSize);
18118            } catch (err) {
18119              this.observer.emit(Events.ERROR, Events.ERROR, {
18120                type: ErrorTypes.MUX_ERROR,
vendor: 5,140 bytes, lines 18121-18272
18121                details: ErrorDetails.REMUX_ALLOC_ERROR,
18122                fatal: false,
18123                error: err,
18124                bytes: mdatSize,
18125                reason: "fail allocating audio mdat " + mdatSize
18126              });
18127              return;
18128            }
18129            if (!rawMPEG) {
18130              var view = new DataView(mdat.buffer);
18131              view.setUint32(0, mdatSize);
18132              mdat.set(MP4.types.mdat, 4);
18133            }
18134          } else {
18135            // no audio samples
18136            return;
18137          }
18138        }
18139        mdat.set(unit, offset);
18140        var unitLen = unit.byteLength;
18141        offset += unitLen;
18142        // Default the sample's duration to the computed mp4SampleDuration, which will either be 1024 for AAC or 1152 for MPEG
18143        // In the case that we have 1 sample, this will be the duration. If we have more than one sample, the duration
18144        // becomes the PTS diff with the previous sample
18145        outputSamples.push(new Mp4Sample(true, mp4SampleDuration, unitLen, 0));
18146        lastPTS = _pts2;
18147      }
18148
18149      // We could end up with no audio samples if all input samples were overlapping with the previously remuxed ones
18150      var nbSamples = outputSamples.length;
18151      if (!nbSamples) {
18152        return;
18153      }
18154
18155      // The next audio sample PTS should be equal to last sample PTS + duration
18156      var lastSample = outputSamples[outputSamples.length - 1];
18157      this.nextAudioPts = nextAudioPts = lastPTS + scaleFactor * lastSample.duration;
18158
18159      // Set the track samples from inputSamples to outputSamples before remuxing
18160      var moof = rawMPEG ? new Uint8Array(0) : MP4.moof(track.sequenceNumber++, firstPTS / scaleFactor, _extends({}, track, {
18161        samples: outputSamples
18162      }));
18163
18164      // Clear the track samples. This also clears the samples array in the demuxer, since the reference is shared
18165      track.samples = [];
18166      var start = firstPTS / inputTimeScale;
18167      var end = nextAudioPts / inputTimeScale;
18168      var type = 'audio';
18169      var audioData = {
18170        data1: moof,
18171        data2: mdat,
18172        startPTS: start,
18173        endPTS: end,
18174        startDTS: start,
18175        endDTS: end,
18176        type: type,
18177        hasAudio: true,
18178        hasVideo: false,
18179        nb: nbSamples
18180      };
18181      this.isAudioContiguous = true;
18182      return audioData;
18183    };
18184    return MP4Remuxer;
18185  }();
18186  function normalizePts(value, reference) {
18187    var offset;
18188    if (reference === null) {
18189      return value;
18190    }
18191    if (reference < value) {
18192      // - 2^33
18193      offset = -8589934592;
18194    } else {
18195      // + 2^33
18196      offset = 8589934592;
18197    }
18198    /* PTS is 33bit (from 0 to 2^33 -1)
18199      if diff between value and reference is bigger than half of the amplitude (2^32) then it means that
18200      PTS looping occured. fill the gap */
18201    while (Math.abs(value - reference) > 4294967296) {
18202      value += offset;
18203    }
18204    return value;
18205  }
18206  function findKeyframeIndex(samples) {
18207    for (var i = 0; i < samples.length; i++) {
18208      if (samples[i].key) {
18209        return i;
18210      }
18211    }
18212    return -1;
18213  }
18214  function flushTextTrackMetadataCueSamples(track, timeOffset, initPTS, initDTS) {
18215    var length = track.samples.length;
18216    if (!length) {
18217      return;
18218    }
18219    var inputTimeScale = track.inputTimeScale;
18220    for (var index = 0; index < length; index++) {
18221      var sample = track.samples[index];
18222      // setting id3 pts, dts to relative time
18223      // using this._initPTS and this._initDTS to calculate relative time
18224      sample.pts = normalizePts(sample.pts - initPTS.baseTime * inputTimeScale / initPTS.timescale, timeOffset * inputTimeScale) / inputTimeScale;
18225      sample.dts = normalizePts(sample.dts - initDTS.baseTime * inputTimeScale / initDTS.timescale, timeOffset * inputTimeScale) / inputTimeScale;
18226    }
18227    var samples = track.samples;
18228    track.samples = [];
18229    return {
18230      samples: samples
18231    };
18232  }
18233  function flushTextTrackUserdataCueSamples(track, timeOffset, initPTS) {
18234    var length = track.samples.length;
18235    if (!length) {
18236      return;
18237    }
18238    var inputTimeScale = track.inputTimeScale;
18239    for (var index = 0; index < length; index++) {
18240      var sample = track.samples[index];
18241      // setting text pts, dts to relative time
18242      // using this._initPTS and this._initDTS to calculate relative time
18243      sample.pts = normalizePts(sample.pts - initPTS.baseTime * inputTimeScale / initPTS.timescale, timeOffset * inputTimeScale) / inputTimeScale;
18244    }
18245    track.samples.sort(function (a, b) {
18246      return a.pts - b.pts;
18247    });
18248    var samples = track.samples;
18249    track.samples = [];
18250    return {
18251      samples: samples
18252    };
18253  }
18254  var Mp4Sample = function Mp4Sample(isKeyframe, duration, size, cts) {
18255    this.size = void 0;
18256    this.duration = void 0;
18257    this.cts = void 0;
18258    this.flags = void 0;
18259    this.duration = duration;
18260    this.size = size;
18261    this.cts = cts;
18262    this.flags = {
18263      isLeading: 0,
18264      isDependedOn: 0,
18265      hasRedundancy: 0,
18266      degradPrio: 0,
18267      dependsOn: isKeyframe ? 2 : 1,
18268      isNonSync: isKeyframe ? 0 : 1
18269    };
18270  };
18271
18272  var PassThroughRemuxer = /*#__PURE__*/function () {
18273    function PassThroughRemuxer(observer, config, typeSupported, logger) {
18274      this.logger = void 0;
18275      this.emitInitSegment = false;
18276      this.audioCodec = void 0;
18277      this.videoCodec = void 0;
18278      this.initData = void 0;
18279      this.initPTS = null;
18280      this.initTracks = void 0;
18281      this.lastEndTime = null;
18282      this.logger = logger;
18283    }
18284    var _proto = PassThroughRemuxer.prototype;
18285    _proto.destroy = function destroy() {};
18286    _proto.resetTimeStamp = function resetTimeStamp(defaultInitPTS) {
18287      this.initPTS = defaultInitPTS;
18288      this.lastEndTime = null;
18289    };
18290    _proto.resetNextTimestamp = function resetNextTimestamp() {
18291      this.lastEndTime = null;
18292    };
18293    _proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, decryptdata) {
18294      this.audioCodec = audioCodec;
18295      this.videoCodec = videoCodec;
18296      this.generateInitSegment(patchEncyptionData(initSegment, decryptdata));
18297      this.emitInitSegment = true;
18298    };
18299    _proto.generateInitSegment = function generateInitSegment(initSegment) {
18300      var audioCodec = this.audioCodec,
18301        videoCodec = this.videoCodec;
18302      if (!(initSegment != null && initSegment.byteLength)) {
18303        this.initTracks = undefined;
18304        this.initData = undefined;
18305        return;
18306      }
18307      var initData = this.initData = parseInitSegment(initSegment);
18308
18309      // Get codec from initSegment or fallback to default
18310      if (initData.audio) {
18311        audioCodec = getParsedTrackCodec(initData.audio, ElementaryStreamTypes.AUDIO);
18312      }
18313      if (initData.video) {
18314        videoCodec = getParsedTrackCodec(initData.video, ElementaryStreamTypes.VIDEO);
18315      }
18316      var tracks = {};
18317      if (initData.audio && initData.video) {
18318        tracks.audiovideo = {
18319          container: 'video/mp4',
18320          codec: audioCodec + ',' + videoCodec,
18321          initSegment: initSegment,
18322          id: 'main'
18323        };
18324      } else if (initData.audio) {
18325        tracks.audio = {
18326          container: 'audio/mp4',
18327          codec: audioCodec,
18328          initSegment: initSegment,
18329          id: 'audio'
18330        };
18331      } else if (initData.video) {
18332        tracks.video = {
18333          container: 'video/mp4',
18334          codec: videoCodec,
18335          initSegment: initSegment,
18336          id: 'main'
18337        };
18338      } else {
18339        this.logger.warn('[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes.');
18340      }
18341      this.initTracks = tracks;
18342    };
18343    _proto.remux = function remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset) {
18344      var _initData, _initData2;
18345      var initPTS = this.initPTS,
18346        lastEndTime = this.lastEndTime;
18347      var result = {
18348        audio: undefined,
18349        video: undefined,
18350        text: textTrack,
18351        id3: id3Track,
18352        initSegment: undefined
18353      };
18354
18355      // If we haven't yet set a lastEndDTS, or it was reset, set it to the provided timeOffset. We want to use the
18356      // lastEndDTS over timeOffset whenever possible; during progressive playback, the media source will not update
18357      // the media duration (which is what timeOffset is provided as) before we need to process the next chunk.
18358      if (!isFiniteNumber(lastEndTime)) {
18359        lastEndTime = this.lastEndTime = timeOffset || 0;
18360      }
18361
18362      // The binary segment data is added to the videoTrack in the mp4demuxer. We don't check to see if the data is only
18363      // audio or video (or both); adding it to video was an arbitrary choice.
18364      var data = videoTrack.samples;
18365      if (!(data != null && data.length)) {
18366        return result;
18367      }
18368      var initSegment = {
18369        initPTS: undefined,
18370        timescale: 1
18371      };
18372      var initData = this.initData;
18373      if (!((_initData = initData) != null && _initData.length)) {
18374        this.generateInitSegment(data);
18375        initData = this.initData;
18376      }
18377      if (!((_initData2 = initData) != null && _initData2.length)) {
18378        // We can't remux if the initSegment could not be generated
18379        this.logger.warn('[passthrough-remuxer.ts]: Failed to generate initSegment.');
18380        return result;
18381      }
18382      if (this.emitInitSegment) {
18383        initSegment.tracks = this.initTracks;
18384        this.emitInitSegment = false;
18385      }
18386      var duration = getDuration(data, initData);
18387      var startDTS = getStartDTS(initData, data);
18388      var decodeTime = startDTS === null ? timeOffset : startDTS;
18389      if (isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) || initSegment.timescale !== initPTS.timescale && accurateTimeOffset) {
18390        initSegment.initPTS = decodeTime - timeOffset;
18391        if (initPTS && initPTS.timescale === 1) {
18392          this.logger.warn("Adjusting initPTS @" + timeOffset + " from " + initPTS.baseTime / initPTS.timescale + " to " + initSegment.initPTS);
18393        }
18394        this.initPTS = initPTS = {
18395          baseTime: initSegment.initPTS,
18396          timescale: 1
18397        };
18398      }
18399      var startTime = audioTrack ? decodeTime - initPTS.baseTime / initPTS.timescale : lastEndTime;
18400      var endTime = startTime + duration;
18401      offsetStartDTS(initData, data, initPTS.baseTime / initPTS.timescale);
18402      if (duration > 0) {
18403        this.lastEndTime = endTime;
18404      } else {
18405        this.logger.warn('Duration parsed from mp4 should be greater than zero');
18406        this.resetNextTimestamp();
18407      }
18408      var hasAudio = !!initData.audio;
18409      var hasVideo = !!initData.video;
18410      var type = '';
18411      if (hasAudio) {
18412        type += 'audio';
18413      }
18414      if (hasVideo) {
18415        type += 'video';
18416      }
18417      var track = {
18418        data1: data,
18419        startPTS: startTime,
18420        startDTS: startTime,
18421        endPTS: endTime,
18422        endDTS: endTime,
18423        type: type,
18424        hasAudio: hasAudio,
18425        hasVideo: hasVideo,
18426        nb: 1,
18427        dropped: 0
18428      };
18429      result.audio = track.type === 'audio' ? track : undefined;
18430      result.video = track.type !== 'audio' ? track : undefined;
18431      result.initSegment = initSegment;
18432      result.id3 = flushTextTrackMetadataCueSamples(id3Track, timeOffset, initPTS, initPTS);
18433      if (textTrack.samples.length) {
18434        result.text = flushTextTrackUserdataCueSamples(textTrack, timeOffset, initPTS);
18435      }
18436      return result;
18437    };
18438    return PassThroughRemuxer;
18439  }();
18440  function isInvalidInitPts(initPTS, startDTS, timeOffset, duration) {
18441    if (initPTS === null) {
18442      return true;
18443    }
18444    // InitPTS is invalid when distance from program would be more than segment duration or a minimum of one second
18445    var minDuration = Math.max(duration, 1);
18446    var startTime = startDTS - initPTS.baseTime / initPTS.timescale;
18447    return Math.abs(startTime - timeOffset) > minDuration;
18448  }
18449  function getParsedTrackCodec(track, type) {
18450    var parsedCodec = track == null ? void 0 : track.codec;
18451    if (parsedCodec && parsedCodec.length > 4) {
18452      return parsedCodec;
18453    }
18454    if (type === ElementaryStreamTypes.AUDIO) {
18455      if (parsedCodec === 'ec-3' || parsedCodec === 'ac-3' || parsedCodec === 'alac') {
18456        return parsedCodec;
18457      }
18458      if (parsedCodec === 'fLaC' || parsedCodec === 'Opus') {
18459        // Opting not to get `preferManagedMediaSource` from player config for isSupported() check for simplicity
18460        var preferManagedMediaSource = false;
18461        return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
18462      }
18463      var result = 'mp4a.40.5';
18464      this.logger.info("Parsed audio codec \"" + parsedCodec + "\" or audio object type not handled. Using \"" + result + "\"");
18465      return result;
18466    }
18467    // Provide defaults based on codec type
18468    // This allows for some playback of some fmp4 playlists without CODECS defined in manifest
18469    this.logger.warn("Unhandled video codec \"" + parsedCodec + "\"");
18470    if (parsedCodec === 'hvc1' || parsedCodec === 'hev1') {
18471      return 'hvc1.1.6.L120.90';
18472    }
18473    if (parsedCodec === 'av01') {
18474      return 'av01.0.04M.08';
18475    }
18476    return 'avc1.42e01e';
18477  }
18478
18479  var now;
18480  // performance.now() not available on WebWorker, at least on Safari Desktop
18481  try {
18482    now = self.performance.now.bind(self.performance);
18483  } catch (err) {
18484    now = Date.now;
18485  }
18486  var muxConfig = [{
18487    demux: MP4Demuxer,
18488    remux: PassThroughRemuxer
18489  }, {
18490    demux: TSDemuxer,
18491    remux: MP4Remuxer
18492  }, {
18493    demux: AACDemuxer,
18494    remux: MP4Remuxer
18495  }, {
18496    demux: MP3Demuxer,
18497    remux: MP4Remuxer
18498  }];
18499  var Transmuxer = /*#__PURE__*/function () {
18500    function Transmuxer(observer, typeSupported, config, vendor, id, logger) {
18501      this.asyncResult = false;
vendor: 13,616 bytes, lines 18502-18826
18502      this.logger = void 0;
18503      this.observer = void 0;
18504      this.typeSupported = void 0;
18505      this.config = void 0;
18506      this.id = void 0;
18507      this.demuxer = void 0;
18508      this.remuxer = void 0;
18509      this.decrypter = void 0;
18510      this.probe = void 0;
18511      this.decryptionPromise = null;
18512      this.transmuxConfig = void 0;
18513      this.currentTransmuxState = void 0;
18514      this.observer = observer;
18515      this.typeSupported = typeSupported;
18516      this.config = config;
18517      this.id = id;
18518      this.logger = logger;
18519    }
18520    var _proto = Transmuxer.prototype;
18521    _proto.configure = function configure(transmuxConfig) {
18522      this.transmuxConfig = transmuxConfig;
18523      if (this.decrypter) {
18524        this.decrypter.reset();
18525      }
18526    };
18527    _proto.push = function push(data, decryptdata, chunkMeta, state) {
18528      var _this = this;
18529      var stats = chunkMeta.transmuxing;
18530      stats.executeStart = now();
18531      var uintData = new Uint8Array(data);
18532      var currentTransmuxState = this.currentTransmuxState,
18533        transmuxConfig = this.transmuxConfig;
18534      if (state) {
18535        this.currentTransmuxState = state;
18536      }
18537      var _ref = state || currentTransmuxState,
18538        contiguous = _ref.contiguous,
18539        discontinuity = _ref.discontinuity,
18540        trackSwitch = _ref.trackSwitch,
18541        accurateTimeOffset = _ref.accurateTimeOffset,
18542        timeOffset = _ref.timeOffset,
18543        initSegmentChange = _ref.initSegmentChange;
18544      var audioCodec = transmuxConfig.audioCodec,
18545        videoCodec = transmuxConfig.videoCodec,
18546        defaultInitPts = transmuxConfig.defaultInitPts,
18547        duration = transmuxConfig.duration,
18548        initSegmentData = transmuxConfig.initSegmentData;
18549      var keyData = getEncryptionType(uintData, decryptdata);
18550      if (keyData && isFullSegmentEncryption(keyData.method)) {
18551        var decrypter = this.getDecrypter();
18552        var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
18553
18554        // Software decryption is synchronous; webCrypto is not
18555        if (decrypter.isSync()) {
18556          // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
18557          // data is handled in the flush() call
18558          var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
18559          // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
18560          var loadingParts = chunkMeta.part > -1;
18561          if (loadingParts) {
18562            decryptedData = decrypter.flush();
18563          }
18564          if (!decryptedData) {
18565            stats.executeEnd = now();
18566            return emptyResult(chunkMeta);
18567          }
18568          uintData = new Uint8Array(decryptedData);
18569        } else {
18570          this.asyncResult = true;
18571          this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
18572            // Calling push here is important; if flush() is called while this is still resolving, this ensures that
18573            // the decrypted data has been transmuxed
18574            var result = _this.push(decryptedData, null, chunkMeta);
18575            _this.decryptionPromise = null;
18576            return result;
18577          });
18578          return this.decryptionPromise;
18579        }
18580      }
18581      var resetMuxers = this.needsProbing(discontinuity, trackSwitch);
18582      if (resetMuxers) {
18583        var error = this.configureTransmuxer(uintData);
18584        if (error) {
18585          this.logger.warn("[transmuxer] " + error.message);
18586          this.observer.emit(Events.ERROR, Events.ERROR, {
18587            type: ErrorTypes.MEDIA_ERROR,
18588            details: ErrorDetails.FRAG_PARSING_ERROR,
18589            fatal: false,
18590            error: error,
18591            reason: error.message
18592          });
18593          stats.executeEnd = now();
18594          return emptyResult(chunkMeta);
18595        }
18596      }
18597      if (discontinuity || trackSwitch || initSegmentChange || resetMuxers) {
18598        this.resetInitSegment(initSegmentData, audioCodec, videoCodec, duration, decryptdata);
18599      }
18600      if (discontinuity || initSegmentChange || resetMuxers) {
18601        this.resetInitialTimestamp(defaultInitPts);
18602      }
18603      if (!contiguous) {
18604        this.resetContiguity();
18605      }
18606      var result = this.transmux(uintData, keyData, timeOffset, accurateTimeOffset, chunkMeta);
18607      this.asyncResult = isPromise(result);
18608      var currentState = this.currentTransmuxState;
18609      currentState.contiguous = true;
18610      currentState.discontinuity = false;
18611      currentState.trackSwitch = false;
18612      stats.executeEnd = now();
18613      return result;
18614    }
18615
18616    // Due to data caching, flush calls can produce more than one TransmuxerResult (hence the Array type)
18617    ;
18618    _proto.flush = function flush(chunkMeta) {
18619      var _this2 = this;
18620      var stats = chunkMeta.transmuxing;
18621      stats.executeStart = now();
18622      var decrypter = this.decrypter,
18623        currentTransmuxState = this.currentTransmuxState,
18624        decryptionPromise = this.decryptionPromise;
18625      if (decryptionPromise) {
18626        this.asyncResult = true;
18627        // Upon resolution, the decryption promise calls push() and returns its TransmuxerResult up the stack. Therefore
18628        // only flushing is required for async decryption
18629        return decryptionPromise.then(function () {
18630          return _this2.flush(chunkMeta);
18631        });
18632      }
18633      var transmuxResults = [];
18634      var timeOffset = currentTransmuxState.timeOffset;
18635      if (decrypter) {
18636        // The decrypter may have data cached, which needs to be demuxed. In this case we'll have two TransmuxResults
18637        // This happens in the case that we receive only 1 push call for a segment (either for non-progressive downloads,
18638        // or for progressive downloads with small segments)
18639        var decryptedData = decrypter.flush();
18640        if (decryptedData) {
18641          // Push always returns a TransmuxerResult if decryptdata is null
18642          transmuxResults.push(this.push(decryptedData, null, chunkMeta));
18643        }
18644      }
18645      var demuxer = this.demuxer,
18646        remuxer = this.remuxer;
18647      if (!demuxer || !remuxer) {
18648        // If probing failed, then Hls.js has been given content its not able to handle
18649        stats.executeEnd = now();
18650        var emptyResults = [emptyResult(chunkMeta)];
18651        if (this.asyncResult) {
18652          return Promise.resolve(emptyResults);
18653        }
18654        return emptyResults;
18655      }
18656      var demuxResultOrPromise = demuxer.flush(timeOffset);
18657      if (isPromise(demuxResultOrPromise)) {
18658        this.asyncResult = true;
18659        // Decrypt final SAMPLE-AES samples
18660        return demuxResultOrPromise.then(function (demuxResult) {
18661          _this2.flushRemux(transmuxResults, demuxResult, chunkMeta);
18662          return transmuxResults;
18663        });
18664      }
18665      this.flushRemux(transmuxResults, demuxResultOrPromise, chunkMeta);
18666      if (this.asyncResult) {
18667        return Promise.resolve(transmuxResults);
18668      }
18669      return transmuxResults;
18670    };
18671    _proto.flushRemux = function flushRemux(transmuxResults, demuxResult, chunkMeta) {
18672      var audioTrack = demuxResult.audioTrack,
18673        videoTrack = demuxResult.videoTrack,
18674        id3Track = demuxResult.id3Track,
18675        textTrack = demuxResult.textTrack;
18676      var _this$currentTransmux = this.currentTransmuxState,
18677        accurateTimeOffset = _this$currentTransmux.accurateTimeOffset,
18678        timeOffset = _this$currentTransmux.timeOffset;
18679      this.logger.log("[transmuxer.ts]: Flushed " + this.id + " sn: " + chunkMeta.sn + (chunkMeta.part > -1 ? ' p: ' + chunkMeta.part : '') + " of " + (this.id === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + chunkMeta.level);
18680      var remuxResult = this.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset, true, this.id);
18681      transmuxResults.push({
18682        remuxResult: remuxResult,
18683        chunkMeta: chunkMeta
18684      });
18685      chunkMeta.transmuxing.executeEnd = now();
18686    };
18687    _proto.resetInitialTimestamp = function resetInitialTimestamp(defaultInitPts) {
18688      var demuxer = this.demuxer,
18689        remuxer = this.remuxer;
18690      if (!demuxer || !remuxer) {
18691        return;
18692      }
18693      demuxer.resetTimeStamp(defaultInitPts);
18694      remuxer.resetTimeStamp(defaultInitPts);
18695    };
18696    _proto.resetContiguity = function resetContiguity() {
18697      var demuxer = this.demuxer,
18698        remuxer = this.remuxer;
18699      if (!demuxer || !remuxer) {
18700        return;
18701      }
18702      demuxer.resetContiguity();
18703      remuxer.resetNextTimestamp();
18704    };
18705    _proto.resetInitSegment = function resetInitSegment(initSegmentData, audioCodec, videoCodec, trackDuration, decryptdata) {
18706      var demuxer = this.demuxer,
18707        remuxer = this.remuxer;
18708      if (!demuxer || !remuxer) {
18709        return;
18710      }
18711      demuxer.resetInitSegment(initSegmentData, audioCodec, videoCodec, trackDuration);
18712      remuxer.resetInitSegment(initSegmentData, audioCodec, videoCodec, decryptdata);
18713    };
18714    _proto.destroy = function destroy() {
18715      if (this.demuxer) {
18716        this.demuxer.destroy();
18717        this.demuxer = undefined;
18718      }
18719      if (this.remuxer) {
18720        this.remuxer.destroy();
18721        this.remuxer = undefined;
18722      }
18723    };
18724    _proto.transmux = function transmux(data, keyData, timeOffset, accurateTimeOffset, chunkMeta) {
18725      var result;
18726      if (keyData && keyData.method === 'SAMPLE-AES') {
18727        result = this.transmuxSampleAes(data, keyData, timeOffset, accurateTimeOffset, chunkMeta);
18728      } else {
18729        result = this.transmuxUnencrypted(data, timeOffset, accurateTimeOffset, chunkMeta);
18730      }
18731      return result;
18732    };
18733    _proto.transmuxUnencrypted = function transmuxUnencrypted(data, timeOffset, accurateTimeOffset, chunkMeta) {
18734      var _demux = this.demuxer.demux(data, timeOffset, false, !this.config.progressive),
18735        audioTrack = _demux.audioTrack,
18736        videoTrack = _demux.videoTrack,
18737        id3Track = _demux.id3Track,
18738        textTrack = _demux.textTrack;
18739      var remuxResult = this.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset, false, this.id);
18740      return {
18741        remuxResult: remuxResult,
18742        chunkMeta: chunkMeta
18743      };
18744    };
18745    _proto.transmuxSampleAes = function transmuxSampleAes(data, decryptData, timeOffset, accurateTimeOffset, chunkMeta) {
18746      var _this3 = this;
18747      return this.demuxer.demuxSampleAes(data, decryptData, timeOffset).then(function (demuxResult) {
18748        var remuxResult = _this3.remuxer.remux(demuxResult.audioTrack, demuxResult.videoTrack, demuxResult.id3Track, demuxResult.textTrack, timeOffset, accurateTimeOffset, false, _this3.id);
18749        return {
18750          remuxResult: remuxResult,
18751          chunkMeta: chunkMeta
18752        };
18753      });
18754    };
18755    _proto.configureTransmuxer = function configureTransmuxer(data) {
18756      var config = this.config,
18757        observer = this.observer,
18758        typeSupported = this.typeSupported;
18759      // probe for content type
18760      var mux;
18761      for (var i = 0, len = muxConfig.length; i < len; i++) {
18762        var _muxConfig$i$demux;
18763        if ((_muxConfig$i$demux = muxConfig[i].demux) != null && _muxConfig$i$demux.probe(data, this.logger)) {
18764          mux = muxConfig[i];
18765          break;
18766        }
18767      }
18768      if (!mux) {
18769        return new Error('Failed to find demuxer by probing fragment data');
18770      }
18771      // so let's check that current remuxer and demuxer are still valid
18772      var demuxer = this.demuxer;
18773      var remuxer = this.remuxer;
18774      var Remuxer = mux.remux;
18775      var Demuxer = mux.demux;
18776      if (!remuxer || !(remuxer instanceof Remuxer)) {
18777        this.remuxer = new Remuxer(observer, config, typeSupported, this.logger);
18778      }
18779      if (!demuxer || !(demuxer instanceof Demuxer)) {
18780        this.demuxer = new Demuxer(observer, config, typeSupported, this.logger);
18781        this.probe = Demuxer.probe;
18782      }
18783    };
18784    _proto.needsProbing = function needsProbing(discontinuity, trackSwitch) {
18785      // in case of continuity change, or track switch
18786      // we might switch from content type (AAC container to TS container, or TS to fmp4 for example)
18787      return !this.demuxer || !this.remuxer || discontinuity || trackSwitch;
18788    };
18789    _proto.getDecrypter = function getDecrypter() {
18790      var decrypter = this.decrypter;
18791      if (!decrypter) {
18792        decrypter = this.decrypter = new Decrypter(this.config);
18793      }
18794      return decrypter;
18795    };
18796    return Transmuxer;
18797  }();
18798  function getEncryptionType(data, decryptData) {
18799    var encryptionType = null;
18800    if (data.byteLength > 0 && (decryptData == null ? void 0 : decryptData.key) != null && decryptData.iv !== null && decryptData.method != null) {
18801      encryptionType = decryptData;
18802    }
18803    return encryptionType;
18804  }
18805  var emptyResult = function emptyResult(chunkMeta) {
18806    return {
18807      remuxResult: {},
18808      chunkMeta: chunkMeta
18809    };
18810  };
18811  function isPromise(p) {
18812    return 'then' in p && p.then instanceof Function;
18813  }
18814  var TransmuxConfig = function TransmuxConfig(audioCodec, videoCodec, initSegmentData, duration, defaultInitPts) {
18815    this.audioCodec = void 0;
18816    this.videoCodec = void 0;
18817    this.initSegmentData = void 0;
18818    this.duration = void 0;
18819    this.defaultInitPts = void 0;
18820    this.audioCodec = audioCodec;
18821    this.videoCodec = videoCodec;
18822    this.initSegmentData = initSegmentData;
18823    this.duration = duration;
18824    this.defaultInitPts = defaultInitPts || null;
18825  };
18826  var TransmuxState = function TransmuxState(discontinuity, contiguous, accurateTimeOff
vendor: 5,517 bytes, lines 18826-19011
18826set, trackSwitch, timeOffset, initSegmentChange) {
18827    this.discontinuity = void 0;
18828    this.contiguous = void 0;
18829    this.accurateTimeOffset = void 0;
18830    this.trackSwitch = void 0;
18831    this.timeOffset = void 0;
18832    this.initSegmentChange = void 0;
18833    this.discontinuity = discontinuity;
18834    this.contiguous = contiguous;
18835    this.accurateTimeOffset = accurateTimeOffset;
18836    this.trackSwitch = trackSwitch;
18837    this.timeOffset = timeOffset;
18838    this.initSegmentChange = initSegmentChange;
18839  };
18840
18841  var eventemitter3 = {exports: {}};
18842
18843  (function (module) {
18844
18845  	var has = Object.prototype.hasOwnProperty
18846  	  , prefix = '~';
18847
18848  	/**
18849  	 * Constructor to create a storage for our `EE` objects.
18850  	 * An `Events` instance is a plain object whose properties are event names.
18851  	 *
18852  	 * @constructor
18853  	 * @private
18854  	 */
18855  	function Events() {}
18856
18857  	//
18858  	// We try to not inherit from `Object.prototype`. In some engines creating an
18859  	// instance in this way is faster than calling `Object.create(null)` directly.
18860  	// If `Object.create(null)` is not supported we prefix the event names with a
18861  	// character to make sure that the built-in object properties are not
18862  	// overridden or used as an attack vector.
18863  	//
18864  	if (Object.create) {
18865  	  Events.prototype = Object.create(null);
18866
18867  	  //
18868  	  // This hack is needed because the `__proto__` property is still inherited in
18869  	  // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
18870  	  //
18871  	  if (!new Events().__proto__) prefix = false;
18872  	}
18873
18874  	/**
18875  	 * Representation of a single event listener.
18876  	 *
18877  	 * @param {Function} fn The listener function.
18878  	 * @param {*} context The context to invoke the listener with.
18879  	 * @param {Boolean} [once=false] Specify if the listener is a one-time listener.
18880  	 * @constructor
18881  	 * @private
18882  	 */
18883  	function EE(fn, context, once) {
18884  	  this.fn = fn;
18885  	  this.context = context;
18886  	  this.once = once || false;
18887  	}
18888
18889  	/**
18890  	 * Add a listener for a given event.
18891  	 *
18892  	 * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
18893  	 * @param {(String|Symbol)} event The event name.
18894  	 * @param {Function} fn The listener function.
18895  	 * @param {*} context The context to invoke the listener with.
18896  	 * @param {Boolean} once Specify if the listener is a one-time listener.
18897  	 * @returns {EventEmitter}
18898  	 * @private
18899  	 */
18900  	function addListener(emitter, event, fn, context, once) {
18901  	  if (typeof fn !== 'function') {
18902  	    throw new TypeError('The listener must be a function');
18903  	  }
18904
18905  	  var listener = new EE(fn, context || emitter, once)
18906  	    , evt = prefix ? prefix + event : event;
18907
18908  	  if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
18909  	  else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
18910  	  else emitter._events[evt] = [emitter._events[evt], listener];
18911
18912  	  return emitter;
18913  	}
18914
18915  	/**
18916  	 * Clear event by name.
18917  	 *
18918  	 * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
18919  	 * @param {(String|Symbol)} evt The Event name.
18920  	 * @private
18921  	 */
18922  	function clearEvent(emitter, evt) {
18923  	  if (--emitter._eventsCount === 0) emitter._events = new Events();
18924  	  else delete emitter._events[evt];
18925  	}
18926
18927  	/**
18928  	 * Minimal `EventEmitter` interface that is molded against the Node.js
18929  	 * `EventEmitter` interface.
18930  	 *
18931  	 * @constructor
18932  	 * @public
18933  	 */
18934  	function EventEmitter() {
18935  	  this._events = new Events();
18936  	  this._eventsCount = 0;
18937  	}
18938
18939  	/**
18940  	 * Return an array listing the events for which the emitter has registered
18941  	 * listeners.
18942  	 *
18943  	 * @returns {Array}
18944  	 * @public
18945  	 */
18946  	EventEmitter.prototype.eventNames = function eventNames() {
18947  	  var names = []
18948  	    , events
18949  	    , name;
18950
18951  	  if (this._eventsCount === 0) return names;
18952
18953  	  for (name in (events = this._events)) {
18954  	    if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
18955  	  }
18956
18957  	  if (Object.getOwnPropertySymbols) {
18958  	    return names.concat(Object.getOwnPropertySymbols(events));
18959  	  }
18960
18961  	  return names;
18962  	};
18963
18964  	/**
18965  	 * Return the listeners registered for a given event.
18966  	 *
18967  	 * @param {(String|Symbol)} event The event name.
18968  	 * @returns {Array} The registered listeners.
18969  	 * @public
18970  	 */
18971  	EventEmitter.prototype.listeners = function listeners(event) {
18972  	  var evt = prefix ? prefix + event : event
18973  	    , handlers = this._events[evt];
18974
18975  	  if (!handlers) return [];
18976  	  if (handlers.fn) return [handlers.fn];
18977
18978  	  for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
18979  	    ee[i] = handlers[i].fn;
18980  	  }
18981
18982  	  return ee;
18983  	};
18984
18985  	/**
18986  	 * Return the number of listeners listening to a given event.
18987  	 *
18988  	 * @param {(String|Symbol)} event The event name.
18989  	 * @returns {Number} The number of listeners.
18990  	 * @public
18991  	 */
18992  	EventEmitter.prototype.listenerCount = function listenerCount(event) {
18993  	  var evt = prefix ? prefix + event : event
18994  	    , listeners = this._events[evt];
18995
18996  	  if (!listeners) return 0;
18997  	  if (listeners.fn) return 1;
18998  	  return listeners.length;
18999  	};
19000
19001  	/**
19002  	 * Calls each of the listeners registered for a given event.
19003  	 *
19004  	 * @param {(String|Symbol)} event The event name.
19005  	 * @returns {Boolean} `true` if the event had listeners, else `false`.
19006  	 * @public
19007  	 */
19008  	EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
19009  	  var evt = prefix ? prefix + event : event;
19010
19011  	  if (!this._events[evt]) return false;
vendor: 19,133 bytes, lines 19012-19592
19012
19013  	  var listeners = this._events[evt]
19014  	    , len = arguments.length
19015  	    , args
19016  	    , i;
19017
19018  	  if (listeners.fn) {
19019  	    if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
19020
19021  	    switch (len) {
19022  	      case 1: return listeners.fn.call(listeners.context), true;
19023  	      case 2: return listeners.fn.call(listeners.context, a1), true;
19024  	      case 3: return listeners.fn.call(listeners.context, a1, a2), true;
19025  	      case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
19026  	      case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
19027  	      case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
19028  	    }
19029
19030  	    for (i = 1, args = new Array(len -1); i < len; i++) {
19031  	      args[i - 1] = arguments[i];
19032  	    }
19033
19034  	    listeners.fn.apply(listeners.context, args);
19035  	  } else {
19036  	    var length = listeners.length
19037  	      , j;
19038
19039  	    for (i = 0; i < length; i++) {
19040  	      if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
19041
19042  	      switch (len) {
19043  	        case 1: listeners[i].fn.call(listeners[i].context); break;
19044  	        case 2: listeners[i].fn.call(listeners[i].context, a1); break;
19045  	        case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
19046  	        case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
19047  	        default:
19048  	          if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
19049  	            args[j - 1] = arguments[j];
19050  	          }
19051
19052  	          listeners[i].fn.apply(listeners[i].context, args);
19053  	      }
19054  	    }
19055  	  }
19056
19057  	  return true;
19058  	};
19059
19060  	/**
19061  	 * Add a listener for a given event.
19062  	 *
19063  	 * @param {(String|Symbol)} event The event name.
19064  	 * @param {Function} fn The listener function.
19065  	 * @param {*} [context=this] The context to invoke the listener with.
19066  	 * @returns {EventEmitter} `this`.
19067  	 * @public
19068  	 */
19069  	EventEmitter.prototype.on = function on(event, fn, context) {
19070  	  return addListener(this, event, fn, context, false);
19071  	};
19072
19073  	/**
19074  	 * Add a one-time listener for a given event.
19075  	 *
19076  	 * @param {(String|Symbol)} event The event name.
19077  	 * @param {Function} fn The listener function.
19078  	 * @param {*} [context=this] The context to invoke the listener with.
19079  	 * @returns {EventEmitter} `this`.
19080  	 * @public
19081  	 */
19082  	EventEmitter.prototype.once = function once(event, fn, context) {
19083  	  return addListener(this, event, fn, context, true);
19084  	};
19085
19086  	/**
19087  	 * Remove the listeners of a given event.
19088  	 *
19089  	 * @param {(String|Symbol)} event The event name.
19090  	 * @param {Function} fn Only remove the listeners that match this function.
19091  	 * @param {*} context Only remove the listeners that have this context.
19092  	 * @param {Boolean} once Only remove one-time listeners.
19093  	 * @returns {EventEmitter} `this`.
19094  	 * @public
19095  	 */
19096  	EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
19097  	  var evt = prefix ? prefix + event : event;
19098
19099  	  if (!this._events[evt]) return this;
19100  	  if (!fn) {
19101  	    clearEvent(this, evt);
19102  	    return this;
19103  	  }
19104
19105  	  var listeners = this._events[evt];
19106
19107  	  if (listeners.fn) {
19108  	    if (
19109  	      listeners.fn === fn &&
19110  	      (!once || listeners.once) &&
19111  	      (!context || listeners.context === context)
19112  	    ) {
19113  	      clearEvent(this, evt);
19114  	    }
19115  	  } else {
19116  	    for (var i = 0, events = [], length = listeners.length; i < length; i++) {
19117  	      if (
19118  	        listeners[i].fn !== fn ||
19119  	        (once && !listeners[i].once) ||
19120  	        (context && listeners[i].context !== context)
19121  	      ) {
19122  	        events.push(listeners[i]);
19123  	      }
19124  	    }
19125
19126  	    //
19127  	    // Reset the array, or remove it completely if we have no more listeners.
19128  	    //
19129  	    if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
19130  	    else clearEvent(this, evt);
19131  	  }
19132
19133  	  return this;
19134  	};
19135
19136  	/**
19137  	 * Remove all listeners, or those of the specified event.
19138  	 *
19139  	 * @param {(String|Symbol)} [event] The event name.
19140  	 * @returns {EventEmitter} `this`.
19141  	 * @public
19142  	 */
19143  	EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
19144  	  var evt;
19145
19146  	  if (event) {
19147  	    evt = prefix ? prefix + event : event;
19148  	    if (this._events[evt]) clearEvent(this, evt);
19149  	  } else {
19150  	    this._events = new Events();
19151  	    this._eventsCount = 0;
19152  	  }
19153
19154  	  return this;
19155  	};
19156
19157  	//
19158  	// Alias methods names because people roll like that.
19159  	//
19160  	EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
19161  	EventEmitter.prototype.addListener = EventEmitter.prototype.on;
19162
19163  	//
19164  	// Expose the prefix.
19165  	//
19166  	EventEmitter.prefixed = prefix;
19167
19168  	//
19169  	// Allow `EventEmitter` to be imported as module namespace.
19170  	//
19171  	EventEmitter.EventEmitter = EventEmitter;
19172
19173  	//
19174  	// Expose the module.
19175  	//
19176  	{
19177  	  module.exports = EventEmitter;
19178  	} 
19179  } (eventemitter3));
19180
19181  var eventemitter3Exports = eventemitter3.exports;
19182  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
19183
19184  var transmuxers = [];
19185  if (typeof __IN_WORKER__ !== 'undefined' && __IN_WORKER__) {
19186    startWorker();
19187  }
19188  function startWorker() {
19189    self.addEventListener('message', function (ev) {
19190      var data = ev.data;
19191      var instanceNo = data.instanceNo;
19192      if (instanceNo === undefined) {
19193        return;
19194      }
19195      var transmuxer = transmuxers[instanceNo];
19196      if (data.cmd === 'reset') {
19197        delete transmuxers[data.resetNo];
19198        if (transmuxer) {
19199          transmuxer.destroy();
19200        }
19201        data.cmd = 'init';
19202      }
19203      if (data.cmd === 'init') {
19204        var config = JSON.parse(data.config);
19205        var observer = new EventEmitter();
19206        observer.on(Events.FRAG_DECRYPTED, forwardMessage);
19207        observer.on(Events.ERROR, forwardMessage);
19208        var logger = enableLogs(config.debug, data.id);
19209        forwardWorkerLogs(logger, instanceNo);
19210        transmuxers[instanceNo] = new Transmuxer(observer, data.typeSupported, config, '', data.id, logger);
19211        forwardMessage('init', null, instanceNo);
19212        return;
19213      }
19214      if (!transmuxer) {
19215        return;
19216      }
19217      switch (data.cmd) {
19218        case 'configure':
19219          {
19220            transmuxer.configure(data.config);
19221            break;
19222          }
19223        case 'demux':
19224          {
19225            var transmuxResult = transmuxer.push(data.data, data.decryptdata, data.chunkMeta, data.state);
19226            if (isPromise(transmuxResult)) {
19227              transmuxResult.then(function (data) {
19228                emitTransmuxComplete(self, data, instanceNo);
19229              }).catch(function (error) {
19230                forwardMessage(Events.ERROR, {
19231                  instanceNo: instanceNo,
19232                  type: ErrorTypes.MEDIA_ERROR,
19233                  details: ErrorDetails.FRAG_PARSING_ERROR,
19234                  chunkMeta: data.chunkMeta,
19235                  fatal: false,
19236                  error: error,
19237                  err: error,
19238                  reason: "transmuxer-worker push error"
19239                }, instanceNo);
19240              });
19241            } else {
19242              emitTransmuxComplete(self, transmuxResult, instanceNo);
19243            }
19244            break;
19245          }
19246        case 'flush':
19247          {
19248            var chunkMeta = data.chunkMeta;
19249            var _transmuxResult = transmuxer.flush(chunkMeta);
19250            if (isPromise(_transmuxResult)) {
19251              _transmuxResult.then(function (results) {
19252                handleFlushResult(self, results, chunkMeta, instanceNo);
19253              }).catch(function (error) {
19254                forwardMessage(Events.ERROR, {
19255                  type: ErrorTypes.MEDIA_ERROR,
19256                  details: ErrorDetails.FRAG_PARSING_ERROR,
19257                  chunkMeta: data.chunkMeta,
19258                  fatal: false,
19259                  error: error,
19260                  err: error,
19261                  reason: "transmuxer-worker flush error"
19262                }, instanceNo);
19263              });
19264            } else {
19265              handleFlushResult(self, _transmuxResult, chunkMeta, instanceNo);
19266            }
19267            break;
19268          }
19269      }
19270    });
19271  }
19272  function emitTransmuxComplete(self, transmuxResult, instanceNo) {
19273    if (isEmptyResult(transmuxResult.remuxResult)) {
19274      return false;
19275    }
19276    var transferable = [];
19277    var _transmuxResult$remux = transmuxResult.remuxResult,
19278      audio = _transmuxResult$remux.audio,
19279      video = _transmuxResult$remux.video;
19280    if (audio) {
19281      addToTransferable(transferable, audio);
19282    }
19283    if (video) {
19284      addToTransferable(transferable, video);
19285    }
19286    self.postMessage({
19287      event: 'transmuxComplete',
19288      data: transmuxResult,
19289      instanceNo: instanceNo
19290    }, transferable);
19291    return true;
19292  }
19293
19294  // Converts data to a transferable object https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast)
19295  // in order to minimize message passing overhead
19296  function addToTransferable(transferable, track) {
19297    if (track.data1) {
19298      transferable.push(track.data1.buffer);
19299    }
19300    if (track.data2) {
19301      transferable.push(track.data2.buffer);
19302    }
19303  }
19304  function handleFlushResult(self, results, chunkMeta, instanceNo) {
19305    var parsed = results.reduce(function (parsed, result) {
19306      return emitTransmuxComplete(self, result, instanceNo) || parsed;
19307    }, false);
19308    if (!parsed) {
19309      // Emit at least one "transmuxComplete" message even if media is not found to update stream-controller state to PARSING
19310      self.postMessage({
19311        event: 'transmuxComplete',
19312        data: results[0],
19313        instanceNo: instanceNo
19314      });
19315    }
19316    self.postMessage({
19317      event: 'flush',
19318      data: chunkMeta,
19319      instanceNo: instanceNo
19320    });
19321  }
19322  function forwardMessage(event, data, instanceNo) {
19323    self.postMessage({
19324      event: event,
19325      data: data,
19326      instanceNo: instanceNo
19327    });
19328  }
19329  function forwardWorkerLogs(logger, instanceNo) {
19330    var _loop = function _loop(logFn) {
19331      var func = function func(message) {
19332        forwardMessage('workerLog', {
19333          logType: logFn,
19334          message: message
19335        }, instanceNo);
19336      };
19337      logger[logFn] = func;
19338    };
19339    for (var logFn in logger) {
19340      _loop(logFn);
19341    }
19342  }
19343  function isEmptyResult(remuxResult) {
19344    return !remuxResult.audio && !remuxResult.video && !remuxResult.text && !remuxResult.id3 && !remuxResult.initSegment;
19345  }
19346
19347  var version = undefined;
19348
19349  // ensure the worker ends up in the bundle
19350  // If the worker should not be included this gets aliased to empty.js
19351  var workerStore = {};
19352  function hasUMDWorker() {
19353    return typeof __HLS_WORKER_BUNDLE__ === 'function';
19354  }
19355  function injectWorker() {
19356    var workerContext = workerStore[version];
19357    if (workerContext) {
19358      workerContext.clientCount++;
19359      return workerContext;
19360    }
19361    var blob = new self.Blob(["var exports={};var module={exports:exports};function define(f){f()};define.amd=true;(" + __HLS_WORKER_BUNDLE__.toString() + ")(true);"], {
19362      type: 'text/javascript'
19363    });
19364    var objectURL = self.URL.createObjectURL(blob);
19365    var worker = new self.Worker(objectURL);
19366    var result = {
19367      worker: worker,
19368      objectURL: objectURL,
19369      clientCount: 1
19370    };
19371    workerStore[version] = result;
19372    return result;
19373  }
19374  function loadWorker(path) {
19375    var workerContext = workerStore[path];
19376    if (workerContext) {
19377      workerContext.clientCount++;
19378      return workerContext;
19379    }
19380    var scriptURL = new self.URL(path, self.location.href).href;
19381    var worker = new self.Worker(scriptURL);
19382    var result = {
19383      worker: worker,
19384      scriptURL: scriptURL,
19385      clientCount: 1
19386    };
19387    workerStore[path] = result;
19388    return result;
19389  }
19390  function removeWorkerFromStore(path) {
19391    var workerContext = workerStore[path || version];
19392    if (workerContext) {
19393      var clientCount = workerContext.clientCount--;
19394      if (clientCount === 1) {
19395        var worker = workerContext.worker,
19396          objectURL = workerContext.objectURL;
19397        delete workerStore[path || version];
19398        if (objectURL) {
19399          // revoke the Object URL that was used to create transmuxer worker, so as not to leak it
19400          self.URL.revokeObjectURL(objectURL);
19401        }
19402        worker.terminate();
19403      }
19404    }
19405  }
19406
19407  var transmuxerInstanceCount = 0;
19408  var TransmuxerInterface = /*#__PURE__*/function () {
19409    function TransmuxerInterface(_hls, id, onTransmuxComplete, onFlush) {
19410      var _this = this;
19411      this.error = null;
19412      this.hls = void 0;
19413      this.id = void 0;
19414      this.instanceNo = transmuxerInstanceCount++;
19415      this.observer = void 0;
19416      this.frag = null;
19417      this.part = null;
19418      this.useWorker = void 0;
19419      this.workerContext = null;
19420      this.transmuxer = null;
19421      this.onTransmuxComplete = void 0;
19422      this.onFlush = void 0;
19423      this.onWorkerMessage = function (event) {
19424        var data = event.data;
19425        var hls = _this.hls;
19426        if (!hls || !(data != null && data.event) || data.instanceNo !== _this.instanceNo) {
19427          return;
19428        }
19429        switch (data.event) {
19430          case 'init':
19431            {
19432              var _this$workerContext;
19433              var objectURL = (_this$workerContext = _this.workerContext) == null ? void 0 : _this$workerContext.objectURL;
19434              if (objectURL) {
19435                // revoke the Object URL that was used to create transmuxer worker, so as not to leak it
19436                self.URL.revokeObjectURL(objectURL);
19437              }
19438              break;
19439            }
19440          case 'transmuxComplete':
19441            {
19442              _this.handleTransmuxComplete(data.data);
19443              break;
19444            }
19445          case 'flush':
19446            {
19447              _this.onFlush(data.data);
19448              break;
19449            }
19450
19451          // pass logs from the worker thread to the main logger
19452          case 'workerLog':
19453            {
19454              if (hls.logger[data.data.logType]) {
19455                hls.logger[data.data.logType](data.data.message);
19456              }
19457              break;
19458            }
19459          default:
19460            {
19461              data.data = data.data || {};
19462              data.data.frag = _this.frag;
19463              data.data.part = _this.part;
19464              data.data.id = _this.id;
19465              hls.trigger(data.event, data.data);
19466              break;
19467            }
19468        }
19469      };
19470      this.onWorkerError = function (event) {
19471        if (!_this.hls) {
19472          return;
19473        }
19474        var error = new Error(event.message + "  (" + event.filename + ":" + event.lineno + ")");
19475        _this.hls.config.enableWorker = false;
19476        _this.hls.logger.warn("Error in \"" + _this.id + "\" Web Worker, fallback to inline");
19477        _this.hls.trigger(Events.ERROR, {
19478          type: ErrorTypes.OTHER_ERROR,
19479          details: ErrorDetails.INTERNAL_EXCEPTION,
19480          fatal: false,
19481          event: 'demuxerWorker',
19482          error: error
19483        });
19484      };
19485      var config = _hls.config;
19486      this.hls = _hls;
19487      this.id = id;
19488      this.useWorker = !!config.enableWorker;
19489      this.onTransmuxComplete = onTransmuxComplete;
19490      this.onFlush = onFlush;
19491      var forwardMessage = function forwardMessage(ev, data) {
19492        data = data || {};
19493        data.frag = _this.frag || undefined;
19494        if (ev === Events.ERROR) {
19495          data = data;
19496          data.parent = _this.id;
19497          data.part = _this.part;
19498          _this.error = data.error;
19499        }
19500        _this.hls.trigger(ev, data);
19501      };
19502
19503      // forward events to main thread
19504      this.observer = new EventEmitter();
19505      this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
19506      this.observer.on(Events.ERROR, forwardMessage);
19507      var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
19508      if (this.useWorker && typeof Worker !== 'undefined') {
19509        var logger = this.hls.logger;
19510        var canCreateWorker = config.workerPath || hasUMDWorker();
19511        if (canCreateWorker) {
19512          try {
19513            if (config.workerPath) {
19514              logger.log("loading Web Worker " + config.workerPath + " for \"" + id + "\"");
19515              this.workerContext = loadWorker(config.workerPath);
19516            } else {
19517              logger.log("injecting Web Worker for \"" + id + "\"");
19518              this.workerContext = injectWorker();
19519            }
19520            var worker = this.workerContext.worker;
19521            worker.addEventListener('message', this.onWorkerMessage);
19522            worker.addEventListener('error', this.onWorkerError);
19523            worker.postMessage({
19524              instanceNo: this.instanceNo,
19525              cmd: 'init',
19526              typeSupported: m2tsTypeSupported,
19527              id: id,
19528              config: JSON.stringify(config)
19529            });
19530          } catch (err) {
19531            logger.warn("Error setting up \"" + id + "\" Web Worker, fallback to inline", err);
19532            this.terminateWorker();
19533            this.error = null;
19534            this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id, _hls.logger);
19535          }
19536          return;
19537        }
19538      }
19539      this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id, _hls.logger);
19540    }
19541    var _proto = TransmuxerInterface.prototype;
19542    _proto.reset = function reset() {
19543      this.frag = null;
19544      this.part = null;
19545      if (this.workerContext) {
19546        var instanceNo = this.instanceNo;
19547        this.instanceNo = transmuxerInstanceCount++;
19548        var config = this.hls.config;
19549        var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
19550        this.workerContext.worker.postMessage({
19551          instanceNo: this.instanceNo,
19552          cmd: 'reset',
19553          resetNo: instanceNo,
19554          typeSupported: m2tsTypeSupported,
19555          id: this.id,
19556          config: JSON.stringify(config)
19557        });
19558      }
19559    };
19560    _proto.terminateWorker = function terminateWorker() {
19561      if (this.workerContext) {
19562        var worker = this.workerContext.worker;
19563        this.workerContext = null;
19564        worker.removeEventListener('message', this.onWorkerMessage);
19565        worker.removeEventListener('error', this.onWorkerError);
19566        removeWorkerFromStore(this.hls.config.workerPath);
19567      }
19568    };
19569    _proto.destroy = function destroy() {
19570      if (this.workerContext) {
19571        this.terminateWorker();
19572        // @ts-ignore
19573        this.onWorkerMessage = this.onWorkerError = null;
19574      } else {
19575        var transmuxer = this.transmuxer;
19576        if (transmuxer) {
19577          transmuxer.destroy();
19578          this.transmuxer = null;
19579        }
19580      }
19581      var observer = this.observer;
19582      if (observer) {
19583        observer.removeAllListeners();
19584      }
19585      this.frag = null;
19586      this.part = null;
19587      // @ts-ignore
19588      this.observer = null;
19589      // @ts-ignore
19590      this.hls = null;
19591    };
19592    _proto.push = function push(data, initSegmentData, audioCodec, videoCodec, frag, part, duration, accurateTimeOff
vendor: 4,789 bytes, lines 19592-19692
19592set, chunkMeta, defaultInitPTS) {
19593      var _frag$initSegment,
19594        _lastFrag$initSegment,
19595        _this2 = this;
19596      chunkMeta.transmuxing.start = self.performance.now();
19597      var instanceNo = this.instanceNo,
19598        transmuxer = this.transmuxer;
19599      var timeOffset = part ? part.start : frag.start;
19600      // TODO: push "clear-lead" decrypt data for unencrypted fragments in streams with encrypted ones
19601      var decryptdata = frag.decryptdata;
19602      var lastFrag = this.frag;
19603      var discontinuity = !(lastFrag && frag.cc === lastFrag.cc);
19604      var trackSwitch = !(lastFrag && chunkMeta.level === lastFrag.level);
19605      var snDiff = lastFrag ? chunkMeta.sn - lastFrag.sn : -1;
19606      var partDiff = this.part ? chunkMeta.part - this.part.index : -1;
19607      var progressive = snDiff === 0 && chunkMeta.id > 1 && chunkMeta.id === (lastFrag == null ? void 0 : lastFrag.stats.chunkCount);
19608      var contiguous = !trackSwitch && (snDiff === 1 || snDiff === 0 && (partDiff === 1 || progressive && partDiff <= 0));
19609      var now = self.performance.now();
19610      if (trackSwitch || snDiff || frag.stats.parsing.start === 0) {
19611        frag.stats.parsing.start = now;
19612      }
19613      if (part && (partDiff || !contiguous)) {
19614        part.stats.parsing.start = now;
19615      }
19616      var initSegmentChange = !(lastFrag && ((_frag$initSegment = frag.initSegment) == null ? void 0 : _frag$initSegment.url) === ((_lastFrag$initSegment = lastFrag.initSegment) == null ? void 0 : _lastFrag$initSegment.url));
19617      var state = new TransmuxState(discontinuity, contiguous, accurateTimeOffset, trackSwitch, timeOffset, initSegmentChange);
19618      if (!contiguous || discontinuity || initSegmentChange) {
19619        this.hls.logger.log("[transmuxer-interface, " + frag.type + "]: Starting new transmux session for sn: " + chunkMeta.sn + " p: " + chunkMeta.part + " level: " + chunkMeta.level + " id: " + chunkMeta.id + "\n        discontinuity: " + discontinuity + "\n        trackSwitch: " + trackSwitch + "\n        contiguous: " + contiguous + "\n        accurateTimeOffset: " + accurateTimeOffset + "\n        timeOffset: " + timeOffset + "\n        initSegmentChange: " + initSegmentChange);
19620        var config = new TransmuxConfig(audioCodec, videoCodec, initSegmentData, duration, defaultInitPTS);
19621        this.configureTransmuxer(config);
19622      }
19623      this.frag = frag;
19624      this.part = part;
19625
19626      // Frags with sn of 'initSegment' are not transmuxed
19627      if (this.workerContext) {
19628        // post fragment payload as transferable objects for ArrayBuffer (no copy)
19629        this.workerContext.worker.postMessage({
19630          instanceNo: instanceNo,
19631          cmd: 'demux',
19632          data: data,
19633          decryptdata: decryptdata,
19634          chunkMeta: chunkMeta,
19635          state: state
19636        }, data instanceof ArrayBuffer ? [data] : []);
19637      } else if (transmuxer) {
19638        var transmuxResult = transmuxer.push(data, decryptdata, chunkMeta, state);
19639        if (isPromise(transmuxResult)) {
19640          transmuxResult.then(function (data) {
19641            _this2.handleTransmuxComplete(data);
19642          }).catch(function (error) {
19643            _this2.transmuxerError(error, chunkMeta, 'transmuxer-interface push error');
19644          });
19645        } else {
19646          this.handleTransmuxComplete(transmuxResult);
19647        }
19648      }
19649    };
19650    _proto.flush = function flush(chunkMeta) {
19651      var _this3 = this;
19652      chunkMeta.transmuxing.start = self.performance.now();
19653      var instanceNo = this.instanceNo,
19654        transmuxer = this.transmuxer;
19655      if (this.workerContext) {
19656        this.workerContext.worker.postMessage({
19657          instanceNo: instanceNo,
19658          cmd: 'flush',
19659          chunkMeta: chunkMeta
19660        });
19661      } else if (transmuxer) {
19662        var transmuxResult = transmuxer.flush(chunkMeta);
19663        if (isPromise(transmuxResult)) {
19664          transmuxResult.then(function (data) {
19665            _this3.handleFlushResult(data, chunkMeta);
19666          }).catch(function (error) {
19667            _this3.transmuxerError(error, chunkMeta, 'transmuxer-interface flush error');
19668          });
19669        } else {
19670          this.handleFlushResult(transmuxResult, chunkMeta);
19671        }
19672      }
19673    };
19674    _proto.transmuxerError = function transmuxerError(error, chunkMeta, reason) {
19675      if (!this.hls) {
19676        return;
19677      }
19678      this.error = error;
19679      this.hls.trigger(Events.ERROR, {
19680        type: ErrorTypes.MEDIA_ERROR,
19681        details: ErrorDetails.FRAG_PARSING_ERROR,
19682        chunkMeta: chunkMeta,
19683        frag: this.frag || undefined,
19684        part: this.part || undefined,
19685        fatal: false,
19686        error: error,
19687        err: error,
19688        reason: reason
19689      });
19690    };
19691    _proto.handleFlushResult = function handleFlushResult(results, chunkMeta) {
19692      var _this4 = this;
19693      results.forEach(function (result) {
19694        _this4.handleTransmuxComplete(result);
19695      });
19696      this.onFlush(chunkMeta);
19697    };
19698    _proto.configureTransmuxer = function configureTransmuxer(config) {
19699      var instanceNo = this.instanceNo,
19700        transmuxer = this.transmuxer;
19701      if (this.workerContext) {
19702        this.workerContext.worker.postMessage({
19703          instanceNo: instanceNo,
19704          cmd: 'configure',
19705          config: config
19706        });
19707      } else if (transmuxer) {
19708        transmuxer.configure(config);
19709      }
19710    };
19711    _proto.handleTransmuxComplete = function handleTransmuxComplete(result) {
19712      result.chunkMeta.transmuxing.end = self.performance.now();
19713      this.onTransmuxComplete(result);
19714    };
19715    return TransmuxerInterface;
19716  }();
19717
19718  var STALL_MINIMUM_DURATION_MS = 250;
19719  var MAX_START_GAP_JUMP = 2.0;
19720  var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
19721  var SKIP_BUFFER_RANGE_START = 0.05;
19722  var GapController = /*#__PURE__*/function (_Logger) {
19723    function GapController(config, media, fragmentTracker, hls) {
19724      var _this;
19725      _this = _Logger.call(this, 'gap-controller', hls.logger) || this;
19726      _this.config = void 0;
19727      _this.media = null;
19728      _this.fragmentTracker = void 0;
19729      _this.hls = void 0;
19730      _this.nudgeRetry = 0;
19731      _this.stallReported = false;
19732      _this.stalled = null;
19733      _this.moved = false;
19734      _this.seeking = false;
19735      _this.ended = 0;
19736      _this.config = config;
19737      _this.media = media;
19738      _this.fragmentTracker = fragmentTracker;
19739      _this.hls = hls;
19740      return _this;
19741    }
19742    _inheritsLoose(GapController, _Logger);
19743    var _proto = GapController.prototype;
19744    _proto.destroy = function destroy() {
19745      this.media = null;
19746      // @ts-ignore
19747      this.hls = this.fragmentTracker = null;
19748    }
19749
19750    /**
19751     * Checks if the playhead is stuck within a gap, and if so, attempts to free it.
19752     * A gap is an unbuffered range between two buffered ranges (or the start and the first buffered range).
19753     *
19754     * @param lastCurrentTime - Previously read playhead position
19755     */;
19756    _proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
19757      var config = this.config,
19758        media = this.media,
19759        stalled = this.stalled;
19760      if (media === null) {
19761        return;
19762      }
19763      var currentTime = media.currentTime,
19764        seeking = media.seeking;
19765      var seeked = this.seeking && !seeking;
19766      var beginSeek = !this.seeking && seeking;
19767      this.seeking = seeking;
19768
19769      // The playhead is moving, no-op
19770      if (currentTime !== lastCurrentTime) {
19771        this.ended = 0;
19772        this.moved = true;
19773        if (!seeking) {
19774          this.nudgeRetry = 0;
19775        }
19776        if (stalled !== null) {
19777          // The playhead is now moving, but was previously stalled
19778          if (this.stallReported) {
19779            var _stalledDuration = self.performance.now() - stalled;
19780            this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
19781            this.stallReported = false;
19782          }
19783          this.stalled = null;
19784        }
19785        return;
19786      }
19787
19788      // Clear stalled state when beginning or finishing seeking so that we don't report stalls coming out of a seek
19789      if (beginSeek || seeked) {
19790        this.stalled = null;
19791        return;
19792      }
19793
19794      // The playhead should not be moving
19795      if (media.paused && !seeking || media.ended || media.playbackRate === 0 || !BufferHelper.getBuffered(media).length) {
19796        this.nudgeRetry = 0;
19797        return;
19798      }
19799      var bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
19800      var nextStart = bufferInfo.nextStart || 0;
19801      if (seeking) {
19802        // Waiting for seeking in a buffered range to complete
19803        var hasEnoughBuffer = bufferInfo.len > MAX_START_GAP_JUMP;
19804        // Next buffered range is too far ahead to jump to while still seeking
19805        var noBufferGap = !nextStart || activeFrag && activeFrag.start <= currentTime || nextStart - currentTime > MAX_START_GAP_JUMP && !this.fragmentTracker.getPartialFragment(currentTime);
19806        if (hasEnoughBuffer || noBufferGap) {
19807          return;
19808        }
19809        // Reset moved state when seeking to a point in or before a gap
19810        this.moved = false;
19811      }
19812
19813      // Skip start gaps if we haven't played, but the last poll detected the start of a stall
19814      // The addition poll gives the browser a chance to jump the gap for us
19815      if (!this.moved && this.stalled !== null) {
19816        // There is no playable buffer (seeked, waiting for buffer)
19817        var isBuffered = bufferInfo.len > 0;
19818        if (!isBuffered && !nextStart) {
19819          return;
19820        }
19821        // Jump start gaps within jump threshold
19822        var startJump = Math.max(nextStart, bufferInfo.start || 0) - currentTime;
19823
19824        // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
19825        // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
19826        // that begins over 1 target duration after the video start position.
19827        var isLive = !!(levelDetails != null && levelDetails.live);
19828        var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
19829        var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
19830        if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
19831          if (!media.paused) {
19832            this._trySkipBufferHole(partialOrGap);
19833          }
19834          return;
19835        }
19836      }
19837
19838      // Start tracking stall time
19839      var tnow = self.performance.now();
19840      if (stalled === null) {
19841        this.stalled = tnow;
19842        return;
19843      }
19844      var stalledDuration = tnow - stalled;
19845      if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
19846        // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
19847        if (state === State.ENDED && !(levelDetails != null && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
19848          if (stalledDuration < 1000 || this.ended) {
19849            return;
19850          }
19851          this.ended = currentTime;
19852          this.hls.trigger(Events.MEDIA_ENDED, {
19853            stalled: true
19854          });
19855          return;
19856        }
19857        // Report stalling after trying to fix
19858        this._reportStall(bufferInfo);
19859        if (!this.media) {
19860          return;
19861        }
19862      }
19863      var bufferedWithHoles = BufferHelper.bufferInfo(media, currentTime, config.maxBufferHole);
19864      this._tryFixBufferStall(bufferedWithHoles, stalledDuration);
19865    }
19866
19867    /**
19868     * Detects and attempts to fix known buffer stalling issues.
19869     * @param bufferInfo - The properties of the current buffer.
19870     * @param stalledDurationMs - The amount of time Hls.js has been stalling for.
19871     * @private
19872     */;
19873    _proto._tryFixBufferStall = function _tryFixBufferStall(bufferInfo, stalledDurationMs) {
19874      var config = this.config,
19875        fragmentTracker = this.fragmentTracker,
19876        media = this.media;
19877      if (media === null) {
19878        return;
19879      }
19880      var currentTime = media.currentTime;
19881      var partial = fragmentTracker.getPartialFragment(currentTime);
19882      if (partial) {
19883        // Try to skip over the buffer hole caused by a partial fragment
19884        // This method isn't limited by the size of the gap between buffered ranges
19885        var targetTime = this._trySkipBufferHole(partial);
19886        // we return here in this case, meaning
19887        // the branch below only executes when we haven't seeked to a new position
19888        if (targetTime || !this.media) {
19889          return;
19890        }
19891      }
19892
19893      // if we haven't had to skip over a buffer hole of a partial fragment
19894      // we may just have to "nudge" the playlist as the browser decoding/rendering engine
19895      // needs to cross some sort of threshold covering all source-buffers content
19896      // to start playing properly.
19897      if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
19898        this.warn('Trying to nudge playhead over buffer-hole');
19899        // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
19900        // We only try to jump the hole if it's under the configured size
19901        // Reset stalled so to rearm watchdog timer
19902        this.stalled = null;
19903        this._tryNudgeBuffer();
19904      }
19905    }
19906
19907    /**
19908     * Triggers a BUFFER_STALLED_ERROR event, but only once per stall period.
19909     * @param bufferLen - The playhead distance from the end of the current buffer segment.
19910     * @private
19911     */;
19912    _proto._reportStall = function _reportStall(bufferInfo) {
19913      var hls = this.hls,
19914        media = this.media,
19915        stallReported = this.stallReported;
19916      if (!stallReported && media) {
19917        // Report stalled error once
19918        this.stallReported = true;
19919        var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
19920        this.warn(error.message);
19921        hls.trigger(Events.ERROR, {
19922          type: ErrorTypes.MEDIA_ERROR,
19923          details: ErrorDetails.BUFFER_STALLED_ERROR,
19924          fatal: false,
19925          error: error,
19926          buffer: bufferInfo.len
19927        });
19928      }
19929    }
19930
19931    /**
19932     * Attempts to fix buffer stalls by jumping over known gaps caused by partial fragments
19933     * @param partial - The partial fragment found at the current time (where playback is stalling).
19934     * @private
19935     */;
19936    _proto._trySkipBufferHole = function _trySkipBufferHole(partial) {
19937      var config = this.config,
19938        hls = this.hls,
19939        media = this.media;
19940      if (media === null) {
19941        return 0;
19942      }
19943
19944      // Check if currentTime is between unbuffered regions of partial fragments
19945      var currentTime = media.currentTime;
19946      var bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
19947      var startTime = currentTime < bufferInfo.start ? bufferInfo.start : bufferInfo.nextStart;
19948      if (startTime) {
19949        var bufferStarved = bufferInfo.len <= config.maxBufferHole;
19950        var waiting = bufferInfo.len > 0 && bufferInfo.len < 1 && media.readyState < 3;
19951        var gapLength = startTime - currentTime;
19952        if (gapLength > 0 && (bufferStarved || waiting)) {
19953          // Only allow large gaps to be skipped if it is a start gap, or all fragments in skip range are partial
19954          if (gapLength > config.maxBufferHole) {
19955            var fragmentTracker = this.fragmentTracker;
19956            var startGap = false;
19957            if (currentTime === 0) {
19958              var startFrag = fragmentTracker.getAppendedFrag(0, PlaylistLevelType.MAIN);
19959              if (startFrag && startTime < startFrag.end) {
19960                startGap = true;
19961              }
19962            }
19963            if (!startGap) {
19964              var startProvisioned = partial || fragmentTracker.getAppendedFrag(currentTime, PlaylistLevelType.MAIN);
19965              if (startProvisioned) {
19966                var moreToLoad = false;
19967                var pos = startProvisioned.end;
19968                while (pos < startTime) {
19969                  var provisioned = fragmentTracker.getPartialFragment(pos);
19970                  if (provisioned) {
19971                    pos += provisioned.duration;
19972                  } else {
19973                    moreToLoad = true;
19974                    break;
19975                  }
19976                }
19977                if (moreToLoad) {
19978                  return 0;
19979                }
19980              }
19981            }
19982          }
19983          var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
19984          this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
19985          this.moved = true;
19986          this.stalled = null;
19987          media.currentTime = targetTime;
19988          if (partial && !partial.gap) {
19989            var error = new Error("fragment loaded with buffer holes, seeking from " + currentTime + " to " + targetTime);
19990            hls.trigger(Events.ERROR, {
19991              type: ErrorTypes.MEDIA_ERROR,
19992              details: ErrorDetails.BUFFER_SEEK_OVER_HOLE,
19993              fatal: false,
19994              error: error,
19995              reason: error.message,
19996              frag: partial
19997            });
19998          }
19999          return targetTime;
20000        }
20001      }
20002      return 0;
20003    }
20004
20005    /**
20006     * Attempts to fix buffer stalls by advancing the mediaElement's current time by a small amount.
20007     * @private
20008     */;
20009    _proto._tryNudgeBuffer = function _tryNudgeBuffer() {
20010      var config = this.config,
20011        hls = this.hls,
20012        media = this.media,
20013        nudgeRetry = this.nudgeRetry;
20014      if (media === null) {
20015        return;
20016      }
20017      var currentTime = media.currentTime;
20018      this.nudgeRetry++;
20019      if (nudgeRetry < config.nudgeMaxRetry) {
20020        var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
20021        // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
20022        var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
20023        this.warn(error.message);
20024        media.currentTime = targetTime;
20025        hls.trigger(Events.ERROR, {
20026          type: ErrorTypes.MEDIA_ERROR,
20027          details: ErrorDetails.BUFFER_NUDGE_ON_STALL,
20028          error: error,
20029          fatal: false
20030        });
20031      } else {
20032        var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
20033        this.error(_error.message);
20034        hls.trigger(Events.ERROR, {
20035          type: ErrorTypes.MEDIA_ERROR,
20036          details: ErrorDetails.BUFFER_STALLED_ERROR,
20037          error: _error,
20038          fatal: true
20039        });
20040      }
20041    };
20042    return GapController;
20043  }(Logger);
20044
20045  var TICK_INTERVAL = 100; // how often to tick in ms
20046  var StreamController = /*#__PURE__*/function (_BaseStreamController) {
20047    function StreamController(hls, fragmentTracker, keyLoader) {
20048      var _this;
20049      _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
20050      _this.audioCodecSwap = false;
20051      _this.gapController = null;
20052      _this.level = -1;
20053      _this._forceStartLoad = false;
20054      _this.altAudio = false;
20055      _this.audioOnly = false;
20056      _this.fragPlaying = null;
20057      _this.fragLastKbps = 0;
20058      _this.couldBacktrack = false;
20059      _this.backtrackFragment = null;
20060      _this.audioCodecSwitch = false;
20061      _this.videoBuffer = null;
20062      _this.onMediaPlaying = function () {
20063        // tick to speed up FRAG_CHANGED triggering
20064        _this.tick();
20065      };
20066      _this.onMediaSeeked = function () {
20067        var media = _this.media;
20068        var currentTime = media ? media.currentTime : null;
20069        if (isFiniteNumber(currentTime)) {
20070          _this.log("Media seeked to " + currentTime.toFixed(3));
20071        }
20072
20073        // If seeked was issued before buffer was appended do not tick immediately
20074        var bufferInfo = _this.getMainFwdBufferInfo();
20075        if (bufferInfo === null || bufferInfo.len === 0) {
20076          _this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
20077          return;
20078        }
20079
20080        // tick to speed up FRAG_CHANGED triggering
20081        _this.tick();
20082      };
20083      _this.registerListeners();
20084      return _this;
20085    }
20086    _inheritsLoose(StreamController, _BaseStreamController);
20087    var _proto = StreamController.prototype;
20088    _proto.registerListeners = function registerListeners() {
20089      _BaseStreamController.prototype.registerListeners.call(this);
20090      var hls = this.hls;
20091      hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
20092      hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
20093      hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
20094      hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
20095      hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
20096      hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
20097      hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
20098      hls.on(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
20099      hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
20100      hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
20101    };
20102    _proto.unregisterListeners = function unregisterListeners() {
20103      _BaseStreamController.prototype.unregisterListeners.call(this);
20104      var hls = this.hls;
20105      hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
20106      hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
20107      hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
20108      hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
20109      hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
20110      hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
20111      hls.off(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
20112      hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
20113      hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
20114    };
20115    _proto.onHandlerDestroying = function onHandlerDestroying() {
20116      // @ts-ignore
20117      this.onMediaPlaying = this.onMediaSeeked = null;
20118      this.unregisterListeners();
20119      _BaseStreamController.prototype.onHandlerDestroying.call(this);
20120    };
20121    _proto.startLoad = function startLoad(startPosition) {
20122      if (this.levels) {
20123        var lastCurrentTime = this.lastCurrentTime,
20124          hls = this.hls;
20125        this.stopLoad();
20126        this.setInterval(TICK_INTERVAL);
20127        this.level = -1;
20128        if (!this.startFragRequested) {
20129          // determine load level
20130          var startLevel = hls.startLevel;
20131          if (startLevel === -1) {
20132            if (hls.config.testBandwidth && this.levels.length > 1) {
vendor: 10,305 bytes, lines 20133-20367
20133              // -1 : guess start Level by doing a bitrate test by loading first fragment of lowest quality level
20134              startLevel = 0;
20135              this.bitrateTest = true;
20136            } else {
20137              startLevel = hls.firstAutoLevel;
20138            }
20139          }
20140          // set new level to playlist loader : this will trigger start level load
20141          // hls.nextLoadLevel remains until it is set to a new value or until a new frag is successfully loaded
20142          hls.nextLoadLevel = startLevel;
20143          this.level = hls.loadLevel;
20144          this.loadedmetadata = false;
20145        }
20146        // if startPosition undefined but lastCurrentTime set, set startPosition to last currentTime
20147        if (lastCurrentTime > 0 && startPosition === -1) {
20148          this.log("Override startPosition with lastCurrentTime @" + lastCurrentTime.toFixed(3));
20149          startPosition = lastCurrentTime;
20150        }
20151        this.state = State.IDLE;
20152        this.nextLoadPosition = this.startPosition = this.lastCurrentTime = startPosition;
20153        this.tick();
20154      } else {
20155        this._forceStartLoad = true;
20156        this.state = State.STOPPED;
20157      }
20158    };
20159    _proto.stopLoad = function stopLoad() {
20160      this._forceStartLoad = false;
20161      _BaseStreamController.prototype.stopLoad.call(this);
20162    };
20163    _proto.doTick = function doTick() {
20164      switch (this.state) {
20165        case State.WAITING_LEVEL:
20166          {
20167            var levels = this.levels,
20168              level = this.level;
20169            var currentLevel = levels == null ? void 0 : levels[level];
20170            var details = currentLevel == null ? void 0 : currentLevel.details;
20171            if (details && (!details.live || this.levelLastLoaded === currentLevel)) {
20172              if (this.waitForCdnTuneIn(details)) {
20173                break;
20174              }
20175              this.state = State.IDLE;
20176              break;
20177            } else if (this.hls.nextLoadLevel !== this.level) {
20178              this.state = State.IDLE;
20179              break;
20180            }
20181            break;
20182          }
20183        case State.FRAG_LOADING_WAITING_RETRY:
20184          {
20185            var _this$media;
20186            var now = self.performance.now();
20187            var retryDate = this.retryDate;
20188            // if current time is gt than retryDate, or if media seeking let's switch to IDLE state to retry loading
20189            if (!retryDate || now >= retryDate || (_this$media = this.media) != null && _this$media.seeking) {
20190              var _levels = this.levels,
20191                _level = this.level;
20192              var _currentLevel = _levels == null ? void 0 : _levels[_level];
20193              this.resetStartWhenNotLoaded(_currentLevel || null);
20194              this.state = State.IDLE;
20195            }
20196          }
20197          break;
20198      }
20199      if (this.state === State.IDLE) {
20200        this.doTickIdle();
20201      }
20202      this.onTickEnd();
20203    };
20204    _proto.onTickEnd = function onTickEnd() {
20205      _BaseStreamController.prototype.onTickEnd.call(this);
20206      this.checkBuffer();
20207      this.checkFragmentChanged();
20208    };
20209    _proto.doTickIdle = function doTickIdle() {
20210      if (!this.buffering) {
20211        return;
20212      }
20213      var hls = this.hls,
20214        levelLastLoaded = this.levelLastLoaded,
20215        levels = this.levels,
20216        media = this.media;
20217
20218      // if start level not parsed yet OR
20219      // if video not attached AND start fragment already requested OR start frag prefetch not enabled
20220      // exit loop, as we either need more info (level not parsed) or we need media to be attached to load new fragment
20221      if (levelLastLoaded === null || !media && (this.startFragRequested || !hls.config.startFragPrefetch)) {
20222        return;
20223      }
20224
20225      // If the "main" level is audio-only but we are loading an alternate track in the same group, do not load anything
20226      if (this.altAudio && this.audioOnly) {
20227        return;
20228      }
20229      var level = hls.nextLoadLevel;
20230      if (!(levels != null && levels[level])) {
20231        return;
20232      }
20233      var levelInfo = levels[level];
20234
20235      // if buffer length is less than maxBufLen try to load a new fragment
20236
20237      var bufferInfo = this.getMainFwdBufferInfo();
20238      if (bufferInfo === null) {
20239        return;
20240      }
20241      var lastDetails = this.getLevelDetails();
20242      if (lastDetails && this._streamEnded(bufferInfo, lastDetails)) {
20243        var data = {};
20244        if (this.altAudio) {
20245          data.type = 'video';
20246        }
20247        this.hls.trigger(Events.BUFFER_EOS, data);
20248        this.state = State.ENDED;
20249        return;
20250      }
20251
20252      // set next load level : this will trigger a playlist load if needed
20253      if (hls.loadLevel !== level && hls.manualLevel === -1) {
20254        this.log("Adapting to level " + level + " from level " + this.level);
20255      }
20256      this.level = hls.nextLoadLevel = level;
20257      var levelDetails = levelInfo.details;
20258      // if level info not retrieved yet, switch state and wait for level retrieval
20259      // if live playlist, ensure that new playlist has been refreshed to avoid loading/try to load
20260      // a useless and outdated fragment (that might even introduce load error if it is already out of the live playlist)
20261      if (!levelDetails || this.state === State.WAITING_LEVEL || levelDetails.live && this.levelLastLoaded !== levelInfo) {
20262        this.level = level;
20263        this.state = State.WAITING_LEVEL;
20264        return;
20265      }
20266      var bufferLen = bufferInfo.len;
20267
20268      // compute max Buffer Length that we could get from this load level, based on level bitrate. don't buffer more than 60 MB and more than 30s
20269      var maxBufLen = this.getMaxBufferLength(levelInfo.maxBitrate);
20270
20271      // Stay idle if we are still with buffer margins
20272      if (bufferLen >= maxBufLen) {
20273        return;
20274      }
20275      if (this.backtrackFragment && this.backtrackFragment.start > bufferInfo.end) {
20276        this.backtrackFragment = null;
20277      }
20278      var targetBufferTime = this.backtrackFragment ? this.backtrackFragment.start : bufferInfo.end;
20279      var frag = this.getNextFragment(targetBufferTime, levelDetails);
20280      // Avoid backtracking by loading an earlier segment in streams with segments that do not start with a key frame (flagged by `couldBacktrack`)
20281      if (this.couldBacktrack && !this.fragPrevious && frag && frag.sn !== 'initSegment' && this.fragmentTracker.getState(frag) !== FragmentState.OK) {
20282        var _this$backtrackFragme;
20283        var backtrackSn = ((_this$backtrackFragme = this.backtrackFragment) != null ? _this$backtrackFragme : frag).sn;
20284        var fragIdx = backtrackSn - levelDetails.startSN;
20285        var backtrackFrag = levelDetails.fragments[fragIdx - 1];
20286        if (backtrackFrag && frag.cc === backtrackFrag.cc) {
20287          frag = backtrackFrag;
20288          this.fragmentTracker.removeFragment(backtrackFrag);
20289        }
20290      } else if (this.backtrackFragment && bufferInfo.len) {
20291        this.backtrackFragment = null;
20292      }
20293      // Avoid loop loading by using nextLoadPosition set for backtracking and skipping consecutive GAP tags
20294      if (frag && this.isLoopLoading(frag, targetBufferTime)) {
20295        var gapStart = frag.gap;
20296        if (!gapStart) {
20297          // Cleanup the fragment tracker before trying to find the next unbuffered fragment
20298          var type = this.audioOnly && !this.altAudio ? ElementaryStreamTypes.AUDIO : ElementaryStreamTypes.VIDEO;
20299          var mediaBuffer = (type === ElementaryStreamTypes.VIDEO ? this.videoBuffer : this.mediaBuffer) || this.media;
20300          if (mediaBuffer) {
20301            this.afterBufferFlushed(mediaBuffer, type, PlaylistLevelType.MAIN);
20302          }
20303        }
20304        frag = this.getNextFragmentLoopLoading(frag, levelDetails, bufferInfo, PlaylistLevelType.MAIN, maxBufLen);
20305      }
20306      if (!frag) {
20307        return;
20308      }
20309      if (frag.initSegment && !frag.initSegment.data && !this.bitrateTest) {
20310        frag = frag.initSegment;
20311      }
20312      this.loadFragment(frag, levelInfo, targetBufferTime);
20313    };
20314    _proto.loadFragment = function loadFragment(frag, level, targetBufferTime) {
20315      // Check if fragment is not loaded
20316      var fragState = this.fragmentTracker.getState(frag);
20317      if (fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) {
20318        if (frag.sn === 'initSegment') {
20319          this._loadInitSegment(frag, level);
20320        } else if (this.bitrateTest) {
20321          this.log("Fragment " + frag.sn + " of level " + frag.level + " is being downloaded to test bitrate and will not be buffered");
20322          this._loadBitrateTestFrag(frag, level);
20323        } else {
20324          _BaseStreamController.prototype.loadFragment.call(this, frag, level, targetBufferTime);
20325        }
20326      } else {
20327        this.clearTrackerIfNeeded(frag);
20328      }
20329    };
20330    _proto.getBufferedFrag = function getBufferedFrag(position) {
20331      return this.fragmentTracker.getBufferedFrag(position, PlaylistLevelType.MAIN);
20332    };
20333    _proto.followingBufferedFrag = function followingBufferedFrag(frag) {
20334      if (frag) {
20335        // try to get range of next fragment (500ms after this range)
20336        return this.getBufferedFrag(frag.end + 0.5);
20337      }
20338      return null;
20339    }
20340
20341    /*
20342      on immediate level switch :
20343       - pause playback if playing
20344       - cancel any pending load request
20345       - and trigger a buffer flush
20346    */;
20347    _proto.immediateLevelSwitch = function immediateLevelSwitch() {
20348      this.abortCurrentFrag();
20349      this.flushMainBuffer(0, Number.POSITIVE_INFINITY);
20350    }
20351
20352    /**
20353     * try to switch ASAP without breaking video playback:
20354     * in order to ensure smooth but quick level switching,
20355     * we need to find the next flushable buffer range
20356     * we should take into account new segment fetch time
20357     */;
20358    _proto.nextLevelSwitch = function nextLevelSwitch() {
20359      var levels = this.levels,
20360        media = this.media;
20361      // ensure that media is defined and that metadata are available (to retrieve currentTime)
20362      if (media != null && media.readyState) {
20363        var fetchdelay;
20364        var fragPlayingCurrent = this.getAppendedFrag(media.currentTime);
20365        if (fragPlayingCurrent && fragPlayingCurrent.start > 1) {
20366          // flush buffer preceding current fragment (flush until current fragment start offset)
20367          // minus 1s to avoid video freezing, that could happen if we flush ke
20367yframe of current video ...
20368          this.flushMainBuffer(0, fragPlayingCurrent.start - 1);
20369        }
20370        var levelDetails = this.getLevelDetails();
20371        if (levelDetails != null && levelDetails.live) {
20372          var bufferInfo = this.getMainFwdBufferInfo();
20373          // Do not flush in live stream with low buffer
20374          if (!bufferInfo || bufferInfo.len < levelDetails.targetduration * 2) {
20375            return;
20376          }
20377        }
20378        if (!media.paused && levels) {
20379          // add a safety delay of 1s
20380          var nextLevelId = this.hls.nextLoadLevel;
20381          var nextLevel = levels[nextLevelId];
20382          var fragLastKbps = this.fragLastKbps;
20383          if (fragLastKbps && this.fragCurrent) {
20384            fetchdelay = this.fragCurrent.duration * nextLevel.maxBitrate / (1000 * fragLastKbps) + 1;
20385          } else {
20386            fetchdelay = 0;
20387          }
20388        } else {
20389          fetchdelay = 0;
20390        }
20391        // this.log('fetchdelay:'+fetchdelay);
20392        // find buffer range that will be reached once new fragment will be fetched
20393        var bufferedFrag = this.getBufferedFrag(media.currentTime + fetchdelay);
20394        if (bufferedFrag) {
20395          // we can flush buffer range following this one without stalling playback
20396          var nextBufferedFrag = this.followingBufferedFrag(bufferedFrag);
20397          if (nextBufferedFrag) {
20398            // if we are here, we can also cancel any loading/demuxing in progress, as they are useless
20399            this.abortCurrentFrag();
20400            // start flush position is in next buffered frag. Leave some padding for non-independent segments and smoother playback.
20401            var maxStart = nextBufferedFrag.maxStartPTS ? nextBufferedFrag.maxStartPTS : nextBufferedFrag.start;
20402            var fragDuration = nextBufferedFrag.duration;
20403            var startPts = Math.max(bufferedFrag.end, maxStart + Math.min(Math.max(fragDuration - this.config.maxFragLookUpTolerance, fragDuration * (this.couldBacktrack ? 0.5 : 0.125)), fragDuration * (this.couldBacktrack ? 0.75 : 0.25)));
20404            this.flushMainBuffer(startPts, Number.POSITIVE_INFINITY);
20405          }
20406        }
20407      }
20408    };
20409    _proto.abortCurrentFrag = function abortCurrentFrag() {
20410      var fragCurrent = this.fragCurrent;
20411      this.fragCurrent = null;
20412      this.backtrackFragment = null;
20413      if (fragCurrent) {
20414        fragCurrent.abortRequests();
20415        this.fragmentTracker.removeFragment(fragCurrent);
20416      }
20417      switch (this.state) {
20418        case State.KEY_LOADING:
20419        case State.FRAG_LOADING:
20420        case State.FRAG_LOADING_WAITING_RETRY:
20421        case State.PARSING:
20422        case State.PARSED:
20423          this.state = State.IDLE;
20424          break;
20425      }
20426      this.nextLoadPosition = this.getLoadPosition();
20427    };
20428    _proto.flushMainBuffer = function flushMainBuffer(startOffset, endOffset) {
20429      _BaseStreamController.prototype.flushMainBuffer.call(this, startOffset, endOffset, this.altAudio ? 'video' : null);
20430    };
20431    _proto.onMediaAttached = function onMediaAttached(event, data) {
20432      _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
20433      var media = data.media;
20434      media.addEventListener('playing', this.onMediaPlaying);
20435      media.addEventListener('seeked', this.onMediaSeeked);
20436      this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
20437    };
20438    _proto.onMediaDetaching = function onMediaDetaching() {
20439      var media = this.media;
20440      if (media) {
20441        media.removeEventListener('playing', this.onMediaPlaying);
20442        media.removeEventListener('seeked', this.onMediaSeeked);
20443      }
20444      this.videoBuffer = null;
20445      this.fragPlaying = null;
20446      if (this.gapController) {
20447        this.gapController.destroy();
20448        this.gapController = null;
20449      }
20450      _BaseStreamController.prototype.onMediaDetaching.call(this);
20451    };
20452    _proto.onManifestLoading = function onManifestLoading() {
20453      _BaseStreamController.prototype.onManifestLoading.call(this);
20454      // reset buffer on manifest loading
20455      this.log('Trigger BUFFER_RESET');
20456      this.hls.trigger(Events.BUFFER_RESET, undefined);
20457      this.couldBacktrack = false;
vendor: 4,344 bytes, lines 20458-20561
20458      this.fragLastKbps = 0;
20459      this.fragPlaying = this.backtrackFragment = null;
20460      this.altAudio = this.audioOnly = false;
20461    };
20462    _proto.onManifestParsed = function onManifestParsed(event, data) {
20463      // detect if we have different kind of audio codecs used amongst playlists
20464      var aac = false;
20465      var heaac = false;
20466      data.levels.forEach(function (level) {
20467        var codec = level.audioCodec;
20468        if (codec) {
20469          aac = aac || codec.indexOf('mp4a.40.2') !== -1;
20470          heaac = heaac || codec.indexOf('mp4a.40.5') !== -1;
20471        }
20472      });
20473      this.audioCodecSwitch = aac && heaac && !changeTypeSupported();
20474      if (this.audioCodecSwitch) {
20475        this.log('Both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC');
20476      }
20477      this.levels = data.levels;
20478      this.startFragRequested = false;
20479    };
20480    _proto.onLevelLoading = function onLevelLoading(event, data) {
20481      var levels = this.levels;
20482      if (!levels || this.state !== State.IDLE) {
20483        return;
20484      }
20485      var level = levels[data.level];
20486      if (!level.details || level.details.live && this.levelLastLoaded !== level || this.waitForCdnTuneIn(level.details)) {
20487        this.state = State.WAITING_LEVEL;
20488      }
20489    };
20490    _proto.onLevelLoaded = function onLevelLoaded(event, data) {
20491      var _curLevel$details;
20492      var levels = this.levels;
20493      var newLevelId = data.level;
20494      var newDetails = data.details;
20495      var duration = newDetails.totalduration;
20496      if (!levels) {
20497        this.warn("Levels were reset while loading level " + newLevelId);
20498        return;
20499      }
20500      this.log("Level " + newLevelId + " loaded [" + newDetails.startSN + "," + newDetails.endSN + "]" + (newDetails.lastPartSn ? "[part-" + newDetails.lastPartSn + "-" + newDetails.lastPartIndex + "]" : '') + ", cc [" + newDetails.startCC + ", " + newDetails.endCC + "] duration:" + duration);
20501      var curLevel = levels[newLevelId];
20502      var fragCurrent = this.fragCurrent;
20503      if (fragCurrent && (this.state === State.FRAG_LOADING || this.state === State.FRAG_LOADING_WAITING_RETRY)) {
20504        if (fragCurrent.level !== data.level && fragCurrent.loader) {
20505          this.abortCurrentFrag();
20506        }
20507      }
20508      var sliding = 0;
20509      if (newDetails.live || (_curLevel$details = curLevel.details) != null && _curLevel$details.live) {
20510        var _this$levelLastLoaded;
20511        this.checkLiveUpdate(newDetails);
20512        if (newDetails.deltaUpdateFailed) {
20513          return;
20514        }
20515        sliding = this.alignPlaylists(newDetails, curLevel.details, (_this$levelLastLoaded = this.levelLastLoaded) == null ? void 0 : _this$levelLastLoaded.details);
20516      }
20517      // override level info
20518      curLevel.details = newDetails;
20519      this.levelLastLoaded = curLevel;
20520      this.hls.trigger(Events.LEVEL_UPDATED, {
20521        details: newDetails,
20522        level: newLevelId
20523      });
20524
20525      // only switch back to IDLE state if we were waiting for level to start downloading a new fragment
20526      if (this.state === State.WAITING_LEVEL) {
20527        if (this.waitForCdnTuneIn(newDetails)) {
20528          // Wait for Low-Latency CDN Tune-in
20529          return;
20530        }
20531        this.state = State.IDLE;
20532      }
20533      if (!this.startFragRequested) {
20534        this.setStartPosition(newDetails, sliding);
20535      } else if (newDetails.live) {
20536        this.synchronizeToLiveEdge(newDetails);
20537      }
20538
20539      // trigger handler right now
20540      this.tick();
20541    };
20542    _proto._handleFragmentLoadProgress = function _handleFragmentLoadProgress(data) {
20543      var _frag$initSegment;
20544      var frag = data.frag;
20545      var part = data.part,
20546        payload = data.payload;
20547      var levels = this.levels;
20548      if (!levels) {
20549        this.warn("Levels were reset while fragment load was in progress. Fragment " + frag.sn + " of level " + frag.level + " will not be buffered");
20550        return;
20551      }
20552      var currentLevel = levels[frag.level];
20553      var details = currentLevel.details;
20554      if (!details) {
20555        this.warn("Dropping fragment " + frag.sn + " of level " + frag.level + " after level details were reset");
20556        this.fragmentTracker.removeFragment(frag);
20557        return;
20558      }
20559      var videoCodec = currentLevel.videoCodec;
20560
20561      // time Offset is accurate if level PTS is known, or if playlist is not sliding (not live)
vendor: 5,286 bytes, lines 20562-20671
20562      var accurateTimeOffset = details.PTSKnown || !details.live;
20563      var initSegmentData = (_frag$initSegment = frag.initSegment) == null ? void 0 : _frag$initSegment.data;
20564      var audioCodec = this._getAudioCodec(currentLevel);
20565
20566      // transmux the MPEG-TS data to ISO-BMFF segments
20567      // this.log(`Transmuxing ${frag.sn} of [${details.startSN} ,${details.endSN}],level ${frag.level}, cc ${frag.cc}`);
20568      var transmuxer = this.transmuxer = this.transmuxer || new TransmuxerInterface(this.hls, PlaylistLevelType.MAIN, this._handleTransmuxComplete.bind(this), this._handleTransmuxerFlush.bind(this));
20569      var partIndex = part ? part.index : -1;
20570      var partial = partIndex !== -1;
20571      var chunkMeta = new ChunkMetadata(frag.level, frag.sn, frag.stats.chunkCount, payload.byteLength, partIndex, partial);
20572      var initPTS = this.initPTS[frag.cc];
20573      transmuxer.push(payload, initSegmentData, audioCodec, videoCodec, frag, part, details.totalduration, accurateTimeOffset, chunkMeta, initPTS);
20574    };
20575    _proto.onAudioTrackSwitching = function onAudioTrackSwitching(event, data) {
20576      // if any URL found on new audio track, it is an alternate audio track
20577      var fromAltAudio = this.altAudio;
20578      var altAudio = !!data.url;
20579      // if we switch on main audio, ensure that main fragment scheduling is synced with media.buffered
20580      // don't do anything if we switch to alt audio: audio stream controller is handling it.
20581      // we will just have to change buffer scheduling on audioTrackSwitched
20582      if (!altAudio) {
20583        if (this.mediaBuffer !== this.media) {
20584          this.log('Switching on main audio, use media.buffered to schedule main fragment loading');
20585          this.mediaBuffer = this.media;
20586          var fragCurrent = this.fragCurrent;
20587          // we need to refill audio buffer from main: cancel any frag loading to speed up audio switch
20588          if (fragCurrent) {
20589            this.log('Switching to main audio track, cancel main fragment load');
20590            fragCurrent.abortRequests();
20591            this.fragmentTracker.removeFragment(fragCurrent);
20592          }
20593          // destroy transmuxer to force init segment generation (following audio switch)
20594          this.resetTransmuxer();
20595          // switch to IDLE state to load new fragment
20596          this.resetLoadingState();
20597        } else if (this.audioOnly) {
20598          // Reset audio transmuxer so when switching back to main audio we're not still appending where we left off
20599          this.resetTransmuxer();
20600        }
20601        var hls = this.hls;
20602        // If switching from alt to main audio, flush all audio and trigger track switched
20603        if (fromAltAudio) {
20604          hls.trigger(Events.BUFFER_FLUSHING, {
20605            startOffset: 0,
20606            endOffset: Number.POSITIVE_INFINITY,
20607            type: null
20608          });
20609          this.fragmentTracker.removeAllFragments();
20610        }
20611        hls.trigger(Events.AUDIO_TRACK_SWITCHED, data);
20612      }
20613    };
20614    _proto.onAudioTrackSwitched = function onAudioTrackSwitched(event, data) {
20615      var trackId = data.id;
20616      var altAudio = !!this.hls.audioTracks[trackId].url;
20617      if (altAudio) {
20618        var videoBuffer = this.videoBuffer;
20619        // if we switched on alternate audio, ensure that main fragment scheduling is synced with video sourcebuffer buffered
20620        if (videoBuffer && this.mediaBuffer !== videoBuffer) {
20621          this.log('Switching on alternate audio, use video.buffered to schedule main fragment loading');
20622          this.mediaBuffer = videoBuffer;
20623        }
20624      }
20625      this.altAudio = altAudio;
20626      this.tick();
20627    };
20628    _proto.onBufferCreated = function onBufferCreated(event, data) {
20629      var tracks = data.tracks;
20630      var mediaTrack;
20631      var name;
20632      var alternate = false;
20633      for (var type in tracks) {
20634        var track = tracks[type];
20635        if (track.id === 'main') {
20636          name = type;
20637          mediaTrack = track;
20638          // keep video source buffer reference
20639          if (type === 'video') {
20640            var videoTrack = tracks[type];
20641            if (videoTrack) {
20642              this.videoBuffer = videoTrack.buffer;
20643            }
20644          }
20645        } else {
20646          alternate = true;
20647        }
20648      }
20649      if (alternate && mediaTrack) {
20650        this.log("Alternate track found, use " + name + ".buffered to schedule main fragment loading");
20651        this.mediaBuffer = mediaTrack.buffer;
20652      } else {
20653        this.mediaBuffer = this.media;
20654      }
20655    };
20656    _proto.onFragBuffered = function onFragBuffered(event, data) {
20657      var frag = data.frag,
20658        part = data.part;
20659      if (frag && frag.type !== PlaylistLevelType.MAIN) {
20660        return;
20661      }
20662      if (this.fragContextChanged(frag)) {
20663        // If a level switch was requested while a fragment was buffering, it will emit the FRAG_BUFFERED event upon completion
20664        // Avoid setting state back to IDLE, since that will interfere with a level switch
20665        this.warn("Fragment " + frag.sn + (part ? ' p: ' + part.index : '') + " of level " + frag.level + " finished buffering, but was aborted. state: " + this.state);
20666        if (this.state === State.PARSED) {
20667          this.state = State.IDLE;
20668        }
20669        return;
20670      }
20671      var stats = part ? part.stats : frag.stats;
20672      this.fragLastKbps = Math.round(8 * stats.total / (stats.buffering.end - stats.loading.first));
20673      if (frag.sn !== 'initSegment') {
20674        this.fragPrevious = frag;
20675      }
20676      this.fragBufferedComplete(frag, part);
20677    };
20678    _proto.onError = function onError(event, data) {
20679      var _data$context;
20680      if (data.fatal) {
20681        this.state = State.ERROR;
20682        return;
20683      }
20684      switch (data.details) {
20685        case ErrorDetails.FRAG_GAP:
20686        case ErrorDetails.FRAG_PARSING_ERROR:
20687        case ErrorDetails.FRAG_DECRYPT_ERROR:
20688        case ErrorDetails.FRAG_LOAD_ERROR:
20689        case ErrorDetails.FRAG_LOAD_TIMEOUT:
20690        case ErrorDetails.KEY_LOAD_ERROR:
20691        case ErrorDetails.KEY_LOAD_TIMEOUT:
20692          this.onFragmentOrKeyLoadError(PlaylistLevelType.MAIN, data);
20693          break;
20694        case ErrorDetails.LEVEL_LOAD_ERROR:
20695        case ErrorDetails.LEVEL_LOAD_TIMEOUT:
20696        case ErrorDetails.LEVEL_PARSING_ERROR:
20697          // in case of non fatal error while loading level, if level controller is not retrying to load level, switch back to IDLE
20698          if (!data.levelRetry && this.state === State.WAITING_LEVEL && ((_data$context = data.context) == null ? void 0 : _data$context.type) === PlaylistContextType.LEVEL) {
20699            this.state = State.IDLE;
20700          }
20701          break;
20702        case ErrorDetails.BUFFER_APPEND_ERROR:
20703        case ErrorDetails.BUFFER_FULL_ERROR:
20704          if (!data.parent || data.parent !== 'main') {
20705            return;
20706          }
20707          if (data.details === ErrorDetails.BUFFER_APPEND_ERROR) {
20708            this.resetLoadingState();
20709            return;
20710          }
20711          if (this.reduceLengthAndFlushBuffer(data)) {
20712            this.flushMainBuffer(0, Number.POSITIVE_INFINITY);
20713          }
20714          break;
20715        case ErrorDetails.INTERNAL_EXCEPTION:
20716          this.recoverWorkerError(data);
20717          break;
20718      }
20719    }
20720
20721    // Checks the health of the buffer and attempts to resolve playback stalls.
20722    ;
20723    _proto.checkBuffer = function checkBuffer() {
20724      var media = this.media,
20725        gapController = this.gapController;
20726      if (!media || !gapController || !media.readyState) {
20727        // Exit early if we don't have media or if the media hasn't buffered anything yet (readyState 0)
20728        return;
20729      }
20730      if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
20731        // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
20732        var state = this.state;
20733        var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
20734        var levelDetails = this.getLevelDetails();
20735        gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
20736      }
20737      this.lastCurrentTime = media.currentTime;
20738    };
20739    _proto.onFragLoadEmergencyAborted = function onFragLoadEmergencyAborted() {
20740      this.state = State.IDLE;
20741      // if loadedmetadata is not set, it means that we are emergency switch down on first frag
20742      // in that case, reset startFragRequested flag
20743      if (!this.loadedmetadata) {
20744        this.startFragRequested = false;
20745        this.nextLoadPosition = this.lastCurrentTime;
20746      }
20747      this.tickImmediate();
20748    };
20749    _proto.onBufferFlushed = function onBufferFlushed(event, _ref) {
20750      var type = _ref.type;
20751      if (type !== ElementaryStreamTypes.AUDIO || this.audioOnly && !this.altAudio) {
20752        var mediaBuffer = (type === ElementaryStreamTypes.VIDEO ? this.videoBuffer : this.mediaBuffer) || this.media;
20753        this.afterBufferFlushed(mediaBuffer, type, PlaylistLevelType.MAIN);
20754        this.tick();
20755      }
20756    };
20757    _proto.onLevelsUpdated = function onLevelsUpdated(event, data) {
20758      if (this.level > -1 && this.fragCurrent) {
20759        this.level = this.fragCurrent.level;
20760      }
20761      this.levels = data.levels;
20762    };
20763    _proto.swapAudioCodec = function swapAudioCodec() {
20764      this.audioCodecSwap = !this.audioCodecSwap;
20765    }
20766
20767    /**
20768     * Seeks to the set startPosition if not equal to the mediaElement's current time.
20769     */;
20770    _proto.seekToStartPos = function seekToStartPos() {
20771      var media = this.media;
20772      if (!media) {
20773        return;
20774      }
20775      var currentTime = media.currentTime;
20776      var startPosition = this.startPosition;
20777      // only adjust currentTime if different from startPosition or if startPosition not buffered
20778      // at that stage, there should be only one buffered range, as we reach that code after first fragment has been buffered
20779      if (startPosition >= 0 && currentTime < startPosition) {
20780        if (media.seeking) {
20781          this.log("could not seek to " + startPosition + ", already seeking at " + currentTime);
20782          return;
20783        }
20784        var buffered = BufferHelper.getBuffered(media);
20785        var bufferStart = buffered.length ? buffered.start(0) : 0;
20786        var delta = bufferStart - startPosition;
20787        if (delta > 0 && (delta < this.config.maxBufferHole || delta < this.config.maxFragLookUpTolerance)) {
20788          this.log("adjusting start position by " + delta + " to match buffer start");
20789          startPosition += delta;
20790          this.startPosition = startPosition;
20791        }
20792        this.log("seek to target start position " + startPosition + " from current time " + currentTime);
20793        media.currentTime = startPosition;
20794      }
20795    };
20796    _proto._getAudioCodec = function _getAudioCodec(currentLevel) {
20797      var audioCodec = this.config.defaultAudioCodec || currentLevel.audioCodec;
20798      if (this.audioCodecSwap && audioCodec) {
20799        this.log('Swapping audio codec');
20800        if (audioCodec.indexOf('mp4a.40.5') !== -1) {
20801          audioCodec = 'mp4a.40.2';
20802        } else {
20803          audioCodec = 'mp4a.40.5';
20804        }
20805      }
20806      return audioCodec;
20807    };
20808    _proto._loadBitrateTestFrag = function _loadBitrateTestFrag(frag, level) {
20809      var _this2 = this;
20810      frag.bitrateTest = true;
20811      this._doFragLoad(frag, level).then(function (data) {
20812        var hls = _this2.hls;
20813        if (!data || _this2.fragContextChanged(frag)) {
20814          return;
20815        }
20816        level.fragmentError = 0;
20817        _this2.state = State.IDLE;
20818        _this2.startFragRequested = false;
vendor: 20,019 bytes, lines 20819-21283
20819        _this2.bitrateTest = false;
20820        var stats = frag.stats;
20821        // Bitrate tests fragments are neither parsed nor buffered
20822        stats.parsing.start = stats.parsing.end = stats.buffering.start = stats.buffering.end = self.performance.now();
20823        hls.trigger(Events.FRAG_LOADED, data);
20824        frag.bitrateTest = false;
20825      });
20826    };
20827    _proto._handleTransmuxComplete = function _handleTransmuxComplete(transmuxResult) {
20828      var _id3$samples;
20829      var id = this.playlistType;
20830      var hls = this.hls;
20831      var remuxResult = transmuxResult.remuxResult,
20832        chunkMeta = transmuxResult.chunkMeta;
20833      var context = this.getCurrentContext(chunkMeta);
20834      if (!context) {
20835        this.resetWhenMissingContext(chunkMeta);
20836        return;
20837      }
20838      var frag = context.frag,
20839        part = context.part,
20840        level = context.level;
20841      var video = remuxResult.video,
20842        text = remuxResult.text,
20843        id3 = remuxResult.id3,
20844        initSegment = remuxResult.initSegment;
20845      var details = level.details;
20846      // The audio-stream-controller handles audio buffering if Hls.js is playing an alternate audio track
20847      var audio = this.altAudio ? undefined : remuxResult.audio;
20848
20849      // Check if the current fragment has been aborted. We check this by first seeing if we're still playing the current level.
20850      // If we are, subsequently check if the currently loading fragment (fragCurrent) has changed.
20851      if (this.fragContextChanged(frag)) {
20852        this.fragmentTracker.removeFragment(frag);
20853        return;
20854      }
20855      this.state = State.PARSING;
20856      if (initSegment) {
20857        if (initSegment != null && initSegment.tracks) {
20858          var mapFragment = frag.initSegment || frag;
20859          this._bufferInitSegment(level, initSegment.tracks, mapFragment, chunkMeta);
20860          hls.trigger(Events.FRAG_PARSING_INIT_SEGMENT, {
20861            frag: mapFragment,
20862            id: id,
20863            tracks: initSegment.tracks
20864          });
20865        }
20866
20867        // This would be nice if Number.isFinite acted as a typeguard, but it doesn't. See: https://github.com/Microsoft/TypeScript/issues/10038
20868        var initPTS = initSegment.initPTS;
20869        var timescale = initSegment.timescale;
20870        if (isFiniteNumber(initPTS)) {
20871          this.initPTS[frag.cc] = {
20872            baseTime: initPTS,
20873            timescale: timescale
20874          };
20875          hls.trigger(Events.INIT_PTS_FOUND, {
20876            frag: frag,
20877            id: id,
20878            initPTS: initPTS,
20879            timescale: timescale
20880          });
20881        }
20882      }
20883
20884      // Avoid buffering if backtracking this fragment
20885      if (video && details) {
20886        var prevFrag = details.fragments[frag.sn - 1 - details.startSN];
20887        var isFirstFragment = frag.sn === details.startSN;
20888        var isFirstInDiscontinuity = !prevFrag || frag.cc > prevFrag.cc;
20889        if (remuxResult.independent !== false) {
20890          var startPTS = video.startPTS,
20891            endPTS = video.endPTS,
20892            startDTS = video.startDTS,
20893            endDTS = video.endDTS;
20894          if (part) {
20895            part.elementaryStreams[video.type] = {
20896              startPTS: startPTS,
20897              endPTS: endPTS,
20898              startDTS: startDTS,
20899              endDTS: endDTS
20900            };
20901          } else {
20902            if (video.firstKeyFrame && video.independent && chunkMeta.id === 1 && !isFirstInDiscontinuity) {
20903              this.couldBacktrack = true;
20904            }
20905            if (video.dropped && video.independent) {
20906              // Backtrack if dropped frames create a gap after currentTime
20907
20908              var bufferInfo = this.getMainFwdBufferInfo();
20909              var targetBufferTime = (bufferInfo ? bufferInfo.end : this.getLoadPosition()) + this.config.maxBufferHole;
20910              var startTime = video.firstKeyFramePTS ? video.firstKeyFramePTS : startPTS;
20911              if (!isFirstFragment && targetBufferTime < startTime - this.config.maxBufferHole && !isFirstInDiscontinuity) {
20912                this.backtrack(frag);
20913                return;
20914              } else if (isFirstInDiscontinuity) {
20915                // Mark segment with a gap to avoid loop loading
20916                frag.gap = true;
20917              }
20918              // Set video stream start to fragment start so that truncated samples do not distort the timeline, and mark it partial
20919              frag.setElementaryStreamInfo(video.type, frag.start, endPTS, frag.start, endDTS, true);
20920            } else if (isFirstFragment && startPTS > MAX_START_GAP_JUMP) {
20921              // Mark segment with a gap to skip large start gap
20922              frag.gap = true;
20923            }
20924          }
20925          frag.setElementaryStreamInfo(video.type, startPTS, endPTS, startDTS, endDTS);
20926          if (this.backtrackFragment) {
20927            this.backtrackFragment = frag;
20928          }
20929          this.bufferFragmentData(video, frag, part, chunkMeta, isFirstFragment || isFirstInDiscontinuity);
20930        } else if (isFirstFragment || isFirstInDiscontinuity) {
20931          // Mark segment with a gap to avoid loop loading
20932          frag.gap = true;
20933        } else {
20934          this.backtrack(frag);
20935          return;
20936        }
20937      }
20938      if (audio) {
20939        var _startPTS = audio.startPTS,
20940          _endPTS = audio.endPTS,
20941          _startDTS = audio.startDTS,
20942          _endDTS = audio.endDTS;
20943        if (part) {
20944          part.elementaryStreams[ElementaryStreamTypes.AUDIO] = {
20945            startPTS: _startPTS,
20946            endPTS: _endPTS,
20947            startDTS: _startDTS,
20948            endDTS: _endDTS
20949          };
20950        }
20951        frag.setElementaryStreamInfo(ElementaryStreamTypes.AUDIO, _startPTS, _endPTS, _startDTS, _endDTS);
20952        this.bufferFragmentData(audio, frag, part, chunkMeta);
20953      }
20954      if (details && id3 != null && (_id3$samples = id3.samples) != null && _id3$samples.length) {
20955        var emittedID3 = {
20956          id: id,
20957          frag: frag,
20958          details: details,
20959          samples: id3.samples
20960        };
20961        hls.trigger(Events.FRAG_PARSING_METADATA, emittedID3);
20962      }
20963      if (details && text) {
20964        var emittedText = {
20965          id: id,
20966          frag: frag,
20967          details: details,
20968          samples: text.samples
20969        };
20970        hls.trigger(Events.FRAG_PARSING_USERDATA, emittedText);
20971      }
20972    };
20973    _proto._bufferInitSegment = function _bufferInitSegment(currentLevel, tracks, frag, chunkMeta) {
20974      var _this3 = this;
20975      if (this.state !== State.PARSING) {
20976        return;
20977      }
20978      this.audioOnly = !!tracks.audio && !tracks.video;
20979
20980      // if audio track is expected to come from audio stream controller, discard any coming from main
20981      if (this.altAudio && !this.audioOnly) {
20982        delete tracks.audio;
20983      }
20984      // include levelCodec in audio and video tracks
20985      var audio = tracks.audio,
20986        video = tracks.video,
20987        audiovideo = tracks.audiovideo;
20988      if (audio) {
20989        var audioCodec = currentLevel.audioCodec;
20990        var ua = navigator.userAgent.toLowerCase();
20991        if (this.audioCodecSwitch) {
20992          if (audioCodec) {
20993            if (audioCodec.indexOf('mp4a.40.5') !== -1) {
20994              audioCodec = 'mp4a.40.2';
20995            } else {
20996              audioCodec = 'mp4a.40.5';
20997            }
20998          }
20999          // In the case that AAC and HE-AAC audio codecs are signalled in manifest,
21000          // force HE-AAC, as it seems that most browsers prefers it.
21001          // don't force HE-AAC if mono stream, or in Firefox
21002          var audioMetadata = audio.metadata;
21003          if (audioMetadata && 'channelCount' in audioMetadata && (audioMetadata.channelCount || 1) !== 1 && ua.indexOf('firefox') === -1) {
21004            audioCodec = 'mp4a.40.5';
21005          }
21006        }
21007        // HE-AAC is broken on Android, always signal audio codec as AAC even if variant manifest states otherwise
21008        if (audioCodec && audioCodec.indexOf('mp4a.40.5') !== -1 && ua.indexOf('android') !== -1 && audio.container !== 'audio/mpeg') {
21009          // Exclude mpeg audio
21010          audioCodec = 'mp4a.40.2';
21011          this.log("Android: force audio codec to " + audioCodec);
21012        }
21013        if (currentLevel.audioCodec && currentLevel.audioCodec !== audioCodec) {
21014          this.log("Swapping manifest audio codec \"" + currentLevel.audioCodec + "\" for \"" + audioCodec + "\"");
21015        }
21016        audio.levelCodec = audioCodec;
21017        audio.id = 'main';
21018        this.log("Init audio buffer, container:" + audio.container + ", codecs[selected/level/parsed]=[" + (audioCodec || '') + "/" + (currentLevel.audioCodec || '') + "/" + audio.codec + "]");
21019        delete tracks.audiovideo;
21020      }
21021      if (video) {
21022        video.levelCodec = currentLevel.videoCodec;
21023        video.id = 'main';
21024        this.log("Init video buffer, container:" + video.container + ", codecs[level/parsed]=[" + (currentLevel.videoCodec || '') + "/" + video.codec + "]");
21025        delete tracks.audiovideo;
21026      }
21027      if (audiovideo) {
21028        this.log("Init audiovideo buffer, container:" + audiovideo.container + ", codecs[level/parsed]=[" + currentLevel.codecs + "/" + audiovideo.codec + "]");
21029        delete tracks.video;
21030        delete tracks.audio;
21031      }
21032      var trackTypes = Object.keys(tracks);
21033      if (trackTypes.length) {
21034        this.hls.trigger(Events.BUFFER_CODECS, tracks);
21035        // loop through tracks that are going to be provided to bufferController
21036        trackTypes.forEach(function (trackName) {
21037          var track = tracks[trackName];
21038          var initSegment = track.initSegment;
21039          if (initSegment != null && initSegment.byteLength) {
21040            _this3.hls.trigger(Events.BUFFER_APPENDING, {
21041              type: trackName,
21042              data: initSegment,
21043              frag: frag,
21044              part: null,
21045              chunkMeta: chunkMeta,
21046              parent: frag.type
21047            });
21048          }
21049        });
21050      }
21051      // trigger handler right now
21052      this.tickImmediate();
21053    };
21054    _proto.getMainFwdBufferInfo = function getMainFwdBufferInfo() {
21055      return this.getFwdBufferInfo(this.mediaBuffer ? this.mediaBuffer : this.media, PlaylistLevelType.MAIN);
21056    };
21057    _proto.backtrack = function backtrack(frag) {
21058      this.couldBacktrack = true;
21059      // Causes findFragments to backtrack through fragments to find the keyframe
21060      this.backtrackFragment = frag;
21061      this.resetTransmuxer();
21062      this.flushBufferGap(frag);
21063      this.fragmentTracker.removeFragment(frag);
21064      this.fragPrevious = null;
21065      this.nextLoadPosition = frag.start;
21066      this.state = State.IDLE;
21067    };
21068    _proto.checkFragmentChanged = function checkFragmentChanged() {
21069      var video = this.media;
21070      var fragPlayingCurrent = null;
21071      if (video && video.readyState > 1 && video.seeking === false) {
21072        var currentTime = video.currentTime;
21073        /* if video element is in seeked state, currentTime can only increase.
21074          (assuming that playback rate is positive ...)
21075          As sometimes currentTime jumps back to zero after a
21076          media decode error, check this, to avoid seeking back to
21077          wrong position after a media decode error
21078        */
21079
21080        if (BufferHelper.isBuffered(video, currentTime)) {
21081          fragPlayingCurrent = this.getAppendedFrag(currentTime);
21082        } else if (BufferHelper.isBuffered(video, currentTime + 0.1)) {
21083          /* ensure that FRAG_CHANGED event is triggered at startup,
21084            when first video frame is displayed and playback is paused.
21085            add a tolerance of 100ms, in case current position is not buffered,
21086            check if current pos+100ms is buffered and use that buffer range
21087            for FRAG_CHANGED event reporting */
21088          fragPlayingCurrent = this.getAppendedFrag(currentTime + 0.1);
21089        }
21090        if (fragPlayingCurrent) {
21091          this.backtrackFragment = null;
21092          var fragPlaying = this.fragPlaying;
21093          var fragCurrentLevel = fragPlayingCurrent.level;
21094          if (!fragPlaying || fragPlayingCurrent.sn !== fragPlaying.sn || fragPlaying.level !== fragCurrentLevel) {
21095            this.fragPlaying = fragPlayingCurrent;
21096            this.hls.trigger(Events.FRAG_CHANGED, {
21097              frag: fragPlayingCurrent
21098            });
21099            if (!fragPlaying || fragPlaying.level !== fragCurrentLevel) {
21100              this.hls.trigger(Events.LEVEL_SWITCHED, {
21101                level: fragCurrentLevel
21102              });
21103            }
21104          }
21105        }
21106      }
21107    };
21108    return _createClass(StreamController, [{
21109      key: "maxBufferLength",
21110      get: function get() {
21111        var levels = this.levels,
21112          level = this.level;
21113        var levelInfo = levels == null ? void 0 : levels[level];
21114        if (!levelInfo) {
21115          return this.config.maxBufferLength;
21116        }
21117        return this.getMaxBufferLength(levelInfo.maxBitrate);
21118      }
21119    }, {
21120      key: "nextLevel",
21121      get: function get() {
21122        var frag = this.nextBufferedFrag;
21123        if (frag) {
21124          return frag.level;
21125        }
21126        return -1;
21127      }
21128    }, {
21129      key: "currentFrag",
21130      get: function get() {
21131        var _this$media2;
21132        if (this.fragPlaying) {
21133          return this.fragPlaying;
21134        }
21135        var currentTime = ((_this$media2 = this.media) == null ? void 0 : _this$media2.currentTime) || this.lastCurrentTime;
21136        if (isFiniteNumber(currentTime)) {
21137          return this.getAppendedFrag(currentTime);
21138        }
21139        return null;
21140      }
21141    }, {
21142      key: "currentProgramDateTime",
21143      get: function get() {
21144        var _this$media3;
21145        var currentTime = ((_this$media3 = this.media) == null ? void 0 : _this$media3.currentTime) || this.lastCurrentTime;
21146        if (isFiniteNumber(currentTime)) {
21147          var details = this.getLevelDetails();
21148          var frag = this.currentFrag || (details ? findFragmentByPTS(null, details.fragments, currentTime) : null);
21149          if (frag) {
21150            var programDateTime = frag.programDateTime;
21151            if (programDateTime !== null) {
21152              var epocMs = programDateTime + (currentTime - frag.start) * 1000;
21153              return new Date(epocMs);
21154            }
21155          }
21156        }
21157        return null;
21158      }
21159    }, {
21160      key: "currentLevel",
21161      get: function get() {
21162        var frag = this.currentFrag;
21163        if (frag) {
21164          return frag.level;
21165        }
21166        return -1;
21167      }
21168    }, {
21169      key: "nextBufferedFrag",
21170      get: function get() {
21171        var frag = this.currentFrag;
21172        if (frag) {
21173          return this.followingBufferedFrag(frag);
21174        }
21175        return null;
21176      }
21177    }, {
21178      key: "forceStartLoad",
21179      get: function get() {
21180        return this._forceStartLoad;
21181      }
21182    }]);
21183  }(BaseStreamController);
21184
21185  /**
21186   * The `Hls` class is the core of the HLS.js library used to instantiate player instances.
21187   * @public
21188   */
21189  var Hls = /*#__PURE__*/function () {
21190    /**
21191     * Creates an instance of an HLS client that can attach to exactly one `HTMLMediaElement`.
21192     * @param userConfig - Configuration options applied over `Hls.DefaultConfig`
21193     */
21194    function Hls(userConfig) {
21195      if (userConfig === void 0) {
21196        userConfig = {};
21197      }
21198      /**
21199       * The runtime configuration used by the player. At instantiation this is combination of `hls.userConfig` merged over `Hls.DefaultConfig`.
21200       */
21201      this.config = void 0;
21202      /**
21203       * The configuration object provided on player instantiation.
21204       */
21205      this.userConfig = void 0;
21206      /**
21207       * The logger functions used by this player instance, configured on player instantiation.
21208       */
21209      this.logger = void 0;
21210      this.coreComponents = void 0;
21211      this.networkControllers = void 0;
21212      this._emitter = new EventEmitter();
21213      this._autoLevelCapping = -1;
21214      this._maxHdcpLevel = null;
21215      this.abrController = void 0;
21216      this.bufferController = void 0;
21217      this.capLevelController = void 0;
21218      this.latencyController = void 0;
21219      this.levelController = void 0;
21220      this.streamController = void 0;
21221      this.audioTrackController = void 0;
21222      this.subtitleTrackController = void 0;
21223      this.emeController = void 0;
21224      this.cmcdController = void 0;
21225      this._media = null;
21226      this._url = null;
21227      this.triggeringException = void 0;
21228      var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
21229      var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
21230      this.userConfig = userConfig;
21231      if (config.progressive) {
21232        enableStreamingMode(config, logger);
21233      }
21234
21235      // core controllers and network loaders
21236      var ConfigAbrController = config.abrController,
21237        ConfigBufferController = config.bufferController,
21238        ConfigCapLevelController = config.capLevelController,
21239        ConfigErrorController = config.errorController,
21240        ConfigFpsController = config.fpsController;
21241      var errorController = new ConfigErrorController(this);
21242      var abrController = this.abrController = new ConfigAbrController(this);
21243      // FragmentTracker must be defined before StreamController because the order of event handling is important
21244      var fragmentTracker = new FragmentTracker(this);
21245      var bufferController = this.bufferController = new ConfigBufferController(this, fragmentTracker);
21246      var capLevelController = this.capLevelController = new ConfigCapLevelController(this);
21247      var fpsController = new ConfigFpsController(this);
21248      var playListLoader = new PlaylistLoader(this);
21249      var id3TrackController = new ID3TrackController(this);
21250      var ConfigContentSteeringController = config.contentSteeringController;
21251      // ContentSteeringController is defined before LevelController to receive Multivariant Playlist events first
21252      var contentSteering = ConfigContentSteeringController ? new ConfigContentSteeringController(this) : null;
21253      var levelController = this.levelController = new LevelController(this, contentSteering);
21254      var keyLoader = new KeyLoader(this.config);
21255      var streamController = this.streamController = new StreamController(this, fragmentTracker, keyLoader);
21256
21257      // Cap level controller uses streamController to flush the buffer
21258      capLevelController.setStreamController(streamController);
21259      // fpsController uses streamController to switch when frames are being dropped
21260      fpsController.setStreamController(streamController);
21261      var networkControllers = [playListLoader, levelController, streamController];
21262      if (contentSteering) {
21263        networkControllers.splice(1, 0, contentSteering);
21264      }
21265      this.networkControllers = networkControllers;
21266      var coreComponents = [abrController, bufferController, capLevelController, fpsController, id3TrackController, fragmentTracker];
21267      this.audioTrackController = this.createController(config.audioTrackController, networkControllers);
21268      var AudioStreamControllerClass = config.audioStreamController;
21269      if (AudioStreamControllerClass) {
21270        networkControllers.push(new AudioStreamControllerClass(this, fragmentTracker, keyLoader));
21271      }
21272      // Instantiate subtitleTrackController before SubtitleStreamController to receive level events first
21273      this.subtitleTrackController = this.createController(config.subtitleTrackController, networkControllers);
21274      var SubtitleStreamControllerClass = config.subtitleStreamController;
21275      if (SubtitleStreamControllerClass) {
21276        networkControllers.push(new SubtitleStreamControllerClass(this, fragmentTracker, keyLoader));
21277      }
21278      this.createController(config.timelineController, coreComponents);
21279      keyLoader.emeController = this.emeController = this.createController(config.emeController, coreComponents);
21280      this.cmcdController = this.createController(config.cmcdController, coreComponents);
21281      this.latencyController = this.createController(LatencyController, coreComponents);
21282      this.coreComponents = coreComponents;
21283
vendor: 4,720 bytes, lines 21284-21422
21284      // Error controller handles errors before and after all other controllers
21285      // This listener will be invoked after all other controllers error listeners
21286      networkControllers.push(errorController);
21287      var onErrorOut = errorController.onErrorOut;
21288      if (typeof onErrorOut === 'function') {
21289        this.on(Events.ERROR, onErrorOut, errorController);
21290      }
21291    }
21292    /**
21293     * Check if the required MediaSource Extensions are available.
21294     */
21295    Hls.isMSESupported = function isMSESupported$1() {
21296      return isMSESupported();
21297    }
21298
21299    /**
21300     * Check if MediaSource Extensions are available and isTypeSupported checks pass for any baseline codecs.
21301     */;
21302    Hls.isSupported = function isSupported$1() {
21303      return isSupported();
21304    }
21305
21306    /**
21307     * Get the MediaSource global used for MSE playback (ManagedMediaSource, MediaSource, or WebKitMediaSource).
21308     */;
21309    Hls.getMediaSource = function getMediaSource$1() {
21310      return getMediaSource();
21311    };
21312    var _proto = Hls.prototype;
21313    _proto.createController = function createController(ControllerClass, components) {
21314      if (ControllerClass) {
21315        var controllerInstance = new ControllerClass(this);
21316        if (components) {
21317          components.push(controllerInstance);
21318        }
21319        return controllerInstance;
21320      }
21321      return null;
21322    }
21323
21324    // Delegate the EventEmitter through the public API of Hls.js
21325    ;
21326    _proto.on = function on(event, listener, context) {
21327      if (context === void 0) {
21328        context = this;
21329      }
21330      this._emitter.on(event, listener, context);
21331    };
21332    _proto.once = function once(event, listener, context) {
21333      if (context === void 0) {
21334        context = this;
21335      }
21336      this._emitter.once(event, listener, context);
21337    };
21338    _proto.removeAllListeners = function removeAllListeners(event) {
21339      this._emitter.removeAllListeners(event);
21340    };
21341    _proto.off = function off(event, listener, context, once) {
21342      if (context === void 0) {
21343        context = this;
21344      }
21345      this._emitter.off(event, listener, context, once);
21346    };
21347    _proto.listeners = function listeners(event) {
21348      return this._emitter.listeners(event);
21349    };
21350    _proto.emit = function emit(event, name, eventObject) {
21351      return this._emitter.emit(event, name, eventObject);
21352    };
21353    _proto.trigger = function trigger(event, eventObject) {
21354      if (this.config.debug) {
21355        return this.emit(event, event, eventObject);
21356      } else {
21357        try {
21358          return this.emit(event, event, eventObject);
21359        } catch (error) {
21360          this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
21361          // Prevent recursion in error event handlers that throw #5497
21362          if (!this.triggeringException) {
21363            this.triggeringException = true;
21364            var fatal = event === Events.ERROR;
21365            this.trigger(Events.ERROR, {
21366              type: ErrorTypes.OTHER_ERROR,
21367              details: ErrorDetails.INTERNAL_EXCEPTION,
21368              fatal: fatal,
21369              event: event,
21370              error: error
21371            });
21372            this.triggeringException = false;
21373          }
21374        }
21375      }
21376      return false;
21377    };
21378    _proto.listenerCount = function listenerCount(event) {
21379      return this._emitter.listenerCount(event);
21380    }
21381
21382    /**
21383     * Dispose of the instance
21384     */;
21385    _proto.destroy = function destroy() {
21386      this.logger.log('destroy');
21387      this.trigger(Events.DESTROYING, undefined);
21388      this.detachMedia();
21389      this.removeAllListeners();
21390      this._autoLevelCapping = -1;
21391      this._url = null;
21392      this.networkControllers.forEach(function (component) {
21393        return component.destroy();
21394      });
21395      this.networkControllers.length = 0;
21396      this.coreComponents.forEach(function (component) {
21397        return component.destroy();
21398      });
21399      this.coreComponents.length = 0;
21400      // Remove any references that could be held in config options or callbacks
21401      var config = this.config;
21402      config.xhrSetup = config.fetchSetup = undefined;
21403      // @ts-ignore
21404      this.userConfig = null;
21405    }
21406
21407    /**
21408     * Attaches Hls.js to a media element
21409     */;
21410    _proto.attachMedia = function attachMedia(media) {
21411      if (!media) {
21412        var error = new Error("attachMedia failed: media argument is " + media);
21413        this.trigger(Events.ERROR, {
21414          type: ErrorTypes.OTHER_ERROR,
21415          details: ErrorDetails.ATTACH_MEDIA_ERROR,
21416          fatal: true,
21417          error: error
21418        });
21419        return;
21420      }
21421      this.logger.log('attachMedia');
21422      this._media = media;
vendor: 5,025 bytes, lines 21423-21567
21423      this.trigger(Events.MEDIA_ATTACHING, {
21424        media: media
21425      });
21426    }
21427
21428    /**
21429     * Detach Hls.js from the media
21430     */;
21431    _proto.detachMedia = function detachMedia() {
21432      this.logger.log('detachMedia');
21433      this.trigger(Events.MEDIA_DETACHING, undefined);
21434      this._media = null;
21435    }
21436
21437    /**
21438     * Set the source URL. Can be relative or absolute.
21439     */;
21440    _proto.loadSource = function loadSource(url) {
21441      this.stopLoad();
21442      var media = this.media;
21443      var loadedSource = this._url;
21444      var loadingSource = this._url = urlToolkitExports.buildAbsoluteURL(self.location.href, url, {
21445        alwaysNormalize: true
21446      });
21447      this._autoLevelCapping = -1;
21448      this._maxHdcpLevel = null;
21449      this.logger.log("loadSource:" + loadingSource);
21450      if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
21451        this.detachMedia();
21452        this.attachMedia(media);
21453      }
21454      // when attaching to a source URL, trigger a playlist load
21455      this.trigger(Events.MANIFEST_LOADING, {
21456        url: url
21457      });
21458    }
21459
21460    /**
21461     * Gets the currently loaded URL
21462     */;
21463    /**
21464     * Start loading data from the stream source.
21465     * Depending on default config, client starts loading automatically when a source is set.
21466     *
21467     * @param startPosition - Set the start position to stream from.
21468     * Defaults to -1 (None: starts from earliest point)
21469     */
21470    _proto.startLoad = function startLoad(startPosition) {
21471      if (startPosition === void 0) {
21472        startPosition = -1;
21473      }
21474      this.logger.log("startLoad(" + startPosition + ")");
21475      this.networkControllers.forEach(function (controller) {
21476        controller.startLoad(startPosition);
21477      });
21478    }
21479
21480    /**
21481     * Stop loading of any stream data.
21482     */;
21483    _proto.stopLoad = function stopLoad() {
21484      this.logger.log('stopLoad');
21485      this.networkControllers.forEach(function (controller) {
21486        controller.stopLoad();
21487      });
21488    }
21489
21490    /**
21491     * Resumes stream controller segment loading after `pauseBuffering` has been called.
21492     */;
21493    _proto.resumeBuffering = function resumeBuffering() {
21494      this.networkControllers.forEach(function (controller) {
21495        if (controller.resumeBuffering) {
21496          controller.resumeBuffering();
21497        }
21498      });
21499    }
21500
21501    /**
21502     * Prevents stream controller from loading new segments until `resumeBuffering` is called.
21503     * This allows for media buffering to be paused without interupting playlist loading.
21504     */;
21505    _proto.pauseBuffering = function pauseBuffering() {
21506      this.networkControllers.forEach(function (controller) {
21507        if (controller.pauseBuffering) {
21508          controller.pauseBuffering();
21509        }
21510      });
21511    }
21512
21513    /**
21514     * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
21515     */;
21516    _proto.swapAudioCodec = function swapAudioCodec() {
21517      this.logger.log('swapAudioCodec');
21518      this.streamController.swapAudioCodec();
21519    }
21520
21521    /**
21522     * When the media-element fails, this allows to detach and then re-attach it
21523     * as one call (convenience method).
21524     *
21525     * Automatic recovery of media-errors by this process is configurable.
21526     */;
21527    _proto.recoverMediaError = function recoverMediaError() {
21528      this.logger.log('recoverMediaError');
21529      var media = this._media;
21530      this.detachMedia();
21531      if (media) {
21532        this.attachMedia(media);
21533      }
21534    };
21535    _proto.removeLevel = function removeLevel(levelIndex) {
21536      this.levelController.removeLevel(levelIndex);
21537    }
21538
21539    /**
21540     * @returns an array of levels (variants) sorted by HDCP-LEVEL, RESOLUTION (height), FRAME-RATE, CODECS, VIDEO-RANGE, and BANDWIDTH
21541     */;
21542    /**
21543     * Find and select the best matching audio track, making a level switch when a Group change is necessary.
21544     * Updates `hls.config.audioPreference`. Returns the selected track, or null when no matching track is found.
21545     */
21546    _proto.setAudioOption = function setAudioOption(audioOption) {
21547      var _this$audioTrackContr;
21548      return ((_this$audioTrackContr = this.audioTrackController) == null ? void 0 : _this$audioTrackContr.setAudioOption(audioOption)) || null;
21549    }
21550    /**
21551     * Find and select the best matching subtitle track, making a level switch when a Group change is necessary.
21552     * Updates `hls.config.subtitlePreference`. Returns the selected track, or null when no matching track is found.
21553     */;
21554    _proto.setSubtitleOption = function setSubtitleOption(subtitleOption) {
21555      var _this$subtitleTrackCo;
21556      return ((_this$subtitleTrackCo = this.subtitleTrackController) == null ? void 0 : _this$subtitleTrackCo.setSubtitleOption(subtitleOption)) || null;
21557    }
21558
21559    /**
21560     * Get the complete list of audio tracks across all media groups
21561     */;
21562    return _createClass(Hls, [{
21563      key: "url",
21564      get: function get() {
21565        return this._url;
21566      }
21567    }, {
vendor: 4,822 bytes, lines 21568-21703
21568      key: "levels",
21569      get: function get() {
21570        var levels = this.levelController.levels;
21571        return levels ? levels : [];
21572      }
21573
21574      /**
21575       * Index of quality level (variant) currently played
21576       */
21577    }, {
21578      key: "currentLevel",
21579      get: function get() {
21580        return this.streamController.currentLevel;
21581      }
21582
21583      /**
21584       * 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.
21585       */,
21586      set: function set(newLevel) {
21587        this.logger.log("set currentLevel:" + newLevel);
21588        this.levelController.manualLevel = newLevel;
21589        this.streamController.immediateLevelSwitch();
21590      }
21591
21592      /**
21593       * Index of next quality level loaded as scheduled by stream controller.
21594       */
21595    }, {
21596      key: "nextLevel",
21597      get: function get() {
21598        return this.streamController.nextLevel;
21599      }
21600
21601      /**
21602       * Set quality level index for next loaded data.
21603       * This will switch the video quality asap, without interrupting playback.
21604       * May abort current loading of data, and flush parts of buffer (outside currently played fragment region).
21605       * @param newLevel - Pass -1 for automatic level selection
21606       */,
21607      set: function set(newLevel) {
21608        this.logger.log("set nextLevel:" + newLevel);
21609        this.levelController.manualLevel = newLevel;
21610        this.streamController.nextLevelSwitch();
21611      }
21612
21613      /**
21614       * Return the quality level of the currently or last (of none is loaded currently) segment
21615       */
21616    }, {
21617      key: "loadLevel",
21618      get: function get() {
21619        return this.levelController.level;
21620      }
21621
21622      /**
21623       * Set quality level index for next loaded data in a conservative way.
21624       * This will switch the quality without flushing, but interrupt current loading.
21625       * Thus the moment when the quality switch will appear in effect will only be after the already existing buffer.
21626       * @param newLevel - Pass -1 for automatic level selection
21627       */,
21628      set: function set(newLevel) {
21629        this.logger.log("set loadLevel:" + newLevel);
21630        this.levelController.manualLevel = newLevel;
21631      }
21632
21633      /**
21634       * get next quality level loaded
21635       */
21636    }, {
21637      key: "nextLoadLevel",
21638      get: function get() {
21639        return this.levelController.nextLoadLevel;
21640      }
21641
21642      /**
21643       * Set quality level of next loaded segment in a fully "non-destructive" way.
21644       * Same as `loadLevel` but will wait for next switch (until current loading is done).
21645       */,
21646      set: function set(level) {
21647        this.levelController.nextLoadLevel = level;
21648      }
21649
21650      /**
21651       * Return "first level": like a default level, if not set,
21652       * falls back to index of first level referenced in manifest
21653       */
21654    }, {
21655      key: "firstLevel",
21656      get: function get() {
21657        return Math.max(this.levelController.firstLevel, this.minAutoLevel);
21658      }
21659
21660      /**
21661       * Sets "first-level", see getter.
21662       */,
21663      set: function set(newLevel) {
21664        this.logger.log("set firstLevel:" + newLevel);
21665        this.levelController.firstLevel = newLevel;
21666      }
21667
21668      /**
21669       * Return the desired start level for the first fragment that will be loaded.
21670       * The default value of -1 indicates automatic start level selection.
21671       * Setting hls.nextAutoLevel without setting a startLevel will result in
21672       * the nextAutoLevel value being used for one fragment load.
21673       */
21674    }, {
21675      key: "startLevel",
21676      get: function get() {
21677        var startLevel = this.levelController.startLevel;
21678        if (startLevel === -1 && this.abrController.forcedAutoLevel > -1) {
21679          return this.abrController.forcedAutoLevel;
21680        }
21681        return startLevel;
21682      }
21683
21684      /**
21685       * set  start level (level of first fragment that will be played back)
21686       * if not overrided by user, first level appearing in manifest will be used as start level
21687       * if -1 : automatic start level selection, playback will start from level matching download bandwidth
21688       * (determined from download of first segment)
21689       */,
21690      set: function set(newLevel) {
21691        this.logger.log("set startLevel:" + newLevel);
21692        // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
21693        if (newLevel !== -1) {
21694          newLevel = Math.max(newLevel, this.minAutoLevel);
21695        }
21696        this.levelController.startLevel = newLevel;
21697      }
21698
21699      /**
21700       * Whether level capping is enabled.
21701       * Default value is set via `config.capLevelToPlayerSize`.
21702       */
21703    }, {
vendor: 4,391 bytes, lines 21704-21848
21704      key: "capLevelToPlayerSize",
21705      get: function get() {
21706        return this.config.capLevelToPlayerSize;
21707      }
21708
21709      /**
21710       * Enables or disables level capping. If disabled after previously enabled, `nextLevelSwitch` will be immediately called.
21711       */,
21712      set: function set(shouldStartCapping) {
21713        var newCapLevelToPlayerSize = !!shouldStartCapping;
21714        if (newCapLevelToPlayerSize !== this.config.capLevelToPlayerSize) {
21715          if (newCapLevelToPlayerSize) {
21716            this.capLevelController.startCapping(); // If capping occurs, nextLevelSwitch will happen based on size.
21717          } else {
21718            this.capLevelController.stopCapping();
21719            this.autoLevelCapping = -1;
21720            this.streamController.nextLevelSwitch(); // Now we're uncapped, get the next level asap.
21721          }
21722          this.config.capLevelToPlayerSize = newCapLevelToPlayerSize;
21723        }
21724      }
21725
21726      /**
21727       * Capping/max level value that should be used by automatic level selection algorithm (`ABRController`)
21728       */
21729    }, {
21730      key: "autoLevelCapping",
21731      get: function get() {
21732        return this._autoLevelCapping;
21733      }
21734
21735      /**
21736       * Returns the current bandwidth estimate in bits per second, when available. Otherwise, `NaN` is returned.
21737       */,
21738      set:
21739      /**
21740       * Capping/max level value that should be used by automatic level selection algorithm (`ABRController`)
21741       */
21742      function set(newLevel) {
21743        if (this._autoLevelCapping !== newLevel) {
21744          this.logger.log("set autoLevelCapping:" + newLevel);
21745          this._autoLevelCapping = newLevel;
21746          this.levelController.checkMaxAutoUpdated();
21747        }
21748      }
21749    }, {
21750      key: "bandwidthEstimate",
21751      get: function get() {
21752        var bwEstimator = this.abrController.bwEstimator;
21753        if (!bwEstimator) {
21754          return NaN;
21755        }
21756        return bwEstimator.getEstimate();
21757      },
21758      set: function set(abrEwmaDefaultEstimate) {
21759        this.abrController.resetEstimator(abrEwmaDefaultEstimate);
21760      }
21761
21762      /**
21763       * get time to first byte estimate
21764       * @type {number}
21765       */
21766    }, {
21767      key: "ttfbEstimate",
21768      get: function get() {
21769        var bwEstimator = this.abrController.bwEstimator;
21770        if (!bwEstimator) {
21771          return NaN;
21772        }
21773        return bwEstimator.getEstimateTTFB();
21774      }
21775    }, {
21776      key: "maxHdcpLevel",
21777      get: function get() {
21778        return this._maxHdcpLevel;
21779      },
21780      set: function set(value) {
21781        if (isHdcpLevel(value) && this._maxHdcpLevel !== value) {
21782          this._maxHdcpLevel = value;
21783          this.levelController.checkMaxAutoUpdated();
21784        }
21785      }
21786
21787      /**
21788       * True when automatic level selection enabled
21789       */
21790    }, {
21791      key: "autoLevelEnabled",
21792      get: function get() {
21793        return this.levelController.manualLevel === -1;
21794      }
21795
21796      /**
21797       * Level set manually (if any)
21798       */
21799    }, {
21800      key: "manualLevel",
21801      get: function get() {
21802        return this.levelController.manualLevel;
21803      }
21804
21805      /**
21806       * min level selectable in auto mode according to config.minAutoBitrate
21807       */
21808    }, {
21809      key: "minAutoLevel",
21810      get: function get() {
21811        var levels = this.levels,
21812          minAutoBitrate = this.config.minAutoBitrate;
21813        if (!levels) return 0;
21814        var len = levels.length;
21815        for (var i = 0; i < len; i++) {
21816          if (levels[i].maxBitrate >= minAutoBitrate) {
21817            return i;
21818          }
21819        }
21820        return 0;
21821      }
21822
21823      /**
21824       * max level selectable in auto mode according to autoLevelCapping
21825       */
21826    }, {
21827      key: "maxAutoLevel",
21828      get: function get() {
21829        var levels = this.levels,
21830          autoLevelCapping = this.autoLevelCapping,
21831          maxHdcpLevel = this.maxHdcpLevel;
21832        var maxAutoLevel;
21833        if (autoLevelCapping === -1 && levels != null && levels.length) {
21834          maxAutoLevel = levels.length - 1;
21835        } else {
21836          maxAutoLevel = autoLevelCapping;
21837        }
21838        if (maxHdcpLevel) {
21839          for (var i = maxAutoLevel; i--;) {
21840            var hdcpLevel = levels[i].attrs['HDCP-LEVEL'];
21841            if (hdcpLevel && hdcpLevel <= maxHdcpLevel) {
21842              return i;
21843            }
21844          }
21845        }
21846        return maxAutoLevel;
21847      }
21848    }, {
vendor: 8,114 bytes, lines 21849-22133
21849      key: "firstAutoLevel",
21850      get: function get() {
21851        return this.abrController.firstAutoLevel;
21852      }
21853
21854      /**
21855       * next automatically selected quality level
21856       */
21857    }, {
21858      key: "nextAutoLevel",
21859      get: function get() {
21860        return this.abrController.nextAutoLevel;
21861      }
21862
21863      /**
21864       * this setter is used to force next auto level.
21865       * this is useful to force a switch down in auto mode:
21866       * in case of load error on level N, hls.js can set nextAutoLevel to N-1 for example)
21867       * forced value is valid for one fragment. upon successful frag loading at forced level,
21868       * this value will be resetted to -1 by ABR controller.
21869       */,
21870      set: function set(nextLevel) {
21871        this.abrController.nextAutoLevel = nextLevel;
21872      }
21873
21874      /**
21875       * get the datetime value relative to media.currentTime for the active level Program Date Time if present
21876       */
21877    }, {
21878      key: "playingDate",
21879      get: function get() {
21880        return this.streamController.currentProgramDateTime;
21881      }
21882    }, {
21883      key: "mainForwardBufferInfo",
21884      get: function get() {
21885        return this.streamController.getMainFwdBufferInfo();
21886      }
21887    }, {
21888      key: "maxBufferLength",
21889      get: function get() {
21890        return this.streamController.maxBufferLength;
21891      }
21892    }, {
21893      key: "allAudioTracks",
21894      get: function get() {
21895        var audioTrackController = this.audioTrackController;
21896        return audioTrackController ? audioTrackController.allAudioTracks : [];
21897      }
21898
21899      /**
21900       * Get the list of selectable audio tracks
21901       */
21902    }, {
21903      key: "audioTracks",
21904      get: function get() {
21905        var audioTrackController = this.audioTrackController;
21906        return audioTrackController ? audioTrackController.audioTracks : [];
21907      }
21908
21909      /**
21910       * index of the selected audio track (index in audio track lists)
21911       */
21912    }, {
21913      key: "audioTrack",
21914      get: function get() {
21915        var audioTrackController = this.audioTrackController;
21916        return audioTrackController ? audioTrackController.audioTrack : -1;
21917      }
21918
21919      /**
21920       * selects an audio track, based on its index in audio track lists
21921       */,
21922      set: function set(audioTrackId) {
21923        var audioTrackController = this.audioTrackController;
21924        if (audioTrackController) {
21925          audioTrackController.audioTrack = audioTrackId;
21926        }
21927      }
21928
21929      /**
21930       * get the complete list of subtitle tracks across all media groups
21931       */
21932    }, {
21933      key: "allSubtitleTracks",
21934      get: function get() {
21935        var subtitleTrackController = this.subtitleTrackController;
21936        return subtitleTrackController ? subtitleTrackController.allSubtitleTracks : [];
21937      }
21938
21939      /**
21940       * get alternate subtitle tracks list from playlist
21941       */
21942    }, {
21943      key: "subtitleTracks",
21944      get: function get() {
21945        var subtitleTrackController = this.subtitleTrackController;
21946        return subtitleTrackController ? subtitleTrackController.subtitleTracks : [];
21947      }
21948
21949      /**
21950       * index of the selected subtitle track (index in subtitle track lists)
21951       */
21952    }, {
21953      key: "subtitleTrack",
21954      get: function get() {
21955        var subtitleTrackController = this.subtitleTrackController;
21956        return subtitleTrackController ? subtitleTrackController.subtitleTrack : -1;
21957      },
21958      set:
21959      /**
21960       * select an subtitle track, based on its index in subtitle track lists
21961       */
21962      function set(subtitleTrackId) {
21963        var subtitleTrackController = this.subtitleTrackController;
21964        if (subtitleTrackController) {
21965          subtitleTrackController.subtitleTrack = subtitleTrackId;
21966        }
21967      }
21968
21969      /**
21970       * Whether subtitle display is enabled or not
21971       */
21972    }, {
21973      key: "media",
21974      get: function get() {
21975        return this._media;
21976      }
21977    }, {
21978      key: "subtitleDisplay",
21979      get: function get() {
21980        var subtitleTrackController = this.subtitleTrackController;
21981        return subtitleTrackController ? subtitleTrackController.subtitleDisplay : false;
21982      }
21983
21984      /**
21985       * Enable/disable subtitle display rendering
21986       */,
21987      set: function set(value) {
21988        var subtitleTrackController = this.subtitleTrackController;
21989        if (subtitleTrackController) {
21990          subtitleTrackController.subtitleDisplay = value;
21991        }
21992      }
21993
21994      /**
21995       * get mode for Low-Latency HLS loading
21996       */
21997    }, {
21998      key: "lowLatencyMode",
21999      get: function get() {
22000        return this.config.lowLatencyMode;
22001      }
22002
22003      /**
22004       * Enable/disable Low-Latency HLS part playlist and segment loading, and start live streams at playlist PART-HOLD-BACK rather than HOLD-BACK.
22005       */,
22006      set: function set(mode) {
22007        this.config.lowLatencyMode = mode;
22008      }
22009
22010      /**
22011       * Position (in seconds) of live sync point (ie edge of live position minus safety delay defined by ```hls.config.liveSyncDuration```)
22012       * @returns null prior to loading live Playlist
22013       */
22014    }, {
22015      key: "liveSyncPosition",
22016      get: function get() {
22017        return this.latencyController.liveSyncPosition;
22018      }
22019
22020      /**
22021       * Estimated position (in seconds) of live edge (ie edge of live playlist plus time sync playlist advanced)
22022       * @returns 0 before first playlist is loaded
22023       */
22024    }, {
22025      key: "latency",
22026      get: function get() {
22027        return this.latencyController.latency;
22028      }
22029
22030      /**
22031       * maximum distance from the edge before the player seeks forward to ```hls.liveSyncPosition```
22032       * configured using ```liveMaxLatencyDurationCount``` (multiple of target duration) or ```liveMaxLatencyDuration```
22033       * @returns 0 before first playlist is loaded
22034       */
22035    }, {
22036      key: "maxLatency",
22037      get: function get() {
22038        return this.latencyController.maxLatency;
22039      }
22040
22041      /**
22042       * target distance from the edge as calculated by the latency controller
22043       */
22044    }, {
22045      key: "targetLatency",
22046      get: function get() {
22047        return this.latencyController.targetLatency;
22048      },
22049      set: function set(latency) {
22050        this.latencyController.targetLatency = latency;
22051      }
22052
22053      /**
22054       * the rate at which the edge of the current live playlist is advancing or 1 if there is none
22055       */
22056    }, {
22057      key: "drift",
22058      get: function get() {
22059        return this.latencyController.drift;
22060      }
22061
22062      /**
22063       * set to true when startLoad is called before MANIFEST_PARSED event
22064       */
22065    }, {
22066      key: "forceStartLoad",
22067      get: function get() {
22068        return this.streamController.forceStartLoad;
22069      }
22070
22071      /**
22072       * ContentSteering pathwayPriority getter/setter
22073       */
22074    }, {
22075      key: "pathwayPriority",
22076      get: function get() {
22077        return this.levelController.pathwayPriority;
22078      },
22079      set: function set(pathwayPriority) {
22080        this.levelController.pathwayPriority = pathwayPriority;
22081      }
22082    }], [{
22083      key: "version",
22084      get:
22085      /**
22086       * Get the video-dev/hls.js package version.
22087       */
22088      function get() {
22089        return version;
22090      }
22091    }, {
22092      key: "Events",
22093      get: function get() {
22094        return Events;
22095      }
22096    }, {
22097      key: "ErrorTypes",
22098      get: function get() {
22099        return ErrorTypes;
22100      }
22101    }, {
22102      key: "ErrorDetails",
22103      get: function get() {
22104        return ErrorDetails;
22105      }
22106
22107      /**
22108       * Get the default configuration applied to new instances.
22109       */
22110    }, {
22111      key: "DefaultConfig",
22112      get: function get() {
22113        if (!Hls.defaultConfig) {
22114          return hlsDefaultConfig;
22115        }
22116        return Hls.defaultConfig;
22117      }
22118
22119      /**
22120       * Replace the default configuration applied to new instances.
22121       */,
22122      set: function set(defaultConfig) {
22123        Hls.defaultConfig = defaultConfig;
22124      }
22125    }]);
22126  }();
22127  Hls.defaultConfig = void 0;
22128
22129  return Hls;
22130
22131}));
22132})(false);
22133//# sourceMappingURL=hls.light.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.