hls.js
Version:
JavaScript HLS client using MediaSourceExtension
1,085 lines (1,015 loc) • 981 kB
JavaScript
(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())