UNPKG

hls.js

Version:

JavaScript HLS client using MediaSourceExtension

1,085 lines (1,015 loc) • 981 kB
(function __HLS_WORKER_BUNDLE__(__IN_WORKER__){ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Hls = factory()); })(this, (function () { 'use strict'; function _construct(t, e, r) { if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments); var o = [null]; o.push.apply(o, e); var p = new (t.bind.apply(t, o))(); return r && _setPrototypeOf(p, r.prototype), p; } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: false }), e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e; } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inheritsLoose(t, o) { t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o); } function _isNativeFunction(t) { try { return -1 !== Function.toString.call(t).indexOf("[native code]"); } catch (n) { return "function" == typeof t; } } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function () { return !!t; })(); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _wrapNativeSuper(t) { var r = "function" == typeof Map ? new Map() : void 0; return _wrapNativeSuper = function (t) { if (null === t || !_isNativeFunction(t)) return t; if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function"); if (void 0 !== r) { if (r.has(t)) return r.get(t); r.set(t, Wrapper); } function Wrapper() { return _construct(t, arguments, _getPrototypeOf(this).constructor); } return Wrapper.prototype = Object.create(t.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }), _setPrototypeOf(Wrapper, t); }, _wrapNativeSuper(t); } /** * Generate a random v4 UUID * * @returns A random v4 UUID * * @group Utils * * @beta */ function uuid() { try { return crypto.randomUUID(); } catch (error) { try { var url = URL.createObjectURL(new Blob()); var _uuid = url.toString(); URL.revokeObjectURL(url); return _uuid.slice(_uuid.lastIndexOf('/') + 1); } catch (error) { var dt = new Date().getTime(); var _uuid2 = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = (dt + Math.random() * 16) % 16 | 0; dt = Math.floor(dt / 16); return (c == 'x' ? r : r & 0x3 | 0x8).toString(16); }); return _uuid2; } } } function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var eventemitter3 = {exports: {}}; var hasRequiredEventemitter3; function requireEventemitter3 () { if (hasRequiredEventemitter3) return eventemitter3.exports; hasRequiredEventemitter3 = 1; (function (module) { var has = Object.prototype.hasOwnProperty , prefix = '~'; /** * Constructor to create a storage for our `EE` objects. * An `Events` instance is a plain object whose properties are event names. * * @constructor * @private */ function Events() {} // // We try to not inherit from `Object.prototype`. In some engines creating an // instance in this way is faster than calling `Object.create(null)` directly. // If `Object.create(null)` is not supported we prefix the event names with a // character to make sure that the built-in object properties are not // overridden or used as an attack vector. // if (Object.create) { Events.prototype = Object.create(null); // // This hack is needed because the `__proto__` property is still inherited in // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. // if (!new Events().__proto__) prefix = false; } /** * Representation of a single event listener. * * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} [once=false] Specify if the listener is a one-time listener. * @constructor * @private */ function EE(fn, context, once) { this.fn = fn; this.context = context; this.once = once || false; } /** * Add a listener for a given event. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} once Specify if the listener is a one-time listener. * @returns {EventEmitter} * @private */ function addListener(emitter, event, fn, context, once) { if (typeof fn !== 'function') { throw new TypeError('The listener must be a function'); } var listener = new EE(fn, context || emitter, once) , evt = prefix ? prefix + event : event; if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++; else if (!emitter._events[evt].fn) emitter._events[evt].push(listener); else emitter._events[evt] = [emitter._events[evt], listener]; return emitter; } /** * Clear event by name. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} evt The Event name. * @private */ function clearEvent(emitter, evt) { if (--emitter._eventsCount === 0) emitter._events = new Events(); else delete emitter._events[evt]; } /** * Minimal `EventEmitter` interface that is molded against the Node.js * `EventEmitter` interface. * * @constructor * @public */ function EventEmitter() { this._events = new Events(); this._eventsCount = 0; } /** * Return an array listing the events for which the emitter has registered * listeners. * * @returns {Array} * @public */ EventEmitter.prototype.eventNames = function eventNames() { var names = [] , events , name; if (this._eventsCount === 0) return names; for (name in (events = this._events)) { if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); } if (Object.getOwnPropertySymbols) { return names.concat(Object.getOwnPropertySymbols(events)); } return names; }; /** * Return the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Array} The registered listeners. * @public */ EventEmitter.prototype.listeners = function listeners(event) { var evt = prefix ? prefix + event : event , handlers = this._events[evt]; if (!handlers) return []; if (handlers.fn) return [handlers.fn]; for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) { ee[i] = handlers[i].fn; } return ee; }; /** * Return the number of listeners listening to a given event. * * @param {(String|Symbol)} event The event name. * @returns {Number} The number of listeners. * @public */ EventEmitter.prototype.listenerCount = function listenerCount(event) { var evt = prefix ? prefix + event : event , listeners = this._events[evt]; if (!listeners) return 0; if (listeners.fn) return 1; return listeners.length; }; /** * Calls each of the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Boolean} `true` if the event had listeners, else `false`. * @public */ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return false; var listeners = this._events[evt] , len = arguments.length , args , i; if (listeners.fn) { if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); switch (len) { case 1: return listeners.fn.call(listeners.context), true; case 2: return listeners.fn.call(listeners.context, a1), true; case 3: return listeners.fn.call(listeners.context, a1, a2), true; case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; } for (i = 1, args = new Array(len -1); i < len; i++) { args[i - 1] = arguments[i]; } listeners.fn.apply(listeners.context, args); } else { var length = listeners.length , j; for (i = 0; i < length; i++) { if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true); switch (len) { case 1: listeners[i].fn.call(listeners[i].context); break; case 2: listeners[i].fn.call(listeners[i].context, a1); break; case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; default: if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { args[j - 1] = arguments[j]; } listeners[i].fn.apply(listeners[i].context, args); } } } return true; }; /** * Add a listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.on = function on(event, fn, context) { return addListener(this, event, fn, context, false); }; /** * Add a one-time listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.once = function once(event, fn, context) { return addListener(this, event, fn, context, true); }; /** * Remove the listeners of a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn Only remove the listeners that match this function. * @param {*} context Only remove the listeners that have this context. * @param {Boolean} once Only remove one-time listeners. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return this; if (!fn) { clearEvent(this, evt); return this; } var listeners = this._events[evt]; if (listeners.fn) { if ( listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context) ) { clearEvent(this, evt); } } else { for (var i = 0, events = [], length = listeners.length; i < length; i++) { if ( listeners[i].fn !== fn || (once && !listeners[i].once) || (context && listeners[i].context !== context) ) { events.push(listeners[i]); } } // // Reset the array, or remove it completely if we have no more listeners. // if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; else clearEvent(this, evt); } return this; }; /** * Remove all listeners, or those of the specified event. * * @param {(String|Symbol)} [event] The event name. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { var evt; if (event) { evt = prefix ? prefix + event : event; if (this._events[evt]) clearEvent(this, evt); } else { this._events = new Events(); this._eventsCount = 0; } return this; }; // // Alias methods names because people roll like that. // EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.addListener = EventEmitter.prototype.on; // // Expose the prefix. // EventEmitter.prefixed = prefix; // // Allow `EventEmitter` to be imported as module namespace. // EventEmitter.EventEmitter = EventEmitter; // // Expose the module. // { module.exports = EventEmitter; } } (eventemitter3)); return eventemitter3.exports; } var eventemitter3Exports = requireEventemitter3(); var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports); var urlToolkit = {exports: {}}; var hasRequiredUrlToolkit; function requireUrlToolkit () { if (hasRequiredUrlToolkit) return urlToolkit.exports; hasRequiredUrlToolkit = 1; (function (module, exports) { // see https://tools.ietf.org/html/rfc1808 (function (root) { var URL_REGEX = /^(?=((?:[a-zA-Z0-9+\-.]+:)?))\1(?=((?:\/\/[^\/?#]*)?))\2(?=((?:(?:[^?#\/]*\/)*[^;?#\/]*)?))\3((?:;[^?#]*)?)(\?[^#]*)?(#[^]*)?$/; var FIRST_SEGMENT_REGEX = /^(?=([^\/?#]*))\1([^]*)$/; var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g; var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g; var URLToolkit = { // If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or // // E.g // With opts.alwaysNormalize = false (default, spec compliant) // http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g // With opts.alwaysNormalize = true (not spec compliant) // http://a.com/b/cd + /e/f/../g => http://a.com/e/g buildAbsoluteURL: function (baseURL, relativeURL, opts) { opts = opts || {}; // remove any remaining space and CRLF baseURL = baseURL.trim(); relativeURL = relativeURL.trim(); if (!relativeURL) { // 2a) If the embedded URL is entirely empty, it inherits the // entire base URL (i.e., is set equal to the base URL) // and we are done. if (!opts.alwaysNormalize) { return baseURL; } var basePartsForNormalise = URLToolkit.parseURL(baseURL); if (!basePartsForNormalise) { throw new Error('Error trying to parse base URL.'); } basePartsForNormalise.path = URLToolkit.normalizePath( basePartsForNormalise.path ); return URLToolkit.buildURLFromParts(basePartsForNormalise); } var relativeParts = URLToolkit.parseURL(relativeURL); if (!relativeParts) { throw new Error('Error trying to parse relative URL.'); } if (relativeParts.scheme) { // 2b) If the embedded URL starts with a scheme name, it is // interpreted as an absolute URL and we are done. if (!opts.alwaysNormalize) { return relativeURL; } relativeParts.path = URLToolkit.normalizePath(relativeParts.path); return URLToolkit.buildURLFromParts(relativeParts); } var baseParts = URLToolkit.parseURL(baseURL); if (!baseParts) { throw new Error('Error trying to parse base URL.'); } if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') { // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a' var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path); baseParts.netLoc = pathParts[1]; baseParts.path = pathParts[2]; } if (baseParts.netLoc && !baseParts.path) { baseParts.path = '/'; } var builtParts = { // 2c) Otherwise, the embedded URL inherits the scheme of // the base URL. scheme: baseParts.scheme, netLoc: relativeParts.netLoc, path: null, params: relativeParts.params, query: relativeParts.query, fragment: relativeParts.fragment, }; if (!relativeParts.netLoc) { // 3) If the embedded URL's <net_loc> is non-empty, we skip to // Step 7. Otherwise, the embedded URL inherits the <net_loc> // (if any) of the base URL. builtParts.netLoc = baseParts.netLoc; // 4) If the embedded URL path is preceded by a slash "/", the // path is not relative and we skip to Step 7. if (relativeParts.path[0] !== '/') { if (!relativeParts.path) { // 5) If the embedded URL path is empty (and not preceded by a // slash), then the embedded URL inherits the base URL path builtParts.path = baseParts.path; // 5a) if the embedded URL's <params> is non-empty, we skip to // step 7; otherwise, it inherits the <params> of the base // URL (if any) and if (!relativeParts.params) { builtParts.params = baseParts.params; // 5b) if the embedded URL's <query> is non-empty, we skip to // step 7; otherwise, it inherits the <query> of the base // URL (if any) and we skip to step 7. if (!relativeParts.query) { builtParts.query = baseParts.query; } } } else { // 6) The last segment of the base URL's path (anything // following the rightmost slash "/", or the entire path if no // slash is present) is removed and the embedded URL's path is // appended in its place. var baseURLPath = baseParts.path; var newPath = baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) + relativeParts.path; builtParts.path = URLToolkit.normalizePath(newPath); } } } if (builtParts.path === null) { builtParts.path = opts.alwaysNormalize ? URLToolkit.normalizePath(relativeParts.path) : relativeParts.path; } return URLToolkit.buildURLFromParts(builtParts); }, parseURL: function (url) { var parts = URL_REGEX.exec(url); if (!parts) { return null; } return { scheme: parts[1] || '', netLoc: parts[2] || '', path: parts[3] || '', params: parts[4] || '', query: parts[5] || '', fragment: parts[6] || '', }; }, normalizePath: function (path) { // The following operations are // then applied, in order, to the new path: // 6a) All occurrences of "./", where "." is a complete path // segment, are removed. // 6b) If the path ends with "." as a complete path segment, // that "." is removed. path = path.split('').reverse().join('').replace(SLASH_DOT_REGEX, ''); // 6c) All occurrences of "<segment>/../", where <segment> is a // complete path segment not equal to "..", are removed. // Removal of these path segments is performed iteratively, // removing the leftmost matching pattern on each iteration, // until no matching pattern remains. // 6d) If the path ends with "<segment>/..", where <segment> is a // complete path segment not equal to "..", that // "<segment>/.." is removed. while ( path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, '')).length ) {} return path.split('').reverse().join(''); }, buildURLFromParts: function (parts) { return ( parts.scheme + parts.netLoc + parts.path + parts.params + parts.query + parts.fragment ); }, }; module.exports = URLToolkit; })(); } (urlToolkit)); return urlToolkit.exports; } var urlToolkitExports = requireUrlToolkit(); // https://caniuse.com/mdn-javascript_builtins_number_isfinite var isFiniteNumber = Number.isFinite || function (value) { return typeof value === 'number' && isFinite(value); }; // https://caniuse.com/mdn-javascript_builtins_number_issafeinteger var isSafeInteger = Number.isSafeInteger || function (value) { return typeof value === 'number' && Math.abs(value) <= MAX_SAFE_INTEGER; }; var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; var ErrorTypes = /*#__PURE__*/function (ErrorTypes) { // Identifier for a network error (loading error / timeout ...) ErrorTypes["NETWORK_ERROR"] = "networkError"; // Identifier for a media Error (video/parsing/mediasource error) ErrorTypes["MEDIA_ERROR"] = "mediaError"; // EME (encrypted media extensions) errors ErrorTypes["KEY_SYSTEM_ERROR"] = "keySystemError"; // Identifier for a mux Error (demuxing/remuxing) ErrorTypes["MUX_ERROR"] = "muxError"; // Identifier for all other errors ErrorTypes["OTHER_ERROR"] = "otherError"; return ErrorTypes; }({}); var ErrorDetails = /*#__PURE__*/function (ErrorDetails) { ErrorDetails["KEY_SYSTEM_NO_KEYS"] = "keySystemNoKeys"; ErrorDetails["KEY_SYSTEM_NO_ACCESS"] = "keySystemNoAccess"; ErrorDetails["KEY_SYSTEM_NO_SESSION"] = "keySystemNoSession"; ErrorDetails["KEY_SYSTEM_NO_CONFIGURED_LICENSE"] = "keySystemNoConfiguredLicense"; ErrorDetails["KEY_SYSTEM_LICENSE_REQUEST_FAILED"] = "keySystemLicenseRequestFailed"; ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED"] = "keySystemServerCertificateRequestFailed"; ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_UPDATE_FAILED"] = "keySystemServerCertificateUpdateFailed"; ErrorDetails["KEY_SYSTEM_SESSION_UPDATE_FAILED"] = "keySystemSessionUpdateFailed"; ErrorDetails["KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED"] = "keySystemStatusOutputRestricted"; ErrorDetails["KEY_SYSTEM_STATUS_INTERNAL_ERROR"] = "keySystemStatusInternalError"; ErrorDetails["KEY_SYSTEM_DESTROY_MEDIA_KEYS_ERROR"] = "keySystemDestroyMediaKeysError"; ErrorDetails["KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR"] = "keySystemDestroyCloseSessionError"; ErrorDetails["KEY_SYSTEM_DESTROY_REMOVE_SESSION_ERROR"] = "keySystemDestroyRemoveSessionError"; // Identifier for a manifest load error - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["MANIFEST_LOAD_ERROR"] = "manifestLoadError"; // Identifier for a manifest load timeout - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["MANIFEST_LOAD_TIMEOUT"] = "manifestLoadTimeOut"; // Identifier for a manifest parsing error - data: { url : faulty URL, reason : error reason} ErrorDetails["MANIFEST_PARSING_ERROR"] = "manifestParsingError"; // Identifier for a manifest with only incompatible codecs error - data: { url : faulty URL, reason : error reason} ErrorDetails["MANIFEST_INCOMPATIBLE_CODECS_ERROR"] = "manifestIncompatibleCodecsError"; // Identifier for a level which contains no fragments - data: { url: faulty URL, reason: "no fragments found in level", level: index of the bad level } ErrorDetails["LEVEL_EMPTY_ERROR"] = "levelEmptyError"; // Identifier for a level load error - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["LEVEL_LOAD_ERROR"] = "levelLoadError"; // Identifier for a level load timeout - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["LEVEL_LOAD_TIMEOUT"] = "levelLoadTimeOut"; // Identifier for a level parse error - data: { url : faulty URL, error: Error, reason: error message } ErrorDetails["LEVEL_PARSING_ERROR"] = "levelParsingError"; // Identifier for a level switch error - data: { level : faulty level Id, event : error description} ErrorDetails["LEVEL_SWITCH_ERROR"] = "levelSwitchError"; // Identifier for an audio track load error - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["AUDIO_TRACK_LOAD_ERROR"] = "audioTrackLoadError"; // Identifier for an audio track load timeout - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["AUDIO_TRACK_LOAD_TIMEOUT"] = "audioTrackLoadTimeOut"; // Identifier for a subtitle track load error - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["SUBTITLE_LOAD_ERROR"] = "subtitleTrackLoadError"; // Identifier for a subtitle track load timeout - data: { url : faulty URL, response : { code: error code, text: error text }} ErrorDetails["SUBTITLE_TRACK_LOAD_TIMEOUT"] = "subtitleTrackLoadTimeOut"; // Identifier for fragment load error - data: { frag : fragment object, response : { code: error code, text: error text }} ErrorDetails["FRAG_LOAD_ERROR"] = "fragLoadError"; // Identifier for fragment load timeout error - data: { frag : fragment object} ErrorDetails["FRAG_LOAD_TIMEOUT"] = "fragLoadTimeOut"; // Identifier for a fragment decryption error event - data: {id : demuxer Id,frag: fragment object, reason : parsing error description } ErrorDetails["FRAG_DECRYPT_ERROR"] = "fragDecryptError"; // Identifier for a fragment parsing error event - data: { id : demuxer Id, reason : parsing error description } // will be renamed DEMUX_PARSING_ERROR and switched to MUX_ERROR in the next major release ErrorDetails["FRAG_PARSING_ERROR"] = "fragParsingError"; // Identifier for a fragment or part load skipped because of a GAP tag or attribute ErrorDetails["FRAG_GAP"] = "fragGap"; // Identifier for a remux alloc error event - data: { id : demuxer Id, frag : fragment object, bytes : nb of bytes on which allocation failed , reason : error text } ErrorDetails["REMUX_ALLOC_ERROR"] = "remuxAllocError"; // Identifier for decrypt key load error - data: { frag : fragment object, response : { code: error code, text: error text }} ErrorDetails["KEY_LOAD_ERROR"] = "keyLoadError"; // Identifier for decrypt key load timeout error - data: { frag : fragment object} ErrorDetails["KEY_LOAD_TIMEOUT"] = "keyLoadTimeOut"; // Triggered when an exception occurs while adding a sourceBuffer to MediaSource - data : { error : exception , mimeType : mimeType } ErrorDetails["BUFFER_ADD_CODEC_ERROR"] = "bufferAddCodecError"; // Triggered when source buffer(s) could not be created using level (manifest CODECS attribute), parsed media, or best guess codec(s) - data: { reason : error reason } ErrorDetails["BUFFER_INCOMPATIBLE_CODECS_ERROR"] = "bufferIncompatibleCodecsError"; // Identifier for a buffer append error - data: append error description ErrorDetails["BUFFER_APPEND_ERROR"] = "bufferAppendError"; // Identifier for a buffer appending error event - data: appending error description ErrorDetails["BUFFER_APPENDING_ERROR"] = "bufferAppendingError"; // Identifier for a buffer stalled error event ErrorDetails["BUFFER_STALLED_ERROR"] = "bufferStalledError"; // Identifier for a buffer full event ErrorDetails["BUFFER_FULL_ERROR"] = "bufferFullError"; // Identifier for a buffer seek over hole event ErrorDetails["BUFFER_SEEK_OVER_HOLE"] = "bufferSeekOverHole"; // Identifier for a buffer nudge on stall (playback is stuck although currentTime is in a buffered area) ErrorDetails["BUFFER_NUDGE_ON_STALL"] = "bufferNudgeOnStall"; // Identifier for a Interstitial Asset List load error - data: { url: faulty URL, response: { code: error code, text: error text } } ErrorDetails["ASSET_LIST_LOAD_ERROR"] = "assetListLoadError"; // Identifier for a Interstitial Asset List load timeout - data: { url: faulty URL, response: { code: error code, text: error text } } ErrorDetails["ASSET_LIST_LOAD_TIMEOUT"] = "assetListLoadTimeout"; // Identifier for a Interstitial Asset List parsing error - data: { url : faulty URL, reason : error reason, response : { code: error code, text: error text }} ErrorDetails["ASSET_LIST_PARSING_ERROR"] = "assetListParsingError"; // Identifier for a Interstitial Asset List parsing error - data: { url : faulty URL, reason : error reason, response : { code: error code, text: error text }} ErrorDetails["INTERSTITIAL_ASSET_ITEM_ERROR"] = "interstitialAssetItemError"; // Identifier for an internal exception happening inside hls.js while handling an event ErrorDetails["INTERNAL_EXCEPTION"] = "internalException"; // Identifier for an internal call to abort a loader ErrorDetails["INTERNAL_ABORTED"] = "aborted"; // Triggered when attachMedia fails ErrorDetails["ATTACH_MEDIA_ERROR"] = "attachMediaError"; // Uncategorized error ErrorDetails["UNKNOWN"] = "unknown"; return ErrorDetails; }({}); var Events = /*#__PURE__*/function (Events) { // Fired before MediaSource is attaching to media element Events["MEDIA_ATTACHING"] = "hlsMediaAttaching"; // Fired when MediaSource has been successfully attached to media element Events["MEDIA_ATTACHED"] = "hlsMediaAttached"; // Fired before detaching MediaSource from media element Events["MEDIA_DETACHING"] = "hlsMediaDetaching"; // Fired when MediaSource has been detached from media element Events["MEDIA_DETACHED"] = "hlsMediaDetached"; // Fired when HTMLMediaElement dispatches "ended" event, or stalls at end of VOD program Events["MEDIA_ENDED"] = "hlsMediaEnded"; // Fired after playback stall is resolved with playing, seeked, or ended event following BUFFER_STALLED_ERROR Events["STALL_RESOLVED"] = "hlsStallResolved"; // Fired when the buffer is going to be reset Events["BUFFER_RESET"] = "hlsBufferReset"; // Fired when we know about the codecs that we need buffers for to push into - data: {tracks : { container, codec, levelCodec, initSegment, metadata }} Events["BUFFER_CODECS"] = "hlsBufferCodecs"; // fired when sourcebuffers have been created - data: { tracks : tracks } Events["BUFFER_CREATED"] = "hlsBufferCreated"; // fired when we append a segment to the buffer - data: { segment: segment object } Events["BUFFER_APPENDING"] = "hlsBufferAppending"; // fired when we are done with appending a media segment to the buffer - data : { parent : segment parent that triggered BUFFER_APPENDING, pending : nb of segments waiting for appending for this segment parent} Events["BUFFER_APPENDED"] = "hlsBufferAppended"; // fired when the stream is finished and we want to notify the media buffer that there will be no more data - data: { } Events["BUFFER_EOS"] = "hlsBufferEos"; // fired when all buffers are full to the end of the program, after calling MediaSource.endOfStream() (unless restricted) Events["BUFFERED_TO_END"] = "hlsBufferedToEnd"; // fired when the media buffer should be flushed - data { startOffset, endOffset } Events["BUFFER_FLUSHING"] = "hlsBufferFlushing"; // fired when the media buffer has been flushed - data: { } Events["BUFFER_FLUSHED"] = "hlsBufferFlushed"; // fired to signal that a manifest loading starts - data: { url : manifestURL} Events["MANIFEST_LOADING"] = "hlsManifestLoading"; // fired after manifest has been loaded - data: { levels : [available quality levels], audioTracks : [ available audio tracks ], url : manifestURL, stats : LoaderStats } Events["MANIFEST_LOADED"] = "hlsManifestLoaded"; // fired after manifest has been parsed - data: { levels : [available quality levels], firstLevel : index of first quality level appearing in Manifest} Events["MANIFEST_PARSED"] = "hlsManifestParsed"; // fired when a level switch is requested - data: { level : id of new level } Events["LEVEL_SWITCHING"] = "hlsLevelSwitching"; // fired when a level switch is effective - data: { level : id of new level } Events["LEVEL_SWITCHED"] = "hlsLevelSwitched"; // fired when a level playlist loading starts - data: { url : level URL, level : id of level being loaded} Events["LEVEL_LOADING"] = "hlsLevelLoading"; // fired when a level playlist loading finishes - data: { details : levelDetails object, level : id of loaded level, stats : LoaderStats } Events["LEVEL_LOADED"] = "hlsLevelLoaded"; // fired when a level's details have been updated based on previous details, after it has been loaded - data: { details : levelDetails object, level : id of updated level } Events["LEVEL_UPDATED"] = "hlsLevelUpdated"; // fired when a level's PTS information has been updated after parsing a fragment - data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment } Events["LEVEL_PTS_UPDATED"] = "hlsLevelPtsUpdated"; // fired to notify that levels have changed after removing a level - data: { levels : [available quality levels] } Events["LEVELS_UPDATED"] = "hlsLevelsUpdated"; // fired to notify that audio track lists has been updated - data: { audioTracks : audioTracks } Events["AUDIO_TRACKS_UPDATED"] = "hlsAudioTracksUpdated"; // fired when an audio track switching is requested - data: { id : audio track id } Events["AUDIO_TRACK_SWITCHING"] = "hlsAudioTrackSwitching"; // fired when an audio track switch actually occurs - data: { id : audio track id } Events["AUDIO_TRACK_SWITCHED"] = "hlsAudioTrackSwitched"; // fired when an audio track loading starts - data: { url : audio track URL, id : audio track id } Events["AUDIO_TRACK_LOADING"] = "hlsAudioTrackLoading"; // fired when an audio track loading finishes - data: { details : levelDetails object, id : audio track id, stats : LoaderStats } Events["AUDIO_TRACK_LOADED"] = "hlsAudioTrackLoaded"; // fired when an audio tracks's details have been updated based on previous details, after it has been loaded - data: { details : levelDetails object, id : track id } Events["AUDIO_TRACK_UPDATED"] = "hlsAudioTrackUpdated"; // fired to notify that subtitle track lists has been updated - data: { subtitleTracks : subtitleTracks } Events["SUBTITLE_TRACKS_UPDATED"] = "hlsSubtitleTracksUpdated"; // fired to notify that subtitle tracks were cleared as a result of stopping the media Events["SUBTITLE_TRACKS_CLEARED"] = "hlsSubtitleTracksCleared"; // fired when an subtitle track switch occurs - data: { id : subtitle track id } Events["SUBTITLE_TRACK_SWITCH"] = "hlsSubtitleTrackSwitch"; // fired when a subtitle track loading starts - data: { url : subtitle track URL, id : subtitle track id } Events["SUBTITLE_TRACK_LOADING"] = "hlsSubtitleTrackLoading"; // fired when a subtitle track loading finishes - data: { details : levelDetails object, id : subtitle track id, stats : LoaderStats } Events["SUBTITLE_TRACK_LOADED"] = "hlsSubtitleTrackLoaded"; // fired when a subtitle racks's details have been updated based on previous details, after it has been loaded - data: { details : levelDetails object, id : track id } Events["SUBTITLE_TRACK_UPDATED"] = "hlsSubtitleTrackUpdated"; // fired when a subtitle fragment has been processed - data: { success : boolean, frag : the processed frag } Events["SUBTITLE_FRAG_PROCESSED"] = "hlsSubtitleFragProcessed"; // fired when a set of VTTCues to be managed externally has been parsed - data: { type: string, track: string, cues: [ VTTCue ] } Events["CUES_PARSED"] = "hlsCuesParsed"; // fired when a text track to be managed externally is found - data: { tracks: [ { label: string, kind: string, default: boolean } ] } Events["NON_NATIVE_TEXT_TRACKS_FOUND"] = "hlsNonNativeTextTracksFound"; // fired when the first timestamp is found - data: { id : demuxer id, initPTS: initPTS, timescale: timescale, frag : fragment object } Events["INIT_PTS_FOUND"] = "hlsInitPtsFound"; // fired when a fragment loading starts - data: { frag : fragment object } Events["FRAG_LOADING"] = "hlsFragLoading"; // fired when a fragment loading is progressing - data: { frag : fragment object, { trequest, tfirst, loaded } } // FRAG_LOAD_PROGRESS = 'hlsFragLoadProgress', // Identifier for fragment load aborting for emergency switch down - data: { frag : fragment object } Events["FRAG_LOAD_EMERGENCY_ABORTED"] = "hlsFragLoadEmergencyAborted"; // fired when a fragment loading is completed - data: { frag : fragment object, payload : fragment payload, stats : LoaderStats } Events["FRAG_LOADED"] = "hlsFragLoaded"; // fired when a fragment has finished decrypting - data: { id : demuxer id, frag: fragment object, payload : fragment payload, stats : { tstart, tdecrypt } } Events["FRAG_DECRYPTED"] = "hlsFragDecrypted"; // fired when Init Segment has been extracted from fragment - data: { id : demuxer id, frag: fragment object, moov : moov MP4 box, codecs : codecs found while parsing fragment } Events["FRAG_PARSING_INIT_SEGMENT"] = "hlsFragParsingInitSegment"; // fired when parsing sei text is completed - data: { id : demuxer id, frag: fragment object, samples : [ sei samples pes ] } Events["FRAG_PARSING_USERDATA"] = "hlsFragParsingUserdata"; // fired when parsing id3 is completed - data: { id : demuxer id, frag: fragment object, samples : [ id3 samples pes ] } Events["FRAG_PARSING_METADATA"] = "hlsFragParsingMetadata"; // fired when data have been extracted from fragment - data: { id : demuxer id, frag: fragment object, data1 : moof MP4 box or TS fragments, data2 : mdat MP4 box or null} // FRAG_PARSING_DATA = 'hlsFragParsingData', // fired when fragment parsing is completed - data: { id : demuxer id, frag: fragment object } Events["FRAG_PARSED"] = "hlsFragParsed"; // fired when fragment remuxed MP4 boxes have all been appended into SourceBuffer - data: { id : demuxer id, frag : fragment object, stats : LoaderStats } Events["FRAG_BUFFERED"] = "hlsFragBuffered"; // fired when fragment matching with current media position is changing - data : { id : demuxer id, frag : fragment object } Events["FRAG_CHANGED"] = "hlsFragChanged"; // Identifier for a FPS drop event - data: { currentDropped, currentDecoded, totalDroppedFrames } Events["FPS_DROP"] = "hlsFpsDrop"; // triggered when FPS drop triggers auto level capping - data: { level, droppedLevel } Events["FPS_DROP_LEVEL_CAPPING"] = "hlsFpsDropLevelCapping"; // triggered when maxAutoLevel changes - data { autoLevelCapping, levels, maxAutoLevel, minAutoLevel, maxHdcpLevel } Events["MAX_AUTO_LEVEL_UPDATED"] = "hlsMaxAutoLevelUpdated"; // Identifier for an error event - data: { type : error type, details : error details, fatal : if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data } Events["ERROR"] = "hlsError"; // fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example - data: { } Events["DESTROYING"] = "hlsDestroying"; // fired when a decrypt key loading starts - data: { frag : fragment object } Events["KEY_LOADING"] = "hlsKeyLoading"; // fired when a decrypt key loading is completed - data: { frag : fragment object, keyInfo : KeyLoaderInfo } Events["KEY_LOADED"] = "hlsKeyLoaded"; // deprecated; please use BACK_BUFFER_REACHED - data : { bufferEnd: number } Events["LIVE_BACK_BUFFER_REACHED"] = "hlsLiveBackBufferReached"; // fired when the back buffer is reached as defined by the backBufferLength config option - data : { bufferEnd: number } Events["BACK_BUFFER_REACHED"] = "hlsBackBufferReached"; // fired after steering manifest has been loaded - data: { steeringManifest: SteeringManifest object, url: steering manifest URL } Events["STEERING_MANIFEST_LOADED"] = "hlsSteeringManifestLoaded"; // fired when asset list has begun loading Events["ASSET_LIST_LOADING"] = "hlsAssetListLoading"; // fired when a valid asset list is loaded Events["ASSET_LIST_LOADED"] = "hlsAssetListLoaded"; // fired when the list of Interstitial Events and Interstitial Schedule is updated Events["INTERSTITIALS_UPDATED"] = "hlsInterstitialsUpdated"; // fired when the buffer reaches an Interstitial Schedule boundary (both Primary segments and Interstitial Assets) Events["INTERSTITIALS_BUFFERED_TO_BOUNDARY"] = "hlsInterstitialsBufferedToBoundary"; // fired when a player instance for an Interstitial Asset has been created Events["INTERSTITIAL_ASSET_PLAYER_CREATED"] = "hlsInterstitialAssetPlayerCreated"; // Interstitial playback started Events["INTERSTITIAL_STARTED"] = "hlsInterstitialStarted"; // InterstitialAsset playback started Events["INTERSTITIAL_ASSET_STARTED"] = "hlsInterstitialAssetStarted"; // InterstitialAsset playback ended Events["INTERSTITIAL_ASSET_ENDED"] = "hlsInterstitialAssetEnded"; // InterstitialAsset playback errored Events["INTERSTITIAL_ASSET_ERROR"] = "hlsInterstitialAssetError"; // Interstitial playback ended Events["INTERSTITIAL_ENDED"] = "hlsInterstitialEnded"; // Interstitial schedule resumed primary playback Events["INTERSTITIALS_PRIMARY_RESUMED"] = "hlsInterstitialsPrimaryResumed"; // Interstitial players dispatch this event when playout limit is reached Events["PLAYOUT_LIMIT_REACHED"] = "hlsPlayoutLimitReached"; // Event DateRange cue "enter" event dispatched Events["EVENT_CUE_ENTER"] = "hlsEventCueEnter"; return Events; }({}); /** * Defines each Event type and payload by Event name. Used in {@link hls.js#HlsEventEmitter} to strongly type the event listener API. */ var PlaylistContextType = { MANIFEST: "manifest", LEVEL: "level", AUDIO_TRACK: "audioTrack", SUBTITLE_TRACK: "subtitleTrack" }; var PlaylistLevelType = { MAIN: "main", AUDIO: "audio", SUBTITLE: "subtitle" }; /* * compute an Exponential Weighted moving average * - https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average * - heavily inspired from shaka-player */ var EWMA = /*#__PURE__*/function () { // About half of the estimated value will be from the last |halfLife| samples by weight. function EWMA(halfLife, estimate, weight) { if (estimate === void 0) { estimate = 0; } if (weight === void 0) { weight = 0; } this.halfLife = void 0; this.alpha_ = void 0; this.estimate_ = void 0; this.totalWeight_ = void 0; this.halfLife = halfLife; // Larger values of alpha expire historical data more slowly. this.alpha_ = halfLife ? Math.exp(Math.log(0.5) / halfLife) : 0; this.estimate_ = estimate; this.totalWeight_ = weight; } var _proto = EWMA.prototype; _proto.sample = function sample(weight, value) { var adjAlpha = Math.pow(this.alpha_, weight); this.estimate_ = value * (1 - adjAlpha) + adjAlpha * this.estimate_; this.totalWeight_ += weight; }; _proto.getTotalWeight = function getTotalWeight() { return this.totalWeight_; }; _proto.getEstimate = function getEstimate() { if (this.alpha_) { var zeroFactor = 1 - Math.pow(this.alpha_, this.totalWeight_); if (zeroFactor) { return this.estimate_ / zeroFactor; } } return this.estimate_; }; return EWMA; }(); var EwmaBandWidthEstimator = /*#__PURE__*/function () { function EwmaBandWidthEstimator(slow, fast, defaultEstimate, defaultTTFB) { if (defaultTTFB === void 0) { defaultTTFB = 100; } this.defaultEstimate_ = void 0; this.minWeight_ = void 0; this.minDelayMs_ = void 0; this.slow_ = void 0; this.fast_ = void 0; this.defaultTTFB_ = void 0; this.ttfb_ = void 0; this.defaultEstimate_ = defaultEstimate; this.minWeight_ = 0.001; this.minDelayMs_ = 50; this.slow_ = new EWMA(slow); this.fast_ = new EWMA(fast); this.defaultTTFB_ = defaultTTFB; this.ttfb_ = new EWMA(slow); } var _proto = EwmaBandWidthEstimator.prototype; _proto.update = function update(slow, fast) { var slow_ = this.slow_, fast_ = this.fast_, ttfb_ = this.ttfb_; if (slow_.halfLife !== slow) { this.slow_ = new EWMA(slow, slow_.getEstimate(), slow_.getTotalWeight()); } if (fast_.halfLife !== fast) { this.fast_ = new EWMA(fast, fast_.getEstimate(), fast_.getTotalWeight()); } if (ttfb_.halfLife !== slow) { this.ttfb_ = new EWMA(slow, ttfb_.getEstimate(), ttfb_.getTotalWeight()); } }; _proto.sample = function sample(durationMs, numBytes) { durationMs = Math.max(durationMs, this.minDelayMs_); var numBits = 8 * numBytes; // weight is duration in seconds var durationS = durationMs / 1000; // value is bandwidth in bits/s var bandwidthInBps = numBits / durationS; this.fast_.sample(durationS, bandwidthInBps); this.slow_.sample(durationS, bandwidthInBps); }; _proto.sampleTTFB = function sampleTTFB(ttfb) { // weight is frequency curve applied to TTFB in seconds // (longer times have less weight with expected input under 1 second) var seconds = ttfb / 1000; var weight = Math.sqrt(2) * Math.exp(-Math.pow(seconds, 2) / 2); this.ttfb_.sample(weight, Math.max(ttfb, 5)); }; _proto.canEstimate = function canEstimate() { return this.fast_.getTotalWeight() >= this.minWeight_; }; _proto.getEstimate = function getEstimate() { if (this.canEstimate()) { // console.log('slow estimate:'+ Math.round(this.slow_.getEstimate())); // console.log('fast estimate:'+ Math.round(this.fast_.getEstimate())