From 03ae3c819096640cd378ddc2b5345b05826e4e97 Mon Sep 17 00:00:00 2001 From: Daniel Silhavy Date: Fri, 11 Dec 2020 13:14:53 +0100 Subject: [PATCH] Add dist files for version 3.2.0 --- dist/dash.all.debug.js | 5000 +++++++++++++++++++++------- dist/dash.all.debug.js.map | 154 +- dist/dash.all.min.js | 4 +- dist/dash.all.min.js.map | 2 +- dist/dash.mediaplayer.debug.js | 4957 ++++++++++++++++++++------- dist/dash.mediaplayer.debug.js.map | 136 +- dist/dash.mediaplayer.min.js | 4 +- dist/dash.mediaplayer.min.js.map | 2 +- dist/dash.mss.debug.js | 61 +- dist/dash.mss.min.js | 4 +- dist/dash.protection.debug.js | 22 +- dist/dash.protection.debug.js.map | 10 +- dist/dash.protection.min.js | 4 +- dist/dash.protection.min.js.map | 2 +- dist/dash.reporting.debug.js | 164 +- dist/dash.reporting.debug.js.map | 18 +- dist/dash.reporting.min.js | 4 +- dist/dash.reporting.min.js.map | 2 +- 18 files changed, 8055 insertions(+), 2495 deletions(-) diff --git a/dist/dash.all.debug.js b/dist/dash.all.debug.js index 43bf19daee..836da5d537 100644 --- a/dist/dash.all.debug.js +++ b/dist/dash.all.debug.js @@ -15526,6 +15526,7 @@ function Debug(config) { function setLogTimestampVisible(value) { showLogTimestamp = value; } + /** * Prepends the callee object name, and media type if available, to each log message. * @param {boolean} value Set to true if you want to see the callee object name and media type in each log message. @@ -15611,7 +15612,9 @@ function Debug(config) { } // send log event regardless of log level - eventBus.trigger(_eventsEvents2['default'].LOG, { message: message, level: level }); + if (settings && settings.get().debug.dispatchEvent) { + eventBus.trigger(_eventsEvents2['default'].LOG, { message: message, level: level }); + } } instance = { @@ -15681,6 +15684,8 @@ var _FactoryMaker = _dereq_(47); var _FactoryMaker2 = _interopRequireDefault(_FactoryMaker); +var _streamingMediaPlayerEvents = _dereq_(101); + var EVENT_PRIORITY_LOW = 0; var EVENT_PRIORITY_HIGH = 5000; @@ -15689,7 +15694,7 @@ function EventBus() { var handlers = {}; function on(type, listener, scope) { - var priority = arguments.length <= 3 || arguments[3] === undefined ? EVENT_PRIORITY_LOW : arguments[3]; + var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; if (!type) { throw new Error('event type cannot be null or undefined'); @@ -15698,6 +15703,8 @@ function EventBus() { throw new Error('listener must be a function: ' + listener); } + var priority = options.priority || EVENT_PRIORITY_LOW; + if (getHandlerIdx(type, listener, scope) >= 0) return; handlers[type] = handlers[type] || []; @@ -15708,6 +15715,16 @@ function EventBus() { priority: priority }; + if (scope && scope.getStreamId) { + handler.streamId = scope.getStreamId(); + } + if (scope && scope.getType) { + handler.mediaType = scope.getType(); + } + if (options && options.mode) { + handler.mode = options.mode; + } + var inserted = handlers[type].some(function (item, idx) { if (item && priority > item.priority) { handlers[type].splice(idx, 0, handler); @@ -15727,7 +15744,10 @@ function EventBus() { handlers[type][idx] = null; } - function trigger(type, payload) { + function trigger(type) { + var payload = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + var filters = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; + if (!type || !handlers[type]) return; payload = payload || {}; @@ -15736,10 +15756,29 @@ function EventBus() { payload.type = type; - handlers[type] = handlers[type].filter(function (item) { - return item; - }); - handlers[type].forEach(function (handler) { + if (filters.streamId) { + payload.streamId = filters.streamId; + } + if (filters.mediaType) { + payload.mediaType = filters.mediaType; + } + + handlers[type].filter(function (handler) { + if (!handler) { + return false; + } + if (filters.streamId && handler.streamId && handler.streamId !== filters.streamId) { + return false; + } + if (filters.mediaType && handler.mediaType && handler.mediaType !== filters.mediaType) { + return false; + } + // This is used for dispatching DASH events. By default we use the onStart mode. Consequently we filter everything that has a non matching mode and the onReceive events for handlers that did not specify a mode. + if (filters.mode && handler.mode && handler.mode !== filters.mode || !handler.mode && filters.mode && filters.mode === _streamingMediaPlayerEvents.EVENT_MODE_ON_RECEIVE) { + return false; + } + return true; + }).forEach(function (handler) { return handler && handler.callback.call(handler.scope, payload); }); } @@ -15781,7 +15820,7 @@ _FactoryMaker2['default'].updateSingletonFactory(EventBus.__dashjs_factory_name, exports['default'] = factory; module.exports = exports['default']; -},{"47":47}],47:[function(_dereq_,module,exports){ +},{"101":101,"47":47}],47:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -15883,6 +15922,19 @@ var FactoryMaker = (function () { }); } + /** + * Use this method to remove all singleton instances associated with a particular context. + * + * @param {Object} context + * @memberof module:FactoryMaker + * @instance + */ + function deleteSingletonInstances(context) { + singletonContexts = singletonContexts.filter(function (x) { + return x.context !== context; + }); + } + /*------------------------------------------------------------------------------------------*/ // Factories storage Management @@ -16030,6 +16082,7 @@ var FactoryMaker = (function () { extend: extend, getSingletonInstance: getSingletonInstance, setSingletonInstance: setSingletonInstance, + deleteSingletonInstances: deleteSingletonInstances, getSingletonFactory: getSingletonFactory, getSingletonFactoryByName: getSingletonFactoryByName, updateSingletonFactory: updateSingletonFactory, @@ -16101,7 +16154,7 @@ var _streamingConstantsConstants = _dereq_(108); var _streamingConstantsConstants2 = _interopRequireDefault(_streamingConstantsConstants); -var _streamingVoMetricsHTTPRequest = _dereq_(242); +var _streamingVoMetricsHTTPRequest = _dereq_(248); /** @module Settings * @description Define the configuration parameters of Dash.js MediaPlayer. @@ -16117,7 +16170,8 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * // Full settings object * settings = { * debug: { - * logLevel: Debug.LOG_LEVEL_WARNING + * logLevel: Debug.LOG_LEVEL_WARNING, + * dispatchEvent: false * }, * streaming: { * metricsMaxListDepth: 1000, @@ -16127,6 +16181,8 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * scheduleWhilePaused: true, * fastSwitchEnabled: false, * flushBufferAtTrackSwitch: false, + * calcSegmentAvailabilityRangeFromTimeline: false, + * reuseExistingSourceBuffers: true, * bufferPruningInterval: 10, * bufferToKeep: 20, * jumpGaps: true, @@ -16143,12 +16199,19 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * useSuggestedPresentationDelay: true, * useAppendWindow: true, * manifestUpdateRetryInterval: 100, - * liveCatchUpMinDrift: 0.02, - * liveCatchUpMaxDrift: 0, - * liveCatchUpPlaybackRate: 0.5, + * liveCatchup: { + * minDrift: 0.02, + * maxDrift: 0, + * playbackRate: 0.5, + * latencyThreshold: NaN, + * playbackBufferMin: NaN, + * enabled: false, + * mode: Constants.LIVE_CATCHUP_MODE_DEFAULT + * }, * lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, * lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, * cacheLoadThresholds: { video: 50, audio: 5 }, + * fragmentRequestTimeout: 0, * retryIntervals: { * MPD: 500, * XLinkExpansion: 500, @@ -16183,7 +16246,8 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * maxRepresentationRatio: { audio: 1, video: 1 }, * initialBitrate: { audio: -1, video: -1 }, * initialRepresentationRatio: { audio: -1, video: -1 }, - * autoSwitchBitrate: { audio: true, video: true } + * autoSwitchBitrate: { audio: true, video: true }, + * fetchThroughputCalculationMode: Constants.ABR_FETCH_THROUGHPUT_CALCULATION_DOWNLOADED_DATA * }, * cmcd: { * enabled: false, @@ -16220,6 +16284,8 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); *
  • dashjs.Debug.LOG_LEVEL_DEBUG
    * Log debug messages. * + * @property {boolean} [dispatchEvent=false] + * Enable to trigger a Events.LOG event whenever log output is generated. Note this will be dispatched regardless of log level */ /** @@ -16241,7 +16307,6 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * Standard ABR throughput rules multiply the throughput by this value. It should be between 0 and 1, * with lower values giving less rebuffering (but also lower quality). * @property {boolean} [useDefaultABRRules=true] Should the default ABR rules be used, or the custom ones added. - * @property {boolean} [useBufferOccupancyABR=false] Whether to use the BOLA abr rule. * @property {boolean} [useDeadTimeLatency=true] * If true, only the download portion will be considered part of the download bitrate * and latency will be regarded as static. If false, the reciprocal of the whole @@ -16265,6 +16330,9 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * @property {module:Settings~AudioVideoSettings} [initialBitrate={audio: -1, video: -1}] Explicitly set the starting bitrate for audio or video * @property {module:Settings~AudioVideoSettings} [initialRepresentationRatio={audio: -1, video: -1}] Explicitly set the initial representation ratio. If initalBitrate is specified, this is ignored. * @property {module:Settings~AudioVideoSettings} [autoSwitchBitrate={audio: true, video: true}] Indicates whether the player should enable ABR algorithms to switch the bitrate. + * + * @property {boolean} [fetchThroughputCalculationMode=Constants.ABR_FETCH_THROUGHPUT_CALCULATION_DOWNLOADED_DATA] + * Algorithm to determine the throughput in case the Fetch API is used for low latency streaming. For details please check the samples section and FetchLoader.js */ /** @@ -16302,11 +16370,12 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * fragment may be appended in the same range as the playhead or even in the past, in IE11 it may cause a stutter * or stall in playback. * @property {boolean} [flushBufferAtTrackSwitch=false] - * When enabled, after a track switch and in case buffer is being replaced (see MEdiaPlayer.setTrackSwitchModeFor(MediaController.TRACK_SWITCH_MODE_ALWAYS_REPLACE)), + * When enabled, after a track switch and in case buffer is being replaced (see MEdiaPlayer.setTrackSwitchModeFor(Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE)), * the video element is flushed (seek at current playback time) once a segment of the new track is appended in buffer in order to force video decoder to play new track. * This can be required on some devices like GoogleCast devices to make track switching functional. Otherwise track switching will be effective only once after previous * buffered track is fully consumed. - * @property {boolean} [calcSegmentAvailabilityRangeFromTimeline=true] Enable calculation of the DVR window for SegmentTimeline manifests based on the entries in + * @property {boolean} [calcSegmentAvailabilityRangeFromTimeline=false] Enable calculation of the DVR window for SegmentTimeline manifests based on the entries in + * @property {boolean} [reuseExistingSourceBuffers=true] Enable reuse of existing MediaSource Sourcebuffers during period transition * @property {number} [bufferPruningInterval=10] The interval of pruning buffer in sconds. * @property {number} [bufferToKeep=20] * This value influences the buffer pruning logic. @@ -16347,42 +16416,8 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * For live streams, set the interval-frequency in milliseconds at which * dash.js will check if the current manifest is still processed before * downloading the next manifest once the minimumUpdatePeriod time has - * @property {number} [liveCatchUpMinDrift=0.02] - * Use this method to set the minimum latency deviation allowed before activating catch-up mechanism. In low latency mode, - * when the difference between the measured latency and the target one, - * as an absolute number, is higher than the one sets with this method, then dash.js increases/decreases - * playback rate until target latency is reached. - * - * LowLatencyMinDrift should be provided in seconds, and it uses values between 0.0 and 0.5. - * - * Note: Catch-up mechanism is only applied when playing low latency live streams. - * @property {number} [liveCatchUpMaxDrift=0] - * Use this method to set the maximum latency deviation allowed before dash.js to do a seeking to live position. In low latency mode, - * when the difference between the measured latency and the target one, - * as an absolute number, is higher than the one sets with this method, then dash.js does a seek to live edge position minus - * the target live delay. - * - * LowLatencyMaxDriftBeforeSeeking should be provided in seconds. If 0, then seeking operations won't be used for - * fixing latency deviations. - * - * Note: Catch-up mechanism is only applied when playing low latency live streams. - * @property {number} [liveCatchUpPlaybackRate=0.5] - * Use this parameter to set the maximum catch up rate, as a percentage, for low latency live streams. In low latency mode, - * when measured latency is higher/lower than the target one, - * dash.js increases/decreases playback rate respectively up to (+/-) the percentage defined with this method until target is reached. - * - * Valid values for catch up rate are in range 0-0.5 (0-50%). Set it to 0 to turn off live catch up feature. - * - * Note: Catch-up mechanism is only applied when playing low latency live streams. - * @property {number} [liveCatchupLatencyThreshold=NaN] - * Use this parameter to set the maximum threshold for which live catch up is applied. For instance, if this value is set to 8 seconds, - * then live catchup is only applied if the current live latency is equal or below 8 seconds. The reason behind this parameter is to avoid an increase - * of the playback rate if the user seeks within the DVR window. - * - * If no value is specified this will be twice the maximum live delay. The maximum live delay is either specified in the manifest as part of a ServiceDescriptor or calculated the following: - * maximumLiveDelay = targetDelay + liveCatchupMinDrift - * - * Note: Catch-up mechanism is only applied when playing low latency live streams. + * @property {number} [stallThreshold=0.5] + * Stall threshold used in BufferController.js to determine whether a track should still be changed and which buffer range to prune. * @property {module:Settings~CachingInfoSettings} [lastBitrateCachingInfo={enabled: true, ttl: 360000}] * Set to false if you would like to disable the last known bit rate from being stored during playback and used * to set the initial bit rate for subsequent playback within the expiration window. @@ -16398,10 +16433,12 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * @property {module:Settings~AudioVideoSettings} [cacheLoadThresholds={video: 50, audio: 5}] * For a given media type, the threshold which defines if the response to a fragment * request is coming from browser cache or not. + * @property {module:Settings~RequestTypeSettings} [fragmentRequestTimeout] Time in milliseconds before timing out on loading a media fragment. Fragments that timeout are retried as if they failed. * @property {module:Settings~RequestTypeSettings} [retryIntervals] Time in milliseconds of which to reload a failed file load attempt. For low latency mode these values are divided by lowLatencyReductionFactor. * @property {module:Settings~RequestTypeSettings} [retryAttempts] Total number of retry attempts that will occur on a file load before it fails. For low latency mode these values are multiplied by lowLatencyMultiplyFactor. * @property {module:Settings~AbrSettings} abr Adaptive Bitrate algorithm related settings. * @property {module:Settings~CmcdSettings} cmcd Settings related to Common Media Client Data reporting. + * @property {module:Settings~LiveCatchupSettings} liveCatchup Settings related to live catchup. */ /** @@ -16436,6 +16473,56 @@ var _streamingVoMetricsHTTPRequest = _dereq_(242); * @property {string} [did=dash.js-cmcd-default-id] A unique string identifying the current device. */ +/** + * @typedef {Object} module:Settings~LiveCatchupSettings + @property {number} [minDrift=0.02] + * Use this method to set the minimum latency deviation allowed before activating catch-up mechanism. In low latency mode, + * when the difference between the measured latency and the target one, + * as an absolute number, is higher than the one sets with this method, then dash.js increases/decreases + * playback rate until target latency is reached. + * + * LowLatencyMinDrift should be provided in seconds, and it uses values between 0.0 and 0.5. + * + * Note: Catch-up mechanism is only applied when playing low latency live streams. + * @property {number} [maxDrift=0] + * Use this method to set the maximum latency deviation allowed before dash.js to do a seeking to live position. In low latency mode, + * when the difference between the measured latency and the target one, + * as an absolute number, is higher than the one sets with this method, then dash.js does a seek to live edge position minus + * the target live delay. + * + * LowLatencyMaxDriftBeforeSeeking should be provided in seconds. If 0, then seeking operations won't be used for + * fixing latency deviations. + * + * Note: Catch-up mechanism is only applied when playing low latency live streams. + * @property {number} [playbackRate=0.5] + * Use this parameter to set the maximum catch up rate, as a percentage, for low latency live streams. In low latency mode, + * when measured latency is higher/lower than the target one, + * dash.js increases/decreases playback rate respectively up to (+/-) the percentage defined with this method until target is reached. + * + * Valid values for catch up rate are in range 0-0.5 (0-50%). Set it to 0 to turn off live catch up feature. + * + * Note: Catch-up mechanism is only applied when playing low latency live streams. + * @property {number} [latencyThreshold=NaN] + * Use this parameter to set the maximum threshold for which live catch up is applied. For instance, if this value is set to 8 seconds, + * then live catchup is only applied if the current live latency is equal or below 8 seconds. The reason behind this parameter is to avoid an increase + * of the playback rate if the user seeks within the DVR window. + * + * If no value is specified this will be twice the maximum live delay. The maximum live delay is either specified in the manifest as part of a ServiceDescriptor or calculated the following: + * maximumLiveDelay = targetDelay + liveCatchupMinDrift + * + * @property {number} [playbackBufferMin=NaN] + * Use this parameter to specify the minimum buffer which is used for LoL+ based playback rate reduction + * + * + * @property {boolean} [enabled=false] + * Use this parameter to enable the catchup mode for non low-latency streams + * + * @property {String} [mode=Constants.LIVE_CATCHUP_MODE_DEFAULT] + * Use this parameter to switch between different catchup modes. Options: "liveCatchupModeDefault" or "liveCatchupModeLOLP" + * + * Note: Catch-up mechanism is automatically applied when playing low latency live streams. + */ + /** * @class * @ignore @@ -16451,7 +16538,8 @@ function Settings() { */ var defaultSettings = { debug: { - logLevel: _coreDebug2['default'].LOG_LEVEL_WARNING + logLevel: _coreDebug2['default'].LOG_LEVEL_WARNING, + dispatchEvent: false }, streaming: { metricsMaxListDepth: 1000, @@ -16461,7 +16549,8 @@ function Settings() { scheduleWhilePaused: true, fastSwitchEnabled: false, flushBufferAtTrackSwitch: false, - calcSegmentAvailabilityRangeFromTimeline: true, + calcSegmentAvailabilityRangeFromTimeline: false, + reuseExistingSourceBuffers: true, bufferPruningInterval: 10, bufferToKeep: 20, jumpGaps: true, @@ -16478,13 +16567,25 @@ function Settings() { useSuggestedPresentationDelay: true, useAppendWindow: true, manifestUpdateRetryInterval: 100, - liveCatchUpMinDrift: 0.02, - liveCatchUpMaxDrift: 0, - liveCatchUpPlaybackRate: 0.5, - liveCatchupLatencyThreshold: NaN, + stallThreshold: 0.5, + liveCatchup: { + minDrift: 0.02, + maxDrift: 0, + playbackRate: 0.5, + latencyThreshold: 60, + playbackBufferMin: 0.5, + enabled: false, + mode: _streamingConstantsConstants2['default'].LIVE_CATCHUP_MODE_DEFAULT + }, lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, cacheLoadThresholds: { video: 50, audio: 5 }, + trackSwitchMode: { + audio: _streamingConstantsConstants2['default'].TRACK_SWITCH_MODE_ALWAYS_REPLACE, + video: _streamingConstantsConstants2['default'].TRACK_SWITCH_MODE_NEVER_REPLACE + }, + selectionModeForInitialTrack: _streamingConstantsConstants2['default'].TRACK_SELECTION_MODE_HIGHEST_BITRATE, + fragmentRequestTimeout: 0, retryIntervals: (_retryIntervals = {}, _defineProperty(_retryIntervals, _streamingVoMetricsHTTPRequest.HTTPRequest.MPD_TYPE, 500), _defineProperty(_retryIntervals, _streamingVoMetricsHTTPRequest.HTTPRequest.XLINK_EXPANSION_TYPE, 500), _defineProperty(_retryIntervals, _streamingVoMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE, 1000), _defineProperty(_retryIntervals, _streamingVoMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE, 1000), _defineProperty(_retryIntervals, _streamingVoMetricsHTTPRequest.HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE, 1000), _defineProperty(_retryIntervals, _streamingVoMetricsHTTPRequest.HTTPRequest.INDEX_SEGMENT_TYPE, 1000), _defineProperty(_retryIntervals, _streamingVoMetricsHTTPRequest.HTTPRequest.OTHER_TYPE, 1000), _defineProperty(_retryIntervals, 'lowLatencyReductionFactor', 10), _retryIntervals), retryAttempts: (_retryAttempts = {}, _defineProperty(_retryAttempts, _streamingVoMetricsHTTPRequest.HTTPRequest.MPD_TYPE, 3), _defineProperty(_retryAttempts, _streamingVoMetricsHTTPRequest.HTTPRequest.XLINK_EXPANSION_TYPE, 1), _defineProperty(_retryAttempts, _streamingVoMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE, 3), _defineProperty(_retryAttempts, _streamingVoMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE, 3), _defineProperty(_retryAttempts, _streamingVoMetricsHTTPRequest.HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE, 3), _defineProperty(_retryAttempts, _streamingVoMetricsHTTPRequest.HTTPRequest.INDEX_SEGMENT_TYPE, 3), _defineProperty(_retryAttempts, _streamingVoMetricsHTTPRequest.HTTPRequest.OTHER_TYPE, 3), _defineProperty(_retryAttempts, 'lowLatencyMultiplyFactor', 5), _retryAttempts), abr: { @@ -16492,7 +16593,6 @@ function Settings() { ABRStrategy: _streamingConstantsConstants2['default'].ABR_STRATEGY_DYNAMIC, bandwidthSafetyFactor: 0.9, useDefaultABRRules: true, - useBufferOccupancyABR: false, useDeadTimeLatency: true, limitBitrateByPortal: false, usePixelRatioInLimitBitrateByPortal: false, @@ -16501,13 +16601,13 @@ function Settings() { maxRepresentationRatio: { audio: 1, video: 1 }, initialBitrate: { audio: -1, video: -1 }, initialRepresentationRatio: { audio: -1, video: -1 }, - autoSwitchBitrate: { audio: true, video: true } + autoSwitchBitrate: { audio: true, video: true }, + fetchThroughputCalculationMode: _streamingConstantsConstants2['default'].ABR_FETCH_THROUGHPUT_CALCULATION_DOWNLOADED_DATA }, cmcd: { enabled: false, sid: null, - cid: null, - did: null + cid: null } } }; @@ -16580,7 +16680,7 @@ var factory = _FactoryMaker2['default'].getSingletonFactory(Settings); exports['default'] = factory; module.exports = exports['default']; -},{"108":108,"242":242,"45":45,"47":47,"49":49}],49:[function(_dereq_,module,exports){ +},{"108":108,"248":248,"45":45,"47":47,"49":49}],49:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -16744,7 +16844,7 @@ Object.defineProperty(exports, '__esModule', { value: true }); exports.getVersionString = getVersionString; -var VERSION = '3.1.3'; +var VERSION = '3.2.0'; function getVersionString() { return VERSION; @@ -17079,7 +17179,6 @@ var CoreEvents = (function (_EventsBase) { this.SEGMENTBASE_INIT_REQUEST_NEEDED = 'segmentBaseInitRequestNeeded'; this.SEGMENTBASE_SEGMENTSLIST_REQUEST_NEEDED = 'segmentBaseSegmentsListRequestNeeded'; this.SEEK_TARGET = 'seekTarget'; - this.DYNAMIC_STREAM_COMPLETED = 'dynamicStreamCompleted'; } return CoreEvents; @@ -17439,7 +17538,7 @@ function DashAdapter() { if (currentMediaInfo[streamInfo.id] && currentMediaInfo[streamInfo.id][type]) { for (var i = 0, ln = adaptations.length; i < ln; i++) { - if (currentMediaInfo[streamInfo.id][type].isMediaInfoEqual(allMediaInfoForType[i])) { + if (areMediaInfosEqual(currentMediaInfo[streamInfo.id][type], allMediaInfoForType[i])) { return adaptations[i]; } } @@ -17455,6 +17554,27 @@ function DashAdapter() { return adaptations[0]; } + /** + * Compares two mediaInfo objects + * @param {MediaInfo} mInfoOne + * @param {MediaInfo} mInfoTwo + * @returns {boolean} + */ + function areMediaInfosEqual(mInfoOne, mInfoTwo) { + if (!mInfoOne || !mInfoTwo) { + return false; + } + + var sameId = mInfoOne.id === mInfoTwo.id; + var sameViewpoint = mInfoOne.viewpoint === mInfoTwo.viewpoint; + var sameLang = mInfoOne.lang === mInfoTwo.lang; + var sameRoles = mInfoOne.roles.toString() === mInfoTwo.roles.toString(); + var sameAccessibility = mInfoOne.accessibility.toString() === mInfoTwo.accessibility.toString(); + var sameAudioChannelConfiguration = mInfoOne.audioChannelConfiguration.toString() === mInfoTwo.audioChannelConfiguration.toString(); + + return sameId && sameViewpoint && sameLang && sameRoles && sameAccessibility && sameAudioChannelConfiguration; + } + /** * Returns the mediaInfo for a given mediaType * @param {object} streamInfo @@ -17641,46 +17761,55 @@ function DashAdapter() { /** * * @param {object} eventBox - * @param {Array} eventStreams - * @param {number} startTime + * @param {object} eventStreams + * @param {number} mediaStartTime + * @param {object} voRepresentation * @returns {null|Event} * @memberOf module:DashAdapter * @instance * @ignore */ - function getEvent(eventBox, eventStreams, startTime) { - if (!eventBox || !eventStreams) { - return null; - } - var event = new _voEvent2['default'](); - var schemeIdUri = eventBox.scheme_id_uri; - var value = eventBox.value; - var timescale = eventBox.timescale; - var presentationTimeDelta = undefined; - var calculatedPresentationTime = undefined; - if (eventBox.version === 0) { - presentationTimeDelta = eventBox.presentation_time_delta; - calculatedPresentationTime = startTime * timescale + presentationTimeDelta; - } else { - presentationTimeDelta = 0; - calculatedPresentationTime = eventBox.presentation_time_delta; - } - var duration = eventBox.event_duration; - var id = eventBox.id; - var messageData = eventBox.message_data; + function getEvent(eventBox, eventStreams, mediaStartTime, voRepresentation) { + try { + if (!eventBox || !eventStreams || isNaN(mediaStartTime) || !voRepresentation) { + return null; + } + var _event = new _voEvent2['default'](); + var schemeIdUri = eventBox.scheme_id_uri; + var value = eventBox.value; + var timescale = eventBox.timescale || 1; + var presentationTimeOffset = voRepresentation.presentationTimeOffset || 0; + var periodStart = voRepresentation.adaptation.period.start; + var presentationTimeDelta = eventBox.presentation_time_delta / timescale; // In case of version 1 events the presentation_time is parsed as presentation_time_delta + var calculatedPresentationTime = undefined; + + if (eventBox.version === 0) { + calculatedPresentationTime = periodStart + mediaStartTime - presentationTimeOffset + presentationTimeDelta; + } else { + calculatedPresentationTime = periodStart - presentationTimeOffset + presentationTimeDelta; + } + + var duration = eventBox.event_duration; + var id = eventBox.id; + var messageData = eventBox.message_data; - if (!eventStreams[schemeIdUri + '/' + value]) return null; + if (!eventStreams[schemeIdUri + '/' + value]) { + return null; + } - event.eventStream = eventStreams[schemeIdUri + '/' + value]; - event.eventStream.value = value; - event.eventStream.timescale = timescale; - event.duration = duration; - event.id = id; - event.calculatedPresentationTime = calculatedPresentationTime; - event.messageData = messageData; - event.presentationTimeDelta = presentationTimeDelta; + _event.eventStream = eventStreams[schemeIdUri + '/' + value]; + _event.eventStream.value = value; + _event.eventStream.timescale = timescale; + _event.duration = duration; + _event.id = id; + _event.calculatedPresentationTime = calculatedPresentationTime; + _event.messageData = messageData; + _event.presentationTimeDelta = presentationTimeDelta; - return event; + return _event; + } catch (e) { + return null; + } } /** @@ -18246,11 +18375,11 @@ Object.defineProperty(exports, '__esModule', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } -var _streamingVoFragmentRequest = _dereq_(228); +var _streamingVoFragmentRequest = _dereq_(234); var _streamingVoFragmentRequest2 = _interopRequireDefault(_streamingVoFragmentRequest); -var _streamingVoMetricsHTTPRequest = _dereq_(242); +var _streamingVoMetricsHTTPRequest = _dereq_(248); var _coreFactoryMaker = _dereq_(47); @@ -18298,7 +18427,7 @@ function DashHandler(config) { eventBus.on(events.INITIALIZATION_LOADED, onInitializationLoaded, instance); eventBus.on(events.SEGMENTS_LOADED, onSegmentsLoaded, instance); eventBus.on(events.REPRESENTATION_UPDATE_STARTED, onRepresentationUpdateStarted, instance); - eventBus.on(events.DYNAMIC_STREAM_COMPLETED, onDynamicStreamCompleted, instance); + eventBus.on(events.DYNAMIC_TO_STATIC, onDynamicToStatic, instance); } function initialize(isDynamic) { @@ -18307,6 +18436,10 @@ function DashHandler(config) { segmentsController.initialize(isDynamic); } + function getStreamId() { + return streamInfo.id; + } + function getType() { return type; } @@ -18341,7 +18474,7 @@ function DashHandler(config) { eventBus.off(events.INITIALIZATION_LOADED, onInitializationLoaded, instance); eventBus.off(events.SEGMENTS_LOADED, onSegmentsLoaded, instance); eventBus.off(events.REPRESENTATION_UPDATE_STARTED, onRepresentationUpdateStarted, instance); - eventBus.off(events.DYNAMIC_STREAM_COMPLETED, onDynamicStreamCompleted, instance); + eventBus.off(events.DYNAMIC_TO_STATIC, onDynamicToStatic, instance); } function setRequestUrl(request, destination, representation) { @@ -18405,25 +18538,20 @@ function DashHandler(config) { dashMetrics.updateManifestUpdateInfo({ presentationStartTime: liveEdge }); } - function onRepresentationUpdateStarted(eventObj) { - if (eventObj.sender.getType() !== getType()) return; - - processRepresentation(eventObj.representation); + function onRepresentationUpdateStarted(e) { + processRepresentation(e.representation); } function processRepresentation(voRepresentation) { var hasInitialization = voRepresentation.hasInitialization(); var hasSegments = voRepresentation.hasSegments(); - //if representation has initialization and segments information, REPRESENTATION_UPDATE_COMPLETED can be triggered immediately - //otherwise, it means that a request has to be made to get initialization and/or segments informations + // If representation has initialization and segments information, REPRESENTATION_UPDATE_COMPLETED can be triggered immediately + // otherwise, it means that a request has to be made to get initialization and/or segments informations if (hasInitialization && hasSegments) { - eventBus.trigger(events.REPRESENTATION_UPDATE_COMPLETED, { - sender: instance, - representation: voRepresentation - }); + eventBus.trigger(events.REPRESENTATION_UPDATE_COMPLETED, { representation: voRepresentation }, { streamId: streamInfo.id, mediaType: type }); } else { - segmentsController.update(voRepresentation, getType(), selectedMimeType, hasInitialization, hasSegments); + segmentsController.update(voRepresentation, selectedMimeType, hasInitialization, hasSegments); } } @@ -18447,6 +18575,7 @@ function DashHandler(config) { request.type = _streamingVoMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE; request.range = segment.mediaRange; request.startTime = segment.presentationStartTime; + request.mediaStartTime = segment.mediaStartTime; request.duration = segment.duration; request.timescale = representation.timescale; request.availabilityStartTime = segment.availabilityStartTime; @@ -18583,11 +18712,11 @@ function DashHandler(config) { var representation = e.representation; if (!representation.segments) return; - eventBus.trigger(events.REPRESENTATION_UPDATE_COMPLETED, { sender: this, representation: representation }); + eventBus.trigger(events.REPRESENTATION_UPDATE_COMPLETED, { representation: representation }, { streamId: streamInfo.id, mediaType: type }); } function onSegmentsLoaded(e) { - if (e.error || getType() !== e.mediaType) return; + if (e.error) return; var fragments = e.segments; var representation = e.representation; @@ -18631,17 +18760,18 @@ function DashHandler(config) { return; } - eventBus.trigger(events.REPRESENTATION_UPDATE_COMPLETED, { sender: this, representation: representation }); + eventBus.trigger(events.REPRESENTATION_UPDATE_COMPLETED, { representation: representation }, { streamId: streamInfo.id, mediaType: type }); } - function onDynamicStreamCompleted() { + function onDynamicToStatic() { logger.debug('Dynamic stream complete'); dynamicStreamCompleted = true; } instance = { initialize: initialize, - getType: getType, //need to be public in order to be used by logger + getStreamId: getStreamId, + getType: getType, getStreamInfo: getStreamInfo, getInitRequest: getInitRequest, getRequestForSegment: getRequestForSegment, @@ -18664,7 +18794,7 @@ DashHandler.__dashjs_factory_name = 'DashHandler'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(DashHandler); module.exports = exports['default']; -},{"228":228,"242":242,"47":47,"64":64,"80":80}],58:[function(_dereq_,module,exports){ +},{"234":234,"248":248,"47":47,"64":64,"80":80}],58:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -18707,7 +18837,7 @@ var _streamingConstantsConstants = _dereq_(108); var _streamingConstantsConstants2 = _interopRequireDefault(_streamingConstantsConstants); -var _streamingVoMetricsHTTPRequest = _dereq_(242); +var _streamingVoMetricsHTTPRequest = _dereq_(248); var _coreFactoryMaker = _dereq_(47); @@ -18725,7 +18855,7 @@ var _streamingModelsMetricsModel = _dereq_(153); var _streamingModelsMetricsModel2 = _interopRequireDefault(_streamingModelsMetricsModel); -var _streamingVoMetricsPlayList = _dereq_(244); +var _streamingVoMetricsPlayList = _dereq_(250); /** * @module DashMetrics @@ -19220,7 +19350,7 @@ DashMetrics.__dashjs_factory_name = 'DashMetrics'; exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(DashMetrics); module.exports = exports['default']; -},{"108":108,"109":109,"153":153,"242":242,"244":244,"47":47,"78":78}],59:[function(_dereq_,module,exports){ +},{"108":108,"109":109,"153":153,"248":248,"250":250,"47":47,"78":78}],59:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -19263,7 +19393,7 @@ var _voSegment = _dereq_(94); var _voSegment2 = _interopRequireDefault(_voSegment); -var _streamingVoDashJSError = _dereq_(226); +var _streamingVoDashJSError = _dereq_(232); var _streamingVoDashJSError2 = _interopRequireDefault(_streamingVoDashJSError); @@ -19271,7 +19401,7 @@ var _coreFactoryMaker = _dereq_(47); var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker); -var _streamingVoFragmentRequest = _dereq_(228); +var _streamingVoFragmentRequest = _dereq_(234); var _streamingVoFragmentRequest2 = _interopRequireDefault(_streamingVoFragmentRequest); @@ -19381,7 +19511,7 @@ function SegmentBaseLoader() { } } - function loadInitialization(representation, loadingInfo) { + function loadInitialization(streamId, mediaType, representation, loadingInfo) { checkConfig(); var initRange = null; var baseUrl = representation ? baseURLController.resolve(representation.path) : null; @@ -19395,7 +19525,7 @@ function SegmentBaseLoader() { searching: false, bytesLoaded: 0, bytesToLoad: 1500, - mediaType: representation && representation.adaptation ? representation.adaptation.type : null + mediaType: mediaType }; logger.debug('Start searching for initialization.'); @@ -19410,15 +19540,15 @@ function SegmentBaseLoader() { representation.range = initRange; // note that we don't explicitly set rep.initialization as this // will be computed when all BaseURLs are resolved later - eventBus.trigger(events.INITIALIZATION_LOADED, { representation: representation }); + eventBus.trigger(events.INITIALIZATION_LOADED, { representation: representation }, { streamId: streamId, mediaType: mediaType }); } else { info.range.end = info.bytesLoaded + info.bytesToLoad; - loadInitialization(representation, info); + loadInitialization(streamId, mediaType, representation, info); } }; var onerror = function onerror() { - eventBus.trigger(events.INITIALIZATION_LOADED, { representation: representation }); + eventBus.trigger(events.INITIALIZATION_LOADED, { representation: representation }, { streamId: streamId, mediaType: mediaType }); }; urlLoader.load({ request: request, success: onload, error: onerror }); @@ -19426,7 +19556,7 @@ function SegmentBaseLoader() { logger.debug('Perform init search: ' + info.url); } - function loadSegments(representation, type, range, callback, loadingInfo) { + function loadSegments(streamId, mediaType, representation, range, callback, loadingInfo) { checkConfig(); if (range && (range.start === undefined || range.end === undefined)) { var parts = range ? range.toString().split('-') : null; @@ -19445,7 +19575,7 @@ function SegmentBaseLoader() { searching: !hasRange, bytesLoaded: loadingInfo ? loadingInfo.bytesLoaded : 0, bytesToLoad: 1500, - mediaType: representation && representation.adaptation ? representation.adaptation.type : null + mediaType: mediaType }; var request = getFragmentRequest(info); @@ -19464,7 +19594,7 @@ function SegmentBaseLoader() { info.range.end = info.range.start + (sidx.size || extraBytes); } else if (loadedLength < info.bytesLoaded) { // if we have reached a search limit or if we have reached the end of the file we have to stop trying to find sidx - callback(null, representation, type); + callback(streamId, mediaType, null, representation); return; } else { var lastBox = isoFile.getLastBox(); @@ -19476,7 +19606,7 @@ function SegmentBaseLoader() { info.range.end += extraBytes; } } - loadSegments(representation, type, info.range, callback, info); + loadSegments(streamId, mediaType, representation, info.range, callback, info); } else { var ref = sidx.references; var loadMultiSidx = undefined, @@ -19499,7 +19629,7 @@ function SegmentBaseLoader() { var segs = []; var count = 0; var offset = (sidx.offset || info.range.start) + sidx.size; - var tmpCallback = function tmpCallback(result) { + var tmpCallback = function tmpCallback(streamId, mediaType, result) { if (result) { segs = segs.concat(result); count++; @@ -19509,10 +19639,10 @@ function SegmentBaseLoader() { segs.sort(function (a, b) { return a.startTime - b.startTime < 0 ? -1 : 0; }); - callback(segs, representation, type); + callback(streamId, mediaType, segs, representation); } } else { - callback(null, representation, type); + callback(streamId, mediaType, null, representation); } }; @@ -19521,19 +19651,19 @@ function SegmentBaseLoader() { se = offset + ref[j].referenced_size - 1; offset = offset + ref[j].referenced_size; r = { start: ss, end: se }; - loadSegments(representation, null, r, tmpCallback, info); + loadSegments(streamId, mediaType, representation, r, tmpCallback, info); } })(); } else { - logger.debug('Parsing segments from SIDX. representation ' + representation.adaptation.type + ' - id: ' + representation.id + ' for range : ' + info.range.start + ' - ' + info.range.end); + logger.debug('Parsing segments from SIDX. representation ' + mediaType + ' - id: ' + representation.id + ' for range : ' + info.range.start + ' - ' + info.range.end); segments = getSegmentsForSidx(sidx, info); - callback(segments, representation, type); + callback(streamId, mediaType, segments, representation); } } }; var onerror = function onerror() { - callback(null, representation, type); + callback(streamId, mediaType, null, representation); }; urlLoader.load({ request: request, success: onload, error: onerror }); @@ -19589,12 +19719,12 @@ function SegmentBaseLoader() { return request; } - function onLoaded(segments, representation, type) { - if (segments) { - eventBus.trigger(events.SEGMENTS_LOADED, { segments: segments, representation: representation, mediaType: type }); - } else { - eventBus.trigger(events.SEGMENTS_LOADED, { segments: null, representation: representation, mediaType: type, error: new _streamingVoDashJSError2['default'](errors.SEGMENT_BASE_LOADER_ERROR_CODE, errors.SEGMENT_BASE_LOADER_ERROR_MESSAGE) }); - } + function onLoaded(streamId, mediaType, segments, representation) { + eventBus.trigger(events.SEGMENTS_LOADED, { + segments: segments, + representation: representation, + error: segments ? undefined : new _streamingVoDashJSError2['default'](errors.SEGMENT_BASE_LOADER_ERROR_CODE, errors.SEGMENT_BASE_LOADER_ERROR_MESSAGE) + }, { streamId: streamId, mediaType: mediaType }); } instance = { @@ -19614,7 +19744,7 @@ SegmentBaseLoader.__dashjs_factory_name = 'SegmentBaseLoader'; exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(SegmentBaseLoader); module.exports = exports['default']; -},{"159":159,"226":226,"228":228,"47":47,"94":94}],60:[function(_dereq_,module,exports){ +},{"159":159,"232":232,"234":234,"47":47,"94":94}],60:[function(_dereq_,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { @@ -19623,7 +19753,7 @@ Object.defineProperty(exports, '__esModule', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } -var _streamingUtilsEBMLParser = _dereq_(212); +var _streamingUtilsEBMLParser = _dereq_(218); var _streamingUtilsEBMLParser2 = _interopRequireDefault(_streamingUtilsEBMLParser); @@ -19639,7 +19769,7 @@ var _voSegment = _dereq_(94); var _voSegment2 = _interopRequireDefault(_voSegment); -var _streamingVoFragmentRequest = _dereq_(228); +var _streamingVoFragmentRequest = _dereq_(234); var _streamingVoFragmentRequest2 = _interopRequireDefault(_streamingVoFragmentRequest); @@ -19647,7 +19777,7 @@ var _streamingNetURLLoader = _dereq_(159); var _streamingNetURLLoader2 = _interopRequireDefault(_streamingNetURLLoader); -var _streamingVoDashJSError = _dereq_(226); +var _streamingVoDashJSError = _dereq_(232); var _streamingVoDashJSError2 = _interopRequireDefault(_streamingVoDashJSError); @@ -19942,7 +20072,7 @@ function WebmSegmentBaseLoader() { } } - function loadInitialization(representation, loadingInfo) { + function loadInitialization(streamId, mediaType, representation, loadingInfo) { checkConfig(); var request = null; var baseUrl = representation ? baseURLController.resolve(representation.path) : null; @@ -19955,7 +20085,7 @@ function WebmSegmentBaseLoader() { request: request, url: baseUrl ? baseUrl.url : undefined, init: true, - mediaType: representation && representation.adaptation ? representation.adaptation.type : null + mediaType: mediaType }; logger.info('Start loading initialization.'); @@ -19965,15 +20095,11 @@ function WebmSegmentBaseLoader() { var onload = function onload() { // note that we don't explicitly set rep.initialization as this // will be computed when all BaseURLs are resolved later - eventBus.trigger(events.INITIALIZATION_LOADED, { - representation: representation - }); + eventBus.trigger(events.INITIALIZATION_LOADED, { representation: representation }, { streamId: streamId, mediaType: mediaType }); }; var onloadend = function onloadend() { - eventBus.trigger(events.INITIALIZATION_LOADED, { - representation: representation - }); + eventBus.trigger(events.INITIALIZATION_LOADED, { representation: representation }, { streamId: streamId, mediaType: mediaType }); }; urlLoader.load({ @@ -19985,7 +20111,7 @@ function WebmSegmentBaseLoader() { logger.debug('Perform init load: ' + info.url); } - function loadSegments(representation, type, theRange, callback) { + function loadSegments(streamId, mediaType, representation, theRange, callback) { checkConfig(); var request = null; var baseUrl = representation ? baseURLController.resolve(representation.path) : null; @@ -20001,7 +20127,7 @@ function WebmSegmentBaseLoader() { request: request, url: media, init: false, - mediaType: representation && representation.adaptation ? representation.adaptation.type : null + mediaType: mediaType }; callback = !callback ? onLoaded : callback; @@ -20014,12 +20140,12 @@ function WebmSegmentBaseLoader() { var onload = function onload(response) { parseEbmlHeader(response, media, theRange, function (segments) { - callback(segments, representation, type); + callback(streamId, mediaType, segments, representation); }); }; var onloadend = function onloadend() { - callback(null, representation, type); + callback(streamId, mediaType, null, representation); }; urlLoader.load({ @@ -20029,21 +20155,12 @@ function WebmSegmentBaseLoader() { }); } - function onLoaded(segments, representation, type) { - if (segments) { - eventBus.trigger(events.SEGMENTS_LOADED, { - segments: segments, - representation: representation, - mediaType: type - }); - } else { - eventBus.trigger(events.SEGMENTS_LOADED, { - segments: null, - representation: representation, - mediaType: type, - error: new _streamingVoDashJSError2['default'](errors.SEGMENT_BASE_LOADER_ERROR_CODE, errors.SEGMENT_BASE_LOADER_ERROR_MESSAGE) - }); - } + function onLoaded(streamId, mediaType, segments, representation) { + eventBus.trigger(events.SEGMENTS_LOADED, { + segments: segments, + representation: representation, + error: segments ? undefined : new _streamingVoDashJSError2['default'](errors.SEGMENT_BASE_LOADER_ERROR_CODE, errors.SEGMENT_BASE_LOADER_ERROR_MESSAGE) + }, { streamId: streamId, mediaType: mediaType }); } function getFragmentRequest(info) { @@ -20074,7 +20191,7 @@ WebmSegmentBaseLoader.__dashjs_factory_name = 'WebmSegmentBaseLoader'; exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(WebmSegmentBaseLoader); module.exports = exports['default']; -},{"108":108,"159":159,"212":212,"226":226,"228":228,"47":47,"94":94}],61:[function(_dereq_,module,exports){ +},{"108":108,"159":159,"218":218,"232":232,"234":234,"47":47,"94":94}],61:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -20278,7 +20395,7 @@ var _streamingConstantsConstants = _dereq_(108); var _streamingConstantsConstants2 = _interopRequireDefault(_streamingConstantsConstants); -var _streamingVoDashJSError = _dereq_(226); +var _streamingVoDashJSError = _dereq_(232); var _streamingVoDashJSError2 = _interopRequireDefault(_streamingVoDashJSError); @@ -20297,7 +20414,7 @@ function RepresentationController(config) { var playbackController = config.playbackController; var timelineConverter = config.timelineConverter; var type = config.type; - var streamId = config.streamId; + var streamInfo = config.streamInfo; var dashConstants = config.dashConstants; var instance = undefined, @@ -20315,6 +20432,14 @@ function RepresentationController(config) { eventBus.on(events.MANIFEST_VALIDITY_CHANGED, onManifestValidityChanged, instance); } + function getStreamId() { + return streamInfo.id; + } + + function getType() { + return type; + } + function checkConfig() { if (!abrController || !dashMetrics || !playbackController || !timelineConverter) { throw new Error(_streamingConstantsConstants2['default'].MISSING_CONFIG_ERROR); @@ -20340,7 +20465,6 @@ function RepresentationController(config) { } function reset() { - eventBus.off(events.QUALITY_CHANGE_REQUESTED, onQualityChanged, instance); eventBus.off(events.REPRESENTATION_UPDATE_COMPLETED, onRepresentationUpdated, instance); eventBus.off(events.WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, instance); @@ -20349,14 +20473,6 @@ function RepresentationController(config) { resetInitialSettings(); } - function getType() { - return type; - } - - function getStreamId() { - return streamId; - } - function updateData(newRealAdaptation, availableRepresentations, type, quality) { checkConfig(); @@ -20429,10 +20545,7 @@ function RepresentationController(config) { for (var i = 0, ln = voAvailableRepresentations.length; i < ln; i++) { updateRepresentation(voAvailableRepresentations[i], isDynamic); if (notifyUpdate) { - eventBus.trigger(events.REPRESENTATION_UPDATE_STARTED, { - sender: instance, - representation: voAvailableRepresentations[i] - }); + eventBus.trigger(events.REPRESENTATION_UPDATE_STARTED, { representation: voAvailableRepresentations[i] }, { streamId: streamInfo.id, mediaType: type }); } } } @@ -20445,16 +20558,16 @@ function RepresentationController(config) { function startDataUpdate() { updating = true; - eventBus.trigger(events.DATA_UPDATE_STARTED, { sender: instance }); + eventBus.trigger(events.DATA_UPDATE_STARTED, {}, { streamId: streamInfo.id, mediaType: type }); } function endDataUpdate(error) { updating = false; - var eventArg = { sender: instance, data: realAdaptation, currentRepresentation: currentVoRepresentation }; - if (error) { - eventArg.error = error; - } - eventBus.trigger(events.DATA_UPDATE_COMPLETED, eventArg); + eventBus.trigger(events.DATA_UPDATE_COMPLETED, { + data: realAdaptation, + currentRepresentation: currentVoRepresentation, + error: error + }, { streamId: streamInfo.id, mediaType: type }); } function postponeUpdate(postponeTimePeriod) { @@ -20475,14 +20588,13 @@ function RepresentationController(config) { } function onRepresentationUpdated(e) { - if (e.sender.getType() !== getType() || e.sender.getStreamInfo().id !== streamId || !isUpdating()) return; + if (!isUpdating()) return; if (e.error) { endDataUpdate(e.error); return; } - var streamInfo = e.sender.getStreamInfo(); var r = e.representation; var manifestUpdateInfo = dashMetrics.getCurrentManifestUpdate(); var alreadyAdded = false; @@ -20493,7 +20605,7 @@ function RepresentationController(config) { if (r.adaptation.period.mpd.manifest.type === dashConstants.DYNAMIC && !r.adaptation.period.mpd.manifest.ignorePostponeTimePeriod && playbackController.getStreamController().getStreams().length <= 1) { // We must put things to sleep unless till e.g. the startTime calculation in ScheduleController.onLiveEdgeSearchCompleted fall after the segmentAvailabilityRange.start - postponeTimePeriod = getRepresentationUpdatePostponeTimePeriod(r, streamInfo); + postponeTimePeriod = getRepresentationUpdatePostponeTimePeriod(r); } if (postponeTimePeriod > 0) { @@ -20530,7 +20642,7 @@ function RepresentationController(config) { } } - function getRepresentationUpdatePostponeTimePeriod(representation, streamInfo) { + function getRepresentationUpdatePostponeTimePeriod(representation) { try { var streamController = playbackController.getStreamController(); var activeStreamInfo = streamController.getActiveStreamInfo(); @@ -20557,8 +20669,6 @@ function RepresentationController(config) { } function onQualityChanged(e) { - if (e.mediaType !== getType() || streamId !== e.streamInfo.id) return; - currentVoRepresentation = getRepresentationForQuality(e.newQuality); addRepresentationSwitch(); } @@ -20574,14 +20684,14 @@ function RepresentationController(config) { } instance = { + getStreamId: getStreamId, + getType: getType, getData: getData, isUpdating: isUpdating, updateData: updateData, updateRepresentation: updateRepresentation, getCurrentRepresentation: getCurrentRepresentation, getRepresentationForQuality: getRepresentationForQuality, - getType: getType, - getStreamId: getStreamId, reset: reset }; @@ -20593,7 +20703,7 @@ RepresentationController.__dashjs_factory_name = 'RepresentationController'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(RepresentationController); module.exports = exports['default']; -},{"108":108,"226":226,"47":47}],63:[function(_dereq_,module,exports){ +},{"108":108,"232":232,"47":47}],63:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -20708,17 +20818,17 @@ function SegmentBaseController(config) { function onInitSegmentBaseNeeded(e) { if (isWebM(e.mimeType)) { - webmSegmentBaseLoader.loadInitialization(e.representation); + webmSegmentBaseLoader.loadInitialization(e.streamId, e.mediaType, e.representation); } else { - segmentBaseLoader.loadInitialization(e.representation); + segmentBaseLoader.loadInitialization(e.streamId, e.mediaType, e.representation); } } function onSegmentsListSegmentBaseNeeded(e) { if (isWebM(e.mimeType)) { - webmSegmentBaseLoader.loadSegments(e.representation, e.mediaType, e.representation ? e.representation.indexRange : null, e.callback); + webmSegmentBaseLoader.loadSegments(e.streamId, e.mediaType, e.representation, e.representation ? e.representation.indexRange : null, e.callback); } else { - segmentBaseLoader.loadSegments(e.representation, e.mediaType, e.representation ? e.representation.indexRange : null, e.callback); + segmentBaseLoader.loadSegments(e.streamId, e.mediaType, e.representation, e.representation ? e.representation.indexRange : null, e.callback); } } @@ -20808,6 +20918,8 @@ function SegmentsController(config) { var events = config.events; var eventBus = config.eventBus; var dashConstants = config.dashConstants; + var streamInfo = config.streamInfo; + var type = config.type; var instance = undefined, getters = undefined; @@ -20823,13 +20935,23 @@ function SegmentsController(config) { getters[dashConstants.SEGMENT_BASE] = (0, _utilsSegmentBaseGetter2['default'])(context).create(config, isDynamic); } - function update(voRepresentation, type, mimeType, hasInitialization, hasSegments) { + function update(voRepresentation, mimeType, hasInitialization, hasSegments) { if (!hasInitialization) { - eventBus.trigger(events.SEGMENTBASE_INIT_REQUEST_NEEDED, { mimeType: mimeType, representation: voRepresentation }); + eventBus.trigger(events.SEGMENTBASE_INIT_REQUEST_NEEDED, { + streamId: streamInfo.id, + mediaType: type, + mimeType: mimeType, + representation: voRepresentation + }); } if (!hasSegments) { - eventBus.trigger(events.SEGMENTBASE_SEGMENTSLIST_REQUEST_NEEDED, { mimeType: mimeType, mediaType: type, representation: voRepresentation }); + eventBus.trigger(events.SEGMENTBASE_SEGMENTSLIST_REQUEST_NEEDED, { + streamId: streamInfo.id, + mediaType: type, + mimeType: mimeType, + representation: voRepresentation + }); } } @@ -20943,11 +21065,11 @@ var _voEventStream = _dereq_(87); var _voEventStream2 = _interopRequireDefault(_voEventStream); -var _streamingUtilsObjectUtils = _dereq_(217); +var _streamingUtilsObjectUtils = _dereq_(223); var _streamingUtilsObjectUtils2 = _interopRequireDefault(_streamingUtilsObjectUtils); -var _streamingUtilsURLUtils = _dereq_(221); +var _streamingUtilsURLUtils = _dereq_(227); var _streamingUtilsURLUtils2 = _interopRequireDefault(_streamingUtilsURLUtils); @@ -20959,7 +21081,7 @@ var _coreDebug = _dereq_(45); var _coreDebug2 = _interopRequireDefault(_coreDebug); -var _streamingVoDashJSError = _dereq_(226); +var _streamingVoDashJSError = _dereq_(232); var _streamingVoDashJSError2 = _interopRequireDefault(_streamingVoDashJSError); @@ -20967,7 +21089,7 @@ var _coreErrorsErrors = _dereq_(51); var _coreErrorsErrors2 = _interopRequireDefault(_coreErrorsErrors); -var _streamingThumbnailThumbnailTracks = _dereq_(205); +var _streamingThumbnailThumbnailTracks = _dereq_(211); function DashManifestModel() { var instance = undefined, @@ -21701,42 +21823,46 @@ function DashManifestModel() { eventStream.timescale = 1; if (eventStreams[i].hasOwnProperty(_streamingConstantsConstants2['default'].SCHEME_ID_URI)) { - eventStream.schemeIdUri = eventStreams[i].schemeIdUri; + eventStream.schemeIdUri = eventStreams[i][_streamingConstantsConstants2['default'].SCHEME_ID_URI]; } else { throw new Error('Invalid EventStream. SchemeIdUri has to be set'); } if (eventStreams[i].hasOwnProperty(_constantsDashConstants2['default'].TIMESCALE)) { - eventStream.timescale = eventStreams[i].timescale; + eventStream.timescale = eventStreams[i][_constantsDashConstants2['default'].TIMESCALE]; } if (eventStreams[i].hasOwnProperty(_constantsDashConstants2['default'].VALUE)) { - eventStream.value = eventStreams[i].value; + eventStream.value = eventStreams[i][_constantsDashConstants2['default'].VALUE]; + } + if (eventStreams[i].hasOwnProperty(_constantsDashConstants2['default'].PRESENTATION_TIME_OFFSET)) { + eventStream.presentationTimeOffset = eventStreams[i][_constantsDashConstants2['default'].PRESENTATION_TIME_OFFSET]; } for (j = 0; eventStreams[i].Event_asArray && j < eventStreams[i].Event_asArray.length; j++) { + var currentMpdEvent = eventStreams[i].Event_asArray[j]; var _event = new _voEvent2['default'](); _event.presentationTime = 0; _event.eventStream = eventStream; - if (eventStreams[i].Event_asArray[j].hasOwnProperty(_constantsDashConstants2['default'].PRESENTATION_TIME)) { - _event.presentationTime = eventStreams[i].Event_asArray[j].presentationTime; - var presentationTimeOffset = eventStream.presentationTimeOffset ? eventStream.presentationTimeOffset * eventStream.timescale : 0; - _event.calculatedPresentationTime = _event.presentationTime + period.start * eventStream.timescale + presentationTimeOffset; + if (currentMpdEvent.hasOwnProperty(_constantsDashConstants2['default'].PRESENTATION_TIME)) { + _event.presentationTime = currentMpdEvent.presentationTime; + var presentationTimeOffset = eventStream.presentationTimeOffset ? eventStream.presentationTimeOffset / eventStream.timescale : 0; + _event.calculatedPresentationTime = _event.presentationTime / eventStream.timescale + period.start - presentationTimeOffset; } - if (eventStreams[i].Event_asArray[j].hasOwnProperty(_constantsDashConstants2['default'].DURATION)) { - _event.duration = eventStreams[i].Event_asArray[j].duration; + if (currentMpdEvent.hasOwnProperty(_constantsDashConstants2['default'].DURATION)) { + _event.duration = currentMpdEvent.duration / eventStream.timescale; } - if (eventStreams[i].Event_asArray[j].hasOwnProperty(_constantsDashConstants2['default'].ID)) { - _event.id = eventStreams[i].Event_asArray[j].id; + if (currentMpdEvent.hasOwnProperty(_constantsDashConstants2['default'].ID)) { + _event.id = currentMpdEvent.id; } - if (eventStreams[i].Event_asArray[j].Signal && eventStreams[i].Event_asArray[j].Signal.Binary) { + if (currentMpdEvent.Signal && currentMpdEvent.Signal.Binary) { // toString is used to manage both regular and namespaced tags - _event.messageData = BASE64.decodeArray(eventStreams[i].Event_asArray[j].Signal.Binary.toString()); + _event.messageData = BASE64.decodeArray(currentMpdEvent.Signal.Binary.toString()); } else { // From Cor.1: 'NOTE: this attribute is an alternative // to specifying a complete XML element(s) in the Event. // It is useful when an event leans itself to a compact // string representation'. - _event.messageData = eventStreams[i].Event_asArray[j].messageData || eventStreams[i].Event_asArray[j].__text; + _event.messageData = currentMpdEvent.messageData || currentMpdEvent.__text; } events.push(_event); @@ -22114,7 +22240,7 @@ DashManifestModel.__dashjs_factory_name = 'DashManifestModel'; exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(DashManifestModel); module.exports = exports['default']; -},{"108":108,"205":205,"217":217,"221":221,"226":226,"45":45,"47":47,"51":51,"61":61,"84":84,"85":85,"86":86,"87":87,"90":90,"91":91,"92":92,"96":96}],66:[function(_dereq_,module,exports){ +},{"108":108,"211":211,"223":223,"227":227,"232":232,"45":45,"47":47,"51":51,"61":61,"84":84,"85":85,"86":86,"87":87,"90":90,"91":91,"92":92,"96":96}],66:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -23835,7 +23961,7 @@ function TemplateSegmentsGetter(config, isDynamic) { var seg = (0, _SegmentsUtils.getIndexBasedSegment)(timelineConverter, isDynamic, representation, index); if (seg) { - seg.replacementTime = (index - 1) * representation.segmentDuration; + seg.replacementTime = Math.round((index - 1) * representation.segmentDuration * representation.timescale, 10); var url = template.media; url = (0, _SegmentsUtils.replaceTokenForTemplate)(url, 'Number', seg.replacementNumber); @@ -24655,6 +24781,7 @@ var EventStream = function EventStream() { this.timescale = 1; this.value = ''; this.schemeIdUri = ''; + this.presentationTimeOffset = 0; }; exports['default'] = EventStream; @@ -24756,55 +24883,31 @@ module.exports = exports["default"]; "use strict"; Object.defineProperty(exports, "__esModule", { - value: true + value: true }); -var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var MediaInfo = (function () { - function MediaInfo() { - _classCallCheck(this, MediaInfo); - - this.id = null; - this.index = null; - this.type = null; - this.streamInfo = null; - this.representationCount = 0; - this.lang = null; - this.viewpoint = null; - this.accessibility = null; - this.audioChannelConfiguration = null; - this.roles = null; - this.codec = null; - this.mimeType = null; - this.contentProtection = null; - this.isText = false; - this.KID = null; - this.bitrateList = null; - } - - _createClass(MediaInfo, [{ - key: "isMediaInfoEqual", - value: function isMediaInfoEqual(mediaInfo) { - if (!mediaInfo) { - return false; - } - - var sameId = this.id === mediaInfo.id; - var sameViewpoint = this.viewpoint === mediaInfo.viewpoint; - var sameLang = this.lang === mediaInfo.lang; - var sameRoles = this.roles.toString() === mediaInfo.roles.toString(); - var sameAccessibility = this.accessibility.toString() === mediaInfo.accessibility.toString(); - var sameAudioChannelConfiguration = this.audioChannelConfiguration.toString() === mediaInfo.audioChannelConfiguration.toString(); - - return sameId && sameViewpoint && sameLang && sameRoles && sameAccessibility && sameAudioChannelConfiguration; - } - }]); +var MediaInfo = function MediaInfo() { + _classCallCheck(this, MediaInfo); - return MediaInfo; -})(); + this.id = null; + this.index = null; + this.type = null; + this.streamInfo = null; + this.representationCount = 0; + this.lang = null; + this.viewpoint = null; + this.accessibility = null; + this.audioChannelConfiguration = null; + this.roles = null; + this.codec = null; + this.mimeType = null; + this.contentProtection = null; + this.isText = false; + this.KID = null; + this.bitrateList = null; +}; exports["default"] = MediaInfo; module.exports = exports["default"]; @@ -25316,11 +25419,11 @@ var _netURLLoader = _dereq_(159); var _netURLLoader2 = _interopRequireDefault(_netURLLoader); -var _voHeadRequest = _dereq_(229); +var _voHeadRequest = _dereq_(235); var _voHeadRequest2 = _interopRequireDefault(_voHeadRequest); -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); @@ -25351,7 +25454,8 @@ function FragmentLoader(config) { urlUtils: urlUtils, constants: _constantsConstants2['default'], boxParser: config.boxParser, - dashConstants: config.dashConstants + dashConstants: config.dashConstants, + requestTimeout: config.settings.get().streaming.fragmentRequestTimeout }); } @@ -25414,7 +25518,11 @@ function FragmentLoader(config) { }, abort: function abort(request) { if (request) { - eventBus.trigger(events.LOADING_ABANDONED, { request: request, mediaType: request.mediaType, sender: instance }); + eventBus.trigger(events.LOADING_ABANDONED, { + mediaType: request.mediaType, + request: request, + sender: instance + }); } } }); @@ -25452,7 +25560,7 @@ FragmentLoader.__dashjs_factory_name = 'FragmentLoader'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(FragmentLoader); module.exports = exports['default']; -},{"108":108,"159":159,"226":226,"229":229,"47":47}],98:[function(_dereq_,module,exports){ +},{"108":108,"159":159,"232":232,"235":235,"47":47}],98:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -25507,19 +25615,19 @@ var _netURLLoader = _dereq_(159); var _netURLLoader2 = _interopRequireDefault(_netURLLoader); -var _utilsURLUtils = _dereq_(221); +var _utilsURLUtils = _dereq_(227); var _utilsURLUtils2 = _interopRequireDefault(_utilsURLUtils); -var _voTextRequest = _dereq_(233); +var _voTextRequest = _dereq_(239); var _voTextRequest2 = _interopRequireDefault(_voTextRequest); -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); -var _voMetricsHTTPRequest = _dereq_(242); +var _voMetricsHTTPRequest = _dereq_(248); var _coreEventBus = _dereq_(46); @@ -25586,9 +25694,7 @@ function ManifestLoader(config) { } function onXlinkReady(event) { - eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, { - manifest: event.manifest - }); + eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, { manifest: event.manifest }); } function createParser(data) { @@ -25684,9 +25790,7 @@ function ManifestLoader(config) { manifest.loadedTime = new Date(); xlinkController.resolveManifestOnLoad(manifest); - eventBus.trigger(_coreEventsEvents2['default'].ORIGINAL_MANIFEST_LOADED, { - originalManifest: data - }); + eventBus.trigger(_coreEventsEvents2['default'].ORIGINAL_MANIFEST_LOADED, { originalManifest: data }); } else { eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, { manifest: null, @@ -25737,7 +25841,7 @@ var factory = _coreFactoryMaker2['default'].getClassFactory(ManifestLoader); exports['default'] = factory; module.exports = exports['default']; -},{"108":108,"124":124,"159":159,"221":221,"226":226,"233":233,"242":242,"46":46,"47":47,"51":51,"54":54,"61":61,"66":66}],99:[function(_dereq_,module,exports){ +},{"108":108,"124":124,"159":159,"227":227,"232":232,"239":239,"248":248,"46":46,"47":47,"51":51,"54":54,"61":61,"66":66}],99:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -25810,6 +25914,7 @@ function ManifestUpdater() { refreshDelay = undefined, refreshTimer = undefined, isPaused = undefined, + isStopped = undefined, isUpdating = undefined, manifestLoader = undefined, manifestModel = undefined, @@ -25858,6 +25963,7 @@ function ManifestUpdater() { refreshDelay = NaN; isUpdating = false; isPaused = true; + isStopped = false; stopManifestRefreshTimer(); } @@ -25881,6 +25987,10 @@ function ManifestUpdater() { function startManifestRefreshTimer(delay) { stopManifestRefreshTimer(); + if (isStopped) { + return; + } + if (isNaN(delay) && !isNaN(refreshDelay)) { delay = refreshDelay * 1000; } @@ -25907,7 +26017,9 @@ function ManifestUpdater() { // See DASH-IF IOP v4.3 section 4.6.4 "Transition Phase between Live and On-Demand" // Stop manifest update, ignore static manifest and signal end of dynamic stream to detect end of stream if (manifestModel.getValue() && manifestModel.getValue().type === _dashConstantsDashConstants2['default'].DYNAMIC && manifest.type === _dashConstantsDashConstants2['default'].STATIC) { - eventBus.trigger(_coreEventsEvents2['default'].DYNAMIC_STREAM_COMPLETED); + eventBus.trigger(_coreEventsEvents2['default'].DYNAMIC_TO_STATIC); + isUpdating = false; + isStopped = true; return; } @@ -26060,23 +26172,23 @@ var _ManifestLoader = _dereq_(98); var _ManifestLoader2 = _interopRequireDefault(_ManifestLoader); -var _utilsErrorHandler = _dereq_(213); +var _utilsErrorHandler = _dereq_(219); var _utilsErrorHandler2 = _interopRequireDefault(_utilsErrorHandler); -var _utilsCapabilities = _dereq_(208); +var _utilsCapabilities = _dereq_(214); var _utilsCapabilities2 = _interopRequireDefault(_utilsCapabilities); -var _textTextTracks = _dereq_(203); +var _textTextTracks = _dereq_(209); var _textTextTracks2 = _interopRequireDefault(_textTextTracks); -var _utilsRequestModifier = _dereq_(218); +var _utilsRequestModifier = _dereq_(224); var _utilsRequestModifier2 = _interopRequireDefault(_utilsRequestModifier); -var _textTextController = _dereq_(201); +var _textTextController = _dereq_(207); var _textTextController2 = _interopRequireDefault(_textTextController); @@ -26108,7 +26220,7 @@ var _modelsCmcdModel = _dereq_(149); var _modelsCmcdModel2 = _interopRequireDefault(_modelsCmcdModel); -var _utilsDOMStorage = _dereq_(210); +var _utilsDOMStorage = _dereq_(216); var _utilsDOMStorage2 = _interopRequireDefault(_utilsDOMStorage); @@ -26160,7 +26272,7 @@ var _dashUtilsTimelineConverter = _dereq_(82); var _dashUtilsTimelineConverter2 = _interopRequireDefault(_dashUtilsTimelineConverter); -var _voMetricsHTTPRequest = _dereq_(242); +var _voMetricsHTTPRequest = _dereq_(248); var _externalsBase64 = _dereq_(1); @@ -26170,21 +26282,21 @@ var _codemIsoboxer = _dereq_(9); var _codemIsoboxer2 = _interopRequireDefault(_codemIsoboxer); -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); -var _utilsSupervisorTools = _dereq_(219); +var _utilsSupervisorTools = _dereq_(225); var _ManifestUpdater = _dereq_(99); var _ManifestUpdater2 = _interopRequireDefault(_ManifestUpdater); -var _streamingUtilsURLUtils = _dereq_(221); +var _streamingUtilsURLUtils = _dereq_(227); var _streamingUtilsURLUtils2 = _interopRequireDefault(_streamingUtilsURLUtils); -var _utilsBoxParser = _dereq_(207); +var _utilsBoxParser = _dereq_(213); var _utilsBoxParser2 = _interopRequireDefault(_utilsBoxParser); @@ -26432,6 +26544,12 @@ function MediaPlayer() { segmentBaseController.initialize(); + // configure controllers + mediaController.setConfig({ + domStorage: domStorage, + settings: settings + }); + restoreDefaultUTCTimingSources(); setAutoPlay(AutoPlay !== undefined ? AutoPlay : true); @@ -26453,7 +26571,8 @@ function MediaPlayer() { * Sets the MPD source and the video element to null. You can also reset the MediaPlayer by * calling attachSource with a new source file. * - * Calling this method is all that is necessary to destroy a MediaPlayer instance. + * This call does not destroy the MediaPlayer. To destroy the MediaPlayer and free all of its + * memory, call destroy(). * * @memberof module:MediaPlayer * @instance @@ -26481,6 +26600,17 @@ function MediaPlayer() { } } + /** + * Completely destroys the media player and frees all memory. + * + * @memberof module:MediaPlayer + * @instance + */ + function destroy() { + reset(); + _coreFactoryMaker2['default'].deleteSingletonInstances(context); + } + /** * The ready state of the MediaPlayer based on both the video element and MPD source being defined. * @@ -26500,11 +26630,12 @@ function MediaPlayer() { * @param {string} type - {@link MediaPlayerEvents} * @param {Function} listener - callback method when the event fires. * @param {Object} scope - context of the listener so it can be removed properly. + * @param {Object} options - object to define various options such as priority and mode * @memberof module:MediaPlayer * @instance */ - function on(type, listener, scope) { - eventBus.on(type, listener, scope); + function on(type, listener, scope, options) { + eventBus.on(type, listener, scope, options); } /** @@ -27639,11 +27770,11 @@ function MediaPlayer() { /** * This method sets the current track switch mode. Available options are: * - * MediaController.TRACK_SWITCH_MODE_NEVER_REPLACE + * Constants.TRACK_SWITCH_MODE_NEVER_REPLACE * (used to forbid clearing the buffered data (prior to current playback position) after track switch. * Defers to fastSwitchEnabled for placement of new data. Default for video) * - * MediaController.TRACK_SWITCH_MODE_ALWAYS_REPLACE + * Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE * (used to clear the buffered data (prior to current playback position) after track switch. Default for audio) * * @param {MediaType} type @@ -27663,10 +27794,10 @@ function MediaPlayer() { * This method sets the selection mode for the initial track. This mode defines how the initial track will be selected * if no initial media settings are set. If initial media settings are set this parameter will be ignored. Available options are: * - * MediaController.TRACK_SELECTION_MODE_HIGHEST_BITRATE + * Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE * this mode makes the player select the track with a highest bitrate. This mode is a default mode. * - * MediaController.TRACK_SELECTION_MODE_WIDEST_RANGE + * Constants.TRACK_SELECTION_MODE_WIDEST_RANGE * this mode makes the player select the track with a widest range of bitrates * * @param {string} mode @@ -28024,11 +28155,6 @@ function MediaPlayer() { streamController = (0, _controllersStreamController2['default'])(context).getInstance(); } - // configure controllers - mediaController.setConfig({ - domStorage: domStorage - }); - streamController.setConfig({ capabilities: capabilities, manifestLoader: manifestLoader, @@ -28077,7 +28203,6 @@ function MediaPlayer() { videoModel: videoModel, settings: settings }); - abrController.createAbrRulesCollection(); textController.setConfig({ errHandler: errHandler, @@ -28393,7 +28518,8 @@ function MediaPlayer() { getSettings: getSettings, updateSettings: updateSettings, resetSettings: resetSettings, - reset: reset + reset: reset, + destroy: destroy }; setup(); @@ -28410,7 +28536,7 @@ _coreFactoryMaker2['default'].updateClassFactory(MediaPlayer.__dashjs_factory_na exports['default'] = factory; module.exports = exports['default']; -},{"1":1,"101":101,"108":108,"109":109,"111":111,"112":112,"117":117,"118":118,"120":120,"122":122,"149":149,"151":151,"152":152,"154":154,"155":155,"158":158,"2":2,"201":201,"203":203,"207":207,"208":208,"210":210,"213":213,"218":218,"219":219,"221":221,"226":226,"242":242,"45":45,"46":46,"47":47,"48":48,"50":50,"51":51,"54":54,"56":56,"58":58,"61":61,"63":63,"82":82,"9":9,"98":98,"99":99}],101:[function(_dereq_,module,exports){ +},{"1":1,"101":101,"108":108,"109":109,"111":111,"112":112,"117":117,"118":118,"120":120,"122":122,"149":149,"151":151,"152":152,"154":154,"155":155,"158":158,"2":2,"207":207,"209":209,"213":213,"214":214,"216":216,"219":219,"224":224,"225":225,"227":227,"232":232,"248":248,"45":45,"46":46,"47":47,"48":48,"50":50,"51":51,"54":54,"56":56,"58":58,"61":61,"63":63,"82":82,"9":9,"98":98,"99":99}],101:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -28503,6 +28629,12 @@ var MediaPlayerEvents = (function (_EventsBase) { */ this.BUFFER_LEVEL_STATE_CHANGED = 'bufferStateChanged'; + /** + * Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand). + * @event MediaPlayerEvents#DYNAMIC_TO_STATIC + */ + this.DYNAMIC_TO_STATIC = 'dynamicToStatic'; + /** * Triggered when there is an error from the element or MSE source buffer. * @event MediaPlayerEvents#ERROR @@ -28782,6 +28914,24 @@ var MediaPlayerEvents = (function (_EventsBase) { * @event MediaPlayerEvents#GAP_CAUSED_SEEK_TO_PERIOD_END */ this.GAP_CAUSED_SEEK_TO_PERIOD_END = 'gapCausedSeekToPeriodEnd'; + + /** + * A gap occured in the timeline which requires an internal seek + * @event MediaPlayerEvents#GAP_CAUSED_INTERNAL_SEEK + */ + this.GAP_CAUSED_INTERNAL_SEEK = 'gapCausedInternalSeek'; + + /** + * Dash events are triggered at their respective start points on the timeline. + * @event MediaPlayerEvents#EVENT_MODE_ON_START + */ + this.EVENT_MODE_ON_START = 'eventModeOnStart'; + + /** + * Dash events are triggered as soon as they were parsed. + * @event MediaPlayerEvents#EVENT_MODE_ON_RECEIVE + */ + this.EVENT_MODE_ON_RECEIVE = 'eventModeOnReceive'; } return MediaPlayerEvents; @@ -29188,7 +29338,7 @@ var _coreDebug = _dereq_(45); var _coreDebug2 = _interopRequireDefault(_coreDebug); -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); @@ -29204,7 +29354,7 @@ var _coreFactoryMaker = _dereq_(47); var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker); -var _textTextController = _dereq_(201); +var _textTextController = _dereq_(207); var _textTextController2 = _interopRequireDefault(_textTextController); @@ -29224,6 +29374,7 @@ function SourceBufferSink(mediaSource, mediaInfo, onAppendedCallback, oldBuffer) var eventBus = (0, _coreEventBus2['default'])(context).getInstance(); var instance = undefined, + type = undefined, logger = undefined, buffer = undefined, isAppendingInProgress = undefined, @@ -29237,6 +29388,7 @@ function SourceBufferSink(mediaSource, mediaInfo, onAppendedCallback, oldBuffer) logger = (0, _coreDebug2['default'])(context).getInstance().getLogger(instance); isAppendingInProgress = false; + type = mediaInfo.type; var codec = mediaInfo.codec; try { // Safari claims to support anything starting 'application/mp4'. @@ -29280,6 +29432,10 @@ function SourceBufferSink(mediaSource, mediaInfo, onAppendedCallback, oldBuffer) } } + function getType() { + return type; + } + function reset(keepBuffer) { if (buffer) { if (typeof buffer.removeEventListener === 'function') { @@ -29379,7 +29535,7 @@ function SourceBufferSink(mediaSource, mediaInfo, onAppendedCallback, oldBuffer) buffer.appendWindowStart = 0; buffer.appendWindowEnd = appendWindowEnd; buffer.appendWindowStart = appendWindowStart; - logger.debug('Updated append window for ' + mediaInfo.type + '. Set start to ' + buffer.appendWindowStart + ' and end to ' + buffer.appendWindowEnd); + logger.debug('Updated append window. Set start to ' + buffer.appendWindowStart + ' and end to ' + buffer.appendWindowEnd); } catch (e) { logger.warn('Failed to set append window'); } @@ -29537,7 +29693,7 @@ function SourceBufferSink(mediaSource, mediaInfo, onAppendedCallback, oldBuffer) } function errHandler() { - logger.error('SourceBufferSink error', mediaInfo.type); + logger.error('SourceBufferSink error'); } function waitForUpdateEnd(callback) { @@ -29549,6 +29705,7 @@ function SourceBufferSink(mediaSource, mediaInfo, onAppendedCallback, oldBuffer) } instance = { + getType: getType, getAllBufferRanges: getAllBufferRanges, getBuffer: getBuffer, append: append, @@ -29571,7 +29728,7 @@ var factory = _coreFactoryMaker2['default'].getClassFactory(SourceBufferSink); exports['default'] = factory; module.exports = exports['default']; -},{"201":201,"226":226,"45":45,"46":46,"47":47,"51":51,"54":54}],105:[function(_dereq_,module,exports){ +},{"207":207,"232":232,"45":45,"46":46,"47":47,"51":51,"54":54}],105:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -29626,7 +29783,7 @@ var _controllersFragmentController = _dereq_(116); var _controllersFragmentController2 = _interopRequireDefault(_controllersFragmentController); -var _thumbnailThumbnailController = _dereq_(204); +var _thumbnailThumbnailController = _dereq_(210); var _thumbnailThumbnailController2 = _interopRequireDefault(_thumbnailThumbnailController); @@ -29650,15 +29807,15 @@ var _coreFactoryMaker = _dereq_(47); var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker); -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); -var _utilsBoxParser = _dereq_(207); +var _utilsBoxParser = _dereq_(213); var _utilsBoxParser2 = _interopRequireDefault(_utilsBoxParser); -var _utilsURLUtils = _dereq_(221); +var _utilsURLUtils = _dereq_(227); var _utilsURLUtils2 = _interopRequireDefault(_utilsURLUtils); @@ -29682,12 +29839,13 @@ function Stream(config) { var eventController = config.eventController; var mediaController = config.mediaController; var textController = config.textController; + var protectionController = config.protectionController; var videoModel = config.videoModel; var settings = config.settings; + var streamInfo = config.streamInfo; var instance = undefined, logger = undefined, - streamInfo = undefined, streamProcessors = undefined, isStreamInitialized = undefined, isStreamActivated = undefined, @@ -29696,7 +29854,6 @@ function Stream(config) { hasAudioTrack = undefined, updateError = undefined, isUpdating = undefined, - protectionController = undefined, fragmentController = undefined, thumbnailController = undefined, preloaded = undefined, @@ -29722,6 +29879,7 @@ function Stream(config) { boxParser = (0, _utilsBoxParser2['default'])(context).getInstance(); fragmentController = (0, _controllersFragmentController2['default'])(context).create({ + streamInfo: streamInfo, mediaPlayerModel: mediaPlayerModel, dashMetrics: dashMetrics, errHandler: errHandler, @@ -29730,8 +29888,12 @@ function Stream(config) { dashConstants: _dashConstantsDashConstants2['default'], urlUtils: urlUtils }); + } + function initialize() { registerEvents(); + registerProtectionEvents(); + eventBus.trigger(_coreEventsEvents2['default'].STREAM_UPDATED, { streamInfo: streamInfo }); } function registerEvents() { @@ -29768,17 +29930,8 @@ function Stream(config) { } } - function initialize(strInfo, prtctnController) { - streamInfo = strInfo; - if (strInfo) { - fragmentController.setStreamId(strInfo.id); - } - protectionController = prtctnController; - registerProtectionEvents(); - - eventBus.trigger(_coreEventsEvents2['default'].STREAM_UPDATED, { - streamInfo: streamInfo - }); + function getStreamId() { + return streamInfo ? streamInfo.id : null; } /** @@ -29853,7 +30006,6 @@ function Stream(config) { function resetInitialSettings() { deactivate(); - streamInfo = null; isStreamInitialized = false; hasVideoTrack = false; hasAudioTrack = false; @@ -29874,6 +30026,8 @@ function Stream(config) { fragmentController = null; } + streamInfo = null; + resetInitialSettings(); unRegisterEvents(); @@ -30034,7 +30188,7 @@ function Stream(config) { function createStreamProcessor(mediaInfo, allMediaForType, mediaSource, optionalSettings) { - var fragmentModel = fragmentController.getModel(getId(), mediaInfo ? mediaInfo.type : null); + var fragmentModel = fragmentController.getModel(mediaInfo ? mediaInfo.type : null); var streamProcessor = (0, _StreamProcessor2['default'])(context).create({ streamInfo: streamInfo, @@ -30254,7 +30408,10 @@ function Stream(config) { // could be cleared in case an error is detected while initializing DRM keysystem for (var i = 0; i < ln && streamProcessors[i]; i++) { if (streamProcessors[i].getType() === _constantsConstants2['default'].AUDIO || streamProcessors[i].getType() === _constantsConstants2['default'].VIDEO || streamProcessors[i].getType() === _constantsConstants2['default'].FRAGMENTED_TEXT) { - protectionController.initializeForMedia(streamProcessors[i].getMediaInfo()); + var mediaInfo = streamProcessors[i].getMediaInfo(); + if (mediaInfo) { + protectionController.initializeForMedia(mediaInfo); + } } } } @@ -30304,9 +30461,7 @@ function Stream(config) { return buffers; } - function onBufferingCompleted(e) { - if (e.streamId !== streamInfo.id) return; - + function onBufferingCompleted() { var processors = getProcessors(); var ln = processors.length; @@ -30325,20 +30480,15 @@ function Stream(config) { } logger.debug('onBufferingCompleted - trigger STREAM_BUFFERING_COMPLETED'); - eventBus.trigger(_coreEventsEvents2['default'].STREAM_BUFFERING_COMPLETED, { - streamInfo: streamInfo - }); + eventBus.trigger(_coreEventsEvents2['default'].STREAM_BUFFERING_COMPLETED, { streamInfo: streamInfo }); } function onDataUpdateCompleted(e) { - if (!streamInfo || e.sender.getStreamId() !== streamInfo.id) return; - - updateError[e.sender.getType()] = e.error; + updateError[e.mediaType] = e.error; checkIfInitializationCompleted(); } function onInbandEvents(e) { - if (!streamInfo || e.sender.getStreamInfo().id !== streamInfo.id) return; addInbandEvents(e.events); } @@ -30379,9 +30529,7 @@ function Stream(config) { isUpdating = true; streamInfo = updatedStreamInfo; - eventBus.trigger(_coreEventsEvents2['default'].STREAM_UPDATED, { - streamInfo: streamInfo - }); + eventBus.trigger(_coreEventsEvents2['default'].STREAM_UPDATED, { streamInfo: streamInfo }); if (eventController) { addInlineEvents(); @@ -30394,8 +30542,11 @@ function Stream(config) { var streamProcessor = streamProcessors[i]; streamProcessor.updateStreamInfo(streamInfo); var mediaInfo = adapter.getMediaInfoForType(streamInfo, streamProcessor.getType()); - abrController.updateTopQualityIndex(mediaInfo); - streamProcessor.addMediaInfo(mediaInfo, true); + // Check if AdaptationSet has not been removed in MPD update + if (mediaInfo) { + abrController.updateTopQualityIndex(mediaInfo); + streamProcessor.addMediaInfo(mediaInfo, true); + } } if (trackChangedEvent) { @@ -30554,6 +30705,7 @@ function Stream(config) { instance = { initialize: initialize, + getStreamId: getStreamId, activate: activate, deactivate: deactivate, isActive: isActive, @@ -30587,7 +30739,7 @@ Stream.__dashjs_factory_name = 'Stream'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(Stream); module.exports = exports['default']; -},{"106":106,"108":108,"116":116,"204":204,"207":207,"221":221,"226":226,"45":45,"46":46,"47":47,"51":51,"54":54,"61":61}],106:[function(_dereq_,module,exports){ +},{"106":106,"108":108,"116":116,"210":210,"213":213,"227":227,"232":232,"45":45,"46":46,"47":47,"51":51,"54":54,"61":61}],106:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -30646,7 +30798,7 @@ var _controllersBufferController = _dereq_(114); var _controllersBufferController2 = _interopRequireDefault(_controllersBufferController); -var _textTextBufferController = _dereq_(200); +var _textTextBufferController = _dereq_(206); var _textTextBufferController2 = _interopRequireDefault(_textTextBufferController); @@ -30658,7 +30810,7 @@ var _dashControllersRepresentationController = _dereq_(62); var _dashControllersRepresentationController2 = _interopRequireDefault(_dashControllersRepresentationController); -var _utilsLiveEdgeFinder = _dereq_(216); +var _utilsLiveEdgeFinder = _dereq_(222); var _utilsLiveEdgeFinder2 = _interopRequireDefault(_utilsLiveEdgeFinder); @@ -30666,7 +30818,7 @@ var _coreFactoryMaker = _dereq_(47); var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker); -var _utilsSupervisorTools = _dereq_(219); +var _utilsSupervisorTools = _dereq_(225); var _coreEventBus = _dereq_(46); @@ -30684,7 +30836,7 @@ var _coreErrorsErrors = _dereq_(51); var _coreErrorsErrors2 = _interopRequireDefault(_coreErrorsErrors); -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); @@ -30692,23 +30844,23 @@ var _coreDebug = _dereq_(45); var _coreDebug2 = _interopRequireDefault(_coreDebug); -var _utilsRequestModifier = _dereq_(218); +var _utilsRequestModifier = _dereq_(224); var _utilsRequestModifier2 = _interopRequireDefault(_utilsRequestModifier); -var _streamingUtilsURLUtils = _dereq_(221); +var _streamingUtilsURLUtils = _dereq_(227); var _streamingUtilsURLUtils2 = _interopRequireDefault(_streamingUtilsURLUtils); -var _utilsBoxParser = _dereq_(207); +var _utilsBoxParser = _dereq_(213); var _utilsBoxParser2 = _interopRequireDefault(_utilsBoxParser); -var _voFragmentRequest = _dereq_(228); +var _voFragmentRequest = _dereq_(234); var _voFragmentRequest2 = _interopRequireDefault(_voFragmentRequest); -var _voMetricsPlayList = _dereq_(244); +var _voMetricsPlayList = _dereq_(250); function StreamProcessor(config) { @@ -30750,7 +30902,7 @@ function StreamProcessor(config) { logger = (0, _coreDebug2['default'])(context).getInstance().getLogger(instance); resetInitialSettings(); - eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance, _coreEventBus2['default'].EVENT_PRIORITY_HIGH); // High priority to be notified before Stream + eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance, { priority: _coreEventBus2['default'].EVENT_PRIORITY_HIGH }); // High priority to be notified before Stream eventBus.on(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, onQualityChanged, instance); eventBus.on(_coreEventsEvents2['default'].INIT_FRAGMENT_NEEDED, onInitFragmentNeeded, instance); eventBus.on(_coreEventsEvents2['default'].MEDIA_FRAGMENT_NEEDED, onMediaFragmentNeeded, instance); @@ -30795,7 +30947,7 @@ function StreamProcessor(config) { abrController.registerStreamType(type, instance); representationController = (0, _dashControllersRepresentationController2['default'])(context).create({ - streamId: streamInfo.id, + streamInfo: streamInfo, type: type, abrController: abrController, dashMetrics: dashMetrics, @@ -30813,7 +30965,7 @@ function StreamProcessor(config) { } scheduleController = (0, _controllersScheduleController2['default'])(context).create({ - streamId: streamInfo.id, + streamInfo: streamInfo, type: type, mimeType: mimeType, adapter: adapter, @@ -30834,6 +30986,14 @@ function StreamProcessor(config) { bufferPruned = false; } + function getStreamId() { + return streamInfo.id; + } + + function getType() { + return type; + } + function resetInitialSettings() { mediaInfoArr = []; mediaInfo = null; @@ -30889,8 +31049,6 @@ function StreamProcessor(config) { } function onDataUpdateCompleted(e) { - if (e.sender.getType() !== getType() || e.sender.getStreamId() !== streamInfo.id) return; - if (!e.error) { // Update representation if no error scheduleController.setCurrentRepresentation(adapter.convertDataToRepresentationInfo(e.currentRepresentation)); @@ -30905,7 +31063,6 @@ function StreamProcessor(config) { } function onQualityChanged(e) { - if (type !== e.mediaType || streamInfo.id !== e.streamInfo.id) return; var representationInfo = getRepresentationInfo(e.newQuality); scheduleController.setCurrentRepresentation(representationInfo); dashMetrics.pushPlayListTraceMetrics(new Date(), _voMetricsPlayList.PlayListTrace.REPRESENTATION_SWITCH_STOP_REASON); @@ -30913,10 +31070,7 @@ function StreamProcessor(config) { } function onBufferLevelUpdated(e) { - if (e.streamId !== streamInfo.id || e.mediaType !== type) return; - dashMetrics.addBufferLevel(type, new Date(), e.bufferLevel * 1000); - var activeStreamId = playbackController.getStreamController().getActiveStreamInfo().id; if (!manifestModel.getValue().doNotUpdateDVRWindowOnBufferUpdated && streamInfo.id === activeStreamId) { addDVRMetric(); @@ -30924,8 +31078,6 @@ function StreamProcessor(config) { } function onBufferLevelStateChanged(e) { - if (e.streamId !== streamInfo.id || e.mediaType !== type) return; - dashMetrics.addBufferState(type, e.state, scheduleController.getBufferTarget()); if (e.state === _constantsMetricsConstants2['default'].BUFFER_EMPTY && !playbackController.isSeeking()) { // logger.info('Buffer is empty! Stalling!'); @@ -30934,8 +31086,6 @@ function StreamProcessor(config) { } function onBufferCleared(e) { - if (e.streamId !== streamInfo.id || e.mediaType !== type) return; - // Remove executed requests not buffered anymore fragmentModel.syncExecutedRequestsWithBufferedRange(bufferController.getBuffer().getAllBufferRanges(), streamInfo.duration); @@ -30953,10 +31103,6 @@ function StreamProcessor(config) { dashMetrics.addDVRInfo(getType(), playbackController.getTime(), manifestInfo, range); } - function getType() { - return type; - } - function getRepresentationController() { return representationController; } @@ -31085,7 +31231,8 @@ function StreamProcessor(config) { } function onInitFragmentNeeded(e) { - if (!e.sender || e.mediaType !== type || e.streamId !== streamInfo.id) return; + // Event propagation may have been stopped (see MssHandler) + if (!e.sender) return; if (adapter.getIsTextTrack(mimeType) && !textController.isTextEnabled()) return; @@ -31099,9 +31246,6 @@ function StreamProcessor(config) { } function onMediaFragmentNeeded(e) { - if (!e.sender || e.mediaType !== type || e.streamId !== streamInfo.id) { - return; - } var request = undefined; // Don't schedule next fragments while pruning to avoid buffer inconsistencies @@ -31176,7 +31320,6 @@ function StreamProcessor(config) { function onMediaFragmentLoaded(e) { var chunk = e.chunk; - if (chunk.streamId !== streamInfo.id || chunk.mediaInfo.type != type) return; var bytes = chunk.bytes; var quality = chunk.quality; @@ -31194,33 +31337,45 @@ function StreamProcessor(config) { })[0]; var events = handleInbandEvents(bytes, request, eventStreamMedia, eventStreamTrack); - eventBus.trigger(_coreEventsEvents2['default'].INBAND_EVENTS, { sender: instance, events: events }); + eventBus.trigger(_coreEventsEvents2['default'].INBAND_EVENTS, { events: events }, { streamId: streamInfo.id }); } } function handleInbandEvents(data, request, mediaInbandEvents, trackInbandEvents) { - var fragmentStartTime = Math.max(!request || isNaN(request.startTime) ? 0 : request.startTime, 0); - var eventStreams = []; - var events = []; + try { + var eventStreams = {}; + var events = []; - /* Extract the possible schemeIdUri : If a DASH client detects an event message box with a scheme that is not defined in MPD, the client is expected to ignore it */ - var inbandEvents = mediaInbandEvents.concat(trackInbandEvents); - for (var i = 0, ln = inbandEvents.length; i < ln; i++) { - eventStreams[inbandEvents[i].schemeIdUri + '/' + inbandEvents[i].value] = inbandEvents[i]; - } + /* Extract the possible schemeIdUri : If a DASH client detects an event message box with a scheme that is not defined in MPD, the client is expected to ignore it */ + var inbandEvents = mediaInbandEvents.concat(trackInbandEvents); + for (var i = 0, ln = inbandEvents.length; i < ln; i++) { + eventStreams[inbandEvents[i].schemeIdUri + '/' + inbandEvents[i].value] = inbandEvents[i]; + } - var isoFile = (0, _utilsBoxParser2['default'])(context).getInstance().parse(data); - var eventBoxes = isoFile.getBoxes('emsg'); + var isoFile = (0, _utilsBoxParser2['default'])(context).getInstance().parse(data); + var eventBoxes = isoFile.getBoxes('emsg'); - for (var i = 0, ln = eventBoxes.length; i < ln; i++) { - var _event = adapter.getEvent(eventBoxes[i], eventStreams, fragmentStartTime); + if (!eventBoxes || eventBoxes.length === 0) { + return events; + } + + var sidx = isoFile.getBox('sidx'); + var mediaAnchorTime = sidx && !isNaN(sidx.earliest_presentation_time) && !isNaN(sidx.timescale) ? sidx.earliest_presentation_time / sidx.timescale : request && !isNaN(request.mediaStartTime) ? request.mediaStartTime : 0; + var fragmentMediaStartTime = Math.max(mediaAnchorTime, 0); + var voRepresentation = representationController.getCurrentRepresentation(); + + for (var i = 0, ln = eventBoxes.length; i < ln; i++) { + var _event = adapter.getEvent(eventBoxes[i], eventStreams, fragmentMediaStartTime, voRepresentation); - if (_event) { - events.push(_event); + if (_event) { + events.push(_event); + } } - } - return events; + return events; + } catch (e) { + return []; + } } function createBuffer(previousBuffers) { @@ -31340,8 +31495,6 @@ function StreamProcessor(config) { } function onSeekTarget(e) { - if (e.mediaType && e.mediaType !== type || e.streamId !== streamInfo.id) return; - bufferingTime = e.time; scheduleController.setSeekTarget(e.time); } @@ -31386,8 +31539,9 @@ function StreamProcessor(config) { instance = { initialize: initialize, - isUpdating: isUpdating, + getStreamId: getStreamId, getType: getType, + isUpdating: isUpdating, getBufferController: getBufferController, getFragmentModel: getFragmentModel, getScheduleController: getScheduleController, @@ -31426,7 +31580,7 @@ StreamProcessor.__dashjs_factory_name = 'StreamProcessor'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(StreamProcessor); module.exports = exports['default']; -},{"108":108,"109":109,"114":114,"121":121,"150":150,"200":200,"207":207,"216":216,"218":218,"219":219,"221":221,"226":226,"228":228,"244":244,"45":45,"46":46,"47":47,"51":51,"54":54,"57":57,"61":61,"62":62}],107:[function(_dereq_,module,exports){ +},{"108":108,"109":109,"114":114,"121":121,"150":150,"206":206,"213":213,"222":222,"224":224,"225":225,"227":227,"232":232,"234":234,"250":250,"45":45,"46":46,"47":47,"51":51,"54":54,"57":57,"61":61,"62":62}],107:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -31465,7 +31619,7 @@ Object.defineProperty(exports, '__esModule', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); @@ -31473,9 +31627,9 @@ var _netURLLoader = _dereq_(159); var _netURLLoader2 = _interopRequireDefault(_netURLLoader); -var _voMetricsHTTPRequest = _dereq_(242); +var _voMetricsHTTPRequest = _dereq_(248); -var _voTextRequest = _dereq_(233); +var _voTextRequest = _dereq_(239); var _voTextRequest2 = _interopRequireDefault(_voTextRequest); @@ -31562,7 +31716,7 @@ XlinkLoader.__dashjs_factory_name = 'XlinkLoader'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(XlinkLoader); module.exports = exports['default']; -},{"159":159,"226":226,"233":233,"242":242,"46":46,"47":47,"51":51,"54":54}],108:[function(_dereq_,module,exports){ +},{"159":159,"232":232,"239":239,"248":248,"46":46,"47":47,"51":51,"54":54}],108:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -31712,6 +31866,20 @@ var Constants = (function () { */ this.ABR_STRATEGY_BOLA = 'abrBola'; + /** + * @constant {string} ABR_STRATEGY_L2A Adaptive bitrate algorithm based on L2A (online learning) + * @memberof Constants# + * @static + */ + this.ABR_STRATEGY_L2A = 'abrL2A'; + + /** + * @constant {string} ABR_STRATEGY_LoLP Adaptive bitrate algorithm based on LoL+ + * @memberof Constants# + * @static + */ + this.ABR_STRATEGY_LoLP = 'abrLoLP'; + /** * @constant {string} ABR_STRATEGY_THROUGHPUT Adaptive bitrate algorithm based on throughput * @memberof Constants# @@ -31719,6 +31887,34 @@ var Constants = (function () { */ this.ABR_STRATEGY_THROUGHPUT = 'abrThroughput'; + /** + * @constant {string} ABR_FETCH_THROUGHPUT_CALUCUALTION_DOWNLOADED_DATA Throughput calculation based on downloaded data array + * @memberof Constants# + * @static + */ + this.ABR_FETCH_THROUGHPUT_CALCULATION_DOWNLOADED_DATA = 'abrFetchThroughputCalculationDownloadedData'; + + /** + * @constant {string} ABR_FETCH_THROUGHPUT_CALCULATION_MOOF_PARSING Throughput calculation based on moof parsing + * @memberof Constants# + * @static + */ + this.ABR_FETCH_THROUGHPUT_CALCULATION_MOOF_PARSING = 'abrFetchThroughputCalculationMoofParsing'; + + /** + * @constant {string} LIVE_CATCHUP_MODE_DEFAULT Throughput calculation based on moof parsing + * @memberof Constants# + * @static + */ + this.LIVE_CATCHUP_MODE_DEFAULT = 'liveCatchupModeDefault'; + + /** + * @constant {string} LIVE_CATCHUP_MODE_LOLP Throughput calculation based on moof parsing + * @memberof Constants# + * @static + */ + this.LIVE_CATCHUP_MODE_LOLP = 'liveCatchupModeLoLP'; + /** * @constant {string} MOVING_AVERAGE_SLIDING_WINDOW Moving average sliding window * @memberof Constants# @@ -31741,11 +31937,40 @@ var Constants = (function () { this.BAD_ARGUMENT_ERROR = 'Invalid Arguments'; /** - * @constant {string} MISSING_CONFIG_ERROR Missing ocnfiguration parameters type of error + * @constant {string} MISSING_CONFIG_ERROR Missing configuration parameters type of error * @memberof Constants# * @static */ this.MISSING_CONFIG_ERROR = 'Missing config parameter(s)'; + + /** + * @constant {string} TRACK_SWITCH_MODE_ALWAYS_REPLACE used to clear the buffered data (prior to current playback position) after track switch. Default for audio + * @memberof Constants# + * @static + */ + this.TRACK_SWITCH_MODE_ALWAYS_REPLACE = 'alwaysReplace'; + + /** + * @constant {string} TRACK_SWITCH_MODE_NEVER_REPLACE used to forbid clearing the buffered data (prior to current playback position) after track switch. Defers to fastSwitchEnabled for placement of new data. Default for video + * @memberof Constants# + * @static + */ + this.TRACK_SWITCH_MODE_NEVER_REPLACE = 'neverReplace'; + + /** + * @constant {string} TRACK_SELECTION_MODE_HIGHEST_BITRATE makes the player select the track with a highest bitrate. This mode is a default mode. + * @memberof Constants# + * @static + */ + this.TRACK_SELECTION_MODE_HIGHEST_BITRATE = 'highestBitrate'; + + /** + * @constant {string} TRACK_SELECTION_MODE_WIDEST_RANGE this mode makes the player select the track with a widest range of bitrates + * @memberof Constants# + * @static + */ + this.TRACK_SELECTION_MODE_WIDEST_RANGE = 'widestRange'; + this.LOCATION = 'Location'; this.INITIALIZE = 'initialize'; this.TEXT_SHOWING = 'showing'; @@ -31759,6 +31984,8 @@ var Constants = (function () { this.SUPPLEMENTAL_PROPERTY_LL_SCHEME = 'urn:dvb:dash:lowlatency:critical:2019'; this.XML = 'XML'; this.ARRAY_BUFFER = 'ArrayBuffer'; + this.DVB_REPORTING_URL = 'dvb:reportingUrl'; + this.DVB_PROBABILITY = 'dvb:probability'; } }]); @@ -31982,7 +32209,7 @@ var _constantsMetricsConstants = _dereq_(109); var _constantsMetricsConstants2 = _interopRequireDefault(_constantsMetricsConstants); -var _voBitrateInfo = _dereq_(225); +var _voBitrateInfo = _dereq_(231); var _voBitrateInfo2 = _interopRequireDefault(_voBitrateInfo); @@ -32026,9 +32253,9 @@ var _coreDebug = _dereq_(45); var _coreDebug2 = _interopRequireDefault(_coreDebug); -var _voMetricsHTTPRequest = _dereq_(242); +var _voMetricsHTTPRequest = _dereq_(248); -var _utilsSupervisorTools = _dereq_(219); +var _utilsSupervisorTools = _dereq_(225); var DEFAULT_VIDEO_BITRATE = 1000; var DEFAULT_AUDIO_BITRATE = 100; @@ -32061,6 +32288,8 @@ function AbrController() { droppedFramesHistory = undefined, throughputHistory = undefined, isUsingBufferOccupancyABRDict = undefined, + isUsingL2AABRDict = undefined, + isUsingLoLPBRDict = undefined, dashMetrics = undefined, settings = undefined; @@ -32075,14 +32304,16 @@ function AbrController() { abandonmentStateDict[type] = abandonmentStateDict[type] || {}; abandonmentStateDict[type].state = _constantsMetricsConstants2['default'].ALLOW_LOAD; isUsingBufferOccupancyABRDict[type] = false; - eventBus.on(_coreEventsEvents2['default'].LOADING_PROGRESS, onFragmentLoadProgress, this); - if (type == _constantsConstants2['default'].VIDEO) { - eventBus.on(_coreEventsEvents2['default'].QUALITY_CHANGE_RENDERED, onQualityChangeRendered, this); + isUsingL2AABRDict[type] = false; + isUsingLoLPBRDict[type] = false; + eventBus.on(_coreEventsEvents2['default'].LOADING_PROGRESS, onFragmentLoadProgress, instance); + if (type === _constantsConstants2['default'].VIDEO) { + eventBus.on(_coreEventsEvents2['default'].QUALITY_CHANGE_RENDERED, onQualityChangeRendered, instance); droppedFramesHistory = droppedFramesHistory || (0, _rulesDroppedFramesHistory2['default'])(context).create(); setElementSize(); } - eventBus.on(_coreEventsEvents2['default'].METRIC_ADDED, onMetricAdded, this); - eventBus.on(_coreEventsEvents2['default'].PERIOD_SWITCH_COMPLETED, createAbrRulesCollection, this); + eventBus.on(_coreEventsEvents2['default'].METRIC_ADDED, onMetricAdded, instance); + eventBus.on(_coreEventsEvents2['default'].PERIOD_SWITCH_COMPLETED, createAbrRulesCollection, instance); throughputHistory = throughputHistory || (0, _rulesThroughputHistory2['default'])(context).create({ settings: settings @@ -32110,6 +32341,8 @@ function AbrController() { streamProcessorDict = {}; switchHistoryDict = {}; isUsingBufferOccupancyABRDict = {}; + isUsingL2AABRDict = {}; + isUsingLoLPBRDict = {}; if (windowResizeEventCalled === undefined) { windowResizeEventCalled = false; } @@ -32124,10 +32357,10 @@ function AbrController() { resetInitialSettings(); - eventBus.off(_coreEventsEvents2['default'].LOADING_PROGRESS, onFragmentLoadProgress, this); - eventBus.off(_coreEventsEvents2['default'].QUALITY_CHANGE_RENDERED, onQualityChangeRendered, this); - eventBus.off(_coreEventsEvents2['default'].METRIC_ADDED, onMetricAdded, this); - eventBus.off(_coreEventsEvents2['default'].PERIOD_SWITCH_COMPLETED, createAbrRulesCollection, this); + eventBus.off(_coreEventsEvents2['default'].LOADING_PROGRESS, onFragmentLoadProgress, instance); + eventBus.off(_coreEventsEvents2['default'].QUALITY_CHANGE_RENDERED, onQualityChangeRendered, instance); + eventBus.off(_coreEventsEvents2['default'].METRIC_ADDED, onMetricAdded, instance); + eventBus.off(_coreEventsEvents2['default'].PERIOD_SWITCH_COMPLETED, createAbrRulesCollection, instance); if (abrRulesCollection) { abrRulesCollection.reset(); @@ -32179,7 +32412,7 @@ function AbrController() { } if (e.metric === _constantsMetricsConstants2['default'].BUFFER_LEVEL && (e.mediaType === _constantsConstants2['default'].AUDIO || e.mediaType === _constantsConstants2['default'].VIDEO)) { - updateIsUsingBufferOccupancyABR(e.mediaType, 0.001 * e.value.level); + _updateAbrStrategy(e.mediaType, 0.001 * e.value.level); } } @@ -32292,7 +32525,10 @@ function AbrController() { currentValue: oldQuality, switchHistory: switchHistoryDict[type], droppedFramesHistory: droppedFramesHistory, - useBufferOccupancyABR: useBufferOccupancyABR(type) + useBufferOccupancyABR: useBufferOccupancyABR(type), + useL2AABR: useL2AABR(type), + useLoLPABR: useLoLPABR(type), + videoModel: videoModel }); if (droppedFramesHistory) { @@ -32320,7 +32556,7 @@ function AbrController() { changeQuality(type, oldQuality, newQuality, topQualityIdx, switchRequest.reason); } } else if (settings.get().debug.logLevel === _coreDebug2['default'].LOG_LEVEL_DEBUG) { - var bufferLevel = dashMetrics.getCurrentBufferLevel(type); + var bufferLevel = dashMetrics.getCurrentBufferLevel(type, true); logger.debug('[' + type + '] stay on ' + oldQuality + '/' + topQualityIdx + ' (buffer: ' + bufferLevel + ')'); } } @@ -32348,7 +32584,11 @@ function AbrController() { logger.info('[' + type + '] switch from ' + oldQuality + ' to ' + newQuality + '/' + topQualityIdx + ' (buffer: ' + bufferLevel + ') ' + (reason ? JSON.stringify(reason) : '.')); } setQualityFor(type, id, newQuality); - eventBus.trigger(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, { mediaType: type, streamInfo: streamInfo, oldQuality: oldQuality, newQuality: newQuality, reason: reason }); + eventBus.trigger(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, { + oldQuality: oldQuality, + newQuality: newQuality, + reason: reason + }, { streamId: streamInfo.id, mediaType: type }); var bitrate = throughputHistory.getAverageThroughput(type); if (!isNaN(bitrate)) { domStorage.setSavedBitrateSettings(type, bitrate); @@ -32424,18 +32664,36 @@ function AbrController() { return infoList; } - function updateIsUsingBufferOccupancyABR(mediaType, bufferLevel) { + function _updateAbrStrategy(mediaType, bufferLevel) { var strategy = settings.get().streaming.abr.ABRStrategy; - if (strategy === _constantsConstants2['default'].ABR_STRATEGY_BOLA) { + if (strategy === _constantsConstants2['default'].ABR_STRATEGY_L2A) { + isUsingBufferOccupancyABRDict[mediaType] = false; + isUsingLoLPBRDict[mediaType] = false; + isUsingL2AABRDict[mediaType] = true; + return; + } + if (strategy === _constantsConstants2['default'].ABR_STRATEGY_LoLP) { + isUsingBufferOccupancyABRDict[mediaType] = false; + isUsingLoLPBRDict[mediaType] = true; + isUsingL2AABRDict[mediaType] = false; + return; + } else if (strategy === _constantsConstants2['default'].ABR_STRATEGY_BOLA) { isUsingBufferOccupancyABRDict[mediaType] = true; + isUsingLoLPBRDict[mediaType] = false; + isUsingL2AABRDict[mediaType] = false; return; } else if (strategy === _constantsConstants2['default'].ABR_STRATEGY_THROUGHPUT) { isUsingBufferOccupancyABRDict[mediaType] = false; + isUsingLoLPBRDict[mediaType] = false; + isUsingL2AABRDict[mediaType] = false; return; } // else ABR_STRATEGY_DYNAMIC + _updateDynamicAbrStrategy(mediaType, bufferLevel); + } + function _updateDynamicAbrStrategy(mediaType, bufferLevel) { var stableBufferTime = mediaPlayerModel.getStableBufferTime(); var switchOnThreshold = stableBufferTime; var switchOffThreshold = 0.5 * stableBufferTime; @@ -32457,20 +32715,26 @@ function AbrController() { return isUsingBufferOccupancyABRDict[mediaType]; } + function useL2AABR(mediaType) { + return isUsingL2AABRDict[mediaType]; + } + + function useLoLPABR(mediaType) { + return isUsingLoLPBRDict[mediaType]; + } + function getThroughputHistory() { return throughputHistory; } function updateTopQualityIndex(mediaInfo) { - if (mediaInfo) { - var type = mediaInfo.type; - var streamId = mediaInfo.streamInfo.id; - var max = mediaInfo.representationCount - 1; + var type = mediaInfo.type; + var streamId = mediaInfo.streamInfo.id; + var max = mediaInfo.representationCount - 1; - setTopQualityIndex(type, streamId, max); + setTopQualityIndex(type, streamId, max); - return max; - } + return max; } function isPlayingAtTopQuality(streamInfo) { @@ -32591,24 +32855,36 @@ function AbrController() { abrController: instance, streamProcessor: streamProcessor, currentRequest: e.request, - useBufferOccupancyABR: useBufferOccupancyABR(type) + useBufferOccupancyABR: useBufferOccupancyABR(type), + useL2AABR: useL2AABR(type), + useLoLPABR: useLoLPABR(type), + videoModel: videoModel }); var switchRequest = abrRulesCollection.shouldAbandonFragment(rulesContext); if (switchRequest.quality > _rulesSwitchRequest2['default'].NO_CHANGE) { var fragmentModel = streamProcessor.getFragmentModel(); - var request = fragmentModel.getRequests({ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_LOADING, index: e.request.index })[0]; + var request = fragmentModel.getRequests({ + state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_LOADING, + index: e.request.index + })[0]; if (request) { //TODO Check if we should abort or if better to finish download. check bytesLoaded/Total fragmentModel.abortRequests(); setAbandonmentStateFor(type, _constantsMetricsConstants2['default'].ABANDON_LOAD); switchHistoryDict[type].reset(); - switchHistoryDict[type].push({ oldValue: getQualityFor(type), newValue: switchRequest.quality, confidence: 1, reason: switchRequest.reason }); + switchHistoryDict[type].push({ + oldValue: getQualityFor(type), + newValue: switchRequest.quality, + confidence: 1, + reason: switchRequest.reason + }); setPlaybackQuality(type, streamController.getActiveStreamInfo(), switchRequest.quality, switchRequest.reason); clearTimeout(abandonmentTimeout); abandonmentTimeout = setTimeout(function () { - setAbandonmentStateFor(type, _constantsMetricsConstants2['default'].ALLOW_LOAD);abandonmentTimeout = null; + setAbandonmentStateFor(type, _constantsMetricsConstants2['default'].ALLOW_LOAD); + abandonmentTimeout = null; }, settings.get().streaming.abandonLoadTimeout); } } @@ -32651,7 +32927,7 @@ _coreFactoryMaker2['default'].updateSingletonFactory(AbrController.__dashjs_fact exports['default'] = factory; module.exports = exports['default']; -},{"108":108,"109":109,"150":150,"185":185,"186":186,"187":187,"188":188,"189":189,"190":190,"219":219,"225":225,"242":242,"45":45,"46":46,"47":47,"54":54}],112:[function(_dereq_,module,exports){ +},{"108":108,"109":109,"150":150,"185":185,"186":186,"187":187,"188":188,"189":189,"190":190,"225":225,"231":231,"248":248,"45":45,"46":46,"47":47,"54":54}],112:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -32695,11 +32971,11 @@ var _modelsBaseURLTreeModel = _dereq_(148); var _modelsBaseURLTreeModel2 = _interopRequireDefault(_modelsBaseURLTreeModel); -var _utilsBaseURLSelector = _dereq_(206); +var _utilsBaseURLSelector = _dereq_(212); var _utilsBaseURLSelector2 = _interopRequireDefault(_utilsBaseURLSelector); -var _utilsURLUtils = _dereq_(221); +var _utilsURLUtils = _dereq_(227); var _utilsURLUtils2 = _interopRequireDefault(_utilsURLUtils); @@ -32819,7 +33095,7 @@ BaseURLController.__dashjs_factory_name = 'BaseURLController'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BaseURLController); module.exports = exports['default']; -},{"148":148,"206":206,"221":221,"46":46,"47":47,"54":54,"85":85}],113:[function(_dereq_,module,exports){ +},{"148":148,"212":212,"227":227,"46":46,"47":47,"54":54,"85":85}],113:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -32870,6 +33146,7 @@ var _coreEventBus2 = _interopRequireDefault(_coreEventBus); function BlackListController(config) { config = config || {}; + var instance = undefined; var blacklist = []; var eventBus = (0, _coreEventBus2['default'])(this.context).getInstance(); @@ -32891,9 +33168,7 @@ function BlackListController(config) { blacklist.push(entry); - eventBus.trigger(updateEventName, { - entry: entry - }); + eventBus.trigger(updateEventName, { entry: entry }); } function onAddBlackList(e) { @@ -32902,7 +33177,7 @@ function BlackListController(config) { function setup() { if (addBlacklistEventName) { - eventBus.on(addBlacklistEventName, onAddBlackList, this); + eventBus.on(addBlacklistEventName, onAddBlackList, instance); } } @@ -32910,13 +33185,14 @@ function BlackListController(config) { blacklist = []; } - setup(); - - return { + instance = { add: add, contains: contains, reset: reset }; + + setup(); + return instance; } BlackListController.__dashjs_factory_name = 'BlackListController'; @@ -32986,10 +33262,6 @@ var _AbrController = _dereq_(111); var _AbrController2 = _interopRequireDefault(_AbrController); -var _MediaController = _dereq_(118); - -var _MediaController2 = _interopRequireDefault(_MediaController); - var _coreEventBus = _dereq_(46); var _coreEventBus2 = _interopRequireDefault(_coreEventBus); @@ -33006,11 +33278,11 @@ var _coreDebug = _dereq_(45); var _coreDebug2 = _interopRequireDefault(_coreDebug); -var _utilsInitCache = _dereq_(214); +var _utilsInitCache = _dereq_(220); var _utilsInitCache2 = _interopRequireDefault(_utilsInitCache); -var _voDashJSError = _dereq_(226); +var _voDashJSError = _dereq_(232); var _voDashJSError2 = _interopRequireDefault(_voDashJSError); @@ -33018,9 +33290,9 @@ var _coreErrorsErrors = _dereq_(51); var _coreErrorsErrors2 = _interopRequireDefault(_coreErrorsErrors); -var _voMetricsHTTPRequest = _dereq_(242); +var _voMetricsHTTPRequest = _dereq_(248); -var STALL_THRESHOLD = 0.5; +var BUFFERING_COMPLETED_THRESHOLD = 0.1; var BUFFER_END_THRESHOLD = 0.5; var BUFFER_RANGE_CALCULATION_THRESHOLD = 0.01; var QUOTA_EXCEEDED_ERROR_CODE = 22; @@ -33096,10 +33368,18 @@ function BufferController(config) { eventBus.on(_coreEventsEvents2['default'].PLAYBACK_SEEKED, onPlaybackSeeked, this); eventBus.on(_coreEventsEvents2['default'].PLAYBACK_STALLED, onPlaybackStalled, this); eventBus.on(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, this); - eventBus.on(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, onCurrentTrackChanged, this, _coreEventBus2['default'].EVENT_PRIORITY_HIGH); + eventBus.on(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, onCurrentTrackChanged, this, { priority: _coreEventBus2['default'].EVENT_PRIORITY_HIGH }); eventBus.on(_coreEventsEvents2['default'].SOURCEBUFFER_REMOVE_COMPLETED, onRemoved, this); } + function getStreamId() { + return streamInfo.id; + } + + function getType() { + return type; + } + function getRepresentationInfo(quality) { return adapter.convertDataToRepresentationInfo(representationController.getRepresentationForQuality(quality)); } @@ -33127,7 +33407,7 @@ function BufferController(config) { } else { buffer = (0, _PreBufferSink2['default'])(context).create(onAppended.bind(this)); } - updateBufferTimestampOffset(this.getRepresentationInfo(requiredQuality)); + updateBufferTimestampOffset(getRepresentationInfo(requiredQuality)); return buffer; } @@ -33165,8 +33445,6 @@ function BufferController(config) { } function onInitFragmentLoaded(e) { - if (e.chunk.streamId !== streamInfo.id || e.chunk.mediaInfo.type !== type) return; - logger.info('Init fragment finished loading saving to', type + '\'s init cache'); initCache.save(e.chunk); logger.debug('Append Init fragment', type, ' with representationId:', e.chunk.representationId, ' and quality:', e.chunk.quality, ', data size:', e.chunk.bytes.byteLength); @@ -33190,12 +33468,11 @@ function BufferController(config) { function onMediaFragmentLoaded(e) { var chunk = e.chunk; - if (chunk.streamId !== streamInfo.id || chunk.mediaInfo.type !== type) return; if (replacingBuffer) { mediaChunk = chunk; var ranges = buffer && buffer.getAllBufferRanges(); - if (ranges && ranges.length > 0 && playbackController.getTimeToStreamEnd() > STALL_THRESHOLD) { + if (ranges && ranges.length > 0 && playbackController.getTimeToStreamEnd() > settings.get().streaming.stallThreshold) { logger.debug('Clearing buffer because track changed - ' + (ranges.end(ranges.length - 1) + BUFFER_END_THRESHOLD)); clearBuffers([{ start: 0, @@ -33273,7 +33550,7 @@ function BufferController(config) { // (and previous buffered data removed) then seek stream to current time var currentTime = playbackController.getTime(); logger.debug('AppendToBuffer seek target should be ' + currentTime); - triggerEvent(_coreEventsEvents2['default'].SEEK_TARGET, { time: currentTime, mediaType: type, streamId: streamInfo.id }); + triggerEvent(_coreEventsEvents2['default'].SEEK_TARGET, { time: currentTime }); } if (appendedBytesInfo) { @@ -33320,7 +33597,7 @@ function BufferController(config) { } function onQualityChanged(e) { - if (e.streamInfo.id !== streamInfo.id || e.mediaType !== type || requiredQuality === e.newQuality) return; + if (requiredQuality === e.newQuality) return; updateBufferTimestampOffset(this.getRepresentationInfo(e.newQuality)); requiredQuality = e.newQuality; @@ -33389,7 +33666,7 @@ function BufferController(config) { // we include fragment right behind the one in current time position var behindRange = { start: 0, - end: currentTimeRequest.startTime - STALL_THRESHOLD + end: currentTimeRequest.startTime - settings.get().streaming.stallThreshold }; var prevReq = fragmentModel.getRequests({ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_EXECUTED, @@ -33406,16 +33683,16 @@ function BufferController(config) { // Build buffer ahead range. To avoid pruning time around current time position, // we include fragment right after the one in current time position var aheadRange = { - start: currentTimeRequest.startTime + currentTimeRequest.duration + STALL_THRESHOLD, + start: currentTimeRequest.startTime + currentTimeRequest.duration + settings.get().streaming.stallThreshold, end: endOfBuffer }; var nextReq = fragmentModel.getRequests({ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_EXECUTED, - time: currentTimeRequest.startTime + currentTimeRequest.duration + STALL_THRESHOLD, + time: currentTimeRequest.startTime + currentTimeRequest.duration + settings.get().streaming.stallThreshold, threshold: BUFFER_RANGE_CALCULATION_THRESHOLD })[0]; if (nextReq && nextReq.startTime !== currentTimeRequest.startTime) { - aheadRange.start = nextReq.startTime + nextReq.duration + STALL_THRESHOLD; + aheadRange.start = nextReq.startTime + nextReq.duration + settings.get().streaming.stallThreshold; } if (aheadRange.start < aheadRange.end && aheadRange.start < endOfBuffer) { clearRanges.push(aheadRange); @@ -33497,6 +33774,11 @@ function BufferController(config) { var range = undefined, length = undefined; + // Consider gap/discontinuity limit as tolerance + if (settings.get().streaming.jumpGaps) { + tolerance = settings.get().streaming.smallGapLimit; + } + range = getRangeAt(time, tolerance); if (range === null) { @@ -33529,18 +33811,17 @@ function BufferController(config) { // No need to check buffer if type is not audio or video (for example if several errors occur during text parsing, so that the buffer cannot be filled, no error must occur on video playback) if (type !== _constantsConstants2['default'].AUDIO && type !== _constantsConstants2['default'].VIDEO) return; - if (seekClearedBufferingCompleted && !isBufferingCompleted && bufferLevel > 0 && playbackController && playbackController.getTimeToStreamEnd() - bufferLevel < STALL_THRESHOLD) { + if (seekClearedBufferingCompleted && !isBufferingCompleted && bufferLevel > 0 && playbackController && playbackController.getTimeToStreamEnd() - bufferLevel < BUFFERING_COMPLETED_THRESHOLD) { seekClearedBufferingCompleted = false; isBufferingCompleted = true; logger.debug('checkIfSufficientBuffer trigger BUFFERING_COMPLETED for type ' + type); - logger.debug('checkIfSufficientBuffer trigger BUFFERING_COMPLETED for type ' + type); triggerEvent(_coreEventsEvents2['default'].BUFFERING_COMPLETED); } - // When the player is working in low latency mode, the buffer is often below STALL_THRESHOLD. + // When the player is working in low latency mode, the buffer is often below settings.get().streaming.stallThreshold. // So, when in low latency mode, change dash.js behavior so it notifies a stall just when // buffer reach 0 seconds - if ((!settings.get().streaming.lowLatencyEnabled && bufferLevel < STALL_THRESHOLD || bufferLevel === 0) && !isBufferingCompleted) { + if ((!settings.get().streaming.lowLatencyEnabled && bufferLevel < settings.get().streaming.stallThreshold || bufferLevel === 0) && !isBufferingCompleted) { notifyBufferStateChanged(_constantsMetricsConstants2['default'].BUFFER_EMPTY); } else { if (isBufferingCompleted || bufferLevel >= streamInfo.manifestInfo.minBufferTime) { @@ -33710,16 +33991,11 @@ function BufferController(config) { } function onDataUpdateCompleted(e) { - if (e.sender.getStreamId() !== streamInfo.id || e.sender.getType() !== type) return; - if (e.error) return; - if (isBufferingCompleted) { - return; - } + if (e.error || isBufferingCompleted) return; updateBufferTimestampOffset(e.currentRepresentation); } function onStreamCompleted(e) { - if (e.request.mediaInfo.streamInfo.id !== streamInfo.id || e.request.mediaType !== type) return; lastIndex = e.request.index; checkIfBufferingCompleted(); } @@ -33731,8 +34007,8 @@ function BufferController(config) { if (!ranges) return; logger.info('Track change asked'); - if (mediaController.getSwitchMode(type) === _MediaController2['default'].TRACK_SWITCH_MODE_ALWAYS_REPLACE) { - if (ranges && ranges.length > 0 && playbackController.getTimeToStreamEnd() > STALL_THRESHOLD) { + if (mediaController.getSwitchMode(type) === _constantsConstants2['default'].TRACK_SWITCH_MODE_ALWAYS_REPLACE) { + if (ranges && ranges.length > 0 && playbackController.getTimeToStreamEnd() > settings.get().streaming.stallThreshold) { isBufferingCompleted = false; lastIndex = Number.POSITIVE_INFINITY; } @@ -33752,10 +34028,6 @@ function BufferController(config) { checkIfSufficientBuffer(); } - function getType() { - return type; - } - function getBuffer() { return buffer; } @@ -33817,10 +34089,7 @@ function BufferController(config) { function triggerEvent(eventType, data) { var payload = data || {}; - payload.sender = instance; - payload.mediaType = type; - payload.streamId = streamInfo.id; - eventBus.trigger(eventType, payload); + eventBus.trigger(eventType, payload, { streamId: streamInfo.id, mediaType: type }); } function resetInitialSettings(errored, keepBuffers) { @@ -33871,12 +34140,13 @@ function BufferController(config) { } instance = { + initialize: initialize, + getStreamId: getStreamId, + getType: getType, getBufferControllerType: getBufferControllerType, getRepresentationInfo: getRepresentationInfo, - initialize: initialize, createBuffer: createBuffer, dischargePreBuffer: dischargePreBuffer, - getType: getType, getBuffer: getBuffer, setBuffer: setBuffer, getBufferLevel: getBufferLevel, @@ -33899,7 +34169,7 @@ BufferController.__dashjs_factory_name = BUFFER_CONTROLLER_TYPE; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BufferController); module.exports = exports['default']; -},{"103":103,"104":104,"108":108,"109":109,"111":111,"118":118,"150":150,"214":214,"226":226,"242":242,"45":45,"46":46,"47":47,"51":51,"54":54}],115:[function(_dereq_,module,exports){ +},{"103":103,"104":104,"108":108,"109":109,"111":111,"150":150,"220":220,"232":232,"248":248,"45":45,"46":46,"47":47,"51":51,"54":54}],115:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -33951,9 +34221,9 @@ var _coreEventBus = _dereq_(46); var _coreEventBus2 = _interopRequireDefault(_coreEventBus); -var _coreEventsEvents = _dereq_(54); +var _streamingMediaPlayerEvents = _dereq_(101); -var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents); +var _streamingMediaPlayerEvents2 = _interopRequireDefault(_streamingMediaPlayerEvents); var _netXHRLoader = _dereq_(160); @@ -34047,8 +34317,14 @@ function EventController() { if (values) { for (var i = 0; i < values.length; i++) { var _event = values[i]; - inlineEvents[_event.id] = _event; logger.debug('Add inline event with id ' + _event.id); + + // If we see the event for the first time we trigger it in onReceive mode + if (!inlineEvents[_event.id]) { + _startEvent(_event.id, _event, values, _streamingMediaPlayerEvents2['default'].EVENT_MODE_ON_RECEIVE); + } + + inlineEvents[_event.id] = _event; } } logger.debug('Added ' + values.length + ' inline events'); @@ -34073,6 +34349,7 @@ function EventController() { } inbandEvents[_event2.id] = _event2; logger.debug('Add inband event with id ' + _event2.id); + _startEvent(_event2.id, _event2, values, _streamingMediaPlayerEvents2['default'].EVENT_MODE_ON_RECEIVE); } else { logger.debug('Repeated event with id ' + _event2.id); } @@ -34086,21 +34363,22 @@ function EventController() { function _handleManifestReloadEvent(event) { try { if (event.eventStream.value == MPD_RELOAD_VALUE) { - var timescale = event.eventStream.timescale || 1; - var validUntil = event.calculatedPresentationTime / timescale; + var validUntil = event.calculatedPresentationTime; var newDuration = undefined; if (event.calculatedPresentationTime == 0xFFFFFFFF) { //0xFF... means remaining duration unknown newDuration = NaN; } else { - newDuration = (event.calculatedPresentationTime + event.duration) / timescale; + newDuration = event.calculatedPresentationTime + event.duration; } - logger.info('Manifest validity changed: Valid until: ' + validUntil + '; remaining duration: ' + newDuration); - eventBus.trigger(_coreEventsEvents2['default'].MANIFEST_VALIDITY_CHANGED, { + //logger.info('Manifest validity changed: Valid until: ' + validUntil + '; remaining duration: ' + newDuration); + eventBus.trigger(_streamingMediaPlayerEvents2['default'].MANIFEST_VALIDITY_CHANGED, { id: event.id, validUntil: validUntil, newDuration: newDuration, newManifestValidAfter: NaN //event.message_data - this is an arraybuffer with a timestring in it, but not used yet + }, { + mode: _streamingMediaPlayerEvents2['default'].EVENT_MODE_ON_START }); } } catch (e) {} @@ -34118,7 +34396,7 @@ function EventController() { for (var i = 0; i < eventIds.length; i++) { var eventId = eventIds[i]; var _event3 = activeEvents[eventId]; - if (_event3 !== null && (_event3.duration + _event3.calculatedPresentationTime) / _event3.eventStream.timescale < currentVideoTime) { + if (_event3 !== null && _event3.duration + _event3.calculatedPresentationTime < currentVideoTime) { logger.debug('Remove Event ' + eventId + ' at time ' + currentVideoTime); _event3 = null; delete activeEvents[eventId]; @@ -34134,6 +34412,7 @@ function EventController() { function _onEventTimer() { try { if (!eventHandlingInProgress) { + eventHandlingInProgress = true; var currentVideoTime = playbackController.getTime(); var presentationTimeThreshold = currentVideoTime - lastEventTimerCall; @@ -34145,8 +34424,8 @@ function EventController() { _removeEvents(); lastEventTimerCall = currentVideoTime; + eventHandlingInProgress = false; } - eventHandlingInProgress = false; } catch (e) { eventHandlingInProgress = false; } @@ -34170,11 +34449,11 @@ function EventController() { var _event4 = events[eventId]; if (_event4 !== undefined) { - var calculatedPresentationTimeInSeconds = _event4.calculatedPresentationTime / _event4.eventStream.timescale; - - if (calculatedPresentationTimeInSeconds <= currentVideoTime && calculatedPresentationTimeInSeconds + presentationTimeThreshold >= currentVideoTime) { - _startEvent(eventId, _event4, events); - } else if (_eventHasExpired(currentVideoTime, presentationTimeThreshold, calculatedPresentationTimeInSeconds) || _eventIsInvalid(_event4)) { + var duration = !isNaN(_event4.duration) ? _event4.duration : 0; + // The event is either about to start or has already been started and we are within its duration + if (_event4.calculatedPresentationTime <= currentVideoTime && _event4.calculatedPresentationTime + presentationTimeThreshold + duration >= currentVideoTime) { + _startEvent(eventId, _event4, events, _streamingMediaPlayerEvents2['default'].EVENT_MODE_ON_START); + } else if (_eventHasExpired(currentVideoTime, duration + presentationTimeThreshold, _event4.calculatedPresentationTime) || _eventIsInvalid(_event4)) { logger.debug('Deleting event ' + eventId + ' as it is expired or invalid'); delete events[eventId]; } @@ -34184,9 +34463,9 @@ function EventController() { } catch (e) {} } - function _eventHasExpired(currentVideoTime, presentationTimeThreshold, calculatedPresentationTimeInSeconds) { + function _eventHasExpired(currentVideoTime, threshold, calculatedPresentationTimeInSeconds) { try { - return currentVideoTime - presentationTimeThreshold > calculatedPresentationTimeInSeconds; + return currentVideoTime - threshold > calculatedPresentationTimeInSeconds; } catch (e) { return false; } @@ -34196,7 +34475,7 @@ function EventController() { try { var periodEndTime = event.eventStream.period.start + event.eventStream.period.duration; - return event.calculatedPresentationTime / 1000 > periodEndTime; + return event.calculatedPresentationTime > periodEndTime; } catch (e) { return false; } @@ -34225,10 +34504,10 @@ function EventController() { eventIds.forEach(function (eventId) { var event = events[eventId]; - var calculatedPresentationTimeInSeconds = event.calculatedPresentationTime / event.eventStream.timescale; + var calculatedPresentationTimeInSeconds = event.calculatedPresentationTime; if (Math.abs(calculatedPresentationTimeInSeconds - currentTime) < REMAINING_EVENTS_THRESHOLD) { - _startEvent(eventId, event, events); + _startEvent(eventId, event, events, _streamingMediaPlayerEvents2['default'].EVENT_MODE_ON_START); } }); })(); @@ -34237,26 +34516,32 @@ function EventController() { } catch (e) {} } - function _startEvent(eventId, event, events) { + function _startEvent(eventId, event, events, mode) { try { var currentVideoTime = playbackController.getTime(); + if (mode === _streamingMediaPlayerEvents2['default'].EVENT_MODE_ON_RECEIVE) { + logger.debug('Received event ' + eventId); + eventBus.trigger(event.eventStream.schemeIdUri, { event: event }, { mode: mode }); + return; + } + if (event.duration > 0) { activeEvents[eventId] = event; } - if (event.eventStream.schemeIdUri === MPD_RELOAD_SCHEME && event.eventStream.value == MPD_RELOAD_VALUE) { + if (event.eventStream.schemeIdUri === MPD_RELOAD_SCHEME && event.eventStream.value === MPD_RELOAD_VALUE) { if (event.duration !== 0 || event.presentationTimeDelta !== 0) { //If both are set to zero, it indicates the media is over at this point. Don't reload the manifest. logger.debug('Starting manifest refresh event ' + eventId + ' at ' + currentVideoTime); _refreshManifest(); } - } else if (event.eventStream.schemeIdUri === MPD_CALLBACK_SCHEME && event.eventStream.value == MPD_CALLBACK_VALUE) { + } else if (event.eventStream.schemeIdUri === MPD_CALLBACK_SCHEME && event.eventStream.value === MPD_CALLBACK_VALUE) { logger.debug('Starting callback event ' + eventId + ' at ' + currentVideoTime); _sendCallbackRequest(event.messageData); } else { logger.debug('Starting event ' + eventId + ' at ' + currentVideoTime); - eventBus.trigger(event.eventStream.schemeIdUri, { event: event }); + eventBus.trigger(event.eventStream.schemeIdUri, { event: event }, { mode: mode }); } delete events[eventId]; @@ -34325,7 +34610,7 @@ EventController.__dashjs_factory_name = 'EventController'; exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(EventController); module.exports = exports['default']; -},{"160":160,"45":45,"46":46,"47":47,"54":54}],116:[function(_dereq_,module,exports){ +},{"101":101,"160":160,"45":45,"46":46,"47":47}],116:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -34368,7 +34653,7 @@ var _constantsConstants = _dereq_(108); var _constantsConstants2 = _interopRequireDefault(_constantsConstants); -var _voDataChunk = _dereq_(227); +var _voDataChunk = _dereq_(233); var _voDataChunk2 = _interopRequireDefault(_voDataChunk); @@ -34380,7 +34665,7 @@ var _FragmentLoader = _dereq_(97); var _FragmentLoader2 = _interopRequireDefault(_FragmentLoader); -var _utilsRequestModifier = _dereq_(218); +var _utilsRequestModifier = _dereq_(224); var _utilsRequestModifier2 = _interopRequireDefault(_utilsRequestModifier); @@ -34414,11 +34699,11 @@ function FragmentController(config) { var mediaPlayerModel = config.mediaPlayerModel; var dashMetrics = config.dashMetrics; var debug = (0, _coreDebug2['default'])(context).getInstance(); + var streamInfo = config.streamInfo; var instance = undefined, logger = undefined, - fragmentModels = undefined, - streamId = undefined; + fragmentModels = undefined; function setup() { logger = debug.getLogger(instance); @@ -34427,11 +34712,16 @@ function FragmentController(config) { eventBus.on(_coreEventsEvents2['default'].FRAGMENT_LOADING_PROGRESS, onFragmentLoadingCompleted, instance); } - function getModel(streamId, type) { + function getStreamId() { + return streamInfo.id; + } + + function getModel(type) { var model = fragmentModels[type]; if (!model) { model = (0, _modelsFragmentModel2['default'])(context).create({ - streamId: streamId, + streamInfo: streamInfo, + type: type, dashMetrics: dashMetrics, fragmentLoader: (0, _FragmentLoader2['default'])(context).create({ dashMetrics: dashMetrics, @@ -34495,18 +34785,16 @@ function FragmentController(config) { var request = e.request; var bytes = e.response; var isInit = request.isInitializationRequest(); - var streamInfo = request.mediaInfo.streamInfo; - - if (streamInfo && streamInfo.id !== streamId) return; + var strInfo = request.mediaInfo.streamInfo; if (e.error) { - if (e.request.mediaType === _constantsConstants2['default'].AUDIO || e.request.mediaType === _constantsConstants2['default'].VIDEO || e.request.mediaType === _constantsConstants2['default'].FRAGMENTED_TEXT) { + if (request.mediaType === _constantsConstants2['default'].AUDIO || request.mediaType === _constantsConstants2['default'].VIDEO || request.mediaType === _constantsConstants2['default'].FRAGMENTED_TEXT) { // add service location to blacklist controller - only for audio or video. text should not set errors eventBus.trigger(_coreEventsEvents2['default'].SERVICE_LOCATION_BLACKLIST_ADD, { entry: e.request.serviceLocation }); } } - if (!bytes || !streamInfo) { + if (!bytes || !strInfo) { logger.warn('No ' + request.mediaType + ' bytes to push or stream is inactive.'); return; } @@ -34514,16 +34802,12 @@ function FragmentController(config) { eventBus.trigger(isInit ? _coreEventsEvents2['default'].INIT_FRAGMENT_LOADED : _coreEventsEvents2['default'].MEDIA_FRAGMENT_LOADED, { chunk: chunk, request: request - }); - } - - function setStreamId(id) { - streamId = id; + }, { streamId: strInfo.id, mediaType: request.mediaType }); } instance = { + getStreamId: getStreamId, getModel: getModel, - setStreamId: setStreamId, reset: reset }; @@ -34536,7 +34820,7 @@ FragmentController.__dashjs_factory_name = 'FragmentController'; exports['default'] = _coreFactoryMaker2['default'].getClassFactory(FragmentController); module.exports = exports['default']; -},{"108":108,"150":150,"218":218,"227":227,"45":45,"46":46,"47":47,"51":51,"54":54,"97":97}],117:[function(_dereq_,module,exports){ +},{"108":108,"150":150,"224":224,"233":233,"45":45,"46":46,"47":47,"51":51,"54":54,"97":97}],117:[function(_dereq_,module,exports){ /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor @@ -34592,7 +34876,7 @@ var _coreEventBus = _dereq_(46); var _coreEventBus2 = _interopRequireDefault(_coreEventBus); var GAP_HANDLER_INTERVAL = 100; -var THRESHOLD_TO_STALLS = 10; +var THRESHOLD_TO_STALLS = 30; var GAP_THRESHOLD = 0.1; function GapController() { @@ -34610,6 +34894,7 @@ function GapController() { videoModel = undefined, timelineConverter = undefined, adapter = undefined, + jumpTimeoutHandler = undefined, logger = undefined; function initialize() { @@ -34632,6 +34917,7 @@ function GapController() { gapHandlerInterval = null; lastGapJumpPosition = NaN; wallclockTicked = 0; + jumpTimeoutHandler = null; } function setConfig(config) { @@ -34659,13 +34945,15 @@ function GapController() { } function registerEvents() { - eventBus.on(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, this); - eventBus.on(_coreEventsEvents2['default'].BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this); + eventBus.on(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, _onWallclockTimeUpdated, this); + eventBus.on(_coreEventsEvents2['default'].PLAYBACK_SEEKING, _onPlaybackSeeking, this); + eventBus.on(_coreEventsEvents2['default'].BYTES_APPENDED_END_FRAGMENT, onBytesAppended, instance); } function unregisterEvents() { - eventBus.off(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, this); - eventBus.off(_coreEventsEvents2['default'].BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this); + eventBus.off(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, _onWallclockTimeUpdated, this); + eventBus.off(_coreEventsEvents2['default'].PLAYBACK_SEEKING, _onPlaybackSeeking, this); + eventBus.off(_coreEventsEvents2['default'].BYTES_APPENDED_END_FRAGMENT, onBytesAppended, instance); } function onBytesAppended() { @@ -34674,11 +34962,14 @@ function GapController() { } } - function _shouldCheckForGaps() { - return settings.get().streaming.jumpGaps && streamController.getActiveStreamProcessors().length > 0 && (!playbackController.isSeeking() || streamController.hasStreamFinishedBuffering(streamController.getActiveStream())) && !playbackController.isPaused() && !streamController.getIsStreamSwitchInProgress() && !streamController.getHasMediaOrIntialisationError(); + function _onPlaybackSeeking() { + if (jumpTimeoutHandler) { + clearTimeout(jumpTimeoutHandler); + jumpTimeoutHandler = null; + } } - function onWallclockTimeUpdated() /*e*/{ + function _onWallclockTimeUpdated() /*e*/{ if (!_shouldCheckForGaps()) { return; } @@ -34696,23 +34987,27 @@ function GapController() { } } - function getNextRangeStartTime(currentTime) { + function _shouldCheckForGaps() { + return settings.get().streaming.jumpGaps && streamController.getActiveStreamProcessors().length > 0 && (!playbackController.isSeeking() || streamController.hasStreamFinishedBuffering(streamController.getActiveStream())) && !playbackController.isPaused() && !streamController.getIsStreamSwitchInProgress() && !streamController.getHasMediaOrIntialisationError(); + } + + function getNextRangeIndex(ranges, currentTime) { try { - var ranges = videoModel.getBufferRange(); + if (!ranges || ranges.length <= 1 && currentTime > 0) { - return null; + return NaN; } - var nextRangeStartTime = null; + var nextRangeIndex = NaN; var j = 0; - while (!nextRangeStartTime && j < ranges.length) { + while (isNaN(nextRangeIndex) && j < ranges.length) { var rangeEnd = j > 0 ? ranges.end(j - 1) : 0; if (currentTime < ranges.start(j) && rangeEnd - currentTime < GAP_THRESHOLD) { - nextRangeStartTime = ranges.start(j); + nextRangeIndex = j; } j += 1; } - return nextRangeStartTime; + return nextRangeIndex; } catch (e) { return null; } @@ -34746,36 +35041,58 @@ function GapController() { var smallGapLimit = settings.get().streaming.smallGapLimit; var jumpLargeGaps = settings.get().streaming.jumpLargeGaps; - var nextRangeStartTime = null; + var ranges = videoModel.getBufferRange(); + var nextRangeIndex = undefined; var seekToPosition = NaN; var jumpToStreamEnd = false; // Get the range just after current time position - nextRangeStartTime = getNextRangeStartTime(currentTime); + nextRangeIndex = getNextRangeIndex(ranges, currentTime); - if (nextRangeStartTime && nextRangeStartTime > 0) { - var gap = nextRangeStartTime - currentTime; + if (!isNaN(nextRangeIndex)) { + var start = ranges.start(nextRangeIndex); + var gap = start - currentTime; if (gap > 0 && (gap <= smallGapLimit || jumpLargeGaps)) { - seekToPosition = nextRangeStartTime; + seekToPosition = start; } } // Playback has stalled before period end. We seek to the end of the period var timeToStreamEnd = playbackController.getTimeToStreamEnd(); - if (isNaN(seekToPosition) && playbackStalled && isFinite(timeToStreamEnd) && !isNaN(timeToStreamEnd) && (timeToStreamEnd < smallGapLimit || streamController.hasStreamFinishedBuffering(streamController.getActiveStream()))) { + if (isNaN(seekToPosition) && playbackStalled && isFinite(timeToStreamEnd) && !isNaN(timeToStreamEnd) && timeToStreamEnd < smallGapLimit) { seekToPosition = parseFloat(playbackController.getStreamEndTime().toFixed(5)); jumpToStreamEnd = true; } - if (seekToPosition > 0 && lastGapJumpPosition !== seekToPosition) { - if (jumpToStreamEnd) { - logger.warn('Jumping to end of stream because of gap from ' + currentTime + ' to ' + seekToPosition + '. Gap duration: ' + (seekToPosition - currentTime)); - eventBus.trigger(_coreEventsEvents2['default'].GAP_CAUSED_SEEK_TO_PERIOD_END, { seekTime: seekToPosition }); - } else { - logger.warn('Jumping gap from ' + currentTime + ' to ' + seekToPosition + '. Gap duration: ' + (seekToPosition - currentTime)); - playbackController.seek(seekToPosition, true, true); - } - lastGapJumpPosition = seekToPosition; + if (seekToPosition > 0 && lastGapJumpPosition !== seekToPosition && seekToPosition > currentTime && !jumpTimeoutHandler) { + (function () { + var timeUntilGapEnd = seekToPosition - currentTime; + + if (jumpToStreamEnd) { + logger.warn('Jumping to end of stream because of gap from ' + currentTime + ' to ' + seekToPosition + '. Gap duration: ' + timeUntilGapEnd); + eventBus.trigger(_coreEventsEvents2['default'].GAP_CAUSED_SEEK_TO_PERIOD_END, { + seekTime: seekToPosition, + duration: timeUntilGapEnd + }); + } else { + (function () { + var isDynamic = playbackController.getIsDynamic(); + var start = nextRangeIndex > 0 ? ranges.end(nextRangeIndex - 1) : currentTime; + var timeToWait = !isDynamic ? 0 : timeUntilGapEnd * 1000; + + jumpTimeoutHandler = window.setTimeout(function () { + playbackController.seek(seekToPosition, true, true); + logger.warn('Jumping gap starting at ' + start + ' and ending at ' + seekToPosition + '. Jumping by: ' + timeUntilGapEnd); + eventBus.trigger(_coreEventsEvents2['default'].GAP_CAUSED_INTERNAL_SEEK, { + seekTime: seekToPosition, + duration: timeUntilGapEnd + }); + jumpTimeoutHandler = null; + }, timeToWait); + })(); + } + lastGapJumpPosition = seekToPosition; + })(); } } @@ -34853,12 +35170,6 @@ var _coreDebug = _dereq_(45); var _coreDebug2 = _interopRequireDefault(_coreDebug); -var TRACK_SWITCH_MODE_NEVER_REPLACE = 'neverReplace'; -var TRACK_SWITCH_MODE_ALWAYS_REPLACE = 'alwaysReplace'; -var TRACK_SELECTION_MODE_HIGHEST_BITRATE = 'highestBitrate'; -var TRACK_SELECTION_MODE_WIDEST_RANGE = 'widestRange'; -var DEFAULT_INIT_TRACK_SELECTION_MODE = TRACK_SELECTION_MODE_HIGHEST_BITRATE; - function MediaController() { var context = this.context; @@ -34867,14 +35178,13 @@ function MediaController() { var instance = undefined, logger = undefined, tracks = undefined, + settings = undefined, initialSettings = undefined, - selectionMode = undefined, - switchMode = undefined, domStorage = undefined; - var validTrackSwitchModes = [TRACK_SWITCH_MODE_ALWAYS_REPLACE, TRACK_SWITCH_MODE_NEVER_REPLACE]; + var validTrackSwitchModes = [_constantsConstants2['default'].TRACK_SWITCH_MODE_ALWAYS_REPLACE, _constantsConstants2['default'].TRACK_SWITCH_MODE_NEVER_REPLACE]; - var validTrackSelectionModes = [TRACK_SELECTION_MODE_HIGHEST_BITRATE, TRACK_SELECTION_MODE_WIDEST_RANGE]; + var validTrackSelectionModes = [_constantsConstants2['default'].TRACK_SELECTION_MODE_HIGHEST_BITRATE, _constantsConstants2['default'].TRACK_SELECTION_MODE_WIDEST_RANGE]; function setup() { logger = (0, _coreDebug2['default'])(context).getInstance().getLogger(instance); @@ -35008,29 +35318,33 @@ function MediaController() { tracks[id][type].current = track; if (tracks[id][type].current && !(noSettingsSave && type === _constantsConstants2['default'].FRAGMENTED_TEXT)) { - eventBus.trigger(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, { oldMediaInfo: current, newMediaInfo: track, switchMode: switchMode[type] }); + eventBus.trigger(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, { + oldMediaInfo: current, + newMediaInfo: track, + switchMode: getSwitchMode(type) + }); } if (!noSettingsSave) { - var settings = extractSettings(track); + var _settings = extractSettings(track); - if (!settings || !tracks[id][type].storeLastSettings) return; + if (!_settings || !tracks[id][type].storeLastSettings) return; - if (settings.roles) { - settings.role = settings.roles[0]; - delete settings.roles; + if (_settings.roles) { + _settings.role = _settings.roles[0]; + delete _settings.roles; } - if (settings.accessibility) { - settings.accessibility = settings.accessibility[0]; + if (_settings.accessibility) { + _settings.accessibility = _settings.accessibility[0]; } - if (settings.audioChannelConfiguration) { - settings.audioChannelConfiguration = settings.audioChannelConfiguration[0]; + if (_settings.audioChannelConfiguration) { + _settings.audioChannelConfiguration = _settings.audioChannelConfiguration[0]; } - domStorage.setSavedMediaSettings(type, settings); + domStorage.setSavedMediaSettings(type, _settings); } } @@ -35067,8 +35381,10 @@ function MediaController() { * @param {string} type * @param {string} mode * @memberof MediaController# + * @deprecated Please use updateSettings({streaming: { trackSwitchMode: mode } }) instead */ function setSwitchMode(type, mode) { + logger.warn('deprecated: Please use updateSettings({streaming: { trackSwitchMode: mode } }) instead'); var isModeSupported = validTrackSwitchModes.indexOf(mode) !== -1; if (!isModeSupported) { @@ -35076,7 +35392,14 @@ function MediaController() { return; } + var switchMode = {}; switchMode[type] = mode; + + settings.update({ + streaming: { + trackSwitchMode: switchMode + } + }); } /** @@ -35085,21 +35408,28 @@ function MediaController() { * @memberof MediaController# */ function getSwitchMode(type) { - return switchMode[type]; + return settings.get().streaming.trackSwitchMode[type]; } /** * @param {string} mode * @memberof MediaController# + * @deprecated Please use updateSettings({streaming: { selectionModeForInitialTrack: mode } }) instead */ function setSelectionModeForInitialTrack(mode) { + logger.warn('deprecated: Please use updateSettings({streaming: { selectionModeForInitialTrack: mode } }) instead'); var isModeSupported = validTrackSelectionModes.indexOf(mode) !== -1; if (!isModeSupported) { logger.warn('Track selection mode is not supported: ' + mode); return; } - selectionMode = mode; + + settings.update({ + streaming: { + selectionModeForInitialTrack: mode + } + }); } /** @@ -35107,7 +35437,7 @@ function MediaController() { * @memberof MediaController# */ function getSelectionModeForInitialTrack() { - return selectionMode || DEFAULT_INIT_TRACK_SELECTION_MODE; + return settings.get().streaming.selectionModeForInitialTrack; } /** @@ -35150,6 +35480,10 @@ function MediaController() { if (config.domStorage) { domStorage = config.domStorage; } + + if (config.settings) { + settings = config.settings; + } } /** @@ -35158,7 +35492,6 @@ function MediaController() { function reset() { tracks = {}; resetInitialSettings(); - resetSwitchMode(); } function extractSettings(mediaInfo) { @@ -35190,13 +35523,6 @@ function MediaController() { return matchLang && matchViewPoint && matchRole && matchAccessibility && matchAudioChannelConfiguration; } - function resetSwitchMode() { - switchMode = { - audio: TRACK_SWITCH_MODE_ALWAYS_REPLACE, - video: TRACK_SWITCH_MODE_NEVER_REPLACE - }; - } - function resetInitialSettings() { initialSettings = { audio: null, @@ -35251,14 +35577,14 @@ function MediaController() { }; switch (mode) { - case TRACK_SELECTION_MODE_HIGHEST_BITRATE: + case _constantsConstants2['default'].TRACK_SELECTION_MODE_HIGHEST_BITRATE: tmpArr = getTracksWithHighestBitrate(tracks); if (tmpArr.length > 1) { tmpArr = getTracksWithWidestRange(tmpArr); } break; - case TRACK_SELECTION_MODE_WIDEST_RANGE: + case _constantsConstants2['default'].TRACK_SELECTION_MODE_WIDEST_RANGE: tmpArr = getTracksWithWidestRange(tracks); if (tmpArr.length > 1) { @@ -35331,11 +35657,6 @@ function MediaController() { MediaController.__dashjs_factory_name = 'MediaController'; var factory = _coreFactoryMaker2['default'].getSingletonFactory(MediaController); -factory.TRACK_SWITCH_MODE_NEVER_REPLACE = TRACK_SWITCH_MODE_NEVER_REPLACE; -factory.TRACK_SWITCH_MODE_ALWAYS_REPLACE = TRACK_SWITCH_MODE_ALWAYS_REPLACE; -factory.TRACK_SELECTION_MODE_HIGHEST_BITRATE = TRACK_SELECTION_MODE_HIGHEST_BITRATE; -factory.TRACK_SELECTION_MODE_WIDEST_RANGE = TRACK_SELECTION_MODE_WIDEST_RANGE; -factory.DEFAULT_INIT_TRACK_SELECTION_MODE = DEFAULT_INIT_TRACK_SELECTION_MODE; _coreFactoryMaker2['default'].updateSingletonFactory(MediaController.__dashjs_factory_name, factory); exports['default'] = factory; module.exports = exports['default']; @@ -35597,7 +35918,7 @@ function PlaybackController() { eventBus.on(_coreEventsEvents2['default'].BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this); eventBus.on(_coreEventsEvents2['default'].PLAYBACK_PROGRESS, onPlaybackProgression, this); eventBus.on(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, onPlaybackProgression, this); - eventBus.on(_coreEventsEvents2['default'].PLAYBACK_ENDED, onPlaybackEnded, this); + eventBus.on(_coreEventsEvents2['default'].PLAYBACK_ENDED, onPlaybackEnded, this, { priority: _coreEventBus2['default'].EVENT_PRIORITY_HIGH }); eventBus.on(_coreEventsEvents2['default'].STREAM_INITIALIZING, onStreamInitializing, this); if (playOnceInitialized) { @@ -35624,7 +35945,7 @@ function PlaybackController() { var dvrWindow = dvrInfo ? dvrInfo.range : null; if (dvrWindow) { // #t shall be relative to period start - var startTimeFromUri = getStartTimeFromUriParameters(streamInfo.start, true); + var startTimeFromUri = getStartTimeFromUriParameters(true); if (!isNaN(startTimeFromUri)) { logger.info('Start time from URI parameters: ' + startTimeFromUri); startTime = Math.max(Math.min(startTime, startTimeFromUri), dvrWindow.start); @@ -35634,7 +35955,7 @@ function PlaybackController() { // For static stream, start by default at period start startTime = streamInfo.start; // If start time in URI, take max value between period start and time from URI (if in period range) - var startTimeFromUri = getStartTimeFromUriParameters(streamInfo.start, false); + var startTimeFromUri = getStartTimeFromUriParameters(false); if (!isNaN(startTimeFromUri) && startTimeFromUri < startTime + streamInfo.duration) { logger.info('Start time from URI parameters: ' + startTimeFromUri); startTime = Math.max(startTime, startTimeFromUri); @@ -35644,9 +35965,7 @@ function PlaybackController() { if (!isNaN(startTime) && startTime !== videoModel.getTime()) { // Trigger PLAYBACK_SEEKING event for controllers - eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_SEEKING, { - seekTime: startTime - }); + eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_SEEKING, { seekTime: startTime }); // Seek video model seek(startTime, false, true); } @@ -35879,22 +36198,20 @@ function PlaybackController() { } } - function getStartTimeFromUriParameters(rangeStart, isDynamic) { + function getStartTimeFromUriParameters(isDynamic) { var fragData = uriFragmentModel.getURIFragmentData(); if (!fragData || !fragData.t) { return NaN; } - - var startTime = NaN; - + var refStream = streamController.getStreams()[0]; + var refStreamStartTime = refStream.getStreamInfo().start; // Consider only start time of MediaRange // TODO: consider end time of MediaRange to stop playback at provided end time fragData.t = fragData.t.split(',')[0]; - - // "t=