UNPKG

playable

Version:

Video player based on HTML5Video

299 lines 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var hls_light_js_1 = (0, tslib_1.__importDefault)(require("hls.js/dist/hls.light.js")); var video_data_1 = require("../utils/video-data"); var environment_detection_1 = require("../utils/environment-detection"); var device_detection_1 = require("../utils/device-detection"); var constants_1 = require("../constants"); var LIVE_SYNC_DURATION = 4; var LIVE_SYNC_DURATION_DELTA = 5; var DEFAULT_HLS_CONFIG = { abrEwmaDefaultEstimate: 5000 * 1000, liveSyncDuration: LIVE_SYNC_DURATION, nudgeMaxRetry: 40, // can be removed with hls v1.5.0 https://github.com/video-dev/hls.js/issues/5904#issuecomment-1762365377 }; var NETWORK_ERROR_RECOVER_TIMEOUT = 1000; var MEDIA_ERROR_RECOVER_TIMEOUT = 1000; var HlsAdapter = /** @class */ (function () { function HlsAdapter(eventEmitter) { this.eventEmitter = eventEmitter; this.hls = null; this.videoElement = null; this.mediaStream = null; this._isDynamicContent = false; this._isDynamicContentEnded = null; this._bindCallbacks(); } HlsAdapter.isSupported = function () { return environment_detection_1.NativeEnvironmentSupport.MSE && hls_light_js_1.default.isSupported(); }; HlsAdapter.prototype._bindCallbacks = function () { this._attachOnPlay = this._attachOnPlay.bind(this); this._broadcastError = this._broadcastError.bind(this); this._onEndOfStream = this._onEndOfStream.bind(this); this._onLevelUpdated = this._onLevelUpdated.bind(this); }; Object.defineProperty(HlsAdapter.prototype, "currentUrl", { get: function () { return this.mediaStream.url; }, enumerable: false, configurable: true }); Object.defineProperty(HlsAdapter.prototype, "syncWithLiveTime", { get: function () { if (!this.isDynamicContent) { return; } return (this.hls.liveSyncPosition || this.videoElement.duration - LIVE_SYNC_DURATION); }, enumerable: false, configurable: true }); Object.defineProperty(HlsAdapter.prototype, "isDynamicContent", { get: function () { return this._isDynamicContent; }, enumerable: false, configurable: true }); Object.defineProperty(HlsAdapter.prototype, "isDynamicContentEnded", { get: function () { return this._isDynamicContentEnded; }, enumerable: false, configurable: true }); Object.defineProperty(HlsAdapter.prototype, "isSyncWithLive", { get: function () { if (!this.isDynamicContent || this.isDynamicContentEnded) { return false; } return (this.videoElement.currentTime > this.syncWithLiveTime - LIVE_SYNC_DURATION_DELTA); }, enumerable: false, configurable: true }); Object.defineProperty(HlsAdapter.prototype, "isSeekAvailable", { get: function () { if (this.isDynamicContent && this.hls.levels) { var level = this.hls.levels[this.hls.firstLevel]; if (!level.details) { return false; } var type = level.details.type || ''; return type.trim() === 'EVENT'; } return true; }, enumerable: false, configurable: true }); Object.defineProperty(HlsAdapter.prototype, "mediaStreamDeliveryPriority", { get: function () { return (0, device_detection_1.isDesktopSafari)() || (0, device_detection_1.isAndroid)() ? constants_1.MediaStreamDeliveryPriority.FORCED : constants_1.MediaStreamDeliveryPriority.ADAPTIVE_VIA_MSE; }, enumerable: false, configurable: true }); Object.defineProperty(HlsAdapter.prototype, "debugInfo", { get: function () { var bitrates; var currentTime = 0; var currentBitrate = null; var nearestBufferSegInfo = null; var overallBufferLength = null; var bwEstimate = 0; var _a = this.hls, streamController = _a.streamController, levelController = _a.levelController; if (levelController) { bitrates = levelController.levels.map(function (level) { return level.bitrate; }); if (bitrates) { currentBitrate = bitrates[levelController.level]; } } if (streamController) { currentTime = streamController.lastCurrentTime; if (streamController.mediaBuffer) { overallBufferLength = (0, video_data_1.geOverallBufferLength)(streamController.mediaBuffer.buffered); nearestBufferSegInfo = (0, video_data_1.getNearestBufferSegmentInfo)(streamController.mediaBuffer.buffered, currentTime); } if (streamController.stats) { bwEstimate = streamController.stats.bwEstimate; } } return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, this.mediaStream), { bwEstimate: bwEstimate, deliveryPriority: this.mediaStreamDeliveryPriority, bitrates: bitrates, currentBitrate: currentBitrate, overallBufferLength: overallBufferLength, nearestBufferSegInfo: nearestBufferSegInfo }); }, enumerable: false, configurable: true }); HlsAdapter.prototype.canPlay = function (mediaType) { return mediaType === constants_1.MediaStreamType.HLS; }; HlsAdapter.prototype.setMediaStreams = function (mediaStreams) { if (mediaStreams.length === 1) { this.mediaStream = mediaStreams[0]; } else { throw new Error("Can only handle a single HLS stream. Received ".concat(mediaStreams.length, " streams.")); } }; HlsAdapter.prototype._logError = function (error, errorEvent) { this.eventEmitter.emitAsync(constants_1.VideoEvent.ERROR, { errorType: error, streamType: constants_1.MediaStreamType.HLS, streamProvider: 'hls.js', errorInstance: errorEvent, }); }; HlsAdapter.prototype._broadcastError = function (_error, data) { // TODO: Investigate why this callback is called after hls is destroyed if (!this.hls) { return; } var ErrorTypes = hls_light_js_1.default.ErrorTypes, ErrorDetails = hls_light_js_1.default.ErrorDetails; if (data.type === ErrorTypes.NETWORK_ERROR) { switch (data.details) { case ErrorDetails.MANIFEST_LOAD_ERROR: this._logError(constants_1.Error.MANIFEST_LOAD, data); break; case ErrorDetails.MANIFEST_LOAD_TIMEOUT: this._logError(constants_1.Error.MANIFEST_LOAD, data); break; case ErrorDetails.MANIFEST_PARSING_ERROR: this._logError(constants_1.Error.MANIFEST_PARSE, data); break; case ErrorDetails.LEVEL_LOAD_ERROR: this._logError(constants_1.Error.LEVEL_LOAD, data); break; case ErrorDetails.LEVEL_LOAD_TIMEOUT: this._logError(constants_1.Error.LEVEL_LOAD, data); break; case ErrorDetails.AUDIO_TRACK_LOAD_ERROR: this._logError(constants_1.Error.CONTENT_LOAD, data); break; case ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT: this._logError(constants_1.Error.CONTENT_LOAD, data); break; case ErrorDetails.FRAG_LOAD_ERROR: this._logError(constants_1.Error.CONTENT_LOAD, data); break; case ErrorDetails.FRAG_LOAD_TIMEOUT: this._logError(constants_1.Error.CONTENT_LOAD, data); break; default: this._logError(constants_1.Error.UNKNOWN, data); break; } if (data.fatal) { this._tryRecoverNetworkError(); } } else if (data.type === ErrorTypes.MEDIA_ERROR) { // NOTE: when error is BUFFER_STALLED_ERROR // video play successfully without recovering // while recover breaks video playback if (data.fatal && data.details !== ErrorDetails.BUFFER_STALLED_ERROR) { this._tryRecoverMediaError(); } switch (data.details) { case ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR: this._logError(constants_1.Error.MANIFEST_INCOMPATIBLE, data); break; case ErrorDetails.FRAG_PARSING_ERROR: this._logError(constants_1.Error.CONTENT_PARSE, data); break; default: this._logError(constants_1.Error.MEDIA, data); break; } } else { this._logError(constants_1.Error.UNKNOWN, data); } }; HlsAdapter.prototype._tryRecoverMediaError = function () { var _this = this; if (!this._mediaRecoverTimeout) { this.hls.recoverMediaError(); this._mediaRecoverTimeout = window.setTimeout(function () { _this._mediaRecoverTimeout = null; }, MEDIA_ERROR_RECOVER_TIMEOUT); } }; HlsAdapter.prototype._tryRecoverNetworkError = function () { var _this = this; if (!this._networkRecoverTimeout) { this.hls.startLoad(); this._networkRecoverTimeout = window.setTimeout(function () { _this._networkRecoverTimeout = null; }, NETWORK_ERROR_RECOVER_TIMEOUT); } }; HlsAdapter.prototype._attachOnPlay = function () { if (!this.videoElement) { return; } this.hls.startLoad(); this.videoElement.removeEventListener('play', this._attachOnPlay); }; HlsAdapter.prototype._onLevelUpdated = function (_eventName, _a) { var details = _a.details; this._isDynamicContent = details.live; this._isDynamicContentEnded = details.live ? false : null; this.hls.off(hls_light_js_1.default.Events.LEVEL_UPDATED, this._onLevelUpdated); }; HlsAdapter.prototype._onEndOfStream = function () { if (this._isDynamicContent) { this._isDynamicContentEnded = true; this.eventEmitter.emitAsync(constants_1.VideoEvent.DYNAMIC_CONTENT_ENDED); } }; HlsAdapter.prototype.attach = function (videoElement) { if (!this.mediaStream) { return; } var config = (0, tslib_1.__assign)({}, HlsAdapter.DEFAULT_HLS_CONFIG); this.videoElement = videoElement; if (this.videoElement.preload === 'none') { config.autoStartLoad = false; this.videoElement.addEventListener('play', this._attachOnPlay); } this.hls = new hls_light_js_1.default(config); this.hls.on(hls_light_js_1.default.Events.ERROR, this._broadcastError); this.hls.on(hls_light_js_1.default.Events.LEVEL_UPDATED, this._onLevelUpdated); this.hls.on(hls_light_js_1.default.Events.BUFFER_EOS, this._onEndOfStream); this.hls.loadSource(this.mediaStream.url); this.hls.attachMedia(this.videoElement); this._isAttached = true; }; HlsAdapter.prototype.detach = function () { if (!this._isAttached) { return; } if (this._networkRecoverTimeout) { window.clearTimeout(this._networkRecoverTimeout); this._networkRecoverTimeout = null; } if (this._mediaRecoverTimeout) { window.clearTimeout(this._mediaRecoverTimeout); this._mediaRecoverTimeout = null; } this.hls.off(hls_light_js_1.default.Events.ERROR, this._broadcastError); this.hls.off(hls_light_js_1.default.Events.BUFFER_EOS, this._onEndOfStream); this.hls.off(hls_light_js_1.default.Events.LEVEL_UPDATED, this._onLevelUpdated); this.hls.destroy(); this.hls = null; this.videoElement.removeEventListener('play', this._attachOnPlay); this.videoElement.removeAttribute('src'); this.videoElement = null; }; HlsAdapter.DEFAULT_HLS_CONFIG = DEFAULT_HLS_CONFIG; return HlsAdapter; }()); exports.default = HlsAdapter; //# sourceMappingURL=hls.js.map