UNPKG

dashjs

Version:

A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.

32 lines 1.62 MB
<html>
<head>
</head>
<body style="background: transparent;">
    <script src="scripts/docstrap.lib.js"></script>
    <script src="scripts/lunr.min.js"></script>
    <script src="scripts/fulltext-search.js"></script>

    <script type="text/x-docstrap-searchdb">
    {"streaming_controllers_AbrController.js.html":{"id":"streaming_controllers_AbrController.js.html","title":"Source: streaming/controllers/AbrController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/AbrController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import ABRRulesCollection from '../rules/abr/ABRRulesCollection'; import Constants from '../constants/Constants'; import MetricsConstants from '../constants/MetricsConstants'; import BitrateInfo from '../vo/BitrateInfo'; import FragmentModel from '../models/FragmentModel'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; import RulesContext from '../rules/RulesContext'; import SwitchRequest from '../rules/SwitchRequest'; import SwitchRequestHistory from '../rules/SwitchRequestHistory'; import DroppedFramesHistory from '../rules/DroppedFramesHistory'; import ThroughputHistory from '../rules/ThroughputHistory'; import Debug from '../../core/Debug'; import {HTTPRequest} from '../vo/metrics/HTTPRequest'; import {checkInteger} from '../utils/SupervisorTools'; import MediaPlayerEvents from '../MediaPlayerEvents'; const DEFAULT_VIDEO_BITRATE = 1000; const DEFAULT_AUDIO_BITRATE = 100; const QUALITY_DEFAULT = 0; function AbrController() { const context = this.context; const debug = Debug(context).getInstance(); const eventBus = EventBus(context).getInstance(); let instance, logger, abrRulesCollection, streamController, topQualities, qualityDict, streamProcessorDict, abandonmentStateDict, abandonmentTimeout, windowResizeEventCalled, elementWidth, elementHeight, adapter, videoModel, mediaPlayerModel, customParametersModel, domStorage, playbackIndex, switchHistoryDict, droppedFramesHistory, throughputHistory, isUsingBufferOccupancyAbrDict, isUsingL2AAbrDict, isUsingLoLPAbrDict, dashMetrics, settings; function setup() { logger = debug.getLogger(instance); resetInitialSettings(); } /** * Initialize everything that is not Stream specific. We only have one instance of the ABR Controller for all periods. */ function initialize() { droppedFramesHistory = DroppedFramesHistory(context).create(); throughputHistory = ThroughputHistory(context).create({ settings }); abrRulesCollection = ABRRulesCollection(context).create({ dashMetrics, customParametersModel, mediaPlayerModel, settings }); abrRulesCollection.initialize(); eventBus.on(MediaPlayerEvents.QUALITY_CHANGE_RENDERED, _onQualityChangeRendered, instance); eventBus.on(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); eventBus.on(Events.LOADING_PROGRESS, _onFragmentLoadProgress, instance); } /** * Whenever a StreamProcessor is created it is added to the list of streamProcessorDict * In addition, the corresponding objects for this object and its stream id are created * @param {object} type * @param {object} streamProcessor */ function registerStreamType(type, streamProcessor) { const streamId = streamProcessor.getStreamInfo().id; if (!streamProcessorDict[streamId]) { streamProcessorDict[streamId] = {}; } if (!switchHistoryDict[streamId]) { switchHistoryDict[streamId] = {}; } if (!abandonmentStateDict[streamId]) { abandonmentStateDict[streamId] = {}; } switchHistoryDict[streamId][type] = SwitchRequestHistory(context).create(); streamProcessorDict[streamId][type] = streamProcessor; abandonmentStateDict[streamId][type] = {}; abandonmentStateDict[streamId][type].state = MetricsConstants.ALLOW_LOAD; _initializeAbrStrategy(type); if (type === Constants.VIDEO) { setElementSize(); } } function _initializeAbrStrategy(type) { const strategy = settings.get().streaming.abr.ABRStrategy; if (strategy === Constants.ABR_STRATEGY_L2A) { isUsingBufferOccupancyAbrDict[type] = false; isUsingLoLPAbrDict[type] = false; isUsingL2AAbrDict[type] = true; } else if (strategy === Constants.ABR_STRATEGY_LoLP) { isUsingBufferOccupancyAbrDict[type] = false; isUsingLoLPAbrDict[type] = true; isUsingL2AAbrDict[type] = false; } else if (strategy === Constants.ABR_STRATEGY_BOLA) { isUsingBufferOccupancyAbrDict[type] = true; isUsingLoLPAbrDict[type] = false; isUsingL2AAbrDict[type] = false; } else if (strategy === Constants.ABR_STRATEGY_THROUGHPUT) { isUsingBufferOccupancyAbrDict[type] = false; isUsingLoLPAbrDict[type] = false; isUsingL2AAbrDict[type] = false; } else if (strategy === Constants.ABR_STRATEGY_DYNAMIC) { isUsingBufferOccupancyAbrDict[type] = isUsingBufferOccupancyAbrDict &amp;&amp; isUsingBufferOccupancyAbrDict[type] ? isUsingBufferOccupancyAbrDict[type] : false; isUsingLoLPAbrDict[type] = false; isUsingL2AAbrDict[type] = false; } } function unRegisterStreamType(streamId, type) { try { if (streamProcessorDict[streamId] &amp;&amp; streamProcessorDict[streamId][type]) { delete streamProcessorDict[streamId][type]; } if (switchHistoryDict[streamId] &amp;&amp; switchHistoryDict[streamId][type]) { delete switchHistoryDict[streamId][type]; } if (abandonmentStateDict[streamId] &amp;&amp; abandonmentStateDict[streamId][type]) { delete abandonmentStateDict[streamId][type]; } } catch (e) { } } function resetInitialSettings() { topQualities = {}; qualityDict = {}; abandonmentStateDict = {}; streamProcessorDict = {}; switchHistoryDict = {}; isUsingBufferOccupancyAbrDict = {}; isUsingL2AAbrDict = {}; isUsingLoLPAbrDict = {}; if (windowResizeEventCalled === undefined) { windowResizeEventCalled = false; } if (droppedFramesHistory) { droppedFramesHistory.reset(); } playbackIndex = undefined; droppedFramesHistory = undefined; throughputHistory = undefined; clearTimeout(abandonmentTimeout); abandonmentTimeout = null; } function reset() { resetInitialSettings(); eventBus.off(Events.LOADING_PROGRESS, _onFragmentLoadProgress, instance); eventBus.off(MediaPlayerEvents.QUALITY_CHANGE_RENDERED, _onQualityChangeRendered, instance); eventBus.off(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); if (abrRulesCollection) { abrRulesCollection.reset(); } } function setConfig(config) { if (!config) return; if (config.streamController) { streamController = config.streamController; } if (config.domStorage) { domStorage = config.domStorage; } if (config.mediaPlayerModel) { mediaPlayerModel = config.mediaPlayerModel; } if (config.customParametersModel) { customParametersModel = config.customParametersModel; } if (config.dashMetrics) { dashMetrics = config.dashMetrics; } if (config.adapter) { adapter = config.adapter; } if (config.videoModel) { videoModel = config.videoModel; } if (config.settings) { settings = config.settings; } } function checkConfig() { if (!domStorage || !domStorage.hasOwnProperty('getSavedBitrateSettings')) { throw new Error(Constants.MISSING_CONFIG_ERROR); } } /** * While fragment loading is in progress we check if we might need to abort the request * @param {object} e * @private */ function _onFragmentLoadProgress(e) { const type = e.request.mediaType; const streamId = e.streamId; if (!type || !streamId || !streamProcessorDict[streamId] || !settings.get().streaming.abr.autoSwitchBitrate[type]) { return; } const streamProcessor = streamProcessorDict[streamId][type]; if (!streamProcessor) { return; } const rulesContext = RulesContext(context).create({ abrController: instance, streamProcessor: streamProcessor, currentRequest: e.request, useBufferOccupancyABR: isUsingBufferOccupancyAbrDict[type], useL2AABR: isUsingL2AAbrDict[type], useLoLPABR: isUsingLoLPAbrDict[type], videoModel }); const switchRequest = abrRulesCollection.shouldAbandonFragment(rulesContext, streamId); if (switchRequest.quality &gt; SwitchRequest.NO_CHANGE) { const fragmentModel = streamProcessor.getFragmentModel(); const request = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_LOADING, index: e.request.index })[0]; if (request) { abandonmentStateDict[streamId][type].state = MetricsConstants.ABANDON_LOAD; switchHistoryDict[streamId][type].reset(); switchHistoryDict[streamId][type].push({ oldValue: getQualityFor(type, streamId), newValue: switchRequest.quality, confidence: 1, reason: switchRequest.reason }); setPlaybackQuality(type, streamController.getActiveStreamInfo(), switchRequest.quality, switchRequest.reason); clearTimeout(abandonmentTimeout); abandonmentTimeout = setTimeout( () =&gt; { abandonmentStateDict[streamId][type].state = MetricsConstants.ALLOW_LOAD; abandonmentTimeout = null; }, settings.get().streaming.abandonLoadTimeout ); } } } /** * Update dropped frames history when the quality was changed * @param {object} e * @private */ function _onQualityChangeRendered(e) { if (e.mediaType === Constants.VIDEO) { if (playbackIndex !== undefined) { droppedFramesHistory.push(e.streamId, playbackIndex, videoModel.getPlaybackQuality()); } playbackIndex = e.newQuality; } } /** * When the buffer level is updated we check if we need to change the ABR strategy * @param e * @private */ function _onMetricAdded(e) { if (e.metric === MetricsConstants.HTTP_REQUEST &amp;&amp; e.value &amp;&amp; e.value.type === HTTPRequest.MEDIA_SEGMENT_TYPE &amp;&amp; (e.mediaType === Constants.AUDIO || e.mediaType === Constants.VIDEO)) { throughputHistory.push(e.mediaType, e.value, settings.get().streaming.abr.useDeadTimeLatency); } if (e.metric === MetricsConstants.BUFFER_LEVEL &amp;&amp; (e.mediaType === Constants.AUDIO || e.mediaType === Constants.VIDEO)) { _updateAbrStrategy(e.mediaType, 0.001 * e.value.level); } } /** * Returns the highest possible index taking limitations like maxBitrate, representationRatio and portal size into account. * @param {string} type * @param {string} streamId * @return {number} */ function getMaxAllowedIndexFor(type, streamId) { try { let idx; topQualities[streamId] = topQualities[streamId] || {}; if (!topQualities[streamId].hasOwnProperty(type)) { topQualities[streamId][type] = 0; } idx = _checkMaxBitrate(type, streamId); idx = _checkMaxRepresentationRatio(idx, type, streamId); idx = _checkPortalSize(idx, type, streamId); return idx; } catch (e) { return undefined } } /** * Returns the minimum allowed index. We consider thresholds defined in the settings, i.e. minBitrate for the corresponding media type. * @param {string} type * @param {string} streamId * @return {undefined|number} */ function getMinAllowedIndexFor(type, streamId) { try { return _getMinIndexBasedOnBitrateFor(type, streamId); } catch (e) { return undefined } } /** * Returns the maximum allowed index. * @param {string} type * @param {string} streamId * @return {undefined|number} */ function _getMaxIndexBasedOnBitrateFor(type, streamId) { try { const maxBitrate = mediaPlayerModel.getAbrBitrateParameter('maxBitrate', type); if (maxBitrate &gt; -1) { return getQualityForBitrate(streamProcessorDict[streamId][type].getMediaInfo(), maxBitrate, streamId); } else { return undefined; } } catch (e) { return undefined } } /** * Returns the minimum allowed index. * @param {string} type * @param {string} streamId * @return {undefined|number} */ function _getMinIndexBasedOnBitrateFor(type, streamId) { try { const minBitrate = mediaPlayerModel.getAbrBitrateParameter('minBitrate', type); if (minBitrate &gt; -1) { const mediaInfo = streamProcessorDict[streamId][type].getMediaInfo(); const bitrateList = getBitrateList(mediaInfo); // This returns the quality index &lt;= for the given bitrate let minIdx = getQualityForBitrate(mediaInfo, minBitrate, streamId); if (bitrateList[minIdx] &amp;&amp; minIdx &lt; bitrateList.length - 1 &amp;&amp; bitrateList[minIdx].bitrate &lt; minBitrate * 1000) { minIdx++; // Go to the next bitrate } return minIdx; } else { return undefined; } } catch (e) { return undefined; } } /** * Returns the maximum possible index * @param type * @param streamId * @return {number|*} */ function _checkMaxBitrate(type, streamId) { let idx = topQualities[streamId][type]; let newIdx = idx; if (!streamProcessorDict[streamId] || !streamProcessorDict[streamId][type]) { return newIdx; } const minIdx = getMinAllowedIndexFor(type, streamId); if (minIdx !== undefined) { newIdx = Math.max(idx, minIdx); } const maxIdx = _getMaxIndexBasedOnBitrateFor(type, streamId); if (maxIdx !== undefined) { newIdx = Math.min(newIdx, maxIdx); } return newIdx; } /** * Returns the maximum index according to maximum representation ratio * @param idx * @param type * @param streamId * @return {number|*} * @private */ function _checkMaxRepresentationRatio(idx, type, streamId) { let maxIdx = topQualities[streamId][type] const maxRepresentationRatio = settings.get().streaming.abr.maxRepresentationRatio[type]; if (isNaN(maxRepresentationRatio) || maxRepresentationRatio &gt;= 1 || maxRepresentationRatio &lt; 0) { return idx; } return Math.min(idx, Math.round(maxIdx * maxRepresentationRatio)); } /** * Returns the maximum index according to the portal size * @param idx * @param type * @param streamId * @return {number|*} * @private */ function _checkPortalSize(idx, type, streamId) { if (type !== Constants.VIDEO || !settings.get().streaming.abr.limitBitrateByPortal || !streamProcessorDict[streamId] || !streamProcessorDict[streamId][type]) { return idx; } if (!windowResizeEventCalled) { setElementSize(); } const streamInfo = streamProcessorDict[streamId][type].getStreamInfo(); const representation = adapter.getAdaptationForType(streamInfo.index, type, streamInfo).Representation_asArray; let newIdx = idx; if (elementWidth &gt; 0 &amp;&amp; elementHeight &gt; 0) { while ( newIdx &gt; 0 &amp;&amp; representation[newIdx] &amp;&amp; elementWidth &lt; representation[newIdx].width &amp;&amp; elementWidth - representation[newIdx - 1].width &lt; representation[newIdx].width - elementWidth) { newIdx = newIdx - 1; } // Make sure that in case of multiple representation elements have same // resolution, every such element is included while (newIdx &lt; representation.length - 1 &amp;&amp; representation[newIdx].width === representation[newIdx + 1].width) { newIdx = newIdx + 1; } } return newIdx; } /** * Gets top BitrateInfo for the player * @param {string} type - 'video' or 'audio' are the type options. * @param {string} streamId - Id of the stream * @returns {BitrateInfo | null} */ function getTopBitrateInfoFor(type, streamId = null) { if (!streamId) { streamId = streamController.getActiveStreamInfo().id; } if (type &amp;&amp; streamProcessorDict &amp;&amp; streamProcessorDict[streamId] &amp;&amp; streamProcessorDict[streamId][type]) { const idx = getMaxAllowedIndexFor(type, streamId); const bitrates = getBitrateList(streamProcessorDict[streamId][type].getMediaInfo()); return bitrates[idx] ? bitrates[idx] : null; } return null; } /** * Returns the initial bitrate for a specific media type and stream id * @param {string} type * @param {string} streamId * @returns {number} A value of the initial bitrate, kbps * @memberof AbrController# */ function getInitialBitrateFor(type, streamId) { checkConfig(); if (type === Constants.TEXT) { return NaN; } const savedBitrate = domStorage.getSavedBitrateSettings(type); let configBitrate = mediaPlayerModel.getAbrBitrateParameter('initialBitrate', type); let configRatio = settings.get().streaming.abr.initialRepresentationRatio[type]; if (configBitrate === -1) { if (configRatio &gt; -1) { const streamInfo = streamProcessorDict[streamId][type].getStreamInfo(); const representation = adapter.getAdaptationForType(streamInfo.index, type, streamInfo).Representation_asArray; if (Array.isArray(representation)) { const repIdx = Math.max(Math.round(representation.length * configRatio) - 1, 0); configBitrate = representation[repIdx].bandwidth / 1000; } else { configBitrate = 0; } } else if (!isNaN(savedBitrate)) { configBitrate = savedBitrate; } else { configBitrate = (type === Constants.VIDEO) ? DEFAULT_VIDEO_BITRATE : DEFAULT_AUDIO_BITRATE; } } return configBitrate; } /** * This function is called by the scheduleControllers to check if the quality should be changed. * Consider this the main entry point for the ABR decision logic * @param {string} type * @param {string} streamId */ function checkPlaybackQuality(type, streamId) { try { if (!type || !streamProcessorDict || !streamProcessorDict[streamId] || !streamProcessorDict[streamId][type]) { return false; } if (droppedFramesHistory) { const playbackQuality = videoModel.getPlaybackQuality(); if (playbackQuality) { droppedFramesHistory.push(streamId, playbackIndex, playbackQuality); } } // ABR is turned off, do nothing if (!settings.get().streaming.abr.autoSwitchBitrate[type]) { return false; } const oldQuality = getQualityFor(type, streamId); const rulesContext = RulesContext(context).create({ abrController: instance, switchHistory: switchHistoryDict[streamId][type], droppedFramesHistory: droppedFramesHistory, streamProcessor: streamProcessorDict[streamId][type], currentValue: oldQuality, useBufferOccupancyABR: isUsingBufferOccupancyAbrDict[type], useL2AABR: isUsingL2AAbrDict[type], useLoLPABR: isUsingLoLPAbrDict[type], videoModel }); const minIdx = getMinAllowedIndexFor(type, streamId); const maxIdx = getMaxAllowedIndexFor(type, streamId); const switchRequest = abrRulesCollection.getMaxQuality(rulesContext); let newQuality = switchRequest.quality; if (minIdx !== undefined &amp;&amp; ((newQuality &gt; SwitchRequest.NO_CHANGE) ? newQuality : oldQuality) &lt; minIdx) { newQuality = minIdx; } if (newQuality &gt; maxIdx) { newQuality = maxIdx; } switchHistoryDict[streamId][type].push({ oldValue: oldQuality, newValue: newQuality }); if (newQuality &gt; SwitchRequest.NO_CHANGE &amp;&amp; newQuality !== oldQuality &amp;&amp; (abandonmentStateDict[streamId][type].state === MetricsConstants.ALLOW_LOAD || newQuality &lt; oldQuality)) { _changeQuality(type, oldQuality, newQuality, maxIdx, switchRequest.reason, streamId); return true; } return false; } catch (e) { return false; } } /** * Returns the current quality for a specific media type and a specific streamId * @param {string} type * @param {string} streamId * @return {number|*} */ function getQualityFor(type, streamId = null) { try { if (!streamId) { streamId = streamController.getActiveStreamInfo().id; } if (type &amp;&amp; streamProcessorDict[streamId] &amp;&amp; streamProcessorDict[streamId][type]) { let quality; if (streamId) { qualityDict[streamId] = qualityDict[streamId] || {}; if (!qualityDict[streamId].hasOwnProperty(type)) { qualityDict[streamId][type] = QUALITY_DEFAULT; } quality = qualityDict[streamId][type]; return quality; } } return QUALITY_DEFAULT; } catch (e) { return QUALITY_DEFAULT; } } /** * Sets the new playback quality. Starts from index 0. * If the index of the new quality is the same as the old one changeQuality will not be called. * @param {string} type * @param {object} streamInfo * @param {number} newQuality * @param {string} reason */ function setPlaybackQuality(type, streamInfo, newQuality, reason = null) { if (!streamInfo || !streamInfo.id || !type) { return; } const streamId = streamInfo.id; const oldQuality = getQualityFor(type, streamId); checkInteger(newQuality); const topQualityIdx = getMaxAllowedIndexFor(type, streamId); if (newQuality !== oldQuality &amp;&amp; newQuality &gt;= 0 &amp;&amp; newQuality &lt;= topQualityIdx) { _changeQuality(type, oldQuality, newQuality, topQualityIdx, reason, streamId); } } /** * * @param {string} streamId * @param {type} type * @return {*|null} */ function getAbandonmentStateFor(streamId, type) { return abandonmentStateDict[streamId] &amp;&amp; abandonmentStateDict[streamId][type] ? abandonmentStateDict[streamId][type].state : null; } /** * Changes the internal qualityDict values according to the new quality * @param {string} type * @param {number} oldQuality * @param {number} newQuality * @param {number} maxIdx * @param {string} reason * @param {object} streamId * @private */ function _changeQuality(type, oldQuality, newQuality, maxIdx, reason, streamId) { if (type &amp;&amp; streamProcessorDict[streamId] &amp;&amp; streamProcessorDict[streamId][type]) { const streamInfo = streamProcessorDict[streamId][type].getStreamInfo(); const isDynamic = streamInfo &amp;&amp; streamInfo.manifestInfo &amp;&amp; streamInfo.manifestInfo.isDynamic; const bufferLevel = dashMetrics.getCurrentBufferLevel(type); logger.info('Stream ID: ' + streamId + ' [' + type + '] switch from ' + oldQuality + ' to ' + newQuality + '/' + maxIdx + ' (buffer: ' + bufferLevel + ') ' + (reason ? JSON.stringify(reason) : '.')); qualityDict[streamId] = qualityDict[streamId] || {}; qualityDict[streamId][type] = newQuality; const bitrateInfo = _getBitrateInfoForQuality(streamId, type, newQuality); eventBus.trigger(Events.QUALITY_CHANGE_REQUESTED, { oldQuality, newQuality, reason, streamInfo, bitrateInfo, maxIdx, mediaType: type }, { streamId: streamInfo.id, mediaType: type } ); const bitrate = throughputHistory.getAverageThroughput(type, isDynamic); if (!isNaN(bitrate)) { domStorage.setSavedBitrateSettings(type, bitrate); } } } function _getBitrateInfoForQuality(streamId, type, idx) { if (type &amp;&amp; streamProcessorDict &amp;&amp; streamProcessorDict[streamId] &amp;&amp; streamProcessorDict[streamId][type]) { const bitrates = getBitrateList(streamProcessorDict[streamId][type].getMediaInfo()); return bitrates[idx] ? bitrates[idx] : null; } return null; } /** * @param {MediaInfo} mediaInfo * @param {number} bitrate A bitrate value, kbps * @param {String} streamId Period ID * @param {number|null} latency Expected latency of connection, ms * @returns {number} A quality index &lt;= for the given bitrate * @memberof AbrController# */ function getQualityForBitrate(mediaInfo, bitrate, streamId, latency = null) { const voRepresentation = mediaInfo &amp;&amp; mediaInfo.type ? streamProcessorDict[streamId][mediaInfo.type].getRepresentationInfo() : null; if (settings.get().streaming.abr.useDeadTimeLatency &amp;&amp; latency &amp;&amp; voRepresentation &amp;&amp; voRepresentation.fragmentDuration) { latency = latency / 1000; const fragmentDuration = voRepresentation.fragmentDuration; if (latency &gt; fragmentDuration) { return 0; } else { const deadTimeRatio = latency / fragmentDuration; bitrate = bitrate * (1 - deadTimeRatio); } } const bitrateList = getBitrateList(mediaInfo); for (let i = bitrateList.length - 1; i &gt;= 0; i--) { const bitrateInfo = bitrateList[i]; if (bitrate * 1000 &gt;= bitrateInfo.bitrate) { return i; } } return QUALITY_DEFAULT; } /** * @param {MediaInfo} mediaInfo * @returns {Array|null} A list of {@link BitrateInfo} objects * @memberof AbrController# */ function getBitrateList(mediaInfo) { const infoList = []; if (!mediaInfo || !mediaInfo.bitrateList) return infoList; const bitrateList = mediaInfo.bitrateList; const type = mediaInfo.type; let bitrateInfo; for (let i = 0, ln = bitrateList.length; i &lt; ln; i++) { bitrateInfo = new BitrateInfo(); bitrateInfo.mediaType = type; bitrateInfo.qualityIndex = i; bitrateInfo.bitrate = bitrateList[i].bandwidth; bitrateInfo.width = bitrateList[i].width; bitrateInfo.height = bitrateList[i].height; bitrateInfo.scanType = bitrateList[i].scanType; infoList.push(bitrateInfo); } return infoList; } function _updateAbrStrategy(mediaType, bufferLevel) { // else ABR_STRATEGY_DYNAMIC const strategy = settings.get().streaming.abr.ABRStrategy; if (strategy === Constants.ABR_STRATEGY_DYNAMIC) { _updateDynamicAbrStrategy(mediaType, bufferLevel); } } function _updateDynamicAbrStrategy(mediaType, bufferLevel) { try { const stableBufferTime = mediaPlayerModel.getStableBufferTime(); const switchOnThreshold = stableBufferTime; const switchOffThreshold = 0.5 * stableBufferTime; const useBufferABR = isUsingBufferOccupancyAbrDict[mediaType]; const newUseBufferABR = bufferLevel &gt; (useBufferABR ? switchOffThreshold : switchOnThreshold); // use hysteresis to avoid oscillating rules isUsingBufferOccupancyAbrDict[mediaType] = newUseBufferABR; if (newUseBufferABR !== useBufferABR) { if (newUseBufferABR) { logger.info('[' + mediaType + '] switching from throughput to buffer occupancy ABR rule (buffer: ' + bufferLevel.toFixed(3) + ').'); } else { logger.info('[' + mediaType + '] switching from buffer occupancy to throughput ABR rule (buffer: ' + bufferLevel.toFixed(3) + ').'); } } } catch (e) { logger.error(e); } } function getThroughputHistory() { return throughputHistory; } function updateTopQualityIndex(mediaInfo) { const type = mediaInfo.type; const streamId = mediaInfo.streamInfo.id; const max = mediaInfo.representationCount - 1; topQualities[streamId] = topQualities[streamId] || {}; topQualities[streamId][type] = max; return max; } function isPlayingAtTopQuality(streamInfo) { const streamId = streamInfo ? streamInfo.id : null; const audioQuality = getQualityFor(Constants.AUDIO, streamId); const videoQuality = getQualityFor(Constants.VIDEO, streamId); const isAtTop = (audioQuality === getMaxAllowedIndexFor(Constants.AUDIO, streamId)) &amp;&amp; (videoQuality === getMaxAllowedIndexFor(Constants.VIDEO, streamId)); return isAtTop; } function setWindowResizeEventCalled(value) { windowResizeEventCalled = value; } function setElementSize() { if (videoModel) { const hasPixelRatio = settings.get().streaming.abr.usePixelRatioInLimitBitrateByPortal &amp;&amp; window.hasOwnProperty('devicePixelRatio'); const pixelRatio = hasPixelRatio ? window.devicePixelRatio : 1; elementWidth = videoModel.getClientWidth() * pixelRatio; elementHeight = videoModel.getClientHeight() * pixelRatio; } } function clearDataForStream(streamId) { if (droppedFramesHistory) { droppedFramesHistory.clearForStream(streamId); } if (streamProcessorDict[streamId]) { delete streamProcessorDict[streamId]; } if (switchHistoryDict[streamId]) { delete switchHistoryDict[streamId]; } if (abandonmentStateDict[streamId]) { delete abandonmentStateDict[streamId]; } } instance = { initialize, isPlayingAtTopQuality, updateTopQualityIndex, clearDataForStream, getThroughputHistory, getBitrateList, getQualityForBitrate, getTopBitrateInfoFor, getMinAllowedIndexFor, getMaxAllowedIndexFor, getInitialBitrateFor, getQualityFor, getAbandonmentStateFor, setPlaybackQuality, checkPlaybackQuality, setElementSize, setWindowResizeEventCalled, registerStreamType, unRegisterStreamType, setConfig, reset }; setup(); return instance; } AbrController.__dashjs_factory_name = 'AbrController'; const factory = FactoryMaker.getSingletonFactory(AbrController); factory.QUALITY_DEFAULT = QUALITY_DEFAULT; FactoryMaker.updateSingletonFactory(AbrController.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_rules_abr_ABRRulesCollection.js.html":{"id":"streaming_rules_abr_ABRRulesCollection.js.html","title":"Source: streaming/rules/abr/ABRRulesCollection.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/rules/abr/ABRRulesCollection.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import ThroughputRule from './ThroughputRule'; import InsufficientBufferRule from './InsufficientBufferRule'; import AbandonRequestsRule from './AbandonRequestsRule'; import DroppedFramesRule from './DroppedFramesRule'; import SwitchHistoryRule from './SwitchHistoryRule'; import BolaRule from './BolaRule'; import L2ARule from './L2ARule.js'; import LoLPRule from './lolp/LoLpRule.js'; import FactoryMaker from '../../../core/FactoryMaker'; import SwitchRequest from '../SwitchRequest'; import Constants from '../../constants/Constants'; const QUALITY_SWITCH_RULES = 'qualitySwitchRules'; const ABANDON_FRAGMENT_RULES = 'abandonFragmentRules'; function ABRRulesCollection(config) { config = config || {}; const context = this.context; const mediaPlayerModel = config.mediaPlayerModel; const customParametersModel = config.customParametersModel; const dashMetrics = config.dashMetrics; const settings = config.settings; let instance, qualitySwitchRules, abandonFragmentRules; function initialize() { qualitySwitchRules = []; abandonFragmentRules = []; if (settings.get().streaming.abr.useDefaultABRRules) { // If L2A is used we only need this one rule if (settings.get().streaming.abr.ABRStrategy === Constants.ABR_STRATEGY_L2A) { qualitySwitchRules.push( L2ARule(context).create({ dashMetrics: dashMetrics, settings: settings }) ); } // If LoLP is used we only need this one rule else if (settings.get().streaming.abr.ABRStrategy === Constants.ABR_STRATEGY_LoLP) { qualitySwitchRules.push( LoLPRule(context).create({ dashMetrics: dashMetrics }) ); } else { // Only one of BolaRule and ThroughputRule will give a switchRequest.quality !== SwitchRequest.NO_CHANGE. // This is controlled by useBufferOccupancyABR mechanism in AbrController. qualitySwitchRules.push( BolaRule(context).create({ dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, settings: settings }) ); qualitySwitchRules.push( ThroughputRule(context).create({ dashMetrics: dashMetrics }) ); if (settings.get().streaming.abr.additionalAbrRules.insufficientBufferRule) { qualitySwitchRules.push( InsufficientBufferRule(context).create({ dashMetrics: dashMetrics, settings }) ); } if (settings.get().streaming.abr.additionalAbrRules.switchHistoryRule) { qualitySwitchRules.push( SwitchHistoryRule(context).create() ); } if (settings.get().streaming.abr.additionalAbrRules.droppedFramesRule) { qualitySwitchRules.push( DroppedFramesRule(context).create() ); } if (settings.get().streaming.abr.additionalAbrRules.abandonRequestsRule) { abandonFragmentRules.push( AbandonRequestsRule(context).create({ dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, settings: settings }) ); } } } // add custom ABR rules if any const customRules = customParametersModel.getAbrCustomRules(); customRules.forEach(function (rule) { if (rule.type === QUALITY_SWITCH_RULES) { qualitySwitchRules.push(rule.rule(context).create()); } if (rule.type === ABANDON_FRAGMENT_RULES) { abandonFragmentRules.push(rule.rule(context).create()); } }); } function _getRulesWithChange(srArray) { return srArray.filter(sr =&gt; sr.quality &gt; SwitchRequest.NO_CHANGE); } /** * * @param {array} srArray * @return {object} SwitchRequest */ function getMinSwitchRequest(srArray) { const values = {}; let newSwitchReq = null; let i, len, req, quality, reason; if (srArray.length === 0) { return; } values[SwitchRequest.PRIORITY.STRONG] = { quality: SwitchRequest.NO_CHANGE, reason: null }; values[SwitchRequest.PRIORITY.WEAK] = { quality: SwitchRequest.NO_CHANGE, reason: null }; values[SwitchRequest.PRIORITY.DEFAULT] = { quality: SwitchRequest.NO_CHANGE, reason: null }; for (i = 0, len = srArray.length; i &lt; len; i += 1) { req = srArray[i]; if (req.quality !== SwitchRequest.NO_CHANGE) { // We only use the new quality in case it is lower than the already saved one or if no new quality has been selected for the respective priority if (values[req.priority].quality === SwitchRequest.NO_CHANGE || values[req.priority].quality &gt; req.quality) { values[req.priority].quality = req.quality; values[req.priority].reason = req.reason || null; } } } if (values[SwitchRequest.PRIORITY.WEAK].quality !== SwitchRequest.NO_CHANGE) { newSwitchReq = values[SwitchRequest.PRIORITY.WEAK]; } if (values[SwitchRequest.PRIORITY.DEFAULT].quality !== SwitchRequest.NO_CHANGE) { newSwitchReq = values[SwitchRequest.PRIORITY.DEFAULT]; } if (values[SwitchRequest.PRIORITY.STRONG].quality !== SwitchRequest.NO_CHANGE) { newSwitchReq = values[SwitchRequest.PRIORITY.STRONG]; } if (newSwitchReq) { quality = newSwitchReq.quality; reason = newSwitchReq.reason; } return SwitchRequest(context).create(quality, reason); } function getMaxQuality(rulesContext) { const switchRequestArray = qualitySwitchRules.map(rule =&gt; rule.getMaxIndex(rulesContext)); const activeRules = _getRulesWithChange(switchRequestArray); const maxQuality = getMinSwitchRequest(activeRules); return maxQuality || SwitchRequest(context).create(); } function shouldAbandonFragment(rulesContext, streamId) { const abandonRequestArray = abandonFragmentRules.map(rule =&gt; rule.shouldAbandon(rulesContext, streamId)); const activeRules = _getRulesWithChange(abandonRequestArray); const shouldAbandon = getMinSwitchRequest(activeRules); return shouldAbandon || SwitchRequest(context).create(); } function reset() { [qualitySwitchRules, abandonFragmentRules].forEach(rules =&gt; { if (rules &amp;&amp; rules.length) { rules.forEach(rule =&gt; rule.reset &amp;&amp; rule.reset()); } }); qualitySwitchRules = []; abandonFragmentRules = []; } function getQualitySwitchRules() { return qualitySwitchRules; } instance = { initialize, reset, getMaxQuality, getMinSwitchRequest, shouldAbandonFragment, getQualitySwitchRules }; return instance; } ABRRulesCollection.__dashjs_factory_name = 'ABRRulesCollection'; const factory = FactoryMaker.getClassFactory(ABRRulesCollection); factory.QUALITY_SWITCH_RULES = QUALITY_SWITCH_RULES; factory.ABANDON_FRAGMENT_RULES = ABANDON_FRAGMENT_RULES; FactoryMaker.updateSingletonFactory(ABRRulesCollection.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_utils_BoxParser.js.html":{"id":"streaming_utils_BoxParser.js.html","title":"Source: streaming/utils/BoxParser.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/BoxParser.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Debug from '../../core/Debug'; import IsoFile from './IsoFile'; import FactoryMaker from '../../core/FactoryMaker'; import ISOBoxer from 'codem-isoboxer'; import IsoBoxSearchInfo from '../vo/IsoBoxSearchInfo'; function BoxParser(/*config*/) { let logger, instance; let context = this.context; function setup() { logger = Debug(context).getInstance().getLogger(instance); } /** * @param {ArrayBuffer} data * @returns {IsoFile|null} * @memberof BoxParser# */ function parse(data) { if (!data) return null; if (data.fileStart === undefined) { data.fileStart = 0; } let parsedFile = ISOBoxer.parseBuffer(data); let dashIsoFile = IsoFile(context).create(); dashIsoFile.setData(parsedFile); return dashIsoFile; } /** * From the list of type boxes to look for, returns the latest one that is fully completed (header + payload). This * method only looks into the list of top boxes and doesn't analyze nested boxes. * @param {string[]} types * @param {ArrayBuffer|uint8Array} buffer * @param {number} offset * @returns {IsoBoxSearchInfo} * @memberof BoxParser# */ function findLastTopIsoBoxCompleted(types, buffer, offset) { if (offset === undefined) { offset = 0; } // 8 = size (uint32) + type (4 characters) if (!buffer || offset + 8 &gt;= buffer.byteLength) { return new IsoBoxSearchInfo(0, false); } const data = (buffer instanceof ArrayBuffer) ? new Uint8Array(buffer) : buffer; let boxInfo; let lastCompletedOffset = 0; while (offset &lt; data.byteLength) { const boxSize = parseUint32(data, offset); const boxType = parseIsoBoxType(data, offset + 4); if (boxSize === 0) { break; } if (offset + boxSize &lt;= data.byteLength) { if (types.indexOf(boxType) &gt;= 0) { boxInfo = new IsoBoxSearchInfo(offset, true, boxSize); } else { lastCompletedOffset = offset + boxSize; } } offset += boxSize; } if (!boxInfo) { return new IsoBoxSearchInfo(lastCompletedOffset, false); } return boxInfo; } function getSamplesInfo(ab) { if (!ab || ab.byteLength === 0) { return {sampleList: [], lastSequenceNumber: NaN, totalDuration: NaN, numSequences: NaN}; } let isoFile = parse(ab); // zero or more moofs let moofBoxes = isoFile.getBoxes('moof'); // exactly one mfhd per moof let mfhdBoxes = isoFile.getBoxes('mfhd'); let sampleDuration, sampleCompositionTimeOffset, sampleCount, sampleSize, sampleDts, sampleList, sample, i, j, k, l, m, n, dataOffset, lastSequenceNumber, numSequences, totalDuration; numSequences = isoFile.getBoxes('moof').length; lastSequenceNumber = mfhdBoxes[mfhdBoxes.length - 1].sequence_number; sampleCount = 0; sampleList = []; let subsIndex = -1; let nextSubsSample = -1; for (l = 0; l &lt; moofBoxes.length; l++) { let moofBox = moofBoxes[l]; // zero or more trafs per moof let trafBoxes = moofBox.getChildBoxes('traf'); for (j = 0; j &lt; trafBoxes.length; j++) { let trafBox = trafBoxes[j]; // exactly one tfhd per traf let tfhdBox = trafBox.getChildBox('tfhd'); // zero or one tfdt per traf let tfdtBox = trafBox.getChildBox('tfdt'); sampleDts = tfdtBox.baseMediaDecodeTime; // zero or more truns per traf let trunBoxes = trafBox.getChildBoxes('trun'); // zero or more subs per traf let subsBoxes = trafBox.getChildBoxes('subs'); for (k = 0; k &lt; trunBoxes.length; k++) { let trunBox = trunBoxes[k]; sampleCount = trunBox.sample_count; dataOffset = (tfhdBox.base_data_offset || 0) + (trunBox.data_offset || 0); for (i = 0; i &lt; sampleCount; i++) { sample = trunBox.samples[i]; sampleDuration = (sample.sample_duration !== undefined) ? sample.sample_duration : tfhdBox.default_sample_duration; sampleSize = (sample.sample_size !== undefined) ? sample.sample_size : tfhdBox.default_sample_size; sampleCompositionTimeOffset = (sample.sample_composition_time_offset !== undefined) ? sample.sample_composition_time_offset : 0; let sampleData = { 'dts': sampleDts, 'cts': (sampleDts + sampleCompositionTimeOffset), 'duration': sampleDuration, 'offset': moofBox.offset + dataOffset, 'size': sampleSize, 'subSizes': [sampleSize] }; if (subsBoxes) { for (m = 0; m &lt; subsBoxes.length; m++) { let subsBox = subsBoxes[m]; if (subsIndex &lt; (subsBox.entry_count - 1) &amp;&amp; i &gt; nextSubsSample) { subsIndex++; nextSubsSample += subsBox.entries[subsIndex].sample_delta; } if (i == nextSubsSample) { sampleData.subSizes = []; let entry = subsBox.entries[subsIndex]; for (n = 0; n &lt; entry.subsample_count; n++) { sampleData.subSizes.push(entry.subsamples[n].subsample_size); } } } } sampleList.push(sampleData); dataOffset += sampleSize; sampleDts += sampleDuration; } } totalDuration = sampleDts - tfdtBox.baseMediaDecodeTime; } } return {sampleList: sampleList, lastSequenceNumber: lastSequenceNumber, totalDuration: totalDuration, numSequences: numSequences}; } function getMediaTimescaleFromMoov(ab) { let isoFile = parse(ab); let mdhdBox = isoFile ? isoFile.getBox('mdhd') : undefined; return mdhdBox ? mdhdBox.timescale : NaN; } function parseUint32(data, offset) { return data[offset + 3] &gt;&gt;&gt; 0 | (data[offset + 2] &lt;&lt; 8) &gt;&gt;&gt; 0 | (data[offset + 1] &lt;&lt; 16) &gt;&gt;&gt; 0 | (data[offset] &lt;&lt; 24) &gt;&gt;&gt; 0; } function parseIsoBoxType(data, offset) { return String.fromCharCode(data[offset++]) + String.fromCharCode(data[offset++]) + String.fromCharCode(data[offset++]) + String.fromCharCode(data[offset]); } function findInitRange(data) { let initRange = null; let start, end; const isoFile = parse(data); if (!isoFile) { return initRange; } const ftyp = isoFile.getBox('ftyp'); const moov = isoFile.getBox('moov'); logger.debug('Searching for initialization.'); if (moov &amp;&amp; moov.isComplete) { start = ftyp ? ftyp.offset : moov.offset; end = moov.offset + moov.size - 1; initRange = start + '-' + end; logger.debug('Found the initialization. Range: ' + initRange); } return initRange; } /** * Real-time parsing (whenever data is loaded in the buffer payload) of the payload to capture the moof of a chunk * @param {array} types * @param {ArrayBuffer} buffer * @param {number} offset * @return {IsoBoxSearchInfo} */ function parsePayload(types, buffer, offset) { if (offset === undefined) { offset = 0; } if (!buffer || offset + 8 &gt;= buffer.byteLength) { return new IsoBoxSearchInfo(0, false); } const data = (buffer instanceof ArrayBuffer) ? new Uint8Array(buffer) : buffer; let boxInfo; let lastCompletedOffset = 0; while (offset &lt; data.byteLength) { const boxSize = parseUint32(data, offset); const boxType = parseIsoBoxType(data, offset + 4); if (boxSize === 0) { break; } if (offset + boxSize &lt;= data.byteLength) { if (types.indexOf(boxType) &gt;= 0) { boxInfo = new IsoBoxSearchInfo(offset, true, boxSize, boxType); } else { lastCompletedOffset = offset + boxSize; } } offset += boxSize; } if (!boxInfo) { return new IsoBoxSearchInfo(lastCompletedOffset, false); } return boxInfo; } instance = { parse, findLastTopIsoBoxCompleted, getMediaTimescaleFromMoov, getSamplesInfo, findInitRange, parsePayload }; setup(); return instance; } BoxParser.__dashjs_factory_name = 'BoxParser'; export default FactoryMaker.getSingletonFactory(BoxParser); × Search results Close "},"streaming_controllers_BufferController.js.html":{"id":"streaming_controllers_BufferController.js.html","title":"Source: streaming/controllers/BufferController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/BufferController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../constants/Constants'; import MetricsConstants from '../constants/MetricsConstants'; import FragmentModel from '../models/FragmentModel'; import SourceBufferSink from '../SourceBufferSink'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import InitCache from '../utils/InitCache'; import DashJSError from '../vo/DashJSError'; import Errors from '../../core/errors/Errors'; import {HTTPRequest} from '../vo/metrics/HTTPRequest'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents'; const BUFFER_END_THRESHOLD = 0.5; const BUFFER_RANGE_CALCULATION_THRESHOLD = 0.01; const QUOTA_EXCEEDED_ERROR_CODE = 22; const BUFFER_CONTROLLER_TYPE = 'BufferController'; function BufferController(config) { config = config || {}; const context = this.context; const eventBus = EventBus(context).getInstance(); const errHandler = config.errHandler; const fragmentModel = config.fragmentModel; const representationController = config.representationController; const adapter = config.adapter; const textController = config.textController; const abrController = config.abrController; const playbackController = config.playbackController; const streamInfo = config.streamInfo; const type = config.type; const settings = config.settings; let instance, logger, isBufferingCompleted, bufferLevel, criticalBufferLevel, mediaSource, maxAppendedIndex, maximumIndex, sourceBufferSink, bufferState, appendedBytesInfo, wallclockTicked, isPruningInProgress, isQuotaExceeded, initCache, pendingPruningRanges, replacingBuffer, seekTarget; function setup() { logger = Debug(context).getInstance().getLogger(instance); initCache = InitCache(context).getInstance(); resetInitialSettings(); } /** * Initialize the BufferController. Sets the media source and registers the event handlers. * @param {object} mediaSource */ function initialize(mediaSource) { setMediaSource(mediaSource); eventBus.on(Events.INIT_FRAGMENT_LOADED, _onInitFragmentLoaded, instance); eventBus.on(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, instance); eventBus.on(Events.WALLCLOCK_TIME_UPDATED, _onWallclockTimeUpdated, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_PLAYING, _onPlaybackPlaying, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_RATE_CHANGED, _onPlaybackRateChanged, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_STALLED, _onPlaybackStalled, instance); } /** * Returns the stream id * @return {string} */ function getStreamId() { return streamInfo.id; } /** * Returns the media type * @return {type} */ function getType() { return type; } /** * Returns the type of the BufferController. We distinguish between standard buffer controllers and buffer controllers related to texttracks. * @return {string} */ function getBufferControllerType() { return BUFFER_CONTROLLER_TYPE; } /** * Sets the mediasource. * @param {object} value */ function setMediaSource(value) { mediaSource = value; } /** * Get the RepresentationInfo for a certain quality. * @param {number} quality * @return {object} * @private */ function _getRepresentationInfo(quality) { return adapter.convertRepresentationToRepresentationInfo(representationController.getRepresentationForQuality(quality)); } /** * Creates a SourceBufferSink object * @param {object} mediaInfo * @param {array} oldBufferSinks * @return {object|null} SourceBufferSink */ function createBufferSink(mediaInfo, oldBufferSinks = []) { return new Promise((resolve, reject) =&gt; { if (!initCache || !mediaInfo || !mediaSource) { resolve(null); return; } const requiredQuality = abrController.getQualityFor(type, streamInfo.id); sourceBufferSink = SourceBufferSink(context).create({ mediaSource, textController, eventBus }); _initializeSink(mediaInfo, oldBufferSinks, requiredQuality) .then(() =&gt; { return updateBufferTimestampOffset(_getRepresentationInfo(requiredQuality)); }) .then(() =&gt; { resolve(sourceBufferSink); }) .catch((e) =&gt; { logger.fatal('Caught error on create SourceBuffer: ' + e); errHandler.error(new DashJSError(Errors.MEDIASOURCE_TYPE_UNSUPPORTED_CODE, Errors.MEDIASOURCE_TYPE_UNSUPPORTED_MESSAGE + type)); reject(e); }); }); } function _initializeSink(mediaInfo, oldBufferSinks, requiredQuality) { const selectedRepresentation = _getRepresentationInfo(requiredQuality); if (oldBufferSinks &amp;&amp; oldBufferSinks[type] &amp;&amp; (type === Constants.VIDEO || type === Constants.AUDIO)) { return sourceBufferSink.initializeForStreamSwitch(mediaInfo, selectedRepresentation, oldBufferSinks[type]); } else { return sourceBufferSink.initializeForFirstUse(streamInfo, mediaInfo, selectedRepresentation); } } /** * Callback handler when init segment has been loaded. Based on settings, the init segment is saved to the cache, and appended to the buffer. * @param {object} e * @private */ function _onInitFragmentLoaded(e) { if (settings.get().streaming.cacheInitSegments) { 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); _appendToBuffer(e.chunk); } /** * Append the init segment for a certain representation to the buffer. If the init segment is cached we take the one from the cache. Otherwise the function returns false and the segment has to be requested again. * @param {string} representationId * @return {boolean} */ function appendInitSegmentFromCache(representationId) { // Get init segment from cache const chunk = initCache.extract(streamInfo.id, representationId); if (!chunk) { // Init segment not in cache, shall be requested return false; } // Append init segment into buffer logger.info('Append Init fragment', type, ' with representationId:', chunk.representationId, ' and quality:', chunk.quality, ', data size:', chunk.bytes.byteLength); _appendToBuffer(chunk); return true; } /** * Calls the _appendToBuffer function to append the segment to the buffer. In case of a track switch the buffer might be cleared. * @param {object} e */ function _onMediaFragmentLoaded(e) { _appendToBuffer(e.chunk, e.request); } /** * Append data to the MSE buffer using the SourceBufferSink * @param {object} chunk * @private */ function _appendToBuffer(chunk, request = null) { sourceBufferSink.append(chunk, request) .then((e) =&gt; { _onAppended(e); }) .catch((e) =&gt; { _onAppended(e); }); if (chunk.mediaInfo.type === Constants.VIDEO) { _triggerEvent(Events.VIDEO_CHUNK_RECEIVED, { chunk: chunk }); } } function _showBufferRanges(ranges) { if (ranges &amp;&amp; ranges.length &gt; 0) { for (let i = 0, len = ranges.length; i &lt; len; i++) { logger.debug('Buffered range: ' + ranges.start(i) + ' - ' + ranges.end(i) + ', currentTime = ', playbackController.getTime()); } } } function _onAppended(e) { if (e.error) { // If we receive a QUOTA_EXCEEDED_ERROR_CODE we should adjust the target buffer times to avoid this error in the future. if (e.error.code === QUOTA_EXCEEDED_ERROR_CODE) { _handleQuotaExceededError(); } if (e.error.code === QUOTA_EXCEEDED_ERROR_CODE || !hasEnoughSpaceToAppend()) { logger.warn('Clearing playback buffer to overcome quota exceed situation'); // Notify ScheduleController to stop scheduling until buffer has been pruned _triggerEvent(Events.QUOTA_EXCEEDED, { criticalBufferLevel: criticalBufferLevel, quotaExceededTime: e.chunk.start }); clearBuffers(getClearRanges()); } return; } // Check if session has not been stopped in the meantime (while last segment was being appended) if (!sourceBufferSink) return; _updateBufferLevel(); isQuotaExceeded = false; appendedBytesInfo = e.chunk; if (!appendedBytesInfo || !appendedBytesInfo.endFragment) { return; } if (appendedBytesInfo &amp;&amp; !isNaN(appendedBytesInfo.index)) { maxAppendedIndex = Math.max(appendedBytesInfo.index, maxAppendedIndex); _checkIfBufferingCompleted(); } const ranges = sourceBufferSink.getAllBufferRanges(); if (appendedBytesInfo.segmentType === HTTPRequest.MEDIA_SEGMENT_TYPE) { _showBufferRanges(ranges); _onPlaybackProgression(); _adjustSeekTarget(); } if (appendedBytesInfo) { _triggerEvent(Events.BYTES_APPENDED_END_FRAGMENT, { quality: appendedBytesInfo.quality, startTime: appendedBytesInfo.start, index: appendedBytesInfo.index, bufferedRanges: ranges, segmentType: appendedBytesInfo.segmentType, mediaType: type }); } } /** * In some cases the segment we requested might start at a different time than we initially aimed for. segments timeline/template tolerance. * We might need to do an internal seek if there is drift. * @private */ function _adjustSeekTarget() { if (isNaN(seekTarget)) return; // Check buffered data only for audio and video if (type !== Constants.AUDIO &amp;&amp; type !== Constants.VIDEO) { seekTarget = NaN; return; } // Check if current buffered range already contains seek target (and current video element time) const currentTime = playbackController.getTime(); const rangeAtCurrenTime = getRangeAt(currentTime, 0); const rangeAtSeekTarget = getRangeAt(seekTarget, 0); if (rangeAtCurrenTime &amp;&amp; rangeAtSeekTarget &amp;&amp; rangeAtCurrenTime.start === rangeAtSeekTarget.start) { seekTarget = NaN; return; } // Get buffered range corresponding to the seek target const segmentDuration = representationController.getCurrentRepresentation().segmentDuration; const range = getRangeAt(seekTarget, segmentDuration); if (!range) return; if (settings.get().streaming.buffer.enableSeekDecorrelationFix &amp;&amp; Math.abs(currentTime - seekTarget) &gt; segmentDuration) { // If current video model time is decorrelated from seek target (and appended buffer) then seek video element // (in case of live streams on some browsers/devices for which we can't set video element time at unavalaible range) // Check if appended segment is not anterior from seek target (segments timeline/template tolerance) if (seekTarget &lt;= range.end) { // Seek video element to seek target or range start if appended buffer starts after seek target (segments timeline/template tolerance) playbackController.seek(Math.max(seekTarget, range.start), false, true); } } else if (currentTime &lt; range.start) { // If appended buffer starts after seek target (segments timeline/template tolerance) then seek to range start playbackController.seek(range.start, false, true); } } function _handleQuotaExceededError() { isQuotaExceeded = true; criticalBufferLevel = getTotalBufferedTime() * 0.8; logger.warn('Quota exceeded, Critical Buffer: ' + criticalBufferLevel); if (criticalBufferLevel &gt; 0) { // recalculate buffer lengths according to criticalBufferLevel const bufferToKeep = Math.max(0.2 * criticalBufferLevel, 1); const bufferAhead = criticalBufferLevel - bufferToKeep; const bufferTimeAtTopQuality = Math.min(settings.get().streaming.buffer.bufferTimeAtTopQuality, bufferAhead * 0.9); const bufferTimeAtTopQualityLongForm = Math.min(settings.get().streaming.buffer.bufferTimeAtTopQualityLongForm, bufferAhead * 0.9); const s = { streaming: { buffer: { bufferToKeep: parseFloat(bufferToKeep.toFixed(5)), bufferTimeAtTopQuality: parseFloat(bufferTimeAtTopQuality.toFixed(5)), bufferTimeAtTopQualityLongForm: parseFloat(bufferTimeAtTopQualityLongForm.toFixed(5)) } } }; settings.update(s); } } //********************************************************************** // START Buffer Level, State &amp; Sufficiency Handling. //********************************************************************** function prepareForPlaybackSeek() { if (isBufferingCompleted) { setIsBufferingCompleted(false); } // Abort the current request and empty all possible segments to be appended return sourceBufferSink.abort(); } function prepareForReplacementTrackSwitch(codec) { return new Promise((resolve, reject) =&gt; { sourceBufferSink.abort() .then(() =&gt; { return updateAppendWindow(); }) .then(() =&gt; { return sourceBufferSink.changeType(codec); }) .then(() =&gt; { return pruneAllSafely(); }) .then(() =&gt; { setIsBufferingCompleted(false); resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function prepareForReplacementQualitySwitch() { return new Promise((resolve, reject) =&gt; { sourceBufferSink.abort() .then(() =&gt; { return updateAppendWindow(); }) .then(() =&gt; { return pruneAllSafely(); }) .then(() =&gt; { setIsBufferingCompleted(false); resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function prepareForNonReplacementTrackSwitch(codec) { return new Promise((resolve, reject) =&gt; { updateAppendWindow() .then(() =&gt; { return sourceBufferSink.changeType(codec); }) .then(() =&gt; { resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function pruneAllSafely() { return new Promise((resolve, reject) =&gt; { let ranges = getAllRangesWithSafetyFactor(); if (!ranges || ranges.length === 0) { _onPlaybackProgression(); resolve(); return; } clearBuffers(ranges) .then(() =&gt; { resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function getAllRangesWithSafetyFactor(seekTime) { const clearRanges = []; const ranges = sourceBufferSink.getAllBufferRanges(); // no valid ranges if (!ranges || ranges.length === 0) { return clearRanges; } // if no target time is provided we clear everyhing if ((!seekTime &amp;&amp; seekTime !== 0) || isNaN(seekTime)) { clearRanges.push({ start: ranges.start(0), end: ranges.end(ranges.length - 1) + BUFFER_END_THRESHOLD }); } // otherwise we need to calculate the correct pruning range else { const behindPruningRange = _getRangeBehindForPruning(seekTime, ranges); const aheadPruningRange = _getRangeAheadForPruning(seekTime, ranges); if (behindPruningRange) { clearRanges.push(behindPruningRange); } if (aheadPruningRange) { clearRanges.push(aheadPruningRange); } } return clearRanges; } function _getRangeBehindForPruning(targetTime, ranges) { const bufferToKeepBehind = settings.get().streaming.buffer.bufferToKeep; const startOfBuffer = ranges.start(0); // if we do a seek ahead of the current play position we do need to prune behind the new play position const behindDiff = targetTime - startOfBuffer; if (behindDiff &gt; bufferToKeepBehind) { let rangeEnd = Math.max(0, targetTime - bufferToKeepBehind); // Ensure we keep full range of current fragment const currentTimeRequest = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_EXECUTED, time: targetTime, threshold: BUFFER_RANGE_CALCULATION_THRESHOLD })[0]; if (currentTimeRequest) { rangeEnd = Math.min(currentTimeRequest.startTime, rangeEnd); } if (rangeEnd &gt; 0) { return { start: startOfBuffer, end: rangeEnd }; } } return null; } function _getRangeAheadForPruning(targetTime, ranges) { // if we do a seek behind the current play position we do need to prune ahead of the new play position const endOfBuffer = ranges.end(ranges.length - 1) + BUFFER_END_THRESHOLD; const isLongFormContent = streamInfo.manifestInfo.duration &gt;= settings.get().streaming.buffer.longFormContentDurationThreshold; const bufferToKeepAhead = isLongFormContent ? settings.get().streaming.buffer.bufferTimeAtTopQualityLongForm : settings.get().streaming.buffer.bufferTimeAtTopQuality; const aheadDiff = endOfBuffer - targetTime; if (aheadDiff &gt; bufferToKeepAhead) { let rangeStart = targetTime + bufferToKeepAhead; // Ensure we keep full range of current fragment const currentTimeRequest = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_EXECUTED, time: targetTime, threshold: BUFFER_RANGE_CALCULATION_THRESHOLD })[0]; if (currentTimeRequest) { rangeStart = Math.max(currentTimeRequest.startTime + currentTimeRequest.duration, rangeStart); } // Never remove the contiguous range of targetTime in order to avoid flushes &amp; reenqueues when the user doesn't want it const avoidCurrentTimeRangePruning = settings.get().streaming.buffer.avoidCurrentTimeRangePruning; if (avoidCurrentTimeRangePruning) { for (let i = 0; i &lt; ranges.length; i++) { if (ranges.start(i) &lt;= targetTime &amp;&amp; targetTime &lt;= ranges.end(i) &amp;&amp; ranges.start(i) &lt;= rangeStart &amp;&amp; rangeStart &lt;= ranges.end(i)) { let oldRangeStart = rangeStart; if (i + 1 &lt; ranges.length) { rangeStart = ranges.start(i+1); } else { rangeStart = ranges.end(i) + 1; } logger.debug('Buffered range [' + ranges.start(i) + ', ' + ranges.end(i) + '] overlaps with targetTime ' + targetTime + ' and range to be pruned [' + oldRangeStart + ', ' + endOfBuffer + '], using [' + rangeStart + ', ' + endOfBuffer +'] instead' + ((rangeStart &lt; endOfBuffer) ? '' : ' (no actual pruning)')); break; } } } if (rangeStart &lt; endOfBuffer) { return { start: rangeStart, end: endOfBuffer }; } } return null; } function _onPlaybackProgression() { if (!replacingBuffer || (type === Constants.TEXT &amp;&amp; textController.isTextEnabled())) { _updateBufferLevel(); } } function _onPlaybackStalled() { checkIfSufficientBuffer(); } function _onPlaybackPlaying() { checkIfSufficientBuffer(); seekTarget = NaN; } function getRangeAt(time, tolerance) { const ranges = sourceBufferSink.getAllBufferRanges(); let start = 0; let end = 0; let firstStart = null; let lastEnd = null; let gap = 0; let len, i; const toler = !isNaN(tolerance) ? tolerance : 0.15; if (ranges !== null &amp;&amp; ranges !== undefined) { for (i = 0, len = ranges.length; i &lt; len; i++) { start = ranges.start(i); end = ranges.end(i); if (firstStart === null) { gap = Math.abs(start - time); if (time &gt;= start &amp;&amp; time &lt; end) { // start the range firstStart = start; lastEnd = end; } else if (gap &lt;= toler) { // start the range even though the buffer does not contain time 0 firstStart = start; lastEnd = end; } } else { gap = start - lastEnd; if (gap &lt;= toler) { // the discontinuity is smaller than the tolerance, combine the ranges lastEnd = end; } else { break; } } } if (firstStart !== null) { return { start: firstStart, end: lastEnd }; } } return null; } function getBufferLength(time, tolerance) { let range, length; // Consider gap/discontinuity limit as tolerance if (settings.get().streaming.gaps.jumpGaps) { tolerance = settings.get().streaming.gaps.smallGapLimit; } range = getRangeAt(time, tolerance); if (range === null) { length = 0; } else { length = range.end - time; } return length; } function _updateBufferLevel() { if (playbackController) { const tolerance = settings.get().streaming.gaps.jumpGaps &amp;&amp; !isNaN(settings.get().streaming.gaps.smallGapLimit) ? settings.get().streaming.gaps.smallGapLimit : NaN; bufferLevel = Math.max(getBufferLength(playbackController.getTime() || 0, tolerance), 0); _triggerEvent(Events.BUFFER_LEVEL_UPDATED, { mediaType: type, bufferLevel: bufferLevel }); checkIfSufficientBuffer(); } } function _checkIfBufferingCompleted() { const isLastIdxAppended = maxAppendedIndex &gt;= maximumIndex - 1; // Handles 0 and non 0 based request index // To avoid rounding error when comparing, the stream time and buffer level only must be within 5 decimal places const periodBuffered = playbackController.getTimeToStreamEnd(streamInfo) - bufferLevel &lt; 0.00001; if ((isLastIdxAppended || periodBuffered) &amp;&amp; !isBufferingCompleted) { setIsBufferingCompleted(true); logger.debug(`checkIfBufferingCompleted trigger BUFFERING_COMPLETED for stream id ${streamInfo.id} and type ${type}`); } } function checkIfSufficientBuffer() { // 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 !== Constants.AUDIO &amp;&amp; type !== Constants.VIDEO) return; // When the player is working in low latency mode, the buffer is often below STALL_THRESHOLD. // So, when in low latency mode, change dash.js behavior so it notifies a stall just when // buffer reach 0 seconds if (((!playbackController.getLowLatencyModeEnabled() &amp;&amp; bufferLevel &lt; settings.get().streaming.buffer.stallThreshold) || bufferLevel === 0) &amp;&amp; !isBufferingCompleted) { _notifyBufferStateChanged(MetricsConstants.BUFFER_EMPTY); } else { if (isBufferingCompleted || bufferLevel &gt;= settings.get().streaming.buffer.stallThreshold || (playbackController.getLowLatencyModeEnabled() &amp;&amp; bufferLevel &gt; 0)) { _notifyBufferStateChanged(MetricsConstants.BUFFER_LOADED); } } } function _notifyBufferStateChanged(state) { if (bufferState === state || (state === MetricsConstants.BUFFER_EMPTY &amp;&amp; playbackController.getTime() === 0) || // Don't trigger BUFFER_EMPTY if it's initial loading (type === Constants.TEXT &amp;&amp; !textController.isTextEnabled())) { return; } bufferState = state; _triggerEvent(Events.BUFFER_LEVEL_STATE_CHANGED, { state: state }); _triggerEvent(state === MetricsConstants.BUFFER_LOADED ? Events.BUFFER_LOADED : Events.BUFFER_EMPTY); logger.debug(state === MetricsConstants.BUFFER_LOADED ? 'Got enough buffer to start' : 'Waiting for more buffer before starting playback'); } /* prune buffer on our own in background to avoid browsers pruning buffer silently */ function pruneBuffer() { if (!sourceBufferSink || type === Constants.TEXT) { return; } if (!isBufferingCompleted) { clearBuffers(getClearRanges()); } } function getClearRanges() { const clearRanges = []; const ranges = sourceBufferSink.getAllBufferRanges(); if (!ranges || ranges.length === 0) { return clearRanges; } const currentTime = playbackController.getTime(); let startRangeToKeep = Math.max(0, currentTime - settings.get().streaming.buffer.bufferToKeep); const currentTimeRequest = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_EXECUTED, time: currentTime, threshold: BUFFER_RANGE_CALCULATION_THRESHOLD })[0]; // Ensure we keep full range of current fragment if (currentTimeRequest) { startRangeToKeep = Math.min(currentTimeRequest.startTime, startRangeToKeep); } else if (currentTime === 0 &amp;&amp; playbackController.getIsDynamic()) { // Don't prune before the live stream starts, it messes with low latency return []; } if (ranges.start(0) &lt;= startRangeToKeep) { const behindRange = { start: 0, end: startRangeToKeep }; for (let i = 0; i &lt; ranges.length &amp;&amp; ranges.end(i) &lt;= startRangeToKeep; i++) { behindRange.end = ranges.end(i); } if (behindRange.start &lt; behindRange.end) { clearRanges.push(behindRange); } } return clearRanges; } function clearBuffers(ranges) { return new Promise((resolve, reject) =&gt; { if (!ranges || !sourceBufferSink || ranges.length === 0) { resolve(); return; } const promises = []; ranges.forEach((range) =&gt; { promises.push(_addClearRangeWithPromise(range)); }); if (!isPruningInProgress) { clearNextRange(); } Promise.all(promises) .then(() =&gt; { resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function _addClearRangeWithPromise(range) { return new Promise((resolve, reject) =&gt; { range.resolve = resolve; range.reject = reject; pendingPruningRanges.push(range); }); } function clearNextRange() { try { // If there's nothing to prune reset state if (pendingPruningRanges.length === 0 || !sourceBufferSink) { logger.debug('Nothing to prune, halt pruning'); pendingPruningRanges = []; isPruningInProgress = false; return; } const sourceBuffer = sourceBufferSink.getBuffer(); // If there's nothing buffered any pruning is invalid, so reset our state if (!sourceBuffer || !sourceBuffer.buffered || sourceBuffer.buffered.length === 0) { logger.debug('SourceBuffer is empty (or does not exist), halt pruning'); pendingPruningRanges = []; isPruningInProgress = false; return; } const range = pendingPruningRanges.shift(); logger.debug(`${type}: Removing buffer from: ${range.start} to ${range.end}`); isPruningInProgress = true; // If removing buffer ahead current playback position, update maxAppendedIndex const currentTime = playbackController.getTime(); if (currentTime &lt; range.end) { setIsBufferingCompleted(false); } sourceBufferSink.remove(range) .then((e) =&gt; { _onRemoved(e); }) .catch((e) =&gt; { _onRemoved(e); }); } catch (e) { isPruningInProgress = false; } } function _onRemoved(e) { logger.debug('onRemoved buffer from:', e.from, 'to', e.to); const ranges = sourceBufferSink.getAllBufferRanges(); _showBufferRanges(ranges); if (pendingPruningRanges.length === 0) { isPruningInProgress = false; _updateBufferLevel(); } if (e.unintended) { logger.warn('Detected unintended removal from:', e.from, 'to', e.to, 'setting streamprocessor time to', e.from); _triggerEvent(Events.SEEK_TARGET, { time: e.from }); } if (isPruningInProgress) { clearNextRange(); } else { if (!replacingBuffer) { _updateBufferLevel(); } else { replacingBuffer = false; } _triggerEvent(Events.BUFFER_CLEARED, { from: e.from, to: e.to, unintended: e.unintended, hasEnoughSpaceToAppend: hasEnoughSpaceToAppend(), quotaExceeded: isQuotaExceeded }); } } function updateBufferTimestampOffset(representationInfo) { return new Promise((resolve) =&gt; { if (!representationInfo || representationInfo.MSETimeOffset === undefined || !sourceBufferSink || !sourceBufferSink.updateTimestampOffset) { resolve(); return; } // Each track can have its own @presentationTimeOffset, so we should set the offset // if it has changed after switching the quality or updating an mpd sourceBufferSink.updateTimestampOffset(representationInfo.MSETimeOffset) .then(() =&gt; { resolve(); }) .catch(() =&gt; { resolve(); }); }); } function updateAppendWindow() { if (sourceBufferSink &amp;&amp; !isBufferingCompleted) { return sourceBufferSink.updateAppendWindow(streamInfo); } return Promise.resolve(); } function segmentRequestingCompleted(segmentIndex) { if (!isNaN(segmentIndex)) { maximumIndex = segmentIndex; _checkIfBufferingCompleted(); } } function _onWallclockTimeUpdated() { wallclockTicked++; const secondsElapsed = (wallclockTicked * (settings.get().streaming.wallclockTimeUpdateInterval / 1000)); if ((secondsElapsed &gt;= settings.get().streaming.buffer.bufferPruningInterval)) { wallclockTicked = 0; pruneBuffer(); } } function _onPlaybackRateChanged() { checkIfSufficientBuffer(); } function getBuffer() { return sourceBufferSink; } function getBufferLevel() { return bufferLevel; } function getMediaSource() { return mediaSource; } function getIsBufferingCompleted() { return isBufferingCompleted; } function setIsBufferingCompleted(value) { if (isBufferingCompleted === value) { return; } isBufferingCompleted = value; if (isBufferingCompleted) { _triggerEvent(Events.BUFFERING_COMPLETED); } else { maximumIndex = Number.POSITIVE_INFINITY; } } function getIsPruningInProgress() { return isPruningInProgress; } function getTotalBufferedTime() { try { const ranges = sourceBufferSink.getAllBufferRanges(); let totalBufferedTime = 0; let ln, i; if (!ranges) return totalBufferedTime; for (i = 0, ln = ranges.length; i &lt; ln; i++) { totalBufferedTime += ranges.end(i) - ranges.start(i); } return totalBufferedTime; } catch (e) { return 0; } } /** * This function returns the maximum time for which the buffer is continuous starting from a target time. * As soon as there is a gap we return the time before the gap starts * @param {number} targetTime */ function getContinuousBufferTimeForTargetTime(targetTime) { try { let adjustedTime = targetTime; const ranges = sourceBufferSink.getAllBufferRanges(); if (!ranges || ranges.length === 0) { return NaN; } let i = 0; while (adjustedTime === targetTime &amp;&amp; i &lt; ranges.length) { const start = ranges.start(i); const end = ranges.end(i); if (adjustedTime &gt;= start &amp;&amp; adjustedTime &lt;= end) { adjustedTime = end; } i += 1; } return adjustedTime === targetTime ? NaN : adjustedTime; } catch (e) { } } function hasEnoughSpaceToAppend() { const totalBufferedTime = getTotalBufferedTime(); return (isNaN(totalBufferedTime) || totalBufferedTime &lt; criticalBufferLevel); } function setSeekTarget(value) { seekTarget = value; } function _triggerEvent(eventType, data) { let payload = data || {}; eventBus.trigger(eventType, payload, { streamId: streamInfo.id, mediaType: type }); } function resetInitialSettings(errored, keepBuffers) { criticalBufferLevel = Number.POSITIVE_INFINITY; bufferState = undefined; maximumIndex = Number.POSITIVE_INFINITY; maxAppendedIndex = 0; appendedBytesInfo = null; isBufferingCompleted = false; isPruningInProgress = false; isQuotaExceeded = false; bufferLevel = 0; wallclockTicked = 0; pendingPruningRanges = []; seekTarget = NaN; if (sourceBufferSink) { let tmpSourceBufferSinkToReset = sourceBufferSink; sourceBufferSink = null; if (!errored &amp;&amp; !keepBuffers) { tmpSourceBufferSinkToReset.abort() .then(() =&gt; { tmpSourceBufferSinkToReset.reset(keepBuffers); tmpSourceBufferSinkToReset = null; }); } } replacingBuffer = false; } function reset(errored, keepBuffers) { eventBus.off(Events.INIT_FRAGMENT_LOADED, _onInitFragmentLoaded, this); eventBus.off(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, this); eventBus.off(Events.WALLCLOCK_TIME_UPDATED, _onWallclockTimeUpdated, this); eventBus.off(MediaPlayerEvents.PLAYBACK_PLAYING, _onPlaybackPlaying, this); eventBus.off(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, this); eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, this); eventBus.off(MediaPlayerEvents.PLAYBACK_RATE_CHANGED, _onPlaybackRateChanged, this); eventBus.off(MediaPlayerEvents.PLAYBACK_STALLED, _onPlaybackStalled, this); resetInitialSettings(errored, keepBuffers); } instance = { initialize, getStreamId, getType, getBufferControllerType, createBufferSink, getBuffer, getBufferLevel, getRangeAt, setMediaSource, getMediaSource, appendInitSegmentFromCache, getIsBufferingCompleted, setIsBufferingCompleted, getIsPruningInProgress, reset, prepareForPlaybackSeek, prepareForReplacementTrackSwitch, prepareForNonReplacementTrackSwitch, prepareForReplacementQualitySwitch, updateAppendWindow, getAllRangesWithSafetyFactor, getContinuousBufferTimeForTargetTime, clearBuffers, pruneAllSafely, updateBufferTimestampOffset, setSeekTarget, segmentRequestingCompleted }; setup(); return instance; } BufferController.__dashjs_factory_name = BUFFER_CONTROLLER_TYPE; export default FactoryMaker.getClassFactory(BufferController); × Search results Close "},"streaming_vo_metrics_BufferLevel.js.html":{"id":"streaming_vo_metrics_BufferLevel.js.html","title":"Source: streaming/vo/metrics/BufferLevel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/BufferLevel.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ class BufferLevel { /** * @description This Object holds reference to the current buffer level and the time it was recorded. */ constructor() { /** * Real-Time | Time of the measurement of the buffer level. * @public */ this.t = null; /** * Level of the buffer in milliseconds. Indicates the playout duration for which * media data of all active media components is available starting from the * current playout time. * @public */ this.level = null; } } export default BufferLevel; × Search results Close "},"streaming_vo_metrics_BufferState.js.html":{"id":"streaming_vo_metrics_BufferState.js.html","title":"Source: streaming/vo/metrics/BufferState.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/BufferState.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import MetricsConstants from '../../constants/MetricsConstants'; /** * @class * @ignore */ class BufferState { /** * @description This Object holds reference to the current buffer state of the video element. */ constructor() { /** * The Buffer Level Target determined by the BufferLevelRule. * @public */ this.target = null; /** * Current buffer state. Will be MetricsConstants.BUFFER_EMPTY or MetricsConstants.BUFFER_LOADED. * @public */ this.state = MetricsConstants.BUFFER_EMPTY; } } export default BufferState; × Search results Close "},"streaming_utils_Capabilities.js.html":{"id":"streaming_utils_Capabilities.js.html","title":"Source: streaming/utils/Capabilities.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/Capabilities.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import {THUMBNAILS_SCHEME_ID_URIS} from '../thumbnail/ThumbnailTracks'; import Constants from '../constants/Constants'; const codecCompatibilityTable = [ { 'codec': 'avc1', 'compatibleCodecs': ['avc3'] }, { 'codec': 'avc3', 'compatibleCodecs': ['avc1'] } ]; export function supportsMediaSource() { let hasWebKit = ('WebKitMediaSource' in window); let hasMediaSource = ('MediaSource' in window); return (hasWebKit || hasMediaSource); } function Capabilities() { let instance, settings, encryptedMediaSupported; function setup() { encryptedMediaSupported = false; } function setConfig(config) { if (!config) { return; } if (config.settings) { settings = config.settings; } } /** * Returns whether Encrypted Media Extensions are supported on this * user agent * * @return {boolean} true if EME is supported, false otherwise */ function supportsEncryptedMedia() { return encryptedMediaSupported; } /** * * @param {boolean} value */ function setEncryptedMediaSupported(value) { encryptedMediaSupported = value; } /** * Check if a codec is supported by the MediaSource. We use the MediaCapabilities API or the MSE to check. * @param {object} config * @param {string} type * @return {Promise&lt;boolean&gt;} */ function supportsCodec(config, type) { if (type !== Constants.AUDIO &amp;&amp; type !== Constants.VIDEO) { return Promise.resolve(true); } if (_canUseMediaCapabilitiesApi(config, type)) { return _checkCodecWithMediaCapabilities(config, type); } return _checkCodecWithMse(config); } /** * MediaCapabilitiesAPI throws an error if one of the attribute is missing. We only use it if we have all required information. * @param {object} config * @param {string} type * @return {*|boolean|boolean} * @private */ function _canUseMediaCapabilitiesApi(config, type) { return settings.get().streaming.capabilities.useMediaCapabilitiesApi &amp;&amp; navigator.mediaCapabilities &amp;&amp; navigator.mediaCapabilities.decodingInfo &amp;&amp; ((config.codec &amp;&amp; type === Constants.AUDIO) || (type === Constants.VIDEO &amp;&amp; config.codec &amp;&amp; config.width &amp;&amp; config.height &amp;&amp; config.bitrate &amp;&amp; config.framerate)); } /** * Check codec support using the MSE * @param {object} config * @return {Promise&lt;void&gt; | Promise&lt;boolean&gt;} * @private */ function _checkCodecWithMse(config) { return new Promise((resolve) =&gt; { if (!config || !config.codec) { resolve(false); return; } let codec = config.codec; if (config.width &amp;&amp; config.height) { codec += ';width=\"' + config.width + '\";height=\"' + config.height + '\"'; } if ('MediaSource' in window &amp;&amp; MediaSource.isTypeSupported(codec)) { resolve(true); return; } else if ('WebKitMediaSource' in window &amp;&amp; WebKitMediaSource.isTypeSupported(codec)) { resolve(true); return; } resolve(false); }); } /** * Check codec support using the MediaCapabilities API * @param {object} config * @param {string} type * @return {Promise&lt;boolean&gt;} * @private */ function _checkCodecWithMediaCapabilities(config, type) { return new Promise((resolve) =&gt; { if (!config || !config.codec) { resolve(false); return; } const configuration = { type: 'media-source' }; configuration[type] = {}; configuration[type].contentType = config.codec; configuration[type].width = config.width; configuration[type].height = config.height; configuration[type].bitrate = parseInt(config.bitrate); configuration[type].framerate = parseFloat(config.framerate); navigator.mediaCapabilities.decodingInfo(configuration) .then((result) =&gt; { resolve(result.supported); }) .catch(() =&gt; { resolve(false); }); }); } /** * Check if a specific EssentialProperty is supported * @param {object} ep * @return {boolean} */ function supportsEssentialProperty(ep) { try { return THUMBNAILS_SCHEME_ID_URIS.indexOf(ep.schemeIdUri) !== -1; } catch (e) { return true; } } /** * Check if the root of the old codec is the same as the new one, or if it's declared as compatible in the compat table * @param {string} codec1 * @param {string} codec2 * @return {boolean} */ function codecRootCompatibleWithCodec(codec1, codec2) { const codecRoot = codec1.split('.')[0]; const rootCompatible = codec2.indexOf(codecRoot) === 0; let compatTableCodec; for (let i = 0; i &lt; codecCompatibilityTable.length; i++) { if (codecCompatibilityTable[i].codec === codecRoot) { compatTableCodec = codecCompatibilityTable[i]; break; } } if (compatTableCodec) { return rootCompatible || compatTableCodec.compatibleCodecs.some((compatibleCodec) =&gt; codec2.indexOf(compatibleCodec) === 0); } return rootCompatible; } instance = { setConfig, supportsMediaSource, supportsEncryptedMedia, supportsCodec, setEncryptedMediaSupported, supportsEssentialProperty, codecRootCompatibleWithCodec }; setup(); return instance; } Capabilities.__dashjs_factory_name = 'Capabilities'; export default FactoryMaker.getSingletonFactory(Capabilities); × Search results Close "},"streaming_controllers_CatchupController.js.html":{"id":"streaming_controllers_CatchupController.js.html","title":"Source: streaming/controllers/CatchupController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/CatchupController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import EventBus from '../../core/EventBus'; import Constants from '../constants/Constants'; import MediaPlayerEvents from '../MediaPlayerEvents'; import Events from '../../core/events/Events'; import MetricsConstants from '../constants/MetricsConstants'; import Utils from '../../core/Utils'; function CatchupController() { const context = this.context; const eventBus = EventBus(context).getInstance(); let instance, isCatchupSeekInProgress, isSafari, videoModel, settings, streamController, playbackController, mediaPlayerModel, playbackStalled, logger; function initialize() { _registerEvents(); } function setConfig(config) { if (!config) { return; } if (config.settings) { settings = config.settings; } if (config.videoModel) { videoModel = config.videoModel; } if (config.streamController) { streamController = config.streamController; } if (config.playbackController) { playbackController = config.playbackController; } if (config.mediaPlayerModel) { mediaPlayerModel = config.mediaPlayerModel; } } function _registerEvents() { eventBus.on(MediaPlayerEvents.BUFFER_LEVEL_UPDATED, _onBufferLevelUpdated, instance); eventBus.on(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_SEEKED, _onPlaybackSeeked, instance); eventBus.on(Events.SETTING_UPDATED_CATCHUP_ENABLED, _onCatchupSettingUpdated, instance); } function _unregisterEvents() { eventBus.off(MediaPlayerEvents.BUFFER_LEVEL_UPDATED, _onBufferLevelUpdated, instance); eventBus.off(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_SEEKED, _onPlaybackProgression, instance); eventBus.off(Events.SETTING_UPDATED_CATCHUP_ENABLED, _onCatchupSettingUpdated, instance); } function setup() { logger = Debug(context).getInstance().getLogger(instance); _resetInitialSettings(); } function reset() { _unregisterEvents(); _resetInitialSettings(); videoModel.setPlaybackRate(1.0, true); } function _resetInitialSettings() { isCatchupSeekInProgress = false; const ua = Utils.parseUserAgent(); isSafari = ua &amp;&amp; ua.browser &amp;&amp; ua.browser.name &amp;&amp; ua.browser.name.toLowerCase() === 'safari'; } function _onPlaybackSeeked() { isCatchupSeekInProgress = false; } /** * When the buffer level updated we check if we can remove the stalled state * @param {object} e * @private */ function _onBufferLevelUpdated(e) { // do not stop when getting an event from Stream that is not active if (e.streamId !== streamController.getActiveStreamInfo().id || !playbackStalled) { return; } // we remove the stalled state once we reach a certain buffer level const liveDelay = playbackController.getLiveDelay(); const bufferLevel = playbackController.getBufferLevel(); if (bufferLevel &gt; liveDelay / 2) { playbackStalled = false; } } /** * When the buffer state changed to BUFFER_EMPTY we update the stalled state * @param {object} e * @private */ function _onBufferLevelStateChanged(e) { // do not stop when getting an event from Stream that is not active if (e.streamId !== streamController.getActiveStreamInfo().id) { return; } playbackStalled = e.state === MetricsConstants.BUFFER_EMPTY; } /** * If the catchup mode is disabled in the settings we reset playback rate to 1.0 * @private */ function _onCatchupSettingUpdated() { if (!mediaPlayerModel.getCatchupModeEnabled()) { videoModel.setPlaybackRate(1.0); } } /** * While playback is progressing we check if we need to start or stop the catchup mechanism to reach the target latency * @private */ function _onPlaybackProgression() { if (playbackController.getIsDynamic() &amp;&amp; mediaPlayerModel.getCatchupModeEnabled() &amp;&amp; mediaPlayerModel.getCatchupPlaybackRate() &gt; 0 &amp;&amp; !playbackController.isPaused() &amp;&amp; !playbackController.isSeeking() &amp;&amp; _shouldStartCatchUp()) { _startPlaybackCatchUp(); } } /** * Apply catchup mode. We either seek back to the target live edge or increase the playback rate. */ function _startPlaybackCatchUp() { // we are seeking dont do anything for now if (isCatchupSeekInProgress) { return; } if (videoModel) { let newRate; const currentPlaybackRate = videoModel.getPlaybackRate(); const liveCatchupPlaybackRate = mediaPlayerModel.getCatchupPlaybackRate(); const bufferLevel = playbackController.getBufferLevel(); const deltaLatency = _getLatencyDrift(); // we reached the maxDrift. Do a seek const maxDrift = mediaPlayerModel.getCatchupMaxDrift(); if (!isNaN(maxDrift) &amp;&amp; maxDrift &gt; 0 &amp;&amp; deltaLatency &gt; maxDrift) { logger.info('[CatchupController]: Low Latency catchup mechanism. Latency too high, doing a seek to live point'); isCatchupSeekInProgress = true; playbackController.seekToCurrentLive(true, false); } // try to reach the target latency by adjusting the playback rate else { const currentLiveLatency = playbackController.getCurrentLiveLatency(); const targetLiveDelay = playbackController.getLiveDelay(); if (_getCatchupMode() === Constants.LIVE_CATCHUP_MODE_LOLP) { // Custom playback control: Based on buffer level const playbackBufferMin = settings.get().streaming.liveCatchup.playbackBufferMin; newRate = _calculateNewPlaybackRateLolP(liveCatchupPlaybackRate, currentLiveLatency, targetLiveDelay, playbackBufferMin, bufferLevel, currentPlaybackRate); } else { // Default playback control: Based on target and current latency newRate = _calculateNewPlaybackRateDefault(liveCatchupPlaybackRate, currentLiveLatency, targetLiveDelay, bufferLevel, currentPlaybackRate); } // We adjust the min change linear, depending on the maximum catchup rate. Default is 0.02 for rate 0.5. // For Safari we stick to a fixed value because of https://bugs.webkit.org/show_bug.cgi?id=208142 const minPlaybackRateChange = isSafari ? 0.25 : 0.02 / (0.5 / liveCatchupPlaybackRate); // Obtain newRate and apply to video model. Don't change playbackrate for small variations (don't overload element with playbackrate changes) if (newRate &amp;&amp; Math.abs(currentPlaybackRate - newRate) &gt;= minPlaybackRateChange) { // non-null logger.debug(`[CatchupController]: Setting playback rate to ${newRate}`); videoModel.setPlaybackRate(newRate); } } } } /** * Calculates the drift between the current latency and the target latency * @return {number} * @private */ function _getLatencyDrift() { const currentLiveLatency = playbackController.getCurrentLiveLatency(); const targetLiveDelay = playbackController.getLiveDelay(); return currentLiveLatency - targetLiveDelay; } /** * Checks whether the catchup mechanism should be enabled. We use different subfunctions here depending on the catchup mode. * @return {boolean} */ function _shouldStartCatchUp() { try { if (!playbackController.getTime() &gt; 0 || isCatchupSeekInProgress) { return false; } const catchupMode = _getCatchupMode(); if (catchupMode === Constants.LIVE_CATCHUP_MODE_LOLP) { const currentBuffer = playbackController.getBufferLevel(); const playbackBufferMin = settings.get().streaming.liveCatchup.playbackBufferMin; return _lolpNeedToCatchUpCustom(currentBuffer, playbackBufferMin); } else { return _defaultNeedToCatchUp(); } } catch (e) { return false; } } /** * Returns the mode for live playback catchup. * @return {String} * @private */ function _getCatchupMode() { const playbackBufferMin = settings.get().streaming.liveCatchup.playbackBufferMin; return settings.get().streaming.liveCatchup.mode === Constants.LIVE_CATCHUP_MODE_LOLP &amp;&amp; playbackBufferMin !== null &amp;&amp; !isNaN(playbackBufferMin) ? Constants.LIVE_CATCHUP_MODE_LOLP : Constants.LIVE_CATCHUP_MODE_DEFAULT; } /** * Default algorithm to determine if catchup mode should be enabled * @return {boolean} * @private */ function _defaultNeedToCatchUp() { try { const latencyDrift = Math.abs(_getLatencyDrift()); return latencyDrift &gt; 0; } catch (e) { return false; } } /** * LoL+ logic to determine if catchup mode should be enabled * @param {number} currentBuffer * @param {number} playbackBufferMin * @return {boolean} * @private */ function _lolpNeedToCatchUpCustom(currentBuffer, playbackBufferMin) { try { const latencyDrift = Math.abs(_getLatencyDrift()); return latencyDrift &gt; 0 || currentBuffer &lt; playbackBufferMin; } catch (e) { return false; } } /** * Default algorithm to calculate the new playback rate * @param {number} liveCatchUpPlaybackRate * @param {number} currentLiveLatency * @param {number} liveDelay * @param {number} bufferLevel * @param {number} currentPlaybackRate * @return {number} * @private */ function _calculateNewPlaybackRateDefault(liveCatchUpPlaybackRate, currentLiveLatency, liveDelay, bufferLevel) { // if we recently ran into an empty buffer we wait for the buffer to recover before applying a new rate if (playbackStalled) { return 1.0; } const cpr = liveCatchUpPlaybackRate; const deltaLatency = currentLiveLatency - liveDelay; const d = deltaLatency * 5; // Playback rate must be between (1 - cpr) - (1 + cpr) // ex: if cpr is 0.5, it can have values between 0.5 - 1.5 const s = (cpr * 2) / (1 + Math.pow(Math.E, -d)); let newRate = (1 - cpr) + s; // take into account situations in which there are buffer stalls, // in which increasing playbackRate to reach target latency will // just cause more and more stall situations if (playbackController.getPlaybackStalled()) { if (bufferLevel &lt;= liveDelay / 2 &amp;&amp; deltaLatency &gt; 0) { newRate = 1.0; } } return newRate; } /** * Lol+ algorithm to calculate the new playback rate * @param {number} liveCatchUpPlaybackRate * @param {number} currentLiveLatency * @param {number} liveDelay * @param {number} playbackBufferMin * @param {number} bufferLevel * @param {number} currentPlaybackRate * @return {number} * @private */ function _calculateNewPlaybackRateLolP(liveCatchUpPlaybackRate, currentLiveLatency, liveDelay, playbackBufferMin, bufferLevel) { const cpr = liveCatchUpPlaybackRate; let newRate; // Hybrid: Buffer-based if (bufferLevel &lt; playbackBufferMin) { // Buffer in danger, slow down const deltaBuffer = bufferLevel - playbackBufferMin; // -ve value const d = deltaBuffer * 5; // Playback rate must be between (1 - cpr) - (1 + cpr) // ex: if cpr is 0.5, it can have values between 0.5 - 1.5 const s = (cpr * 2) / (1 + Math.pow(Math.E, -d)); newRate = (1 - cpr) + s; logger.debug('[LoL+ playback control_buffer-based] bufferLevel: ' + bufferLevel + ', newRate: ' + newRate); } else { // Hybrid: Latency-based // Buffer is safe, vary playback rate based on latency // Check if latency is within range of target latency const minDifference = 0.02; if (Math.abs(currentLiveLatency - liveDelay) &lt;= (minDifference * liveDelay)) { newRate = 1; } else { const deltaLatency = currentLiveLatency - liveDelay; const d = deltaLatency * 5; // Playback rate must be between (1 - cpr) - (1 + cpr) // ex: if cpr is 0.5, it can have values between 0.5 - 1.5 const s = (cpr * 2) / (1 + Math.pow(Math.E, -d)); newRate = (1 - cpr) + s; } logger.debug('[LoL+ playback control_latency-based] latency: ' + currentLiveLatency + ', newRate: ' + newRate); } return newRate } instance = { reset, setConfig, initialize }; setup(); return instance; } CatchupController.__dashjs_factory_name = 'CatchupController'; export default FactoryMaker.getSingletonFactory(CatchupController); × Search results Close "},"streaming_protection_vo_ClearKeyKeySet.js.html":{"id":"streaming_protection_vo_ClearKeyKeySet.js.html","title":"Source: streaming/protection/vo/ClearKeyKeySet.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/vo/ClearKeyKeySet.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @classdesc A collection of ClearKey encryption keys with an (optional) associated * type * @ignore */ class ClearKeyKeySet { /** * @param {Array.&lt;KeyPair&gt;} keyPairs * @param {string} type the type of keys in this set. One of either 'persistent' * or 'temporary'. Can also be null or undefined. * @class * @ignore */ constructor(keyPairs, type) { if (type &amp;&amp; type !== 'persistent' &amp;&amp; type !== 'temporary') throw new Error('Invalid ClearKey key set type! Must be one of \\'persistent\\' or \\'temporary\\''); this.keyPairs = keyPairs; this.type = type; } /** * Convert this key set to its JSON Web Key (JWK) representation * * @return {ArrayBuffer} JWK object UTF-8 encoded as ArrayBuffer */ toJWK() { let i; let numKeys = this.keyPairs.length; let jwk = {keys: []}; for (i = 0; i &lt; numKeys; i++) { let key = { kty: 'oct', alg: 'A128KW', kid: this.keyPairs[i].keyID, k: this.keyPairs[i].key }; jwk.keys.push(key); } if (this.type) { jwk.type = this.type; } let jwkString = JSON.stringify(jwk); const len = jwkString.length; // Convert JSON string to ArrayBuffer let buf = new ArrayBuffer(len); let bView = new Uint8Array(buf); for (i = 0; i &lt; len; i++) bView[i] = jwkString.charCodeAt(i); return buf; } } export default ClearKeyKeySet; × Search results Close "},"streaming_protection_CommonEncryption.js.html":{"id":"streaming_protection_CommonEncryption.js.html","title":"Source: streaming/protection/CommonEncryption.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/CommonEncryption.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ const LICENSE_SERVER_MANIFEST_CONFIGURATIONS = { attributes: ['Laurl', 'laurl'], prefixes: ['clearkey', 'dashif'] }; /** * @class * @ignore */ class CommonEncryption { /** * Find and return the ContentProtection element in the given array * that indicates support for MPEG Common Encryption * * @param {Array} cpArray array of content protection elements * @returns {Object|null} the Common Encryption content protection element or * null if one was not found */ static findCencContentProtection(cpArray) { let retVal = null; for (let i = 0; i &lt; cpArray.length; ++i) { let cp = cpArray[i]; if (cp.schemeIdUri.toLowerCase() === 'urn:mpeg:dash:mp4protection:2011' &amp;&amp; (cp.value.toLowerCase() === 'cenc' || cp.value.toLowerCase() === 'cbcs')) retVal = cp; } return retVal; } /** * Returns just the data portion of a single PSSH * * @param {ArrayBuffer} pssh - the PSSH * @return {ArrayBuffer} data portion of the PSSH */ static getPSSHData(pssh) { let offset = 8; // Box size and type fields let view = new DataView(pssh); // Read version let version = view.getUint8(offset); offset += 20; // Version (1), flags (3), system ID (16) if (version &gt; 0) { offset += 4 + (16 * view.getUint32(offset)); // Key ID count (4) and All key IDs (16*count) } offset += 4; // Data size return pssh.slice(offset); } /** * Returns the PSSH associated with the given key system from the concatenated * list of PSSH boxes in the given initData * * @param {KeySystem} keySystem the desired * key system * @param {ArrayBuffer} initData 'cenc' initialization data. Concatenated list of PSSH. * @returns {ArrayBuffer|null} The PSSH box data corresponding to the given key system, null if not found * or null if a valid association could not be found. */ static getPSSHForKeySystem(keySystem, initData) { let psshList = CommonEncryption.parsePSSHList(initData); if (keySystem &amp;&amp; psshList.hasOwnProperty(keySystem.uuid.toLowerCase())) { return psshList[keySystem.uuid.toLowerCase()]; } return null; } /** * Parse a standard common encryption PSSH which contains a simple * base64-encoding of the init data * * @param {Object} cpData the ContentProtection element * @param {BASE64} BASE64 reference * @returns {ArrayBuffer|null} the init data or null if not found */ static parseInitDataFromContentProtection(cpData, BASE64) { if ('pssh' in cpData) { // Remove whitespaces and newlines from pssh text cpData.pssh.__text = cpData.pssh.__text.replace(/\\r?\\n|\\r/g, '').replace(/\\s+/g, ''); return BASE64.decodeArray(cpData.pssh.__text).buffer; } return null; } /** * Parses list of PSSH boxes into keysystem-specific PSSH data * * @param {ArrayBuffer} data - the concatenated list of PSSH boxes as provided by * CDM as initialization data when CommonEncryption content is detected * @returns {Object|Array} an object that has a property named according to each of * the detected key system UUIDs (e.g. 00000000-0000-0000-0000-0000000000) * and a ArrayBuffer (the entire PSSH box) as the property value */ static parsePSSHList(data) { if (data === null || data === undefined) return []; let dv = new DataView(data.buffer || data); // data.buffer first for Uint8Array support let done = false; let pssh = {}; // TODO: Need to check every data read for end of buffer let byteCursor = 0; while (!done) { let size, nextBox, version, systemID; let boxStart = byteCursor; if (byteCursor &gt;= dv.buffer.byteLength) break; /* Box size */ size = dv.getUint32(byteCursor); nextBox = byteCursor + size; byteCursor += 4; /* Verify PSSH */ if (dv.getUint32(byteCursor) !== 0x70737368) { byteCursor = nextBox; continue; } byteCursor += 4; /* Version must be 0 or 1 */ version = dv.getUint8(byteCursor); if (version !== 0 &amp;&amp; version !== 1) { byteCursor = nextBox; continue; } byteCursor++; byteCursor += 3; /* skip flags */ // 16-byte UUID/SystemID systemID = ''; let i, val; for (i = 0; i &lt; 4; i++) { val = dv.getUint8(byteCursor + i).toString(16); systemID += (val.length === 1) ? '0' + val : val; } byteCursor += 4; systemID += '-'; for (i = 0; i &lt; 2; i++) { val = dv.getUint8(byteCursor + i).toString(16); systemID += (val.length === 1) ? '0' + val : val; } byteCursor += 2; systemID += '-'; for (i = 0; i &lt; 2; i++) { val = dv.getUint8(byteCursor + i).toString(16); systemID += (val.length === 1) ? '0' + val : val; } byteCursor += 2; systemID += '-'; for (i = 0; i &lt; 2; i++) { val = dv.getUint8(byteCursor + i).toString(16); systemID += (val.length === 1) ? '0' + val : val; } byteCursor += 2; systemID += '-'; for (i = 0; i &lt; 6; i++) { val = dv.getUint8(byteCursor + i).toString(16); systemID += (val.length === 1) ? '0' + val : val; } byteCursor += 6; systemID = systemID.toLowerCase(); /* PSSH Data Size */ byteCursor += 4; /* PSSH Data */ pssh[systemID] = dv.buffer.slice(boxStart, nextBox); byteCursor = nextBox; } return pssh; } static getLicenseServerUrlFromMediaInfo(mediaInfo, schemeIdUri) { try { if (!mediaInfo || mediaInfo.length === 0) { return null; } let i = 0; let licenseServer = null; while (i &lt; mediaInfo.length &amp;&amp; !licenseServer) { const info = mediaInfo[i]; if (info &amp;&amp; info.contentProtection &amp;&amp; info.contentProtection.length &gt; 0) { const targetProtectionData = info.contentProtection.filter((cp) =&gt; { return cp.schemeIdUri &amp;&amp; cp.schemeIdUri === schemeIdUri; }); if (targetProtectionData &amp;&amp; targetProtectionData.length &gt; 0) { let j = 0; while (j &lt; targetProtectionData.length &amp;&amp; !licenseServer) { const ckData = targetProtectionData[j]; let k = 0; while (k &lt; LICENSE_SERVER_MANIFEST_CONFIGURATIONS.attributes.length &amp;&amp; !licenseServer) { let l = 0; const attribute = LICENSE_SERVER_MANIFEST_CONFIGURATIONS.attributes[k]; while (l &lt; LICENSE_SERVER_MANIFEST_CONFIGURATIONS.prefixes.length &amp;&amp; !licenseServer) { const prefix = LICENSE_SERVER_MANIFEST_CONFIGURATIONS.prefixes[l]; if (ckData[attribute] &amp;&amp; ckData[attribute].__prefix &amp;&amp; ckData[attribute].__prefix === prefix &amp;&amp; ckData[attribute].__text) { licenseServer = ckData[attribute].__text; } l += 1; } k += 1; } j += 1; } } } i += 1; } return licenseServer; } catch (e) { return null; } } } export default CommonEncryption; × Search results Close "},"streaming_constants_Constants.js.html":{"id":"streaming_constants_Constants.js.html","title":"Source: streaming/constants/Constants.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/constants/Constants.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Constants declaration * @class * @ignore * @hideconstructor */ class Constants { init() { /** * @constant {string} STREAM Stream media type. Mainly used to report metrics relative to the full stream * @memberof Constants# * @static */ this.STREAM = 'stream'; /** * @constant {string} VIDEO Video media type * @memberof Constants# * @static */ this.VIDEO = 'video'; /** * @constant {string} AUDIO Audio media type * @memberof Constants# * @static */ this.AUDIO = 'audio'; /** * @constant {string} TEXT Text media type * @memberof Constants# * @static */ this.TEXT = 'text'; /** * @constant {string} MUXED Muxed (video/audio in the same chunk) media type * @memberof Constants# * @static */ this.MUXED = 'muxed'; /** * @constant {string} IMAGE Image media type * @memberof Constants# * @static */ this.IMAGE = 'image'; /** * @constant {string} STPP STTP Subtitles format * @memberof Constants# * @static */ this.STPP = 'stpp'; /** * @constant {string} TTML STTP Subtitles format * @memberof Constants# * @static */ this.TTML = 'ttml'; /** * @constant {string} VTT STTP Subtitles format * @memberof Constants# * @static */ this.VTT = 'vtt'; /** * @constant {string} WVTT STTP Subtitles format * @memberof Constants# * @static */ this.WVTT = 'wvtt'; /** * @constant {string} Content Steering * @memberof Constants# * @static */ this.CONTENT_STEERING = 'contentSteering'; /** * @constant {string} ABR_STRATEGY_DYNAMIC Dynamic Adaptive bitrate algorithm * @memberof Constants# * @static */ this.ABR_STRATEGY_DYNAMIC = 'abrDynamic'; /** * @constant {string} ABR_STRATEGY_BOLA Adaptive bitrate algorithm based on Bola (buffer level) * @memberof Constants# * @static */ 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# * @static */ 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} ABR_FETCH_THROUGHPUT_CALCULATION_AAST Throughput calculation based on adjusted availability start time in low latency mode * @memberof Constants# * @static */ this.ABR_FETCH_THROUGHPUT_CALCULATION_AAST = 'abrFetchThroughputCalculationAAST'; /** * @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# * @static */ this.MOVING_AVERAGE_SLIDING_WINDOW = 'slidingWindow'; /** * @constant {string} EWMA Exponential moving average * @memberof Constants# * @static */ this.MOVING_AVERAGE_EWMA = 'ewma'; /** * @constant {string} BAD_ARGUMENT_ERROR Invalid Arguments type of error * @memberof Constants# * @static */ this.BAD_ARGUMENT_ERROR = 'Invalid Arguments'; /** * @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_FIRST_TRACK makes the player select the first track found in the manifest. * @memberof Constants# * @static */ this.TRACK_SELECTION_MODE_FIRST_TRACK = 'firstTrack'; /** * @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_HIGHEST_EFFICIENCY makes the player select the track with the lowest bitrate per pixel average. * @memberof Constants# * @static */ this.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY = 'highestEfficiency'; /** * @constant {string} TRACK_SELECTION_MODE_WIDEST_RANGE makes the player select the track with a widest range of bitrates. * @memberof Constants# * @static */ this.TRACK_SELECTION_MODE_WIDEST_RANGE = 'widestRange'; /** * @constant {string} TRACK_SELECTION_MODE_WIDEST_RANGE makes the player select the track with the highest selectionPriority as defined in the manifest * @memberof Constants# * @static */ this.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY = 'highestSelectionPriority'; /** * @constant {string} CMCD_MODE_QUERY specifies to attach CMCD metrics as query parameters. * @memberof Constants# * @static */ this.CMCD_MODE_QUERY = 'query'; /** * @constant {string} CMCD_MODE_HEADER specifies to attach CMCD metrics as HTTP headers. * @memberof Constants# * @static */ this.CMCD_MODE_HEADER = 'header'; this.LOCATION = 'Location'; this.INITIALIZE = 'initialize'; this.TEXT_SHOWING = 'showing'; this.TEXT_HIDDEN = 'hidden'; this.CC1 = 'CC1'; this.CC3 = 'CC3'; this.UTF8 = 'utf-8'; this.SCHEME_ID_URI = 'schemeIdUri'; this.START_TIME = 'starttime'; this.SERVICE_DESCRIPTION_DVB_LL_SCHEME = 'urn:dvb:dash:lowlatency:scope:2019'; this.SUPPLEMENTAL_PROPERTY_DVB_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'; this.VIDEO_ELEMENT_READY_STATES = { HAVE_NOTHING: 0, HAVE_METADATA: 1, HAVE_CURRENT_DATA: 2, HAVE_FUTURE_DATA: 3, HAVE_ENOUGH_DATA: 4 }; this.FILE_LOADER_TYPES = { FETCH: 'fetch_loader', XHR: 'xhr_loader' } } constructor() { this.init(); } } const constants = new Constants(); export default constants; × Search results Close "},"streaming_models_CustomParametersModel.js.html":{"id":"streaming_models_CustomParametersModel.js.html","title":"Source: streaming/models/CustomParametersModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/models/CustomParametersModel.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import UTCTiming from '../../dash/vo/UTCTiming'; import FactoryMaker from '../../core/FactoryMaker'; import Settings from '../../core/Settings'; import {checkParameterType} from '../utils/SupervisorTools'; import ABRRulesCollection from '../rules/abr/ABRRulesCollection'; import Constants from '../constants/Constants'; const DEFAULT_XHR_WITH_CREDENTIALS = false; function CustomParametersModel() { let instance, utcTimingSources, xhrWithCredentials, licenseRequestFilters, licenseResponseFilters, customCapabilitiesFilters, customInitialTrackSelectionFunction, customAbrRules; const context = this.context; const settings = Settings(context).getInstance(); function setup() { xhrWithCredentials = { default: DEFAULT_XHR_WITH_CREDENTIALS }; _resetInitialSettings(); } function _resetInitialSettings() { licenseRequestFilters = []; licenseResponseFilters = []; customCapabilitiesFilters = []; customAbrRules = []; customInitialTrackSelectionFunction = null; utcTimingSources = []; } function reset() { _resetInitialSettings(); } function setConfig() { } /** * Registers a custom initial track selection function. Only one function is allowed. Calling this method will overwrite a potentially existing function. * @param {function} customFunc - the custom function that returns the initial track */ function setCustomInitialTrackSelectionFunction(customFunc) { customInitialTrackSelectionFunction = customFunc; } /** * Resets the custom initial track selection */ function resetCustomInitialTrackSelectionFunction() { customInitialTrackSelectionFunction = null; } /** * Returns the initial track selection function * @return {function} */ function getCustomInitialTrackSelectionFunction() { return customInitialTrackSelectionFunction; } /** * Returns all license request filters * @return {array} */ function getLicenseRequestFilters() { return licenseRequestFilters; } /** * Returns all license response filters * @return {array} */ function getLicenseResponseFilters() { return licenseResponseFilters; } /** * Registers a license request filter. This enables application to manipulate/overwrite any request parameter and/or request data. * The provided callback function shall return a promise that shall be resolved once the filter process is completed. * The filters are applied in the order they are registered. * @param {function} filter - the license request filter callback */ function registerLicenseRequestFilter(filter) { licenseRequestFilters.push(filter); } /** * Registers a license response filter. This enables application to manipulate/overwrite the response data * The provided callback function shall return a promise that shall be resolved once the filter process is completed. * The filters are applied in the order they are registered. * @param {function} filter - the license response filter callback */ function registerLicenseResponseFilter(filter) { licenseResponseFilters.push(filter); } /** * Unregisters a license request filter. * @param {function} filter - the license request filter callback */ function unregisterLicenseRequestFilter(filter) { _unregisterFilter(licenseRequestFilters, filter); } /** * Unregisters a license response filter. * @param {function} filter - the license response filter callback */ function unregisterLicenseResponseFilter(filter) { _unregisterFilter(licenseResponseFilters, filter); } /** * Returns all custom capabilities filter * @return {array} */ function getCustomCapabilitiesFilters() { return customCapabilitiesFilters; } /** * Registers a custom capabilities filter. This enables application to filter representations to use. * The provided callback function shall return a boolean based on whether or not to use the representation. * The filters are applied in the order they are registered. * @param {function} filter - the custom capabilities filter callback */ function registerCustomCapabilitiesFilter(filter) { customCapabilitiesFilters.push(filter); } /** * Unregisters a custom capabilities filter. * @param {function} filter - the custom capabilities filter callback */ function unregisterCustomCapabilitiesFilter(filter) { _unregisterFilter(customCapabilitiesFilters, filter); } /** * Unregister a filter from the list of existing filers. * @param {array} filters * @param {function} filter * @private */ function _unregisterFilter(filters, filter) { let index = -1; filters.some((item, i) =&gt; { if (item === filter) { index = i; return true; } }); if (index &lt; 0) return; filters.splice(index, 1); } /** * Iterate through the list of custom ABR rules and find the right rule by name * @param {string} rulename * @return {number} rule number */ function _findAbrCustomRuleIndex(rulename) { let i; for (i = 0; i &lt; customAbrRules.length; i++) { if (customAbrRules[i].rulename === rulename) { return i; } } return -1; } /** * Add a custom ABR Rule * Rule will be apply on next stream if a stream is being played * * @param {string} type - rule type (one of ['qualitySwitchRules','abandonFragmentRules']) * @param {string} rulename - name of rule (used to identify custom rule). If one rule of same name has been added, then existing rule will be updated * @param {object} rule - the rule object instance * @throws {@link Constants#BAD_ARGUMENT_ERROR BAD_ARGUMENT_ERROR} if called with invalid arguments. */ function addAbrCustomRule(type, rulename, rule) { if (typeof type !== 'string' || (type !== ABRRulesCollection.ABANDON_FRAGMENT_RULES &amp;&amp; type !== ABRRulesCollection.QUALITY_SWITCH_RULES) || typeof rulename !== 'string') { throw Constants.BAD_ARGUMENT_ERROR; } let index = _findAbrCustomRuleIndex(rulename); if (index === -1) { // add rule customAbrRules.push({ type: type, rulename: rulename, rule: rule }); } else { // update rule customAbrRules[index].type = type; customAbrRules[index].rule = rule; } } /** * Remove a custom ABR Rule * * @param {string} rulename - name of the rule to be removed */ function removeAbrCustomRule(rulename) { if (rulename) { let index = _findAbrCustomRuleIndex(rulename); //if no rulename custom rule has been found, do nothing if (index !== -1) { // remove rule customAbrRules.splice(index, 1); } } else { //if no rulename is defined, remove all ABR custome rules customAbrRules = []; } } /** * Remove all custom rules */ function removeAllAbrCustomRule() { customAbrRules = []; } /** * Return all ABR custom rules * @return {array} */ function getAbrCustomRules() { return customAbrRules; } /** * Add a UTC timing source at the top of the list * @param {string} schemeIdUri * @param {string} value */ function addUTCTimingSource(schemeIdUri, value) { removeUTCTimingSource(schemeIdUri, value); //check if it already exists and remove if so. let vo = new UTCTiming(); vo.schemeIdUri = schemeIdUri; vo.value = value; utcTimingSources.push(vo); } /** * Return all UTC timing sources * @return {array} */ function getUTCTimingSources() { return utcTimingSources; } /** * Remove a specific timing source from the array * @param {string} schemeIdUri * @param {string} value */ function removeUTCTimingSource(schemeIdUri, value) { checkParameterType(schemeIdUri, 'string'); checkParameterType(value, 'string'); utcTimingSources.forEach(function (obj, idx) { if (obj.schemeIdUri === schemeIdUri &amp;&amp; obj.value === value) { utcTimingSources.splice(idx, 1); } }); } /** * Remove all timing sources */ function clearDefaultUTCTimingSources() { utcTimingSources = []; } /** * Add the default timing source to the list */ function restoreDefaultUTCTimingSources() { let defaultUtcTimingSource = settings.get().streaming.utcSynchronization.defaultTimingSource; addUTCTimingSource(defaultUtcTimingSource.scheme, defaultUtcTimingSource.value); } function setXHRWithCredentialsForType(type, value) { if (!type) { Object.keys(xhrWithCredentials).forEach(key =&gt; { setXHRWithCredentialsForType(key, value); }); } else { xhrWithCredentials[type] = !!value; } } function getXHRWithCredentialsForType(type) { const useCreds = xhrWithCredentials[type]; return useCreds === undefined ? xhrWithCredentials.default : useCreds; } instance = { getCustomInitialTrackSelectionFunction, setCustomInitialTrackSelectionFunction, resetCustomInitialTrackSelectionFunction, getLicenseResponseFilters, getLicenseRequestFilters, getCustomCapabilitiesFilters, registerCustomCapabilitiesFilter, registerLicenseResponseFilter, registerLicenseRequestFilter, unregisterCustomCapabilitiesFilter, unregisterLicenseResponseFilter, unregisterLicenseRequestFilter, addAbrCustomRule, removeAllAbrCustomRule, removeAbrCustomRule, getAbrCustomRules, addUTCTimingSource, removeUTCTimingSource, getUTCTimingSources, clearDefaultUTCTimingSources, restoreDefaultUTCTimingSources, setXHRWithCredentialsForType, getXHRWithCredentialsForType, setConfig, reset }; setup(); return instance; } CustomParametersModel.__dashjs_factory_name = 'CustomParametersModel'; export default FactoryMaker.getSingletonFactory(CustomParametersModel); × Search results Close "},"dash_DashHandler.js.html":{"id":"dash_DashHandler.js.html","title":"Source: dash/DashHandler.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: dash/DashHandler.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FragmentRequest from '../streaming/vo/FragmentRequest'; import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; import FactoryMaker from '../core/FactoryMaker'; import MediaPlayerEvents from '../streaming/MediaPlayerEvents'; import { replaceIDForTemplate, replaceTokenForTemplate, unescapeDollarsInTemplate } from './utils/SegmentsUtils'; import DashConstants from './constants/DashConstants'; const DEFAULT_ADJUST_SEEK_TIME_THRESHOLD = 0.5; function DashHandler(config) { config = config || {}; const eventBus = config.eventBus; const debug = config.debug; const urlUtils = config.urlUtils; const type = config.type; const streamInfo = config.streamInfo; const segmentsController = config.segmentsController; const timelineConverter = config.timelineConverter; const baseURLController = config.baseURLController; let instance, logger, lastSegment, isDynamicManifest, mediaHasFinished; function setup() { logger = debug.getLogger(instance); resetInitialSettings(); eventBus.on(MediaPlayerEvents.DYNAMIC_TO_STATIC, _onDynamicToStatic, instance); } function initialize(isDynamic) { isDynamicManifest = isDynamic; mediaHasFinished = false; segmentsController.initialize(isDynamic); } function getStreamId() { return streamInfo.id; } function getType() { return type; } function getStreamInfo() { return streamInfo; } function resetInitialSettings() { lastSegment = null; } function reset() { resetInitialSettings(); eventBus.off(MediaPlayerEvents.DYNAMIC_TO_STATIC, _onDynamicToStatic, instance); } function _setRequestUrl(request, destination, representation) { const baseURL = baseURLController.resolve(representation.path); let url, serviceLocation; if (!baseURL || (destination === baseURL.url) || (!urlUtils.isRelative(destination))) { url = destination; } else { url = baseURL.url; serviceLocation = baseURL.serviceLocation; if (destination) { url = urlUtils.resolve(destination, url); } } if (urlUtils.isRelative(url)) { return false; } request.url = url; request.serviceLocation = serviceLocation; return true; } function getInitRequest(mediaInfo, representation) { if (!representation) return null; return _generateInitRequest(mediaInfo, representation, getType()); } function _generateInitRequest(mediaInfo, representation, mediaType) { const request = new FragmentRequest(); const period = representation.adaptation.period; const presentationStartTime = period.start; request.mediaType = mediaType; request.type = HTTPRequest.INIT_SEGMENT_TYPE; request.range = representation.range; request.availabilityStartTime = timelineConverter.calcAvailabilityStartTimeFromPresentationTime(presentationStartTime, representation, isDynamicManifest); request.availabilityEndTime = timelineConverter.calcAvailabilityEndTimeFromPresentationTime(presentationStartTime + period.duration, representation, isDynamicManifest); request.quality = representation.index; request.mediaInfo = mediaInfo; request.representationId = representation.id; if (_setRequestUrl(request, representation.initialization, representation)) { request.url = replaceTokenForTemplate(request.url, 'Bandwidth', representation.bandwidth); return request; } } function _getRequestForSegment(mediaInfo, segment) { if (segment === null || segment === undefined) { return null; } const request = new FragmentRequest(); const representation = segment.representation; const bandwidth = representation.adaptation.period.mpd.manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index].Representation_asArray[representation.index].bandwidth; let url = segment.media; url = replaceTokenForTemplate(url, 'Number', segment.replacementNumber); url = replaceTokenForTemplate(url, 'Time', segment.replacementTime); url = replaceTokenForTemplate(url, 'Bandwidth', bandwidth); url = replaceIDForTemplate(url, representation.id); url = unescapeDollarsInTemplate(url); request.mediaType = getType(); request.type = 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; request.availabilityEndTime = segment.availabilityEndTime; request.availabilityTimeComplete = representation.availabilityTimeComplete; request.wallStartTime = segment.wallStartTime; request.quality = representation.index; request.index = segment.index; request.mediaInfo = mediaInfo; request.adaptationIndex = representation.adaptation.index; request.representationId = representation.id; if (_setRequestUrl(request, url, representation)) { return request; } } function isLastSegmentRequested(representation, bufferingTime) { if (!representation || !lastSegment) { return false; } // Either transition from dynamic to static was done or no next static segment found if (mediaHasFinished) { return true; } // Period is endless if (!isFinite(representation.adaptation.period.duration)) { return false; } // we are replacing existing stuff in the buffer for instance after a track switch if (lastSegment.presentationStartTime + lastSegment.duration &gt; bufferingTime) { return false; } // Additional segment references may be added to the last period. // Additional periods may be added to the end of the MPD. // Segment references SHALL NOT be added to any period other than the last period. // An MPD update MAY combine adding segment references to the last period with adding of new periods. An MPD update that adds content MAY be combined with an MPD update that removes content. // The index of the last requested segment is higher than the number of available segments. // For SegmentTimeline and SegmentTemplate the index does not include the startNumber. // For SegmentList the index includes the startnumber which is why the numberOfSegments includes this as well if (representation.mediaFinishedInformation &amp;&amp; !isNaN(representation.mediaFinishedInformation.numberOfSegments) &amp;&amp; !isNaN(lastSegment.index) &amp;&amp; lastSegment.index &gt;= (representation.mediaFinishedInformation.numberOfSegments - 1)) { // For static manifests and Template addressing we can compare the index against the number of available segments if (!isDynamicManifest || representation.segmentInfoType === DashConstants.SEGMENT_TEMPLATE) { return true; } // For SegmentList we need to check if the next period is signaled else if (isDynamicManifest &amp;&amp; representation.segmentInfoType === DashConstants.SEGMENT_LIST &amp;&amp; representation.adaptation.period.nextPeriodId) { return true } } // For dynamic SegmentTimeline manifests we need to check if the next period is already signaled and the segment we fetched before is the last one that is signaled. // We can not simply use the index, as numberOfSegments might have decreased after an MPD update return !!(isDynamicManifest &amp;&amp; representation.adaptation.period.nextPeriodId &amp;&amp; representation.segmentInfoType === DashConstants.SEGMENT_TIMELINE &amp;&amp; representation.mediaFinishedInformation &amp;&amp; !isNaN(representation.mediaFinishedInformation.mediaTimeOfLastSignaledSegment) &amp;&amp; lastSegment &amp;&amp; !isNaN(lastSegment.mediaStartTime) &amp;&amp; !isNaN(lastSegment.duration) &amp;&amp; lastSegment.mediaStartTime + lastSegment.duration &gt;= (representation.mediaFinishedInformation.mediaTimeOfLastSignaledSegment - 0.05)); } function getSegmentRequestForTime(mediaInfo, representation, time) { let request = null; if (!representation || !representation.segmentInfoType) { return request; } const segment = segmentsController.getSegmentByTime(representation, time); if (segment) { lastSegment = segment; logger.debug('Index for time ' + time + ' is ' + segment.index); request = _getRequestForSegment(mediaInfo, segment); } return request; } /** * This function returns the next segment request without modifying any internal variables. Any class (e.g CMCD Model) that needs information about the upcoming request should use this method. * @param {object} mediaInfo * @param {object} representation * @return {FragmentRequest|null} */ function getNextSegmentRequestIdempotent(mediaInfo, representation) { let request = null; let indexToRequest = lastSegment ? lastSegment.index + 1 : 0; const segment = segmentsController.getSegmentByIndex( representation, indexToRequest, lastSegment ? lastSegment.mediaStartTime : -1 ); if (!segment) return null; request = _getRequestForSegment(mediaInfo, segment); return request; } /** * Main function to get the next segment request. * @param {object} mediaInfo * @param {object} representation * @return {FragmentRequest|null} */ function getNextSegmentRequest(mediaInfo, representation) { let request = null; if (!representation || !representation.segmentInfoType) { return null; } let indexToRequest = lastSegment ? lastSegment.index + 1 : 0; const segment = segmentsController.getSegmentByIndex(representation, indexToRequest, lastSegment ? lastSegment.mediaStartTime : -1); // No segment found if (!segment) { // Dynamic manifest there might be something available in the next iteration if (isDynamicManifest &amp;&amp; !mediaHasFinished) { logger.debug(getType() + ' No segment found at index: ' + indexToRequest + '. Wait for next loop'); return null; } else { mediaHasFinished = true; } } else { request = _getRequestForSegment(mediaInfo, segment); lastSegment = segment; } return request; } /** * This function returns a time for which we can generate a request. It is supposed to be as close as possible to the target time. * This is useful in scenarios in which the user seeks into a gap. We will not find a valid request then and need to adjust the seektime. * @param {number} time * @param {object} mediaInfo * @param {object} representation * @param {number} targetThreshold */ function getValidTimeCloseToTargetTime(time, mediaInfo, representation, targetThreshold) { try { if (isNaN(time) || !mediaInfo || !representation) { return NaN; } if (time &lt; 0) { time = 0; } if (isNaN(targetThreshold)) { targetThreshold = DEFAULT_ADJUST_SEEK_TIME_THRESHOLD; } if (getSegmentRequestForTime(mediaInfo, representation, time)) { return time; } const start = representation.adaptation.period.start; const end = representation.adaptation.period.start + representation.adaptation.period.duration; let currentUpperTime = Math.min(time + targetThreshold, end); let currentLowerTime = Math.max(time - targetThreshold, start); let adjustedTime = NaN; let targetRequest = null; while (currentUpperTime &lt;= end || currentLowerTime &gt;= start) { let upperRequest = null; let lowerRequest = null; if (currentUpperTime &lt;= end) { upperRequest = getSegmentRequestForTime(mediaInfo, representation, currentUpperTime); } if (currentLowerTime &gt;= start) { lowerRequest = getSegmentRequestForTime(mediaInfo, representation, currentLowerTime); } if (lowerRequest) { adjustedTime = currentLowerTime; targetRequest = lowerRequest; break; } else if (upperRequest) { adjustedTime = currentUpperTime; targetRequest = upperRequest; break; } currentUpperTime += targetThreshold; currentLowerTime -= targetThreshold; } if (targetRequest) { const requestEndTime = targetRequest.startTime + targetRequest.duration; // Keep the original start time in case it is covered by a segment if (time &gt;= targetRequest.startTime &amp;&amp; requestEndTime - time &gt; targetThreshold) { return time; } // If target time is before the start of the request use request starttime if (time &lt; targetRequest.startTime) { return targetRequest.startTime; } return Math.min(requestEndTime - targetThreshold, adjustedTime); } return adjustedTime; } catch (e) { return NaN; } } /** * This function returns a time larger than the current time for which we can generate a request. * This is useful in scenarios in which the user seeks into a gap in a dynamic Timeline manifest. We will not find a valid request then and need to adjust the seektime. * @param {number} time * @param {object} mediaInfo * @param {object} representation * @param {number} targetThreshold */ function getValidTimeAheadOfTargetTime(time, mediaInfo, representation, targetThreshold) { try { if (isNaN(time) || !mediaInfo || !representation) { return NaN; } if (time &lt; 0) { time = 0; } if (isNaN(targetThreshold)) { targetThreshold = DEFAULT_ADJUST_SEEK_TIME_THRESHOLD; } if (getSegmentRequestForTime(mediaInfo, representation, time)) { return time; } if (representation.adaptation.period.start + representation.adaptation.period.duration &lt; time) { return NaN; } // Only look 30 seconds ahead const end = Math.min(representation.adaptation.period.start + representation.adaptation.period.duration, time + 30); let currentUpperTime = Math.min(time + targetThreshold, end); let adjustedTime = NaN; let targetRequest = null; while (currentUpperTime &lt;= end) { let upperRequest = null; if (currentUpperTime &lt;= end) { upperRequest = getSegmentRequestForTime(mediaInfo, representation, currentUpperTime); } if (upperRequest) { adjustedTime = currentUpperTime; targetRequest = upperRequest; break; } currentUpperTime += targetThreshold; } if (targetRequest) { const requestEndTime = targetRequest.startTime + targetRequest.duration; // Keep the original start time in case it is covered by a segment if (time &gt; targetRequest.startTime &amp;&amp; requestEndTime - time &gt; targetThreshold) { return time; } if (!isNaN(targetRequest.startTime) &amp;&amp; time &lt; targetRequest.startTime &amp;&amp; adjustedTime &gt; targetRequest.startTime) { return targetRequest.startTime; } return Math.min(requestEndTime - targetThreshold, adjustedTime); } return adjustedTime; } catch (e) { return NaN; } } function getCurrentIndex() { return lastSegment ? lastSegment.index : -1; } function _onDynamicToStatic() { logger.debug('Dynamic stream complete'); mediaHasFinished = true; } instance = { initialize, getStreamId, getType, getStreamInfo, getInitRequest, getSegmentRequestForTime, getCurrentIndex, getNextSegmentRequest, isLastSegmentRequested, reset, getNextSegmentRequestIdempotent, getValidTimeCloseToTargetTime, getValidTimeAheadOfTargetTime }; setup(); return instance; } DashHandler.__dashjs_factory_name = 'DashHandler'; export default FactoryMaker.getClassFactory(DashHandler); × Search results Close "},"streaming_vo_metrics_DroppedFrames.js.html":{"id":"streaming_vo_metrics_DroppedFrames.js.html","title":"Source: streaming/vo/metrics/DroppedFrames.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/DroppedFrames.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ class DroppedFrames { /** * @description This Object holds reference to DroppedFrames count and the time it was recorded. */ constructor() { /** * Real-Time | Time of the measurement of the dropped frames. * @public */ this.time = null; /** * Number of dropped frames * @public */ this.droppedFrames = null; } } export default DroppedFrames; × Search results Close "},"streaming_vo_metrics_DVRInfo.js.html":{"id":"streaming_vo_metrics_DVRInfo.js.html","title":"Source: streaming/vo/metrics/DVRInfo.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/DVRInfo.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ class DVRInfo { /** * @description This Object holds reference to DVR availability window information. */ constructor() { /** * The current time of the video element when this was created. * @public */ this.time = null; /** * The current Segment Availability Range as an object with start and end properties. * It's delta defined by the timeShiftBufferDepth MPD attribute. * @public */ this.range = null; /** * Reference to the internal ManifestInfo.js VO. * @public */ this.manifestInfo = null; } } export default DVRInfo; × Search results Close "},"streaming_utils_EBMLParser.js.html":{"id":"streaming_utils_EBMLParser.js.html","title":"Source: streaming/utils/EBMLParser.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/EBMLParser.js import FactoryMaker from '../../core/FactoryMaker'; /** * Creates an instance of an EBMLParser class which implements a large subset * of the functionality required to parse Matroska EBML * * @param {Object} config object with data member which is the buffer to parse * @ignore */ function EBMLParser(config) { config = config || {}; let instance; let data = new DataView(config.data); let pos = 0; function getPos() { return pos; } function setPos(value) { pos = value; } /** * Consumes an EBML tag from the data stream. * * @param {Object} tag to parse, A tag is an object with at least a {number} tag and * {boolean} required flag. * @param {boolean} test whether or not the function should throw if a required * tag is not found * @return {boolean} whether or not the tag was found * @throws will throw an exception if a required tag is not found and test * param is false or undefined, or if the stream is malformed. * @memberof EBMLParser */ function consumeTag(tag, test) { let found = true; let bytesConsumed = 0; let p1, p2; if (test === undefined) { test = false; } if (tag.tag &gt; 0xFFFFFF) { if (data.getUint32(pos) !== tag.tag) { found = false; } bytesConsumed = 4; } else if (tag.tag &gt; 0xFFFF) { // 3 bytes p1 = data.getUint16(pos); p2 = data.getUint8(pos + 2); // shift p1 over a byte and add p2 if (p1 * 256 + p2 !== tag.tag) { found = false; } bytesConsumed = 3; } else if (tag.tag &gt; 0xFF) { if (data.getUint16(pos) !== tag.tag) { found = false; } bytesConsumed = 2; } else { if (data.getUint8(pos) !== tag.tag) { found = false; } bytesConsumed = 1; } if (!found &amp;&amp; tag.required &amp;&amp; !test) { throw new Error('required tag not found'); } if (found) { pos += bytesConsumed; } return found; } /** * Consumes an EBML tag from the data stream. If the tag is found then this * function will also remove the size field which follows the tag from the * data stream. * * @param {Object} tag to parse, A tag is an object with at least a {number} tag and * {boolean} required flag. * @param {boolean} test whether or not the function should throw if a required * tag is not found * @return {boolean} whether or not the tag was found * @throws will throw an exception if a required tag is not found and test * param is false or undefined, or if the stream is malformedata. * @memberof EBMLParser */ function consumeTagAndSize(tag, test) { let found = consumeTag(tag, test); if (found) { getMatroskaCodedNum(); } return found; } /** * Consumes an EBML tag from the data stream. If the tag is found then this * function will also remove the size field which follows the tag from the * data stream. It will use the value of the size field to parse a binary * field, using a parser defined in the tag itself * * @param {Object} tag to parse, A tag is an object with at least a {number} tag, * {boolean} required flag, and a parse function which takes a size parameter * @return {boolean} whether or not the tag was found * @throws will throw an exception if a required tag is not found, * or if the stream is malformed * @memberof EBMLParser */ function parseTag(tag) { let size; consumeTag(tag); size = getMatroskaCodedNum(); return instance[tag.parse](size); } /** * Consumes an EBML tag from the data stream. If the tag is found then this * function will also remove the size field which follows the tag from the * data stream. It will use the value of the size field to skip over the * entire section of EBML encapsulated by the tag. * * @param {Object} tag to parse, A tag is an object with at least a {number} tag, and * {boolean} required flag * @param {boolean} test a flag to indicate if an exception should be thrown * if a required tag is not found * @return {boolean} whether or not the tag was found * @throws will throw an exception if a required tag is not found and test is * false or undefined or if the stream is malformed * @memberof EBMLParser */ function skipOverElement(tag, test) { let found = consumeTag(tag, test); let headerSize; if (found) { headerSize = getMatroskaCodedNum(); pos += headerSize; } return found; } /** * Returns and consumes a number encoded according to the Matroska EBML * specification from the bitstream. * * @param {boolean} retainMSB whether or not to retain the Most Significant Bit (the * first 1). this is usually true when reading Tag IDs. * @return {number} the decoded number * @throws will throw an exception if the bit stream is malformed or there is * not enough data * @memberof EBMLParser */ function getMatroskaCodedNum(retainMSB) { let bytesUsed = 1; let mask = 0x80; let maxBytes = 8; let extraBytes = -1; let num = 0; let ch = data.getUint8(pos); let i = 0; for (i = 0; i &lt; maxBytes; i += 1) { if ((ch &amp; mask) === mask) { num = (retainMSB === undefined) ? ch &amp; ~mask : ch; extraBytes = i; break; } mask &gt;&gt;= 1; } for (i = 0; i &lt; extraBytes; i += 1, bytesUsed += 1) { num = (num &lt;&lt; 8) | (0xff &amp; data.getUint8(pos + bytesUsed)); } pos += bytesUsed; return num; } /** * Returns and consumes a float from the bitstream. * * @param {number} size 4 or 8 byte floats are supported * @return {number} the decoded number * @throws will throw an exception if the bit stream is malformed or there is * not enough data * @memberof EBMLParser */ function getMatroskaFloat(size) { let outFloat; switch (size) { case 4: outFloat = data.getFloat32(pos); pos += 4; break; case 8: outFloat = data.getFloat64(pos); pos += 8; break; } return outFloat; } /** * Consumes and returns an unsigned int from the bitstream. * * @param {number} size 1 to 8 bytes * @return {number} the decoded number * @throws will throw an exception if the bit stream is malformed or there is * not enough data * @memberof EBMLParser */ function getMatroskaUint(size) { let val = 0; for (let i = 0; i &lt; size; i += 1) { val &lt;&lt;= 8; val |= data.getUint8(pos + i) &amp; 0xff; } pos += size; return val; } /** * Tests whether there is more data in the bitstream for parsing * * @return {boolean} whether there is more data to parse * @memberof EBMLParser */ function moreData() { return pos &lt; data.byteLength; } instance = { getPos: getPos, setPos: setPos, consumeTag: consumeTag, consumeTagAndSize: consumeTagAndSize, parseTag: parseTag, skipOverElement: skipOverElement, getMatroskaCodedNum: getMatroskaCodedNum, getMatroskaFloat: getMatroskaFloat, getMatroskaUint: getMatroskaUint, moreData: moreData }; return instance; } EBMLParser.__dashjs_factory_name = 'EBMLParser'; export default FactoryMaker.getClassFactory(EBMLParser); × Search results Close "},"core_errors_Errors.js.html":{"id":"core_errors_Errors.js.html","title":"Source: core/errors/Errors.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: core/errors/Errors.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import ErrorsBase from './ErrorsBase'; /** * Errors declaration * @class */ class Errors extends ErrorsBase { constructor () { super(); /** * Error code returned when a manifest parsing error occurs */ this.MANIFEST_LOADER_PARSING_FAILURE_ERROR_CODE = 10; /** * Error code returned when a manifest loading error occurs */ this.MANIFEST_LOADER_LOADING_FAILURE_ERROR_CODE = 11; /** * Error code returned when a xlink loading error occurs */ this.XLINK_LOADER_LOADING_FAILURE_ERROR_CODE = 12; /** * Error code returned when no segment ranges could be determined from the sidx box */ this.SEGMENT_BASE_LOADER_ERROR_CODE = 15; /** * Error code returned when the time synchronization failed */ this.TIME_SYNC_FAILED_ERROR_CODE = 16; /** * Error code returned when loading a fragment failed */ this.FRAGMENT_LOADER_LOADING_FAILURE_ERROR_CODE = 17; /** * Error code returned when the FragmentLoader did not receive a request object */ this.FRAGMENT_LOADER_NULL_REQUEST_ERROR_CODE = 18; /** * Error code returned when the BaseUrl resolution failed */ this.URL_RESOLUTION_FAILED_GENERIC_ERROR_CODE = 19; /** * Error code returned when the append operation in the SourceBuffer failed */ this.APPEND_ERROR_CODE = 20; /** * Error code returned when the remove operation in the SourceBuffer failed */ this.REMOVE_ERROR_CODE = 21; /** * Error code returned when updating the internal objects after loading an MPD failed */ this.DATA_UPDATE_FAILED_ERROR_CODE = 22; /** * Error code returned when MediaSource is not supported by the browser */ this.CAPABILITY_MEDIASOURCE_ERROR_CODE = 23; /** * Error code returned when Protected contents are not supported */ this.CAPABILITY_MEDIAKEYS_ERROR_CODE = 24; /** * Error code returned when loading the manifest failed */ this.DOWNLOAD_ERROR_ID_MANIFEST_CODE = 25; /** * Error code returned when loading the sidx failed */ this.DOWNLOAD_ERROR_ID_SIDX_CODE = 26; /** * Error code returned when loading the media content failed */ this.DOWNLOAD_ERROR_ID_CONTENT_CODE = 27; /** * Error code returned when loading the init segment failed */ this.DOWNLOAD_ERROR_ID_INITIALIZATION_CODE = 28; /** * Error code returned when loading the XLink content failed */ this.DOWNLOAD_ERROR_ID_XLINK_CODE = 29; /** * Error code returned when parsing the MPD resulted in a logical error */ this.MANIFEST_ERROR_ID_PARSE_CODE = 31; /** * Error code returned when no stream (period) has been detected in the manifest */ this.MANIFEST_ERROR_ID_NOSTREAMS_CODE = 32; /** * Error code returned when something wrong has happened during parsing and appending subtitles (TTML or VTT) */ this.TIMED_TEXT_ERROR_ID_PARSE_CODE = 33; /** * Error code returned when a 'muxed' media type has been detected in the manifest. This type is not supported */ this.MANIFEST_ERROR_ID_MULTIPLEXED_CODE = 34; /** * Error code returned when a media source type is not supported */ this.MEDIASOURCE_TYPE_UNSUPPORTED_CODE = 35; this.MANIFEST_LOADER_PARSING_FAILURE_ERROR_MESSAGE = 'parsing failed for '; this.MANIFEST_LOADER_LOADING_FAILURE_ERROR_MESSAGE = 'Failed loading manifest: '; this.XLINK_LOADER_LOADING_FAILURE_ERROR_MESSAGE = 'Failed loading Xlink element: '; this.SEGMENTS_UPDATE_FAILED_ERROR_MESSAGE = 'Segments update failed'; this.SEGMENTS_UNAVAILABLE_ERROR_MESSAGE = 'no segments are available yet'; this.SEGMENT_BASE_LOADER_ERROR_MESSAGE = 'error loading segment ranges from sidx'; this.TIME_SYNC_FAILED_ERROR_MESSAGE = 'Failed to synchronize client and server time'; this.FRAGMENT_LOADER_NULL_REQUEST_ERROR_MESSAGE = 'request is null'; this.URL_RESOLUTION_FAILED_GENERIC_ERROR_MESSAGE = 'Failed to resolve a valid URL'; this.APPEND_ERROR_MESSAGE = 'chunk is not defined'; this.REMOVE_ERROR_MESSAGE = 'Removing data from the SourceBuffer'; this.DATA_UPDATE_FAILED_ERROR_MESSAGE = 'Data update failed'; this.CAPABILITY_MEDIASOURCE_ERROR_MESSAGE = 'mediasource is not supported'; this.CAPABILITY_MEDIAKEYS_ERROR_MESSAGE = 'mediakeys is not supported'; this.TIMED_TEXT_ERROR_MESSAGE_PARSE = 'parsing error :'; this.MEDIASOURCE_TYPE_UNSUPPORTED_MESSAGE = 'Error creating source buffer of type : '; } } let errors = new Errors(); export default errors; × Search results Close "},"streaming_controllers_EventController.js.html":{"id":"streaming_controllers_EventController.js.html","title":"Source: streaming/controllers/EventController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/EventController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import EventBus from '../../core/EventBus'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents'; import XHRLoader from '../net/XHRLoader'; function EventController() { const MPD_RELOAD_SCHEME = 'urn:mpeg:dash:event:2012'; const MPD_RELOAD_VALUE = 1; const MPD_CALLBACK_SCHEME = 'urn:mpeg:dash:event:callback:2015'; const MPD_CALLBACK_VALUE = 1; const REMAINING_EVENTS_THRESHOLD = 300; const EVENT_HANDLED_STATES = { DISCARDED: 'discarded', UPDATED: 'updated', ADDED: 'added' }; const context = this.context; const eventBus = EventBus(context).getInstance(); let instance, logger, inlineEvents, // Holds all Inline Events not triggered yet inbandEvents, // Holds all Inband Events not triggered yet eventInterval, // variable holding the setInterval lastEventTimerCall, manifestUpdater, playbackController, settings, eventHandlingInProgress, isStarted; /** * Internal setup when class is instanced */ function _setup() { logger = Debug(context).getInstance().getLogger(instance); _resetInitialSettings(); } /** * Checks if the provded configuration is valid */ function checkConfig() { if (!manifestUpdater || !playbackController) { throw new Error('setConfig function has to be called previously'); } } /** * Reset to initial settings */ function _resetInitialSettings() { isStarted = false; inlineEvents = {}; // Format inlineEvents[periodID][schemeIdUri] inbandEvents = {}; // Format inbandEvents[periodID][schemeIdUri] eventInterval = null; eventHandlingInProgress = false; lastEventTimerCall = Date.now() / 1000; } /** * Stops the EventController by clearing the event interval */ function _stop() { try { if (eventInterval !== null &amp;&amp; isStarted) { clearInterval(eventInterval); eventInterval = null; isStarted = false; _onStopEventController(); } } catch (e) { throw e; } } /** * Starts the interval function of the EventController */ function start() { try { checkConfig(); logger.debug('Start Event Controller'); const refreshDelay = settings.get().streaming.eventControllerRefreshDelay; if (!isStarted &amp;&amp; !isNaN(refreshDelay)) { isStarted = true; eventInterval = setInterval(_onEventTimer, refreshDelay); } } catch (e) { throw e; } } /** * Iterate through the eventList and trigger the events */ function _onEventTimer() { try { if (!eventHandlingInProgress) { eventHandlingInProgress = true; const currentVideoTime = playbackController.getTime(); let presentationTimeThreshold = (currentVideoTime - lastEventTimerCall); // For dynamic streams lastEventTimeCall will be large in the first iteration. Avoid firing all events at once. presentationTimeThreshold = lastEventTimerCall &gt; 0 ? Math.max(0, presentationTimeThreshold) : 0; _triggerEvents(inbandEvents, presentationTimeThreshold, currentVideoTime); _triggerEvents(inlineEvents, presentationTimeThreshold, currentVideoTime); _removeOutdatedEventObjects(inbandEvents); _removeOutdatedEventObjects(inlineEvents); lastEventTimerCall = currentVideoTime; eventHandlingInProgress = false; } } catch (e) { eventHandlingInProgress = false; logger.error(e); } } /** * Iterate over a list of events and trigger the ones for which the presentation time is within the current timing interval * @param {object} events * @param {number} presentationTimeThreshold * @param {number} currentVideoTime * @private */ function _triggerEvents(events, presentationTimeThreshold, currentVideoTime) { try { const callback = function (event) { if (event !== undefined) { const duration = !isNaN(event.duration) ? event.duration : 0; // The event is either about to start or has already been started and we are within its duration if ((event.calculatedPresentationTime &lt;= currentVideoTime &amp;&amp; event.calculatedPresentationTime + presentationTimeThreshold + duration &gt;= currentVideoTime)) { _startEvent(event, MediaPlayerEvents.EVENT_MODE_ON_START); } else if (_eventHasExpired(currentVideoTime, duration + presentationTimeThreshold, event.calculatedPresentationTime) || _eventIsInvalid(event)) { logger.debug(`Removing event ${event.id} from period ${event.eventStream.period.id} as it is expired or invalid`); _removeEvent(events, event); } } }; _iterateAndTriggerCallback(events, callback); } catch (e) { logger.error(e); } } /** * Iterates over the entries of the events object and deletes the entries for which no events are present * @param {object} events * @private */ function _removeOutdatedEventObjects(events) { try { for (const key in events) { if (events.hasOwnProperty(key)) { if (Object.keys(events[key]).length === 0) delete events[key]; } } } catch (e) { logger.error(e); } } /** * Add MPD events to the list of events. * Events that are not in the MPD anymore but not triggered yet will still be deleted. * Existing events might get updated. * @param {Array.&lt;Object&gt;} values * @param {string} periodId */ function addInlineEvents(values, periodId) { try { checkConfig(); if (!inlineEvents[periodId]) { inlineEvents[periodId] = {}; } if (values) { for (let i = 0; i &lt; values.length; i++) { let event = values[i]; const currentTime = playbackController.getTime(); const duration = !isNaN(event.duration) ? event.duration : 0; if (!_eventHasExpired(currentTime, duration, event.calculatedPresentationTime)) { let result = _addOrUpdateEvent(event, inlineEvents[periodId], true); if (result === EVENT_HANDLED_STATES.ADDED) { logger.debug(`Added inline event with id ${event.id} from period ${periodId}`); // If we see the event for the first time we trigger it in onReceive mode _startEvent(event, MediaPlayerEvents.EVENT_MODE_ON_RECEIVE); } else if (result === EVENT_HANDLED_STATES.UPDATED) { logger.debug(`Updated inline event with id ${event.id} from period ${periodId}`); } } } } } catch (e) { throw e; } } /** * Add EMSG events to the list of events * Messages with the same id within the scope of the same scheme_id_uri and value pair are equivalent , i.e. processing of any one event message box with the same id is sufficient. * @param {Array.&lt;Object&gt;} values * @param {string} periodId */ function addInbandEvents(values, periodId) { try { checkConfig(); if (!inbandEvents[periodId]) { inbandEvents[periodId] = {}; } for (let i = 0; i &lt; values.length; i++) { let event = values[i]; const currentTime = playbackController.getTime(); const duration = !isNaN(event.duration) ? event.duration : 0; if (!_eventHasExpired(currentTime, duration, event.calculatedPresentationTime)) { let result = _addOrUpdateEvent(event, inbandEvents[periodId], false); if (result === EVENT_HANDLED_STATES.ADDED) { if (event.eventStream.schemeIdUri === MPD_RELOAD_SCHEME) { _handleManifestReloadEvent(event); } logger.debug(`Added inband event with id ${event.id} from period ${periodId}`); _startEvent(event, MediaPlayerEvents.EVENT_MODE_ON_RECEIVE); } else { logger.debug(`Inband event with scheme_id_uri ${event.eventStream.schemeIdUri}, value ${event.eventStream.value}, period id ${periodId} and event id ${event.id} was ignored because it has been added before.`); } } } _onEventTimer(); } catch (e) { throw e; } } /** * Adds or updates an event to/in the list of events * @param {object} event * @param {object} events * @param {boolean} shouldOverwriteExistingEvents * @return {string} * @private */ function _addOrUpdateEvent(event, events, shouldOverwriteExistingEvents = false) { const schemeIdUri = event.eventStream.schemeIdUri; const value = event.eventStream.value; const id = event.id; let eventState = EVENT_HANDLED_STATES.DISCARDED; if (!events[schemeIdUri]) { events[schemeIdUri] = []; } const indexOfExistingEvent = events[schemeIdUri].findIndex((e) =&gt; { return ((!value || (e.eventStream.value &amp;&amp; e.eventStream.value === value)) &amp;&amp; (e.id === id)); }); // New event, we add it to our list of events if (indexOfExistingEvent === -1) { events[schemeIdUri].push(event); event.triggeredReceivedEvent = false; event.triggeredStartEvent = false; eventState = EVENT_HANDLED_STATES.ADDED; } // We have a similar event for this period with the same schemeIdUri, value and id. Overwrite it or ignore it else if (shouldOverwriteExistingEvents) { const oldEvent = events[schemeIdUri][indexOfExistingEvent]; event.triggeredReceivedEvent = oldEvent.triggeredReceivedEvent; event.triggeredStartEvent = oldEvent.triggeredStartEvent; events[schemeIdUri][indexOfExistingEvent] = event; eventState = EVENT_HANDLED_STATES.UPDATED; } return eventState; } /** * Triggers an MPD reload * @param {object} event * @private */ function _handleManifestReloadEvent(event) { try { if (event.eventStream.value == MPD_RELOAD_VALUE) { const validUntil = event.calculatedPresentationTime; let newDuration; if (event.calculatedPresentationTime == 0xFFFFFFFF) {//0xFF... means remaining duration unknown newDuration = NaN; } else { newDuration = event.calculatedPresentationTime + event.duration; } //logger.info('Manifest validity changed: Valid until: ' + validUntil + '; remaining duration: ' + newDuration); eventBus.trigger(MediaPlayerEvents.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: MediaPlayerEvents.EVENT_MODE_ON_START }); } } catch (e) { logger.error(e); } } /** * When the EventController is stopped this callback is triggered. Starts the remaining events. * @private */ function _onStopEventController() { try { // EventController might be stopped before the period is over. Before we stop the event controller we check for events that needs to be triggered at the period boundary. _triggerRemainingEvents(inbandEvents); _triggerRemainingEvents(inlineEvents); } catch (e) { logger.error(e); } } /** * Triggers the remaining events after the EventController has been stopped * @param {object} events * @private */ function _triggerRemainingEvents(events) { try { const currentTime = playbackController.getTime(); const callback = function (event) { const periodDuration = event.eventStream &amp;&amp; event.eventStream.period &amp;&amp; !isNaN(event.eventStream.period.duration) ? event.eventStream.period.duration : NaN; const periodStart = event.eventStream &amp;&amp; event.eventStream.period &amp;&amp; !isNaN(event.eventStream.period.start) ? event.eventStream.period.start : NaN; if (isNaN(periodDuration) || isNaN(periodStart)) { return; } const calculatedPresentationTimeInSeconds = event.calculatedPresentationTime; if (Math.abs(calculatedPresentationTimeInSeconds - currentTime) &lt; REMAINING_EVENTS_THRESHOLD) { _startEvent(event, MediaPlayerEvents.EVENT_MODE_ON_START); } }; _iterateAndTriggerCallback(events, callback); } catch (e) { logger.error(e); } } /** * Iterates over the inline/inband event object and triggers a callback for each event * @param {object} events * @param {function} callback * @private */ function _iterateAndTriggerCallback(events, callback) { try { if (events) { const periodIds = Object.keys(events); for (let i = 0; i &lt; periodIds.length; i++) { const currentPeriod = events[periodIds[i]]; const schemeIdUris = Object.keys(currentPeriod); for (let j = 0; j &lt; schemeIdUris.length; j++) { const schemeIdEvents = currentPeriod[schemeIdUris[j]]; schemeIdEvents.forEach((event) =&gt; { if (event !== undefined) { callback(event); } }); } } } } catch (e) { logger.error(e); } } /** * Checks if an event is expired. For instance if the presentationTime + the duration of an event are smaller than the current video time. * @param {number} currentVideoTime * @param {number} threshold * @param {number} calculatedPresentationTimeInSeconds * @return {boolean} * @private */ function _eventHasExpired(currentVideoTime, threshold, calculatedPresentationTimeInSeconds) { try { return currentVideoTime - threshold &gt; calculatedPresentationTimeInSeconds; } catch (e) { logger.error(e); return false; } } /** * Checks if an event is invalid. This is the case if the end time of the parent period is smaller than the presentation time of the event. * @param {object} event * @return {boolean} * @private */ function _eventIsInvalid(event) { try { const periodEndTime = event.eventStream.period.start + event.eventStream.period.duration; return event.calculatedPresentationTime &gt; periodEndTime; } catch (e) { logger.error(e); return false; } } /** * Starts an event. Depending on the schemeIdUri we distinguish between * - MPD Reload events * - MPD Callback events * - Events to be dispatched to the application * @param {object} event * @param {String} mode * @private */ function _startEvent(event, mode) { try { const currentVideoTime = playbackController.getTime(); const eventId = event.id; if (mode === MediaPlayerEvents.EVENT_MODE_ON_RECEIVE &amp;&amp; !event.triggeredReceivedEvent) { logger.debug(`Received event ${eventId}`); event.triggeredReceivedEvent = true; eventBus.trigger(event.eventStream.schemeIdUri, { event: event }, { mode }); return; } if (!event.triggeredStartEvent) { if (event.eventStream.schemeIdUri === MPD_RELOAD_SCHEME &amp;&amp; event.eventStream.value == MPD_RELOAD_VALUE) { //If both are set to zero, it indicates the media is over at this point. Don't reload the manifest. if (event.duration !== 0 || event.presentationTimeDelta !== 0) { logger.debug(`Starting manifest refresh event ${eventId} at ${currentVideoTime}`); _refreshManifest(); } } else if (event.eventStream.schemeIdUri === MPD_CALLBACK_SCHEME &amp;&amp; event.eventStream.value == MPD_CALLBACK_VALUE) { logger.debug(`Starting callback event ${eventId} at ${currentVideoTime}`); _sendCallbackRequest(event.messageData); } else { logger.debug(`Starting event ${eventId} from period ${event.eventStream.period.id} at ${currentVideoTime}`); eventBus.trigger(event.eventStream.schemeIdUri, { event: event }, { mode }); } event.triggeredStartEvent = true; } } catch (e) { logger.error(e); } } /** * Removes an event from the list. If this is the last event of type \"schemeIdUri\" the corresponding schemeIdUri Object in the list of events is deleted. * @param {object} events * @param {object} event * @private */ function _removeEvent(events, event) { try { const schemeIdUri = event.eventStream.schemeIdUri; const periodId = event.eventStream.period.id; const value = event.eventStream.value; const id = event.id; events[periodId][schemeIdUri] = events[periodId][schemeIdUri].filter((e) =&gt; { return (value &amp;&amp; e.eventStream.value &amp;&amp; e.eventStream.value !== value) || e.id !== id; }); if (events[periodId][schemeIdUri].length === 0) { delete events[periodId][schemeIdUri]; } } catch (e) { logger.error(e); } } /** * Refresh the manifest * @private */ function _refreshManifest() { try { checkConfig(); manifestUpdater.refreshManifest(); } catch (e) { logger.error(e); } } /** * Send a callback request * @param {String} url * @private */ function _sendCallbackRequest(url) { try { let loader = XHRLoader(context).create({}); loader.load({ method: 'get', url: url, request: { responseType: 'arraybuffer' } }); } catch (e) { logger.error(e); } } /** * Set the config of the EventController * @param {object} config */ function setConfig(config) { try { if (!config) { return; } if (config.manifestUpdater) { manifestUpdater = config.manifestUpdater; } if (config.playbackController) { playbackController = config.playbackController; } if (config.settings) { settings = config.settings; } } catch (e) { throw e; } } /** * Returns all inline events that have not been triggered yet * @return {object} */ function getInlineEvents() { return inlineEvents; } /** * Returns all inband events that have not been triggered yet * @return {object} */ function getInbandEvents() { return inbandEvents; } /** * Stop the EventController and reset all initial settings */ function reset() { _stop(); _resetInitialSettings(); } instance = { addInlineEvents, addInbandEvents, getInbandEvents, getInlineEvents, start, setConfig, reset }; _setup(); return instance; } EventController.__dashjs_factory_name = 'EventController'; export default FactoryMaker.getSingletonFactory(EventController); × Search results Close "},"streaming_models_FragmentModel.js.html":{"id":"streaming_models_FragmentModel.js.html","title":"Source: streaming/models/FragmentModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/models/FragmentModel.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import FragmentRequest from '../vo/FragmentRequest'; const FRAGMENT_MODEL_LOADING = 'loading'; const FRAGMENT_MODEL_EXECUTED = 'executed'; const FRAGMENT_MODEL_CANCELED = 'canceled'; const FRAGMENT_MODEL_FAILED = 'failed'; function FragmentModel(config) { config = config || {}; const eventBus = config.eventBus; const events = config.events; const dashMetrics = config.dashMetrics; const fragmentLoader = config.fragmentLoader; const debug = config.debug; const streamInfo = config.streamInfo; const type = config.type; let instance, logger, executedRequests, loadingRequests; function setup() { logger = debug.getLogger(instance); resetInitialSettings(); eventBus.on(events.LOADING_COMPLETED, onLoadingCompleted, instance); eventBus.on(events.LOADING_DATA_PROGRESS, onLoadingInProgress, instance); eventBus.on(events.LOADING_ABANDONED, onLoadingAborted, instance); } function getStreamId() { return streamInfo.id; } function getType() { return type; } function isFragmentLoaded(request) { const isEqualComplete = function (req1, req2) { return ((req1.action === FragmentRequest.ACTION_COMPLETE) &amp;&amp; (req1.action === req2.action)); }; const isEqualMedia = function (req1, req2) { return !isNaN(req1.index) &amp;&amp; (req1.startTime === req2.startTime) &amp;&amp; (req1.adaptationIndex === req2.adaptationIndex) &amp;&amp; (req1.type === req2.type); }; const isEqualInit = function (req1, req2) { return isNaN(req1.index) &amp;&amp; isNaN(req2.index) &amp;&amp; (req1.quality === req2.quality); }; const check = function (requests) { let isLoaded = false; requests.some(req =&gt; { if (isEqualMedia(request, req) || isEqualInit(request, req) || isEqualComplete(request, req)) { isLoaded = true; return isLoaded; } }); return isLoaded; }; if (!request) { return false; } return check(executedRequests); } function isFragmentLoadedOrPending(request) { let isLoaded = false; let i = 0; let req; // First, check if the fragment has already been loaded isLoaded = isFragmentLoaded(request); // Then, check if the fragment is about to be loeaded if (!isLoaded) { for (i = 0; i &lt; loadingRequests.length; i++) { req = loadingRequests[i]; if ((request.url === req.url) &amp;&amp; (request.startTime === req.startTime)) { isLoaded = true; } } } return isLoaded; } /** * * Gets an array of {@link FragmentRequest} objects * * @param {Object} filter The object with properties by which the method filters the requests to be returned. * the only mandatory property is state, which must be a value from * other properties should match the properties of {@link FragmentRequest}. E.g.: * getRequests({state: FragmentModel.FRAGMENT_MODEL_EXECUTED, quality: 0}) - returns * all the requests from executedRequests array where requests.quality = filter.quality * * @returns {Array} * @memberof FragmentModel# */ function getRequests(filter) { const states = filter ? filter.state instanceof Array ? filter.state : [filter.state] : []; let filteredRequests = []; states.forEach(state =&gt; { const requests = getRequestsForState(state); filteredRequests = filteredRequests.concat(filterRequests(requests, filter)); }); return filteredRequests; } function getRequestThreshold(req) { return isNaN(req.duration) ? 0.25 : Math.min(req.duration / 8, 0.5); } function removeExecutedRequestsBeforeTime(time) { executedRequests = executedRequests.filter(req =&gt; { const threshold = getRequestThreshold(req); return isNaN(req.startTime) || (time !== undefined ? req.startTime &gt;= time - threshold : false); }); } function removeExecutedRequestsAfterTime(time) { executedRequests = executedRequests.filter(req =&gt; { return isNaN(req.startTime) || (time !== undefined ? req.startTime &lt; time : false); }); } function removeExecutedRequestsInTimeRange(start, end) { if (end &lt;= start + 0.5) { return; } executedRequests = executedRequests.filter(req =&gt; { const threshold = getRequestThreshold(req); return (isNaN(req.startTime) || req.startTime &gt;= (end - threshold)) || (isNaN(req.duration) || (req.startTime + req.duration) &lt;= (start + threshold)); }); } // Remove requests that are not \"represented\" by any of buffered ranges function syncExecutedRequestsWithBufferedRange(bufferedRanges, streamDuration) { if (!bufferedRanges || bufferedRanges.length === 0) { removeExecutedRequestsBeforeTime(); return; } let start = 0; for (let i = 0, ln = bufferedRanges.length; i &lt; ln; i++) { removeExecutedRequestsInTimeRange(start, bufferedRanges.start(i)); start = bufferedRanges.end(i); } if (streamDuration &gt; 0) { removeExecutedRequestsInTimeRange(start, streamDuration); } } function abortRequests() { logger.debug('abort requests'); fragmentLoader.abort(); loadingRequests = []; } function executeRequest(request) { switch (request.action) { case FragmentRequest.ACTION_DOWNLOAD: addSchedulingInfoMetrics(request, FRAGMENT_MODEL_LOADING); loadingRequests.push(request); loadCurrentFragment(request); break; default: logger.warn('Unknown request action.'); } } function loadCurrentFragment(request) { eventBus.trigger(events.FRAGMENT_LOADING_STARTED, { request: request }, { streamId: streamInfo.id, mediaType: type } ); fragmentLoader.load(request); } function getRequestForTime(arr, time, threshold) { // loop through the executed requests and pick the one for which the playback interval matches the given time const lastIdx = arr.length - 1; for (let i = lastIdx; i &gt;= 0; i--) { const req = arr[i]; const start = req.startTime; const end = start + req.duration; threshold = !isNaN(threshold) ? threshold : getRequestThreshold(req); if ((!isNaN(start) &amp;&amp; !isNaN(end) &amp;&amp; ((time + threshold) &gt;= start) &amp;&amp; ((time - threshold) &lt; end)) || (isNaN(start) &amp;&amp; isNaN(time))) { return req; } } return null; } function filterRequests(arr, filter) { // for time use a specific filtration function if (filter.hasOwnProperty('time')) { return [getRequestForTime(arr, filter.time, filter.threshold)]; } return arr.filter(request =&gt; { for (const prop in filter) { if (prop === 'state') continue; if (filter.hasOwnProperty(prop) &amp;&amp; request[prop] != filter[prop]) return false; } return true; }); } function getRequestsForState(state) { let requests; switch (state) { case FRAGMENT_MODEL_LOADING: requests = loadingRequests; break; case FRAGMENT_MODEL_EXECUTED: requests = executedRequests; break; default: requests = []; } return requests; } function addSchedulingInfoMetrics(request, state) { dashMetrics.addSchedulingInfo(request, state); dashMetrics.addRequestsQueue(request.mediaType, loadingRequests, executedRequests); } function onLoadingCompleted(e) { if (e.sender !== fragmentLoader) return; loadingRequests.splice(loadingRequests.indexOf(e.request), 1); if (e.response &amp;&amp; !e.error) { executedRequests.push(e.request); } addSchedulingInfoMetrics(e.request, e.error ? FRAGMENT_MODEL_FAILED : FRAGMENT_MODEL_EXECUTED); eventBus.trigger(events.FRAGMENT_LOADING_COMPLETED, { request: e.request, response: e.response, error: e.error, sender: this }, { streamId: streamInfo.id, mediaType: type } ); } function onLoadingInProgress(e) { if (e.sender !== fragmentLoader) return; eventBus.trigger(events.FRAGMENT_LOADING_PROGRESS, { request: e.request, response: e.response, error: e.error, sender: this }, { streamId: streamInfo.id, mediaType: type } ); } function onLoadingAborted(e) { if (e.sender !== fragmentLoader) return; eventBus.trigger(events.FRAGMENT_LOADING_ABANDONED, { request: e.request }, { streamId: streamInfo.id, mediaType: type } ); } function resetInitialSettings() { executedRequests = []; loadingRequests = []; } function reset() { eventBus.off(events.LOADING_COMPLETED, onLoadingCompleted, this); eventBus.off(events.LOADING_DATA_PROGRESS, onLoadingInProgress, this); eventBus.off(events.LOADING_ABANDONED, onLoadingAborted, this); if (fragmentLoader) { fragmentLoader.reset(); } resetInitialSettings(); } function addExecutedRequest(request) { executedRequests.push(request); } instance = { getStreamId, getType, getRequests, isFragmentLoaded, isFragmentLoadedOrPending, removeExecutedRequestsBeforeTime, removeExecutedRequestsAfterTime, syncExecutedRequestsWithBufferedRange, abortRequests, executeRequest, reset, resetInitialSettings, addExecutedRequest }; setup(); return instance; } FragmentModel.__dashjs_factory_name = 'FragmentModel'; const factory = FactoryMaker.getClassFactory(FragmentModel); factory.FRAGMENT_MODEL_LOADING = FRAGMENT_MODEL_LOADING; factory.FRAGMENT_MODEL_EXECUTED = FRAGMENT_MODEL_EXECUTED; factory.FRAGMENT_MODEL_CANCELED = FRAGMENT_MODEL_CANCELED; factory.FRAGMENT_MODEL_FAILED = FRAGMENT_MODEL_FAILED; FactoryMaker.updateClassFactory(FragmentModel.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_FragmentSink.js.html":{"id":"streaming_FragmentSink.js.html","title":"Source: streaming/FragmentSink.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/FragmentSink.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * The end place to put fragments after they have been fetched. * @interface FragmentSink * @ignore */ /** * Append a chunk to the internal buffer. You should assume that the effects of this are asynchronous. * @function FragmentSink#append * @param {Object} chunk A loaded chunk like that generated by the FragmentController */ /** * Remove data from within the specified time ranges. * @function FragmentSink#remove * @param {?Number} start The beginning of the range that should be removed from the sink's internal buffer. If NaN, it is regarded as unbounded. * @param {?Number} end The end of the range that should be removed from the sink's internal buffer. If NaN, it is regarded as unbounded. */ /** * Abort an append operation currently ongoing. * @function FragmentSink#abort */ /** * @function FragmentSink#getAllBufferRanges * @returns {Array} A TimeRanges-like object representing all the buffer ranges that are present in the sink. */ /** * Remove all the data in the sink's internal buffer. * @function FragmentSink#reset */ × Search results Close "},"streaming_vo_metrics_HTTPRequest.js.html":{"id":"streaming_vo_metrics_HTTPRequest.js.html","title":"Source: streaming/vo/metrics/HTTPRequest.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/HTTPRequest.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @classdesc This Object holds reference to the HTTPRequest for manifest, fragment and xlink loading. * Members which are not defined in ISO23009-1 Annex D should be prefixed by a _ so that they are ignored * by Metrics Reporting code. * @ignore */ class HTTPRequest { /** * @class */ constructor() { /** * Identifier of the TCP connection on which the HTTP request was sent. * @public */ this.tcpid = null; /** * This is an optional parameter and should not be included in HTTP request/response transactions for progressive download. * The type of the request: * - MPD * - XLink expansion * - Initialization Fragment * - Index Fragment * - Media Fragment * - Bitstream Switching Fragment * - other * @public */ this.type = null; /** * The original URL (before any redirects or failures) * @public */ this.url = null; /** * The actual URL requested, if different from above * @public */ this.actualurl = null; /** * The contents of the byte-range-spec part of the HTTP Range header. * @public */ this.range = null; /** * Real-Time | The real time at which the request was sent. * @public */ this.trequest = null; /** * Real-Time | The real time at which the first byte of the response was received. * @public */ this.tresponse = null; /** * The HTTP response code. * @public */ this.responsecode = null; /** * The duration of the throughput trace intervals (ms), for successful requests only. * @public */ this.interval = null; /** * Throughput traces, for successful requests only. * @public */ this.trace = []; /** * Type of stream (\"audio\" | \"video\" etc..) * @public */ this._stream = null; /** * Real-Time | The real time at which the request finished. * @public */ this._tfinish = null; /** * The duration of the media requests, if available, in seconds. * @public */ this._mediaduration = null; /** * The media segment quality * @public */ this._quality = null; /** * all the response headers from request. * @public */ this._responseHeaders = null; /** * The selected service location for the request. string. * @public */ this._serviceLocation = null; /** * The type of the loader that was used. Distinguish between fetch loader and xhr loader */ this._fileLoaderType = null; } } /** * @classdesc This Object holds reference to the progress of the HTTPRequest. * @ignore */ class HTTPRequestTrace { /** * @class */ constructor() { /** * Real-Time | Measurement stream start. * @public */ this.s = null; /** * Measurement stream duration (ms). * @public */ this.d = null; /** * List of integers counting the bytes received in each trace interval within the measurement stream. * @public */ this.b = []; } } HTTPRequest.GET = 'GET'; HTTPRequest.HEAD = 'HEAD'; HTTPRequest.MPD_TYPE = 'MPD'; HTTPRequest.XLINK_EXPANSION_TYPE = 'XLinkExpansion'; HTTPRequest.INIT_SEGMENT_TYPE = 'InitializationSegment'; HTTPRequest.INDEX_SEGMENT_TYPE = 'IndexSegment'; HTTPRequest.MEDIA_SEGMENT_TYPE = 'MediaSegment'; HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE = 'BitstreamSwitchingSegment'; HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE = 'FragmentInfoSegment'; HTTPRequest.DVB_REPORTING_TYPE = 'DVBReporting'; HTTPRequest.LICENSE = 'license'; HTTPRequest.CONTENT_STEERING_TYPE = 'ContentSteering'; HTTPRequest.OTHER_TYPE = 'other'; export {HTTPRequest, HTTPRequestTrace}; × Search results Close "},"offline_net_IndexDBOfflineLoader.js.html":{"id":"offline_net_IndexDBOfflineLoader.js.html","title":"Source: offline/net/IndexDBOfflineLoader.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/net/IndexDBOfflineLoader.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import IndexDBStore from '../storage/IndexDBStore'; function IndexDBOfflineLoader(config) { config = config || {}; const context = this.context; const urlUtils = config.urlUtils; const constants = config.constants; const dashConstants = config.dashConstants; let instance, indexDBStore; function setup() { indexDBStore = IndexDBStore(context).getInstance(); } function getManifestId (url) { let myURL = urlUtils.removeHostname(url); var parts = myURL.split('/'); return parts[0]; } /** * Load manifest or fragment from indexeddb database * @param {object} config configuration of request */ function load(config) { if (config.request) { let manifestId = getManifestId(config.request.url); if (manifestId % 1 === 0) { if ( config.request.mediaType === constants.AUDIO || config.request.mediaType === constants.VIDEO || config.request.mediaType === constants.TEXT || config.request.mediaType === constants.MUXED || config.request.mediaType === constants.IMAGE ) { let suffix = config.request.type === 'InitializationSegment' ? 'init' : config.request.index; let key = config.request.representationId + '_' + suffix; indexDBStore.getFragmentByKey(manifestId, key).then(function (fragment) { config.success(fragment, null, config.request.url, constants.ARRAY_BUFFER); }).catch(function (err) { config.error(err); }); } else if (config.request.type === dashConstants.MPD) { indexDBStore.getManifestById(manifestId).then(function (item) { indexDBStore.createFragmentStore(item.fragmentStore); config.success(item.manifest, null, config.request.url, constants.XML); }).catch(function (err) { config.error(config.request, 404, err); }); } } else { config.error(config.request, null, 'MediaType can not be found'); } } } function abort() { // nothing to do } setup(); instance = { load: load, abort: abort }; return instance; } IndexDBOfflineLoader.__dashjs_factory_name = 'IndexDBOfflineLoader'; const factory = dashjs.FactoryMaker.getClassFactory(IndexDBOfflineLoader); /* jshint ignore:line */ export default factory; × Search results Close "},"offline_storage_IndexDBStore.js.html":{"id":"offline_storage_IndexDBStore.js.html","title":"Source: offline/storage/IndexDBStore.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/storage/IndexDBStore.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @ignore */ const localforage = require('localforage'); const entities = require('html-entities').XmlEntities; function IndexDBStore() { let instance, manifestStore, fragmentStores; function setup() { fragmentStores = {}; if (typeof window === 'undefined') { return; } localforage.config({ driver: localforage.INDEXEDDB, name: 'dash_offline_db' }); manifestStore = localforage.createInstance({ driver: localforage.INDEXEDDB, name: 'dash_offline_db', version: 1.0, storeName: 'manifest' }); } ///////////////////////////////////////// // // GET/SET Methods // //////////////////////////////////////// /** * Creates an instance of localforage to store fragments in indexed db * @param {string} storeName * @instance */ function createFragmentStore(storeName) { if (!fragmentStores[storeName]) { console.log('setStore ' + storeName); let fragmentStore = localforage.createInstance({ driver: localforage.INDEXEDDB, name: 'dash_offline_db', version: 1.0, storeName: storeName }); fragmentStores[storeName] = fragmentStore; } } /** * Update download status * @param {number} manifestId * @param {string} newStatus * @returns {Promise} promise * @instance */ function setDownloadingStatus(manifestId, newStatus) { return getManifestById(manifestId).then(function (item) { item.status = newStatus; return updateManifest(item).catch(function () { return Promise.reject('Cannot set status ' + newStatus + ' for this stream !'); }); }).catch(function (err) { return Promise.reject(err); }); } /** * Updat last downloaded fragment index for representationId * @param {number} manifestId - manifest id * @param {string} representationId - representation * @param {number} state - representation state * @returns {Promise} promise * @instance */ function setRepresentationCurrentState(manifestId, representationId, state) { return getManifestById(manifestId).then(function (item) { if (!item.state) { item.state = {}; } if (!item.state[representationId]) { item.state[representationId] = { index: -1, downloaded: 0 }; } item.state[representationId] = state; return updateManifest(item).catch(function () { return Promise.reject('Cannot set current index for represenation id ' + representationId); }); }).catch(function (err) { return Promise.reject(err); }); } /** * Returns current downloaded segment index for representation * @param {number} manifestId - manifest id * @param {string} representationId - representation * @returns {Promise} promise * @instance */ function getRepresentationCurrentState(manifestId, representationId) { return getManifestById(manifestId).then(function (item) { let state = { index: -1, downloaded: 0 }; if (item.state &amp;&amp; item.state[representationId]) { state = item.state[representationId]; } return Promise.resolve(state); }).catch(function (err) { return Promise.reject(err); }); } /** * Returns a fragment from its key * @param {number} manifestId * @param {number} key * @returns {Promise} fragment * @instance */ function getFragmentByKey(manifestId, key) { let fragmentStore = fragmentStores[manifestId]; if (!fragmentStore) { return Promise.reject(new Error (`No fragment store found for manifest ${manifestId}`)); } return fragmentStore.getItem(key).then(function (value) { return Promise.resolve(value); }).catch(function (err) { return Promise.reject(err); }); } /** * Returns a manifest from its identifier * @param {number} id * @returns {Promise} {Object[]} manifests * @instance */ function getManifestById(id) { return getAllManifests().then(function (array) { if (array) { let item = null; for (let i = 0; i &lt; array.manifests.length; i++) { if (array.manifests[i].manifestId === parseInt(id)) { item = array.manifests[i]; } } if (item !== null) { item.manifest = entities.decode(item.manifest); return Promise.resolve(item); } else { return Promise.reject('Cannot found manifest with this manifestId : ' + id); } } else { return Promise.reject('Any manifests stored in DB !'); } }).catch(function (err) { return Promise.reject(err); }); } /** * Returns all offline manifests * @returns {Promise} {Object[]} manifests * @instance */ function getAllManifests() { return manifestStore.getItem('manifest').then(function (array) { return Promise.resolve(array ? array : { 'manifests': [] }); }).catch(function (err) { return Promise.reject(err); }); } /** * Return higher manifest id * @returns {Promise} number * @instance */ function getCurrentHigherManifestId() { return getAllManifests().then(function (array) { let higherManifestId = 0; if (array) { for (let i = 0; i &lt; array.manifests.length; i++) { if (array.manifests[i].manifestId &gt; higherManifestId) { higherManifestId = array.manifests[i].manifestId; } } return Promise.resolve(higherManifestId); } else { return Promise.resolve(higherManifestId); } }).catch(function (err) { return Promise.reject(err); }); } /** * Update manifest * @param {Object} manifest updated manifest * @returns {Promise} promise asynchronously resolved * @instance */ function updateManifest(manifest) { return getAllManifests().then(function (array) { try { for (let i = 0; i &lt; array.manifests.length; i++) { if (array.manifests[i].manifestId === manifest.manifestId) { array.manifests[i] = manifest; } } return manifestStore.setItem('manifest', array); } catch (err) { throw new Error('Any results found !'); } }); } /** * save selected representation by user * @param {Object} manifest updated manifest * @param {Object} selected selected representations * @returns {Promise} promise asynchronously resolved * @instance */ function saveSelectedRepresentations(manifest, selected) { return getManifestById(manifest).then(function (item) { if (!item.selected) { item.selected = {}; } item.selected = selected; return updateManifest(item).catch(function () { return Promise.reject('Cannot save selected representations'); }); }).catch(function (err) { return Promise.reject(err); }); } /** * Store a manifest in manifest array * @param {Object} manifest * @instance */ function storeManifest(manifest) { return manifestStore.getItem('manifest').then(function (results) { let array = results ? results : { 'manifests': [] }; array.manifests.push(manifest); return manifestStore.setItem('manifest', array); }); } /** * Store a fragment in fragment store * @param {number} manifestId * @param {number} fragmentId * @param {Object} fragmentData * @returns {Promise} promise asynchronously resolved * @instance */ function storeFragment(manifestId, fragmentId, fragmentData) { let fragmentStore = fragmentStores[manifestId]; if (!fragmentStore) { return Promise.reject(new Error (`No fragment store found for manifest ${manifestId}`)); } return fragmentStore.setItem(fragmentId, fragmentData, function () { return Promise.resolve(); }).catch(function (err) { return Promise.reject(err); }); } ///////////////////////////////////////// // // DROP Methods // //////////////////////////////////////// /** * Remove all manifest and fragment store * @returns {Promise} promise asynchronously resolved * @instance */ function dropAll() { return localforage.clear().then(function () { return Promise.resolve(); }).catch(function (err) { return Promise.reject(err); }); } /** * Remove framgent store given its name * @param {string} storeName * @instance */ function dropFragmentStore(storeName) { localforage.dropInstance({ driver: localforage.INDEXEDDB, name: 'dash_offline_db', version: 1.0, storeName: storeName }).then(function () { delete fragmentStores[storeName]; }).catch(function (err) { console.log('dropFragmentStore failed ' + err); }); return; } /** * Remove download given its id (fragmentStore + manifest entry in manifest array) * @param {number} manifestId * @returns {Promise} promise asynchronously resolved * @instance */ function deleteDownloadById(manifestId) { return manifestStore.getItem('manifest').then(function (array) { if (array) { return deleteFragmentStore(manifestId).then(function () { for (let i = 0; i &lt; array.manifests.length; i++) { if (array.manifests[i].manifestId === parseInt(manifestId)) { array.manifests.splice(i, 1); } } return manifestStore.setItem('manifest', array).then(function () { return Promise.resolve('This stream has been successfull removed !'); }).catch(function () { return Promise.reject('An error occured when trying to delete this manifest'); }); }); } else { return Promise.resolve('Nothing to delete !'); } }).catch(function (err) { return Promise.reject(err); }); } /** * Remove fragment store * @param {string} storeName * @returns {Promise} promise asynchronously resolved * @instance */ function deleteFragmentStore(storeName) { localforage.createInstance({ name: 'dash_offline_db', storeName: storeName }); return localforage.dropInstance({ name: 'dash_offline_db', storeName: storeName }).then(function () { delete fragmentStores[storeName]; return Promise.resolve(); }).catch(function (err) { console.log(err); return Promise.reject(err); }); } setup(); instance = { dropAll: dropAll, getFragmentByKey: getFragmentByKey, getManifestById: getManifestById, storeFragment: storeFragment, storeManifest: storeManifest, updateManifest: updateManifest, saveSelectedRepresentations: saveSelectedRepresentations, createFragmentStore: createFragmentStore, setDownloadingStatus: setDownloadingStatus, setRepresentationCurrentState: setRepresentationCurrentState, getRepresentationCurrentState: getRepresentationCurrentState, getCurrentHigherManifestId: getCurrentHigherManifestId, getAllManifests: getAllManifests, dropFragmentStore: dropFragmentStore, deleteDownloadById: deleteDownloadById }; return instance; } IndexDBStore.__dashjs_factory_name = 'IndexDBStore'; export default dashjs.FactoryMaker.getSingletonFactory(IndexDBStore); /* jshint ignore:line */ × Search results Close "},"streaming_rules_abr_InsufficientBufferRule.js.html":{"id":"streaming_rules_abr_InsufficientBufferRule.js.html","title":"Source: streaming/rules/abr/InsufficientBufferRule.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/rules/abr/InsufficientBufferRule.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import EventBus from '../../../core/EventBus'; import Events from '../../../core/events/Events'; import FactoryMaker from '../../../core/FactoryMaker'; import Debug from '../../../core/Debug'; import SwitchRequest from '../SwitchRequest'; import Constants from '../../constants/Constants'; import MetricsConstants from '../../constants/MetricsConstants'; import MediaPlayerEvents from '../../MediaPlayerEvents'; function InsufficientBufferRule(config) { config = config || {}; const INSUFFICIENT_BUFFER_SAFETY_FACTOR = 0.5; const SEGMENT_IGNORE_COUNT = 2; const context = this.context; const eventBus = EventBus(context).getInstance(); const dashMetrics = config.dashMetrics; let instance, logger, bufferStateDict; function setup() { logger = Debug(context).getInstance().getLogger(instance); resetInitialSettings(); eventBus.on(MediaPlayerEvents.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.on(Events.BYTES_APPENDED_END_FRAGMENT, _onBytesAppended, instance); } function checkConfig() { if (!dashMetrics || !dashMetrics.hasOwnProperty('getCurrentBufferLevel') || !dashMetrics.hasOwnProperty('getCurrentBufferState')) { throw new Error(Constants.MISSING_CONFIG_ERROR); } } /** * If a BUFFER_EMPTY event happens, then InsufficientBufferRule returns switchRequest.quality=0 until BUFFER_LOADED happens. * Otherwise InsufficientBufferRule gives a maximum bitrate depending on throughput and bufferLevel such that * a whole fragment can be downloaded before the buffer runs out, subject to a conservative safety factor of 0.5. * If the bufferLevel is low, then InsufficientBufferRule avoids rebuffering risk. * If the bufferLevel is high, then InsufficientBufferRule give a high MaxIndex allowing other rules to take over. * @param rulesContext * @return {object} */ function getMaxIndex(rulesContext) { const switchRequest = SwitchRequest(context).create(); if (!rulesContext || !rulesContext.hasOwnProperty('getMediaType')) { return switchRequest; } checkConfig(); const mediaType = rulesContext.getMediaType(); const currentBufferState = dashMetrics.getCurrentBufferState(mediaType); const representationInfo = rulesContext.getRepresentationInfo(); const fragmentDuration = representationInfo.fragmentDuration; const streamInfo = rulesContext.getStreamInfo(); const streamId = streamInfo ? streamInfo.id : null; const scheduleController = rulesContext.getScheduleController(); const isDynamic = streamInfo &amp;&amp; streamInfo.manifestInfo &amp;&amp; streamInfo.manifestInfo.isDynamic; const playbackController = scheduleController.getPlaybackController(); // Don't ask for a bitrate change if there is not info about buffer state or if fragmentDuration is not defined const lowLatencyEnabled = playbackController.getLowLatencyModeEnabled(); if (shouldIgnore(lowLatencyEnabled, mediaType) || !fragmentDuration) { return switchRequest; } if (currentBufferState &amp;&amp; currentBufferState.state === MetricsConstants.BUFFER_EMPTY) { logger.debug('[' + mediaType + '] Switch to index 0; buffer is empty.'); switchRequest.quality = 0; switchRequest.reason = 'InsufficientBufferRule: Buffer is empty'; } else { const mediaInfo = rulesContext.getMediaInfo(); const abrController = rulesContext.getAbrController(); const throughputHistory = abrController.getThroughputHistory(); const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType); const throughput = throughputHistory.getAverageThroughput(mediaType, isDynamic); const latency = throughputHistory.getAverageLatency(mediaType); const bitrate = throughput * (bufferLevel / fragmentDuration) * INSUFFICIENT_BUFFER_SAFETY_FACTOR; switchRequest.quality = abrController.getQualityForBitrate(mediaInfo, bitrate, streamId, latency); switchRequest.reason = 'InsufficientBufferRule: being conservative to avoid immediate rebuffering'; } return switchRequest; } function shouldIgnore(lowLatencyEnabled, mediaType) { return !lowLatencyEnabled &amp;&amp; bufferStateDict[mediaType].ignoreCount &gt; 0; } function resetInitialSettings() { bufferStateDict = {}; bufferStateDict[Constants.VIDEO] = { ignoreCount: SEGMENT_IGNORE_COUNT }; bufferStateDict[Constants.AUDIO] = { ignoreCount: SEGMENT_IGNORE_COUNT }; } function _onPlaybackSeeking() { resetInitialSettings(); } function _onBytesAppended(e) { if (!isNaN(e.startTime) &amp;&amp; (e.mediaType === Constants.AUDIO || e.mediaType === Constants.VIDEO)) { if (bufferStateDict[e.mediaType].ignoreCount &gt; 0) { bufferStateDict[e.mediaType].ignoreCount--; } } } function reset() { resetInitialSettings(); eventBus.off(MediaPlayerEvents.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.off(Events.BYTES_APPENDED_END_FRAGMENT, _onBytesAppended, instance); } instance = { getMaxIndex, reset }; setup(); return instance; } InsufficientBufferRule.__dashjs_factory_name = 'InsufficientBufferRule'; export default FactoryMaker.getClassFactory(InsufficientBufferRule); × Search results Close "},"streaming_utils_IsoFile.js.html":{"id":"streaming_utils_IsoFile.js.html","title":"Source: streaming/utils/IsoFile.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/IsoFile.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import IsoBox from '../vo/IsoBox'; import FactoryMaker from '../../core/FactoryMaker'; function IsoFile() { let instance, parsedIsoFile; /** * @param {string} type * @returns {IsoBox|null} * @memberof IsoFile# */ function getBox(type) { if (!type || !parsedIsoFile || !parsedIsoFile.boxes || (parsedIsoFile.boxes.length === 0) || typeof parsedIsoFile.fetch !== 'function') return null; return convertToDashIsoBox(parsedIsoFile.fetch(type)); } /** * @param {string} type * @returns {Array|null} array of {@link IsoBox} * @memberof IsoFile# */ function getBoxes(type) { let boxes = []; if (!type || !parsedIsoFile || typeof parsedIsoFile.fetchAll !== 'function') { return boxes; } let boxData = parsedIsoFile.fetchAll(type); let box; for (let i = 0, ln = boxData.length; i &lt; ln; i++) { box = convertToDashIsoBox(boxData[i]); if (box) { boxes.push(box); } } return boxes; } /** * @param {string} value * @memberof IsoFile# */ function setData(value) { parsedIsoFile = value; } /** * @returns {IsoBox|null} * @memberof IsoFile# */ function getLastBox() { if (!parsedIsoFile || !parsedIsoFile.boxes || !parsedIsoFile.boxes.length) return null; let type = parsedIsoFile.boxes[parsedIsoFile.boxes.length - 1].type; let boxes = getBoxes(type); return boxes.length &gt; 0 ? boxes[boxes.length - 1] : null; } function convertToDashIsoBox(boxData) { if (!boxData) return null; let box = new IsoBox(boxData); if (boxData.hasOwnProperty('_incomplete')) { box.isComplete = !boxData._incomplete; } return box; } instance = { getBox: getBox, getBoxes: getBoxes, setData: setData, getLastBox: getLastBox }; return instance; } IsoFile.__dashjs_factory_name = 'IsoFile'; export default FactoryMaker.getClassFactory(IsoFile); × Search results Close "},"streaming_protection_drm_KeySystem.js.html":{"id":"streaming_protection_drm_KeySystem.js.html","title":"Source: streaming/protection/drm/KeySystem.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/drm/KeySystem.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Defines the public interface for all Key Systems (DRMs) supported * by the player. * * @interface KeySystem * @ignore */ /** * Key system name string (e.g. 'org.w3.clearkey') * * @instance * @name systemString * @memberof KeySystem * @readonly * @type String */ /** * Key system UUID in the form '01234567-89ab-cdef-0123-456789abcdef' * * @instance * @name uuid * @memberof KeySystem * @readonly * @type String */ /** * The scheme ID URI for this key system in the form * 'urn:uuid:01234567-89ab-cdef-0123-456789abcdef' as used * in DASH ContentProtection elements * * @instance * @name schemeIdURI * @memberof KeySystem * @readonly * @type String */ /** * Parse DRM-specific init data from the ContentProtection * element. * * @function * @name KeySystem#getInitData * @param {Object} contentProtection the json-style contentProtection * object representing the ContentProtection element parsed from the * MPD XML document. * @param {Object} cencContentProtection the Common Encryption content protection element or * null if not specified. * @returns {ArrayBuffer} EME initialization data */ /** * For some key systems, the CDM message contains HTTP headers that * can be parsed by the application and attached to the license request. * Returns a header object with key/value pairs as object properties/values * * @function * @name KeySystem#getRequestHeadersFromMessage * @param {ArrayBuffer} message the CDM message * @returns {?Object} headers object with header names as the object property * names and header values as the corresponding object property values. Return * null if no such headers were found or if the mechanism is not supported by * this key system */ /** * For some key systems, the CDM message contains more than just the * license request data. This method will pull the license request from * the CDM message, if necessary. * * @function * @name KeySystem#getLicenseRequestFromMessage * @param message {ArrayBuffer} the CDM message * @returns {Uint8Array} the license request message as will be passed to * XMLHttpRequest.send() */ /** * Returns a license server URL as parsed from key system initialization data (PSSH). * * @function * @name KeySystem#getLicenseServerURLFromInitData * @param initData {ArrayBuffer} the initialization data. This is just the \"Data\" field * from the PSSH box definition * @returns {?string} The license server URL or null if URL is not available in initData */ /** * Returns specific CDM (custom) data. * * @function * @name MediaPlayer.dependencies.protection.KeySystem#getCDMData * @returns {ArrayBuffer} the CDM (custom) data */ /** * Returns MediaKeySession session ID. * * @function * @name MediaPlayer.dependencies.protection.KeySystem#getSessionId * @returns {String} the MediaKeySession session ID */ × Search results Close "},"streaming_protection_drm_KeySystemClearKey.js.html":{"id":"streaming_protection_drm_KeySystemClearKey.js.html","title":"Source: streaming/protection/drm/KeySystemClearKey.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/drm/KeySystemClearKey.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import KeyPair from '../vo/KeyPair'; import ClearKeyKeySet from '../vo/ClearKeyKeySet'; import CommonEncryption from '../CommonEncryption'; import ProtectionConstants from '../../constants/ProtectionConstants'; const uuid = 'e2719d58-a985-b3c9-781a-b030af78d30e'; const systemString = ProtectionConstants.CLEARKEY_KEYSTEM_STRING; const schemeIdURI = 'urn:uuid:' + uuid; function KeySystemClearKey(config) { config = config || {}; let instance; const BASE64 = config.BASE64; /** * Returns desired clearkeys (as specified in the CDM message) from protection data * * @param {ProtectionData} protectionData the protection data * @param {ArrayBuffer} message the ClearKey CDM message * @returns {ClearKeyKeySet} the key set or null if none found * @throws {Error} if a keyID specified in the CDM message was not found in the * protection data * @memberof KeySystemClearKey */ function getClearKeysFromProtectionData(protectionData, message) { let clearkeySet = null; if (protectionData) { // ClearKey is the only system that does not require a license server URL, so we // handle it here when keys are specified in protection data const jsonMsg = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message))); const keyPairs = []; for (let i = 0; i &lt; jsonMsg.kids.length; i++) { const clearkeyID = jsonMsg.kids[i]; const clearkey = (protectionData.clearkeys &amp;&amp; protectionData.clearkeys.hasOwnProperty(clearkeyID)) ? protectionData.clearkeys[clearkeyID] : null; if (!clearkey) { throw new Error('DRM: ClearKey keyID (' + clearkeyID + ') is not known!'); } // KeyIDs from CDM are not base64 padded. Keys may or may not be padded keyPairs.push(new KeyPair(clearkeyID, clearkey)); } clearkeySet = new ClearKeyKeySet(keyPairs); } return clearkeySet; } function getInitData(cp, cencContentProtection) { try { let initData = CommonEncryption.parseInitDataFromContentProtection(cp, BASE64); if (!initData &amp;&amp; cencContentProtection) { const cencDefaultKid = cencDefaultKidToBase64Representation(cencContentProtection['cenc:default_KID']); const data = { kids: [cencDefaultKid] }; initData = new TextEncoder().encode(JSON.stringify(data)); } return initData; } catch (e) { return null; } } function cencDefaultKidToBase64Representation(cencDefaultKid) { try { let kid = cencDefaultKid.replace(/-/g, ''); kid = btoa(kid.match(/\\w{2}/g).map((a) =&gt; { return String.fromCharCode(parseInt(a, 16)); }).join('')); return kid.replace(/=/g, '') .replace(/\\//g, '_') .replace(/\\+/g, '-'); } catch (e) { return null; } } function getRequestHeadersFromMessage(/*message*/) { // Set content type to application/json by default return { 'Content-Type': 'application/json' }; } function getLicenseRequestFromMessage(message) { return JSON.stringify(JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message)))); } function getLicenseServerURLFromInitData(/*initData*/) { return null; } function getCDMData(/*cdmData*/) { return null; } instance = { uuid, schemeIdURI, systemString, getInitData, getRequestHeadersFromMessage, getLicenseRequestFromMessage, getLicenseServerURLFromInitData, getCDMData, getClearKeysFromProtectionData }; return instance; } KeySystemClearKey.__dashjs_factory_name = 'KeySystemClearKey'; export default dashjs.FactoryMaker.getSingletonFactory(KeySystemClearKey); /* jshint ignore:line */ × Search results Close "},"streaming_protection_drm_KeySystemW3CClearKey.js.html":{"id":"streaming_protection_drm_KeySystemW3CClearKey.js.html","title":"Source: streaming/protection/drm/KeySystemW3CClearKey.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/drm/KeySystemW3CClearKey.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import KeyPair from '../vo/KeyPair'; import ClearKeyKeySet from '../vo/ClearKeyKeySet'; import CommonEncryption from '../CommonEncryption'; import ProtectionConstants from '../../constants/ProtectionConstants'; const uuid = '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b'; const systemString = ProtectionConstants.CLEARKEY_KEYSTEM_STRING; const schemeIdURI = 'urn:uuid:' + uuid; function KeySystemW3CClearKey(config) { let instance; const BASE64 = config.BASE64; const logger = config.debug.getLogger(instance); /** * Returns desired clearkeys (as specified in the CDM message) from protection data * * @param {ProtectionDataSet} protectionData the protection data * @param {ArrayBuffer} message the ClearKey CDM message * @returns {ClearKeyKeySet} the key set or null if none found * @throws {Error} if a keyID specified in the CDM message was not found in the * protection data * @memberof KeySystemClearKey */ function getClearKeysFromProtectionData(protectionData, message) { let clearkeySet = null; if (protectionData) { // ClearKey is the only system that does not require a license server URL, so we // handle it here when keys are specified in protection data const jsonMsg = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message))); const keyPairs = []; for (let i = 0; i &lt; jsonMsg.kids.length; i++) { const clearkeyID = jsonMsg.kids[i]; const clearkey = (protectionData.clearkeys &amp;&amp; protectionData.clearkeys.hasOwnProperty(clearkeyID)) ? protectionData.clearkeys[clearkeyID] : null; if (!clearkey) { throw new Error('DRM: ClearKey keyID (' + clearkeyID + ') is not known!'); } // KeyIDs from CDM are not base64 padded. Keys may or may not be padded keyPairs.push(new KeyPair(clearkeyID, clearkey)); } clearkeySet = new ClearKeyKeySet(keyPairs); logger.warn('ClearKey schemeIdURI is using W3C Common PSSH systemID (1077efec-c0b2-4d02-ace3-3c1e52e2fb4b) in Content Protection. See DASH-IF IOP v4.1 section 7.6.2.4'); } return clearkeySet; } function getInitData(cp) { return CommonEncryption.parseInitDataFromContentProtection(cp, BASE64); } function getRequestHeadersFromMessage(/*message*/) { return null; } function getLicenseRequestFromMessage(message) { return new Uint8Array(message); } function getLicenseServerURLFromInitData(/*initData*/) { return null; } function getCDMData(/*cdmData*/) { return null; } instance = { uuid: uuid, schemeIdURI: schemeIdURI, systemString: systemString, getInitData: getInitData, getRequestHeadersFromMessage: getRequestHeadersFromMessage, getLicenseRequestFromMessage: getLicenseRequestFromMessage, getLicenseServerURLFromInitData: getLicenseServerURLFromInitData, getCDMData: getCDMData, getClearKeysFromProtectionData: getClearKeysFromProtectionData }; return instance; } KeySystemW3CClearKey.__dashjs_factory_name = 'KeySystemW3CClearKey'; export default dashjs.FactoryMaker.getSingletonFactory(KeySystemW3CClearKey); /* jshint ignore:line */ × Search results Close "},"streaming_protection_drm_KeySystemPlayReady.js.html":{"id":"streaming_protection_drm_KeySystemPlayReady.js.html","title":"Source: streaming/protection/drm/KeySystemPlayReady.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/drm/KeySystemPlayReady.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Microsoft PlayReady DRM * * @class * @implements KeySystem */ import CommonEncryption from '../CommonEncryption'; import ProtectionConstants from '../../constants/ProtectionConstants'; const uuid = '9a04f079-9840-4286-ab92-e65be0885f95'; const systemString = ProtectionConstants.PLAYREADY_KEYSTEM_STRING; const schemeIdURI = 'urn:uuid:' + uuid; const PRCDMData = '&lt;PlayReadyCDMData type=\"LicenseAcquisition\"&gt;&lt;LicenseAcquisition version=\"1.0\" Proactive=\"false\"&gt;&lt;CustomData encoding=\"base64encoded\"&gt;%CUSTOMDATA%&lt;/CustomData&gt;&lt;/LicenseAcquisition&gt;&lt;/PlayReadyCDMData&gt;'; function KeySystemPlayReady(config) { config = config || {}; let instance; let messageFormat = 'utf-16'; const BASE64 = config.BASE64; const settings = config.settings; function checkConfig() { if (!BASE64 || !BASE64.hasOwnProperty('decodeArray') || !BASE64.hasOwnProperty('decodeArray') ) { throw new Error('Missing config parameter(s)'); } } function getRequestHeadersFromMessage(message) { let msg, xmlDoc; const headers = {}; const parser = new DOMParser(); if (settings &amp;&amp; settings.get().streaming.protection.detectPlayreadyMessageFormat) { // If message format configured/defaulted to utf-16 AND number of bytes is odd, assume 'unwrapped' raw CDM message. if (messageFormat === 'utf-16' &amp;&amp; message &amp;&amp; message.byteLength % 2 === 1) { headers['Content-Type'] = 'text/xml; charset=utf-8'; return headers; } } const dataview = (messageFormat === 'utf-16') ? new Uint16Array(message) : new Uint8Array(message); msg = String.fromCharCode.apply(null, dataview); xmlDoc = parser.parseFromString(msg, 'application/xml'); const headerNameList = xmlDoc.getElementsByTagName('name'); const headerValueList = xmlDoc.getElementsByTagName('value'); for (let i = 0; i &lt; headerNameList.length; i++) { headers[headerNameList[i].childNodes[0].nodeValue] = headerValueList[i].childNodes[0].nodeValue; } // Some versions of the PlayReady CDM return 'Content' instead of 'Content-Type'. // this is NOT w3c conform and license servers may reject the request! // -&gt; rename it to proper w3c definition! if (headers.hasOwnProperty('Content')) { headers['Content-Type'] = headers.Content; delete headers.Content; } // Set Content-Type header by default if not provided in the the CDM message (&lt;PlayReadyKeyMessage/&gt;) // or if the message contains directly the challenge itself (Ex: LG SmartTVs) if (!headers.hasOwnProperty('Content-Type')) { headers['Content-Type'] = 'text/xml; charset=utf-8'; } return headers; } function getLicenseRequestFromMessage(message) { let licenseRequest = null; const parser = new DOMParser(); if (settings &amp;&amp; settings.get().streaming.protection.detectPlayreadyMessageFormat) { // If message format configured/defaulted to utf-16 AND number of bytes is odd, assume 'unwrapped' raw CDM message. if (messageFormat === 'utf-16' &amp;&amp; message &amp;&amp; message.byteLength % 2 === 1) { return message; } } const dataview = (messageFormat === 'utf-16') ? new Uint16Array(message) : new Uint8Array(message); checkConfig(); const msg = String.fromCharCode.apply(null, dataview); const xmlDoc = parser.parseFromString(msg, 'application/xml'); if (xmlDoc.getElementsByTagName('PlayReadyKeyMessage')[0]) { const Challenge = xmlDoc.getElementsByTagName('Challenge')[0].childNodes[0].nodeValue; if (Challenge) { licenseRequest = BASE64.decode(Challenge); } } else { // The message from CDM is not a wrapped message as on IE11 and Edge, // thus it contains direclty the challenge itself // (note that the xmlDoc at this point may be unreadable since it may have been interpreted as UTF-16) return message; } return licenseRequest; } function getLicenseServerURLFromInitData(initData) { if (initData) { const data = new DataView(initData); const numRecords = data.getUint16(4, true); let offset = 6; const parser = new DOMParser(); for (let i = 0; i &lt; numRecords; i++) { // Parse the PlayReady Record header const recordType = data.getUint16(offset, true); offset += 2; const recordLength = data.getUint16(offset, true); offset += 2; if (recordType !== 0x0001) { offset += recordLength; continue; } const recordData = initData.slice(offset, offset + recordLength); const record = String.fromCharCode.apply(null, new Uint16Array(recordData)); const xmlDoc = parser.parseFromString(record, 'application/xml'); // First try &lt;LA_URL&gt; if (xmlDoc.getElementsByTagName('LA_URL')[0]) { const laurl = xmlDoc.getElementsByTagName('LA_URL')[0].childNodes[0].nodeValue; if (laurl) { return laurl; } } // Optionally, try &lt;LUI_URL&gt; if (xmlDoc.getElementsByTagName('LUI_URL')[0]) { const luiurl = xmlDoc.getElementsByTagName('LUI_URL')[0].childNodes[0].nodeValue; if (luiurl) { return luiurl; } } } } return null; } function getInitData(cpData) { // * desc@ getInitData // * generate PSSH data from PROHeader defined in MPD file // * PSSH format: // * size (4) // * box type(PSSH) (8) // * Protection SystemID (16) // * protection system data size (4) - length of decoded PROHeader // * decoded PROHeader data from MPD file const PSSHBoxType = new Uint8Array([0x70, 0x73, 0x73, 0x68, 0x00, 0x00, 0x00, 0x00]); //'PSSH' 8 bytes const playreadySystemID = new Uint8Array([0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95]); let byteCursor = 0; let uint8arraydecodedPROHeader = null; let PROSize, PSSHSize, PSSHBoxBuffer, PSSHBox, PSSHData; checkConfig(); if (!cpData) { return null; } // Handle common encryption PSSH if ('pssh' in cpData) { return CommonEncryption.parseInitDataFromContentProtection(cpData, BASE64); } // Handle native MS PlayReady ContentProtection elements if ('pro' in cpData) { uint8arraydecodedPROHeader = BASE64.decodeArray(cpData.pro.__text); } else if ('prheader' in cpData) { uint8arraydecodedPROHeader = BASE64.decodeArray(cpData.prheader.__text); } else { return null; } PROSize = uint8arraydecodedPROHeader.length; PSSHSize = 0x4 + PSSHBoxType.length + playreadySystemID.length + 0x4 + PROSize; PSSHBoxBuffer = new ArrayBuffer(PSSHSize); PSSHBox = new Uint8Array(PSSHBoxBuffer); PSSHData = new DataView(PSSHBoxBuffer); PSSHData.setUint32(byteCursor, PSSHSize); byteCursor += 0x4; PSSHBox.set(PSSHBoxType, byteCursor); byteCursor += PSSHBoxType.length; PSSHBox.set(playreadySystemID, byteCursor); byteCursor += playreadySystemID.length; PSSHData.setUint32(byteCursor, PROSize); byteCursor += 0x4; PSSHBox.set(uint8arraydecodedPROHeader, byteCursor); byteCursor += PROSize; return PSSHBox.buffer; } /** * It seems that some PlayReady implementations return their XML-based CDM * messages using UTF16, while others return them as UTF8. Use this function * to modify the message format to expect when parsing CDM messages. * * @param {string} format the expected message format. Either \"utf-8\" or \"utf-16\". * @throws {Error} Specified message format is not one of \"utf8\" or \"utf16\" */ function setPlayReadyMessageFormat(format) { if (format !== 'utf-8' &amp;&amp; format !== 'utf-16') { throw new Error('Specified message format is not one of \"utf-8\" or \"utf-16\"'); } messageFormat = format; } /** * Get Playready Custom data */ function getCDMData(_cdmData) { let customData, cdmData, cdmDataBytes, i; checkConfig(); if (!_cdmData) return null; // Convert custom data into multibyte string customData = []; for (i = 0; i &lt; _cdmData.length; ++i) { customData.push(_cdmData.charCodeAt(i)); customData.push(0); } customData = String.fromCharCode.apply(null, customData); // Encode in Base 64 the custom data string customData = BASE64.encode(customData); // Initialize CDM data with Base 64 encoded custom data // (see https://msdn.microsoft.com/en-us/library/dn457361.aspx) cdmData = PRCDMData.replace('%CUSTOMDATA%', customData); // Convert CDM data into multibyte characters cdmDataBytes = []; for (i = 0; i &lt; cdmData.length; ++i) { cdmDataBytes.push(cdmData.charCodeAt(i)); cdmDataBytes.push(0); } return new Uint8Array(cdmDataBytes).buffer; } instance = { uuid, schemeIdURI, systemString, getInitData, getRequestHeadersFromMessage, getLicenseRequestFromMessage, getLicenseServerURLFromInitData, getCDMData, setPlayReadyMessageFormat }; return instance; } KeySystemPlayReady.__dashjs_factory_name = 'KeySystemPlayReady'; export default dashjs.FactoryMaker.getSingletonFactory(KeySystemPlayReady); /* jshint ignore:line */ × Search results Close "},"streaming_rules_abr_L2ARule.js.html":{"id":"streaming_rules_abr_L2ARule.js.html","title":"Source: streaming/rules/abr/L2ARule.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/rules/abr/L2ARule.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2020, Unified Streaming. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ // For a description of the Learn2Adapt-LowLatency (L2A-LL) bitrate adaptation algorithm, see https://github.com/unifiedstreaming/Learn2Adapt-LowLatency/blob/master/Online_learning_for_bitrate_adaptation_in_low_latency_live_streaming_CR.pdf import MetricsConstants from '../../constants/MetricsConstants'; import SwitchRequest from '../SwitchRequest'; import FactoryMaker from '../../../core/FactoryMaker'; import {HTTPRequest} from '../../vo/metrics/HTTPRequest'; import EventBus from '../../../core/EventBus'; import Events from '../../../core/events/Events'; import Debug from '../../../core/Debug'; import Constants from '../../constants/Constants'; const L2A_STATE_ONE_BITRATE = 0; // If there is only one bitrate (or initialization failed), always return NO_CHANGE. const L2A_STATE_STARTUP = 1; // Set placeholder buffer such that we download fragments at most recently measured throughput. const L2A_STATE_STEADY = 2; // Buffer primed, we switch to steady operation. function L2ARule(config) { config = config || {}; const context = this.context; const dashMetrics = config.dashMetrics; const eventBus = EventBus(context).getInstance(); let instance, l2AStateDict, l2AParameterDict, logger; /** * Setup function to initialize L2ARule */ function setup() { logger = Debug(context).getInstance().getLogger(instance); _resetInitialSettings(); eventBus.on(Events.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.on(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, instance); eventBus.on(Events.METRIC_ADDED, _onMetricAdded, instance); eventBus.on(Events.QUALITY_CHANGE_REQUESTED, _onQualityChangeRequested, instance); } /** * Sets the initial state of the algorithm. Calls the initialize function for the paramteters. * @param {object} rulesContext * @return {object} initialState * @private */ function _getInitialL2AState(rulesContext) { const initialState = {}; const mediaInfo = rulesContext.getMediaInfo(); const bitrates = mediaInfo.bitrateList.map((b) =&gt; { return b.bandwidth / 1000; }); initialState.state = L2A_STATE_STARTUP; initialState.bitrates = bitrates; initialState.lastQuality = 0; _initializeL2AParameters(mediaInfo); _clearL2AStateOnSeek(initialState); return initialState; } /** * Initializes the parameters of the algorithm. This will be done once for each media type. * @param {object} mediaInfo * @private */ function _initializeL2AParameters(mediaInfo) { if (!mediaInfo || !mediaInfo.type) { return; } l2AParameterDict[mediaInfo.type] = {}; l2AParameterDict[mediaInfo.type].w = []; //Vector of probabilities associated with bitrate decisions l2AParameterDict[mediaInfo.type].prev_w = []; //Vector of probabilities associated with bitrate decisions calculated in the previous step l2AParameterDict[mediaInfo.type].Q = 0; //Initialization of Lagrangian multiplier (This keeps track of the buffer displacement) l2AParameterDict[mediaInfo.type].segment_request_start_s = 0; l2AParameterDict[mediaInfo.type].segment_download_finish_s = 0; l2AParameterDict[mediaInfo.type].B_target = 1.5; //Target buffer level } /** * Clears the state object * @param {object} l2AState * @private */ function _clearL2AStateOnSeek(l2AState) { l2AState.placeholderBuffer = 0; l2AState.mostAdvancedSegmentStart = NaN; l2AState.lastSegmentWasReplacement = false; l2AState.lastSegmentStart = NaN; l2AState.lastSegmentDurationS = NaN; l2AState.lastSegmentRequestTimeMs = NaN; l2AState.lastSegmentFinishTimeMs = NaN; } /** * Returns the state object for a fiven media type. If the state object is not yet defined _getInitialL2AState is called * @param {object} rulesContext * @return {object} l2AState * @private */ function _getL2AState(rulesContext) { const mediaType = rulesContext.getMediaType(); let l2AState = l2AStateDict[mediaType]; if (!l2AState) { l2AState = _getInitialL2AState(rulesContext); l2AStateDict[mediaType] = l2AState; } return l2AState; } /** * Event handler for the seeking event. * @private */ function _onPlaybackSeeking() { for (const mediaType in l2AStateDict) { if (l2AStateDict.hasOwnProperty(mediaType)) { const l2aState = l2AStateDict[mediaType]; if (l2aState.state !== L2A_STATE_ONE_BITRATE) { l2aState.state = L2A_STATE_STARTUP; _clearL2AStateOnSeek(l2aState); } } } } /** * Event handler for the mediaFragmentLoaded event * @param {object} e * @private */ function _onMediaFragmentLoaded(e) { if (e &amp;&amp; e.chunk &amp;&amp; e.chunk.mediaInfo) { const l2AState = l2AStateDict[e.chunk.mediaInfo.type]; const l2AParameters = l2AParameterDict[e.chunk.mediaInfo.type]; if (l2AState &amp;&amp; l2AState.state !== L2A_STATE_ONE_BITRATE) { const start = e.chunk.start; if (isNaN(l2AState.mostAdvancedSegmentStart) || start &gt; l2AState.mostAdvancedSegmentStart) { l2AState.mostAdvancedSegmentStart = start; l2AState.lastSegmentWasReplacement = false; } else { l2AState.lastSegmentWasReplacement = true; } l2AState.lastSegmentStart = start; l2AState.lastSegmentDurationS = e.chunk.duration; l2AState.lastQuality = e.chunk.quality; _checkNewSegment(l2AState, l2AParameters); } } } /** * Event handler for the metricAdded event * @param {object} e * @private */ function _onMetricAdded(e) { if (e &amp;&amp; e.metric === MetricsConstants.HTTP_REQUEST &amp;&amp; e.value &amp;&amp; e.value.type === HTTPRequest.MEDIA_SEGMENT_TYPE &amp;&amp; e.value.trace &amp;&amp; e.value.trace.length) { const l2AState = l2AStateDict[e.mediaType]; const l2AParameters = l2AParameterDict[e.mediaType]; if (l2AState &amp;&amp; l2AState.state !== L2A_STATE_ONE_BITRATE) { l2AState.lastSegmentRequestTimeMs = e.value.trequest.getTime(); l2AState.lastSegmentFinishTimeMs = e.value._tfinish.getTime(); _checkNewSegment(l2AState, l2AParameters); } } } /** * When a new metric has been added or a media fragment has been loaded the state is adjusted accordingly * @param {object} L2AState * @param {object} l2AParameters * @private */ function _checkNewSegment(L2AState, l2AParameters) { if (!isNaN(L2AState.lastSegmentStart) &amp;&amp; !isNaN(L2AState.lastSegmentRequestTimeMs)) { l2AParameters.segment_request_start_s = 0.001 * L2AState.lastSegmentRequestTimeMs; l2AParameters.segment_download_finish_s = 0.001 * L2AState.lastSegmentFinishTimeMs; L2AState.lastSegmentStart = NaN; L2AState.lastSegmentRequestTimeMs = NaN; } } /** * Event handler for the qualityChangeRequested event * @param {object} e * @private */ function _onQualityChangeRequested(e) { // Useful to store change requests when abandoning a download. if (e &amp;&amp; e.mediaType) { const L2AState = l2AStateDict[e.mediaType]; if (L2AState &amp;&amp; L2AState.state !== L2A_STATE_ONE_BITRATE) { L2AState.abrQuality = e.newQuality; } } } /** * Dot multiplication of two arrays * @param {array} arr1 * @param {array} arr2 * @return {number} sumdot * @private */ function _dotmultiplication(arr1, arr2) { if (arr1.length !== arr2.length) { return -1; } let sumdot = 0; for (let i = 0; i &lt; arr1.length; i++) { sumdot = sumdot + arr1[i] * arr2[i]; } return sumdot; } /** * Project an n-dim vector y to the simplex Dn * Dn = { x : x n-dim, 1 &gt;= x &gt;= 0, sum(x) = 1} * Algorithm is explained at http://arxiv.org/abs/1101.6081 * @param {array} arr * @return {array} */ function euclideanProjection(arr) { const m = arr.length; let bget = false; let arr2 = []; for (let ii = 0; ii &lt; m; ++ii) { arr2[ii] = arr[ii]; } let s = arr.sort(function (a, b) { return b - a; }); let tmpsum = 0; let tmax = 0; let x = []; for (let ii = 0; ii &lt; m - 1; ++ii) { tmpsum = tmpsum + s[ii]; tmax = (tmpsum - 1) / (ii + 1); if (tmax &gt;= s[ii + 1]) { bget = true; break; } } if (!bget) { tmax = (tmpsum + s[m - 1] - 1) / m; } for (let ii = 0; ii &lt; m; ++ii) { x[ii] = Math.max(arr2[ii] - tmax, 0); } return x; } /** * Returns a switch request object indicating which quality is to be played * @param {object} rulesContext * @return {object} */ function getMaxIndex(rulesContext) { const switchRequest = SwitchRequest(context).create(); const horizon = 4; // Optimization horizon (The amount of steps required to achieve convergence) const vl = Math.pow(horizon, 0.99);// Cautiousness parameter, used to control aggressiveness of the bitrate decision process. const alpha = Math.max(Math.pow(horizon, 1), vl * Math.sqrt(horizon));// Step size, used for gradient descent exploration granularity const mediaInfo = rulesContext.getMediaInfo(); const mediaType = rulesContext.getMediaType(); const bitrates = mediaInfo.bitrateList.map(b =&gt; b.bandwidth); const bitrateCount = bitrates.length; const scheduleController = rulesContext.getScheduleController(); const streamInfo = rulesContext.getStreamInfo(); const abrController = rulesContext.getAbrController(); const throughputHistory = abrController.getThroughputHistory(); const isDynamic = streamInfo &amp;&amp; streamInfo.manifestInfo &amp;&amp; streamInfo.manifestInfo.isDynamic; const useL2AABR = rulesContext.useL2AABR(); const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType, true); const safeThroughput = throughputHistory.getSafeAverageThroughput(mediaType, isDynamic); const throughput = throughputHistory.getAverageThroughput(mediaType, isDynamic); // In kbits/s const react = 2; // Reactiveness to volatility (abrupt throughput drops), used to re-calibrate Lagrangian multiplier Q const latency = throughputHistory.getAverageLatency(mediaType); const videoModel = rulesContext.getVideoModel(); let quality; let currentPlaybackRate = videoModel.getPlaybackRate(); if (!rulesContext || !rulesContext.hasOwnProperty('getMediaInfo') || !rulesContext.hasOwnProperty('getMediaType') || !rulesContext.hasOwnProperty('getScheduleController') || !rulesContext.hasOwnProperty('getStreamInfo') || !rulesContext.hasOwnProperty('getAbrController') || !rulesContext.hasOwnProperty('useL2AABR')) { return switchRequest; } switchRequest.reason = switchRequest.reason || {}; if ((!useL2AABR) || (mediaType === Constants.AUDIO)) {// L2A decides bitrate only for video. Audio to be included in decision process in a later stage return switchRequest; } scheduleController.setTimeToLoadDelay(0); const l2AState = _getL2AState(rulesContext); if (l2AState.state === L2A_STATE_ONE_BITRATE) { // shouldn't even have been called return switchRequest; } const l2AParameter = l2AParameterDict[mediaType]; if (!l2AParameter) { return switchRequest; } switchRequest.reason.state = l2AState.state; switchRequest.reason.throughput = throughput; switchRequest.reason.latency = latency; if (isNaN(throughput)) { // still starting up - not enough information return switchRequest; } switch (l2AState.state) { case L2A_STATE_STARTUP: quality = abrController.getQualityForBitrate(mediaInfo, safeThroughput, streamInfo.id, latency);//During strat-up phase abr.controller is responsible for bitrate decisions. switchRequest.quality = quality; switchRequest.reason.throughput = safeThroughput; l2AState.lastQuality = quality; if (!isNaN(l2AState.lastSegmentDurationS) &amp;&amp; bufferLevel &gt;= l2AParameter.B_target) { l2AState.state = L2A_STATE_STEADY; l2AParameter.Q = vl;// Initialization of Q langrangian multiplier // Update of probability vector w, to be used in main adaptation logic of L2A below (steady state) for (let i = 0; i &lt; bitrateCount; ++i) { if (i === l2AState.lastQuality) { l2AParameter.prev_w[i] = 1; } else { l2AParameter.prev_w[i] = 0; } } } break; // L2A_STATE_STARTUP case L2A_STATE_STEADY: let diff1 = [];//Used to calculate the difference between consecutive decisions (w-w_prev) // Manual calculation of latency and throughput during previous request let throughputMeasureTime = dashMetrics.getCurrentHttpRequest(mediaType).trace.reduce((a, b) =&gt; a + b.d, 0); const downloadBytes = dashMetrics.getCurrentHttpRequest(mediaType).trace.reduce((a, b) =&gt; a + b.b[0], 0); let lastthroughput = Math.round((8 * downloadBytes) / throughputMeasureTime); // bits/ms = kbits/s if (lastthroughput &lt; 1) { lastthroughput = 1; }//To avoid division with 0 (avoid infinity) in case of an absolute network outage let V = l2AState.lastSegmentDurationS; let sign = 1; //Main adaptation logic of L2A-LL for (let i = 0; i &lt; bitrateCount; ++i) { bitrates[i] = bitrates[i] / 1000; // Originally in bps, now in Kbps if (currentPlaybackRate * bitrates[i] &gt; lastthroughput) {// In this case buffer would deplete, leading to a stall, which increases latency and thus the particular probability of selsection of bitrate[i] should be decreased. sign = -1; } // The objective of L2A is to minimize the overall latency=request-response time + buffer length after download+ potential stalling (if buffer less than chunk downlad time) l2AParameter.w[i] = l2AParameter.prev_w[i] + sign * (V / (2 * alpha)) * ((l2AParameter.Q + vl) * (currentPlaybackRate * bitrates[i] / lastthroughput));//Lagrangian descent } // Apply euclidean projection on w to ensure w expresses a probability distribution l2AParameter.w = euclideanProjection(l2AParameter.w); for (let i = 0; i &lt; bitrateCount; ++i) { diff1[i] = l2AParameter.w[i] - l2AParameter.prev_w[i]; l2AParameter.prev_w[i] = l2AParameter.w[i]; } // Lagrangian multiplier Q calculation: l2AParameter.Q = Math.max(0, l2AParameter.Q - V + V * currentPlaybackRate * ((_dotmultiplication(bitrates, l2AParameter.prev_w) + _dotmultiplication(bitrates, diff1)) / lastthroughput)); // Quality is calculated as argmin of the absolute difference between available bitrates (bitrates[i]) and bitrate estimation (dotmultiplication(w,bitrates)). let temp = []; for (let i = 0; i &lt; bitrateCount; ++i) { temp[i] = Math.abs(bitrates[i] - _dotmultiplication(l2AParameter.w, bitrates)); } // Quality is calculated based on the probability distribution w (the output of L2A) quality = temp.indexOf(Math.min(...temp)); // We employ a cautious -stepwise- ascent if (quality &gt; l2AState.lastQuality) { if (bitrates[l2AState.lastQuality + 1] &lt;= lastthroughput) { quality = l2AState.lastQuality + 1; } } // Provision against bitrate over-estimation, by re-calibrating the Lagrangian multiplier Q, to be taken into account for the next chunk if (bitrates[quality] &gt;= lastthroughput) { l2AParameter.Q = react * Math.max(vl, l2AParameter.Q); } switchRequest.quality = quality; switchRequest.reason.throughput = throughput; switchRequest.reason.latency = latency; switchRequest.reason.bufferLevel = bufferLevel; l2AState.lastQuality = switchRequest.quality; break; default: // should not arrive here, try to recover logger.debug('L2A ABR rule invoked in bad state.'); switchRequest.quality = abrController.getQualityForBitrate(mediaInfo, safeThroughput, streamInfo.id, latency); switchRequest.reason.state = l2AState.state; switchRequest.reason.throughput = safeThroughput; switchRequest.reason.latency = latency; l2AState.state = L2A_STATE_STARTUP; _clearL2AStateOnSeek(l2AState); } return switchRequest; } /** * Reset objects to their initial state * @private */ function _resetInitialSettings() { l2AStateDict = {}; l2AParameterDict = {}; } /** * Reset the rule */ function reset() { _resetInitialSettings(); eventBus.off(Events.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.off(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, instance); eventBus.off(Events.METRIC_ADDED, _onMetricAdded, instance); eventBus.off(Events.QUALITY_CHANGE_REQUESTED, _onQualityChangeRequested, instance); } instance = { getMaxIndex: getMaxIndex, reset: reset }; setup(); return instance; } L2ARule.__dashjs_factory_name = 'L2ARule'; export default FactoryMaker.getClassFactory(L2ARule); × Search results Close "},"streaming_rules_abr_lolp_LearningAbrController.js.html":{"id":"streaming_rules_abr_lolp_LearningAbrController.js.html","title":"Source: streaming/rules/abr/lolp/LearningAbrController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/rules/abr/lolp/LearningAbrController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Authors: * Abdelhak Bentaleb | National University of Singapore | bentaleb@comp.nus.edu.sg * Mehmet N. Akcay | Ozyegin University | necmettin.akcay@ozu.edu.tr * May Lim | National University of Singapore | maylim@comp.nus.edu.sg */ import FactoryMaker from '../../../../core/FactoryMaker'; import Debug from '../../../../core/Debug'; const WEIGHT_SELECTION_MODES = { MANUAL: 'manual_weight_selection', RANDOM: 'random_weight_selection', DYNAMIC: 'dynamic_weight_selection' }; function LearningAbrController() { const context = this.context; let instance, logger, somBitrateNeurons, bitrateNormalizationFactor, latencyNormalizationFactor, minBitrate, weights, sortedCenters, weightSelectionMode; /** * Setup the class */ function _setup() { logger = Debug(context).getInstance().getLogger(instance); _resetInitialSettings(); } /** * Reset all values */ function reset() { _resetInitialSettings(); } /** * Reset to initial settings * @private */ function _resetInitialSettings() { somBitrateNeurons = null; bitrateNormalizationFactor = 1; latencyNormalizationFactor = 100; minBitrate = 0; weights = null; sortedCenters = null; weightSelectionMode = WEIGHT_SELECTION_MODES.DYNAMIC; } /** * Returns the maximum throughput * @return {number} * @private */ function _getMaxThroughput() { let maxThroughput = 0; if (somBitrateNeurons) { for (let i = 0; i &lt; somBitrateNeurons.length; i++) { let neuron = somBitrateNeurons[i]; if (neuron.state.throughput &gt; maxThroughput) { maxThroughput = neuron.state.throughput; } } } return maxThroughput; } /** * * @param {array} w * @return {number} * @private */ function _getMagnitude(w) { const magnitude = w.map((x) =&gt; (Math.pow(x, 2))).reduce((sum, now) =&gt; sum + now); return Math.sqrt(magnitude); } /** * * @param {array} a * @param {array} b * @param {array} w * @return {number} * @private */ function _getDistance(a, b, w) { let sum = a .map((x, i) =&gt; (w[i] * (Math.pow(x - b[i], 2)))) // square the difference*w .reduce((sum, now) =&gt; sum + now); // sum let sign = (sum &lt; 0) ? -1 : 1; return sign * Math.sqrt(Math.abs(sum)); } /** * * @param {object} a * @param {object} b * @return {number} * @private */ function _getNeuronDistance(a, b) { let aState = [a.state.throughput, a.state.latency, a.state.rebuffer, a.state.switch]; let bState = [b.state.throughput, b.state.latency, b.state.rebuffer, b.state.switch]; return _getDistance(aState, bState, [1, 1, 1, 1]); } /** * * @param {object} winnerNeuron * @param {array} somElements * @param {array} x * @private */ function _updateNeurons(winnerNeuron, somElements, x) { for (let i = 0; i &lt; somElements.length; i++) { let somNeuron = somElements[i]; let sigma = 0.1; const neuronDistance = _getNeuronDistance(somNeuron, winnerNeuron); let neighbourHood = Math.exp(-1 * Math.pow(neuronDistance, 2) / (2 * Math.pow(sigma, 2))); _updateNeuronState(somNeuron, x, neighbourHood); } } /** * * @param {object} neuron * @param {array} x * @param {object} neighbourHood * @private */ function _updateNeuronState(neuron, x, neighbourHood) { let state = neuron.state; let w = [0.01, 0.01, 0.01, 0.01]; // learning rate state.throughput = state.throughput + (x[0] - state.throughput) * w[0] * neighbourHood; state.latency = state.latency + (x[1] - state.latency) * w[1] * neighbourHood; state.rebuffer = state.rebuffer + (x[2] - state.rebuffer) * w[2] * neighbourHood; state.switch = state.switch + (x[3] - state.switch) * w[3] * neighbourHood; } /** * * @param {object} currentNeuron * @param {number} currentThroughput * @return {object} * @private */ function _getDownShiftNeuron(currentNeuron, currentThroughput) { let maxSuitableBitrate = 0; let result = currentNeuron; if (somBitrateNeurons) { for (let i = 0; i &lt; somBitrateNeurons.length; i++) { let n = somBitrateNeurons[i]; if (n.bitrate &lt; currentNeuron.bitrate &amp;&amp; n.bitrate &gt; maxSuitableBitrate &amp;&amp; currentThroughput &gt; n.bitrate) { // possible downshiftable neuron maxSuitableBitrate = n.bitrate; result = n; } } } return result; } /** * * @param {object} mediaInfo * @param {number} throughput * @param {number} latency * @param {number} bufferSize * @param {number} playbackRate * @param {number} currentQualityIndex * @param {object} dynamicWeightsSelector * @return {null|*} */ function getNextQuality(mediaInfo, throughput, latency, bufferSize, playbackRate, currentQualityIndex, dynamicWeightsSelector) { // For Dynamic Weights Selector let currentLatency = latency; let currentBuffer = bufferSize; let currentThroughput = throughput; let somElements = _getSomBitrateNeurons(mediaInfo); // normalize throughput let throughputNormalized = throughput / bitrateNormalizationFactor; // saturate values higher than 1 if (throughputNormalized &gt; 1) { throughputNormalized = _getMaxThroughput(); } // normalize latency latency = latency / latencyNormalizationFactor; const targetLatency = 0; const targetRebufferLevel = 0; const targetSwitch = 0; // 10K + video encoding is the recommended throughput const throughputDelta = 10000; logger.debug(`getNextQuality called throughput:${throughputNormalized} latency:${latency} bufferSize:${bufferSize} currentQualityIndex:${currentQualityIndex} playbackRate:${playbackRate}`); let currentNeuron = somElements[currentQualityIndex]; let downloadTime = (currentNeuron.bitrate * dynamicWeightsSelector.getSegmentDuration()) / currentThroughput; let rebuffer = Math.max(0, (downloadTime - currentBuffer)); // check buffer for possible stall if (currentBuffer - downloadTime &lt; dynamicWeightsSelector.getMinBuffer()) { logger.debug(`Buffer is low for bitrate= ${currentNeuron.bitrate} downloadTime=${downloadTime} currentBuffer=${currentBuffer} rebuffer=${rebuffer}`); return _getDownShiftNeuron(currentNeuron, currentThroughput).qualityIndex; } switch (weightSelectionMode) { case WEIGHT_SELECTION_MODES.MANUAL: _manualWeightSelection(); break; case WEIGHT_SELECTION_MODES.RANDOM: _randomWeightSelection(somElements); break; case WEIGHT_SELECTION_MODES.DYNAMIC: _dynamicWeightSelection(dynamicWeightsSelector, somElements, currentLatency, currentBuffer, rebuffer, currentThroughput, playbackRate); break; default: _dynamicWeightSelection(dynamicWeightsSelector, somElements, currentLatency, currentBuffer, rebuffer, currentThroughput, playbackRate); } let minDistance = null; let minIndex = null; let winnerNeuron = null; for (let i = 0; i &lt; somElements.length; i++) { let somNeuron = somElements[i]; let somNeuronState = somNeuron.state; let somData = [somNeuronState.throughput, somNeuronState.latency, somNeuronState.rebuffer, somNeuronState.switch]; let distanceWeights = weights.slice(); let nextBuffer = dynamicWeightsSelector.getNextBufferWithBitrate(somNeuron.bitrate, currentBuffer, currentThroughput); let isBufferLow = nextBuffer &lt; dynamicWeightsSelector.getMinBuffer(); if (isBufferLow) { logger.debug(`Buffer is low for bitrate=${somNeuron.bitrate} downloadTime=${downloadTime} currentBuffer=${currentBuffer} nextBuffer=${nextBuffer}`); } // special condition downshift immediately if (somNeuron.bitrate &gt; throughput - throughputDelta || isBufferLow) { if (somNeuron.bitrate !== minBitrate) { // encourage to pick smaller bitrates throughputWeight=100 distanceWeights[0] = 100; } } // calculate the distance with the target let distance = _getDistance(somData, [throughputNormalized, targetLatency, targetRebufferLevel, targetSwitch], distanceWeights); if (minDistance === null || distance &lt; minDistance) { minDistance = distance; minIndex = somNeuron.qualityIndex; winnerNeuron = somNeuron; } } // update current neuron and the neighbourhood with the calculated QoE // will punish current if it is not picked let bitrateSwitch = Math.abs(currentNeuron.bitrate - winnerNeuron.bitrate) / bitrateNormalizationFactor; _updateNeurons(currentNeuron, somElements, [throughputNormalized, latency, rebuffer, bitrateSwitch]); // update bmu and neighbours with targetQoE=1, targetLatency=0 _updateNeurons(winnerNeuron, somElements, [throughputNormalized, targetLatency, targetRebufferLevel, bitrateSwitch]); return minIndex; } /** * Option 1: Manual weights * @private */ function _manualWeightSelection() { let throughputWeight = 0.4; let latencyWeight = 0.4; let bufferWeight = 0.4; let switchWeight = 0.4; weights = [throughputWeight, latencyWeight, bufferWeight, switchWeight]; // throughput, latency, buffer, switch } /** * Option 2: Random (Xavier) weights * @param {array} somElements * @private */ function _randomWeightSelection(somElements) { weights = _getXavierWeights(somElements.length, 4); } /** * Dynamic Weight Selector weights * @param {object} dynamicWeightsSelector * @param {array} somElements * @param {number} currentLatency * @param {number} currentBuffer * @param {number} rebuffer * @param {number} currentThroughput * @param {number} playbackRate * @private */ function _dynamicWeightSelection(dynamicWeightsSelector, somElements, currentLatency, currentBuffer, rebuffer, currentThroughput, playbackRate) { if (!weights) { weights = sortedCenters[sortedCenters.length - 1]; } // Dynamic Weights Selector (step 2/2: find weights) let weightVector = dynamicWeightsSelector.findWeightVector(somElements, currentLatency, currentBuffer, rebuffer, currentThroughput, playbackRate); if (weightVector !== null &amp;&amp; weightVector !== -1) { // null: something went wrong, -1: constraints not met weights = weightVector; } } /** * * @param {number }neuronCount * @param {number }weightCount * @return {array} * @private */ function _getXavierWeights(neuronCount, weightCount) { let W = []; let upperBound = Math.sqrt((2 / neuronCount)); for (let i = 0; i &lt; weightCount; i++) { W.push(Math.random() * upperBound); } weights = W; return weights; } /** * * @param {object} mediaInfo * @return {array} * @private */ function _getSomBitrateNeurons(mediaInfo) { if (!somBitrateNeurons) { somBitrateNeurons = []; const bitrateList = mediaInfo.bitrateList; let bitrateVector = []; minBitrate = bitrateList[0].bandwidth; bitrateList.forEach(element =&gt; { bitrateVector.push(element.bandwidth); if (element.bandwidth &lt; minBitrate) { minBitrate = element.bandwidth; } }); bitrateNormalizationFactor = _getMagnitude(bitrateVector); for (let i = 0; i &lt; bitrateList.length; i++) { let neuron = { qualityIndex: i, bitrate: bitrateList[i].bandwidth, state: { // normalize throughputs throughput: bitrateList[i].bandwidth / bitrateNormalizationFactor, latency: 0, rebuffer: 0, switch: 0 } }; somBitrateNeurons.push(neuron); } sortedCenters = _getInitialKmeansPlusPlusCenters(somBitrateNeurons); } return somBitrateNeurons; } /** * * @param {number} size * @return {array} * @private */ function _getRandomData(size) { let dataArray = []; for (let i = 0; i &lt; size; i++) { let data = [ Math.random() * _getMaxThroughput(), //throughput Math.random(), //latency Math.random(), //buffersize Math.random() //switch ]; dataArray.push(data); } return dataArray; } /** * * @param {array} somElements * @return {array} * @private */ function _getInitialKmeansPlusPlusCenters(somElements) { let centers = []; let randomDataSet = _getRandomData(Math.pow(somElements.length, 2)); centers.push(randomDataSet[0]); let distanceWeights = [1, 1, 1, 1]; for (let k = 1; k &lt; somElements.length; k++) { let nextPoint = null; let maxDistance = null; for (let i = 0; i &lt; randomDataSet.length; i++) { let currentPoint = randomDataSet[i]; let minDistance = null; for (let j = 0; j &lt; centers.length; j++) { let distance = _getDistance(currentPoint, centers[j], distanceWeights); if (minDistance === null || distance &lt; minDistance) { minDistance = distance; } } if (maxDistance === null || minDistance &gt; maxDistance) { nextPoint = currentPoint; maxDistance = minDistance; } } centers.push(nextPoint); } // find the least similar center let maxDistance = null; let leastSimilarIndex = null; for (let i = 0; i &lt; centers.length; i++) { let distance = 0; for (let j = 0; j &lt; centers.length; j++) { if (i === j) continue; distance += _getDistance(centers[i], centers[j], distanceWeights); } if (maxDistance === null || distance &gt; maxDistance) { maxDistance = distance; leastSimilarIndex = i; } } // move centers to sortedCenters let sortedCenters = []; sortedCenters.push(centers[leastSimilarIndex]); centers.splice(leastSimilarIndex, 1); while (centers.length &gt; 0) { let minDistance = null; let minIndex = null; for (let i = 0; i &lt; centers.length; i++) { let distance = _getDistance(sortedCenters[0], centers[i], distanceWeights); if (minDistance === null || distance &lt; minDistance) { minDistance = distance; minIndex = i; } } sortedCenters.push(centers[minIndex]); centers.splice(minIndex, 1); } return sortedCenters; } instance = { getNextQuality, reset }; _setup(); return instance; } LearningAbrController.__dashjs_factory_name = 'LearningAbrController'; export default FactoryMaker.getClassFactory(LearningAbrController); × Search results Close "},"streaming_protection_vo_LicenseRequest.js.html":{"id":"streaming_protection_vo_LicenseRequest.js.html","title":"Source: streaming/protection/vo/LicenseRequest.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/vo/LicenseRequest.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @classdesc Defines a license request * @ignore */ class LicenseRequest { /** * Defines a license request * * @class */ constructor(url, method, responseType, headers, withCredentials, messageType, sessionId, data) { /** * The license request url */ this.url = url; /** * The HTTP method */ this.method = method; /** * The HTTP response type */ this.responseType = responseType; /** * The HTP request headers */ this.headers = headers; /** * Wether request is done using credentials (cross-site cookies) */ this.withCredentials = withCredentials; /** * The license request message type (see https://www.w3.org/TR/encrypted-media/#dom-mediakeymessagetype) */ this.messageType = messageType; /** * The corresponding EME session ID */ this.sessionId = sessionId; /** * The license request data */ this.data = data; } } export default LicenseRequest; × Search results Close "},"streaming_protection_vo_LicenseResponse.js.html":{"id":"streaming_protection_vo_LicenseResponse.js.html","title":"Source: streaming/protection/vo/LicenseResponse.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/vo/LicenseResponse.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @classdesc Defines a license response */ class LicenseResponse { /** * Defines a license request * * @class * @ignore */ constructor(url, headers, data) { /** * The url that was loaded, that can be redirected from original request url */ this.url = url; /** * The HTP response headers */ this.headers = headers; /** * The license response data */ this.data = data; } } export default LicenseResponse; × Search results Close "},"streaming_protection_servers_LicenseServer.js.html":{"id":"streaming_protection_servers_LicenseServer.js.html","title":"Source: streaming/protection/servers/LicenseServer.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/servers/LicenseServer.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Defines the public interface for license server implementations supported * by the player. * * Different license servers have different requirements regarding the methods * used to request DRM licenses. Things like request headers, license response * formats (for both error and success cases) need to be customized for a * specific server implementation * * License servers handle requests for more than just initial license retrieval. * Each API takes a parameter which describes the message type as supported by * the Encrypted Media Extensions. * * @interface */ /** * Returns a new or updated license server URL based on the requirements of the * license server and possibly from information passed in the CDM license message * * @function * @name LicenseServer#getServerURLFromMessage * @param {?string} url the initially established URL (from ProtectionData or initData) * @param {ArrayBuffer} message the CDM message which may be needed to generate the license * requests URL * @param {string} messageType the message type associated with this request. Supported * message types can be found {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}. * @returns {string} the URL to use in license requests */ /** * Returns the HTTP method to be used (i.e. \"GET\", \"POST\", etc.) in * XMLHttpRequest.open(). * * @function * @name LicenseServer#getHTTPMethod * @param {string} messageType the message type associated with this request. Supported * message types can be found {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}. * @returns {string} the HTTP method */ /** * Returns the response type to set for XMLHttpRequest.responseType * * @function * @name LicenseServer#getResponseType * @param {string} keySystemStr the key system string representing the key system * associated with a license request. Multi-DRM license servers may have different * response types depending on the key system. * @param {string} messageType the message type associated with this request. Supported * message types can be found {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}. * @returns {string} the response type */ /** * Parses the license server response for any message intended for * the CDM. * * @function * @name LicenseServer#getLicenseMessage * @param {Object} serverResponse the response as returned in XMLHttpRequest.response * @param {string} keySystemStr the key system string representing the key system * associated with a license request. * @param {string} messageType the message type associated with this request. Supported * message types can be found {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}. * @returns {ArrayBuffer} message that will be sent to the CDM or null if no CDM message * was present in the response. */ /** * Parses the license server response during error conditions and returns a * string to display for debugging purposes * * @function * @name LicenseServer#getErrorResponse * @param {Object} serverResponse the server response * @param {string} messageType the message type associated with this request. Supported * message types can be found {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}. * @returns {string} an error message that indicates the reason for the failure */ × Search results Close "},"core_Logger.js.html":{"id":"core_Logger.js.html","title":"Source: core/Logger.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: core/Logger.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * The an end place to put fragments after they have been fetched. * @interface Logger * @ignore */ /** * This method allows you to send fatal error messages (fatal errors implies playback interruption) to the browser's console. * @param {...*} arguments The message you want to debug. The Arguments object is supported for this method so you can send in comma separated logging items. * @function Logger#fatal */ /** * This method allows you to send error messages to the browser's console. * @param {...*} arguments The message you want to debug. The Arguments object is supported for this method so you can send in comma separated logging items. * @function Logger#error */ /** * This method allows you to send warning messages to the browser's console. * @param {...*} arguments The message you want to debug. The Arguments object is supported for this method so you can send in comma separated logging items. * @function Logger#warning */ /** * This method allows you to send info messages to the browser's console. * @param {...*} arguments The message you want to debug. The Arguments object is supported for this method so you can send in comma separated logging items. * @function Logger#info */ /** * This method allows you to send debug messages to the browser's console. * @param {...*} arguments The message you want to debug. The Arguments object is supported for this method so you can send in comma separated logging items. * @function Logger#debug */ × Search results Close "},"streaming_rules_abr_lolp_LoLpRule.js.html":{"id":"streaming_rules_abr_lolp_LoLpRule.js.html","title":"Source: streaming/rules/abr/lolp/LoLpRule.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/rules/abr/lolp/LoLpRule.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Authors: * Abdelhak Bentaleb | National University of Singapore | bentaleb@comp.nus.edu.sg * Mehmet N. Akcay | Ozyegin University | necmettin.akcay@ozu.edu.tr * May Lim | National University of Singapore | maylim@comp.nus.edu.sg */ import Debug from '../../../../core/Debug'; import FactoryMaker from '../../../../core/FactoryMaker'; import LearningAbrController from './LearningAbrController'; import LoLpQoeEvaluator from './LoLpQoEEvaluator'; import SwitchRequest from '../../SwitchRequest'; import MetricsConstants from '../../../constants/MetricsConstants'; import LoLpWeightSelector from './LoLpWeightSelector'; import Constants from '../../../constants/Constants'; const DWS_TARGET_LATENCY = 1.5; const DWS_BUFFER_MIN = 0.3; function LoLPRule(config) { config = config || {}; let dashMetrics = config.dashMetrics; let context = this.context; let logger, instance, learningController, qoeEvaluator; function _setup() { logger = Debug(context).getInstance().getLogger(instance); learningController = LearningAbrController(context).create(); qoeEvaluator = LoLpQoeEvaluator(context).create(); } function getMaxIndex(rulesContext) { try { let switchRequest = SwitchRequest(context).create(); let mediaType = rulesContext.getMediaInfo().type; let abrController = rulesContext.getAbrController(); const streamInfo = rulesContext.getStreamInfo(); let currentQuality = abrController.getQualityFor(mediaType, streamInfo.id); const mediaInfo = rulesContext.getMediaInfo(); const bufferStateVO = dashMetrics.getCurrentBufferState(mediaType); const scheduleController = rulesContext.getScheduleController(); const currentBufferLevel = dashMetrics.getCurrentBufferLevel(mediaType, true); const isDynamic = streamInfo &amp;&amp; streamInfo.manifestInfo ? streamInfo.manifestInfo.isDynamic : null; const playbackController = scheduleController.getPlaybackController(); let latency = playbackController.getCurrentLiveLatency(); if (!rulesContext.useLoLPABR() || (mediaType === Constants.AUDIO)) { return switchRequest; } if (!latency) { latency = 0; } const playbackRate = playbackController.getPlaybackRate(); const throughputHistory = abrController.getThroughputHistory(); const throughput = throughputHistory.getSafeAverageThroughput(mediaType, isDynamic); logger.debug(`Throughput ${Math.round(throughput)} kbps`); if (isNaN(throughput) || !bufferStateVO) { return switchRequest; } if (abrController.getAbandonmentStateFor(streamInfo.id, mediaType) === MetricsConstants.ABANDON_LOAD) { return switchRequest; } // QoE parameters let bitrateList = mediaInfo.bitrateList; // [{bandwidth: 200000, width: 640, height: 360}, ...] let segmentDuration = rulesContext.getRepresentationInfo().fragmentDuration; let minBitrateKbps = bitrateList[0].bandwidth / 1000.0; // min bitrate level let maxBitrateKbps = bitrateList[bitrateList.length - 1].bandwidth / 1000.0; // max bitrate level for (let i = 0; i &lt; bitrateList.length; i++) { // in case bitrateList is not sorted as expected let b = bitrateList[i].bandwidth / 1000.0; if (b &gt; maxBitrateKbps) maxBitrateKbps = b; else if (b &lt; minBitrateKbps) { minBitrateKbps = b; } } // Learning rule pre-calculations let currentBitrate = bitrateList[currentQuality].bandwidth; let currentBitrateKbps = currentBitrate / 1000.0; let httpRequest = dashMetrics.getCurrentHttpRequest(mediaType, true); let lastFragmentDownloadTime = (httpRequest.tresponse.getTime() - httpRequest.trequest.getTime()) / 1000; let segmentRebufferTime = lastFragmentDownloadTime &gt; segmentDuration ? lastFragmentDownloadTime - segmentDuration : 0; qoeEvaluator.setupPerSegmentQoe(segmentDuration, maxBitrateKbps, minBitrateKbps); qoeEvaluator.logSegmentMetrics(currentBitrateKbps, segmentRebufferTime, latency, playbackRate); /* * Dynamic Weights Selector (step 1/2: initialization) */ let dynamicWeightsSelector = LoLpWeightSelector(context).create({ targetLatency: DWS_TARGET_LATENCY, bufferMin: DWS_BUFFER_MIN, segmentDuration, qoeEvaluator }); /* * Select next quality */ switchRequest.quality = learningController.getNextQuality(mediaInfo, throughput * 1000, latency, currentBufferLevel, playbackRate, currentQuality, dynamicWeightsSelector); switchRequest.reason = { throughput: throughput, latency: latency }; switchRequest.priority = SwitchRequest.PRIORITY.STRONG; scheduleController.setTimeToLoadDelay(0); if (switchRequest.quality !== currentQuality) { console.log('[TgcLearningRule][' + mediaType + '] requesting switch to index: ', switchRequest.quality, 'Average throughput', Math.round(throughput), 'kbps'); } return switchRequest; } catch (e) { throw e; } } /** * Reset objects to their initial state * @private */ function _resetInitialSettings() { learningController.reset(); qoeEvaluator.reset(); } /** * Reset the rule */ function reset() { _resetInitialSettings(); } instance = { getMaxIndex, reset }; _setup(); return instance; } LoLPRule.__dashjs_factory_name = 'LoLPRule'; export default FactoryMaker.getClassFactory(LoLPRule); × Search results Close "},"streaming_rules_abr_lolp_LoLpWeightSelector.js.html":{"id":"streaming_rules_abr_lolp_LoLpWeightSelector.js.html","title":"Source: streaming/rules/abr/lolp/LoLpWeightSelector.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/rules/abr/lolp/LoLpWeightSelector.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Authors: * Abdelhak Bentaleb | National University of Singapore | bentaleb@comp.nus.edu.sg * Mehmet N. Akcay | Ozyegin University | necmettin.akcay@ozu.edu.tr * May Lim | National University of Singapore | maylim@comp.nus.edu.sg */ import FactoryMaker from '../../../../core/FactoryMaker'; function LoLpWeightSelector(config) { let targetLatency = config.targetLatency; let bufferMin = config.bufferMin; let segmentDuration = config.segmentDuration; let qoeEvaluator = config.qoeEvaluator; let instance, valueList, weightTypeCount, weightOptions, previousLatency; /** * * @private */ function _setup() { _resetInitialSettings(); } /** * * @private */ function _resetInitialSettings() { valueList = [0.2, 0.4, 0.6, 0.8, 1]; weightTypeCount = 4; weightOptions = _getPermutations(valueList, weightTypeCount); previousLatency = 0; } /** * Next, at each segment boundary, ABR to input current neurons and target state (only used in Method II) to find the desired weight vector * @param {array} neurons * @param {number} currentLatency * @param {number} currentBuffer * @param {number} currentRebuffer * @param {number} currentThroughput * @param {number} playbackRate * @return {null} * @private */ function findWeightVector(neurons, currentLatency, currentBuffer, currentRebuffer, currentThroughput, playbackRate) { let maxQoE = null; let winnerWeights = null; let winnerBitrate = null; let deltaLatency = Math.abs(currentLatency - previousLatency); // For each neuron, m neurons.forEach((neuron) =&gt; { // For each possible weight vector, z // E.g. For [ throughput, latency, buffer, playbackRate, QoE ] // Possible weightVector = [ 0.2, 0.4, 0.2, 0, 0.2 ] weightOptions.forEach((weightVector) =&gt; { // Apply weightVector to neuron, compute utility and determine winnerWeights // Method I: Utility based on QoE given current state let weightsObj = { throughput: weightVector[0], latency: weightVector[1], buffer: weightVector[2], switch: weightVector[3] }; let downloadTime = (neuron.bitrate * segmentDuration) / currentThroughput; let nextBuffer = getNextBuffer(currentBuffer, downloadTime); let rebuffer = Math.max(0.00001, (downloadTime - nextBuffer)); let wt; if (weightsObj.buffer === 0) { wt = 10; } else { wt = (1 / weightsObj.buffer); } let weightedRebuffer = wt * rebuffer; if (weightsObj.latency === 0) { wt = 10; } else { wt = (1 / weightsObj.latency); // inverse the weight because wt and latency should have positive relationship, i.e., higher latency = higher wt } let weightedLatency = wt * neuron.state.latency; let totalQoE = qoeEvaluator.calculateSingleUseQoe(neuron.bitrate, weightedRebuffer, weightedLatency, playbackRate); if ((maxQoE === null || totalQoE &gt; maxQoE) &amp;&amp; _checkConstraints(currentLatency, nextBuffer, deltaLatency)) { maxQoE = totalQoE; winnerWeights = weightVector; winnerBitrate = neuron.bitrate; } }); }); // winnerWeights was found, check if constraints are satisfied if (winnerWeights === null &amp;&amp; winnerBitrate === null) { winnerWeights = -1; } previousLatency = currentLatency; return winnerWeights; } /** * * @param {number} nextLatency * @param {number} nextBuffer * @param {number} deltaLatency * @return {boolean} * @private */ function _checkConstraints(nextLatency, nextBuffer, deltaLatency) { // A1 // disabled till we find a better way of estimating latency // fails for all with current value if (nextLatency &gt; targetLatency + deltaLatency) { return false; } return nextBuffer &gt;= bufferMin; } /** * * @param {array} list * @param {number} length * @return {*} * @private */ function _getPermutations(list, length) { // Copy initial values as arrays let perm = list.map(function (val) { return [val]; }); // Our permutation generator let generate = function (perm, length, currLen) { // Reached desired length if (currLen === length) { return perm; } // For each existing permutation let len = perm.length; for (let i = 0; i &lt; len; i++) { let currPerm = perm.shift(); // Create new permutation for (let k = 0; k &lt; list.length; k++) { perm.push(currPerm.concat(list[k])); } } // Recurse return generate(perm, length, currLen + 1); }; // Start with size 1 because of initial values return generate(perm, length, 1); } /** * * @return {number} */ function getMinBuffer() { return bufferMin; } /** * * @return {number} */ function getSegmentDuration() { return segmentDuration; } /** * * @param {number} bitrateToDownload * @param {number} currentBuffer * @param {number} currentThroughput * @return {number} */ function getNextBufferWithBitrate(bitrateToDownload, currentBuffer, currentThroughput) { let downloadTime = (bitrateToDownload * segmentDuration) / currentThroughput; return getNextBuffer(currentBuffer, downloadTime); } /** * * @param {number} currentBuffer * @param {number} downloadTime * @return {number} */ function getNextBuffer(currentBuffer, downloadTime) { const segmentDuration = getSegmentDuration(); let nextBuffer; if (downloadTime &gt; segmentDuration) { nextBuffer = currentBuffer - segmentDuration; } else { nextBuffer = currentBuffer + segmentDuration - downloadTime; } return nextBuffer; } instance = { getMinBuffer, getSegmentDuration, getNextBufferWithBitrate, getNextBuffer, findWeightVector }; _setup(); return instance; } LoLpWeightSelector.__dashjs_factory_name = 'LoLpWeightSelector'; export default FactoryMaker.getClassFactory(LoLpWeightSelector); × Search results Close "},"streaming_models_LowLatencyThroughputModel.js.html":{"id":"streaming_models_LowLatencyThroughputModel.js.html","title":"Source: streaming/models/LowLatencyThroughputModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/models/LowLatencyThroughputModel.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Debug from '../../core/Debug'; import FactoryMaker from '../../core/FactoryMaker'; function LowLatencyThroughputModel() { const LLTM_MAX_MEASUREMENTS = 10; // factor (&lt;1) is used to reduce the real needed download time when at very bleeding live edge const LLTM_SEMI_OPTIMISTIC_ESTIMATE_FACTOR = 0.8; const LLTM_OPTIMISTIC_ESTIMATE_FACTOR = 0.6; const LLTM_SLOW_SEGMENT_DOWNLOAD_TOLERANCE = 1.05; const LLTM_MAX_DELAY_MS = 250; const context = this.context; let instance; let logger; let measurements = {}; function setup() { logger = Debug(context).getInstance().getLogger(instance); } /** * Linear regression with least squares method to get a trend function for buffer lavel at chunk receive timestamps * @param {*} chunkMeasurements * @returns linear trend function */ function createBufferLevelTrendFunction(chunkMeasurements) { const result = {}; let sumX = 0 let sumY = 0 let sumXY = 0 let sumXSq = 0 const N = chunkMeasurements.length for (var i = 0; i &lt; N; ++i) { sumX += chunkMeasurements[i].chunkDownloadTimeRelativeMS; sumY += chunkMeasurements[i].bufferLevel; sumXY += chunkMeasurements[i].chunkDownloadTimeRelativeMS * chunkMeasurements[i].bufferLevel; sumXSq += chunkMeasurements[i].chunkDownloadTimeRelativeMS * chunkMeasurements[i].chunkDownloadTimeRelativeMS } result.m = ((sumXY - sumX * sumY / N)) / (sumXSq - sumX * sumX / N) result.b = sumY / N - result.m * sumX / N return function (x) { return result.m * x + result.b } } function isBufferSafeAndStable(lastMeasurements) { let isBufferSafeAndStable = true; let lastBitrate; const aveBufferLevelLastSegements = lastMeasurements.reduce((prev, curr) =&gt; prev + curr.bufferLevelAtSegmentEnd, 0) / lastMeasurements.length; lastMeasurements.forEach(m =&gt; { // inner segment buffer stability if (Math.abs(m.bufferLevelAtSegmentEnd / m.bufferLevelAtSegmentStart) &lt; 0.95) { isBufferSafeAndStable = false; } // inter segment buffer stability if (m.bufferLevelAtSegmentEnd / aveBufferLevelLastSegements &lt; 0.8) { isBufferSafeAndStable = false; } // representation bitrate remained at least constant if (!lastBitrate) { lastBitrate = m.bitrate; } else if (lastBitrate &gt; m.bitrate) { isBufferSafeAndStable = false; } }); return isBufferSafeAndStable; } /** * Based on the MPD, timing and buffer information of the last recent segments and their chunks * the most stable download time (in milliseconds) is calculated. * @param {*} request HTTPLoader request object * @returns download time in milliseconds of last fetched segment */ function getEstimatedDownloadDurationMS(request) { const lastMeasurement = measurements[request.mediaType].slice(-1).pop(); const lastThreeMeasurements = measurements[request.mediaType].slice(-3) // calculate and remember the buffer level trend during the last fetched segment const lastChunkRelativeTimeMS = lastMeasurement.chunkMeasurements.slice(-1).pop().chunkDownloadTimeRelativeMS; lastMeasurement.bufferLevelAtSegmentStart = lastMeasurement.getEstimatedBufferLevel(lastChunkRelativeTimeMS / 2); lastMeasurement.bufferLevelAtSegmentEnd = lastMeasurement.getEstimatedBufferLevel(lastChunkRelativeTimeMS); const isBufferStable = isBufferSafeAndStable(lastThreeMeasurements); const selectedOptimisticFactor = isBufferStable ? LLTM_OPTIMISTIC_ESTIMATE_FACTOR : LLTM_SEMI_OPTIMISTIC_ESTIMATE_FACTOR; // fetch duration was longer than segment duration, but buffer was stable if (lastMeasurement.isBufferStable &amp;&amp; lastMeasurement.segDurationMS * LLTM_SLOW_SEGMENT_DOWNLOAD_TOLERANCE &lt; lastMeasurement.fetchDownloadDurationMS) { return lastMeasurement.fetchDownloadDurationMS; } // buffer is drying or fetch took too long if (!isBufferStable || lastMeasurement.segDurationMS &lt; lastMeasurement.fetchDownloadDurationMS) { return lastMeasurement.fetchDownloadDurationMS * LLTM_SEMI_OPTIMISTIC_ESTIMATE_FACTOR; } // did we requested a fully available segment? -&gt; most accurate throughput calculation // we use adjusted availability start time to decide // Note: this \"download mode\" usually happens at startup and if requests are delayed artificially if (lastMeasurement.adjustedAvailabilityStartTimeMS &lt;= (lastMeasurement.requestTimeMS + lastMeasurement.throughputCapacityDelayMS) - lastMeasurement.segDurationMS) { return lastMeasurement.fetchDownloadDurationMS * LLTM_SEMI_OPTIMISTIC_ESTIMATE_FACTOR; } // get all chunks that have been downloaded before fetch reached bleeding live edge // the remaining chunks loaded at production rate we will approximated const chunkAvailablePeriod = (lastMeasurement.requestTimeMS + lastMeasurement.throughputCapacityDelayMS) - lastMeasurement.adjustedAvailabilityStartTimeMS; let chunkBytesBBLE = 0; // BBLE -&gt; Before bleeding live edge let chunkDownloadtimeMSBBLE = 0; let chunkCount = 0; for (let index = 0; index &lt; lastMeasurement.chunkMeasurements.length; index++) { const chunk = lastMeasurement.chunkMeasurements[index]; if (chunkAvailablePeriod &lt; chunkDownloadtimeMSBBLE + chunk.chunkDownloadDurationMS) { break; } chunkDownloadtimeMSBBLE += chunk.chunkDownloadDurationMS; chunkBytesBBLE += chunk.chunkBytes; chunkCount++; } if (chunkAvailablePeriod &lt; 0) { logger.warn('request time was before adjusted availibitly start time'); } // there have to be some chunks available (20% of max count) // otherwise we are at bleeding live edge and the few chunks are insufficient to estimate correctly if (chunkBytesBBLE &amp;&amp; chunkDownloadtimeMSBBLE &amp;&amp; chunkCount &gt; lastMeasurement.chunkMeasurements.length * 0.2) { const downloadThroughput = chunkBytesBBLE / chunkDownloadtimeMSBBLE; // bytes per millesecond const estimatedDownloadtimeMS = lastMeasurement.segmentBytes / downloadThroughput; // if real download was shorter then report this incl. semi optimistical estimate factor if (lastMeasurement.fetchDownloadDurationMS &lt; estimatedDownloadtimeMS) { return lastMeasurement.fetchDownloadDurationMS * selectedOptimisticFactor; } return estimatedDownloadtimeMS * selectedOptimisticFactor; } // when we are to tight at live edge and it's stable then // we start to optimistically estimate download time // in such a way that a switch to next rep will be possible // optimistical estimate: assume download was fast enough for next higher rendition let nextHigherBitrate = lastMeasurement.bitrate; lastMeasurement.bitrateList.some(b =&gt; { if (b.bandwidth &gt; lastMeasurement.bitrate) { nextHigherBitrate = b.bandwidth; return true; } }); // already highest bitrate? if (nextHigherBitrate === lastMeasurement.bitrate) { return lastMeasurement.fetchDownloadDurationMS * selectedOptimisticFactor; } return selectedOptimisticFactor * lastMeasurement.segmentBytes * 8 * 1000 / nextHigherBitrate; } /** * Get calculated value for a safe artificial delay of the next request to allow to accumulate some chunks. * This allows better line throughput measurement. * @param {*} request * @param {*} currentBufferLevel current buffer level in milliseconds * @returns delay in milliseconds */ function getThroughputCapacityDelayMS(request, currentBufferLevelMS) { const lastThreeMeasurements = measurements[request.mediaType] &amp;&amp; measurements[request.mediaType].slice(-3); if (!lastThreeMeasurements || lastThreeMeasurements.length &lt; 3) { return 0; } // in case not stable buffer, no artificially delay for the next request if (!isBufferSafeAndStable(lastThreeMeasurements)) { return 0; } // allowed artificial delay is the min of quater of buffer level in milliseconds and LLTM_MAX_DELAY_MS return currentBufferLevelMS / 4 &gt; LLTM_MAX_DELAY_MS ? LLTM_MAX_DELAY_MS : currentBufferLevelMS / 4; } /** * Add some measurement data for bookkeeping and being able to derive decisions on estimated throughput. * @param {*} request HTTPLoader object to get MPD and media info from * @param {*} fetchDownloadDurationMS Duration how long the fetch actually took * @param {*} chunkMeasurements Array containing chunk timings and buffer levels * @param {*} requestTimeMS Timestamp at which the fetch was initiated * @param {*} throughputCapacityDelayMS An artificial delay that was used for this request */ function addMeasurement(request, fetchDownloadDurationMS, chunkMeasurements, requestTimeMS, throughputCapacityDelayMS) { if (request &amp;&amp; request.mediaType &amp;&amp; !measurements[request.mediaType]) { measurements[request.mediaType] = []; } const bitrateEntry = request.mediaInfo.bitrateList.find(item =&gt; item.id === request.representationId); measurements[request.mediaType].push({ index: request.index, repId: request.representationId, mediaType: request.mediaType, requestTimeMS, adjustedAvailabilityStartTimeMS: request.availabilityStartTime.getTime(), segDurationMS: request.duration * 1000, chunksDurationMS: chunkMeasurements.reduce((prev, curr) =&gt; prev + curr.chunkDownloadDurationMS, 0), segmentBytes: chunkMeasurements.reduce((prev, curr) =&gt; prev + curr.chunkBytes, 0), bitrate: bitrateEntry &amp;&amp; bitrateEntry.bandwidth, bitrateList: request.mediaInfo.bitrateList, chunkMeasurements, fetchDownloadDurationMS, throughputCapacityDelayMS, getEstimatedBufferLevel: createBufferLevelTrendFunction(chunkMeasurements.slice(1)) // don't use first chunk's buffer level }); // maintain only a maximum amount of most recent measurements if (measurements[request.mediaType].length &gt; LLTM_MAX_MEASUREMENTS) { measurements[request.mediaType].shift(); } } instance = { setup, addMeasurement, getThroughputCapacityDelayMS, getEstimatedDownloadDurationMS }; setup() return instance; } LowLatencyThroughputModel.__dashjs_factory_name = 'LowLatencyThroughputModel'; export default FactoryMaker.getSingletonFactory(LowLatencyThroughputModel); × Search results Close "},"streaming_vo_metrics_ManifestUpdate.js.html":{"id":"streaming_vo_metrics_ManifestUpdate.js.html","title":"Source: streaming/vo/metrics/ManifestUpdate.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/ManifestUpdate.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @classdesc This Object holds reference to the manifest update information. * @ignore */ class ManifestUpdate { /** * @class */ constructor() { /** * Media Type Video | Audio | FragmentedText * @public */ this.mediaType = null; /** * MPD Type static | dynamic * @public */ this.type = null; /** * When this manifest update was requested * @public */ this.requestTime = null; /** * When this manifest update was received * @public */ this.fetchTime = null; /** * Calculated Availability Start time of the stream. * @public */ this.availabilityStartTime = null; /** * the seek point (liveEdge for dynamic, Stream[0].startTime for static) * @public */ this.presentationStartTime = 0; /** * The calculated difference between the server and client wall clock time * @public */ this.clientTimeOffset = 0; /** * Actual element.currentTime * @public */ this.currentTime = null; /** * Actual element.ranges * @public */ this.buffered = null; /** * Static is fixed value of zero. dynamic should be ((Now-@availabilityStartTime) - elementCurrentTime) * @public */ this.latency = 0; /** * Array holding list of StreamInfo VO Objects * @public */ this.streamInfo = []; /** * Array holding list of RepresentationInfo VO Objects * @public */ this.representationInfo = []; } } /** * @classdesc This Object holds reference to the current period's stream information when the manifest was updated. * @ignore */ class ManifestUpdateStreamInfo { /** * @class */ constructor() { /** * Stream@id * @public */ this.id = null; /** * Period Index * @public */ this.index = null; /** * Stream@start * @public */ this.start = null; /** * Stream@duration * @public */ this.duration = null; } } /** * @classdesc This Object holds reference to the current representation's info when the manifest was updated. * @ignore */ class ManifestUpdateRepresentationInfo { /** * @class */ constructor() { /** * Track@id * @public */ this.id = null; /** * Representation Index * @public */ this.index = null; /** * Media Type Video | Audio | FragmentedText * @public */ this.mediaType = null; /** * Which representation * @public */ this.streamIndex = null; /** * Holds reference to @presentationTimeOffset * @public */ this.presentationTimeOffset = null; /** * Holds reference to @startNumber * @public */ this.startNumber = null; /** * list|template|timeline * @public */ this.fragmentInfoType = null; } } export { ManifestUpdate, ManifestUpdateStreamInfo, ManifestUpdateRepresentationInfo }; × Search results Close "},"streaming_controllers_MediaController.js.html":{"id":"streaming_controllers_MediaController.js.html","title":"Source: streaming/controllers/MediaController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/MediaController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../constants/Constants'; import Events from '../../core/events/Events'; import EventBus from '../../core/EventBus'; import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import bcp47Normalize from 'bcp-47-normalize'; import {extendedFilter} from 'bcp-47-match'; function MediaController() { const context = this.context; const eventBus = EventBus(context).getInstance(); let instance, logger, tracks, settings, initialSettings, lastSelectedTracks, customParametersModel, domStorage; function setup() { logger = Debug(context).getInstance().getLogger(instance); reset(); } /** * @param {string} type * @param {StreamInfo} streamInfo * @memberof MediaController# */ function setInitialMediaSettingsForType(type, streamInfo) { let settings = lastSelectedTracks[type] || getInitialSettings(type); const tracksForType = getTracksFor(type, streamInfo.id); const tracks = []; if (!settings) { settings = domStorage.getSavedMediaSettings(type); setInitialSettings(type, settings); } if (!tracksForType || (tracksForType.length === 0)) return; if (settings) { tracksForType.forEach(function (track) { if (matchSettings(settings, track, !!lastSelectedTracks[type])) { tracks.push(track); } }); } if (tracks.length === 0) { setTrack(selectInitialTrack(type, tracksForType), true); } else { if (tracks.length &gt; 1) { setTrack(selectInitialTrack(type, tracks, !!lastSelectedTracks[type])); } else { setTrack(tracks[0]); } } } /** * @param {MediaInfo} track * @memberof MediaController# */ function addTrack(track) { if (!track) return; const mediaType = track.type; if (!_isMultiTrackSupportedByType(mediaType)) return; let streamId = track.streamInfo.id; if (!tracks[streamId]) { tracks[streamId] = createTrackInfo(); } const mediaTracks = tracks[streamId][mediaType].list; for (let i = 0, len = mediaTracks.length; i &lt; len; ++i) { //track is already set. if (isTracksEqual(mediaTracks[i], track)) { return; } } mediaTracks.push(track); } /** * @param {string} type * @param {string} streamId * @returns {Array} * @memberof MediaController# */ function getTracksFor(type, streamId) { if (!type) return []; if (!tracks[streamId] || !tracks[streamId][type]) return []; return tracks[streamId][type].list; } /** * @param {string} type * @param {string} streamId * @returns {Object|null} * @memberof MediaController# */ function getCurrentTrackFor(type, streamId) { if (!type || !tracks[streamId] || !tracks[streamId][type]) return null; return tracks[streamId][type].current; } /** * @param {MediaInfo} track * @returns {boolean} * @memberof MediaController# */ function isCurrentTrack(track) { if (!track) { return false; } const type = track.type; const id = track.streamInfo.id; return (tracks[id] &amp;&amp; tracks[id][type] &amp;&amp; isTracksEqual(tracks[id][type].current, track)); } /** * @param {MediaInfo} track * @param {boolean} noSettingsSave specify if settings must be not be saved * @memberof MediaController# */ function setTrack(track, noSettingsSave = false) { if (!track || !track.streamInfo) return; const type = track.type; const streamInfo = track.streamInfo; const id = streamInfo.id; const current = getCurrentTrackFor(type, id); if (!tracks[id] || !tracks[id][type]) return; tracks[id][type].current = track; if (tracks[id][type].current &amp;&amp; ((type !== Constants.TEXT &amp;&amp; !isTracksEqual(track, current)) || (type === Constants.TEXT &amp;&amp; track.isFragmented))) { eventBus.trigger(Events.CURRENT_TRACK_CHANGED, { oldMediaInfo: current, newMediaInfo: track, switchMode: settings.get().streaming.trackSwitchMode[type] }, { streamId: id }); } if (!noSettingsSave) { let settings = extractSettings(track); if (!settings || !tracks[id][type].storeLastSettings) return; if (settings.roles) { settings.role = settings.roles[0]; delete settings.roles; } if (settings.accessibility) { settings.accessibility = settings.accessibility[0]; } if (settings.audioChannelConfiguration) { settings.audioChannelConfiguration = settings.audioChannelConfiguration[0]; } lastSelectedTracks[type] = settings; domStorage.setSavedMediaSettings(type, settings); } } /** * @param {string} type * @param {Object} value * @memberof MediaController# */ function setInitialSettings(type, value) { if (!type || !value) return; initialSettings[type] = value; } /** * @param {string} type * @returns {Object|null} * @memberof MediaController# */ function getInitialSettings(type) { if (!type) return null; return initialSettings[type]; } /** * @memberof MediaController# */ function saveTextSettingsDisabled() { domStorage.setSavedMediaSettings(Constants.TEXT, null); } /** * @param {string} type * @returns {boolean} * @memberof MediaController# */ function _isMultiTrackSupportedByType(type) { return (type === Constants.AUDIO || type === Constants.VIDEO || type === Constants.TEXT || type === Constants.IMAGE); } /** * @param {MediaInfo} t1 - first track to compare * @param {MediaInfo} t2 - second track to compare * @returns {boolean} * @memberof MediaController# */ function isTracksEqual(t1, t2) { if (!t1 &amp;&amp; !t2) { return true; } if (!t1 || !t2) { return false; } const sameId = t1.id === t2.id; const sameViewpoint = t1.viewpoint === t2.viewpoint; const sameLang = t1.lang === t2.lang; const sameCodec = t1.codec === t2.codec; const sameRoles = t1.roles.toString() === t2.roles.toString(); const sameAccessibility = t1.accessibility.toString() === t2.accessibility.toString(); const sameAudioChannelConfiguration = t1.audioChannelConfiguration.toString() === t2.audioChannelConfiguration.toString(); return (sameId &amp;&amp; sameCodec &amp;&amp; sameViewpoint &amp;&amp; sameLang &amp;&amp; sameRoles &amp;&amp; sameAccessibility &amp;&amp; sameAudioChannelConfiguration); } function setConfig(config) { if (!config) return; if (config.domStorage) { domStorage = config.domStorage; } if (config.settings) { settings = config.settings; } if (config.customParametersModel) { customParametersModel = config.customParametersModel; } } /** * @memberof MediaController# */ function reset() { tracks = {}; lastSelectedTracks = {}; resetInitialSettings(); } function extractSettings(mediaInfo) { const settings = { lang: mediaInfo.lang, viewpoint: mediaInfo.viewpoint, roles: mediaInfo.roles, accessibility: mediaInfo.accessibility, audioChannelConfiguration: mediaInfo.audioChannelConfiguration }; let notEmpty = settings.lang || settings.viewpoint || (settings.role &amp;&amp; settings.role.length &gt; 0) || (settings.accessibility &amp;&amp; settings.accessibility.length &gt; 0) || (settings.audioChannelConfiguration &amp;&amp; settings.audioChannelConfiguration.length &gt; 0); return notEmpty ? settings : null; } function matchSettings(settings, track, isTrackActive = false) { try { let matchLang = false; // If there is no language defined in the target settings we got a match if (!settings.lang) { matchLang = true; } // If the target language is provided as a RegExp apply match function else if (settings.lang instanceof RegExp) { matchLang = track.lang.match(settings.lang); } // If the track has a language and we can normalize the target language check if we got a match else if (track.lang !== '') { const normalizedSettingsLang = bcp47Normalize(settings.lang); if (normalizedSettingsLang) { matchLang = extendedFilter(track.lang, normalizedSettingsLang).length &gt; 0 } } const matchIndex = (settings.index === undefined) || (settings.index === null) || (track.index === settings.index); const matchViewPoint = !settings.viewpoint || (settings.viewpoint === track.viewpoint); const matchRole = !settings.role || !!track.roles.filter(function (item) { return item === settings.role; })[0]; let matchAccessibility = !settings.accessibility || !!track.accessibility.filter(function (item) { return item === settings.accessibility; })[0]; let matchAudioChannelConfiguration = !settings.audioChannelConfiguration || !!track.audioChannelConfiguration.filter(function (item) { return item === settings.audioChannelConfiguration; })[0]; return (matchLang &amp;&amp; matchIndex &amp;&amp; matchViewPoint &amp;&amp; (matchRole || (track.type === Constants.AUDIO &amp;&amp; isTrackActive)) &amp;&amp; matchAccessibility &amp;&amp; matchAudioChannelConfiguration); } catch (e) { return false; logger.error(e); } } function resetInitialSettings() { initialSettings = { audio: null, video: null, text: null }; } function getTracksWithHighestSelectionPriority(trackArr) { let max = 0; let result = []; trackArr.forEach((track) =&gt; { if (!isNaN(track.selectionPriority)) { // Higher max value. Reset list and add new entry if (track.selectionPriority &gt; max) { max = track.selectionPriority; result = [track]; } // Same max value add to list else if (track.selectionPriority === max) { result.push(track); } } }) return result; } function getTracksWithHighestBitrate(trackArr) { let max = 0; let result = []; let tmp; trackArr.forEach(function (track) { tmp = Math.max.apply(Math, track.bitrateList.map(function (obj) { return obj.bandwidth; })); if (tmp &gt; max) { max = tmp; result = [track]; } else if (tmp === max) { result.push(track); } }); return result; } function getTracksWithHighestEfficiency(trackArr) { let min = Infinity; let result = []; let tmp; trackArr.forEach(function (track) { const sum = track.bitrateList.reduce(function (acc, obj) { const resolution = Math.max(1, obj.width * obj.height); const efficiency = obj.bandwidth / resolution; return acc + efficiency; }, 0); tmp = sum / track.bitrateList.length; if (tmp &lt; min) { min = tmp; result = [track]; } else if (tmp === min) { result.push(track); } }); return result; } function getTracksWithWidestRange(trackArr) { let max = 0; let result = []; let tmp; trackArr.forEach(function (track) { tmp = track.representationCount; if (tmp &gt; max) { max = tmp; result = [track]; } else if (tmp === max) { result.push(track); } }); return result; } function selectInitialTrack(type, tracks) { if (type === Constants.TEXT) return tracks[0]; let mode = settings.get().streaming.selectionModeForInitialTrack; let tmpArr; const customInitialTrackSelectionFunction = customParametersModel.getCustomInitialTrackSelectionFunction(); if (customInitialTrackSelectionFunction &amp;&amp; typeof customInitialTrackSelectionFunction === 'function') { tmpArr = customInitialTrackSelectionFunction(tracks); } else { switch (mode) { case Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY: tmpArr = _trackSelectionModeHighestSelectionPriority(tracks); break; case Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE: tmpArr = _trackSelectionModeHighestBitrate(tracks); break; case Constants.TRACK_SELECTION_MODE_FIRST_TRACK: tmpArr = _trackSelectionModeFirstTrack(tracks); break; case Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY: tmpArr = _trackSelectionModeHighestEfficiency(tracks); break; case Constants.TRACK_SELECTION_MODE_WIDEST_RANGE: tmpArr = _trackSelectionModeWidestRange(tracks); break; default: logger.warn(`Track selection mode ${mode} is not supported. Falling back to TRACK_SELECTION_MODE_FIRST_TRACK`); tmpArr = _trackSelectionModeFirstTrack(tracks); break; } } return tmpArr.length &gt; 0 ? tmpArr[0] : tracks[0]; } function _trackSelectionModeHighestSelectionPriority(tracks) { let tmpArr = getTracksWithHighestSelectionPriority(tracks); if (tmpArr.length &gt; 1) { tmpArr = getTracksWithHighestBitrate(tmpArr); } if (tmpArr.length &gt; 1) { tmpArr = getTracksWithWidestRange(tmpArr); } return tmpArr; } function _trackSelectionModeHighestBitrate(tracks) { let tmpArr = getTracksWithHighestBitrate(tracks); if (tmpArr.length &gt; 1) { tmpArr = getTracksWithWidestRange(tmpArr); } return tmpArr; } function _trackSelectionModeFirstTrack(tracks) { return tracks[0]; } function _trackSelectionModeHighestEfficiency(tracks) { let tmpArr = getTracksWithHighestEfficiency(tracks); if (tmpArr.length &gt; 1) { tmpArr = getTracksWithHighestBitrate(tmpArr); } return tmpArr; } function _trackSelectionModeWidestRange(tracks) { let tmpArr = getTracksWithWidestRange(tracks); if (tmpArr.length &gt; 1) { tmpArr = getTracksWithHighestBitrate(tracks); } return tmpArr; } function createTrackInfo() { return { audio: { list: [], storeLastSettings: true, current: null }, video: { list: [], storeLastSettings: true, current: null }, text: { list: [], storeLastSettings: true, current: null }, image: { list: [], storeLastSettings: true, current: null } }; } instance = { setInitialMediaSettingsForType, addTrack, getTracksFor, getCurrentTrackFor, isCurrentTrack, setTrack, selectInitialTrack, setInitialSettings, getInitialSettings, getTracksWithHighestBitrate, getTracksWithHighestEfficiency, getTracksWithWidestRange, isTracksEqual, matchSettings, saveTextSettingsDisabled, setConfig, reset }; setup(); return instance; } MediaController.__dashjs_factory_name = 'MediaController'; const factory = FactoryMaker.getSingletonFactory(MediaController); FactoryMaker.updateSingletonFactory(MediaController.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_MediaPlayerEvents.js.html":{"id":"streaming_MediaPlayerEvents.js.html","title":"Source: streaming/MediaPlayerEvents.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/MediaPlayerEvents.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import EventsBase from '../core/events/EventsBase'; /** * @class * @implements EventsBase */ class MediaPlayerEvents extends EventsBase { /** * @description Public facing external events to be used when developing a player that implements dash.js. */ constructor() { super(); /** * Triggered when playback will not start yet * as the MPD's availabilityStartTime is in the future. * Check delay property in payload to determine time before playback will start. * @event MediaPlayerEvents#AST_IN_FUTURE */ this.AST_IN_FUTURE = 'astInFuture'; /** * Triggered when the video element's buffer state changes to stalled. * Check mediaType in payload to determine type (Video, Audio, FragmentedText). * @event MediaPlayerEvents#BUFFER_EMPTY */ this.BUFFER_EMPTY = 'bufferStalled'; /** * Triggered when the video element's buffer state changes to loaded. * Check mediaType in payload to determine type (Video, Audio, FragmentedText). * @event MediaPlayerEvents#BUFFER_LOADED */ this.BUFFER_LOADED = 'bufferLoaded'; /** * Triggered when the video element's buffer state changes, either stalled or loaded. Check payload for state. * @event MediaPlayerEvents#BUFFER_LEVEL_STATE_CHANGED */ this.BUFFER_LEVEL_STATE_CHANGED = 'bufferStateChanged'; /** * Triggered when the buffer level of a media type has been updated * @event MediaPlayerEvents#BUFFER_LEVEL_UPDATED */ this.BUFFER_LEVEL_UPDATED = 'bufferLevelUpdated'; /** * 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 */ this.ERROR = 'error'; /** * Triggered when a fragment download has completed. * @event MediaPlayerEvents#FRAGMENT_LOADING_COMPLETED */ this.FRAGMENT_LOADING_COMPLETED = 'fragmentLoadingCompleted'; /** * Triggered when a partial fragment download has completed. * @event MediaPlayerEvents#FRAGMENT_LOADING_PROGRESS */ this.FRAGMENT_LOADING_PROGRESS = 'fragmentLoadingProgress'; /** * Triggered when a fragment download has started. * @event MediaPlayerEvents#FRAGMENT_LOADING_STARTED */ this.FRAGMENT_LOADING_STARTED = 'fragmentLoadingStarted'; /** * Triggered when a fragment download is abandoned due to detection of slow download base on the ABR abandon rule.. * @event MediaPlayerEvents#FRAGMENT_LOADING_ABANDONED */ this.FRAGMENT_LOADING_ABANDONED = 'fragmentLoadingAbandoned'; /** * Triggered when {@link module:Debug} logger methods are called. * @event MediaPlayerEvents#LOG */ this.LOG = 'log'; /** * Triggered when the manifest load is complete * @event MediaPlayerEvents#MANIFEST_LOADED */ this.MANIFEST_LOADED = 'manifestLoaded'; /** * Triggered anytime there is a change to the overall metrics. * @event MediaPlayerEvents#METRICS_CHANGED */ this.METRICS_CHANGED = 'metricsChanged'; /** * Triggered when an individual metric is added, updated or cleared. * @event MediaPlayerEvents#METRIC_CHANGED */ this.METRIC_CHANGED = 'metricChanged'; /** * Triggered every time a new metric is added. * @event MediaPlayerEvents#METRIC_ADDED */ this.METRIC_ADDED = 'metricAdded'; /** * Triggered every time a metric is updated. * @event MediaPlayerEvents#METRIC_UPDATED */ this.METRIC_UPDATED = 'metricUpdated'; /** * Triggered when a new stream (period) starts. * @event MediaPlayerEvents#PERIOD_SWITCH_STARTED */ this.PERIOD_SWITCH_STARTED = 'periodSwitchStarted'; /** * Triggered at the stream end of a period. * @event MediaPlayerEvents#PERIOD_SWITCH_COMPLETED */ this.PERIOD_SWITCH_COMPLETED = 'periodSwitchCompleted'; /** * Triggered when an ABR up /down switch is initiated; either by user in manual mode or auto mode via ABR rules. * @event MediaPlayerEvents#QUALITY_CHANGE_REQUESTED */ this.QUALITY_CHANGE_REQUESTED = 'qualityChangeRequested'; /** * Triggered when the new ABR quality is being rendered on-screen. * @event MediaPlayerEvents#QUALITY_CHANGE_RENDERED */ this.QUALITY_CHANGE_RENDERED = 'qualityChangeRendered'; /** * Triggered when the new track is being rendered. * @event MediaPlayerEvents#TRACK_CHANGE_RENDERED */ this.TRACK_CHANGE_RENDERED = 'trackChangeRendered'; /** * Triggered when a stream (period) is being loaded * @event MediaPlayerEvents#STREAM_INITIALIZING */ this.STREAM_INITIALIZING = 'streamInitializing'; /** * Triggered when a stream (period) is loaded * @event MediaPlayerEvents#STREAM_UPDATED */ this.STREAM_UPDATED = 'streamUpdated'; /** * Triggered when a stream (period) is activated * @event MediaPlayerEvents#STREAM_ACTIVATED */ this.STREAM_ACTIVATED = 'streamActivated'; /** * Triggered when a stream (period) is deactivated * @event MediaPlayerEvents#STREAM_DEACTIVATED */ this.STREAM_DEACTIVATED = 'streamDeactivated'; /** * Triggered when a stream (period) is activated * @event MediaPlayerEvents#STREAM_INITIALIZED */ this.STREAM_INITIALIZED = 'streamInitialized'; /** * Triggered when the player has been reset. * @event MediaPlayerEvents#STREAM_TEARDOWN_COMPLETE */ this.STREAM_TEARDOWN_COMPLETE = 'streamTeardownComplete'; /** * Triggered once all text tracks detected in the MPD are added to the video element. * @event MediaPlayerEvents#TEXT_TRACKS_ADDED */ this.TEXT_TRACKS_ADDED = 'allTextTracksAdded'; /** * Triggered when a text track is added to the video element's TextTrackList * @event MediaPlayerEvents#TEXT_TRACK_ADDED */ this.TEXT_TRACK_ADDED = 'textTrackAdded'; /** * Triggered when a ttml chunk is parsed. * @event MediaPlayerEvents#TTML_PARSED */ this.TTML_PARSED = 'ttmlParsed'; /** * Triggered when a ttml chunk has to be parsed. * @event MediaPlayerEvents#TTML_TO_PARSE */ this.TTML_TO_PARSE = 'ttmlToParse'; /** * Triggered when a caption is rendered. * @event MediaPlayerEvents#CAPTION_RENDERED */ this.CAPTION_RENDERED = 'captionRendered'; /** * Triggered when the caption container is resized. * @event MediaPlayerEvents#CAPTION_CONTAINER_RESIZE */ this.CAPTION_CONTAINER_RESIZE = 'captionContainerResize'; /** * Sent when enough data is available that the media can be played, * at least for a couple of frames. This corresponds to the * HAVE_ENOUGH_DATA readyState. * @event MediaPlayerEvents#CAN_PLAY */ this.CAN_PLAY = 'canPlay'; /** * This corresponds to the CAN_PLAY_THROUGH readyState. * @event MediaPlayerEvents#CAN_PLAY_THROUGH */ this.CAN_PLAY_THROUGH = 'canPlayThrough'; /** * Sent when playback completes. * @event MediaPlayerEvents#PLAYBACK_ENDED */ this.PLAYBACK_ENDED = 'playbackEnded'; /** * Sent when an error occurs. The element's error * attribute contains more information. * @event MediaPlayerEvents#PLAYBACK_ERROR */ this.PLAYBACK_ERROR = 'playbackError'; /** * Sent when playback is not allowed (for example if user gesture is needed). * @event MediaPlayerEvents#PLAYBACK_NOT_ALLOWED */ this.PLAYBACK_NOT_ALLOWED = 'playbackNotAllowed'; /** * The media's metadata has finished loading; all attributes now * contain as much useful information as they're going to. * @event MediaPlayerEvents#PLAYBACK_METADATA_LOADED */ this.PLAYBACK_METADATA_LOADED = 'playbackMetaDataLoaded'; /** * The event is fired when the frame at the current playback position of the media has finished loading; * often the first frame * @event MediaPlayerEvents#PLAYBACK_LOADED_DATA */ this.PLAYBACK_LOADED_DATA = 'playbackLoadedData'; /** * Sent when playback is paused. * @event MediaPlayerEvents#PLAYBACK_PAUSED */ this.PLAYBACK_PAUSED = 'playbackPaused'; /** * Sent when the media begins to play (either for the first time, after having been paused, * or after ending and then restarting). * * @event MediaPlayerEvents#PLAYBACK_PLAYING */ this.PLAYBACK_PLAYING = 'playbackPlaying'; /** * Sent periodically to inform interested parties of progress downloading * the media. Information about the current amount of the media that has * been downloaded is available in the media element's buffered attribute. * @event MediaPlayerEvents#PLAYBACK_PROGRESS */ this.PLAYBACK_PROGRESS = 'playbackProgress'; /** * Sent when the playback speed changes. * @event MediaPlayerEvents#PLAYBACK_RATE_CHANGED */ this.PLAYBACK_RATE_CHANGED = 'playbackRateChanged'; /** * Sent when a seek operation completes. * @event MediaPlayerEvents#PLAYBACK_SEEKED */ this.PLAYBACK_SEEKED = 'playbackSeeked'; /** * Sent when a seek operation begins. * @event MediaPlayerEvents#PLAYBACK_SEEKING */ this.PLAYBACK_SEEKING = 'playbackSeeking'; /** * Sent when the video element reports stalled * @event MediaPlayerEvents#PLAYBACK_STALLED */ this.PLAYBACK_STALLED = 'playbackStalled'; /** * Sent when playback of the media starts after having been paused; * that is, when playback is resumed after a prior pause event. * * @event MediaPlayerEvents#PLAYBACK_STARTED */ this.PLAYBACK_STARTED = 'playbackStarted'; /** * The time indicated by the element's currentTime attribute has changed. * @event MediaPlayerEvents#PLAYBACK_TIME_UPDATED */ this.PLAYBACK_TIME_UPDATED = 'playbackTimeUpdated'; /** * Sent when the video element reports that the volume has changed * @event MediaPlayerEvents#PLAYBACK_VOLUME_CHANGED */ this.PLAYBACK_VOLUME_CHANGED = 'playbackVolumeChanged'; /** * Sent when the media playback has stopped because of a temporary lack of data. * * @event MediaPlayerEvents#PLAYBACK_WAITING */ this.PLAYBACK_WAITING = 'playbackWaiting'; /** * Manifest validity changed - As a result of an MPD validity expiration event. * @event MediaPlayerEvents#MANIFEST_VALIDITY_CHANGED */ this.MANIFEST_VALIDITY_CHANGED = 'manifestValidityChanged'; /** * 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'; /** * Event that is dispatched whenever the player encounters a potential conformance validation that might lead to unexpected/not optimal behavior * @event MediaPlayerEvents#CONFORMANCE_VIOLATION */ this.CONFORMANCE_VIOLATION = 'conformanceViolation'; /** * Event that is dispatched whenever the player switches to a different representation * @event MediaPlayerEvents#REPRESENTATION_SWITCH */ this.REPRESENTATION_SWITCH = 'representationSwitch'; /** * Event that is dispatched whenever an adaptation set is removed due to all representations not being supported. * @event MediaPlayerEvents#ADAPTATION_SET_REMOVED_NO_CAPABILITIES */ this.ADAPTATION_SET_REMOVED_NO_CAPABILITIES = 'adaptationSetRemovedNoCapabilities'; /** * Triggered when a content steering request has completed. * @event MediaPlayerEvents#CONTENT_STEERING_REQUEST_COMPLETED */ this.CONTENT_STEERING_REQUEST_COMPLETED = 'contentSteeringRequestCompleted'; } } let mediaPlayerEvents = new MediaPlayerEvents(); export default mediaPlayerEvents; × Search results Close "},"streaming_MediaPlayerFactory.js.html":{"id":"streaming_MediaPlayerFactory.js.html","title":"Source: streaming/MediaPlayerFactory.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/MediaPlayerFactory.js import MediaPlayer from './MediaPlayer'; function MediaPlayerFactory() { /** * mime-type identifier for any source content to be accepted as a dash manifest by the create() method. * @type {string} */ const SUPPORTED_MIME_TYPE = 'application/dash+xml'; let logger; /** * A new MediaPlayer is instantiated for the supplied videoElement and optional source and context. If no context is provided, * a default DashContext is used. If no source is provided, the videoElement is interrogated to extract the first source whose * type is application/dash+xml. * The autoplay property of the videoElement is preserved. Any preload attribute is ignored. This method should be called after the page onLoad event is dispatched. * @param {HTMLMediaElement} video * @param {HTMLSourceElement} source * @param {Object} context * @returns {MediaPlayer|null} */ function create(video, source, context) { if (!video || !(/^VIDEO$/i).test(video.nodeName)) return null; if (video._dashjs_player) return video._dashjs_player; let player; let videoID = (video.id || video.name || 'video element'); source = source || [].slice.call(video.querySelectorAll('source')).filter(function (s) { return s.type == SUPPORTED_MIME_TYPE; })[0]; if (!source &amp;&amp; video.src) { source = document.createElement('source'); source.src = video.src; } else if (!source &amp;&amp; !video.src) { return null; } context = context || {}; player = MediaPlayer(context).create(); player.initialize(video, source.src, video.autoplay); if (!logger) { logger = player.getDebug().getLogger(); } logger.debug('Converted ' + videoID + ' to dash.js player and added content: ' + source.src); // Store a reference to the player on the video element so it can be gotten at for debugging and so we know its // already been setup. video._dashjs_player = player; return player; } /** * Searches the provided scope for all instances of the indicated selector. If no scope is provided, document is used. If no selector is * specified, [data-dashjs-player] is used. The declarative setup also looks for source elements with the type attribute set to 'application/dash+xml'. * It then looks for those video elements which have a source element defined with a type matching 'application/dash+xml'. * A new MediaPlayer is instantiated for each matching video element and the appropriate source is assigned. * The autoplay property of the video element is preserved. Any preload attribute is ignored. This method should be called after the page onLoad event is dispatched. * Returns an array holding all the MediaPlayer instances that were added by this method. * @param {string} selector - CSS selector * @param {Object} scope * @returns {Array} an array of MediaPlayer objects */ function createAll(selector, scope) { let aPlayers = []; selector = selector || '[data-dashjs-player]'; scope = scope || document; let videos = scope.querySelectorAll(selector); for (let i = 0; i &lt; videos.length; i++) { let player = create(videos[i], null); aPlayers.push(player); } let sources = scope.querySelectorAll('source[type=\"' + SUPPORTED_MIME_TYPE + '\"]'); for (let i = 0; i &lt; sources.length; i++) { let video = findVideo(sources[i]); let player = create(video, null); aPlayers.push(player); } return aPlayers; } function findVideo(el) { if ((/^VIDEO$/i).test(el.nodeName)) { return el; } else { return findVideo(el.parentNode); } } return { create: create, createAll: createAll }; } let instance = MediaPlayerFactory(); let loadInterval; function loadHandler() { window.removeEventListener('load', loadHandler); instance.createAll(); } function loadIntervalHandler() { if (window.dashjs) { window.clearInterval(loadInterval); instance.createAll(); } } let avoidAutoCreate = typeof window !== 'undefined' &amp;&amp; window &amp;&amp; window.dashjs &amp;&amp; window.dashjs.skipAutoCreate; if (!avoidAutoCreate &amp;&amp; typeof window !== 'undefined' &amp;&amp; window &amp;&amp; window.addEventListener) { if (window.document.readyState === 'complete') { if (window.dashjs) { instance.createAll(); } else { // If loaded asynchronously, window.readyState may be 'complete' even if dashjs hasn't loaded yet loadInterval = window.setInterval(loadIntervalHandler, 500); } } else { window.addEventListener('load', loadHandler); } } export default instance; × Search results Close "},"streaming_models_MediaPlayerModel.js.html":{"id":"streaming_models_MediaPlayerModel.js.html","title":"Source: streaming/models/MediaPlayerModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/models/MediaPlayerModel.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import Settings from '../../core/Settings'; const DEFAULT_MIN_BUFFER_TIME = 12; const DEFAULT_MIN_BUFFER_TIME_FAST_SWITCH = 20; const LOW_LATENCY_REDUCTION_FACTOR = 10; const LOW_LATENCY_MULTIPLY_FACTOR = 5; const DEFAULT_CATCHUP_MAX_DRIFT = 12; const DEFAULT_CATCHUP_PLAYBACK_RATE = 0.5; /** * We use this model as a wrapper/proxy between Settings.js and classes that are using parameters from Settings.js. * In some cases we require additional logic to be applied and the settings might need to be adjusted before being used. * @class * @constructor */ function MediaPlayerModel() { let instance, playbackController, serviceDescriptionController; const context = this.context; const settings = Settings(context).getInstance(); function setup() { } function setConfig(config) { if (config.playbackController) { playbackController = config.playbackController; } if (config.serviceDescriptionController) { serviceDescriptionController = config.serviceDescriptionController; } } /** * Returns the maximum drift allowed before applying a seek back to the live edge when the catchup mode is enabled * @return {number} */ function getCatchupMaxDrift() { if (!isNaN(settings.get().streaming.liveCatchup.maxDrift) &amp;&amp; settings.get().streaming.liveCatchup.maxDrift &gt; 0) { return settings.get().streaming.liveCatchup.maxDrift; } const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings(); if (serviceDescriptionSettings &amp;&amp; serviceDescriptionSettings.liveCatchup &amp;&amp; !isNaN(serviceDescriptionSettings.liveCatchup.maxDrift) &amp;&amp; serviceDescriptionSettings.liveCatchup.maxDrift &gt; 0) { return serviceDescriptionSettings.liveCatchup.maxDrift; } return DEFAULT_CATCHUP_MAX_DRIFT; } /** * Returns the maximum playback rate to be used when applying the catchup mechanism * @return {number} */ function getCatchupPlaybackRate() { if (!isNaN(settings.get().streaming.liveCatchup.playbackRate) &amp;&amp; settings.get().streaming.liveCatchup.playbackRate &gt; 0) { return settings.get().streaming.liveCatchup.playbackRate; } const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings(); if (serviceDescriptionSettings &amp;&amp; serviceDescriptionSettings.liveCatchup &amp;&amp; !isNaN(serviceDescriptionSettings.liveCatchup.playbackRate) &amp;&amp; serviceDescriptionSettings.liveCatchup.playbackRate &gt; 0) { return serviceDescriptionSettings.liveCatchup.playbackRate; } return DEFAULT_CATCHUP_PLAYBACK_RATE; } /** * Returns whether the catchup mode is activated via the settings or internally in the PlaybackController * @return {boolean} */ function getCatchupModeEnabled() { if (settings.get().streaming.liveCatchup.enabled !== null) { return settings.get().streaming.liveCatchup.enabled; } return playbackController.getInitialCatchupModeActivated(); } /** * Returns the min,max or initial bitrate for a specific media type. * @param {string} field * @param {string} mediaType */ function getAbrBitrateParameter(field, mediaType) { try { const setting = settings.get().streaming.abr[field][mediaType]; if(!isNaN(setting) &amp;&amp; setting !== -1) { return setting; } const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings(); if(serviceDescriptionSettings &amp;&amp; serviceDescriptionSettings[field] &amp;&amp; !isNaN(serviceDescriptionSettings[field][mediaType])) { return serviceDescriptionSettings[field][mediaType]; } return -1; } catch(e) { return -1; } } /** * Returns the initial buffer level taking the stable buffer time into account * @return {number} */ function getInitialBufferLevel() { const initialBufferLevel = settings.get().streaming.buffer.initialBufferLevel; if (isNaN(initialBufferLevel) || initialBufferLevel &lt; 0) { return 0; } return Math.min(getStableBufferTime(), initialBufferLevel); } /** * Returns the stable buffer time taking the live delay into account * @return {number} */ function getStableBufferTime() { let stableBufferTime = settings.get().streaming.buffer.stableBufferTime &gt; 0 ? settings.get().streaming.buffer.stableBufferTime : settings.get().streaming.buffer.fastSwitchEnabled ? DEFAULT_MIN_BUFFER_TIME_FAST_SWITCH : DEFAULT_MIN_BUFFER_TIME; const liveDelay = playbackController.getLiveDelay(); return !isNaN(liveDelay) &amp;&amp; liveDelay &gt; 0 ? Math.min(stableBufferTime, liveDelay) : stableBufferTime; } /** * Returns the number of retry attempts for a specific media type * @param type * @return {number} */ function getRetryAttemptsForType(type) { const lowLatencyMultiplyFactor = !isNaN(settings.get().streaming.retryAttempts.lowLatencyMultiplyFactor) ? settings.get().streaming.retryAttempts.lowLatencyMultiplyFactor : LOW_LATENCY_MULTIPLY_FACTOR; return playbackController.getLowLatencyModeEnabled() ? settings.get().streaming.retryAttempts[type] * lowLatencyMultiplyFactor : settings.get().streaming.retryAttempts[type]; } /** * Returns the retry interval for a specific media type * @param type * @return {number} */ function getRetryIntervalsForType(type) { const lowLatencyReductionFactor = !isNaN(settings.get().streaming.retryIntervals.lowLatencyReductionFactor) ? settings.get().streaming.retryIntervals.lowLatencyReductionFactor : LOW_LATENCY_REDUCTION_FACTOR; return playbackController.getLowLatencyModeEnabled() ? settings.get().streaming.retryIntervals[type] / lowLatencyReductionFactor : settings.get().streaming.retryIntervals[type]; } function reset() { } instance = { getCatchupMaxDrift, getCatchupModeEnabled, getStableBufferTime, getInitialBufferLevel, getRetryAttemptsForType, getRetryIntervalsForType, getCatchupPlaybackRate, getAbrBitrateParameter, setConfig, reset }; setup(); return instance; } MediaPlayerModel.__dashjs_factory_name = 'MediaPlayerModel'; export default FactoryMaker.getSingletonFactory(MediaPlayerModel); × Search results Close "},"streaming_MediaPlayer.js.html":{"id":"streaming_MediaPlayer.js.html","title":"Source: streaming/MediaPlayer.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/MediaPlayer.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import cea608parser from '../../externals/cea608-parser'; import Constants from './constants/Constants'; import DashConstants from '../dash/constants/DashConstants'; import MetricsConstants from './constants/MetricsConstants'; import PlaybackController from './controllers/PlaybackController'; import StreamController from './controllers/StreamController'; import GapController from './controllers/GapController'; import CatchupController from './controllers/CatchupController'; import ServiceDescriptionController from '../dash/controllers/ServiceDescriptionController'; import ContentSteeringController from '../dash/controllers/ContentSteeringController'; import MediaController from './controllers/MediaController'; import BaseURLController from './controllers/BaseURLController'; import ManifestLoader from './ManifestLoader'; import ErrorHandler from './utils/ErrorHandler'; import Capabilities from './utils/Capabilities'; import CapabilitiesFilter from './utils/CapabilitiesFilter'; import RequestModifier from './utils/RequestModifier'; import URIFragmentModel from './models/URIFragmentModel'; import ManifestModel from './models/ManifestModel'; import MediaPlayerModel from './models/MediaPlayerModel'; import AbrController from './controllers/AbrController'; import SchemeLoaderFactory from './net/SchemeLoaderFactory'; import VideoModel from './models/VideoModel'; import CmcdModel from './models/CmcdModel'; import DOMStorage from './utils/DOMStorage'; import Debug from './../core/Debug'; import Errors from './../core/errors/Errors'; import EventBus from './../core/EventBus'; import Events from './../core/events/Events'; import MediaPlayerEvents from './MediaPlayerEvents'; import FactoryMaker from '../core/FactoryMaker'; import Settings from '../core/Settings'; import { getVersionString } from '../core/Version'; //Dash import SegmentBaseController from '../dash/controllers/SegmentBaseController'; import DashAdapter from '../dash/DashAdapter'; import DashMetrics from '../dash/DashMetrics'; import TimelineConverter from '../dash/utils/TimelineConverter'; import { HTTPRequest } from './vo/metrics/HTTPRequest'; import BASE64 from '../../externals/base64'; import ISOBoxer from 'codem-isoboxer'; import DashJSError from './vo/DashJSError'; import {checkParameterType} from './utils/SupervisorTools'; import ManifestUpdater from './ManifestUpdater'; import URLUtils from '../streaming/utils/URLUtils'; import BoxParser from './utils/BoxParser'; import TextController from './text/TextController'; import CustomParametersModel from './models/CustomParametersModel'; /** * The media types * @typedef {(\"video\" | \"audio\" | \"text\" | \"image\")} MediaType */ /** * @module MediaPlayer * @description The MediaPlayer is the primary dash.js Module and a Facade to build your player around. * It will allow you access to all the important dash.js properties/methods via the public API and all the * events to build a robust DASH media player. */ function MediaPlayer() { /** * @constant {string} STREAMING_NOT_INITIALIZED_ERROR error string thrown when a function is called before the dash.js has been fully initialized * @inner */ const STREAMING_NOT_INITIALIZED_ERROR = 'You must first call initialize() and set a source before calling this method'; /** * @constant {string} PLAYBACK_NOT_INITIALIZED_ERROR error string thrown when a function is called before the dash.js has been fully initialized * @inner */ const PLAYBACK_NOT_INITIALIZED_ERROR = 'You must first call initialize() and set a valid source and view before calling this method'; /** * @constant {string} ELEMENT_NOT_ATTACHED_ERROR error string thrown when a function is called before the dash.js has received a reference of an HTML5 video element * @inner */ const ELEMENT_NOT_ATTACHED_ERROR = 'You must first call attachView() to set the video element before calling this method'; /** * @constant {string} SOURCE_NOT_ATTACHED_ERROR error string thrown when a function is called before the dash.js has received a valid source stream. * @inner */ const SOURCE_NOT_ATTACHED_ERROR = 'You must first call attachSource() with a valid source before calling this method'; /** * @constant {string} MEDIA_PLAYER_NOT_INITIALIZED_ERROR error string thrown when a function is called before the dash.js has been fully initialized. * @inner */ const MEDIA_PLAYER_NOT_INITIALIZED_ERROR = 'MediaPlayer not initialized!'; const context = this.context; const eventBus = EventBus(context).getInstance(); let settings = Settings(context).getInstance(); const debug = Debug(context).getInstance({ settings: settings }); let instance, logger, source, protectionData, mediaPlayerInitialized, streamingInitialized, playbackInitialized, autoPlay, abrController, schemeLoaderFactory, timelineConverter, mediaController, protectionController, metricsReportingController, mssHandler, offlineController, adapter, mediaPlayerModel, customParametersModel, errHandler, baseURLController, capabilities, capabilitiesFilter, streamController, textController, gapController, playbackController, serviceDescriptionController, contentSteeringController, catchupController, dashMetrics, manifestModel, cmcdModel, videoModel, uriFragmentModel, domStorage, segmentBaseController; /* --------------------------------------------------------------------------- INIT FUNCTIONS --------------------------------------------------------------------------- */ function setup() { logger = debug.getLogger(instance); mediaPlayerInitialized = false; playbackInitialized = false; streamingInitialized = false; autoPlay = true; protectionController = null; offlineController = null; protectionData = null; adapter = null; segmentBaseController = null; Events.extend(MediaPlayerEvents); mediaPlayerModel = MediaPlayerModel(context).getInstance(); customParametersModel = CustomParametersModel(context).getInstance(); videoModel = VideoModel(context).getInstance(); uriFragmentModel = URIFragmentModel(context).getInstance(); } /** * Configure media player with customs controllers. Helpful for tests * * @param {object=} config controllers configuration * @memberof module:MediaPlayer * @instance */ function setConfig(config) { if (!config) { return; } if (config.capabilities) { capabilities = config.capabilities; } if (config.capabilitiesFilter) { capabilitiesFilter = config.capabilitiesFilter; } if (config.streamController) { streamController = config.streamController; } if (config.textController) { textController = config.textController; } if (config.gapController) { gapController = config.gapController; } if (config.playbackController) { playbackController = config.playbackController; } if (config.serviceDescriptionController) { serviceDescriptionController = config.serviceDescriptionController } if (config.contentSteeringController) { contentSteeringController = config.contentSteeringController; } if (config.catchupController) { catchupController = config.catchupController; } if (config.mediaPlayerModel) { mediaPlayerModel = config.mediaPlayerModel; } if (config.customParametersModel) { customParametersModel = config.customParametersModel; } if (config.abrController) { abrController = config.abrController; } if (config.schemeLoaderFactory) { schemeLoaderFactory = config.schemeLoaderFactory; } if (config.mediaController) { mediaController = config.mediaController; } if (config.settings) { settings = config.settings; } } /** * Upon creating the MediaPlayer you must call initialize before you call anything else. * There is one exception to this rule. It is crucial to call {@link module:MediaPlayer#extend extend()} * with all your extensions prior to calling initialize. * * ALL arguments are optional and there are individual methods to set each argument later on. * The args in this method are just for convenience and should only be used for a simple player setup. * * @param {HTML5MediaElement=} view - Optional arg to set the video element. {@link module:MediaPlayer#attachView attachView()} * @param {string=} source - Optional arg to set the media source. {@link module:MediaPlayer#attachSource attachSource()} * @param {boolean=} autoPlay - Optional arg to set auto play. {@link module:MediaPlayer#setAutoPlay setAutoPlay()} * @param {number|string} startTime - For VoD content the start time is relative to the start time of the first period. * For live content * If the parameter starts from prefix posix: it signifies the absolute time range defined in seconds of Coordinated Universal Time (ITU-R TF.460-6). This is the number of seconds since 01-01-1970 00:00:00 UTC. Fractions of seconds may be optionally specified down to the millisecond level. * If no posix prefix is used the starttime is relative to MPD@availabilityStartTime * @see {@link module:MediaPlayer#attachSource attachSource()} * @see {@link module:MediaPlayer#setAutoPlay setAutoPlay()} * @memberof module:MediaPlayer * @instance */ function initialize(view, source, autoPlay, startTime = NaN) { if (!capabilities) { capabilities = Capabilities(context).getInstance(); capabilities.setConfig({ settings }) } if (!errHandler) { errHandler = ErrorHandler(context).getInstance(); } if (!capabilities.supportsMediaSource()) { errHandler.error(new DashJSError(Errors.CAPABILITY_MEDIASOURCE_ERROR_CODE, Errors.CAPABILITY_MEDIASOURCE_ERROR_MESSAGE)); return; } if (!mediaPlayerInitialized) { mediaPlayerInitialized = true; // init some controllers and models timelineConverter = TimelineConverter(context).getInstance(); if (!abrController) { abrController = AbrController(context).getInstance(); abrController.setConfig({ settings: settings }); } if (!schemeLoaderFactory) { schemeLoaderFactory = SchemeLoaderFactory(context).getInstance(); } if (!playbackController) { playbackController = PlaybackController(context).getInstance(); } if (!mediaController) { mediaController = MediaController(context).getInstance(); } if (!streamController) { streamController = StreamController(context).getInstance(); } if (!gapController) { gapController = GapController(context).getInstance(); } if (!catchupController) { catchupController = CatchupController(context).getInstance(); } if (!serviceDescriptionController) { serviceDescriptionController = ServiceDescriptionController(context).getInstance(); } if (!contentSteeringController) { contentSteeringController = ContentSteeringController(context).getInstance(); } if (!capabilitiesFilter) { capabilitiesFilter = CapabilitiesFilter(context).getInstance(); } adapter = DashAdapter(context).getInstance(); manifestModel = ManifestModel(context).getInstance(); cmcdModel = CmcdModel(context).getInstance(); dashMetrics = DashMetrics(context).getInstance({ settings: settings }); domStorage = DOMStorage(context).getInstance({ settings: settings }); adapter.setConfig({ constants: Constants, cea608parser: cea608parser, errHandler: errHandler, BASE64: BASE64 }); if (!baseURLController) { baseURLController = BaseURLController(context).create(); } baseURLController.setConfig({ adapter }); serviceDescriptionController.setConfig({ adapter }); if (!segmentBaseController) { segmentBaseController = SegmentBaseController(context).getInstance({ dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, errHandler: errHandler, baseURLController: baseURLController, events: Events, eventBus: eventBus, debug: debug, boxParser: BoxParser(context).getInstance(), requestModifier: RequestModifier(context).getInstance(), errors: Errors }); } // configure controllers mediaController.setConfig({ domStorage, settings, customParametersModel }); mediaPlayerModel.setConfig({ playbackController, serviceDescriptionController }); restoreDefaultUTCTimingSources(); setAutoPlay(autoPlay !== undefined ? autoPlay : true); // Detect and initialize offline module to support offline contents playback _detectOffline(); } if (view) { attachView(view); } if (source) { attachSource(source, startTime); } logger.info('[dash.js ' + getVersion() + '] ' + 'MediaPlayer has been initialized'); } /** * Sets the MPD source and the video element to null. You can also reset the MediaPlayer by * calling attachSource with a new source file. * * This call does not destroy the MediaPlayer. To destroy the MediaPlayer and free all of its * memory, call destroy(). * * @memberof module:MediaPlayer * @instance */ function reset() { attachSource(null); attachView(null); protectionData = null; if (protectionController) { protectionController.reset(); protectionController = null; } if (metricsReportingController) { metricsReportingController.reset(); metricsReportingController = null; } if (customParametersModel) { customParametersModel.reset(); } settings.reset(); if (offlineController) { offlineController.reset(); offlineController = null; } } /** * Completely destroys the media player and frees all memory. * * @memberof module:MediaPlayer * @instance */ function destroy() { reset(); FactoryMaker.deleteSingletonInstances(context); } /** * The ready state of the MediaPlayer based on both the video element and MPD source being defined. * * @returns {boolean} The current ready state of the MediaPlayer * @see {@link module:MediaPlayer#attachView attachView()} * @see {@link module:MediaPlayer#attachSource attachSource()} * @memberof module:MediaPlayer * @instance */ function isReady() { return (!!source &amp;&amp; !!videoModel.getElement()); } /** * Use the on method to listen for public events found in MediaPlayer.events. {@link MediaPlayerEvents} * * @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, options) { eventBus.on(type, listener, scope, options); } /** * Use the off method to remove listeners for public events found in MediaPlayer.events. {@link MediaPlayerEvents} * * @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. * @memberof module:MediaPlayer * @instance */ function off(type, listener, scope) { eventBus.off(type, listener, scope); } /** * Current version of Dash.js * @returns {string} the current dash.js version string. * @memberof module:MediaPlayer * @instance */ function getVersion() { return getVersionString(); } /** * Use this method to access the dash.js logging class. * * @returns {Debug} * @memberof module:MediaPlayer * @instance */ function getDebug() { return debug; } /* --------------------------------------------------------------------------- PLAYBACK FUNCTIONS --------------------------------------------------------------------------- */ /** * The play method initiates playback of the media defined by the {@link module:MediaPlayer#attachSource attachSource()} method. * This method will call play on the native Video Element. * * @see {@link module:MediaPlayer#attachSource attachSource()} * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function play() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } if (!autoPlay || (isPaused() &amp;&amp; playbackInitialized)) { playbackController.play(true); } } /** * This method will call pause on the native Video Element. * * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function pause() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } playbackController.pause(); } /** * Returns a Boolean that indicates whether the Video Element is paused. * @return {boolean} * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function isPaused() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } return playbackController.isPaused(); } /** * Sets the currentTime property of the attached video element. If it is a live stream with a * timeShiftBufferLength, then the DVR window offset will be automatically calculated. * * @param {number} value - A relative time, in seconds, based on the return value of the {@link module:MediaPlayer#duration duration()} method is expected. * For dynamic streams duration() returns DVRWindow.end - DVRWindow.start. Consequently, the value provided to this function should be relative to DVRWindow.start. * @see {@link module:MediaPlayer#getDVRSeekOffset getDVRSeekOffset()} * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @throws {@link Constants#BAD_ARGUMENT_ERROR BAD_ARGUMENT_ERROR} if called with an invalid argument, not number type or is NaN. * @memberof module:MediaPlayer * @instance */ function seek(value) { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } checkParameterType(value, 'number'); if (isNaN(value)) { throw Constants.BAD_ARGUMENT_ERROR; } let s = playbackController.getIsDynamic() ? getDVRSeekOffset(value) : value; playbackController.seek(s, false, false, true); } /** * Seeks back to the original live edge (live edge as calculated at playback start). Only applies to live streams, for VoD streams this call will be ignored. */ function seekToOriginalLive() { if (!playbackInitialized || !isDynamic()) { return; } playbackController.seekToOriginalLive(); } /** * Returns a Boolean that indicates whether the media is in the process of seeking to a new position. * @return {boolean} * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function isSeeking() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } return playbackController.isSeeking(); } /** * Returns a Boolean that indicates whether the media is in the process of dynamic. * @return {boolean} * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function isDynamic() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } return playbackController.getIsDynamic(); } /** * Returns a boolean that indicates whether the player is operating in low latency mode. * @return {boolean} * @memberof module:MediaPlayer * @instance */ function getLowLatencyModeEnabled() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } return playbackController.getLowLatencyModeEnabled(); } /** * Use this method to set the native Video Element's playback rate. * @param {number} value * @memberof module:MediaPlayer * @instance */ function setPlaybackRate(value) { getVideoElement().playbackRate = value; } /** * Returns the current playback rate. * @returns {number} * @memberof module:MediaPlayer * @instance */ function getPlaybackRate() { return getVideoElement().playbackRate; } /** * Use this method to set the native Video Element's muted state. Takes a Boolean that determines whether audio is muted. true if the audio is muted and false otherwise. * @param {boolean} value * @memberof module:MediaPlayer * @throws {@link Constants#BAD_ARGUMENT_ERROR BAD_ARGUMENT_ERROR} if called with an invalid argument, not boolean type. * @instance */ function setMute(value) { checkParameterType(value, 'boolean'); getVideoElement().muted = value; } /** * A Boolean that determines whether audio is muted. * @returns {boolean} * @memberof module:MediaPlayer * @instance */ function isMuted() { return getVideoElement().muted; } /** * A double indicating the audio volume, from 0.0 (silent) to 1.0 (loudest). * @param {number} value * @memberof module:MediaPlayer * @throws {@link Constants#BAD_ARGUMENT_ERROR BAD_ARGUMENT_ERROR} if called with an invalid argument, not number type, or is NaN or not between 0 and 1. * @instance */ function setVolume(value) { if (typeof value !== 'number' || isNaN(value) || value &lt; 0.0 || value &gt; 1.0) { throw Constants.BAD_ARGUMENT_ERROR; } getVideoElement().volume = value; } /** * Returns the current audio volume, from 0.0 (silent) to 1.0 (loudest). * @returns {number} * @memberof module:MediaPlayer * @instance */ function getVolume() { return getVideoElement().volume; } /** * The length of the buffer for a given media type, in seconds. Valid media * types are \"video\", \"audio\" and \"text\". If no type is passed * in, then the minimum of video, audio and text buffer length is * returned. NaN is returned if an invalid type is requested, the * presentation does not contain that type, or if no arguments are passed * and the presentation does not include any adaption sets of valid media * type. * * @param {MediaType} type - 'video', 'audio' or 'text' * @returns {number} The length of the buffer for the given media type, in * seconds, or NaN * @memberof module:MediaPlayer * @instance */ function getBufferLength(type) { const types = [Constants.VIDEO, Constants.AUDIO, Constants.TEXT]; if (!type) { const buffer = types.map( t =&gt; getTracksFor(t).length &gt; 0 ? getDashMetrics().getCurrentBufferLevel(t) : Number.MAX_VALUE ).reduce( (p, c) =&gt; Math.min(p, c) ); return buffer === Number.MAX_VALUE ? NaN : buffer; } else { if (types.indexOf(type) !== -1) { const buffer = getDashMetrics().getCurrentBufferLevel(type); return buffer ? buffer : NaN; } else { logger.warn('getBufferLength requested for invalid type'); return NaN; } } } /** * The timeShiftBufferLength (DVR Window), in seconds. * * @returns {number} The window of allowable play time behind the live point of a live stream as defined in the manifest. * @memberof module:MediaPlayer * @instance */ function getDVRWindowSize() { const type = streamController &amp;&amp; streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO; let metric = dashMetrics.getCurrentDVRInfo(type); if (!metric) { return 0; } return metric.manifestInfo.dvrWindowSize; } /** * This method should only be used with a live stream that has a valid timeShiftBufferLength (DVR Window). * NOTE - If you do not need the raw offset value (i.e. media analytics, tracking, etc) consider using the {@link module:MediaPlayer#seek seek()} method * which will calculate this value for you and set the video element's currentTime property all in one simple call. * * @param {number} value - A relative time, in seconds, based on the return value of the {@link module:MediaPlayer#duration duration()} method is expected. * @returns {number} A value that is relative the available range within the timeShiftBufferLength (DVR Window). * @see {@link module:MediaPlayer#seek seek()} * @memberof module:MediaPlayer * @instance */ function getDVRSeekOffset(value) { const type = streamController &amp;&amp; streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO; let metric = dashMetrics.getCurrentDVRInfo(type); if (!metric) { return 0; } let liveDelay = playbackController.getOriginalLiveDelay(); let val = metric.range.start + value; if (val &gt; (metric.range.end - liveDelay)) { val = metric.range.end - liveDelay; } return val; } /** * Returns the target live delay * @returns {number} The target live delay * @memberof module:MediaPlayer * @instance */ function getTargetLiveDelay() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } return playbackController.getOriginalLiveDelay(); } /** * Current time of the playhead, in seconds. * * If called with no arguments then the returned time value is time elapsed since the start point of the first stream, or if it is a live stream, then the time will be based on the return value of the {@link module:MediaPlayer#duration duration()} method. * However if a stream ID is supplied then time is relative to the start of that stream, or is null if there is no such stream id in the manifest. * * @param {string} streamId - The ID of a stream that the returned playhead time must be relative to the start of. If undefined, then playhead time is relative to the first stream. * @returns {number} The current playhead time of the media, or null. * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function time(streamId) { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } let t = getVideoElement().currentTime; if (streamId !== undefined) { t = streamController.getTimeRelativeToStreamId(t, streamId); } else if (playbackController.getIsDynamic()) { const type = streamController &amp;&amp; streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO; let metric = dashMetrics.getCurrentDVRInfo(type); t = (metric === null || t === 0) ? 0 : Math.max(0, (t - metric.range.start)); } return t; } /** * Duration of the media's playback, in seconds. * * @returns {number} The current duration of the media. For a dynamic stream this will return DVRWindow.end - DVRWindow.start * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function duration() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } let d = getVideoElement().duration; if (playbackController.getIsDynamic()) { const type = streamController &amp;&amp; streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO; let metric = dashMetrics.getCurrentDVRInfo(type); d = metric ? (metric.range.end - metric.range.start) : 0; } return d; } /** * Use this method to get the current playhead time as an absolute value, the time in seconds since midnight UTC, Jan 1 1970. * Note - this property only has meaning for live streams. If called before play() has begun, it will return a value of NaN. * * @returns {number} The current playhead time as UTC timestamp. * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function timeAsUTC() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } if (time() &lt; 0) { return NaN; } return _getAsUTC(time()); } /** * Use this method to get the current duration as an absolute value, the time in seconds since midnight UTC, Jan 1 1970. * Note - this property only has meaning for live streams. * * @returns {number} The current duration as UTC timestamp. * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function durationAsUTC() { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } return _getAsUTC(duration()); } /* --------------------------------------------------------------------------- AUTO BITRATE --------------------------------------------------------------------------- */ /** * Gets the top quality BitrateInfo checking portal limit and max allowed. * It calls getMaxAllowedIndexFor internally * * @param {MediaType} type - 'video' or 'audio' * @memberof module:MediaPlayer * @returns {BitrateInfo | null} * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getTopBitrateInfoFor(type) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } return abrController.getTopBitrateInfoFor(type); } /** * Gets the current download quality for media type video, audio or images. For video and audio types the ABR * rules update this value before every new download unless autoSwitchBitrate is set to false. For 'image' * type, thumbnails, there is no ABR algorithm and quality is set manually. * * @param {MediaType} type - 'video', 'audio' or 'image' (thumbnails) * @returns {number} the quality index, 0 corresponding to the lowest bitrate * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#setQualityFor setQualityFor()} * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getQualityFor(type) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } if (type === Constants.IMAGE) { const activeStream = getActiveStream(); if (!activeStream) { return -1; } const thumbnailController = activeStream.getThumbnailController(); return !thumbnailController ? -1 : thumbnailController.getCurrentTrackIndex(); } return abrController.getQualityFor(type); } /** * Sets the current quality for media type instead of letting the ABR Heuristics automatically selecting it. * This value will be overwritten by the ABR rules unless autoSwitchBitrate is set to false. * * @param {MediaType} type - 'video', 'audio' or 'image' * @param {number} value - the quality index, 0 corresponding to the lowest bitrate * @param {boolean} forceReplace - true if segments have to be replaced by segments of the new quality * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#getQualityFor getQualityFor()} * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function setQualityFor(type, value, forceReplace = false) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } if (type === Constants.IMAGE) { const activeStream = getActiveStream(); if (!activeStream) { return; } const thumbnailController = activeStream.getThumbnailController(); if (thumbnailController) { thumbnailController.setTrackByIndex(value); } } abrController.setPlaybackQuality(type, streamController.getActiveStreamInfo(), value, { forceReplace }); } /** * Update the video element size variables * Should be called on window resize (or any other time player is resized). Fullscreen does trigger a window resize event. * * Once windowResizeEventCalled = true, abrController.checkPortalSize() will use element size variables rather than querying clientWidth every time. * * @memberof module:MediaPlayer * @instance */ function updatePortalSize() { abrController.setElementSize(); abrController.setWindowResizeEventCalled(true); } /* --------------------------------------------------------------------------- MEDIA PLAYER CONFIGURATION --------------------------------------------------------------------------- */ /** * &lt;p&gt;Set to false to prevent stream from auto-playing when the view is attached.&lt;/p&gt; * * @param {boolean} value * @default true * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#attachView attachView()} * @throws {@link Constants#BAD_ARGUMENT_ERROR BAD_ARGUMENT_ERROR} if called with an invalid argument, not boolean type. * @instance * */ function setAutoPlay(value) { checkParameterType(value, 'boolean'); autoPlay = value; } /** * @returns {boolean} The current autoPlay state. * @memberof module:MediaPlayer * @instance */ function getAutoPlay() { return autoPlay; } /** * @memberof module:MediaPlayer * @instance * @returns {number|NaN} Current live stream latency in seconds. It is the difference between now time and time position at the playback head. * @throws {@link module:MediaPlayer~MEDIA_PLAYER_NOT_INITIALIZED_ERROR MEDIA_PLAYER_NOT_INITIALIZED_ERROR} if called before initialize function */ function getCurrentLiveLatency() { if (!mediaPlayerInitialized) { throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR; } if (!playbackInitialized) { return NaN; } return playbackController.getCurrentLiveLatency(); } /** * Add a custom ABR Rule * Rule will be apply on next stream if a stream is being played * * @param {string} type - rule type (one of ['qualitySwitchRules','abandonFragmentRules']) * @param {string} rulename - name of rule (used to identify custom rule). If one rule of same name has been added, then existing rule will be updated * @param {object} rule - the rule object instance * @memberof module:MediaPlayer * @throws {@link Constants#BAD_ARGUMENT_ERROR BAD_ARGUMENT_ERROR} if called with invalid arguments. * @instance */ function addABRCustomRule(type, rulename, rule) { customParametersModel.addAbrCustomRule(type, rulename, rule); } /** * Remove a custom ABR Rule * * @param {string} rulename - name of the rule to be removed * @memberof module:MediaPlayer * @instance */ function removeABRCustomRule(rulename) { customParametersModel.removeAbrCustomRule(rulename); } /** * Remove all ABR custom rules * @memberof module:MediaPlayer * @instance */ function removeAllABRCustomRule() { customParametersModel.removeAllAbrCustomRule(); } /** * Returns all ABR custom rules * @return {Array} */ function getABRCustomRules() { return customParametersModel.getAbrCustomRules(); } /** * &lt;p&gt;Allows you to set a scheme and server source for UTC live edge detection for dynamic streams. * If UTCTiming is defined in the manifest, it will take precedence over any time source manually added.&lt;/p&gt; * &lt;p&gt;If you have exposed the Date header, use the method {@link module:MediaPlayer#clearDefaultUTCTimingSources clearDefaultUTCTimingSources()}. * This will allow the date header on the manifest to be used instead of a time server&lt;/p&gt; * @param {string} schemeIdUri - &lt;ul&gt; * &lt;li&gt;urn:mpeg:dash:utc:http-head:2014&lt;/li&gt; * &lt;li&gt;urn:mpeg:dash:utc:http-xsdate:2014&lt;/li&gt; * &lt;li&gt;urn:mpeg:dash:utc:http-iso:2014&lt;/li&gt; * &lt;li&gt;urn:mpeg:dash:utc:direct:2014&lt;/li&gt; * &lt;/ul&gt; * &lt;p&gt;Some specs referencing early ISO23009-1 drafts incorrectly use * 2012 in the URI, rather than 2014. support these for now.&lt;/p&gt; * &lt;ul&gt; * &lt;li&gt;urn:mpeg:dash:utc:http-head:2012&lt;/li&gt; * &lt;li&gt;urn:mpeg:dash:utc:http-xsdate:2012&lt;/li&gt; * &lt;li&gt;urn:mpeg:dash:utc:http-iso:2012&lt;/li&gt; * &lt;li&gt;urn:mpeg:dash:utc:direct:2012&lt;/li&gt; * &lt;/ul&gt; * @param {string} value - Path to a time source. * @default * &lt;ul&gt; * &lt;li&gt;schemeIdUri:urn:mpeg:dash:utc:http-xsdate:2014&lt;/li&gt; * &lt;li&gt;value:http://time.akamai.com/?iso&amp;ms/li&gt; * &lt;/ul&gt; * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#removeUTCTimingSource removeUTCTimingSource()} * @instance */ function addUTCTimingSource(schemeIdUri, value) { customParametersModel.addUTCTimingSource(schemeIdUri, value); } /** * &lt;p&gt;Allows you to remove a UTC time source. Both schemeIdUri and value need to match the Dash.vo.UTCTiming properties in order for the * entry to be removed from the array&lt;/p&gt; * @param {string} schemeIdUri - see {@link module:MediaPlayer#addUTCTimingSource addUTCTimingSource()} * @param {string} value - see {@link module:MediaPlayer#addUTCTimingSource addUTCTimingSource()} * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#clearDefaultUTCTimingSources clearDefaultUTCTimingSources()} * @throws {@link Constants#BAD_ARGUMENT_ERROR BAD_ARGUMENT_ERROR} if called with invalid arguments, schemeIdUri and value are not string type. * @instance */ function removeUTCTimingSource(schemeIdUri, value) { customParametersModel.removeUTCTimingSource(schemeIdUri, value); } /** * &lt;p&gt;Allows you to clear the stored array of time sources.&lt;/p&gt; * &lt;p&gt;Example use: If you have exposed the Date header, calling this method * will allow the date header on the manifest to be used instead of the time server.&lt;/p&gt; * &lt;p&gt;Example use: Calling this method, assuming there is not an exposed date header on the manifest, will default back * to using a binary search to discover the live edge&lt;/p&gt; * * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#restoreDefaultUTCTimingSources restoreDefaultUTCTimingSources()} * @instance */ function clearDefaultUTCTimingSources() { customParametersModel.clearDefaultUTCTimingSources(); } /** * &lt;p&gt;Allows you to restore the default time sources after calling {@link module:MediaPlayer#clearDefaultUTCTimingSources clearDefaultUTCTimingSources()}&lt;/p&gt; * * @default * &lt;ul&gt; * &lt;li&gt;schemeIdUri:urn:mpeg:dash:utc:http-xsdate:2014&lt;/li&gt; * &lt;li&gt;value:http://time.akamai.com/?iso&amp;ms&lt;/li&gt; * &lt;/ul&gt; * * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#addUTCTimingSource addUTCTimingSource()} * @instance */ function restoreDefaultUTCTimingSources() { customParametersModel.restoreDefaultUTCTimingSources(); } /** * Returns the average throughput computed in the ABR logic * * @param {MediaType} type * @return {number} value * @memberof module:MediaPlayer * @instance */ function getAverageThroughput(type) { const throughputHistory = abrController.getThroughputHistory(); const isDynamic = playbackController.getIsDynamic(); return throughputHistory ? throughputHistory.getAverageThroughput(type, isDynamic) : 0; } /** * Sets whether withCredentials on XHR requests for a particular request * type is true or false * * @default false * @param {string} type - one of HTTPRequest.*_TYPE * @param {boolean} value * @memberof module:MediaPlayer * @instance */ function setXHRWithCredentialsForType(type, value) { customParametersModel.setXHRWithCredentialsForType(type, value); } /** * Gets whether withCredentials on XHR requests for a particular request * type is true or false * * @param {string} type - one of HTTPRequest.*_TYPE * @return {boolean} * @memberof module:MediaPlayer * @instance */ function getXHRWithCredentialsForType(type) { return customParametersModel.getXHRWithCredentialsForType(type); } /* --------------------------------------------------------------------------- OFFLINE --------------------------------------------------------------------------- */ /** * Detects if Offline is included and returns an instance of OfflineController.js * @memberof module:MediaPlayer * @instance */ function getOfflineController() { return _detectOffline(); } /* --------------------------------------------------------------------------- METRICS --------------------------------------------------------------------------- */ /** * Returns the DashMetrics.js Module. You use this Module to get access to all the public metrics * stored in dash.js * * @see {@link module:DashMetrics} * @returns {Object} * @memberof module:MediaPlayer * @instance */ function getDashMetrics() { return dashMetrics; } /* --------------------------------------------------------------------------- TEXT MANAGEMENT --------------------------------------------------------------------------- */ /** * Enable/disable text * When enabling text, dash will choose the previous selected text track * * @param {boolean} enable - true to enable text, false otherwise (same as setTextTrack(-1)) * @memberof module:MediaPlayer * @instance */ function enableText(enable) { const activeStreamInfo = streamController.getActiveStreamInfo(); if (!activeStreamInfo || !textController) { return false; } return textController.enableText(activeStreamInfo.id, enable); } /** * Enable/disable text * When enabling dash will keep downloading and process fragmented text tracks even if all tracks are in mode \"hidden\" * * @param {boolean} enable - true to enable text streaming even if all text tracks are hidden. * @memberof module:MediaPlayer * @instance */ function enableForcedTextStreaming(enable) { const activeStreamInfo = streamController.getActiveStreamInfo(); if (!activeStreamInfo || !textController) { return false; } return textController.enableForcedTextStreaming(enable); } /** * Return if text is enabled * * @return {boolean} return true if text is enabled, false otherwise * @memberof module:MediaPlayer * @instance */ function isTextEnabled() { const activeStreamInfo = streamController.getActiveStreamInfo(); if (!activeStreamInfo || !textController) { return false; } return textController.isTextEnabled(activeStreamInfo); } /** * Use this method to change the current text track for both external time text files and fragmented text tracks. There is no need to * set the track mode on the video object to switch a track when using this method. * @param {number} idx - Index of track based on the order of the order the tracks are added Use -1 to disable all tracks. (turn captions off). Use module:MediaPlayer#dashjs.MediaPlayer.events.TEXT_TRACK_ADDED. * @see {@link MediaPlayerEvents#event:TEXT_TRACK_ADDED dashjs.MediaPlayer.events.TEXT_TRACK_ADDED} * @throws {@link module:MediaPlayer~PLAYBACK_NOT_INITIALIZED_ERROR PLAYBACK_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function setTextTrack(idx) { if (!playbackInitialized) { throw PLAYBACK_NOT_INITIALIZED_ERROR; } const activeStreamInfo = streamController.getActiveStreamInfo(); if (!activeStreamInfo || !textController) { return; } textController.setTextTrack(activeStreamInfo.id, idx); } function getCurrentTextTrackIndex() { let idx = NaN; const activeStreamInfo = streamController.getActiveStreamInfo(); if (!activeStreamInfo || !textController) { return; } idx = textController.getCurrentTrackIdx(activeStreamInfo.id); return idx; } /* --------------------------------------------------------------------------- VIDEO ELEMENT MANAGEMENT --------------------------------------------------------------------------- */ /** * Returns instance of Video Element that was attached by calling attachView() * @returns {Object} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~ELEMENT_NOT_ATTACHED_ERROR ELEMENT_NOT_ATTACHED_ERROR} if called before attachView function * @instance */ function getVideoElement() { if (!videoModel.getElement()) { throw ELEMENT_NOT_ATTACHED_ERROR; } return videoModel.getElement(); } /** * Use this method to attach an HTML5 VideoElement for dash.js to operate upon. * * @param {Object} element - An HTMLMediaElement that has already been defined in the DOM (or equivalent stub). * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~MEDIA_PLAYER_NOT_INITIALIZED_ERROR MEDIA_PLAYER_NOT_INITIALIZED_ERROR} if called before initialize function * @instance */ function attachView(element) { if (!mediaPlayerInitialized) { throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR; } videoModel.setElement(element); if (element) { _detectProtection(); _detectMetricsReporting(); _detectMss(); if (streamController) { streamController.switchToVideoElement(); } } if (playbackInitialized) { //Reset if we have been playing before, so this is a new element. _resetPlaybackControllers(); } _initializePlayback(); } /** * Returns instance of Div that was attached by calling attachTTMLRenderingDiv() * @returns {Object} * @memberof module:MediaPlayer * @instance */ function getTTMLRenderingDiv() { return videoModel ? videoModel.getTTMLRenderingDiv() : null; } /** * Use this method to attach an HTML5 div for dash.js to render rich TTML subtitles. * * @param {HTMLDivElement} div - An unstyled div placed after the video element. It will be styled to match the video size and overlay z-order. * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~ELEMENT_NOT_ATTACHED_ERROR ELEMENT_NOT_ATTACHED_ERROR} if called before attachView function * @instance */ function attachTTMLRenderingDiv(div) { if (!videoModel.getElement()) { throw ELEMENT_NOT_ATTACHED_ERROR; } videoModel.setTTMLRenderingDiv(div); } /* --------------------------------------------------------------------------- STREAM AND TRACK MANAGEMENT --------------------------------------------------------------------------- */ /** * @param {MediaType} type * @returns {Array} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getBitrateInfoListFor(type) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } let stream = getActiveStream(); return stream ? stream.getBitrateListFor(type) : []; } /** * This method returns the list of all available streams from a given manifest * @param {Object} manifest * @returns {Array} list of {@link StreamInfo} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getStreamsFromManifest(manifest) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } return adapter.getStreamsInfo(manifest); } /** * This method returns the list of all available tracks for a given media type * @param {MediaType} type * @returns {Array} list of {@link MediaInfo} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getTracksFor(type) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } let streamInfo = streamController.getActiveStreamInfo(); if (!streamInfo) { return []; } return mediaController.getTracksFor(type, streamInfo.id); } /** * This method returns the list of all available tracks for a given media type and streamInfo from a given manifest * @param {MediaType} type * @param {Object} manifest * @param {Object} streamInfo * @returns {Array} list of {@link MediaInfo} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getTracksForTypeFromManifest(type, manifest, streamInfo) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } streamInfo = streamInfo || adapter.getStreamsInfo(manifest, 1)[0]; return streamInfo ? adapter.getAllMediaInfoForType(streamInfo, type, manifest) : []; } /** * @param {MediaType} type * @returns {Object|null} {@link MediaInfo} * * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getCurrentTrackFor(type) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } let streamInfo = streamController.getActiveStreamInfo(); return mediaController.getCurrentTrackFor(type, streamInfo.id); } /** * This method allows to set media settings that will be used to pick the initial track. Format of the settings * is following: &lt;br /&gt; * {lang: langValue (can be either a string primitive, a string object, or a RegExp object to match), * index: indexValue, * viewpoint: viewpointValue, * audioChannelConfiguration: audioChannelConfigurationValue, * accessibility: accessibilityValue, * role: roleValue} * * @param {MediaType} type * @param {Object} value * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~MEDIA_PLAYER_NOT_INITIALIZED_ERROR MEDIA_PLAYER_NOT_INITIALIZED_ERROR} if called before initialize function * @instance */ function setInitialMediaSettingsFor(type, value) { if (!mediaPlayerInitialized) { throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR; } mediaController.setInitialSettings(type, value); } /** * This method returns media settings that is used to pick the initial track. Format of the settings * is following: * {lang: langValue, * index: indexValue, * viewpoint: viewpointValue, * audioChannelConfiguration: audioChannelConfigurationValue, * accessibility: accessibilityValue, * role: roleValue} * @param {MediaType} type * @returns {Object} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~MEDIA_PLAYER_NOT_INITIALIZED_ERROR MEDIA_PLAYER_NOT_INITIALIZED_ERROR} if called before initialize function * @instance */ function getInitialMediaSettingsFor(type) { if (!mediaPlayerInitialized) { throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR; } return mediaController.getInitialSettings(type); } /** * @param {MediaInfo} track - instance of {@link MediaInfo} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function setCurrentTrack(track) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } mediaController.setTrack(track); } /* --------------------------------------------------------------------------- Custom filter and callback functions --------------------------------------------------------------------------- */ /** * Registers a custom capabilities filter. This enables application to filter representations to use. * The provided callback function shall return a boolean based on whether or not to use the representation. * The filters are applied in the order they are registered. * @param {function} filter - the custom capabilities filter callback * @memberof module:MediaPlayer * @instance */ function registerCustomCapabilitiesFilter(filter) { customParametersModel.registerCustomCapabilitiesFilter(filter); } /** * Unregisters a custom capabilities filter. * @param {function} filter - the custom capabilities filter callback * @memberof module:MediaPlayer * @instance */ function unregisterCustomCapabilitiesFilter(filter) { customParametersModel.unregisterCustomCapabilitiesFilter(filter); } /** * Registers a custom initial track selection function. Only one function is allowed. Calling this method will overwrite a potentially existing function. * @param {function} customFunc - the custom function that returns the initial track */ function setCustomInitialTrackSelectionFunction(customFunc) { customParametersModel.setCustomInitialTrackSelectionFunction(customFunc); } /** * Resets the custom initial track selection */ function resetCustomInitialTrackSelectionFunction() { customParametersModel.resetCustomInitialTrackSelectionFunction(null); } /** * Registers a license request filter. This enables application to manipulate/overwrite any request parameter and/or request data. * The provided callback function shall return a promise that shall be resolved once the filter process is completed. * The filters are applied in the order they are registered. * @param {function} filter - the license request filter callback * @memberof module:MediaPlayer * @instance */ function registerLicenseRequestFilter(filter) { customParametersModel.registerLicenseRequestFilter(filter); } /** * Registers a license response filter. This enables application to manipulate/overwrite the response data * The provided callback function shall return a promise that shall be resolved once the filter process is completed. * The filters are applied in the order they are registered. * @param {function} filter - the license response filter callback * @memberof module:MediaPlayer * @instance */ function registerLicenseResponseFilter(filter) { customParametersModel.registerLicenseResponseFilter(filter); } /** * Unregisters a license request filter. * @param {function} filter - the license request filter callback * @memberof module:MediaPlayer * @instance */ function unregisterLicenseRequestFilter(filter) { customParametersModel.unregisterLicenseRequestFilter(filter); } /** * Unregisters a license response filter. * @param {function} filter - the license response filter callback * @memberof module:MediaPlayer * @instance */ function unregisterLicenseResponseFilter(filter) { customParametersModel.unregisterLicenseResponseFilter(filter); } /* --------------------------------------------------------------------------- PROTECTION MANAGEMENT --------------------------------------------------------------------------- */ /** * Detects if Protection is included and returns an instance of ProtectionController.js * @memberof module:MediaPlayer * @instance */ function getProtectionController() { return _detectProtection(); } /** * Will override dash.js protection controller. * @param {ProtectionController} value - valid protection controller instance. * @memberof module:MediaPlayer * @instance */ function attachProtectionController(value) { protectionController = value; } /** * Sets Protection Data required to setup the Protection Module (DRM). Protection Data must * be set before initializing MediaPlayer or, once initialized, before PROTECTION_CREATED event is fired. * @see {@link module:MediaPlayer#initialize initialize()} * @see {@link ProtectionEvents#event:PROTECTION_CREATED dashjs.Protection.events.PROTECTION_CREATED} * @param {ProtectionDataSet} value - object containing * property names corresponding to key system name strings and associated * values being instances of. * @memberof module:MediaPlayer * @instance */ function setProtectionData(value) { protectionData = value; // Propagate changes in case StreamController is already created if (streamController) { streamController.setProtectionData(protectionData); } } /* --------------------------------------------------------------------------- THUMBNAILS MANAGEMENT --------------------------------------------------------------------------- */ /** * Provide the thumbnail at time position. This can be asynchronous, so you must provide a callback ro retrieve thumbnails informations * @param {number} time - A relative time, in seconds, based on the return value of the {@link module:MediaPlayer#duration duration()} method is expected * @param {function} callback - A Callback function provided when retrieving thumbnail the given time position. Thumbnail object is null in case there are is not a thumbnails representation or * if it doesn't contain a thumbnail for the given time position. * @memberof module:MediaPlayer * @instance */ function provideThumbnail(time, callback) { if (typeof callback !== 'function') { return; } if (time &lt; 0) { callback(null); return; } const s = playbackController.getIsDynamic() ? getDVRSeekOffset(time) : time; const stream = streamController.getStreamForTime(s); if (stream === null) { callback(null); return; } const thumbnailController = stream.getThumbnailController(); if (!thumbnailController) { callback(null); return; } return thumbnailController.provide(s, callback); } /* --------------------------------------------------------------------------- TOOLS AND OTHERS FUNCTIONS --------------------------------------------------------------------------- */ /** * Allows application to retrieve a manifest. Manifest loading is asynchro * nous and * requires the app-provided callback function * * @param {string} url - url the manifest url * @param {function} callback - A Callback function provided when retrieving manifests * @memberof module:MediaPlayer * @instance */ function retrieveManifest(url, callback) { let manifestLoader = _createManifestLoader(); let self = this; const handler = function (e) { if (!e.error) { callback(e.manifest); } else { callback(null, e.error); } eventBus.off(Events.INTERNAL_MANIFEST_LOADED, handler, self); manifestLoader.reset(); }; eventBus.on(Events.INTERNAL_MANIFEST_LOADED, handler, self); uriFragmentModel.initialize(url); manifestLoader.load(url); } /** * Returns the source string or manifest that was attached by calling attachSource() * @returns {string | manifest} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~SOURCE_NOT_ATTACHED_ERROR SOURCE_NOT_ATTACHED_ERROR} if called before attachSource function * @instance */ function getSource() { if (!source) { throw SOURCE_NOT_ATTACHED_ERROR; } return source; } /** * Sets the source to a new manifest URL or object without reloading * Useful for updating CDN tokens * @param urlOrManifest */ function updateSource(urlOrManifest) { source = urlOrManifest streamController.load(source); } /** * Use this method to set a source URL to a valid MPD manifest file OR * a previously downloaded and parsed manifest object. Optionally, can * also provide protection information * * @param {string|Object} urlOrManifest - A URL to a valid MPD manifest file, or a * parsed manifest object. * @param {number|string} startTime - For VoD content the start time is relative to the start time of the first period. * For live content * If the parameter starts from prefix posix: it signifies the absolute time range defined in seconds of Coordinated Universal Time (ITU-R TF.460-6). This is the number of seconds since 01-01-1970 00:00:00 UTC. Fractions of seconds may be optionally specified down to the millisecond level. * If no posix prefix is used the starttime is relative to MPD@availabilityStartTime * * @throws {@link module:MediaPlayer~MEDIA_PLAYER_NOT_INITIALIZED_ERROR MEDIA_PLAYER_NOT_INITIALIZED_ERROR} if called before initialize function * * @memberof module:MediaPlayer * @instance */ function attachSource(urlOrManifest, startTime = NaN) { if (!mediaPlayerInitialized) { throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR; } if (typeof urlOrManifest === 'string') { uriFragmentModel.initialize(urlOrManifest); } source = urlOrManifest; if (streamingInitialized || playbackInitialized) { _resetPlaybackControllers(); } if (isReady()) { _initializePlayback(startTime); } } /** * Get the current settings object being used on the player. * @returns {PlayerSettings} The settings object being used. * * @memberof module:MediaPlayer * @instance */ function getSettings() { return settings.get(); } /** * @summary Update the current settings object being used on the player. Anything left unspecified is not modified. * @param {PlayerSettings} settingsObj - An object corresponding to the settings definition. * @description This function does not update the entire object, only properties in the passed in object are updated. * * This means that updateSettings({a: x}) and updateSettings({b: y}) are functionally equivalent to * updateSettings({a: x, b: y}). If the default values are required again, @see{@link resetSettings}. * @example * player.updateSettings({ * streaming: { * lowLatencyEnabled: false, * abr: { * maxBitrate: { audio: 100, video: 1000 } * } * } * }); * @memberof module:MediaPlayer * @instance */ function updateSettings(settingsObj) { settings.update(settingsObj); } /** * Resets the settings object back to the default. * * @memberof module:MediaPlayer * @instance */ function resetSettings() { settings.reset(); } /** * A utility methods which converts UTC timestamp value into a valid time and date string. * * @param {number} time - UTC timestamp to be converted into date and time. * @param {string} locales - a region identifier (i.e. en_US). * @param {boolean} hour12 - 12 vs 24 hour. Set to true for 12 hour time formatting. * @param {boolean} withDate - default is false. Set to true to append current date to UTC time format. * @returns {string} A formatted time and date string. * @memberof module:MediaPlayer * @instance */ function formatUTC(time, locales, hour12, withDate = false) { const dt = new Date(time * 1000); const d = dt.toLocaleDateString(locales); const t = dt.toLocaleTimeString(locales, { hour12: hour12 }); return withDate ? t + ' ' + d : t; } /** * A utility method which converts seconds into TimeCode (i.e. 300 --&gt; 05:00). * * @param {number} value - A number in seconds to be converted into a formatted time code. * @returns {string} A formatted time code string. * @memberof module:MediaPlayer * @instance */ function convertToTimeCode(value) { value = Math.max(value, 0); let h = Math.floor(value / 3600); let m = Math.floor((value % 3600) / 60); let s = Math.floor((value % 3600) % 60); return (h === 0 ? '' : (h &lt; 10 ? '0' + h.toString() + ':' : h.toString() + ':')) + (m &lt; 10 ? '0' + m.toString() : m.toString()) + ':' + (s &lt; 10 ? '0' + s.toString() : s.toString()); } /** * This method should be used to extend or replace internal dash.js objects. * There are two ways to extend dash.js (determined by the override argument): * &lt;ol&gt; * &lt;li&gt;If you set override to true any public method or property in your custom object will * override the dash.js parent object's property(ies) and will be used instead but the * dash.js parent module will still be created.&lt;/li&gt; * * &lt;li&gt;If you set override to false your object will completely replace the dash.js object. * (Note: This is how it was in 1.x of Dash.js with Dijon).&lt;/li&gt; * &lt;/ol&gt; * &lt;b&gt;When you extend you get access to this.context, this.factory and this.parent to operate with in your custom object.&lt;/b&gt; * &lt;ul&gt; * &lt;li&gt;&lt;b&gt;this.context&lt;/b&gt; - can be used to pass context for singleton access.&lt;/li&gt; * &lt;li&gt;&lt;b&gt;this.factory&lt;/b&gt; - can be used to call factory.getSingletonInstance().&lt;/li&gt; * &lt;li&gt;&lt;b&gt;this.parent&lt;/b&gt; - is the reference of the parent object to call other public methods. (this.parent is excluded if you extend with override set to false or option 2)&lt;/li&gt; * &lt;/ul&gt; * &lt;b&gt;You must call extend before you call initialize&lt;/b&gt; * @see {@link module:MediaPlayer#initialize initialize()} * @param {string} parentNameString - name of parent module * @param {Object} childInstance - overriding object * @param {boolean} override - replace only some methods (true) or the whole object (false) * @memberof module:MediaPlayer * @instance */ function extend(parentNameString, childInstance, override) { FactoryMaker.extend(parentNameString, childInstance, override, context); } /** * This method returns the active stream * * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @memberof module:MediaPlayer * @instance */ function getActiveStream() { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } let streamInfo = streamController.getActiveStreamInfo(); return streamInfo ? streamController.getStreamById(streamInfo.id) : null; } /** * Returns the DashAdapter.js Module. * * @see {@link module:DashAdapter} * @returns {Object} * @memberof module:MediaPlayer * @instance */ function getDashAdapter() { return adapter; } /** * Triggers a request to the content steering server to update the steering information. * @return {Promise&lt;any&gt;} */ function triggerSteeringRequest() { if (contentSteeringController) { return contentSteeringController.loadSteeringData(); } } /** * Returns the current response data of the content steering server * @return {object} */ function getCurrentSteeringResponseData() { if(contentSteeringController) { return contentSteeringController.getCurrentSteeringResponseData(); } } //*********************************** // PRIVATE METHODS //*********************************** function _resetPlaybackControllers() { playbackInitialized = false; streamingInitialized = false; adapter.reset(); streamController.reset(); gapController.reset(); catchupController.reset(); playbackController.reset(); serviceDescriptionController.reset(); contentSteeringController.reset(); abrController.reset(); mediaController.reset(); segmentBaseController.reset(); if (protectionController) { if (settings.get().streaming.protection.keepProtectionMediaKeys) { protectionController.stop(); } else { protectionController.reset(); protectionController = null; _detectProtection(); } } textController.reset(); cmcdModel.reset(); } function _createPlaybackControllers() { // creates or get objects instances const manifestLoader = _createManifestLoader(); if (!streamController) { streamController = StreamController(context).getInstance(); } if (!textController) { textController = TextController(context).create({ errHandler, manifestModel, adapter, mediaController, videoModel, settings }); } capabilitiesFilter.setConfig({ capabilities, customParametersModel, adapter, settings, manifestModel, errHandler }); streamController.setConfig({ capabilities, capabilitiesFilter, manifestLoader, manifestModel, mediaPlayerModel, customParametersModel, protectionController, textController, adapter, dashMetrics, errHandler, timelineConverter, videoModel, playbackController, serviceDescriptionController, contentSteeringController, abrController, mediaController, settings, baseURLController, uriFragmentModel, segmentBaseController }); gapController.setConfig({ settings, playbackController, streamController, videoModel, timelineConverter, adapter }); playbackController.setConfig({ streamController, serviceDescriptionController, dashMetrics, adapter, videoModel, timelineConverter, settings }); catchupController.setConfig({ streamController, playbackController, mediaPlayerModel, videoModel, settings }) abrController.setConfig({ streamController, domStorage, mediaPlayerModel, customParametersModel, dashMetrics, adapter, videoModel, settings }); cmcdModel.setConfig({ abrController, dashMetrics, playbackController }); contentSteeringController.setConfig({ adapter, errHandler, dashMetrics, mediaPlayerModel, manifestModel, abrController, eventBus, requestModifier: RequestModifier(context).getInstance() }) // initialises controller abrController.initialize(); streamController.initialize(autoPlay, protectionData); textController.initialize(); gapController.initialize(); catchupController.initialize(); cmcdModel.initialize(); contentSteeringController.initialize(); segmentBaseController.initialize(); } function _createManifestLoader() { return ManifestLoader(context).create({ debug: debug, errHandler: errHandler, dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, requestModifier: RequestModifier(context).getInstance(), mssHandler: mssHandler, settings: settings }); } function _detectProtection() { if (protectionController) { return protectionController; } // do not require Protection as dependencies as this is optional and intended to be loaded separately let Protection = dashjs.Protection; /* jshint ignore:line */ if (typeof Protection === 'function') { //TODO need a better way to register/detect plugin components let protection = Protection(context).create(); Events.extend(Protection.events); MediaPlayerEvents.extend(Protection.events, { publicOnly: true }); Errors.extend(Protection.errors); if (!capabilities) { capabilities = Capabilities(context).getInstance(); } protectionController = protection.createProtectionSystem({ debug, errHandler, videoModel, customParametersModel, capabilities, eventBus, events: Events, BASE64, constants: Constants, cmcdModel, settings }); return protectionController; } return null; } function _detectMetricsReporting() { if (metricsReportingController) { return; } // do not require MetricsReporting as dependencies as this is optional and intended to be loaded separately let MetricsReporting = dashjs.MetricsReporting; /* jshint ignore:line */ if (typeof MetricsReporting === 'function') { //TODO need a better way to register/detect plugin components let metricsReporting = MetricsReporting(context).create(); metricsReportingController = metricsReporting.createMetricsReporting({ debug: debug, eventBus: eventBus, mediaElement: getVideoElement(), adapter: adapter, dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, events: Events, constants: Constants, metricsConstants: MetricsConstants }); } } function _detectMss() { if (mssHandler) { return; } // do not require MssHandler as dependencies as this is optional and intended to be loaded separately let MssHandler = dashjs.MssHandler; /* jshint ignore:line */ if (typeof MssHandler === 'function') { //TODO need a better way to register/detect plugin components Errors.extend(MssHandler.errors); mssHandler = MssHandler(context).create({ eventBus: eventBus, mediaPlayerModel: mediaPlayerModel, dashMetrics: dashMetrics, manifestModel: manifestModel, playbackController: playbackController, streamController: streamController, protectionController: protectionController, baseURLController: baseURLController, errHandler: errHandler, events: Events, constants: Constants, debug: debug, initSegmentType: HTTPRequest.INIT_SEGMENT_TYPE, BASE64: BASE64, ISOBoxer: ISOBoxer, settings: settings }); } } function _detectOffline() { if (!mediaPlayerInitialized) { throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR; } if (offlineController) { return offlineController; } // do not require Offline as dependencies as this is optional and intended to be loaded separately let OfflineController = dashjs.OfflineController; /* jshint ignore:line */ if (typeof OfflineController === 'function') { //TODO need a better way to register/detect plugin components Events.extend(OfflineController.events); MediaPlayerEvents.extend(OfflineController.events, { publicOnly: true }); Errors.extend(OfflineController.errors); const manifestLoader = _createManifestLoader(); const manifestUpdater = ManifestUpdater(context).create(); manifestUpdater.setConfig({ manifestModel: manifestModel, adapter: adapter, manifestLoader: manifestLoader, errHandler: errHandler }); offlineController = OfflineController(context).create({ debug: debug, manifestUpdater: manifestUpdater, baseURLController: baseURLController, manifestLoader: manifestLoader, manifestModel: manifestModel, mediaPlayerModel: mediaPlayerModel, abrController: abrController, playbackController: playbackController, adapter: adapter, errHandler: errHandler, dashMetrics: dashMetrics, timelineConverter: timelineConverter, segmentBaseController: segmentBaseController, schemeLoaderFactory: schemeLoaderFactory, eventBus: eventBus, events: Events, errors: Errors, constants: Constants, settings: settings, dashConstants: DashConstants, urlUtils: URLUtils(context).getInstance() }); return offlineController; } return null; } function _getAsUTC(valToConvert) { const type = streamController &amp;&amp; streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO; let metric = dashMetrics.getCurrentDVRInfo(type); let availableFrom, utcValue; if (!metric) { return 0; } availableFrom = metric.manifestInfo.availableFrom.getTime() / 1000; utcValue = valToConvert + (availableFrom + metric.range.start); return utcValue; } /** * * @private */ function _initializePlayback(startTime = NaN) { if (offlineController) { offlineController.resetRecords(); } if (!streamingInitialized &amp;&amp; source) { streamingInitialized = true; logger.info('Streaming Initialized'); _createPlaybackControllers(); if (typeof source === 'string') { streamController.load(source, startTime); } else { streamController.loadWithManifest(source, startTime); } } if (!playbackInitialized &amp;&amp; isReady()) { playbackInitialized = true; logger.info('Playback Initialized'); } } instance = { initialize, setConfig, on, off, extend, attachView, attachSource, isReady, play, isPaused, pause, isSeeking, isDynamic, getLowLatencyModeEnabled, seek, seekToOriginalLive, setPlaybackRate, getPlaybackRate, setMute, isMuted, setVolume, getVolume, time, duration, timeAsUTC, durationAsUTC, getActiveStream, getDVRWindowSize, getDVRSeekOffset, getTargetLiveDelay, convertToTimeCode, formatUTC, getVersion, getDebug, getBufferLength, getTTMLRenderingDiv, getVideoElement, getSource, updateSource, getCurrentLiveLatency, getTopBitrateInfoFor, setAutoPlay, getAutoPlay, getDashMetrics, getQualityFor, setQualityFor, updatePortalSize, enableText, enableForcedTextStreaming, isTextEnabled, setTextTrack, getBitrateInfoListFor, getStreamsFromManifest, getTracksFor, getTracksForTypeFromManifest, getCurrentTrackFor, setInitialMediaSettingsFor, getInitialMediaSettingsFor, setCurrentTrack, addABRCustomRule, removeABRCustomRule, removeAllABRCustomRule, getABRCustomRules, getAverageThroughput, retrieveManifest, addUTCTimingSource, removeUTCTimingSource, clearDefaultUTCTimingSources, restoreDefaultUTCTimingSources, setXHRWithCredentialsForType, getXHRWithCredentialsForType, getProtectionController, attachProtectionController, setProtectionData, registerLicenseRequestFilter, registerLicenseResponseFilter, unregisterLicenseRequestFilter, unregisterLicenseResponseFilter, registerCustomCapabilitiesFilter, unregisterCustomCapabilitiesFilter, setCustomInitialTrackSelectionFunction, resetCustomInitialTrackSelectionFunction, attachTTMLRenderingDiv, getCurrentTextTrackIndex, provideThumbnail, getDashAdapter, getOfflineController, triggerSteeringRequest, getCurrentSteeringResponseData, getSettings, updateSettings, resetSettings, reset, destroy }; setup(); return instance; } MediaPlayer.__dashjs_factory_name = 'MediaPlayer'; const factory = FactoryMaker.getClassFactory(MediaPlayer); factory.events = MediaPlayerEvents; factory.errors = Errors; FactoryMaker.updateClassFactory(MediaPlayer.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_metrics_MetricsReportingEvents.js.html":{"id":"streaming_metrics_MetricsReportingEvents.js.html","title":"Source: streaming/metrics/MetricsReportingEvents.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/metrics/MetricsReportingEvents.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import EventsBase from '../../core/events/EventsBase'; /** * @class * @implements EventsBase */ class MetricsReportingEvents extends EventsBase { constructor () { super(); this.METRICS_INITIALISATION_COMPLETE = 'internal_metricsReportingInitialized'; this.BECAME_REPORTING_PLAYER = 'internal_becameReportingPlayer'; /** * Triggered when CMCD data was generated for a HTTP request * @event MetricsReportingEvents#CMCD_DATA_GENERATED */ this.CMCD_DATA_GENERATED = 'cmcdDataGenerated'; } } let metricsReportingEvents = new MetricsReportingEvents(); export default metricsReportingEvents; × Search results Close "},"streaming_metrics_MetricsReporting.js.html":{"id":"streaming_metrics_MetricsReporting.js.html","title":"Source: streaming/metrics/MetricsReporting.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/metrics/MetricsReporting.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import DVBErrorsTranslator from './utils/DVBErrorsTranslator'; import MetricsReportingEvents from './MetricsReportingEvents'; import MetricsCollectionController from './controllers/MetricsCollectionController'; import MetricsHandlerFactory from './metrics/MetricsHandlerFactory'; import ReportingFactory from './reporting/ReportingFactory'; function MetricsReporting() { let context = this.context; let instance, dvbErrorsTranslator; /** * Create a MetricsCollectionController, and a DVBErrorsTranslator * @param {Object} config - dependancies from owner * @return {MetricsCollectionController} Metrics Collection Controller */ function createMetricsReporting(config) { dvbErrorsTranslator = DVBErrorsTranslator(context).getInstance({ eventBus: config.eventBus, dashMetrics: config.dashMetrics, metricsConstants: config.metricsConstants, events: config.events }); dvbErrorsTranslator.initialise(); return MetricsCollectionController(context).create(config); } /** * Get the ReportingFactory to allow new reporters to be registered * @return {ReportingFactory} Reporting Factory */ function getReportingFactory() { return ReportingFactory(context).getInstance(); } /** * Get the MetricsHandlerFactory to allow new handlers to be registered * @return {MetricsHandlerFactory} Metrics Handler Factory */ function getMetricsHandlerFactory() { return MetricsHandlerFactory(context).getInstance(); } instance = { createMetricsReporting: createMetricsReporting, getReportingFactory: getReportingFactory, getMetricsHandlerFactory: getMetricsHandlerFactory }; return instance; } MetricsReporting.__dashjs_factory_name = 'MetricsReporting'; const factory = dashjs.FactoryMaker.getClassFactory(MetricsReporting); /* jshint ignore:line */ factory.events = MetricsReportingEvents; dashjs.FactoryMaker.updateClassFactory(MetricsReporting.__dashjs_factory_name, factory); /* jshint ignore:line */ export default factory; × Search results Close "},"streaming_constants_ConformanceViolationConstants.js.html":{"id":"streaming_constants_ConformanceViolationConstants.js.html","title":"Source: streaming/constants/ConformanceViolationConstants.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/constants/ConformanceViolationConstants.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ export default { LEVELS: { SUGGESTION: 'Suggestion', WARNING: 'Warning', ERROR: 'Error' }, EVENTS: { NO_UTC_TIMING_ELEMENT: { key: 'NO_UTC_TIMING_ELEMENT', message: 'No UTCTiming element is present in the manifest. You may experience playback failures. For a detailed validation use https://conformance.dashif.org/' }, NON_COMPLIANT_SMPTE_IMAGE_ATTRIBUTE: { key: 'NON_COMPLIANT_SMPTE_IMAGE_ATTRIBUTE', message: 'SMPTE 2052-1:2013 defines the attribute name as \"imageType\" and does not define \"imagetype\"' }, INVALID_DVR_WINDOW: { key: 'INVALID_DVR_WINDOW', message: 'No valid segment found when applying a specification compliant DVR window calculation. Using SegmentTimeline entries as a fallback.' } } }; × Search results Close "},"dash_DashAdapter.js.html":{"id":"dash_DashAdapter.js.html","title":"Source: dash/DashAdapter.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: dash/DashAdapter.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import DashConstants from './constants/DashConstants'; import RepresentationInfo from './vo/RepresentationInfo'; import MediaInfo from './vo/MediaInfo'; import StreamInfo from './vo/StreamInfo'; import ManifestInfo from './vo/ManifestInfo'; import Event from './vo/Event'; import FactoryMaker from '../core/FactoryMaker'; import DashManifestModel from './models/DashManifestModel'; import PatchManifestModel from './models/PatchManifestModel'; import bcp47Normalize from 'bcp-47-normalize'; /** * @module DashAdapter * @description The DashAdapter module can be accessed using the MediaPlayer API getDashAdapter() */ function DashAdapter() { let instance, dashManifestModel, patchManifestModel, voPeriods, currentMediaInfo, constants, cea608parser; const context = this.context; const PROFILE_DVB = 'urn:dvb:dash:profile:dvb-dash:2014'; function setup() { dashManifestModel = DashManifestModel(context).getInstance(); patchManifestModel = PatchManifestModel(context).getInstance(); reset(); } // #region PUBLIC FUNCTIONS // -------------------------------------------------- function setConfig(config) { if (!config) return; if (config.constants) { constants = config.constants; } if (config.cea608parser) { cea608parser = config.cea608parser; } if (config.errHandler) { dashManifestModel.setConfig({ errHandler: config.errHandler }); } if (config.BASE64) { dashManifestModel.setConfig({ BASE64: config.BASE64 }); } } /** * Creates an instance of RepresentationInfo based on a representation value object * @param {object} voRepresentation * @returns {RepresentationInfo|null} representationInfo * @memberOf module:DashAdapter * @instance * @ignore */ function convertRepresentationToRepresentationInfo(voRepresentation) { if (voRepresentation) { let representationInfo = new RepresentationInfo(); const realAdaptation = voRepresentation.adaptation.period.mpd.manifest.Period_asArray[voRepresentation.adaptation.period.index].AdaptationSet_asArray[voRepresentation.adaptation.index]; const realRepresentation = dashManifestModel.getRepresentationFor(voRepresentation.index, realAdaptation); representationInfo.id = voRepresentation.id; representationInfo.quality = voRepresentation.index; representationInfo.bandwidth = dashManifestModel.getBandwidth(realRepresentation); representationInfo.fragmentDuration = voRepresentation.segmentDuration || (voRepresentation.segments &amp;&amp; voRepresentation.segments.length &gt; 0 ? voRepresentation.segments[0].duration : NaN); representationInfo.MSETimeOffset = voRepresentation.MSETimeOffset; representationInfo.mediaInfo = convertAdaptationToMediaInfo(voRepresentation.adaptation); return representationInfo; } else { return null; } } /** * Returns a MediaInfo object for a given media type and the corresponding streamInfo. * @param {object} streamInfo * @param {MediaType }type * @returns {null|MediaInfo} mediaInfo * @memberOf module:DashAdapter * @instance */ function getMediaInfoForType(streamInfo, type) { if (voPeriods.length === 0 || !streamInfo) { return null; } let selectedVoPeriod = getPeriodForStreamInfo(streamInfo, voPeriods); if (!selectedVoPeriod) return null; const voAdaptations = dashManifestModel.getAdaptationsForPeriod(selectedVoPeriod); let realAdaptation = getAdaptationForType(streamInfo.index, type, streamInfo); if (!realAdaptation) return null; let idx = dashManifestModel.getIndexForAdaptation(realAdaptation, voPeriods[0].mpd.manifest, streamInfo.index); return convertAdaptationToMediaInfo(voAdaptations[idx]); } /** * Checks if the role of the specified AdaptationSet is set to main * @param {object} adaptation * @returns {boolean} * @memberOf module:DashAdapter * @instance */ function getIsMain(adaptation) { return dashManifestModel.getRolesForAdaptation(adaptation).filter(function (role) { return role.value === DashConstants.MAIN; })[0]; } /** * Returns the AdaptationSet for a given period index and a given mediaType. * @param {number} periodIndex * @param {MediaType} type * @param {object} streamInfo * @returns {null|object} adaptation * @memberOf module:DashAdapter * @instance */ function getAdaptationForType(periodIndex, type, streamInfo) { const adaptations = dashManifestModel.getAdaptationsForType(voPeriods[0].mpd.manifest, periodIndex, type); if (!adaptations || adaptations.length === 0) return null; if (adaptations.length &gt; 1 &amp;&amp; streamInfo) { const allMediaInfoForType = getAllMediaInfoForType(streamInfo, type); if (currentMediaInfo[streamInfo.id] &amp;&amp; currentMediaInfo[streamInfo.id][type]) { for (let i = 0, ln = adaptations.length; i &lt; ln; i++) { if (areMediaInfosEqual(currentMediaInfo[streamInfo.id][type], allMediaInfoForType[i])) { return adaptations[i]; } } } for (let i = 0, ln = adaptations.length; i &lt; ln; i++) { if (getIsMain(adaptations[i])) { return adaptations[i]; } } } return adaptations[0]; } /** * Compares two mediaInfo objects * @param {MediaInfo} mInfoOne * @param {MediaInfo} mInfoTwo * @returns {boolean} */ function areMediaInfosEqual(mInfoOne, mInfoTwo) { if (!mInfoOne || !mInfoTwo) { return false; } const sameId = mInfoOne.id === mInfoTwo.id; const sameCodec = mInfoOne.codec === mInfoTwo.codec; const sameViewpoint = mInfoOne.viewpoint === mInfoTwo.viewpoint; const sameLang = mInfoOne.lang === mInfoTwo.lang; const sameRoles = mInfoOne.roles.toString() === mInfoTwo.roles.toString(); const sameAccessibility = mInfoOne.accessibility.toString() === mInfoTwo.accessibility.toString(); const sameAudioChannelConfiguration = mInfoOne.audioChannelConfiguration.toString() === mInfoTwo.audioChannelConfiguration.toString(); return (sameId &amp;&amp; sameCodec &amp;&amp; sameViewpoint &amp;&amp; sameLang &amp;&amp; sameRoles &amp;&amp; sameAccessibility &amp;&amp; sameAudioChannelConfiguration); } function _getAllMediaInfo(manifest, period, streamInfo, adaptations, type, embeddedText) { let mediaArr = []; let data, media, idx, i, j, ln; if (!adaptations || adaptations.length === 0) { return []; } const voAdaptations = dashManifestModel.getAdaptationsForPeriod(period); for (i = 0, ln = adaptations.length; i &lt; ln; i++) { data = adaptations[i]; idx = dashManifestModel.getIndexForAdaptation(data, manifest, streamInfo.index); media = convertAdaptationToMediaInfo(voAdaptations[idx]); if (embeddedText) { let accessibilityLength = media.accessibility.length; for (j = 0; j &lt; accessibilityLength; j++) { if (!media) { continue; } let accessibility = media.accessibility[j]; if (accessibility.indexOf('cea-608:') === 0) { let value = accessibility.substring(8); let parts = value.split(';'); if (parts[0].substring(0, 2) === 'CC') { for (j = 0; j &lt; parts.length; j++) { if (!media) { media = convertAdaptationToMediaInfo.call(this, voAdaptations[idx]); } convertVideoInfoToEmbeddedTextInfo(media, parts[j].substring(0, 3), parts[j].substring(4)); mediaArr.push(media); media = null; } } else { for (j = 0; j &lt; parts.length; j++) { // Only languages for CC1, CC2, ... if (!media) { media = convertAdaptationToMediaInfo.call(this, voAdaptations[idx]); } convertVideoInfoToEmbeddedTextInfo(media, 'CC' + (j + 1), parts[j]); mediaArr.push(media); media = null; } } } else if (accessibility.indexOf('cea-608') === 0) { // Nothing known. We interpret it as CC1=eng convertVideoInfoToEmbeddedTextInfo(media, constants.CC1, 'eng'); mediaArr.push(media); media = null; } } } else if (type === constants.IMAGE) { convertVideoInfoToThumbnailInfo(media); mediaArr.push(media); media = null; } else if (media) { mediaArr.push(media); } } return mediaArr; } /** * Returns all the mediaInfos for a given mediaType and the corresponding streamInfo. * @param {object} streamInfo * @param {MediaType} type * @param {object} externalManifest Set to null or undefined if no external manifest is to be used * @returns {Array} mediaArr * @memberOf module:DashAdapter * @instance */ function getAllMediaInfoForType(streamInfo, type, externalManifest) { let voLocalPeriods = voPeriods; let manifest = externalManifest; let mediaArr = []; if (manifest) { checkConfig(); voLocalPeriods = getRegularPeriods(manifest); } else { if (voPeriods.length &gt; 0) { manifest = voPeriods[0].mpd.manifest; } else { return mediaArr; } } const selectedVoPeriod = getPeriodForStreamInfo(streamInfo, voLocalPeriods); let adaptationsForType = dashManifestModel.getAdaptationsForType(manifest, streamInfo ? streamInfo.index : null, type); mediaArr = _getAllMediaInfo(manifest, selectedVoPeriod, streamInfo, adaptationsForType, type); // Search for embedded text in video track if (type === constants.TEXT) { adaptationsForType = dashManifestModel.getAdaptationsForType(manifest, streamInfo ? streamInfo.index : null, constants.VIDEO); mediaArr = mediaArr.concat(_getAllMediaInfo(manifest, selectedVoPeriod, streamInfo, adaptationsForType, type, true)); } return mediaArr; } /** * Update the internal voPeriods array with the information from the new manifest * @param {object} newManifest * @returns {*} * @memberOf module:DashAdapter * @instance * @ignore */ function updatePeriods(newManifest) { if (!newManifest) return null; checkConfig(); voPeriods = getRegularPeriods(newManifest); } /** * Returns an array of streamInfo objects * @param {object} externalManifest * @param {number} maxStreamsInfo * @returns {Array} streams * @memberOf module:DashAdapter * @instance * @ignore */ function getStreamsInfo(externalManifest, maxStreamsInfo) { const streams = []; let voLocalPeriods = voPeriods; //if manifest is defined, getStreamsInfo is for an outside manifest, not the current one if (externalManifest) { checkConfig(); voLocalPeriods = getRegularPeriods(externalManifest); } if (voLocalPeriods.length &gt; 0) { if (!maxStreamsInfo || maxStreamsInfo &gt; voLocalPeriods.length) { maxStreamsInfo = voLocalPeriods.length; } for (let i = 0; i &lt; maxStreamsInfo; i++) { streams.push(convertPeriodToStreamInfo(voLocalPeriods[i])); } } return streams; } /** * Returns the AdaptationSet as saved in the DashManifestModel * @param {object} streamInfo * @param {object} mediaInfo * @returns {object} realAdaptation * @memberOf module:DashAdapter * @instance */ function getRealAdaptation(streamInfo, mediaInfo) { let id, realAdaptation; const selectedVoPeriod = getPeriodForStreamInfo(streamInfo, voPeriods); id = mediaInfo ? mediaInfo.id : null; if (voPeriods.length &gt; 0 &amp;&amp; selectedVoPeriod) { realAdaptation = id ? dashManifestModel.getAdaptationForId(id, voPeriods[0].mpd.manifest, selectedVoPeriod.index) : dashManifestModel.getAdaptationForIndex(mediaInfo ? mediaInfo.index : null, voPeriods[0].mpd.manifest, selectedVoPeriod.index); } return realAdaptation; } /** * Returns the ProducerReferenceTimes as saved in the DashManifestModel if present * @param {object} streamInfo * @param {object} mediaInfo * @returns {object} producerReferenceTimes * @memberOf module:DashAdapter * @instance */ function getProducerReferenceTimes(streamInfo, mediaInfo) { let id, realAdaptation; const selectedVoPeriod = getPeriodForStreamInfo(streamInfo, voPeriods); id = mediaInfo ? mediaInfo.id : null; if (voPeriods.length &gt; 0 &amp;&amp; selectedVoPeriod) { realAdaptation = id ? dashManifestModel.getAdaptationForId(id, voPeriods[0].mpd.manifest, selectedVoPeriod.index) : dashManifestModel.getAdaptationForIndex(mediaInfo ? mediaInfo.index : null, voPeriods[0].mpd.manifest, selectedVoPeriod.index); } if (!realAdaptation) return []; return dashManifestModel.getProducerReferenceTimesForAdaptation(realAdaptation); } /** * Return all EssentialProperties of a Representation * @param {object} representation * @return {array} */ function getEssentialPropertiesForRepresentation(representation) { try { return dashManifestModel.getEssentialPropertiesForRepresentation(representation); } catch (e) { return []; } } /** * Returns the period as defined in the DashManifestModel for a given index * @param {number} index * @return {object} */ function getRealPeriodByIndex(index) { return dashManifestModel.getRealPeriodForIndex(index, voPeriods[0].mpd.manifest); } /** * Returns all voRepresentations for a given mediaInfo * @param {object} mediaInfo * @returns {Array} voReps * @memberOf module:DashAdapter * @instance */ function getVoRepresentations(mediaInfo) { let voReps; const voAdaptation = getAdaptationForMediaInfo(mediaInfo); voReps = dashManifestModel.getRepresentationsForAdaptation(voAdaptation); return voReps; } /** * Returns the event for the given parameters. * @param {object} eventBox * @param {object} eventStreams * @param {number} mediaStartTime - Specified in seconds * @param {object} voRepresentation * @returns {null|Event} * @memberOf module:DashAdapter * @instance * @ignore */ function getEvent(eventBox, eventStreams, mediaStartTime, voRepresentation) { try { if (!eventBox || !eventStreams || isNaN(mediaStartTime) || !voRepresentation) { return null; } const schemeIdUri = eventBox.scheme_id_uri; const value = eventBox.value; if (!eventStreams[schemeIdUri + '/' + value]) { return null; } const event = new Event(); const timescale = eventBox.timescale || 1; const periodStart = voRepresentation.adaptation.period.start; const eventStream = eventStreams[schemeIdUri + '/' + value]; // The PTO in voRepresentation is already specified in seconds const presentationTimeOffset = !isNaN(voRepresentation.presentationTimeOffset) ? voRepresentation.presentationTimeOffset : !isNaN(eventStream.presentationTimeOffset) ? eventStream.presentationTimeOffset : 0; // In case of version 1 events the presentation_time is parsed as presentation_time_delta let presentationTimeDelta = eventBox.presentation_time_delta / timescale; let calculatedPresentationTime; if (eventBox.version === 0) { calculatedPresentationTime = periodStart + mediaStartTime - presentationTimeOffset + presentationTimeDelta; } else { calculatedPresentationTime = periodStart - presentationTimeOffset + presentationTimeDelta; } const duration = eventBox.event_duration / timescale; const id = eventBox.id; const messageData = eventBox.message_data; event.eventStream = eventStream; 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; } catch (e) { return null; } } /** * Returns the events for the given info object. info can either be an instance of StreamInfo, MediaInfo or RepresentationInfo * @param {object} info * @param {object} voRepresentation * @returns {Array} * @memberOf module:DashAdapter * @instance * @ignore */ function getEventsFor(info, voRepresentation, streamInfo) { let events = []; if (voPeriods.length &gt; 0) { const manifest = voPeriods[0].mpd.manifest; if (info instanceof StreamInfo) { const period = getPeriodForStreamInfo(info, voPeriods) events = dashManifestModel.getEventsForPeriod(period); } else if (info instanceof MediaInfo) { const period = getPeriodForStreamInfo(streamInfo, voPeriods) events = dashManifestModel.getEventStreamForAdaptationSet(manifest, getAdaptationForMediaInfo(info), period); } else if (info instanceof RepresentationInfo) { const period = getPeriodForStreamInfo(streamInfo, voPeriods) events = dashManifestModel.getEventStreamForRepresentation(manifest, voRepresentation, period); } } return events; } /** * Sets the current active mediaInfo for a given streamId and a given mediaType * @param {number} streamId * @param {MediaType} type * @param {object} mediaInfo * @memberOf module:DashAdapter * @instance * @ignore */ function setCurrentMediaInfo(streamId, type, mediaInfo) { currentMediaInfo[streamId] = currentMediaInfo[streamId] || {}; currentMediaInfo[streamId][type] = currentMediaInfo[streamId][type] || {}; currentMediaInfo[streamId][type] = mediaInfo; } /** * Check if the given type is a text track * @param {object} adaptation * @returns {boolean} * @memberOf module:DashAdapter * @instance * @ignore */ function getIsTextTrack(adaptation) { return dashManifestModel.getIsText(adaptation); } /** * Returns the UTC Timing Sources specified in the manifest * @returns {Array} utcTimingSources * @memberOf module:DashAdapter * @instance */ function getUTCTimingSources() { const manifest = getManifest(); return dashManifestModel.getUTCTimingSources(manifest); } /** * Returns the suggestedPresentationDelay as specified in the manifest * @returns {String} suggestedPresentationDelay * @memberOf module:DashAdapter * @instance */ function getSuggestedPresentationDelay() { const mpd = voPeriods.length &gt; 0 ? voPeriods[0].mpd : null; return dashManifestModel.getSuggestedPresentationDelay(mpd); } /** * Returns the availabilityStartTime as specified in the manifest * @param {object} externalManifest Omit this value if no external manifest should be used * @returns {string} availabilityStartTime * @memberOf module:DashAdapter * @instance */ function getAvailabilityStartTime(externalManifest) { const mpd = getMpd(externalManifest); return dashManifestModel.getAvailabilityStartTime(mpd); } /** * Returns a boolean indicating if the manifest is dynamic or not * @param {object} externalManifest Omit this value if no external manifest should be used * @returns {boolean} * @memberOf module:DashAdapter * @instance */ function getIsDynamic(externalManifest) { const manifest = getManifest(externalManifest); return dashManifestModel.getIsDynamic(manifest); } /** * Returns the duration of the MPD * @param {object} externalManifest Omit this value if no external manifest should be used * @returns {number} duration * @memberOf module:DashAdapter * @instance */ function getDuration(externalManifest) { const manifest = getManifest(externalManifest); return dashManifestModel.getDuration(manifest); } /** * Returns all periods of the MPD * @param {object} externalManifest Omit this value if no external manifest should be used * @returns {Array} periods * @memberOf module:DashAdapter * @instance */ function getRegularPeriods(externalManifest) { const mpd = getMpd(externalManifest); return dashManifestModel.getRegularPeriods(mpd); } /** * Returns an MPD object * @param {object} externalManifest Omit this value if no external manifest should be used * @returns {object} MPD * @memberOf module:DashAdapter * @instance */ function getMpd(externalManifest) { const manifest = getManifest(externalManifest); return dashManifestModel.getMpd(manifest); } /** * Returns the ContentSteering element of the MPD * @param {object} manifest * @returns {object} contentSteering * @memberOf module:DashAdapter * @instance */ function getContentSteering(manifest) { return dashManifestModel.getContentSteering(manifest); } /** * Returns the location element of the MPD * @param {object} manifest * @returns {String} location * @memberOf module:DashAdapter * @instance */ function getLocation(manifest) { return dashManifestModel.getLocation(manifest); } /** * Returns the manifest update period used for dynamic manifests * @param {object} manifest * @param {number} latencyOfLastUpdate * @returns {NaN|number} manifestUpdatePeriod * @memberOf module:DashAdapter * @instance */ function getManifestUpdatePeriod(manifest, latencyOfLastUpdate = 0) { return dashManifestModel.getManifestUpdatePeriod(manifest, latencyOfLastUpdate); } /** * Returns the publish time from the manifest * @param {object} manifest * @returns {Date|null} publishTime * @memberOf module:DashAdapter * @instance */ function getPublishTime(manifest) { return dashManifestModel.getPublishTime(manifest); } /** * Returns the patch location of the MPD if one exists and it is still valid * @param {object} manifest * @returns {(String|null)} patch location * @memberOf module:DashAdapter * @instance */ function getPatchLocation(manifest) { const patchLocation = dashManifestModel.getPatchLocation(manifest); const publishTime = dashManifestModel.getPublishTime(manifest); // short-circuit when no patch location or publish time exists if (!patchLocation || !publishTime) { return null; } // if a ttl is provided, ensure patch location has not expired if (patchLocation.hasOwnProperty('ttl') &amp;&amp; publishTime) { // attribute describes number of seconds as a double const ttl = parseFloat(patchLocation.ttl) * 1000; // check if the patch location has expired, if so do not consider it if (publishTime.getTime() + ttl &lt;= new Date().getTime()) { return null; } } // the patch location exists and, if a ttl applies, has not expired return patchLocation.__text; } /** * Checks if the manifest has a DVB profile * @param {object} manifest * @returns {boolean} * @memberOf module:DashAdapter * @instance * @ignore */ function getIsDVB(manifest) { return dashManifestModel.hasProfile(manifest, PROFILE_DVB); } /** * Checks if the manifest is actually just a patch manifest * @param {object} manifest * @return {boolean} */ function getIsPatch(manifest) { return patchManifestModel.getIsPatch(manifest); } /** * Returns the base urls for a given element * @param {object} node * @returns {Array} * @memberOf module:DashAdapter * @instance * @ignore */ function getBaseURLsFromElement(node) { return dashManifestModel.getBaseURLsFromElement(node); } /** * Returns the function to sort the Representations * @returns {*} * @memberOf module:DashAdapter * @instance * @ignore */ function getRepresentationSortFunction() { return dashManifestModel.getRepresentationSortFunction(); } /** * Returns the codec for a given adaptation set and a given representation id. * @param {object} adaptation * @param {number} representationId * @param {boolean} addResolutionInfo Defines whether to include resolution information in the output * @returns {String} codec * @memberOf module:DashAdapter * @instance */ function getCodec(adaptation, representationId, addResolutionInfo) { return dashManifestModel.getCodec(adaptation, representationId, addResolutionInfo); } /** * Returns the bandwidth for a given representation id and the corresponding period index * @param {number} representationId * @param {number} periodIdx * @returns {number} bandwidth * @memberOf module:DashAdapter * @instance */ function getBandwidthForRepresentation(representationId, periodIdx) { let representation; let period = getPeriod(periodIdx); representation = findRepresentation(period, representationId); return representation ? representation.bandwidth : null; } /** * Returns the index for a given representation id * @param {string} representationId * @param {number} periodIdx * @returns {number} index * @memberOf module:DashAdapter * @instance */ function getIndexForRepresentation(representationId, periodIdx) { let period = getPeriod(periodIdx); return findRepresentationIndex(period, representationId); } /** * This method returns the current max index based on what is defined in the MPD. * @param {string} bufferType - String 'audio' or 'video', * @param {number} periodIdx - Make sure this is the period index not id * @return {number} * @memberof module:DashAdapter * @instance */ function getMaxIndexForBufferType(bufferType, periodIdx) { let period = getPeriod(periodIdx); return findMaxBufferIndex(period, bufferType); } /** * Returns the voPeriod object for a given id * @param {String} id * @returns {object|null} */ function getPeriodById(id) { if (!id || voPeriods.length === 0) { return null; } const periods = voPeriods.filter((p) =&gt; { return p.id === id; }); if (periods &amp;&amp; periods.length &gt; 0) { return periods[0]; } return null; } /** * Checks if the given AdaptationSet is from the given media type * @param {object} adaptation * @param {string} type * @return {boolean} */ function getIsTypeOf(adaptation, type) { return dashManifestModel.getIsTypeOf(adaptation, type); } function reset() { voPeriods = []; currentMediaInfo = {}; } /** * Checks if the supplied manifest is compatible for application of the supplied patch * @param {object} manifest * @param {object} patch * @return {boolean} */ function isPatchValid(manifest, patch) { let manifestId = dashManifestModel.getId(manifest); let patchManifestId = patchManifestModel.getMpdId(patch); let manifestPublishTime = dashManifestModel.getPublishTime(manifest); let patchPublishTime = patchManifestModel.getPublishTime(patch); let originalManifestPublishTime = patchManifestModel.getOriginalPublishTime(patch); // Patches are considered compatible if the following are true // - MPD@id == Patch@mpdId // - MPD@publishTime == Patch@originalPublishTime // - MPD@publishTime &lt; Patch@publishTime // - All values in comparison exist return !!(manifestId &amp;&amp; patchManifestId &amp;&amp; (manifestId == patchManifestId) &amp;&amp; manifestPublishTime &amp;&amp; originalManifestPublishTime &amp;&amp; (manifestPublishTime.getTime() == originalManifestPublishTime.getTime()) &amp;&amp; patchPublishTime &amp;&amp; (manifestPublishTime.getTime() &lt; patchPublishTime.getTime())); } /** * Takes a given patch and applies it to the provided manifest, assumes patch is valid for manifest * @param {object} manifest * @param {object} patch */ function applyPatchToManifest(manifest, patch) { // get all operations from the patch and apply them in document order patchManifestModel.getPatchOperations(patch) .forEach((operation) =&gt; { let result = operation.getMpdTarget(manifest); // operation supplies a path that doesn't match mpd, skip if (result === null) { return; } let { name, target, leaf } = result; // short circuit for attribute selectors if (operation.xpath.findsAttribute()) { switch (operation.action) { case 'add': case 'replace': // add and replace are just setting the value target[name] = operation.value; break; case 'remove': // remove is deleting the value delete target[name]; break; } return; } // determine the relative insert position prior to possible removal let relativePosition = (target[name + '_asArray'] || []).indexOf(leaf); let insertBefore = (operation.position === 'prepend' || operation.position === 'before'); // perform removal operation first, we have already capture the appropriate relative position if (operation.action === 'remove' || operation.action === 'replace') { // note that we ignore the 'ws' attribute of patch operations as it does not effect parsed mpd operations // purge the directly named entity delete target[name]; // if we did have a positional reference we need to purge from array set and restore X2JS proper semantics if (relativePosition != -1) { let targetArray = target[name + '_asArray']; targetArray.splice(relativePosition, 1); if (targetArray.length &gt; 1) { target[name] = targetArray; } else if (targetArray.length == 1) { // xml parsing semantics, singular asArray must be non-array in the unsuffixed key target[name] = targetArray[0]; } else { // all nodes of this type deleted, remove entry delete target[name + '_asArray']; } } } // Perform any add/replace operations now, technically RFC5261 only allows a single element to take the // place of a replaced element while the add case allows an arbitrary number of children. // Due to the both operations requiring the same insertion logic they have been combined here and we will // not enforce single child operations for replace, assertions should be made at patch parse time if necessary if (operation.action === 'add' || operation.action === 'replace') { // value will be an object with element name keys pointing to arrays of objects Object.keys(operation.value).forEach((insert) =&gt; { let insertNodes = operation.value[insert]; let updatedNodes = target[insert + '_asArray'] || []; if (updatedNodes.length === 0 &amp;&amp; target[insert]) { updatedNodes.push(target[insert]); } if (updatedNodes.length === 0) { // no original nodes for this element type updatedNodes = insertNodes; } else { // compute the position we need to insert at, default to end of set let position = updatedNodes.length; if (insert == name &amp;&amp; relativePosition != -1) { // if the inserted element matches the operation target (not leaf) and there is a relative position we // want the inserted position to be set such that our insertion is relative to original position // since replace has modified the array length we reduce the insert point by 1 position = relativePosition + (insertBefore ? 0 : 1) + (operation.action == 'replace' ? -1 : 0); } else { // otherwise we are in an add append/prepend case or replace case that removed the target name completely position = insertBefore ? 0 : updatedNodes.length; } // we dont have to perform element removal for the replace case as that was done above updatedNodes.splice.apply(updatedNodes, [position, 0].concat(insertNodes)); } // now we properly reset the element keys on the target to match parsing semantics target[insert + '_asArray'] = updatedNodes; target[insert] = updatedNodes.length == 1 ? updatedNodes[0] : updatedNodes; }); } }); } // #endregion PUBLIC FUNCTIONS // #region PRIVATE FUNCTIONS // -------------------------------------------------- function getManifest(externalManifest) { return externalManifest ? externalManifest : voPeriods.length &gt; 0 ? voPeriods[0].mpd.manifest : null; } function getAdaptationForMediaInfo(mediaInfo) { try { const selectedVoPeriod = getPeriodForStreamInfo(mediaInfo.streamInfo, voPeriods); const voAdaptations = dashManifestModel.getAdaptationsForPeriod(selectedVoPeriod); if (!mediaInfo || !mediaInfo.streamInfo || mediaInfo.streamInfo.id === undefined || !voAdaptations) return null; return voAdaptations[mediaInfo.index]; } catch (e) { return null; } } function getPeriodForStreamInfo(streamInfo, voPeriodsArray) { const ln = voPeriodsArray.length; for (let i = 0; i &lt; ln; i++) { let voPeriod = voPeriodsArray[i]; if (streamInfo &amp;&amp; streamInfo.id === voPeriod.id) return voPeriod; } return null; } function convertAdaptationToMediaInfo(adaptation) { if (!adaptation) { return null; } let mediaInfo = new MediaInfo(); const realAdaptation = adaptation.period.mpd.manifest.Period_asArray[adaptation.period.index].AdaptationSet_asArray[adaptation.index]; let viewpoint; mediaInfo.id = adaptation.id; mediaInfo.index = adaptation.index; mediaInfo.type = adaptation.type; mediaInfo.streamInfo = convertPeriodToStreamInfo(adaptation.period); mediaInfo.representationCount = dashManifestModel.getRepresentationCount(realAdaptation); mediaInfo.labels = dashManifestModel.getLabelsForAdaptation(realAdaptation); mediaInfo.lang = dashManifestModel.getLanguageForAdaptation(realAdaptation); viewpoint = dashManifestModel.getViewpointForAdaptation(realAdaptation); mediaInfo.viewpoint = viewpoint ? viewpoint.value : undefined; mediaInfo.accessibility = dashManifestModel.getAccessibilityForAdaptation(realAdaptation).map(function (accessibility) { let accessibilityValue = accessibility.value; let accessibilityData = accessibilityValue; if (accessibility.schemeIdUri &amp;&amp; (accessibility.schemeIdUri.search('cea-608') &gt;= 0) &amp;&amp; typeof (cea608parser) !== 'undefined') { if (accessibilityValue) { accessibilityData = 'cea-608:' + accessibilityValue; } else { accessibilityData = 'cea-608'; } mediaInfo.embeddedCaptions = true; } return accessibilityData; }); mediaInfo.audioChannelConfiguration = dashManifestModel.getAudioChannelConfigurationForAdaptation(realAdaptation).map(function (audioChannelConfiguration) { return audioChannelConfiguration.value; }); if (mediaInfo.audioChannelConfiguration.length === 0 &amp;&amp; Array.isArray(realAdaptation.Representation_asArray) &amp;&amp; realAdaptation.Representation_asArray.length &gt; 0) { mediaInfo.audioChannelConfiguration = dashManifestModel.getAudioChannelConfigurationForRepresentation(realAdaptation.Representation_asArray[0]).map(function (audioChannelConfiguration) { return audioChannelConfiguration.value; }); } mediaInfo.roles = dashManifestModel.getRolesForAdaptation(realAdaptation).map(function (role) { return role.value; }); mediaInfo.codec = dashManifestModel.getCodec(realAdaptation); mediaInfo.mimeType = dashManifestModel.getMimeType(realAdaptation); mediaInfo.contentProtection = dashManifestModel.getContentProtectionData(realAdaptation); mediaInfo.bitrateList = dashManifestModel.getBitrateListForAdaptation(realAdaptation); mediaInfo.selectionPriority = dashManifestModel.getSelectionPriority(realAdaptation); if (mediaInfo.contentProtection) { // Get the default key ID and apply it to all key systems const keyIds = mediaInfo.contentProtection.map(cp =&gt; dashManifestModel.getKID(cp)).filter(kid =&gt; kid !== null); if (keyIds.length) { const keyId = keyIds[0]; mediaInfo.contentProtection.forEach(cp =&gt; { cp.keyId = keyId; }); } } mediaInfo.isText = dashManifestModel.getIsText(realAdaptation); mediaInfo.supplementalProperties = dashManifestModel.getSupplementalProperties(realAdaptation); mediaInfo.isFragmented = dashManifestModel.getIsFragmented(realAdaptation); mediaInfo.isEmbedded = false; return mediaInfo; } function convertVideoInfoToEmbeddedTextInfo(mediaInfo, channel, lang) { mediaInfo.id = channel; // CC1, CC2, CC3, or CC4 mediaInfo.index = 100 + parseInt(channel.substring(2, 3)); mediaInfo.type = constants.TEXT; mediaInfo.codec = 'cea-608-in-SEI'; mediaInfo.isEmbedded = true; mediaInfo.isFragmented = false; mediaInfo.lang = bcp47Normalize(lang); mediaInfo.roles = ['caption']; } function convertVideoInfoToThumbnailInfo(mediaInfo) { mediaInfo.type = constants.IMAGE; } function convertPeriodToStreamInfo(period) { let streamInfo = new StreamInfo(); const THRESHOLD = 1; streamInfo.id = period.id; streamInfo.index = period.index; streamInfo.start = period.start; streamInfo.duration = period.duration; streamInfo.manifestInfo = convertMpdToManifestInfo(period.mpd); streamInfo.isLast = period.mpd.manifest.Period_asArray.length === 1 || Math.abs((streamInfo.start + streamInfo.duration) - streamInfo.manifestInfo.duration) &lt; THRESHOLD; return streamInfo; } function convertMpdToManifestInfo(mpd) { let manifestInfo = new ManifestInfo(); manifestInfo.dvrWindowSize = mpd.timeShiftBufferDepth; manifestInfo.loadedTime = mpd.manifest.loadedTime; manifestInfo.availableFrom = mpd.availabilityStartTime; manifestInfo.minBufferTime = mpd.manifest.minBufferTime; manifestInfo.maxFragmentDuration = mpd.maxSegmentDuration; manifestInfo.duration = dashManifestModel.getDuration(mpd.manifest); manifestInfo.isDynamic = dashManifestModel.getIsDynamic(mpd.manifest); manifestInfo.serviceDescriptions = dashManifestModel.getServiceDescriptions(mpd.manifest); manifestInfo.protocol = mpd.manifest.protocol; return manifestInfo; } function checkConfig() { if (!constants) { throw new Error('setConfig function has to be called previously'); } } function getPeriod(periodIdx) { return voPeriods.length &gt; 0 ? voPeriods[0].mpd.manifest.Period_asArray[periodIdx] : null; } function findRepresentationIndex(period, representationId) { const index = findRepresentation(period, representationId, true); return index !== null ? index : -1; } function findRepresentation(period, representationId, returnIndex) { let adaptationSet, adaptationSetArray, representation, representationArray, adaptationSetArrayIndex, representationArrayIndex; if (period) { adaptationSetArray = period.AdaptationSet_asArray; for (adaptationSetArrayIndex = 0; adaptationSetArrayIndex &lt; adaptationSetArray.length; adaptationSetArrayIndex = adaptationSetArrayIndex + 1) { adaptationSet = adaptationSetArray[adaptationSetArrayIndex]; representationArray = adaptationSet.Representation_asArray; for (representationArrayIndex = 0; representationArrayIndex &lt; representationArray.length; representationArrayIndex = representationArrayIndex + 1) { representation = representationArray[representationArrayIndex]; if (representationId === representation.id) { if (returnIndex) { return representationArrayIndex; } else { return representation; } } } } } return null; } function findMaxBufferIndex(period, bufferType) { let adaptationSet, adaptationSetArray, representationArray, adaptationSetArrayIndex; if (!period || !bufferType) return -1; adaptationSetArray = period.AdaptationSet_asArray; for (adaptationSetArrayIndex = 0; adaptationSetArrayIndex &lt; adaptationSetArray.length; adaptationSetArrayIndex = adaptationSetArrayIndex + 1) { adaptationSet = adaptationSetArray[adaptationSetArrayIndex]; representationArray = adaptationSet.Representation_asArray; if (dashManifestModel.getIsTypeOf(adaptationSet, bufferType)) { return representationArray.length; } } return -1; } // #endregion PRIVATE FUNCTIONS instance = { getBandwidthForRepresentation, getIndexForRepresentation, getMaxIndexForBufferType, convertRepresentationToRepresentationInfo, getStreamsInfo, getMediaInfoForType, getAllMediaInfoForType, getAdaptationForType, getRealAdaptation, getProducerReferenceTimes, getRealPeriodByIndex, getEssentialPropertiesForRepresentation, getVoRepresentations, getEventsFor, getEvent, getMpd, setConfig, updatePeriods, getIsTextTrack, getUTCTimingSources, getSuggestedPresentationDelay, getAvailabilityStartTime, getIsTypeOf, getIsDynamic, getDuration, getRegularPeriods, getContentSteering, getLocation, getPatchLocation, getManifestUpdatePeriod, getPublishTime, getIsDVB, getIsPatch, getBaseURLsFromElement, getRepresentationSortFunction, getCodec, getPeriodById, setCurrentMediaInfo, isPatchValid, applyPatchToManifest, areMediaInfosEqual, reset }; setup(); return instance; } DashAdapter.__dashjs_factory_name = 'DashAdapter'; export default FactoryMaker.getSingletonFactory(DashAdapter); × Search results Close "},"dash_DashMetrics.js.html":{"id":"dash_DashMetrics.js.html","title":"Source: dash/DashMetrics.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: dash/DashMetrics.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../streaming/constants/Constants'; import { HTTPRequest } from '../streaming/vo/metrics/HTTPRequest'; import FactoryMaker from '../core/FactoryMaker'; import MetricsConstants from '../streaming/constants/MetricsConstants'; import Round10 from './utils/Round10'; import MetricsModel from '../streaming/models/MetricsModel'; import Utils from '../core/Utils'; import { PlayList, PlayListTrace } from '../streaming/vo/metrics/PlayList'; /** * @module DashMetrics * @description The DashMetrics module can be accessed using the MediaPlayer API getDashMetrics() * @param {object} config */ function DashMetrics(config) { config = config || {}; const context = this.context; let instance, playListTraceMetricsClosed, playListTraceMetrics, playListMetrics; let metricsModel = config.metricsModel; function setup() { metricsModel = metricsModel || MetricsModel(context).getInstance({settings: config.settings}); resetInitialSettings(); } function resetInitialSettings() { playListTraceMetricsClosed = true; playListTraceMetrics = null; playListMetrics = null; } /** * Returns the latest Representation switch for a given media type * @param {MediaType} mediaType * @returns {*} * @memberof module:DashMetrics * @instance */ function getCurrentRepresentationSwitch(mediaType) { const metrics = metricsModel.getMetricsFor(mediaType, true); return getCurrent(metrics, MetricsConstants.TRACK_SWITCH); } /** * @param {MediaType} mediaType * @param {Date} t time of the switch event * @param {Date} mt media presentation time * @param {string} to id of representation * @param {string} lto if present, subrepresentation reference * @memberof module:DashMetrics * @instance * @ignore */ function addRepresentationSwitch(mediaType, t, mt, to, lto) { metricsModel.addRepresentationSwitch(mediaType, t, mt, to, lto); } /** * Returns the current buffer state for a given media type * @param {MediaType} mediaType * @returns {number} * @memberof module:DashMetrics * @instance */ function getCurrentBufferState(mediaType) { const metrics = metricsModel.getMetricsFor(mediaType, true); return getCurrent(metrics, MetricsConstants.BUFFER_STATE); } /** * Returns the current buffer level for a given media type * @param {MediaType} mediaType * @returns {number} * @memberof module:DashMetrics * @instance */ function getCurrentBufferLevel(mediaType) { const metrics = metricsModel.getMetricsFor(mediaType, true); const metric = getCurrent(metrics, MetricsConstants.BUFFER_LEVEL); if (metric) { return Round10.round10(metric.level / 1000, -3); } return 0; } /** * @param {MediaType} mediaType * @param {number} t * @param {number} level * @memberof module:DashMetrics * @instance * @ignore */ function addBufferLevel(mediaType, t, level) { metricsModel.addBufferLevel(mediaType, t, level); } /** * @param {MediaType} mediaType * @param {string} state * @param {number} target * @memberof module:DashMetrics * @instance * @ignore */ function addBufferState(mediaType, state, target) { metricsModel.addBufferState(mediaType, state, target); } /** * @memberof module:DashMetrics * @instance * @ignore */ function clearAllCurrentMetrics () { metricsModel.clearAllCurrentMetrics(); } /** * Returns the latest HTTP request for a given media type * @param {MediaType} mediaType * @returns {*} * @memberof module:DashMetrics * @instance */ function getCurrentHttpRequest(mediaType) { const metrics = metricsModel.getMetricsFor(mediaType, true); if (!metrics) { return null; } const httpList = metrics.HttpList; let currentHttpList = null; let httpListLastIndex; if (!httpList || httpList.length &lt;= 0) { return null; } httpListLastIndex = httpList.length - 1; while (httpListLastIndex &gt;= 0) { if (httpList[httpListLastIndex].responsecode) { currentHttpList = httpList[httpListLastIndex]; break; } httpListLastIndex--; } return currentHttpList; } /** * Returns all HTTP requests for a given media type * @param {MediaType} mediaType * @returns {*} * @memberof module:DashMetrics * @instance */ function getHttpRequests(mediaType) { const metrics = metricsModel.getMetricsFor(mediaType, true); if (!metrics) { return []; } return !!metrics.HttpList ? metrics.HttpList : []; } /** * @param {MediaType} mediaType * @param {Array} loadingRequests * @param {Array} executedRequests * @memberof module:DashMetrics * @instance * @ignore */ function addRequestsQueue(mediaType, loadingRequests, executedRequests) { metricsModel.addRequestsQueue(mediaType, loadingRequests, executedRequests); } /** * Returns the latest metrics for a given metric list and specific metric name * @param {MetricsList} metrics * @param {string} metricName * @returns {*} * @memberof module:DashMetrics * @instance */ function getCurrent(metrics, metricName) { if (!metrics) { return null; } const list = metrics[metricName]; return (!list || list.length === 0) ? null : list[list.length - 1]; } /** * Returns the number of dropped frames * @returns {*} * @memberof module:DashMetrics * @instance */ function getCurrentDroppedFrames() { const metrics = metricsModel.getMetricsFor(Constants.VIDEO, true); return getCurrent(metrics, MetricsConstants.DROPPED_FRAMES); } /** * @param {number} quality * @memberof module:DashMetrics * @instance * @ignore */ function addDroppedFrames(quality) { metricsModel.addDroppedFrames(Constants.VIDEO, quality); } /** * Returns the current scheduling info for a given media type * @param {MediaType} mediaType * @returns {*} * @memberof module:DashMetrics * @instance */ function getCurrentSchedulingInfo(mediaType) { const metrics = metricsModel.getMetricsFor(mediaType, true); return getCurrent(metrics, MetricsConstants.SCHEDULING_INFO); } /** * @param {object} request * @param {string} state * @memberof module:DashMetrics * @instance * @ignore */ function addSchedulingInfo(request, state) { metricsModel.addSchedulingInfo( request.mediaType, new Date(), request.type, request.startTime, request.availabilityStartTime, request.duration, request.quality, request.range, state); } /** * Returns the current manifest update information * @returns {*} * @memberof module:DashMetrics * @instance */ function getCurrentManifestUpdate() { const streamMetrics = metricsModel.getMetricsFor(Constants.STREAM); return getCurrent(streamMetrics, MetricsConstants.MANIFEST_UPDATE); } /** * @param {object} updatedFields fields to be updated * @memberof module:DashMetrics * @instance * @ignore */ function updateManifestUpdateInfo(updatedFields) { const manifestUpdate = this.getCurrentManifestUpdate(); metricsModel.updateManifestUpdateInfo(manifestUpdate, updatedFields); } /** * @param {object} streamInfo * @memberof module:DashMetrics * @instance * @ignore */ function addManifestUpdateStreamInfo(streamInfo) { if (streamInfo) { const manifestUpdate = this.getCurrentManifestUpdate(); metricsModel.addManifestUpdateStreamInfo(manifestUpdate, streamInfo.id, streamInfo.index, streamInfo.start, streamInfo.duration); } } /** * @param {object} request * @memberof module:DashMetrics * @instance * @ignore */ function addManifestUpdate(request) { metricsModel.addManifestUpdate(Constants.STREAM, request.type, request.requestStartDate, request.requestEndDate); } /** * @param {object} request * @param {string} responseURL * @param {number} responseStatus * @param {object} responseHeaders * @param {object} traces * @memberof module:DashMetrics * @instance * @ignore */ function addHttpRequest(request, responseURL, responseStatus, responseHeaders, traces) { metricsModel.addHttpRequest(request.mediaType, null, request.type, request.url, request.quality, responseURL, request.serviceLocation || null, request.range || null, request.requestStartDate, request.firstByteDate, request.requestEndDate, responseStatus, request.duration, responseHeaders, traces, request.fileLoaderType); } /** * @param {object} representation * @param {MediaType} mediaType * @memberof module:DashMetrics * @instance * @ignore */ function addManifestUpdateRepresentationInfo(representation, mediaType) { if (representation) { const manifestUpdateInfo = this.getCurrentManifestUpdate(); metricsModel.addManifestUpdateRepresentationInfo(manifestUpdateInfo, representation.id, representation.index, representation.streamIndex, mediaType, representation.presentationTimeOffset, representation.startNumber, representation.fragmentInfoType); } } /** * Returns the current DVR window * @param {MediaType} mediaType * @returns {*} * @memberof module:DashMetrics * @instance */ function getCurrentDVRInfo(mediaType) { const metrics = mediaType ? metricsModel.getMetricsFor(mediaType, true) : metricsModel.getMetricsFor(Constants.VIDEO, true) || metricsModel.getMetricsFor(Constants.AUDIO, true); return getCurrent(metrics, MetricsConstants.DVR_INFO); } /** * @param {MediaType} mediaType * @param {Date} currentTime time of the switch event * @param {object} mpd mpd reference * @param {object} range range of the dvr info * @memberof module:DashMetrics * @instance * @ignore */ function addDVRInfo(mediaType, currentTime, mpd, range) { metricsModel.addDVRInfo(mediaType, currentTime, mpd, range); } /** * Returns the value for a specific request headers used in the latest MPD request * @param {string} id * @returns {*} * @memberof module:DashMetrics * @instance */ function getLatestMPDRequestHeaderValueByID(id) { if (!id) { return null; } let headers = {}; let httpRequestList, httpRequest, i; httpRequestList = getHttpRequests(Constants.STREAM); for (i = httpRequestList.length - 1; i &gt;= 0; i--) { httpRequest = httpRequestList[i]; if (httpRequest.type === HTTPRequest.MPD_TYPE) { headers = Utils.parseHttpHeaders(httpRequest._responseHeaders); break; } } const value = headers[id.toLowerCase()]; return value === undefined ? null : value; } /** * Returns the value for a specific request headers used in the latest fragment request * @param {MediaType} mediaType * @param {string} id * @returns {*} * @memberof module:DashMetrics * @instance */ function getLatestFragmentRequestHeaderValueByID(mediaType, id) { if (!id) { return null; } let headers = {}; let httpRequest = getCurrentHttpRequest(mediaType); if (httpRequest) { headers = Utils.parseHttpHeaders(httpRequest._responseHeaders); } const value = headers[id.toLowerCase()]; return value === undefined ? null : value; } /** * @memberof module:DashMetrics * @instance * @ignore */ function addPlayList() { if (playListMetrics) { metricsModel.addPlayList(playListMetrics); playListMetrics = null; } } /** * Create a new playlist metric * @param {number} mediaStartTime * @param {string} startReason * @ignore */ function createPlaylistMetrics(mediaStartTime, startReason) { playListMetrics = new PlayList(); playListMetrics.start = new Date(); playListMetrics.mstart = mediaStartTime; playListMetrics.starttype = startReason; } /** * Create a playlist trace metric * @param {number} representationId * @param {number} mediaStartTime * @param {number} speed * @ignore */ function createPlaylistTraceMetrics(representationId, mediaStartTime, speed) { if (playListTraceMetricsClosed === true ) { playListTraceMetricsClosed = false; playListTraceMetrics = new PlayListTrace(); playListTraceMetrics.representationid = representationId; playListTraceMetrics.start = new Date(); playListTraceMetrics.mstart = mediaStartTime; playListTraceMetrics.playbackspeed = speed !== null ? speed.toString() : null; } } /** * Update existing playlist trace metric * @param {object} traceToUpdate * @ignore */ function updatePlayListTraceMetrics(traceToUpdate) { if (playListTraceMetrics) { for (let field in playListTraceMetrics) { playListTraceMetrics[field] = traceToUpdate[field]; } } } /** * Push a new playlist trace metric * @param endTime * @param reason * @ignore */ function pushPlayListTraceMetrics(endTime, reason) { if (playListTraceMetricsClosed === false &amp;&amp; playListMetrics &amp;&amp; playListTraceMetrics &amp;&amp; playListTraceMetrics.start) { const startTime = playListTraceMetrics.start; const duration = endTime.getTime() - startTime.getTime(); playListTraceMetrics.duration = duration; playListTraceMetrics.stopreason = reason; playListMetrics.trace.push(playListTraceMetrics); playListTraceMetricsClosed = true; } } /** * @param {object} errors * @memberof module:DashMetrics * @instance * @ignore */ function addDVBErrors(errors) { metricsModel.addDVBErrors(errors); } instance = { getCurrentRepresentationSwitch, getCurrentBufferState, getCurrentBufferLevel, getCurrentHttpRequest, getHttpRequests, getCurrentDroppedFrames, getCurrentSchedulingInfo, getCurrentDVRInfo, getCurrentManifestUpdate, getLatestFragmentRequestHeaderValueByID, getLatestMPDRequestHeaderValueByID, addRepresentationSwitch, addDVRInfo, updateManifestUpdateInfo, addManifestUpdateStreamInfo, addManifestUpdateRepresentationInfo, addManifestUpdate, addHttpRequest, addSchedulingInfo, addRequestsQueue, addBufferLevel, addBufferState, addDroppedFrames, addPlayList, addDVBErrors, createPlaylistMetrics, createPlaylistTraceMetrics, updatePlayListTraceMetrics, pushPlayListTraceMetrics, clearAllCurrentMetrics }; setup(); return instance; } DashMetrics.__dashjs_factory_name = 'DashMetrics'; export default FactoryMaker.getSingletonFactory(DashMetrics); × Search results Close "},"core_Debug.js.html":{"id":"core_Debug.js.html","title":"Source: core/Debug.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: core/Debug.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import EventBus from './EventBus'; import Events from './events/Events'; import FactoryMaker from './FactoryMaker'; const LOG_LEVEL_NONE = 0; const LOG_LEVEL_FATAL = 1; const LOG_LEVEL_ERROR = 2; const LOG_LEVEL_WARNING = 3; const LOG_LEVEL_INFO = 4; const LOG_LEVEL_DEBUG = 5; /** * @module Debug * @param {object} config * @ignore */ function Debug(config) { config = config || {}; const context = this.context; const eventBus = EventBus(context).getInstance(); const settings = config.settings; const logFn = []; let instance, showLogTimestamp, showCalleeName, startTime; function setup() { showLogTimestamp = true; showCalleeName = true; startTime = new Date().getTime(); if (typeof window !== 'undefined' &amp;&amp; window.console) { logFn[LOG_LEVEL_FATAL] = getLogFn(window.console.error); logFn[LOG_LEVEL_ERROR] = getLogFn(window.console.error); logFn[LOG_LEVEL_WARNING] = getLogFn(window.console.warn); logFn[LOG_LEVEL_INFO] = getLogFn(window.console.info); logFn[LOG_LEVEL_DEBUG] = getLogFn(window.console.debug); } } function getLogFn(fn) { if (fn &amp;&amp; fn.bind) { return fn.bind(window.console); } // if not define, return the default function for reporting logs return window.console.log.bind(window.console); } /** * Retrieves a logger which can be used to write logging information in browser console. * @param {object} instance Object for which the logger is created. It is used * to include calle object information in log messages. * @memberof module:Debug * @returns {Logger} * @instance */ function getLogger(instance) { return { fatal: fatal.bind(instance), error: error.bind(instance), warn: warn.bind(instance), info: info.bind(instance), debug: debug.bind(instance) }; } /** * Prepends a timestamp in milliseconds to each log message. * @param {boolean} value Set to true if you want to see a timestamp in each log message. * @default LOG_LEVEL_WARNING * @memberof module:Debug * @instance */ 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. * @default true * @memberof module:Debug * @instance */ function setCalleeNameVisible(value) { showCalleeName = value; } function fatal(...params) { doLog(LOG_LEVEL_FATAL, this, ...params); } function error(...params) { doLog(LOG_LEVEL_ERROR, this, ...params); } function warn(...params) { doLog(LOG_LEVEL_WARNING, this, ...params); } function info(...params) { doLog(LOG_LEVEL_INFO, this, ...params); } function debug(...params) { doLog(LOG_LEVEL_DEBUG, this, ...params); } function doLog(level, _this, ...params) { let message = ''; let logTime = null; if (showLogTimestamp) { logTime = new Date().getTime(); message += '[' + (logTime - startTime) + ']'; } if (showCalleeName &amp;&amp; _this &amp;&amp; _this.getClassName) { message += '[' + _this.getClassName() + ']'; if (_this.getType) { message += '[' + _this.getType() + ']'; } } if (message.length &gt; 0) { message += ' '; } Array.apply(null, params).forEach(function (item) { message += item + ' '; }); // log to console if the log level is high enough if (logFn[level] &amp;&amp; settings.get().debug.logLevel &gt;= level) { logFn[level](message); } // send log event regardless of log level if (settings &amp;&amp; settings.get().debug.dispatchEvent) { eventBus.trigger(Events.LOG, { message: message, level: level }); } } instance = { getLogger: getLogger, setLogTimestampVisible: setLogTimestampVisible, setCalleeNameVisible: setCalleeNameVisible }; setup(); return instance; } Debug.__dashjs_factory_name = 'Debug'; const factory = FactoryMaker.getSingletonFactory(Debug); factory.LOG_LEVEL_NONE = LOG_LEVEL_NONE; factory.LOG_LEVEL_FATAL = LOG_LEVEL_FATAL; factory.LOG_LEVEL_ERROR = LOG_LEVEL_ERROR; factory.LOG_LEVEL_WARNING = LOG_LEVEL_WARNING; factory.LOG_LEVEL_INFO = LOG_LEVEL_INFO; factory.LOG_LEVEL_DEBUG = LOG_LEVEL_DEBUG; FactoryMaker.updateSingletonFactory(Debug.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_utils_DefaultURLUtils.js.html":{"id":"streaming_utils_DefaultURLUtils.js.html","title":"Source: streaming/utils/DefaultURLUtils.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/DefaultURLUtils.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; /** * @module DefaultURLUtils * @description Provides utility functions for operating on URLs. * Initially this is simply a method to determine the Base URL of a URL, but * should probably include other things provided all over the place such as * determining whether a URL is relative/absolute, resolving two paths etc. * @ignore */ function DefaultURLUtils() { let resolveFunction; const schemeRegex = /^[a-z][a-z0-9+\\-_.]*:/i; const httpUrlRegex = /^https?:\\/\\//i; const httpsUrlRegex = /^https:\\/\\//i; const originRegex = /^([a-z][a-z0-9+\\-_.]*:\\/\\/[^\\/]+)\\/?/i; /** * Resolves a url given an optional base url * Uses window.URL to do the resolution. * * @param {string} url * @param {string} [baseUrl] * @return {string} * @memberof module:DefaultURLUtils * @instance * @private */ const nativeURLResolver = (url, baseUrl) =&gt; { try { return new window.URL(url, baseUrl).toString(); } catch (e) { return url; } }; /** * Resolves a url given an optional base url * Does not resolve ./, ../ etc but will do enough to construct something * which will satisfy XHR etc when window.URL is not available ie * IE11/node etc. * * @param {string} url * @param {string} [baseUrl] * @return {string} * @memberof module:DefaultURLUtils * @instance * @private */ const dumbURLResolver = (url, baseUrl) =&gt; { let baseUrlParseFunc = parseBaseUrl; if (!baseUrl) { return url; } if (!isRelative(url)) { return url; } if (isPathAbsolute(url)) { baseUrlParseFunc = parseOrigin; } if (isSchemeRelative(url)) { baseUrlParseFunc = parseScheme; } const base = baseUrlParseFunc(baseUrl); const joinChar = base.charAt(base.length - 1) !== '/' &amp;&amp; url.charAt(0) !== '/' ? '/' : ''; return [base, url].join(joinChar); }; function setup() { try { const u = new window.URL('x', 'http://y'); // eslint-disable-line resolveFunction = nativeURLResolver; } catch (e) { // must be IE11/Node etc } finally { resolveFunction = resolveFunction || dumbURLResolver; } } /** * Returns a string that contains the Base URL of a URL, if determinable. * @param {string} url - full url * @return {string} * @memberof module:DefaultURLUtils * @instance */ function parseBaseUrl(url) { const slashIndex = url.indexOf('/'); const lastSlashIndex = url.lastIndexOf('/'); if (slashIndex !== -1) { // if there is only '//' if (lastSlashIndex === slashIndex + 1) { return url; } if (url.indexOf('?') !== -1) { url = url.substring(0, url.indexOf('?')); } return url.substring(0, lastSlashIndex + 1); } return ''; } /** * Returns a string that contains the scheme and origin of a URL, * if determinable. * @param {string} url - full url * @return {string} * @memberof module:DefaultURLUtils * @instance */ function parseOrigin(url) { const matches = url.match(originRegex); if (matches) { return matches[1]; } return ''; } /** * Returns a string that contains the fragment of a URL without scheme, * if determinable. * @param {string} url - full url * @return {string} * @memberof module:DefaultURLUtils * @instance */ function removeHostname(url) { let urlParts = /^(?:\\w+\\:\\/\\/)?([^\\/]+)(.*)$/.exec(url); //[1] = host / [2] = path return urlParts[2].substring(1); } /** * Returns a string that contains the scheme of a URL, if determinable. * @param {string} url - full url * @return {string} * @memberof module:DefaultURLUtils * @instance */ function parseScheme(url) { const matches = url.match(schemeRegex); if (matches) { return matches[0]; } return ''; } /** * Determines whether the url is relative. * @return {boolean} * @param {string} url * @memberof module:DefaultURLUtils * @instance */ function isRelative(url) { return !schemeRegex.test(url); } /** * Determines whether the url is path-absolute. * @return {bool} * @param {string} url * @memberof module:DefaultURLUtils * @instance */ function isPathAbsolute(url) { return isRelative(url) &amp;&amp; url.charAt(0) === '/'; } /** * Determines whether the url is scheme-relative. * @return {bool} * @param {string} url * @memberof module:DefaultURLUtils * @instance */ function isSchemeRelative(url) { return url.indexOf('//') === 0; } /** * Determines whether the url is an HTTP-URL as defined in ISO/IEC * 23009-1:2014 3.1.15. ie URL with a fixed scheme of http or https * @return {bool} * @param {string} url * @memberof module:DefaultURLUtils * @instance */ function isHTTPURL(url) { return httpUrlRegex.test(url); } /** * Determines whether the supplied url has https scheme * @return {bool} * @param {string} url * @memberof module:DefaultURLUtils * @instance */ function isHTTPS(url) { return httpsUrlRegex.test(url); } /** * Resolves a url given an optional base url * @return {string} * @param {string} url * @param {string} [baseUrl] * @memberof module:DefaultURLUtils * @instance */ function resolve(url, baseUrl) { return resolveFunction(url, baseUrl); } setup(); const instance = { parseBaseUrl: parseBaseUrl, parseOrigin: parseOrigin, parseScheme: parseScheme, isRelative: isRelative, isPathAbsolute: isPathAbsolute, isSchemeRelative: isSchemeRelative, isHTTPURL: isHTTPURL, isHTTPS: isHTTPS, removeHostname: removeHostname, resolve: resolve }; return instance; } DefaultURLUtils.__dashjs_factory_name = 'DefaultURLUtils'; export default FactoryMaker.getSingletonFactory(DefaultURLUtils); × Search results Close "},"streaming_utils_ErrorHandler.js.html":{"id":"streaming_utils_ErrorHandler.js.html","title":"Source: streaming/utils/ErrorHandler.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/ErrorHandler.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; /** * @module ErrorHandler * @ignore */ function ErrorHandler() { let instance; const context = this.context; const eventBus = EventBus(context).getInstance(); /** * @param {object} err DashJSError with code, message and data attributes * @memberof module:ErrorHandler */ function error(err) { eventBus.trigger(Events.ERROR, { error: err }); } instance = { error: error }; return instance; } ErrorHandler.__dashjs_factory_name = 'ErrorHandler'; export default FactoryMaker.getSingletonFactory(ErrorHandler); × Search results Close "},"core_FactoryMaker.js.html":{"id":"core_FactoryMaker.js.html","title":"Source: core/FactoryMaker.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: core/FactoryMaker.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @module FactoryMaker * @ignore */ const FactoryMaker = (function () { let instance; let singletonContexts = []; const singletonFactories = {}; const classFactories = {}; function extend(name, childInstance, override, context) { if (!context[name] &amp;&amp; childInstance) { context[name] = { instance: childInstance, override: override }; } } /** * Use this method from your extended object. this.factory is injected into your object. * this.factory.getSingletonInstance(this.context, 'VideoModel') * will return the video model for use in the extended object. * * @param {Object} context - injected into extended object as this.context * @param {string} className - string name found in all dash.js objects * with name __dashjs_factory_name Will be at the bottom. Will be the same as the object's name. * @returns {*} Context aware instance of specified singleton name. * @memberof module:FactoryMaker * @instance */ function getSingletonInstance(context, className) { for (const i in singletonContexts) { const obj = singletonContexts[i]; if (obj.context === context &amp;&amp; obj.name === className) { return obj.instance; } } return null; } /** * Use this method to add an singleton instance to the system. Useful for unit testing to mock objects etc. * * @param {Object} context * @param {string} className * @param {Object} instance * @memberof module:FactoryMaker * @instance */ function setSingletonInstance(context, className, instance) { for (const i in singletonContexts) { const obj = singletonContexts[i]; if (obj.context === context &amp;&amp; obj.name === className) { singletonContexts[i].instance = instance; return; } } singletonContexts.push({ name: className, context: context, instance: instance }); } /** * 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(x =&gt; x.context !== context); } /*------------------------------------------------------------------------------------------*/ // Factories storage Management /*------------------------------------------------------------------------------------------*/ function getFactoryByName(name, factoriesArray) { return factoriesArray[name]; } function updateFactory(name, factory, factoriesArray) { if (name in factoriesArray) { factoriesArray[name] = factory; } } /*------------------------------------------------------------------------------------------*/ // Class Factories Management /*------------------------------------------------------------------------------------------*/ function updateClassFactory(name, factory) { updateFactory(name, factory, classFactories); } function getClassFactoryByName(name) { return getFactoryByName(name, classFactories); } function getClassFactory(classConstructor) { let factory = getFactoryByName(classConstructor.__dashjs_factory_name, classFactories); if (!factory) { factory = function (context) { if (context === undefined) { context = {}; } return { create: function () { return merge(classConstructor, context, arguments); } }; }; classFactories[classConstructor.__dashjs_factory_name] = factory; // store factory } return factory; } /*------------------------------------------------------------------------------------------*/ // Singleton Factory MAangement /*------------------------------------------------------------------------------------------*/ function updateSingletonFactory(name, factory) { updateFactory(name, factory, singletonFactories); } function getSingletonFactoryByName(name) { return getFactoryByName(name, singletonFactories); } function getSingletonFactory(classConstructor) { let factory = getFactoryByName(classConstructor.__dashjs_factory_name, singletonFactories); if (!factory) { factory = function (context) { let instance; if (context === undefined) { context = {}; } return { getInstance: function () { // If we don't have an instance yet check for one on the context if (!instance) { instance = getSingletonInstance(context, classConstructor.__dashjs_factory_name); } // If there's no instance on the context then create one if (!instance) { instance = merge(classConstructor, context, arguments); singletonContexts.push({ name: classConstructor.__dashjs_factory_name, context: context, instance: instance }); } return instance; } }; }; singletonFactories[classConstructor.__dashjs_factory_name] = factory; // store factory } return factory; } function merge(classConstructor, context, args) { let classInstance; const className = classConstructor.__dashjs_factory_name; const extensionObject = context[className]; if (extensionObject) { let extension = extensionObject.instance; if (extensionObject.override) { //Override public methods in parent but keep parent. classInstance = classConstructor.apply({context}, args); extension = extension.apply({ context, factory: instance, parent: classInstance }, args); for (const prop in extension) { if (classInstance.hasOwnProperty(prop)) { classInstance[prop] = extension[prop]; } } } else { //replace parent object completely with new object. Same as dijon. return extension.apply({ context, factory: instance }, args); } } else { // Create new instance of the class classInstance = classConstructor.apply({context}, args); } // Add getClassName function to class instance prototype (used by Debug) classInstance.getClassName = function () {return className;}; return classInstance; } instance = { extend: extend, getSingletonInstance: getSingletonInstance, setSingletonInstance: setSingletonInstance, deleteSingletonInstances: deleteSingletonInstances, getSingletonFactory: getSingletonFactory, getSingletonFactoryByName: getSingletonFactoryByName, updateSingletonFactory: updateSingletonFactory, getClassFactory: getClassFactory, getClassFactoryByName: getClassFactoryByName, updateClassFactory: updateClassFactory }; return instance; }()); export default FactoryMaker; × Search results Close "},"streaming_net_HTTPLoader.js.html":{"id":"streaming_net_HTTPLoader.js.html","title":"Source: streaming/net/HTTPLoader.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/net/HTTPLoader.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import XHRLoader from './XHRLoader'; import FetchLoader from './FetchLoader'; import {HTTPRequest} from '../vo/metrics/HTTPRequest'; import FactoryMaker from '../../core/FactoryMaker'; import DashJSError from '../vo/DashJSError'; import CmcdModel from '../models/CmcdModel'; import Utils from '../../core/Utils'; import Debug from '../../core/Debug'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import Settings from '../../core/Settings'; import Constants from '../constants/Constants'; import LowLatencyThroughputModel from '../models/LowLatencyThroughputModel'; import CustomParametersModel from '../models/CustomParametersModel'; /** * @module HTTPLoader * @ignore * @description Manages download of resources via HTTP. * @param {Object} cfg - dependencies from parent */ function HTTPLoader(cfg) { cfg = cfg || {}; const context = this.context; const errHandler = cfg.errHandler; const dashMetrics = cfg.dashMetrics; const mediaPlayerModel = cfg.mediaPlayerModel; const requestModifier = cfg.requestModifier; const boxParser = cfg.boxParser; const errors = cfg.errors; const requestTimeout = cfg.requestTimeout || 0; const eventBus = EventBus(context).getInstance(); const settings = Settings(context).getInstance(); let instance, requests, delayedRequests, retryRequests, downloadErrorToRequestTypeMap, cmcdModel, customParametersModel, lowLatencyThroughputModel, logger; function setup() { logger = Debug(context).getInstance().getLogger(instance); requests = []; delayedRequests = []; retryRequests = []; cmcdModel = CmcdModel(context).getInstance(); lowLatencyThroughputModel = LowLatencyThroughputModel(context).getInstance(); customParametersModel = CustomParametersModel(context).getInstance(); downloadErrorToRequestTypeMap = { [HTTPRequest.MPD_TYPE]: errors.DOWNLOAD_ERROR_ID_MANIFEST_CODE, [HTTPRequest.XLINK_EXPANSION_TYPE]: errors.DOWNLOAD_ERROR_ID_XLINK_CODE, [HTTPRequest.INIT_SEGMENT_TYPE]: errors.DOWNLOAD_ERROR_ID_INITIALIZATION_CODE, [HTTPRequest.MEDIA_SEGMENT_TYPE]: errors.DOWNLOAD_ERROR_ID_CONTENT_CODE, [HTTPRequest.INDEX_SEGMENT_TYPE]: errors.DOWNLOAD_ERROR_ID_CONTENT_CODE, [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: errors.DOWNLOAD_ERROR_ID_CONTENT_CODE, [HTTPRequest.OTHER_TYPE]: errors.DOWNLOAD_ERROR_ID_CONTENT_CODE }; } function internalLoad(config, remainingAttempts) { const request = config.request; const traces = []; let firstProgress = true; let needFailureReport = true; let requestStartTime = new Date(); let lastTraceTime = requestStartTime; let lastTraceReceivedCount = 0; let fileLoaderType = null; let httpRequest; if (!requestModifier || !dashMetrics || !errHandler) { throw new Error('config object is not correct or missing'); } const handleLoaded = function (success) { needFailureReport = false; request.requestStartDate = requestStartTime; request.requestEndDate = new Date(); request.firstByteDate = request.firstByteDate || requestStartTime; request.fileLoaderType = fileLoaderType; if (!request.checkExistenceOnly) { const responseUrl = httpRequest.response ? httpRequest.response.responseURL : null; const responseStatus = httpRequest.response ? httpRequest.response.status : null; const responseHeaders = httpRequest.response &amp;&amp; httpRequest.response.getAllResponseHeaders ? httpRequest.response.getAllResponseHeaders() : httpRequest.response ? httpRequest.response.responseHeaders : []; dashMetrics.addHttpRequest(request, responseUrl, responseStatus, responseHeaders, success ? traces : null); if (request.type === HTTPRequest.MPD_TYPE) { dashMetrics.addManifestUpdate(request); } } }; const onloadend = function () { if (requests.indexOf(httpRequest) === -1) { return; } else { requests.splice(requests.indexOf(httpRequest), 1); } if (needFailureReport) { handleLoaded(false); if (remainingAttempts &gt; 0) { // If we get a 404 to a media segment we should check the client clock again and perform a UTC sync in the background. try { if (settings.get().streaming.utcSynchronization.enableBackgroundSyncAfterSegmentDownloadError &amp;&amp; request.type === HTTPRequest.MEDIA_SEGMENT_TYPE) { // Only trigger a sync if the loading failed for the first time const initialNumberOfAttempts = mediaPlayerModel.getRetryAttemptsForType(HTTPRequest.MEDIA_SEGMENT_TYPE); if (initialNumberOfAttempts === remainingAttempts) { eventBus.trigger(Events.ATTEMPT_BACKGROUND_SYNC); } } } catch (e) { } remainingAttempts--; let retryRequest = { config: config }; retryRequests.push(retryRequest); retryRequest.timeout = setTimeout(function () { if (retryRequests.indexOf(retryRequest) === -1) { return; } else { retryRequests.splice(retryRequests.indexOf(retryRequest), 1); } internalLoad(config, remainingAttempts); }, mediaPlayerModel.getRetryIntervalsForType(request.type)); } else { if (request.type === HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE) { return; } errHandler.error(new DashJSError(downloadErrorToRequestTypeMap[request.type], request.url + ' is not available', { request: request, response: httpRequest.response })); if (config.error) { config.error(request, 'error', httpRequest.response.statusText); } if (config.complete) { config.complete(request, httpRequest.response.statusText); } } } }; const progress = function (event) { const currentTime = new Date(); if (firstProgress) { firstProgress = false; if (!event.lengthComputable || (event.lengthComputable &amp;&amp; event.total !== event.loaded)) { request.firstByteDate = currentTime; } } if (event.lengthComputable) { request.bytesLoaded = event.loaded; request.bytesTotal = event.total; } if (!event.noTrace) { traces.push({ s: lastTraceTime, d: event.time ? event.time : currentTime.getTime() - lastTraceTime.getTime(), b: [event.loaded ? event.loaded - lastTraceReceivedCount : 0] }); lastTraceTime = currentTime; lastTraceReceivedCount = event.loaded; } if (config.progress &amp;&amp; event) { config.progress(event); } }; const onload = function () { if (httpRequest.response.status &gt;= 200 &amp;&amp; httpRequest.response.status &lt;= 299) { handleLoaded(true); if (config.success) { config.success(httpRequest.response.response, httpRequest.response.statusText, httpRequest.response.responseURL); } if (config.complete) { config.complete(request, httpRequest.response.statusText); } } }; const onabort = function () { if (config.abort) { config.abort(request); } }; const ontimeout = function (event) { let timeoutMessage; if (event.lengthComputable) { let percentageComplete = (event.loaded / event.total) * 100; timeoutMessage = 'Request timeout: loaded: ' + event.loaded + ', out of: ' + event.total + ' : ' + percentageComplete.toFixed(3) + '% Completed'; } else { timeoutMessage = 'Request timeout: non-computable download size'; } logger.warn(timeoutMessage); }; let loader; if (request.hasOwnProperty('availabilityTimeComplete') &amp;&amp; request.availabilityTimeComplete === false &amp;&amp; window.fetch &amp;&amp; request.responseType === 'arraybuffer' &amp;&amp; request.type === HTTPRequest.MEDIA_SEGMENT_TYPE) { loader = FetchLoader(context).create({ requestModifier: requestModifier, lowLatencyThroughputModel, boxParser: boxParser }); loader.setup({ dashMetrics }); fileLoaderType = Constants.FILE_LOADER_TYPES.FETCH; } else { loader = XHRLoader(context).create({ requestModifier: requestModifier }); fileLoaderType = Constants.FILE_LOADER_TYPES.XHR; } let headers = null; let modifiedUrl = requestModifier.modifyRequestURL ? requestModifier.modifyRequestURL(request.url) : request.url; if (settings.get().streaming.cmcd &amp;&amp; settings.get().streaming.cmcd.enabled) { const cmcdMode = settings.get().streaming.cmcd.mode; if (cmcdMode === Constants.CMCD_MODE_QUERY) { const additionalQueryParameter = _getAdditionalQueryParameter(request); modifiedUrl = Utils.addAditionalQueryParameterToUrl(modifiedUrl, additionalQueryParameter); } else if (cmcdMode === Constants.CMCD_MODE_HEADER) { headers = cmcdModel.getHeaderParameters(request); } } request.url = modifiedUrl; const verb = request.checkExistenceOnly ? HTTPRequest.HEAD : HTTPRequest.GET; const withCredentials = customParametersModel.getXHRWithCredentialsForType(request.type); httpRequest = { url: modifiedUrl, method: verb, withCredentials: withCredentials, request: request, onload: onload, onend: onloadend, onerror: onloadend, progress: progress, onabort: onabort, ontimeout: ontimeout, loader: loader, timeout: requestTimeout, headers: headers }; // Adds the ability to delay single fragment loading time to control buffer. let now = new Date().getTime(); if (isNaN(request.delayLoadingTime) || now &gt;= request.delayLoadingTime) { // no delay - just send requests.push(httpRequest); loader.load(httpRequest); } else { // delay let delayedRequest = { httpRequest: httpRequest }; delayedRequests.push(delayedRequest); delayedRequest.delayTimeout = setTimeout(function () { if (delayedRequests.indexOf(delayedRequest) === -1) { return; } else { delayedRequests.splice(delayedRequests.indexOf(delayedRequest), 1); } try { requestStartTime = new Date(); lastTraceTime = requestStartTime; requests.push(delayedRequest.httpRequest); loader.load(delayedRequest.httpRequest); } catch (e) { delayedRequest.httpRequest.onerror(); } }, (request.delayLoadingTime - now)); } } function _getAdditionalQueryParameter(request) { try { const additionalQueryParameter = []; const cmcdQueryParameter = cmcdModel.getQueryParameter(request); if (cmcdQueryParameter) { additionalQueryParameter.push(cmcdQueryParameter); } return additionalQueryParameter; } catch (e) { return []; } } /** * Initiates a download of the resource described by config.request * @param {Object} config - contains request (FragmentRequest or derived type), and callbacks * @memberof module:HTTPLoader * @instance */ function load(config) { if (config.request) { internalLoad( config, mediaPlayerModel.getRetryAttemptsForType( config.request.type ) ); } else { if (config.error) { config.error(config.request, 'error'); } } } /** * Aborts any inflight downloads * @memberof module:HTTPLoader * @instance */ function abort() { retryRequests.forEach(t =&gt; { clearTimeout(t.timeout); // abort request in order to trigger LOADING_ABANDONED event if (t.config.request &amp;&amp; t.config.abort) { t.config.abort(t.config.request); } }); retryRequests = []; delayedRequests.forEach(x =&gt; clearTimeout(x.delayTimeout)); delayedRequests = []; requests.forEach(x =&gt; { // MSS patch: ignore FragmentInfo requests if (x.request.type === HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE) { return; } // abort will trigger onloadend which we don't want // when deliberately aborting inflight requests - // set them to undefined so they are not called x.onloadend = x.onerror = x.onprogress = undefined; x.loader.abort(x); }); requests = []; } instance = { load: load, abort: abort }; setup(); return instance; } HTTPLoader.__dashjs_factory_name = 'HTTPLoader'; const factory = FactoryMaker.getClassFactory(HTTPLoader); export default factory; × Search results Close "},"streaming_utils_ObjectUtils.js.html":{"id":"streaming_utils_ObjectUtils.js.html","title":"Source: streaming/utils/ObjectUtils.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/ObjectUtils.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import deepEqual from 'fast-deep-equal'; /** * @module ObjectUtils * @ignore * @description Provides utility functions for objects */ function ObjectUtils() { let instance; /** * Returns true if objects are equal * @return {boolean} * @param {object} obj1 * @param {object} obj2 * @memberof module:ObjectUtils * @instance */ function areEqual(obj1, obj2) { return deepEqual(obj1, obj2); } instance = { areEqual: areEqual }; return instance; } ObjectUtils.__dashjs_factory_name = 'ObjectUtils'; export default FactoryMaker.getSingletonFactory(ObjectUtils); × Search results Close "},"offline_controllers_OfflineController.js.html":{"id":"offline_controllers_OfflineController.js.html","title":"Source: offline/controllers/OfflineController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/controllers/OfflineController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import OfflineConstants from '../constants/OfflineConstants'; import OfflineStoreController from './OfflineStoreController'; import OfflineDownload from '../OfflineDownload'; import IndexDBOfflineLoader from '../net/IndexDBOfflineLoader'; import OfflineUrlUtils from '../utils/OfflineUrlUtils'; import OfflineEvents from '../events/OfflineEvents'; import OfflineErrors from '../errors/OfflineErrors'; import OfflineRecord from '../vo/OfflineDownloadVo'; /** * @module OfflineController * @param {Object} config - dependencies * @description Provides access to offline stream recording and playback functionality. This module can be accessed using the MediaPlayer API getOfflineController() */ function OfflineController(config) { const context = this.context; const errHandler = config.errHandler; const events = config.events; const errors = config.errors; const settings = config.settings; const eventBus = config.eventBus; const debug = config.debug; const manifestLoader = config.manifestLoader; const manifestModel = config.manifestModel; const mediaPlayerModel = config.mediaPlayerModel; const abrController = config.abrController; const playbackController = config.playbackController; const dashMetrics = config.dashMetrics; const timelineConverter = config.timelineConverter; const segmentBaseController = config.segmentBaseController; const adapter = config.adapter; const manifestUpdater = config.manifestUpdater; const baseURLController = config.baseURLController; const schemeLoaderFactory = config.schemeLoaderFactory; const constants = config.constants; const dashConstants = config.dashConstants; const urlUtils = config.urlUtils; let instance, downloads, logger, offlineStoreController, offlineUrlUtils; function setup() { logger = debug.getLogger(instance); offlineStoreController = OfflineStoreController(context).create({ eventBus: config.eventBus, errHandler: errHandler }); offlineUrlUtils = OfflineUrlUtils(context).getInstance(); urlUtils.registerUrlRegex(offlineUrlUtils.getRegex(), offlineUrlUtils); schemeLoaderFactory.registerLoader(OfflineConstants.OFFLINE_SCHEME, IndexDBOfflineLoader); downloads = []; } /* --------------------------------------------------------------------------- DOWNLOAD LIST FUNCTIONS --------------------------------------------------------------------------- */ function getDownloadFromId(id) { let download = downloads.find((item) =&gt; { return item.getId() === id; }); return download; } function createDownloadFromId(id) { let download; download = getDownloadFromId(id); if (!download) { // create download controller download = OfflineDownload(context).create({ id: id, eventBus: eventBus, events: events, errors: errors, settings: settings, manifestLoader: manifestLoader, manifestModel: manifestModel, mediaPlayerModel: mediaPlayerModel, manifestUpdater: manifestUpdater, baseURLController: baseURLController, abrController: abrController, playbackController: playbackController, adapter: adapter, dashMetrics: dashMetrics, timelineConverter: timelineConverter, errHandler: errHandler, segmentBaseController: segmentBaseController, offlineStoreController: offlineStoreController, debug: debug, constants: constants, dashConstants: dashConstants, urlUtils: urlUtils }); downloads.push(download); } return download; } function createDownloadFromStorage(offline) { let download = getDownloadFromId(offline.manifestId); if (!download) { download = createDownloadFromId(offline.manifestId); let status = offline.status; if (status === OfflineConstants.OFFLINE_STATUS_STARTED) { status = OfflineConstants.OFFLINE_STATUS_STOPPED; } download.setInitialState({ url: offline.url, progress: offline.progress, originalUrl: offline.originalURL, status: status }); } return download; } function removeDownloadFromId(id) { return new Promise(function (resolve, reject) { let download = getDownloadFromId(id); let waitForStatusChanged = false; if (download) { //is download running? if (download.isDownloading()) { //register status changed event waitForStatusChanged = true; const downloadStopped = function () { eventBus.off(events.OFFLINE_RECORD_STOPPED, downloadStopped, instance); return offlineStoreController.deleteDownloadById(id).then(function () { resolve(); }).catch(function (err) { reject(err); }); }; eventBus.on(events.OFFLINE_RECORD_STOPPED, downloadStopped, instance); } download.deleteDownload(); let index = downloads.indexOf(download); downloads.splice(index, 1); } if (!waitForStatusChanged) { resolve(); } }); } function generateManifestId() { let timestamp = new Date().getTime(); return timestamp; } /* --------------------------------------------------------------------------- OFFLINE CONTROLLER API --------------------------------------------------------------------------- */ /** * Loads records from storage * This methods has to be called first, to be sure that all downloads have been loaded * * @return {Promise} asynchronously resolved * @memberof module:OfflineController */ function loadRecordsFromStorage() { return new Promise(function (resolve, reject) { offlineStoreController.getAllManifests().then((items) =&gt; { items.manifests.forEach((offline) =&gt; { createDownloadFromStorage(offline); }); resolve(); }).catch((e) =&gt; { logger.error('Failed to load downloads ' + e); reject(e); }); }); } /** * Get all records from storage * * @return {Promise} asynchronously resolved with records * @memberof module:OfflineController * @instance */ function getAllRecords() { let records = []; downloads.forEach((download) =&gt; { const record = new OfflineRecord(); record.id = download.getId(); record.progress = download.getDownloadProgression(); record.url = download.getOfflineUrl(); record.originalUrl = download.getManifestUrl(); record.status = download.getStatus(); records.push(record); }); return records; } /** * Create a new content record in storage and download manifest from url * * @param {string} manifestURL - the content manifest url * @return {Promise} asynchronously resolved with record identifier * @memberof module:OfflineController * @instance */ function createRecord(manifestURL) { return new Promise(function (resolve, reject) { let id = generateManifestId(); // create download controller let download = createDownloadFromId(id); download.downloadFromUrl(manifestURL).then(() =&gt; { download.initDownload(); resolve(id); }) .catch((e) =&gt; { logger.error('Failed to download ' + e); removeDownloadFromId(id).then(function () { reject(e); }); }); }); } /** * Start downloading the record with selected tracks representations * * @param {string} id - record identifier * @param {MediaInfo[]} mediaInfos - the selected tracks representations * @memberof module:OfflineController * @instance */ function startRecord(id, mediaInfos) { let download = getDownloadFromId(id); if (download) { download.startDownload(mediaInfos); } } /** * Stop downloading of the record * * @param {string} id - record identifier * @memberof module:OfflineController * @instance */ function stopRecord(id) { let download = getDownloadFromId(id); if (download) { download.stopDownload(); } } /** * Resume downloading of the record * * @param {string} id - record identifier * @memberof module:OfflineController * @instance */ function resumeRecord(id) { let download = getDownloadFromId(id); if (download) { download.resumeDownload(); } } /** * Deletes a record from storage * * @param {string} id - record identifier * @memberof module:OfflineController * @instance */ function deleteRecord(id) { return removeDownloadFromId(id).then(function () { return offlineStoreController.deleteDownloadById(id); }); } /** * Get download progression of a record * * @param {string} id - record identifier * @return {number} percentage progression * @memberof module:OfflineController * @instance */ function getRecordProgression(id) { let download = getDownloadFromId(id); if (download) { return download.getDownloadProgression(); } return 0; } /** * Reset all records * @memberof module:OfflineController * @instance */ function resetRecords() { downloads.forEach((download) =&gt; { download.resetDownload(); }); } /** * Reset * @instance */ function reset() { resetRecords(); schemeLoaderFactory.unregisterLoader(OfflineConstants.OFFLINE_SCHEME); } instance = { loadRecordsFromStorage: loadRecordsFromStorage, createRecord: createRecord, startRecord: startRecord, stopRecord: stopRecord, resumeRecord: resumeRecord, deleteRecord: deleteRecord, getRecordProgression: getRecordProgression, getAllRecords: getAllRecords, resetRecords: resetRecords, reset: reset }; setup(); return instance; } OfflineController.__dashjs_factory_name = 'OfflineController'; const factory = dashjs.FactoryMaker.getClassFactory(OfflineController); /* jshint ignore:line */ factory.events = OfflineEvents; factory.errors = OfflineErrors; dashjs.FactoryMaker.updateClassFactory(OfflineController.__dashjs_factory_name, factory); /* jshint ignore:line */ export default factory; × Search results Close "},"streaming_protection_controllers_ProtectionController.js.html":{"id":"streaming_protection_controllers_ProtectionController.js.html","title":"Source: streaming/protection/controllers/ProtectionController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/controllers/ProtectionController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import CommonEncryption from '../CommonEncryption'; import MediaCapability from '../vo/MediaCapability'; import KeySystemConfiguration from '../vo/KeySystemConfiguration'; import ProtectionErrors from '../errors/ProtectionErrors'; import DashJSError from '../../vo/DashJSError'; import LicenseRequest from '../vo/LicenseRequest'; import LicenseResponse from '../vo/LicenseResponse'; import {HTTPRequest} from '../../vo/metrics/HTTPRequest'; import Utils from '../../../core/Utils'; import Constants from '../../constants/Constants'; import FactoryMaker from '../../../core/FactoryMaker'; const NEEDKEY_BEFORE_INITIALIZE_RETRIES = 5; const NEEDKEY_BEFORE_INITIALIZE_TIMEOUT = 500; const LICENSE_SERVER_REQUEST_RETRIES = 3; const LICENSE_SERVER_REQUEST_RETRY_INTERVAL = 1000; const LICENSE_SERVER_REQUEST_DEFAULT_TIMEOUT = 8000; /** * @module ProtectionController * @description Provides access to media protection information and functionality. Each * ProtectionController manages a single {@link MediaPlayer.models.ProtectionModel} * which encapsulates a set of protection information (EME APIs, selected key system, * key sessions). The APIs of ProtectionController mostly align with the latest EME * APIs. Key system selection is mostly automated when combined with app-overrideable * functionality provided in {@link ProtectionKeyController}. * @todo ProtectionController does almost all of its tasks automatically after init() is * called. Applications might want more control over this process and want to go through * each step manually (key system selection, session creation, session maintenance). * This module can be accessed using the MediaPlayer API getProtectionController() * @param {Object} config */ function ProtectionController(config) { config = config || {}; const protectionKeyController = config.protectionKeyController; let protectionModel = config.protectionModel; const eventBus = config.eventBus; const events = config.events; const debug = config.debug; const BASE64 = config.BASE64; const constants = config.constants; let needkeyRetries = []; const cmcdModel = config.cmcdModel; const settings = config.settings; const customParametersModel = config.customParametersModel; let instance, logger, pendingKeySessionsToHandle, mediaInfoArr, protDataSet, sessionType, robustnessLevel, selectedKeySystem, keySystemSelectionInProgress, licenseXhrRequest, licenseRequestRetryTimeout; function setup() { logger = debug.getLogger(instance); pendingKeySessionsToHandle = []; mediaInfoArr = []; sessionType = 'temporary'; robustnessLevel = ''; licenseXhrRequest = null; licenseRequestRetryTimeout = null; eventBus.on(events.INTERNAL_KEY_MESSAGE, _onKeyMessage, instance); eventBus.on(events.INTERNAL_KEY_STATUS_CHANGED, _onKeyStatusChanged, instance); } function checkConfig() { if (!eventBus || !eventBus.hasOwnProperty('on') || !protectionKeyController || !protectionKeyController.hasOwnProperty('getSupportedKeySystemsFromContentProtection')) { throw new Error('Missing config parameter(s)'); } } /** * Initialize this protection system for a given media type. * * @param {StreamInfo} [mediaInfo] Media information * @memberof module:ProtectionController * @instance */ function initializeForMedia(mediaInfo) { // Not checking here if a session for similar KS/KID combination is already created // because still don't know which keysystem will be selected. // Once Keysystem is selected and before creating the session, we will do that check // so we create the strictly necessary DRM sessions if (!mediaInfo) { throw new Error('mediaInfo can not be null or undefined'); } checkConfig(); mediaInfoArr.push(mediaInfo); } /** * Once all mediaInfo objects have been added to our mediaInfoArray we can select a key system or check if the kid has changed and we need to trigger a new license request * @memberof module:ProtectionController * @instance */ function handleKeySystemFromManifest() { if (!mediaInfoArr || mediaInfoArr.length === 0) { return; } let supportedKeySystems = []; mediaInfoArr.forEach((mInfo) =&gt; { const currentKs = protectionKeyController.getSupportedKeySystemsFromContentProtection(mInfo.contentProtection, protDataSet, sessionType); // We assume that the same key systems are signaled for each AS. We can use the first entry we found if (currentKs.length &gt; 0) { if (supportedKeySystems.length === 0) { supportedKeySystems = currentKs; } // Save config for creating key session once we selected a key system pendingKeySessionsToHandle.push(currentKs); } }) if (supportedKeySystems &amp;&amp; supportedKeySystems.length &gt; 0) { _selectKeySystemOrUpdateKeySessions(supportedKeySystems, true); } } /** * Selects a key system if we dont have any one yet. Otherwise we use the existing key system and trigger a new license request if the initdata has changed * @param {array} supportedKs * @private */ function _handleKeySystemFromPssh(supportedKs) { pendingKeySessionsToHandle.push(supportedKs); _selectKeySystemOrUpdateKeySessions(supportedKs, false); } /** * Select the key system or update one of our existing key sessions * @param {array} supportedKs * @param {boolean} fromManifest * @private */ function _selectKeySystemOrUpdateKeySessions(supportedKs, fromManifest) { // First time, so we need to select a key system if (!selectedKeySystem &amp;&amp; !keySystemSelectionInProgress) { _selectInitialKeySystem(supportedKs, fromManifest); } // We already selected a key system. We only need to trigger a new license exchange if the init data has changed else if (selectedKeySystem) { _handleKeySessions(); } } /** * We do not have a key system yet. Select one * @param {array} supportedKs * @param {boolean} fromManifest * @private */ function _selectInitialKeySystem(supportedKs, fromManifest) { if (!keySystemSelectionInProgress) { keySystemSelectionInProgress = true; const requestedKeySystems = []; // Reorder key systems according to priority order provided in protectionData supportedKs = supportedKs.sort((ksA, ksB) =&gt; { let indexA = (protDataSet &amp;&amp; protDataSet[ksA.ks.systemString] &amp;&amp; protDataSet[ksA.ks.systemString].priority &gt;= 0) ? protDataSet[ksA.ks.systemString].priority : supportedKs.length; let indexB = (protDataSet &amp;&amp; protDataSet[ksB.ks.systemString] &amp;&amp; protDataSet[ksB.ks.systemString].priority &gt;= 0) ? protDataSet[ksB.ks.systemString].priority : supportedKs.length; return indexA - indexB; }); // Add all key systems to our request list since we have yet to select a key system for (let i = 0; i &lt; supportedKs.length; i++) { const keySystemConfiguration = _getKeySystemConfiguration(supportedKs[i]); requestedKeySystems.push({ ks: supportedKs[i].ks, configs: [keySystemConfiguration], protData: supportedKs[i].protData }); } let keySystemAccess; protectionModel.requestKeySystemAccess(requestedKeySystems) .then((event) =&gt; { keySystemAccess = event.data; let selectedSystemString = keySystemAccess.mksa &amp;&amp; keySystemAccess.mksa.selectedSystemString ? keySystemAccess.mksa.selectedSystemString : keySystemAccess.keySystem.systemString; logger.info('DRM: KeySystem Access Granted for system string (' + selectedSystemString + ')! Selecting key system...'); return protectionModel.selectKeySystem(keySystemAccess); }) .then((keySystem) =&gt; { selectedKeySystem = keySystem; keySystemSelectionInProgress = false; if (!protectionModel) { return; } eventBus.trigger(events.KEY_SYSTEM_SELECTED, { data: keySystemAccess }); // Set server certificate from protData const protData = _getProtDataForKeySystem(selectedKeySystem); if (protData &amp;&amp; protData.serverCertificate &amp;&amp; protData.serverCertificate.length &gt; 0) { protectionModel.setServerCertificate(BASE64.decodeArray(protData.serverCertificate).buffer); } _handleKeySessions(); }) .catch((event) =&gt; { selectedKeySystem = null; keySystemSelectionInProgress = false; if (!fromManifest) { eventBus.trigger(events.KEY_SYSTEM_SELECTED, { data: null, error: new DashJSError(ProtectionErrors.KEY_SYSTEM_ACCESS_DENIED_ERROR_CODE, ProtectionErrors.KEY_SYSTEM_ACCESS_DENIED_ERROR_MESSAGE + 'Error selecting key system! -- ' + event.error) }); } }) } } /** * If we have already selected a key system we only need to create a new key session and issue a new license request if the init data has changed. * @private */ function _handleKeySessions() { // Create key sessions for the different AdaptationSets let ksIdx; for (let i = 0; i &lt; pendingKeySessionsToHandle.length; i++) { for (ksIdx = 0; ksIdx &lt; pendingKeySessionsToHandle[i].length; ksIdx++) { if (selectedKeySystem === pendingKeySessionsToHandle[i][ksIdx].ks) { const current = pendingKeySessionsToHandle[i][ksIdx] _loadOrCreateKeySession(current) break; } } } pendingKeySessionsToHandle = []; } /** * Loads an existing key session if we already have a session id. Otherwise we create a new key session * @param {object} keySystemInfo * @private */ function _loadOrCreateKeySession(keySystemInfo) { // Clearkey if (protectionKeyController.isClearKey(selectedKeySystem)) { // For Clearkey: if parameters for generating init data was provided by the user, use them for generating // initData and overwrite possible initData indicated in encrypted event (EME) if (keySystemInfo.protData &amp;&amp; keySystemInfo.protData.hasOwnProperty('clearkeys') &amp;&amp; Object.keys(keySystemInfo.protData.clearkeys).length !== 0) { const initData = { kids: Object.keys(keySystemInfo.protData.clearkeys) }; keySystemInfo.initData = new TextEncoder().encode(JSON.stringify(initData)); } } // Reuse existing KeySession if (keySystemInfo.sessionId) { // Load MediaKeySession with sessionId loadKeySession(keySystemInfo); } // Create a new KeySession else if (keySystemInfo.initData !== null) { // Create new MediaKeySession with initData createKeySession(keySystemInfo); } } /** * Loads a key session with the given session ID from persistent storage. This essentially creates a new key session * * @param {object} ksInfo * @memberof module:ProtectionController * @instance * @fires ProtectionController#KeySessionCreated * @ignore */ function loadKeySession(keySystemInfo) { checkConfig(); protectionModel.loadKeySession(keySystemInfo); } /** * Create a new key session associated with the given initialization data from the MPD or from the PSSH box in the media * For the latest version of the EME a request is generated. Once this request is ready we get notified via the INTERNAL_KEY_MESSAGE event * @param {ArrayBuffer} initData the initialization data * @param {Uint8Array} cdmData the custom data to provide to licenser * @memberof module:ProtectionController * @instance * @fires ProtectionController#KeySessionCreated * @ignore */ function createKeySession(keySystemInfo) { const initDataForKS = CommonEncryption.getPSSHForKeySystem(selectedKeySystem, keySystemInfo ? keySystemInfo.initData : null); if (initDataForKS) { // Check for duplicate key id if (_isKeyIdDuplicate(keySystemInfo.keyId)) { return; } // Check for duplicate initData if (_isInitDataDuplicate(initDataForKS)) { return; } try { keySystemInfo.initData = initDataForKS; protectionModel.createKeySession(keySystemInfo); } catch (error) { eventBus.trigger(events.KEY_SESSION_CREATED, { data: null, error: new DashJSError(ProtectionErrors.KEY_SESSION_CREATED_ERROR_CODE, ProtectionErrors.KEY_SESSION_CREATED_ERROR_MESSAGE + error.message) }); } } else if (keySystemInfo &amp;&amp; keySystemInfo.initData) { protectionModel.createKeySession(keySystemInfo); } else { eventBus.trigger(events.KEY_SESSION_CREATED, { data: null, error: new DashJSError(ProtectionErrors.KEY_SESSION_CREATED_ERROR_CODE, ProtectionErrors.KEY_SESSION_CREATED_ERROR_MESSAGE + 'Selected key system is ' + (selectedKeySystem ? selectedKeySystem.systemString : null) + '. needkey/encrypted event contains no initData corresponding to that key system!') }); } } /** * Returns the protectionData for a specific keysystem as specified by the application. * @param {object} keySystem * @return {object | null} * @private */ function _getProtDataForKeySystem(keySystem) { if (keySystem) { const keySystemString = keySystem.systemString; if (protDataSet) { return (keySystemString in protDataSet) ? protDataSet[keySystemString] : null; } } return null; } /** * Removes all entries from the mediaInfoArr */ function clearMediaInfoArray() { mediaInfoArr = []; } /** * Returns a set of supported key systems and CENC initialization data * from the given array of ContentProtection elements. Only * key systems that are supported by this player will be returned. * Key systems are returned in priority order (highest first). * * @param {Array.&lt;Object&gt;} cps - array of content protection elements parsed * from the manifest * @returns {Array.&lt;Object&gt;} array of objects indicating which supported key * systems were found. Empty array is returned if no * supported key systems were found * @memberof module:ProtectionKeyController * @instance * @ignore */ function getSupportedKeySystemsFromContentProtection(cps) { checkConfig(); return protectionKeyController.getSupportedKeySystemsFromContentProtection(cps, protDataSet, sessionType); } /** * Checks if a session has already created for the provided key id * @param {string} keyId * @return {boolean} * @private */ function _isKeyIdDuplicate(keyId) { if (!keyId) { return false; } try { const sessions = protectionModel.getSessions(); for (let i = 0; i &lt; sessions.length; i++) { if (sessions[i].getKeyId() === keyId) { return true; } } return false; } catch (e) { return false; } } /** * Checks if the provided init data is equal to one of the existing init data values * @param {any} initDataForKS * @return {boolean} * @private */ function _isInitDataDuplicate(initDataForKS) { if (!initDataForKS) { return false; } try { const currentInitData = protectionModel.getAllInitData(); for (let i = 0; i &lt; currentInitData.length; i++) { if (protectionKeyController.initDataEquals(initDataForKS, currentInitData[i])) { logger.debug('DRM: Ignoring initData because we have already seen it!'); return true; } } return false; } catch (e) { return false; } } /** * Removes the given key session from persistent storage and closes the session * as if {@link ProtectionController#closeKeySession} * was called * * @param {SessionToken} sessionToken the session * token * @memberof module:ProtectionController * @instance * @fires ProtectionController#KeySessionRemoved * @fires ProtectionController#KeySessionClosed * @ignore */ function removeKeySession(sessionToken) { checkConfig(); protectionModel.removeKeySession(sessionToken); } /** * Closes the key session and releases all associated decryption keys. These * keys will no longer be available for decrypting media * * @param {SessionToken} sessionToken the session * token * @memberof module:ProtectionController * @instance * @fires ProtectionController#KeySessionClosed * @ignore */ function closeKeySession(sessionToken) { checkConfig(); protectionModel.closeKeySession(sessionToken); } /** * Sets a server certificate for use by the CDM when signing key messages * intended for a particular license server. This will fire * an error event if a key system has not yet been selected. * * @param {ArrayBuffer} serverCertificate a CDM-specific license server * certificate * @memberof module:ProtectionController * @instance * @fires ProtectionController#ServerCertificateUpdated */ function setServerCertificate(serverCertificate) { checkConfig(); protectionModel.setServerCertificate(serverCertificate); } /** * Associate this protection system with the given HTMLMediaElement. This * causes the system to register for needkey/encrypted events from the given * element and provides a destination for setting of MediaKeys * * @param {HTMLMediaElement} element the media element to which the protection * system should be associated * @memberof module:ProtectionController * @instance */ function setMediaElement(element) { checkConfig(); if (element) { protectionModel.setMediaElement(element); eventBus.on(events.NEED_KEY, _onNeedKey, instance); } else if (element === null) { protectionModel.setMediaElement(element); eventBus.off(events.NEED_KEY, _onNeedKey, instance); } } /** * Sets the session type to use when creating key sessions. Either \"temporary\" or * \"persistent-license\". Default is \"temporary\". * * @param {string} value the session type * @memberof module:ProtectionController * @instance */ function setSessionType(value) { sessionType = value; } /** * Sets the robustness level for video and audio capabilities. Optional to remove Chrome warnings. * Possible values are SW_SECURE_CRYPTO, SW_SECURE_DECODE, HW_SECURE_CRYPTO, HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL. * * @param {string} level the robustness level * @memberof module:ProtectionController * @instance */ function setRobustnessLevel(level) { robustnessLevel = level; } /** * Attach KeySystem-specific data to use for license acquisition with EME * * @param {Object} data an object containing property names corresponding to * key system name strings (e.g. \"org.w3.clearkey\") and associated values * being instances of {@link ProtectionData} * @memberof module:ProtectionController * @instance * @ignore */ function setProtectionData(data) { protDataSet = data; protectionKeyController.setProtectionData(data); } /** * Stop method is called when current playback is stopped/resetted. * * @memberof module:ProtectionController * @instance */ function stop() { _abortLicenseRequest(); if (protectionModel) { protectionModel.stop(); } } /** * Destroys all protection data associated with this protection set. This includes * deleting all key sessions. In the case of persistent key sessions, the sessions * will simply be unloaded and not deleted. Additionally, if this protection set is * associated with a HTMLMediaElement, it will be detached from that element. * * @memberof module:ProtectionController * @instance * @ignore */ function reset() { eventBus.off(events.INTERNAL_KEY_MESSAGE, _onKeyMessage, instance); eventBus.off(events.INTERNAL_KEY_STATUS_CHANGED, _onKeyStatusChanged, instance); checkConfig(); _abortLicenseRequest(); setMediaElement(null); selectedKeySystem = null; keySystemSelectionInProgress = false; if (protectionModel) { protectionModel.reset(); protectionModel = null; } needkeyRetries.forEach(retryTimeout =&gt; clearTimeout(retryTimeout)); needkeyRetries = []; mediaInfoArr = []; pendingKeySessionsToHandle = []; } /** * Returns an object corresponding to the EME MediaKeySystemConfiguration dictionary * @param {object} keySystem * @return {KeySystemConfiguration} * @private */ function _getKeySystemConfiguration(keySystemData) { const protData = keySystemData.protData; const audioCapabilities = []; const videoCapabilities = []; const audioRobustness = (protData &amp;&amp; protData.audioRobustness &amp;&amp; protData.audioRobustness.length &gt; 0) ? protData.audioRobustness : robustnessLevel; const videoRobustness = (protData &amp;&amp; protData.videoRobustness &amp;&amp; protData.videoRobustness.length &gt; 0) ? protData.videoRobustness : robustnessLevel; const ksSessionType = keySystemData.sessionType; const distinctiveIdentifier = (protData &amp;&amp; protData.distinctiveIdentifier) ? protData.distinctiveIdentifier : 'optional'; const persistentState = (protData &amp;&amp; protData.persistentState) ? protData.persistentState : (ksSessionType === 'temporary') ? 'optional' : 'required'; mediaInfoArr.forEach((media) =&gt; { if (media.type === constants.AUDIO) { audioCapabilities.push(new MediaCapability(media.codec, audioRobustness)); } else if (media.type === constants.VIDEO) { videoCapabilities.push(new MediaCapability(media.codec, videoRobustness)); } }); return new KeySystemConfiguration( audioCapabilities, videoCapabilities, distinctiveIdentifier, persistentState, [ksSessionType]); } /** * Event handler for when the status of the key has changed * @param {object} e * @private */ function _onKeyStatusChanged(e) { if (e.error) { eventBus.trigger(events.KEY_STATUSES_CHANGED, { data: null, error: e.error }); } else { logger.debug('DRM: key status = ' + e.status); } } /** * Event handler for the key message event. Once we have a key message we can issue a license request * @param {object} e * @private */ function _onKeyMessage(e) { logger.debug('DRM: onKeyMessage'); // Dispatch event to applications indicating we received a key message const keyMessage = e.data; eventBus.trigger(events.KEY_MESSAGE, { data: keyMessage }); const messageType = (keyMessage.messageType) ? keyMessage.messageType : 'license-request'; const message = keyMessage.message; const sessionToken = keyMessage.sessionToken; const protData = _getProtDataForKeySystem(selectedKeySystem); const licenseServerModelInstance = protectionKeyController.getLicenseServerModelInstance(selectedKeySystem, protData, messageType); const eventData = { sessionToken: sessionToken, messageType: messageType }; // Ensure message from CDM is not empty if (!message || message.byteLength === 0) { _sendLicenseRequestCompleteEvent(eventData, new DashJSError(ProtectionErrors.MEDIA_KEY_MESSAGE_NO_CHALLENGE_ERROR_CODE, ProtectionErrors.MEDIA_KEY_MESSAGE_NO_CHALLENGE_ERROR_MESSAGE)); return; } // Message not destined for license server if (!licenseServerModelInstance) { logger.debug('DRM: License server request not required for this message (type = ' + e.data.messageType + '). Session ID = ' + sessionToken.getSessionId()); _sendLicenseRequestCompleteEvent(eventData); return; } // Perform any special handling for ClearKey if (protectionKeyController.isClearKey(selectedKeySystem)) { const clearkeys = protectionKeyController.processClearKeyLicenseRequest(selectedKeySystem, protData, message); if (clearkeys &amp;&amp; clearkeys.keyPairs &amp;&amp; clearkeys.keyPairs.length &gt; 0) { logger.debug('DRM: ClearKey license request handled by application!'); _sendLicenseRequestCompleteEvent(eventData); protectionModel.updateKeySession(sessionToken, clearkeys); return; } } // In all other cases we have to make a license request _issueLicenseRequest(keyMessage, licenseServerModelInstance, protData); } /** * Notify other classes that the license request was completed * @param {object} data * @param {object} error * @private */ function _sendLicenseRequestCompleteEvent(data, error) { eventBus.trigger(events.LICENSE_REQUEST_COMPLETE, { data: data, error: error }); } /** * Start issuing a license request * @param {object} keyMessage * @param {object} licenseServerData * @param {object} protData * @private */ function _issueLicenseRequest(keyMessage, licenseServerData, protData) { const sessionToken = keyMessage.sessionToken; const messageType = (keyMessage.messageType) ? keyMessage.messageType : 'license-request'; const eventData = { sessionToken: sessionToken, messageType: messageType }; const keySystemString = selectedKeySystem ? selectedKeySystem.systemString : null; // Determine license server URL let url = _getLicenseServerUrl(protData, messageType, sessionToken, keyMessage, licenseServerData); // Ensure valid license server URL if (!url) { _sendLicenseRequestCompleteEvent(eventData, new DashJSError(ProtectionErrors.MEDIA_KEY_MESSAGE_NO_LICENSE_SERVER_URL_ERROR_CODE, ProtectionErrors.MEDIA_KEY_MESSAGE_NO_LICENSE_SERVER_URL_ERROR_MESSAGE)); return; } // Set optional XMLHttpRequest headers from protection data and message const reqHeaders = {}; let withCredentials = false; if (protData) { _updateHeaders(reqHeaders, protData.httpRequestHeaders); } const message = keyMessage.message; const headersFromMessage = selectedKeySystem.getRequestHeadersFromMessage(message); _updateHeaders(reqHeaders, headersFromMessage); Object.keys(reqHeaders).forEach((key) =&gt; { if ('authorization' === key.toLowerCase()) { withCredentials = true; } }); // Overwrite withCredentials property from protData if present if (protData &amp;&amp; typeof protData.withCredentials == 'boolean') { withCredentials = protData.withCredentials; } const onLoad = function (xhr) { if (!protectionModel) { return; } if (xhr.status &gt;= 200 &amp;&amp; xhr.status &lt;= 299) { const responseHeaders = Utils.parseHttpHeaders(xhr.getAllResponseHeaders ? xhr.getAllResponseHeaders() : null); let licenseResponse = new LicenseResponse(xhr.responseURL, responseHeaders, xhr.response); const licenseResponseFilters = customParametersModel.getLicenseResponseFilters(); _applyFilters(licenseResponseFilters, licenseResponse) .then(() =&gt; { const licenseMessage = licenseServerData.getLicenseMessage(licenseResponse.data, keySystemString, messageType); if (licenseMessage !== null) { _sendLicenseRequestCompleteEvent(eventData); protectionModel.updateKeySession(sessionToken, licenseMessage); } else { _reportError(xhr, eventData, keySystemString, messageType, licenseServerData); } }); } else { _reportError(xhr, eventData, keySystemString, messageType, licenseServerData); } }; const onAbort = function (xhr) { _sendLicenseRequestCompleteEvent(eventData, new DashJSError(ProtectionErrors.MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE, ProtectionErrors.MEDIA_KEY_MESSAGE_LICENSER_ERROR_MESSAGE + keySystemString + ' update, XHR aborted. status is \"' + xhr.statusText + '\" (' + xhr.status + '), readyState is ' + xhr.readyState)); }; const onError = function (xhr) { _sendLicenseRequestCompleteEvent(eventData, new DashJSError(ProtectionErrors.MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE, ProtectionErrors.MEDIA_KEY_MESSAGE_LICENSER_ERROR_MESSAGE + keySystemString + ' update, XHR error. status is \"' + xhr.statusText + '\" (' + xhr.status + '), readyState is ' + xhr.readyState)); }; const reqPayload = selectedKeySystem.getLicenseRequestFromMessage(message); const reqMethod = licenseServerData.getHTTPMethod(messageType); const responseType = licenseServerData.getResponseType(keySystemString, messageType); const timeout = protData &amp;&amp; !isNaN(protData.httpTimeout) ? protData.httpTimeout : LICENSE_SERVER_REQUEST_DEFAULT_TIMEOUT; const sessionId = sessionToken.getSessionId() || null; let licenseRequest = new LicenseRequest(url, reqMethod, responseType, reqHeaders, withCredentials, messageType, sessionId, reqPayload); const retryAttempts = !isNaN(settings.get().streaming.retryAttempts[HTTPRequest.LICENSE]) ? settings.get().streaming.retryAttempts[HTTPRequest.LICENSE] : LICENSE_SERVER_REQUEST_RETRIES; const licenseRequestFilters = customParametersModel.getLicenseRequestFilters(); _applyFilters(licenseRequestFilters, licenseRequest) .then(() =&gt; { _doLicenseRequest(licenseRequest, retryAttempts, timeout, onLoad, onAbort, onError); }); } /** * Implement license requests with a retry mechanism to avoid temporary network issues to affect playback experience * @param {object} request * @param {number} retriesCount * @param {number} timeout * @param {function} onLoad * @param {function} onAbort * @param {function} onError * @private */ function _doLicenseRequest(request, retriesCount, timeout, onLoad, onAbort, onError) { const xhr = new XMLHttpRequest(); if (settings.get().streaming.cmcd &amp;&amp; settings.get().streaming.cmcd.enabled) { const cmcdMode = settings.get().streaming.cmcd.mode; if (cmcdMode === Constants.CMCD_MODE_QUERY) { const cmcdParams = cmcdModel.getQueryParameter({ url: request.url, type: HTTPRequest.LICENSE }); if (cmcdParams) { request.url = Utils.addAditionalQueryParameterToUrl(request.url, [cmcdParams]); } } } xhr.open(request.method, request.url, true); xhr.responseType = request.responseType; xhr.withCredentials = request.withCredentials; if (timeout &gt; 0) { xhr.timeout = timeout; } for (const key in request.headers) { xhr.setRequestHeader(key, request.headers[key]); } if (settings.get().streaming.cmcd &amp;&amp; settings.get().streaming.cmcd.enabled) { const cmcdMode = settings.get().streaming.cmcd.mode; if (cmcdMode === Constants.CMCD_MODE_HEADER) { const cmcdHeaders = cmcdModel.getHeaderParameters({ url: request.url, type: HTTPRequest.LICENSE }); if (cmcdHeaders) { for (const header in cmcdHeaders) { let value = cmcdHeaders[header]; if (value) { xhr.setRequestHeader(header, value); } } } } } const _retryRequest = function () { // fail silently and retry retriesCount--; const retryInterval = !isNaN(settings.get().streaming.retryIntervals[HTTPRequest.LICENSE]) ? settings.get().streaming.retryIntervals[HTTPRequest.LICENSE] : LICENSE_SERVER_REQUEST_RETRY_INTERVAL; licenseRequestRetryTimeout = setTimeout(function () { _doLicenseRequest(request, retriesCount, timeout, onLoad, onAbort, onError); }, retryInterval); }; xhr.onload = function () { licenseXhrRequest = null; if (this.status &gt;= 200 &amp;&amp; this.status &lt;= 299 || retriesCount &lt;= 0) { onLoad(this); } else { logger.warn('License request failed (' + this.status + '). Retrying it... Pending retries: ' + retriesCount); _retryRequest(); } }; xhr.ontimeout = xhr.onerror = function () { licenseXhrRequest = null; if (retriesCount &lt;= 0) { onError(this); } else { logger.warn('License request network request failed . Retrying it... Pending retries: ' + retriesCount); _retryRequest(); } }; xhr.onabort = function () { onAbort(this); }; // deprecated, to be removed eventBus.trigger(events.LICENSE_REQUEST_SENDING, { url: request.url, headers: request.headers, payload: request.data, sessionId: request.sessionId }); licenseXhrRequest = xhr; xhr.send(request.data); } /** * Aborts license request * @private */ function _abortLicenseRequest() { if (licenseXhrRequest) { licenseXhrRequest.onloadend = licenseXhrRequest.onerror = licenseXhrRequest.onprogress = undefined; //Ignore events from aborted requests. licenseXhrRequest.abort(); licenseXhrRequest = null; } if (licenseRequestRetryTimeout) { clearTimeout(licenseRequestRetryTimeout); licenseRequestRetryTimeout = null; } } /** * Returns the url of the license server * @param {object} protData * @param {string} messageType * @param {object} sessionToken * @param {object} keyMessage * @param {object} licenseServerData * @return {*} * @private */ function _getLicenseServerUrl(protData, messageType, sessionToken, keyMessage, licenseServerData) { let url = null; const message = keyMessage.message; // Check if the url is defined by the application if (protData &amp;&amp; protData.serverURL) { const serverURL = protData.serverURL; if (typeof serverURL === 'string' &amp;&amp; serverURL !== '') { url = serverURL; } else if (typeof serverURL === 'object' &amp;&amp; serverURL.hasOwnProperty(messageType)) { url = serverURL[messageType]; } } // This is the old way of providing the url else if (protData &amp;&amp; protData.laURL &amp;&amp; protData.laURL !== '') { url = protData.laURL; } // No url provided by the app. Check the manifest and the pssh else { // Check for url defined in the manifest url = CommonEncryption.getLicenseServerUrlFromMediaInfo(mediaInfoArr, selectedKeySystem.schemeIdURI); // In case we are not using Clearky we can still get a url from the pssh. if (!url &amp;&amp; !protectionKeyController.isClearKey(selectedKeySystem)) { const psshData = CommonEncryption.getPSSHData(sessionToken.initData); url = selectedKeySystem.getLicenseServerURLFromInitData(psshData); // Still no url, check the keymessage if (!url) { url = keyMessage.laURL; } } } // Possibly update or override the URL based on the message url = licenseServerData.getServerURLFromMessage(url, message, messageType); return url; } /** * Add new headers to the existing ones * @param {array} reqHeaders * @param {object} headers * @private */ function _updateHeaders(reqHeaders, headers) { if (headers) { for (const key in headers) { reqHeaders[key] = headers[key]; } } } /** * Reports an error that might have occured during the license request * @param {object} xhr * @param {object} eventData * @param {string} keySystemString * @param {string} messageType * @param {object} licenseServerData * @private */ function _reportError(xhr, eventData, keySystemString, messageType, licenseServerData) { let errorMsg = 'NONE'; let data = null; if (xhr.response) { errorMsg = licenseServerData.getErrorResponse(xhr.response, keySystemString, messageType); data = { serverResponse: xhr.response || null, responseCode: xhr.status || null, responseText: xhr.statusText || null } } _sendLicenseRequestCompleteEvent(eventData, new DashJSError(ProtectionErrors.MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE, ProtectionErrors.MEDIA_KEY_MESSAGE_LICENSER_ERROR_MESSAGE + keySystemString + ' update, XHR complete. status is \"' + xhr.statusText + '\" (' + xhr.status + '), readyState is ' + xhr.readyState + '. Response is ' + errorMsg, data )); } /** * Applies custom filters defined by the application * @param {array} filters * @param {object} param * @return {Promise&lt;void&gt;|*} * @private */ function _applyFilters(filters, param) { if (!filters) return Promise.resolve(); return filters.reduce((prev, next) =&gt; { return prev.then(() =&gt; { return next(param); }); }, Promise.resolve()); } /** * Event handler for \"needkey\" and \"encrypted\" events * @param {object} event * @param {number} retry */ function _onNeedKey(event, retry) { if (!settings.get().streaming.protection.ignoreEmeEncryptedEvent) { logger.debug('DRM: onNeedKey'); // Ignore non-cenc initData if (event.key.initDataType !== 'cenc') { logger.warn('DRM: Only \\'cenc\\' initData is supported! Ignoring initData of type: ' + event.key.initDataType); return; } if (mediaInfoArr.length === 0) { logger.warn('DRM: onNeedKey called before initializeForMedia, wait until initialized'); retry = typeof retry === 'undefined' ? 1 : retry + 1; if (retry &lt; NEEDKEY_BEFORE_INITIALIZE_RETRIES) { needkeyRetries.push(setTimeout(() =&gt; { _onNeedKey(event, retry); }, NEEDKEY_BEFORE_INITIALIZE_TIMEOUT)); return; } } // Some browsers return initData as Uint8Array (IE), some as ArrayBuffer (Chrome). // Convert to ArrayBuffer let abInitData = event.key.initData; if (ArrayBuffer.isView(abInitData)) { abInitData = abInitData.buffer; } // If key system has already been selected and initData already seen, then do nothing if (selectedKeySystem) { const initDataForKS = CommonEncryption.getPSSHForKeySystem(selectedKeySystem, abInitData); if (initDataForKS) { // Check for duplicate initData if (_isInitDataDuplicate(initDataForKS)) { return; } } } logger.debug('DRM: initData:', String.fromCharCode.apply(null, new Uint8Array(abInitData))); const supportedKs = protectionKeyController.getSupportedKeySystemsFromSegmentPssh(abInitData, protDataSet, sessionType); if (supportedKs.length === 0) { logger.debug('DRM: Received needkey event with initData, but we don\\'t support any of the key systems!'); return; } _handleKeySystemFromPssh(supportedKs); } } /** * Returns all available key systems * @return {array} */ function getKeySystems() { return protectionKeyController ? protectionKeyController.getKeySystems() : []; } /** * Sets all available key systems * @param {array} keySystems */ function setKeySystems(keySystems) { if (protectionKeyController) { protectionKeyController.setKeySystems(keySystems); } } instance = { initializeForMedia, clearMediaInfoArray, handleKeySystemFromManifest, createKeySession, loadKeySession, removeKeySession, closeKeySession, setServerCertificate, setMediaElement, setSessionType, setRobustnessLevel, setProtectionData, getSupportedKeySystemsFromContentProtection, getKeySystems, setKeySystems, stop, reset }; setup(); return instance; } ProtectionController.__dashjs_factory_name = 'ProtectionController'; export default FactoryMaker.getClassFactory(ProtectionController); /* jshint ignore:line */ × Search results Close "},"streaming_protection_controllers_ProtectionKeyController.js.html":{"id":"streaming_protection_controllers_ProtectionKeyController.js.html","title":"Source: streaming/protection/controllers/ProtectionKeyController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/controllers/ProtectionKeyController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import CommonEncryption from './../CommonEncryption'; import KeySystemClearKey from './../drm/KeySystemClearKey'; import KeySystemW3CClearKey from './../drm/KeySystemW3CClearKey'; import KeySystemWidevine from './../drm/KeySystemWidevine'; import KeySystemPlayReady from './../drm/KeySystemPlayReady'; import DRMToday from './../servers/DRMToday'; import PlayReady from './../servers/PlayReady'; import Widevine from './../servers/Widevine'; import ClearKey from './../servers/ClearKey'; import ProtectionConstants from '../../constants/ProtectionConstants'; /** * @module ProtectionKeyController * @ignore * @description Media protection key system functionality that can be modified/overridden by applications */ function ProtectionKeyController() { let context = this.context; let instance, debug, logger, keySystems, BASE64, settings, clearkeyKeySystem, clearkeyW3CKeySystem; function setConfig(config) { if (!config) return; if (config.debug) { debug = config.debug; logger = debug.getLogger(instance); } if (config.BASE64) { BASE64 = config.BASE64; } if(config.settings) { settings = config.settings } } function initialize() { keySystems = []; let keySystem; // PlayReady keySystem = KeySystemPlayReady(context).getInstance({BASE64: BASE64, settings: settings}); keySystems.push(keySystem); // Widevine keySystem = KeySystemWidevine(context).getInstance({BASE64: BASE64}); keySystems.push(keySystem); // ClearKey keySystem = KeySystemClearKey(context).getInstance({BASE64: BASE64}); keySystems.push(keySystem); clearkeyKeySystem = keySystem; // W3C ClearKey keySystem = KeySystemW3CClearKey(context).getInstance({BASE64: BASE64, debug: debug}); keySystems.push(keySystem); clearkeyW3CKeySystem = keySystem; } /** * Returns a prioritized list of key systems supported * by this player (not necessarily those supported by the * user agent) * * @returns {Array.&lt;KeySystem&gt;} a prioritized * list of key systems * @memberof module:ProtectionKeyController * @instance */ function getKeySystems() { return keySystems; } /** * Sets the prioritized list of key systems to be supported * by this player. * * @param {Array.&lt;KeySystem&gt;} newKeySystems the new prioritized * list of key systems * @memberof module:ProtectionKeyController * @instance */ function setKeySystems(newKeySystems) { keySystems = newKeySystems; } /** * Returns the key system associated with the given key system string * name (i.e. 'org.w3.clearkey') * * @param {string} systemString the system string * @returns {KeySystem|null} the key system * or null if no supported key system is associated with the given key * system string * @memberof module:ProtectionKeyController * @instance */ function getKeySystemBySystemString(systemString) { for (let i = 0; i &lt; keySystems.length; i++) { if (keySystems[i].systemString === systemString) { return keySystems[i]; } } return null; } /** * Determines whether the given key system is ClearKey. This is * necessary because the EME spec defines ClearKey and its method * for providing keys to the key session; and this method has changed * between the various API versions. Our EME-specific ProtectionModels * must know if the system is ClearKey so that it can format the keys * according to the particular spec version. * * @param {Object} keySystem the key * @returns {boolean} true if this is the ClearKey key system, false * otherwise * @memberof module:ProtectionKeyController * @instance */ function isClearKey(keySystem) { return (keySystem === clearkeyKeySystem || keySystem === clearkeyW3CKeySystem); } /** * Check equality of initData array buffers. * * @param {ArrayBuffer} initData1 - first initData * @param {ArrayBuffer} initData2 - second initData * @returns {boolean} true if the initData arrays are equal in size and * contents, false otherwise * @memberof module:ProtectionKeyController * @instance */ function initDataEquals(initData1, initData2) { if (initData1.byteLength === initData2.byteLength) { let data1 = new Uint8Array(initData1); let data2 = new Uint8Array(initData2); for (let j = 0; j &lt; data1.length; j++) { if (data1[j] !== data2[j]) { return false; } } return true; } return false; } /** * Returns a set of supported key systems and CENC initialization data * from the given array of ContentProtection elements. Only * key systems that are supported by this player will be returned. * Key systems are returned in priority order (highest first). * * @param {Array.&lt;Object&gt;} cps - array of content protection elements parsed * from the manifest * @param {ProtectionData} protDataSet user specified protection data - license server url etc * supported by the content * @param {string} default session type * @returns {Array.&lt;Object&gt;} array of objects indicating which supported key * systems were found. Empty array is returned if no * supported key systems were found * @memberof module:ProtectionKeyController * @instance */ function getSupportedKeySystemsFromContentProtection(cps, protDataSet, sessionType) { let cp, ks, ksIdx, cpIdx; let supportedKS = []; if (cps) { const cencContentProtection = CommonEncryption.findCencContentProtection(cps); for (ksIdx = 0; ksIdx &lt; keySystems.length; ++ksIdx) { ks = keySystems[ksIdx]; // Get protection data that applies for current key system const protData = _getProtDataForKeySystem(ks.systemString, protDataSet); for (cpIdx = 0; cpIdx &lt; cps.length; ++cpIdx) { cp = cps[cpIdx]; if (cp.schemeIdUri.toLowerCase() === ks.schemeIdURI) { // Look for DRM-specific ContentProtection let initData = ks.getInitData(cp, cencContentProtection); supportedKS.push({ ks: keySystems[ksIdx], keyId: cp.keyId, initData: initData, protData: protData, cdmData: ks.getCDMData(protData ? protData.cdmData : null), sessionId: _getSessionId(protData, cp), sessionType: _getSessionType(protData, sessionType) }); } } } } return supportedKS; } /** * Returns key systems supported by this player for the given PSSH * initializationData. Key systems are returned in priority order * (highest priority first) * * @param {ArrayBuffer} initData Concatenated PSSH data for all DRMs * supported by the content * @param {ProtectionData} protDataSet user specified protection data - license server url etc * supported by the content * @param {string} default session type * @returns {Array.&lt;Object&gt;} array of objects indicating which supported key * systems were found. Empty array is returned if no * supported key systems were found * @memberof module:ProtectionKeyController * @instance */ function getSupportedKeySystemsFromSegmentPssh(initData, protDataSet, sessionType) { let supportedKS = []; let pssh = CommonEncryption.parsePSSHList(initData); let ks, keySystemString; for (let ksIdx = 0; ksIdx &lt; keySystems.length; ++ksIdx) { ks = keySystems[ksIdx]; keySystemString = ks.systemString; // Get protection data that applies for current key system const protData = _getProtDataForKeySystem(keySystemString, protDataSet); if (ks.uuid in pssh) { supportedKS.push({ ks: ks, initData: pssh[ks.uuid], protData: protData, cdmData: ks.getCDMData(protData ? protData.cdmData : null), sessionId: _getSessionId(protData), sessionType: _getSessionType(protData, sessionType) }); } } return supportedKS; } /** * Returns the license server implementation data that should be used for this request. * * @param {KeySystem} keySystem the key system * associated with this license request * @param {ProtectionData} protData protection data to use for the * request * @param {string} [messageType=\"license-request\"] the message type associated with this * request. Supported message types can be found * {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}. * @returns {LicenseServer|null} the license server * implementation that should be used for this request or null if the player should not * pass messages of the given type to a license server * @memberof module:ProtectionKeyController * @instance * */ function getLicenseServerModelInstance(keySystem, protData, messageType) { // Our default server implementations do not do anything with \"license-release\" or // \"individualization-request\" messages, so we just send a success event if (messageType === 'license-release' || messageType === 'individualization-request') { return null; } let licenseServerData = null; if (protData &amp;&amp; protData.hasOwnProperty('drmtoday')) { licenseServerData = DRMToday(context).getInstance({BASE64: BASE64}); } else if (keySystem.systemString === ProtectionConstants.WIDEVINE_KEYSTEM_STRING) { licenseServerData = Widevine(context).getInstance(); } else if (keySystem.systemString === ProtectionConstants.PLAYREADY_KEYSTEM_STRING) { licenseServerData = PlayReady(context).getInstance(); } else if (keySystem.systemString === ProtectionConstants.CLEARKEY_KEYSTEM_STRING) { licenseServerData = ClearKey(context).getInstance(); } return licenseServerData; } /** * Allows application-specific retrieval of ClearKey keys. * * @param {KeySystem} clearkeyKeySystem They exact ClearKey System to be used * @param {ProtectionData} protData protection data to use for the * request * @param {ArrayBuffer} message the key message from the CDM * @return {ClearKeyKeySet|null} the clear keys associated with * the request or null if no keys can be returned by this function * @memberof module:ProtectionKeyController * @instance */ function processClearKeyLicenseRequest(clearkeyKeySystem, protData, message) { try { return clearkeyKeySystem.getClearKeysFromProtectionData(protData, message); } catch (error) { logger.error('Failed to retrieve clearkeys from ProtectionData'); return null; } } function setProtectionData(protectionDataSet) { var getProtectionData = function (keySystemString) { var protData = null; if (protectionDataSet) { protData = (keySystemString in protectionDataSet) ? protectionDataSet[keySystemString] : null; } return protData; }; for (var i = 0; i &lt; keySystems.length; i++) { var keySystem = keySystems[i]; if (keySystem.hasOwnProperty('init')) { keySystem.init(getProtectionData(keySystem.systemString)); } } } function _getProtDataForKeySystem(systemString, protDataSet) { if (!protDataSet) return null; return (systemString in protDataSet) ? protDataSet[systemString] : null; } function _getSessionId(protData, cp) { // Get sessionId from protectionData or from manifest (ContentProtection) if (protData &amp;&amp; protData.sessionId) { return protData.sessionId; } else if (cp &amp;&amp; cp.sessionId) { return cp.sessionId; } return null; } function _getSessionType(protData, sessionType) { return (protData &amp;&amp; protData.sessionType) ? protData.sessionType : sessionType; } instance = { initialize, setProtectionData, isClearKey, initDataEquals, getKeySystems, setKeySystems, getKeySystemBySystemString, getSupportedKeySystemsFromContentProtection, getSupportedKeySystemsFromSegmentPssh, getLicenseServerModelInstance, processClearKeyLicenseRequest, setConfig }; return instance; } ProtectionKeyController.__dashjs_factory_name = 'ProtectionKeyController'; export default dashjs.FactoryMaker.getSingletonFactory(ProtectionKeyController); /* jshint ignore:line */ × Search results Close "},"core_Settings.js.html":{"id":"core_Settings.js.html","title":"Source: core/Settings.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: core/Settings.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from './FactoryMaker'; import Utils from './Utils.js'; import Debug from '../core/Debug'; import Constants from '../streaming/constants/Constants'; import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest'; import EventBus from './EventBus'; import Events from './events/Events'; /** @module Settings * @description Define the configuration parameters of Dash.js MediaPlayer. * @see {@link module:Settings~PlayerSettings PlayerSettings} for further information about the supported configuration properties. */ /** * @typedef {Object} PlayerSettings * @property {module:Settings~DebugSettings} [debug] * Debug related settings. * @property {module:Settings~ErrorSettings} [errors] * Error related settings * @property {module:Settings~StreamingSettings} [streaming] * Streaming related settings. * @example * * // Full settings object * settings = { * debug: { * logLevel: Debug.LOG_LEVEL_WARNING, * dispatchEvent: false * }, * streaming: { * abandonLoadTimeout: 10000, * wallclockTimeUpdateInterval: 100, * manifestUpdateRetryInterval: 100, * cacheInitSegments: true, * applyServiceDescription: true, * applyProducerReferenceTime: true, * applyContentSteering: true, * eventControllerRefreshDelay: 100, * enableManifestDurationMismatchFix: true, * capabilities: { * filterUnsupportedEssentialProperties: true, * useMediaCapabilitiesApi: false * }, * timeShiftBuffer: { * calcFromSegmentTimeline: false, * fallbackToSegmentTimeline: true * }, * metrics: { * maxListDepth: 100 * }, * delay: { * liveDelayFragmentCount: NaN, * liveDelay: NaN, * useSuggestedPresentationDelay: true * }, * protection: { * keepProtectionMediaKeys: false, * ignoreEmeEncryptedEvent: false, * detectPlayreadyMessageFormat: true, * }, * buffer: { * enableSeekDecorrelationFix: true, * fastSwitchEnabled: true, * flushBufferAtTrackSwitch: false, * reuseExistingSourceBuffers: true, * bufferPruningInterval: 10, * bufferToKeep: 20, * bufferTimeAtTopQuality: 30, * bufferTimeAtTopQualityLongForm: 60, * initialBufferLevel: NaN, * stableBufferTime: 12, * longFormContentDurationThreshold: 600, * stallThreshold: 0.5, * useAppendWindow: true, * setStallState: true, * avoidCurrentTimeRangePruning: false * }, * gaps: { * jumpGaps: true, * jumpLargeGaps: true, * smallGapLimit: 1.5, * threshold: 0.3, * enableSeekFix: true, * enableStallFix: false, * stallSeek: 0.1 * }, * utcSynchronization: { * enabled: true, * useManifestDateHeaderTimeSource: true, * backgroundAttempts: 2, * timeBetweenSyncAttempts: 30, * maximumTimeBetweenSyncAttempts: 600, * minimumTimeBetweenSyncAttempts: 2, * timeBetweenSyncAttemptsAdjustmentFactor: 2, * maximumAllowedDrift: 100, * enableBackgroundSyncAfterSegmentDownloadError: true, * defaultTimingSource: { * scheme: 'urn:mpeg:dash:utc:http-xsdate:2014', * value: 'http://time.akamai.com/?iso&amp;ms' * } * }, * scheduling: { * defaultTimeout: 300, * lowLatencyTimeout: 100, * scheduleWhilePaused: true * }, * text: { * defaultEnabled: true * }, * liveCatchup: { * maxDrift: NaN, * playbackRate: NaN, * playbackBufferMin: 0.5, * enabled: false, * mode: Constants.LIVE_CATCHUP_MODE_DEFAULT * }, * lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, * lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, * cacheLoadThresholds: { video: 50, audio: 5 }, * trackSwitchMode: { * audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE, * video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE * }, * selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY, * fragmentRequestTimeout: 0, * retryIntervals: { * [HTTPRequest.MPD_TYPE]: 500, * [HTTPRequest.XLINK_EXPANSION_TYPE]: 500, * [HTTPRequest.MEDIA_SEGMENT_TYPE]: 1000, * [HTTPRequest.INIT_SEGMENT_TYPE]: 1000, * [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 1000, * [HTTPRequest.INDEX_SEGMENT_TYPE]: 1000, * [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 1000, * [HTTPRequest.LICENSE]: 1000, * [HTTPRequest.OTHER_TYPE]: 1000, * lowLatencyReductionFactor: 10 * }, * retryAttempts: { * [HTTPRequest.MPD_TYPE]: 3, * [HTTPRequest.XLINK_EXPANSION_TYPE]: 1, * [HTTPRequest.MEDIA_SEGMENT_TYPE]: 3, * [HTTPRequest.INIT_SEGMENT_TYPE]: 3, * [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 3, * [HTTPRequest.INDEX_SEGMENT_TYPE]: 3, * [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 3, * [HTTPRequest.LICENSE]: 3, * [HTTPRequest.OTHER_TYPE]: 3, * lowLatencyMultiplyFactor: 5 * }, * abr: { * movingAverageMethod: Constants.MOVING_AVERAGE_SLIDING_WINDOW, * ABRStrategy: Constants.ABR_STRATEGY_DYNAMIC, * additionalAbrRules: { * insufficientBufferRule: false, * switchHistoryRule: true, * droppedFramesRule: true, * abandonRequestsRule: false * }, * bandwidthSafetyFactor: 0.9, * useDefaultABRRules: true, * useDeadTimeLatency: true, * limitBitrateByPortal: false, * usePixelRatioInLimitBitrateByPortal: false, * maxBitrate: { audio: -1, video: -1 }, * minBitrate: { audio: -1, video: -1 }, * maxRepresentationRatio: { audio: 1, video: 1 }, * initialBitrate: { audio: -1, video: -1 }, * initialRepresentationRatio: { audio: -1, video: -1 }, * autoSwitchBitrate: { audio: true, video: true }, * fetchThroughputCalculationMode: Constants.ABR_FETCH_THROUGHPUT_CALCULATION_DOWNLOADED_DATA * }, * cmcd: { * enabled: false, * sid: null, * cid: null, * rtp: null, * rtpSafetyFactor: 5, * mode: Constants.CMCD_MODE_QUERY, * enabledKeys: ['br', 'd', 'ot', 'tb' , 'bl', 'dl', 'mtp', 'nor', 'nrr', 'su' , 'bs', 'rtp' , 'cid', 'pr', 'sf', 'sid', 'st', 'v'] * } * }, * errors: { * recoverAttempts: { * mediaErrorDecode: 5 * } * } * } */ /** * @typedef {Object} TimeShiftBuffer * @property {boolean} [calcFromSegmentTimeline=false] * Enable calculation of the DVR window for SegmentTimeline manifests based on the entries in \\&lt;SegmentTimeline\\&gt;. * * @property {boolean} [fallbackToSegmentTimeline=true] * In case the MPD uses \\&lt;SegmentTimeline\\ and no segment is found within the DVR window the DVR window is calculated based on the entries in \\&lt;SegmentTimeline\\&gt;. */ /** * @typedef {Object} LiveDelay * @property {number} [liveDelayFragmentCount=NaN] * Changing this value will lower or increase live stream latency. * * The detected segment duration will be multiplied by this value to define a time in seconds to delay a live stream from the live edge. * * Lowering this value will lower latency but may decrease the player's ability to build a stable buffer. * @property {number} [liveDelay] * Equivalent in seconds of setLiveDelayFragmentCount. * * Lowering this value will lower latency but may decrease the player's ability to build a stable buffer. * * This value should be less than the manifest duration by a couple of segment durations to avoid playback issues. * * If set, this parameter will take precedence over setLiveDelayFragmentCount and manifest info. * @property {boolean} [useSuggestedPresentationDelay=true] * Set to true if you would like to overwrite the default live delay and honor the SuggestedPresentationDelay attribute in by the manifest. */ /** * @typedef {Object} Buffer * @property {boolean} [enableSeekDecorrelationFix=false] * Enables a workaround for playback start on some devices, e.g. WebOS 4.9. * It is necessary because some browsers do not support setting currentTime on video element to a value that is outside of current buffer. * * If you experience unexpected seeking triggered by BufferController, you can try setting this value to false. * @property {boolean} [fastSwitchEnabled=true] * When enabled, after an ABR up-switch in quality, instead of requesting and appending the next fragment at the end of the current buffer range it is requested and appended closer to the current time. * * When enabled, The maximum time to render a higher quality is current time + (1.5 * fragment duration). * * Note, When ABR down-switch is detected, we appended the lower quality at the end of the buffer range to preserve the * higher quality media for as long as possible. * * If enabled, it should be noted there are a few cases when the client will not replace inside buffer range but rather just append at the end. * 1. When the buffer level is less than one fragment duration. * 2. The client is in an Abandonment State due to recent fragment abandonment event. * * Known issues: * 1. In IE11 with auto switching off, if a user switches to a quality they can not download in time the 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, 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} [reuseExistingSourceBuffers=true] * Enable reuse of existing MediaSource Sourcebuffers during period transition. * @property {number} [bufferPruningInterval=10] * The interval of pruning buffer in seconds. * @property {number} [bufferToKeep=20] * This value influences the buffer pruning logic. * * Allows you to modify the buffer that is kept in source buffer in seconds. * 0|-----------bufferToPrune-----------|-----bufferToKeep-----|currentTime| * @property {number} [bufferTimeAtTopQuality=30] * The time that the internal buffer target will be set to once playing the top quality. * * If there are multiple bitrates in your adaptation, and the media is playing at the highest bitrate, then we try to build a larger buffer at the top quality to increase stability and to maintain media quality. * @property {number} [bufferTimeAtTopQualityLongForm=60] * The time that the internal buffer target will be set to once playing the top quality for long form content. * @property {number} [longFormContentDurationThreshold=600] * The threshold which defines if the media is considered long form content. * * This will directly affect the buffer targets when playing back at the top quality. * @property {number} [initialBufferLevel=NaN] * Initial buffer level before playback starts * @property {number} [stableBufferTime=12] * The time that the internal buffer target will be set to post startup/seeks (NOT top quality). * * When the time is set higher than the default you will have to wait longer to see automatic bitrate switches but will have a larger buffer which will increase stability. * @property {number} [stallThreshold=0.3] * Stall threshold used in BufferController.js to determine whether a track should still be changed and which buffer range to prune. * @property {boolean} [useAppendWindow=true] * Specifies if the appendWindow attributes of the MSE SourceBuffers should be set according to content duration from manifest. * @property {boolean} [setStallState=true] * Specifies if we fire manual waiting events once the stall threshold is reached * @property {boolean} [avoidCurrentTimeRangePruning=false] * Avoids pruning of the buffered range that contains the current playback time. * * That buffered range is likely to have been enqueued for playback. Pruning it causes a flush and reenqueue in WPE and WebKitGTK based browsers. This stresses the video decoder and can cause stuttering on embedded platforms. */ /** * @typedef {Object} module:Settings~AudioVideoSettings * @property {number|boolean|string} [audio] * Configuration for audio media type of tracks. * @property {number|boolean|string} [video] * Configuration for video media type of tracks. */ /** * @typedef {Object} DebugSettings * @property {number} [logLevel=dashjs.Debug.LOG_LEVEL_WARNING] * Sets up the log level. The levels are cumulative. * * For example, if you set the log level to dashjs.Debug.LOG_LEVEL_WARNING all warnings, errors and fatals will be logged. * * Possible values. * * - dashjs.Debug.LOG_LEVEL_NONE * No message is written in the browser console. * * - dashjs.Debug.LOG_LEVEL_FATAL * Log fatal errors. * An error is considered fatal when it causes playback to fail completely. * * - dashjs.Debug.LOG_LEVEL_ERROR * Log error messages. * * - dashjs.Debug.LOG_LEVEL_WARNING * Log warning messages. * * - dashjs.Debug.LOG_LEVEL_INFO * Log info messages. * * - 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. */ /** * @typedef {Object} module:Settings~ErrorSettings * @property {object} [recoverAttempts={mediaErrorDecode: 5}] * Defines the maximum number of recover attempts for specific media errors. * * For mediaErrorDecode the player will reset the MSE and skip the blacklisted segment that caused the decode error. The resulting gap will be handled by the GapController. */ /** * @typedef {Object} CachingInfoSettings * @property {boolean} [enable] * Enable or disable the caching feature. * @property {number} [ttl] * Time to live. * * A value defined in milliseconds representing how log to cache the settings for. */ /** * @typedef {Object} Gaps * @property {boolean} [jumpGaps=true] * Sets whether player should jump small gaps (discontinuities) in the buffer. * @property {boolean} [jumpLargeGaps=true] * Sets whether player should jump large gaps (discontinuities) in the buffer. * @property {number} [smallGapLimit=1.5] * Time in seconds for a gap to be considered small. * @property {number} [threshold=0.3] * Threshold at which the gap handling is executed. If currentRangeEnd - currentTime &lt; threshold the gap jump will be triggered. * For live stream the jump might be delayed to keep a consistent live edge. * Note that the amount of buffer at which platforms automatically stall might differ. * @property {boolean} [enableSeekFix=true] * Enables the adjustment of the seek target once no valid segment request could be generated for a specific seek time. This can happen if the user seeks to a position for which there is a gap in the timeline. * @property {boolean} [enableStallFix=false] * If playback stalled in a buffered range this fix will perform a seek by the value defined in stallSeek to trigger playback again. * @property {number} [stallSeek=0.1] * Value to be used in case enableStallFix is set to true */ /** * @typedef {Object} UtcSynchronizationSettings * @property {boolean} [enabled=true] * Enables or disables the UTC clock synchronization * @property {boolean} [useManifestDateHeaderTimeSource=true] * Allows you to enable the use of the Date Header, if exposed with CORS, as a timing source for live edge detection. * * The use of the date header will happen only after the other timing source that take precedence fail or are omitted as described. * @property {number} [backgroundAttempts=2] * Number of synchronization attempts to perform in the background after an initial synchronization request has been done. This is used to verify that the derived client-server offset is correct. * * The background requests are async and done in parallel to the start of the playback. * * This value is also used to perform a resync after 404 errors on segments. * @property {number} [timeBetweenSyncAttempts=30] * The time in seconds between two consecutive sync attempts. * * Note: This value is used as an initial starting value. The internal value of the TimeSyncController is adjusted during playback based on the drift between two consecutive synchronization attempts. * * Note: A sync is only performed after an MPD update. In case the @minimumUpdatePeriod is larger than this value the sync will be delayed until the next MPD update. * @property {number} [maximumTimeBetweenSyncAttempts=600] * The maximum time in seconds between two consecutive sync attempts. * * @property {number} [minimumTimeBetweenSyncAttempts=2] * The minimum time in seconds between two consecutive sync attempts. * * @property {number} [timeBetweenSyncAttemptsAdjustmentFactor=2] * The factor used to multiply or divide the timeBetweenSyncAttempts parameter after a sync. The maximumAllowedDrift defines whether this value is used as a factor or a dividend. * * @property {number} [maximumAllowedDrift=100] * The maximum allowed drift specified in milliseconds between two consecutive synchronization attempts. * * @property {boolean} [enableBackgroundSyncAfterSegmentDownloadError=true] * Enables or disables the background sync after the player ran into a segment download error. * * @property {object} [defaultTimingSource={scheme:'urn:mpeg:dash:utc:http-xsdate:2014',value: 'http://time.akamai.com/?iso&amp;ms'}] * The default timing source to be used. The timing sources in the MPD take precedence over this one. */ /** * @typedef {Object} Scheduling * @property {number} [defaultTimeout=300] * Default timeout between two consecutive segment scheduling attempts * @property {number} [lowLatencyTimeout] * Default timeout between two consecutive low-latency segment scheduling attempts * @property {boolean} [scheduleWhilePaused=true] * Set to true if you would like dash.js to keep downloading fragments in the background when the video element is paused. */ /** * @typedef {Object} Text * @property {number} [defaultEnabled=true] * Enable/disable subtitle rendering by default. */ /** * @typedef {Object} LiveCatchupSettings * @property {number} [maxDrift=NaN] * 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=NaN] * 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 NaN to turn off live catch up feature. * * Note: Catch-up mechanism is only applied when playing low latency live streams. * @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=\"liveCatchupModeDefault\"] * 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. */ /** * @typedef {Object} RequestTypeSettings * @property {number} [MPD] * Manifest type of requests. * @property {number} [XLinkExpansion] * XLink expansion type of requests. * @property {number} [InitializationSegment] * Request to retrieve an initialization segment. * @property {number} [IndexSegment] * Request to retrieve an index segment (SegmentBase). * @property {number} [MediaSegment] * Request to retrieve a media segment (video/audio/image/text chunk). * @property {number} [BitstreamSwitchingSegment] * Bitrate stream switching type of request. * @property {number} [FragmentInfoSegment] * Request to retrieve a FragmentInfo segment (specific to Smooth Streaming live streams). * @property {number} [other] * Other type of request. * @property {number} [lowLatencyReductionFactor] * For low latency mode, values of type of request are divided by lowLatencyReductionFactor. * * Note: It's not type of request. * @property {number} [lowLatencyMultiplyFactor] * For low latency mode, values of type of request are multiplied by lowLatencyMultiplyFactor. * * Note: It's not type of request. */ /** * @typedef {Object} Protection * @property {boolean} [keepProtectionMediaKeys=false] * Set the value for the ProtectionController and MediaKeys life cycle. * * If true, the ProtectionController and then created MediaKeys and MediaKeySessions will be preserved during the MediaPlayer lifetime. * @property {boolean} ignoreEmeEncryptedEvent * If set to true the player will ignore \"encrypted\" and \"needkey\" events thrown by the EME. * * @property {boolean} detectPlayreadyMessageFormat * If set to true the player will use the raw unwrapped message from the Playready CDM */ /** * @typedef {Object} Capabilities * @property {boolean} [filterUnsupportedEssentialProperties=true] * Enable to filter all the AdaptationSets and Representations which contain an unsupported \\&lt;EssentialProperty\\&gt; element. * @property {boolean} [useMediaCapabilitiesApi=false] * Enable to use the MediaCapabilities API to check whether codecs are supported. If disabled MSE.isTypeSupported will be used instead. */ /** * @typedef {Object} AbrSettings * @property {string} [movingAverageMethod=\"slidingWindow\"] * Sets the moving average method used for smoothing throughput estimates. * * Valid methods are \"slidingWindow\" and \"ewma\". * * The call has no effect if an invalid method is passed. * * The sliding window moving average method computes the average throughput using the last four segments downloaded. * * If the stream is live (as opposed to VOD), then only the last three segments are used. * * If wide variations in throughput are detected, the number of segments can be dynamically increased to avoid oscillations. * * The exponentially weighted moving average (EWMA) method computes the average using exponential smoothing. * * Two separate estimates are maintained, a fast one with a three-second half life and a slow one with an eight-second half life. * * The throughput estimate at any time is the minimum of the fast and slow estimates. * * This allows a fast reaction to a bandwidth drop and prevents oscillations on bandwidth spikes. * @property {string} [ABRStrategy=\"abrDynamic\"] * Returns the current ABR strategy being used: \"abrDynamic\", \"abrBola\" or \"abrThroughput\". * @property {object} [trackSwitchMode={video: \"neverReplace\", audio: \"alwaysReplace\"}] * @property {object} [additionalAbrRules={insufficientBufferRule: false,switchHistoryRule: true,droppedFramesRule: true,abandonRequestsRule: false}] * Enable/Disable additional ABR rules in case ABRStrategy is set to \"abrDynamic\", \"abrBola\" or \"abrThroughput\". * @property {number} [bandwidthSafetyFactor=0.9] * 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} [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 transfer time will be used. * @property {boolean} [limitBitrateByPortal=false] * If true, the size of the video portal will limit the max chosen video resolution. * @property {boolean} [usePixelRatioInLimitBitrateByPortal=false] * Sets whether to take into account the device's pixel ratio when defining the portal dimensions. * * Useful on, for example, retina displays. * @property {module:Settings~AudioVideoSettings} [maxBitrate={audio: -1, video: -1}] * The maximum bitrate that the ABR algorithms will choose. This value is specified in kbps. * * Use -1 for no limit. * @property {module:Settings~AudioVideoSettings} [minBitrate={audio: -1, video: -1}] * The minimum bitrate that the ABR algorithms will choose. This value is specified in kbps. * * Use -1 for no limit. * @property {module:Settings~AudioVideoSettings} [maxRepresentationRatio={audio: 1, video: 1}] * When switching multi-bitrate content (auto or manual mode) this property specifies the maximum representation allowed, as a proportion of the size of the representation set. * * You can set or remove this cap at anytime before or during playback. * * To clear this setting you set the value to 1. * * If both this and maxAllowedBitrate are defined, maxAllowedBitrate is evaluated first, then maxAllowedRepresentation, i.e. the lowest value from executing these rules is used. * * This feature is typically used to reserve higher representations for playback only when connected over a fast connection. * @property {module:Settings~AudioVideoSettings} [initialBitrate={audio: -1, video: -1}] * Explicitly set the starting bitrate for audio or video. This value is specified in kbps. * * Use -1 to let the player decide. * @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 {string} [fetchThroughputCalculationMode=\"abrFetchThroughputCalculationDownloadedData\"] * 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. */ /** * @typedef {Object} module:Settings~CmcdSettings * @property {boolean} [enable=false] * Enable or disable the CMCD reporting. * @property {string} [sid] * GUID identifying the current playback session. * * Should be in UUID format. * * If not specified a UUID will be automatically generated. * @property {string} [cid] * A unique string to identify the current content. * * If not specified it will be a hash of the MPD url. * @property {number} [rtp] * The requested maximum throughput that the client considers sufficient for delivery of the asset. * * If not specified this value will be dynamically calculated in the CMCDModel based on the current buffer level. * @property {number} [rtpSafetyFactor] * This value is used as a factor for the rtp value calculation: rtp = minBandwidth * rtpSafetyFactor * * If not specified this value defaults to 5. Note that this value is only used when no static rtp value is defined. * @property {number} [mode] * The method to use to attach cmcd metrics to the requests. 'query' to use query parameters, 'header' to use http headers. * * If not specified this value defaults to 'query'. * @property {Array.&lt;string&gt;} [enabledKeys] * This value is used to specify the desired CMCD parameters. Parameters not included in this list are not reported. */ /** * @typedef {Object} Metrics * @property {number} [metricsMaxListDepth=100] * Maximum number of metrics that are persisted per type. */ /** * @typedef {Object} StreamingSettings * @property {number} [abandonLoadTimeout=10000] * A timeout value in seconds, which during the ABRController will block switch-up events. * * This will only take effect after an abandoned fragment event occurs. * @property {number} [wallclockTimeUpdateInterval=50] * How frequently the wallclockTimeUpdated internal event is triggered (in milliseconds). * @property {number} [manifestUpdateRetryInterval=100] * 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 {boolean} [cacheInitSegments=true] * Enables the caching of init segments to avoid requesting the init segments before each representation switch. * @property {boolean} [applyServiceDescription=true] * Set to true if dash.js should use the parameters defined in ServiceDescription elements * @property {boolean} [applyProducerReferenceTime=true] * Set to true if dash.js should use the parameters defined in ProducerReferenceTime elements in combination with ServiceDescription elements. * @property {boolean} [applyContentSteering=true] * Set to true if dash.js should apply content steering during playback. * @property {number} [eventControllerRefreshDelay=100] * For multi-period streams, overwrite the manifest mediaPresentationDuration attribute with the sum of period durations if the manifest mediaPresentationDuration is greater than the sum of period durations * @property {boolean} [enableManifestDurationMismatchFix=true] * Defines the delay in milliseconds between two consecutive checks for events to be fired. * @property {module:Settings~Metrics} metrics Metric settings * @property {module:Settings~LiveDelay} delay Live Delay settings * @property {module:Settings~TimeShiftBuffer} timeShiftBuffer TimeShiftBuffer settings * @property {module:Settings~Protection} protection DRM related settings * @property {module:Settings~Capabilities} capabilities Capability related settings * @property {module:Settings~Buffer} buffer Buffer related settings * @property {module:Settings~Gaps} gaps Gap related settings * @property {module:Settings~UtcSynchronizationSettings} utcSynchronization Settings related to UTC clock synchronization * @property {module:Settings~Scheduling} scheduling Settings related to segment scheduling * @property {module:Settings~Text} text Settings related to Subtitles and captions * @property {module:Settings~LiveCatchupSettings} liveCatchup Settings related to live catchup. * @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. * * The default expiration is one hour, defined in milliseconds. * * If expired, the default initial bit rate (closest to 1000 kbps) will be used for that session and a new bit rate will be stored during that session. * @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~AudioVideoSettings} [trackSwitchMode={video: \"neverReplace\", audio: \"alwaysReplace\"}] * For a given media type defines if existing segments in the buffer should be overwritten once the track is switched. For instance if the user switches the audio language the existing segments in the audio buffer will be replaced when setting this value to \"alwaysReplace\". * * Possible values * * - Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE * Replace existing segments in the buffer * * - Constants.TRACK_SWITCH_MODE_NEVER_REPLACE * Do not replace existing segments in the buffer * * @property {string} [selectionModeForInitialTrack=\"highestBitrate\"] * 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: * * Possible values * * - Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY * This mode makes the player select the track with the highest selectionPriority as defined in the manifest. If not selectionPriority is given we fallback to TRACK_SELECTION_MODE_HIGHEST_BITRATE. This mode is a default mode. * * - Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE * This mode makes the player select the track with a highest bitrate. * * - Constants.TRACK_SELECTION_MODE_FIRST_TRACK * This mode makes the player select the first track found in the manifest. * * - Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY * This mode makes the player select the track with the lowest bitrate per pixel average. * * - Constants.TRACK_SELECTION_MODE_WIDEST_RANGE * This mode makes the player select the track with a widest range of bitrates. * * * @property {number} [fragmentRequestTimeout=0] * 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. */ /** * @class * @ignore */ function Settings() { let instance; const context = this.context; const eventBus = EventBus(context).getInstance(); const DISPATCH_KEY_MAP = { 'streaming.delay.liveDelay': Events.SETTING_UPDATED_LIVE_DELAY, 'streaming.delay.liveDelayFragmentCount': Events.SETTING_UPDATED_LIVE_DELAY_FRAGMENT_COUNT, 'streaming.liveCatchup.enabled': Events.SETTING_UPDATED_CATCHUP_ENABLED }; /** * @const {PlayerSettings} defaultSettings * @ignore */ const defaultSettings = { debug: { logLevel: Debug.LOG_LEVEL_WARNING, dispatchEvent: false }, streaming: { abandonLoadTimeout: 10000, wallclockTimeUpdateInterval: 100, manifestUpdateRetryInterval: 100, cacheInitSegments: false, applyServiceDescription: true, applyProducerReferenceTime: true, applyContentSteering: true, eventControllerRefreshDelay: 100, enableManifestDurationMismatchFix: true, capabilities: { filterUnsupportedEssentialProperties: true, useMediaCapabilitiesApi: false }, timeShiftBuffer: { calcFromSegmentTimeline: false, fallbackToSegmentTimeline: true }, metrics: { maxListDepth: 100 }, delay: { liveDelayFragmentCount: NaN, liveDelay: NaN, useSuggestedPresentationDelay: true }, protection: { keepProtectionMediaKeys: false, ignoreEmeEncryptedEvent: false, detectPlayreadyMessageFormat: true, }, buffer: { enableSeekDecorrelationFix: false, fastSwitchEnabled: true, flushBufferAtTrackSwitch: false, reuseExistingSourceBuffers: true, bufferPruningInterval: 10, bufferToKeep: 20, bufferTimeAtTopQuality: 30, bufferTimeAtTopQualityLongForm: 60, initialBufferLevel: NaN, stableBufferTime: 12, longFormContentDurationThreshold: 600, stallThreshold: 0.3, useAppendWindow: true, setStallState: true, avoidCurrentTimeRangePruning: false }, gaps: { jumpGaps: true, jumpLargeGaps: true, smallGapLimit: 1.5, threshold: 0.3, enableSeekFix: true, enableStallFix: false, stallSeek: 0.1 }, utcSynchronization: { enabled: true, useManifestDateHeaderTimeSource: true, backgroundAttempts: 2, timeBetweenSyncAttempts: 30, maximumTimeBetweenSyncAttempts: 600, minimumTimeBetweenSyncAttempts: 2, timeBetweenSyncAttemptsAdjustmentFactor: 2, maximumAllowedDrift: 100, enableBackgroundSyncAfterSegmentDownloadError: true, defaultTimingSource: { scheme: 'urn:mpeg:dash:utc:http-xsdate:2014', value: 'https://time.akamai.com/?iso&amp;ms' } }, scheduling: { defaultTimeout: 500, lowLatencyTimeout: 0, scheduleWhilePaused: true }, text: { defaultEnabled: true }, liveCatchup: { maxDrift: NaN, playbackRate: NaN, playbackBufferMin: 0.5, enabled: null, mode: Constants.LIVE_CATCHUP_MODE_DEFAULT }, lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, cacheLoadThresholds: { video: 50, audio: 5 }, trackSwitchMode: { audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE, video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE }, selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY, fragmentRequestTimeout: 20000, retryIntervals: { [HTTPRequest.MPD_TYPE]: 500, [HTTPRequest.XLINK_EXPANSION_TYPE]: 500, [HTTPRequest.MEDIA_SEGMENT_TYPE]: 1000, [HTTPRequest.INIT_SEGMENT_TYPE]: 1000, [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 1000, [HTTPRequest.INDEX_SEGMENT_TYPE]: 1000, [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 1000, [HTTPRequest.LICENSE]: 1000, [HTTPRequest.OTHER_TYPE]: 1000, lowLatencyReductionFactor: 10 }, retryAttempts: { [HTTPRequest.MPD_TYPE]: 3, [HTTPRequest.XLINK_EXPANSION_TYPE]: 1, [HTTPRequest.MEDIA_SEGMENT_TYPE]: 3, [HTTPRequest.INIT_SEGMENT_TYPE]: 3, [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 3, [HTTPRequest.INDEX_SEGMENT_TYPE]: 3, [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 3, [HTTPRequest.LICENSE]: 3, [HTTPRequest.OTHER_TYPE]: 3, lowLatencyMultiplyFactor: 5 }, abr: { movingAverageMethod: Constants.MOVING_AVERAGE_SLIDING_WINDOW, ABRStrategy: Constants.ABR_STRATEGY_DYNAMIC, additionalAbrRules: { insufficientBufferRule: true, switchHistoryRule: true, droppedFramesRule: true, abandonRequestsRule: true }, bandwidthSafetyFactor: 0.9, useDefaultABRRules: true, useDeadTimeLatency: true, limitBitrateByPortal: false, usePixelRatioInLimitBitrateByPortal: false, maxBitrate: { audio: -1, video: -1 }, minBitrate: { audio: -1, video: -1 }, maxRepresentationRatio: { audio: 1, video: 1 }, initialBitrate: { audio: -1, video: -1 }, initialRepresentationRatio: { audio: -1, video: -1 }, autoSwitchBitrate: { audio: true, video: true }, fetchThroughputCalculationMode: Constants.ABR_FETCH_THROUGHPUT_CALCULATION_MOOF_PARSING }, cmcd: { enabled: false, sid: null, cid: null, rtp: null, rtpSafetyFactor: 5, mode: Constants.CMCD_MODE_QUERY, enabledKeys: ['br', 'd', 'ot', 'tb' , 'bl', 'dl', 'mtp', 'nor', 'nrr', 'su' , 'bs', 'rtp' , 'cid', 'pr', 'sf', 'sid', 'st', 'v'] } }, errors: { recoverAttempts: { mediaErrorDecode: 5 } } }; let settings = Utils.clone(defaultSettings); //Merge in the settings. If something exists in the new config that doesn't match the schema of the default config, //regard it as an error and log it. function mixinSettings(source, dest, path) { for (let n in source) { if (source.hasOwnProperty(n)) { if (dest.hasOwnProperty(n)) { if (typeof source[n] === 'object' &amp;&amp; !(source[n] instanceof Array) &amp;&amp; source[n] !== null) { mixinSettings(source[n], dest[n], path.slice() + n + '.'); } else { dest[n] = Utils.clone(source[n]); if (DISPATCH_KEY_MAP[path + n]) { eventBus.trigger(DISPATCH_KEY_MAP[path + n]); } } } else { console.error('Settings parameter ' + path + n + ' is not supported'); } } } } /** * Return the settings object. Don't copy/store this object, you won't get updates. * @func * @instance */ function get() { return settings; } /** * @func * @instance * @param {object} settingsObj - This should be a partial object of the Settings.Schema type. That is, fields defined should match the path (e.g. * settingsObj.streaming.abr.autoSwitchBitrate.audio -&gt; defaultSettings.streaming.abr.autoSwitchBitrate.audio). Where an element's path does * not match it is ignored, and a warning is logged. * * Use to change the settings object. Any new values defined will overwrite the settings and anything undefined will not change. * Implementers of new settings should add it in an approriate namespace to the defaultSettings object and give it a default value (that is not undefined). * */ function update(settingsObj) { if (typeof settingsObj === 'object') { mixinSettings(settingsObj, settings, ''); } } /** * Resets the settings object. Everything is set to its default value. * @func * @instance * */ function reset() { settings = Utils.clone(defaultSettings); } instance = { get, update, reset }; return instance; } Settings.__dashjs_factory_name = 'Settings'; let factory = FactoryMaker.getSingletonFactory(Settings); export default factory; × Search results Close "},"streaming_models_URIFragmentModel.js.html":{"id":"streaming_models_URIFragmentModel.js.html","title":"Source: streaming/models/URIFragmentModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/models/URIFragmentModel.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import URIFragmentData from '../vo/URIFragmentData'; import FactoryMaker from '../../core/FactoryMaker'; /** * Model class managing URI fragments. * @ignore */ function URIFragmentModel() { let instance, URIFragmentDataVO; /** * @param {string} uri The URI to parse for fragment extraction * @memberof module:URIFragmentModel * @instance */ function initialize(uri) { URIFragmentDataVO = new URIFragmentData(); if (!uri) return null; const hashIndex = uri.indexOf('#'); if (hashIndex !== -1) { const fragments = uri.substr(hashIndex + 1).split('&amp;'); for (let i = 0, len = fragments.length; i &lt; len; ++i) { const fragment = fragments[i]; const equalIndex = fragment.indexOf('='); if (equalIndex !== -1) { const key = fragment.substring(0,equalIndex); if (URIFragmentDataVO.hasOwnProperty(key)) { URIFragmentDataVO[key] = fragment.substr(equalIndex + 1); } } } } } /** * @returns {URIFragmentData} Object containing supported URI fragments * @memberof module:URIFragmentModel * @instance */ function getURIFragmentData() { return URIFragmentDataVO; } instance = { initialize: initialize, getURIFragmentData: getURIFragmentData }; return instance; } URIFragmentModel.__dashjs_factory_name = 'URIFragmentModel'; export default FactoryMaker.getSingletonFactory(URIFragmentModel); × Search results Close "},"streaming_utils_URLUtils.js.html":{"id":"streaming_utils_URLUtils.js.html","title":"Source: streaming/utils/URLUtils.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/URLUtils.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import DefaultURLUtils from './DefaultURLUtils'; /** * @module URLUtils * @ignore * @description Provides utility functions for operating on URLs. * Initially this is simply a method to determine the Base URL of a URL, but * should probably include other things provided all over the place such as * determining whether a URL is relative/absolute, resolving two paths etc. */ function URLUtils() { let instance; let defaultURLUtils; let regexUtils = []; const context = this.context; function getUtils(url) { let i; for (i = 0; i &lt; regexUtils.length; i++) { let regex = regexUtils[i].regex; if (regex.test(url)) { return regexUtils[i].utils; } } return defaultURLUtils; } function setup() { defaultURLUtils = DefaultURLUtils(context).getInstance(); } /** * Register a module to handle specific url. * @param {regex} regex - url regex * @param {object} utils - object that handles the regex * @memberof module:URLUtils * @instance */ function registerUrlRegex(regex, utils) { regexUtils.push({regex: regex, utils: utils}); } function internalCall(functionName, url, baseUrl) { let utils = getUtils(baseUrl || url); return utils &amp;&amp; typeof (utils[functionName]) === 'function' ? utils[functionName](url, baseUrl) : defaultURLUtils[functionName](url, baseUrl); } /** * Returns a string that contains the Base URL of a URL, if determinable. * @param {string} url - full url * @return {string} * @memberof module:URLUtils * @instance */ function parseBaseUrl(url) { return internalCall('parseBaseUrl', url); } /** * Returns a string that contains the scheme and origin of a URL, * if determinable. * @param {string} url - full url * @return {string} * @memberof module:URLUtils * @instance */ function parseOrigin(url) { return internalCall('parseOrigin', url); } /** * Returns a string that contains the fragment of a URL without scheme, * if determinable. * @param {string} url - full url * @return {string} * @memberof module:URLUtils * @instance */ function removeHostname(url) { return internalCall('removeHostname', url); } /** * Returns a string that contains the scheme of a URL, if determinable. * @param {string} url - full url * @return {string} * @memberof module:URLUtils * @instance */ function parseScheme(url) { return internalCall('parseScheme', url); } /** * Determines whether the url is relative. * @return {boolean} * @param {string} url * @memberof module:URLUtils * @instance */ function isRelative(url) { return internalCall('isRelative', url); } /** * Determines whether the url is path-absolute. * @return {bool} * @param {string} url * @memberof module:URLUtils * @instance */ function isPathAbsolute(url) { return internalCall('isPathAbsolute', url); } /** * Determines whether the url is scheme-relative. * @return {bool} * @param {string} url * @memberof module:URLUtils * @instance */ function isSchemeRelative(url) { return internalCall('isSchemeRelative', url); } /** * Determines whether the url is an HTTP-URL as defined in ISO/IEC * 23009-1:2014 3.1.15. ie URL with a fixed scheme of http or https * @return {bool} * @param {string} url * @memberof module:URLUtils * @instance */ function isHTTPURL(url) { return internalCall('isHTTPURL', url); } /** * Determines whether the supplied url has https scheme * @return {bool} * @param {string} url * @memberof module:URLUtils * @instance */ function isHTTPS(url) { return internalCall('isHTTPS', url); } /** * Resolves a url given an optional base url * @return {string} * @param {string} url * @param {string} [baseUrl] * @memberof module:URLUtils * @instance */ function resolve(url, baseUrl) { return internalCall('resolve', url, baseUrl); } setup(); instance = { registerUrlRegex: registerUrlRegex, parseBaseUrl: parseBaseUrl, parseOrigin: parseOrigin, parseScheme: parseScheme, isRelative: isRelative, isPathAbsolute: isPathAbsolute, isSchemeRelative: isSchemeRelative, isHTTPURL: isHTTPURL, isHTTPS: isHTTPS, removeHostname: removeHostname, resolve: resolve }; return instance; } URLUtils.__dashjs_factory_name = 'URLUtils'; const factory = FactoryMaker.getSingletonFactory(URLUtils); export default factory; × Search results Close "},"mss_errors_MssErrors.js.html":{"id":"mss_errors_MssErrors.js.html","title":"Source: mss/errors/MssErrors.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: mss/errors/MssErrors.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import ErrorsBase from '../../core/errors/ErrorsBase'; /** * @class * */ class MssErrors extends ErrorsBase { constructor() { super(); /** * Error code returned when no tfrf box is detected in MSS live stream */ this.MSS_NO_TFRF_CODE = 200; /** * Error code returned when one of the codecs defined in the manifest is not supported */ this.MSS_UNSUPPORTED_CODEC_CODE = 201; this.MSS_NO_TFRF_MESSAGE = 'Missing tfrf in live media segment'; this.MSS_UNSUPPORTED_CODEC_MESSAGE = 'Unsupported codec'; } } let mssErrors = new MssErrors(); export default mssErrors; × Search results Close "},"offline_OfflineDownload.js.html":{"id":"offline_OfflineDownload.js.html","title":"Source: offline/OfflineDownload.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/OfflineDownload.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import OfflineConstants from './constants/OfflineConstants'; import OfflineStream from './OfflineStream'; import OfflineIndexDBManifestParser from './utils/OfflineIndexDBManifestParser'; import OfflineErrors from './errors/OfflineErrors'; import DashParser from '../dash/parser/DashParser'; function OfflineDownload(config) { config = config || {}; const context = this.context; const manifestLoader = config.manifestLoader; const mediaPlayerModel = config.mediaPlayerModel; const abrController = config.abrController; const playbackController = config.playbackController; const adapter = config.adapter; const dashMetrics = config.dashMetrics; const timelineConverter = config.timelineConverter; const offlineStoreController = config.offlineStoreController; const manifestId = config.id; const eventBus = config.eventBus; const errHandler = config.errHandler; const events = config.events; const errors = config.errors; const settings = config.settings; const debug = config.debug; const manifestUpdater = config.manifestUpdater; const baseURLController = config.baseURLController; const segmentBaseController = config.segmentBaseController; const constants = config.constants; const dashConstants = config.dashConstants; const urlUtils = config.urlUtils; let instance, logger, _manifestURL, _offlineURL, _xmlManifest, _streams, _manifest, _isDownloadingStatus, _isComposed, _representationsToUpdate, _indexDBManifestParser, _progressionById, _progression, _status; function setup() { logger = debug.getLogger(instance); manifestUpdater.initialize(); _streams = []; _isDownloadingStatus = false; _isComposed = false; _progressionById = {}; _progression = 0; _status = undefined; } function getId() { return manifestId; } function getOfflineUrl() { return _offlineURL; } function getManifestUrl() { return _manifestURL; } function getStatus() { return _status; } function setInitialState(state) { _offlineURL = state.url; _progression = state.progress; _manifestURL = state.originalUrl; _status = state.status; } /** * Download a stream, from url of manifest * @param {string} url * @instance */ function downloadFromUrl(url) { _manifestURL = url; _offlineURL = `${OfflineConstants.OFFLINE_SCHEME}://${manifestId}`; _status = OfflineConstants.OFFLINE_STATUS_CREATED; setupOfflineEvents(); let offlineManifest = { 'fragmentStore': manifestId, 'status': _status, 'manifestId': manifestId, 'url': _offlineURL, 'originalURL': url }; return createOfflineManifest(offlineManifest); } function initDownload() { manifestLoader.load(_manifestURL); _isDownloadingStatus = true; } function setupOfflineEvents() { eventBus.on(events.MANIFEST_UPDATED, onManifestUpdated, instance); eventBus.on(events.ORIGINAL_MANIFEST_LOADED, onOriginalManifestLoaded, instance); setupIndexedDBEvents(); } function setupIndexedDBEvents() { eventBus.on(events.ERROR, onError, instance); } function isDownloading() { return _isDownloadingStatus; } function onManifestUpdated(e) { if (_isComposed) { return; } if (!e.error) { try { _manifest = e.manifest; } catch (err) { _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: err.message, data: { id: manifestId, status: _status } }); } } } function onDownloadingStarted(e) { if (e.id !== manifestId) { return; } if (!e.error &amp;&amp; manifestId !== null) { _status = OfflineConstants.OFFLINE_STATUS_STARTED; offlineStoreController.setDownloadingStatus(manifestId, _status).then(function () { eventBus.trigger(events.OFFLINE_RECORD_STARTED, { id: manifestId, message: 'Downloading started for this stream !' }); }); } else { _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: 'Cannot start download ', data: { id: manifestId, status: _status, error: e.error } }); } } function OnStreamProgression(stream, downloaded, available) { _progressionById[stream.getStreamInfo().id] = { downloaded, available }; let segments = 0; let allSegments = 0; let waitForAllProgress; for (var property in _progressionById) { if (_progressionById.hasOwnProperty(property)) { if (_progressionById[property] === null) { waitForAllProgress = true; } else { segments += _progressionById[property].downloaded; allSegments += _progressionById[property].available; } } } if (!waitForAllProgress) { // all progression have been started, we can compute global progression _progression = segments / allSegments; // store progression offlineStoreController.getManifestById(manifestId) .then((item) =&gt; { item.progress = _progression; return updateOfflineManifest(item); }); } } function onDownloadingFinished(e) { if (e.id !== manifestId) { return; } if (!e.error &amp;&amp; manifestId !== null) { _status = OfflineConstants.OFFLINE_STATUS_FINISHED; offlineStoreController.setDownloadingStatus(manifestId, _status) .then(function () { eventBus.trigger(events.OFFLINE_RECORD_FINISHED, { id: manifestId, message: 'Downloading has been successfully completed for this stream !' }); resetDownload(); }); } else { _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: 'Error finishing download ', data: { id: manifestId, status: _status, error: e.error } }); } } function onManifestUpdateNeeded(e) { if (e.id !== manifestId) { return; } _representationsToUpdate = e.representations; if (_representationsToUpdate.length &gt; 0) { _indexDBManifestParser.parse(_xmlManifest, _representationsToUpdate).then(function (parsedManifest) { if (parsedManifest !== null &amp;&amp; manifestId !== null) { offlineStoreController.getManifestById(manifestId) .then((item) =&gt; { item.manifest = parsedManifest; return updateOfflineManifest(item); }) .then(function () { for (let i = 0, ln = _streams.length; i &lt; ln; i++) { _streams[i].startOfflineStreamProcessors(); } }); } else { throw 'falling parsing offline manifest'; } }).catch(function (err) { throw err; }); } } function composeStreams() { try { adapter.updatePeriods(_manifest); baseURLController.initialize(_manifest); const streamsInfo = adapter.getStreamsInfo(); if (streamsInfo.length === 0) { _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: 'Cannot download - no streams', data: { id: manifestId, status: _status } }); } for (let i = 0, ln = streamsInfo.length; i &lt; ln; i++) { const streamInfo = streamsInfo[i]; let stream = OfflineStream(context).create({ id: manifestId, callbacks: { started: onDownloadingStarted, progression: OnStreamProgression, finished: onDownloadingFinished, updateManifestNeeded: onManifestUpdateNeeded }, constants: constants, dashConstants: dashConstants, eventBus: eventBus, events: events, errors: errors, settings: settings, debug: debug, errHandler: errHandler, mediaPlayerModel: mediaPlayerModel, abrController: abrController, playbackController: playbackController, dashMetrics: dashMetrics, baseURLController: baseURLController, timelineConverter: timelineConverter, adapter: adapter, segmentBaseController: segmentBaseController, offlineStoreController: offlineStoreController }); _streams.push(stream); // initialise stream and get downloadable representations stream.initialize(streamInfo); _progressionById[streamInfo.id] = null; } _isComposed = true; } catch (e) { logger.info(e); _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: e.message, data: { id: manifestId, status: _status, error: e.error } }); } } function getMediaInfos() { _streams.forEach(stream =&gt; { stream.getMediaInfos(); }); } /** * Init databsse to store fragments * @param {number} manifestId * @instance */ function createFragmentStore(manifestId) { return offlineStoreController.createFragmentStore(manifestId); } /** * Store in database the string representation of offline manifest (with only downloaded representations) * @param {object} offlineManifest * @instance */ function createOfflineManifest(offlineManifest) { return offlineStoreController.createOfflineManifest(offlineManifest); } /** * Store in database the string representation of offline manifest (with only downloaded representations) * @param {object} offlineManifest * @instance */ function updateOfflineManifest(offlineManifest) { return offlineStoreController.updateOfflineManifest(offlineManifest); } /** * Triggered when manifest is loaded from internet. * @param {Object[]} e */ function onOriginalManifestLoaded(e) { // unregister form event eventBus.off(events.ORIGINAL_MANIFEST_LOADED, onOriginalManifestLoaded, instance); _xmlManifest = e.originalManifest; if (_manifest.type === dashConstants.DYNAMIC) { _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: 'Cannot handle DYNAMIC manifest', data: { id: manifestId, status: _status } }); logger.error('Cannot handle DYNAMIC manifest'); return; } if (_manifest.Period_asArray.length &gt; 1) { _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: 'MultiPeriod manifest are not yet supported', data: { id: manifestId, status: _status } }); logger.error('MultiPeriod manifest are not yet supported'); return; } // save original manifest (for resume) // initialise offline streams composeStreams(_manifest); // get MediaInfos getMediaInfos(); eventBus.trigger(events.STREAMS_COMPOSED); } function initializeAllMediasInfoList(selectedRepresentations) { for (let i = 0; i &lt; _streams.length; i++) { _streams[i].initializeAllMediasInfoList(selectedRepresentations); } } function getSelectedRepresentations(mediaInfos) { let rep = {}; rep[constants.VIDEO] = []; rep[constants.AUDIO] = []; rep[constants.TEXT] = []; // selectedRepresentations.video.forEach(item =&gt; { // ret[constants.VIDEO].push(item.id); // }); // selectedRepresentations.audio.forEach(item =&gt; { // ret[constants.AUDIO].push(item.id); // }); // selectedRepresentations.text.forEach(item =&gt; { // ret[item.type].push(item.id); // }); mediaInfos.forEach(mediaInfo =&gt; { mediaInfo.bitrateList.forEach(bitrate =&gt; { rep[mediaInfo.type].push(bitrate.id); }); }); return rep; } function startDownload(mediaInfos) { try { let rep = getSelectedRepresentations(mediaInfos); offlineStoreController.saveSelectedRepresentations(manifestId, rep) .then(() =&gt; { return createFragmentStore(manifestId); }) .then(() =&gt; { return generateOfflineManifest(rep); }) .then(function () { initializeAllMediasInfoList(rep); }); } catch (err) { _status = OfflineConstants.OFFLINE_STATUS_ERROR; errHandler.error({ code: OfflineErrors.OFFLINE_ERROR, message: err.message, data: { id: manifestId, status: _status } }); } } /** * Create the parser used to convert original manifest in offline manifest * Creates a JSON object that will be stored in database * @param {Object[]} selectedRepresentations * @instance */ function generateOfflineManifest(selectedRepresentations) { _indexDBManifestParser = OfflineIndexDBManifestParser(context).create({ manifestId: manifestId, allMediaInfos: selectedRepresentations, debug: debug, dashConstants: dashConstants, constants: constants, urlUtils: urlUtils }); return _indexDBManifestParser.parse(_xmlManifest).then(function (parsedManifest) { if (parsedManifest !== null) { return offlineStoreController.getManifestById(manifestId) .then((item) =&gt; { item.originalURL = _manifest.url; item.originalManifest = _xmlManifest; item.manifest = parsedManifest; return updateOfflineManifest(item); }); } else { return Promise.reject('falling parsing offline manifest'); } }).catch(function (err) { return Promise.reject(err); }); } /** * Stops downloading of fragments * @instance */ function stopDownload() { if (manifestId !== null &amp;&amp; isDownloading()) { for (let i = 0, ln = _streams.length; i &lt; ln; i++) { _streams[i].stopOfflineStreamProcessors(); } // remove streams _streams = []; _isComposed = false; _status = OfflineConstants.OFFLINE_STATUS_STOPPED; // update status offlineStoreController.setDownloadingStatus(manifestId, _status).then(function () { eventBus.trigger(events.OFFLINE_RECORD_STOPPED, { sender: this, id: manifestId, status: _status, message: 'Downloading has been stopped for this stream !' }); _isDownloadingStatus = false; }); } } /** * Delete an offline manifest (and all of its data) * @instance */ function deleteDownload() { stopDownload(); } /** * Resume download of a stream * @instance */ function resumeDownload() { if (isDownloading()) { return; } _isDownloadingStatus = true; let selectedRepresentations; offlineStoreController.getManifestById(manifestId) .then((item) =&gt; { let parser = DashParser(context).create({ debug: debug }); _manifest = parser.parse(item.originalManifest); composeStreams(_manifest); selectedRepresentations = item.selected; eventBus.trigger(events.STREAMS_COMPOSED); return createFragmentStore(manifestId); }) .then(() =&gt; { initializeAllMediasInfoList(selectedRepresentations); }); } /** * Compute the progression of download * @instance */ function getDownloadProgression() { return Math.round(_progression * 100); } /** * Reset events listeners * @instance */ function resetDownload() { for (let i = 0, ln = _streams.length; i &lt; ln; i++) { _streams[i].reset(); } _indexDBManifestParser = null; _isDownloadingStatus = false; _streams = []; eventBus.off(events.MANIFEST_UPDATED, onManifestUpdated, instance); eventBus.off(events.ORIGINAL_MANIFEST_LOADED, onOriginalManifestLoaded, instance); resetIndexedDBEvents(); } function onError(e) { if (e.error.code === OfflineErrors.INDEXEDDB_QUOTA_EXCEED_ERROR || e.error.code === OfflineErrors.INDEXEDDB_INVALID_STATE_ERROR) { stopDownload(); } } function resetIndexedDBEvents() { eventBus.on(events.ERROR, onError, instance); } /** * Reset * @instance */ function reset() { if (isDownloading()) { resetDownload(); } baseURLController.reset(); manifestUpdater.reset(); } instance = { reset: reset, getId: getId, getOfflineUrl: getOfflineUrl, getManifestUrl: getManifestUrl, getStatus: getStatus, setInitialState: setInitialState, initDownload: initDownload, downloadFromUrl: downloadFromUrl, startDownload: startDownload, stopDownload: stopDownload, resumeDownload: resumeDownload, deleteDownload: deleteDownload, getDownloadProgression: getDownloadProgression, isDownloading: isDownloading, resetDownload: resetDownload }; setup(); return instance; } OfflineDownload.__dashjs_factory_name = 'OfflineDownload'; export default dashjs.FactoryMaker.getClassFactory(OfflineDownload); /* jshint ignore:line */ × Search results Close "},"offline_errors_OfflineErrors.js.html":{"id":"offline_errors_OfflineErrors.js.html","title":"Source: offline/errors/OfflineErrors.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/errors/OfflineErrors.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import ErrorsBase from '../../core/errors/ErrorsBase'; /** * Offline Errors declaration * @class */ class OfflineErrors extends ErrorsBase { constructor () { super(); /** * Error code returned when an error occurs in offline module */ this.OFFLINE_ERROR = 11000; // Based upon https://developer.mozilla.org/fr/docs/Web/API/DOMException this.INDEXEDDB_QUOTA_EXCEED_ERROR = 11001; this.INDEXEDDB_INVALID_STATE_ERROR = 11002; this.INDEXEDDB_NOT_READABLE_ERROR = 11003; this.INDEXEDDB_NOT_FOUND_ERROR = 11004; this.INDEXEDDB_NETWORK_ERROR = 11005; this.INDEXEDDB_DATA_ERROR = 11006; this.INDEXEDDB_TRANSACTION_INACTIVE_ERROR = 11007; this.INDEXEDDB_NOT_ALLOWED_ERROR = 11008; this.INDEXEDDB_NOT_SUPPORTED_ERROR = 11009; this.INDEXEDDB_VERSION_ERROR = 11010; this.INDEXEDDB_TIMEOUT_ERROR = 11011; this.INDEXEDDB_ABORT_ERROR = 11012; this.INDEXEDDB_UNKNOWN_ERROR = 11013; } } let offlineErrors = new OfflineErrors(); export default offlineErrors; × Search results Close "},"offline_events_OfflineEvents.js.html":{"id":"offline_events_OfflineEvents.js.html","title":"Source: offline/events/OfflineEvents.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/events/OfflineEvents.js import EventsBase from './../../core/events/EventsBase'; /** * These are offline events that should be sent to the player level. * @class */ class OfflineEvents extends EventsBase { constructor () { super(); /** * Triggered when all mediaInfo has been loaded * @event OfflineEvents#OFFLINE_RECORD_LOADEDMETADATA */ this.OFFLINE_RECORD_LOADEDMETADATA = 'public_offlineRecordLoadedmetadata'; /** * Triggered when a record is initialized and download is started * @event OfflineEvents#OFFLINE_RECORD_STARTED */ this.OFFLINE_RECORD_STARTED = 'public_offlineRecordStarted'; /** * Triggered when the user stop downloading a record * @event OfflineEvents#OFFLINE_RECORD_STOPPED */ this.OFFLINE_RECORD_STOPPED = 'public_offlineRecordStopped'; /** * Triggered when all record has been downloaded * @event OfflineEvents#OFFLINE_RECORD_FINISHED */ this.OFFLINE_RECORD_FINISHED = 'public_offlineRecordFinished'; } } let offlineEvents = new OfflineEvents(); export default offlineEvents; × Search results Close "},"offline_utils_OfflineIndexDBManifestParser.js.html":{"id":"offline_utils_OfflineIndexDBManifestParser.js.html","title":"Source: offline/utils/OfflineIndexDBManifestParser.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/utils/OfflineIndexDBManifestParser.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @ignore */ const Entities = require('html-entities').XmlEntities; const OFFLINE_BASE_URL = 'offline_indexeddb://'; function OfflineIndexDBManifestParser(config) { const manifestId = config.manifestId; const allMediaInfos = config.allMediaInfos; const urlUtils = config.urlUtils; const debug = config.debug; const dashConstants = config.dashConstants; const constants = config.constants; let instance, DOM, logger; function setup() { logger = debug.getLogger(instance); } /** * Parse XML manifest * @param {string} XMLDoc - xml manifest * @param {object} representation * @returns {Promise} a promise that will be resolved or rejected at the end of encoding process * @instance */ function parse(XMLDoc, representation) { return new Promise(function (resolve, reject) { DOM = new DOMParser().parseFromString(XMLDoc, 'application/xml'); let mpd = DOM.getElementsByTagName(dashConstants.MPD) ? DOM.getElementsByTagName(dashConstants.MPD) : null; for (let i = 0; i &lt; mpd.length; i++) { if (mpd[i] !== null) { editBaseURLAttribute(mpd[i]); browsePeriods(mpd[i], representation); } } let manifestEncoded = encodeManifest(DOM); if (manifestEncoded !== '') { resolve(manifestEncoded); } else { reject('Encoded error'); } }); } /** * URL encode parsed manifest * @param {string} DOM * @returns {string} Url encoded XML * @instance */ function encodeManifest(DOM) { logger.info('encodedManifest ' + new XMLSerializer().serializeToString(DOM)); return new Entities().encode(new XMLSerializer().serializeToString(DOM)); } /** * Update baseURL to point to local stored data P * @param {XML} currentMPD * @instance */ function editBaseURLAttribute(currentMPD) { let basesURL, fragmentId, representationId; let url = `${OFFLINE_BASE_URL}${manifestId}/`; basesURL = currentMPD.getElementsByTagName(dashConstants.BASE_URL); if (basesURL.length === 0) { // add baseURL let element = DOM.createElement(dashConstants.BASE_URL); element.innerHTML = url; currentMPD.appendChild(element); } basesURL = currentMPD.getElementsByTagName(dashConstants.BASE_URL); for (let i = 0; i &lt; basesURL.length; i++) { let parent = basesURL[i].parentNode; if (parent.nodeName === dashConstants.MPD) { basesURL[i].innerHTML = url; } else if (parent.nodeName === dashConstants.REPRESENTATION) { let adaptationsSet = parent.parentNode; if (adaptationsSet.nodeName == dashConstants.ADAPTATION_SET) { if (urlUtils.isHTTPS(basesURL[i].innerHTML) || urlUtils.isHTTPURL(basesURL[i].innerHTML)) { fragmentId = getFragmentId(basesURL[i].innerHTML); representationId = getBestRepresentationId(adaptationsSet); basesURL[i].innerHTML = url + representationId + '_' + fragmentId; } else if (basesURL[i].innerHTML === './') { basesURL[i].innerHTML = url; } else { fragmentId = getFragmentId(basesURL[i].innerHTML); representationId = getBestRepresentationId(adaptationsSet); basesURL[i].innerHTML = representationId + '_' + fragmentId; } } } else { basesURL[i].innerHTML = url; } } } /** * Browse periods * @param {XML} currentMPD * @param {Object} representation * @instance */ function browsePeriods(currentMPD, representation) { let periods = currentMPD.getElementsByTagName(dashConstants.PERIOD); for (let j = 0; j &lt; periods.length; j++) { browseAdaptationsSet(periods[j], representation); } } /** * Browse adapatation set to update data (delete those taht are not choosen by user ...) * @param {XML} currentPeriod * @param {Array} representationsToUpdate * @instance */ function browseAdaptationsSet(currentPeriod, representationsToUpdate) { let adaptationsSet, currentAdaptationSet, currentAdaptationType, representations; adaptationsSet = currentPeriod.getElementsByTagName(dashConstants.ADAPTATION_SET); for (let i = adaptationsSet.length - 1; i &gt;= 0; i--) { currentAdaptationSet = adaptationsSet[i]; if (currentAdaptationSet) { currentAdaptationType = findAdaptationType(currentAdaptationSet); representations = findRepresentations(currentAdaptationSet); findAndKeepOnlySelectedRepresentations(currentAdaptationSet, representations, currentAdaptationType); representations = findRepresentations(currentAdaptationSet); deleteSegmentBase(currentAdaptationSet); if (representations.length === 0) { currentPeriod.removeChild(currentAdaptationSet); } else { //detect Segment list use case for (let i = 0; i &lt; representations.length; i++) { let rep = representations[i]; let segmentList = getSegmentList(rep); if (segmentList.length &gt;= 1) { editSegmentListAttributes(segmentList, rep); } } let segmentTemplate = getSegmentTemplate(currentAdaptationSet); // segmentTemplate is defined, update attributes in order to be correctly played offline if (segmentTemplate.length &gt;= 1) { editSegmentTemplateAttributes(segmentTemplate); } // detect SegmentBase use case =&gt; transfrom manifest to SegmentList in SegmentTemplate if (representationsToUpdate &amp;&amp; representationsToUpdate.length &gt; 0 ) { let selectedRep; for (let i = 0; i &lt; representations.length; i++) { let rep = representations[i]; for (let j = 0; representationsToUpdate &amp;&amp; j &lt; representationsToUpdate.length; j++) { if (representationsToUpdate[j].id === rep.id) { selectedRep = representationsToUpdate[j]; break; } } } addSegmentTemplateAttributes(currentAdaptationSet, selectedRep); } } } } } /** * Returns type of adapation set * @param {XML} currentAdaptationSet * @returns {string|null} type * @instance */ function findAdaptationType(currentAdaptationSet) { if (getIsMuxed(currentAdaptationSet)) { return constants.MUXED; } else if (getIsAudio(currentAdaptationSet)) { return constants.AUDIO; } else if (getIsVideo(currentAdaptationSet)) { return constants.VIDEO; } else if (getIsText(currentAdaptationSet)) { return constants.TEXT; } else if (getIsImage(currentAdaptationSet)) { return constants.IMAGE; } return null; } function getIsAudio(adaptation) { return getIsTypeOf(adaptation, constants.AUDIO); } function getIsVideo(adaptation) { return getIsTypeOf(adaptation, constants.VIDEO); } function getIsText(adaptation) { return getIsTypeOf(adaptation, constants.TEXT); } function getIsMuxed(adaptation) { return getIsTypeOf(adaptation, constants.MUXED); } function getIsImage(adaptation) { return getIsTypeOf(adaptation, constants.IMAGE); } // based upon DashManifestModel, but using DomParser function getIsTypeOf(adaptation, type) { if (!adaptation) { throw new Error('adaptation is not defined'); } if (!type) { throw new Error('type is not defined'); } return testMimeType(adaptation, type); } function testMimeType(adaptation, type) { let mimeTypeRegEx = (type !== constants.TEXT) ? new RegExp(type) : new RegExp('(vtt|ttml)'); let mimeType = findMimeType(adaptation); if (mimeType) { return mimeTypeRegEx.test(mimeType); } // no mime type in adaptation, search in representation let representations = findRepresentations(adaptation); if (representations) { for (let i = 0; i &lt; representations.length; i++) { let representation = representations[i]; mimeType = findMimeType(representation); if (mimeType) { return mimeTypeRegEx.test(mimeType); } } } return false; } /** * Returns mime-type of xml tag * @param {Object} tag * @returns {string|null} mimeType * @instance */ function findMimeType(tag) { return tag.getAttribute(dashConstants.MIME_TYPE); } /** * Returns representations of adaptation set * @param {XML} adaptation * @returns {XML} representations * @instance */ function findRepresentations(adaptation) { return adaptation.getElementsByTagName(dashConstants.REPRESENTATION); } /** * Return segment template list of adaptations set * @param {XML} currentAdaptationSet * @returns {XML} representations * @instance */ function getSegmentTemplate(currentAdaptationSet) { return currentAdaptationSet.getElementsByTagName(dashConstants.SEGMENT_TEMPLATE); } /** * Return segment list tags of adaptations set * @param {XML} tag * @returns {XML} representations * @instance */ function getSegmentList(tag) { return tag.getElementsByTagName(dashConstants.SEGMENT_LIST); } function deleteSegmentBase(tag) { let elements = tag.getElementsByTagName(dashConstants.SEGMENT_BASE); for (let i = 0; i &lt; elements.length; i++) { let segmentBase = elements[i]; segmentBase.parentNode.removeChild(segmentBase); } } /** * @param {XML} segmentTemplate * @param {object} rep * @instance */ function addSegmentTimelineElements(segmentTemplate, rep) { let S = DOM.createElement('S'); if (rep &amp;&amp; rep.segments) { let segmentTimelineElement = DOM.createElement(dashConstants.SEGMENT_TIMELINE); let changedDuration = getDurationChangeArray(rep); for (let i = 0; i &lt; changedDuration.length; i++) { let repeatValue = i + 1 &lt; changedDuration.length ? (changedDuration[i + 1] - changedDuration[i]) - 1 : 0; if (repeatValue &gt; 1) { S.setAttribute('r', repeatValue); } S.setAttribute('d', rep.segments[changedDuration[i]].duration); segmentTimelineElement.appendChild(S); S = DOM.createElement('S'); } segmentTemplate.appendChild(segmentTimelineElement); } } function getDurationChangeArray(rep) { let array = []; array.push(0); for (let i = 1; i &lt; rep.segments.length; i++) { if (rep.segments[i - 1].duration !== rep.segments[i].duration) { array.push(i); } } return array; } /** * Update attributes of segment templates to match offline urls * @param {Array} segmentsTemplates * @instance */ function editSegmentTemplateAttributes(segmentsTemplates) { for (let i = 0; i &lt; segmentsTemplates.length; i++) { let media = segmentsTemplates[i].getAttribute(dashConstants.MEDIA); media = '$RepresentationID$_$Number$' + media.substring(media.indexOf('.'), media.length); //id + extension segmentsTemplates[i].setAttribute(dashConstants.START_NUMBER, '0'); segmentsTemplates[i].setAttribute(dashConstants.MEDIA, media); segmentsTemplates[i].setAttribute(dashConstants.INITIALIZATION_MINUS,'$RepresentationID$_init'); } } /** * Update attributes of segment list to match offline urls * @param {Array} segmentLists * @param {Object} representation * @instance */ function editSegmentListAttributes(segmentLists, representation) { let repId = representation.getAttribute(dashConstants.ID); for (let i = 0; i &lt; segmentLists.length; i++) { let segmentList = segmentLists[i]; let initialisation = segmentList.getElementsByTagName(dashConstants.INITIALIZATION); if (initialisation) { let sourceURL = initialisation[0].getAttribute(dashConstants.SOURCE_URL); sourceURL = `${repId}_init`; initialisation[0].setAttribute(dashConstants.SOURCE_URL, sourceURL); } let segmentURLs = segmentList.getElementsByTagName(dashConstants.SEGMENT_URL); if (segmentURLs) { for (let j = 0; j &lt; segmentURLs.length; j++) { let segmentUrl = segmentURLs[j]; let media = segmentUrl.getAttribute(dashConstants.MEDIA); media = `${repId}_${j}`; segmentUrl.setAttribute(dashConstants.MEDIA, media); } } } } /** * @param {XML} adaptationSet * @param {object} rep * @instance */ function addSegmentTemplateAttributes(adaptationSet, rep) { let segmentTemplateElement = DOM.createElement(dashConstants.SEGMENT_TEMPLATE); segmentTemplateElement.setAttribute(dashConstants.START_NUMBER, '0'); segmentTemplateElement.setAttribute(dashConstants.MEDIA, '$RepresentationID$-$Time$'); segmentTemplateElement.setAttribute(dashConstants.INITIALIZATION_MINUS,'$RepresentationID$_init'); addSegmentTimelineElements(segmentTemplateElement, rep); adaptationSet.appendChild(segmentTemplateElement); } /** * Delete all representations except the one choosed by user * @param {XML} currentAdaptationSet * @param {XML} representations * @param {string} adaptationType * @instance */ function findAndKeepOnlySelectedRepresentations(currentAdaptationSet, representations, adaptationType) { for ( var i = representations.length - 1; i &gt;= 0; i--) { let representation = representations[i]; let repId = representation.getAttribute(dashConstants.ID); if (allMediaInfos[adaptationType] &amp;&amp; allMediaInfos[adaptationType].indexOf(repId) === -1) { // representation is not selected, remove it currentAdaptationSet.removeChild(representation); } } } // UTILS /** * Get id of first representation of adaptation set * @param {XMl} currentAdaptationSet * @returns {string} id * @instance */ function getBestRepresentationId(currentAdaptationSet) { let bestRepresentation = currentAdaptationSet.getElementsByTagName(dashConstants.REPRESENTATION)[0]; console.log(bestRepresentation.getAttribute(dashConstants.ID)); return bestRepresentation.getAttribute(dashConstants.ID); } /** * Parse and returns fragments of offline url =&gt; xxxx://xxxx/fragmentId/ * @param {string} url * @returns {string} fragmentId * @instance */ function getFragmentId(url) { let idxFragId = url.lastIndexOf('/'); //logger.warn('fragId : ' + url.substring(idxFragId + 1, url.length)); return url.substring(idxFragId,url.length); } setup(); instance = { parse: parse }; return instance; } OfflineIndexDBManifestParser.__dashjs_factory_name = 'OfflineIndexDBManifestParser'; export default dashjs.FactoryMaker.getClassFactory(OfflineIndexDBManifestParser); /* jshint ignore:line */ × Search results Close "},"offline_OfflineStreamProcessor.js.html":{"id":"offline_OfflineStreamProcessor.js.html","title":"Source: offline/OfflineStreamProcessor.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/OfflineStreamProcessor.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import DashHandler from '../dash/DashHandler'; import RepresentationController from '../dash/controllers/RepresentationController'; import FragmentModel from '../streaming/models/FragmentModel'; import FragmentLoader from '../streaming/FragmentLoader'; import URLUtils from '../streaming/utils/URLUtils'; import RequestModifier from '../streaming/utils/RequestModifier'; import SegmentsController from '../dash/controllers/SegmentsController'; function OfflineStreamProcessor(config) { config = config || {}; const context = this.context; const eventBus = config.eventBus; const events = config.events; const errors = config.errors; const debug = config.debug; const constants = config.constants; const settings = config.settings; const dashConstants = config.dashConstants; const manifestId = config.id; const type = config.type; const streamInfo = config.streamInfo; const errHandler = config.errHandler; const mediaPlayerModel = config.mediaPlayerModel; const abrController = config.abrController; const playbackController = config.playbackController; const adapter = config.adapter; const dashMetrics = config.dashMetrics; const baseURLController = config.baseURLController; const timelineConverter = config.timelineConverter; const bitrate = config.bitrate; const offlineStoreController = config.offlineStoreController; const completedCb = config.callbacks &amp;&amp; config.callbacks.completed; const progressCb = config.callbacks &amp;&amp; config.callbacks.progression; let instance, logger, mediaInfo, indexHandler, representationController, fragmentModel, updating, downloadedSegments, isInitialized, segmentsController, isStopped; function setup() { resetInitialSettings(); logger = debug.getLogger(instance); segmentsController = SegmentsController(context).create({ events, eventBus, streamInfo, timelineConverter, dashConstants, segmentBaseController: config.segmentBaseController, type }); indexHandler = DashHandler(context).create({ streamInfo: streamInfo, type: type, timelineConverter: timelineConverter, dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, baseURLController: baseURLController, errHandler: errHandler, settings: settings, // boxParser: boxParser, eventBus: eventBus, events: events, debug: debug, requestModifier: RequestModifier(context).getInstance(), dashConstants: dashConstants, constants: constants, segmentsController: segmentsController, urlUtils: URLUtils(context).getInstance() }); representationController = RepresentationController(context).create({ streamInfo: streamInfo, type: type, abrController: abrController, dashMetrics: dashMetrics, playbackController: playbackController, timelineConverter: timelineConverter, dashConstants: dashConstants, events: events, eventBus: eventBus, errors: errors, segmentsController: segmentsController }); fragmentModel = FragmentModel(context).create({ streamInfo: streamInfo, dashMetrics: dashMetrics, fragmentLoader: FragmentLoader(context).create({ dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, errHandler: errHandler, requestModifier: RequestModifier(context).getInstance(), settings: settings, eventBus: eventBus, events: events, errors: errors, constants: constants, dashConstants: dashConstants, urlUtils: URLUtils(context).getInstance() }), debug: debug, eventBus: eventBus, events: events }); eventBus.on(events.STREAM_REQUESTING_COMPLETED, onStreamRequestingCompleted, instance); eventBus.on(events.FRAGMENT_LOADING_COMPLETED, onFragmentLoadingCompleted, instance); } function initialize(_mediaInfo) { mediaInfo = _mediaInfo; indexHandler.initialize(false); updateRepresentation(mediaInfo); } function isInitRequest(request) { return request.type === 'InitializationSegment'; } function onFragmentLoadingCompleted(e) { if (e.sender !== fragmentModel) { return; } if (e.request !== null) { let isInit = isInitRequest(e.request); let suffix = isInit ? 'init' : e.request.index; let fragmentName = e.request.representationId + '_' + suffix; offlineStoreController.storeFragment(manifestId, fragmentName, e.response) .then(() =&gt; { if (!isInit) { // store current index and downloadedSegments number offlineStoreController.setRepresentationCurrentState(manifestId, e.request.representationId, { index: e.request.index, downloaded: downloadedSegments }); } }); } if (e.error &amp;&amp; e.request.serviceLocation &amp;&amp; !isStopped) { fragmentModel.executeRequest(e.request); } else { downloadedSegments++; download(); } } function onStreamRequestingCompleted(e) { if (e.fragmentModel !== fragmentModel) { return; } logger.info(`[${manifestId}] Stream is complete`); stop(); completedCb(); } function getRepresentationController() { return representationController; } function getRepresentationId() { return representationController.getCurrentRepresentation().id; } /** * Stops download of fragments * @memberof OfflineStreamProcessor# */ function stop() { if (isStopped) { return; } isStopped = true; } function removeExecutedRequestsBeforeTime(time) { if (fragmentModel) { fragmentModel.removeExecutedRequestsBeforeTime(time); } } /** * Execute init request for the represenation * @memberof OfflineStreamProcessor# */ function getInitRequest() { if (!representationController.getCurrentRepresentation()) { return null; } return indexHandler.getInitRequest(getMediaInfo(), representationController.getCurrentRepresentation()); } /** * Get next request * @memberof OfflineStreamProcessor# */ function getNextRequest() { return indexHandler.getNextSegmentRequest(getMediaInfo(), representationController.getCurrentRepresentation()); } /** * Start download * @memberof OfflineStreamProcessor# */ function start() { if (representationController) { if (!representationController.getCurrentRepresentation()) { throw new Error('Start denied to OfflineStreamProcessor'); } isStopped = false; offlineStoreController.getRepresentationCurrentState(manifestId, representationController.getCurrentRepresentation().id) .then((state) =&gt; { if (state) { indexHandler.setCurrentIndex(state.index); downloadedSegments = state.downloaded; } download(); }) .catch(() =&gt; { // start from beginining download(); }); } } /** * Performs download of fragment according to type * @memberof OfflineStreamProcessor# */ function download() { if (isStopped) { return; } if (isNaN(representationController.getCurrentRepresentation())) { let request = null; if (!isInitialized) { request = getInitRequest(); isInitialized = true; } else { request = getNextRequest(); // update progression : done here because availableSegmentsNumber is done in getNextRequest from dash handler updateProgression(); } if (request) { logger.info(`[${manifestId}] download request : ${request.url}`); fragmentModel.executeRequest(request); } else { logger.info(`[${manifestId}] no request to be downloaded`); } } } /** * Update representation * @param {Object} mediaInfo - mediaInfo * @memberof OfflineStreamProcessor# */ function updateRepresentation(mediaInfo) { updating = true; let voRepresentations = adapter.getVoRepresentations(mediaInfo); // get representation VO according to id. let quality = voRepresentations.findIndex((representation) =&gt; { return representation.id === bitrate.id; }); if (type !== constants.VIDEO &amp;&amp; type !== constants.AUDIO &amp;&amp; type !== constants.TEXT) { updating = false; return; } representationController.updateData(null, voRepresentations, type, mediaInfo.isFragmented, quality); } function isUpdating() { return updating; } function getType() { return type; } function getMediaInfo() { return mediaInfo; } function getAvailableSegmentsNumber() { return representationController.getCurrentRepresentation().numberOfSegments + 1; // do not forget init segment } function updateProgression() { if (progressCb) { progressCb(instance, downloadedSegments, getAvailableSegmentsNumber()); } } function resetInitialSettings() { isInitialized = false; downloadedSegments = 0; updating = false; } /** * Reset * @memberof OfflineStreamProcessor# */ function reset() { resetInitialSettings(); indexHandler.reset(); eventBus.off(events.STREAM_REQUESTING_COMPLETED, onStreamRequestingCompleted, instance); eventBus.off(events.FRAGMENT_LOADING_COMPLETED, onFragmentLoadingCompleted, instance); } instance = { initialize: initialize, getMediaInfo: getMediaInfo, getRepresentationController: getRepresentationController, removeExecutedRequestsBeforeTime: removeExecutedRequestsBeforeTime, getType: getType, getRepresentationId: getRepresentationId, isUpdating: isUpdating, start: start, stop: stop, getAvailableSegmentsNumber: getAvailableSegmentsNumber, reset: reset }; setup(); return instance; } OfflineStreamProcessor.__dashjs_factory_name = 'OfflineStreamProcessor'; const factory = dashjs.FactoryMaker.getClassFactory(OfflineStreamProcessor); /* jshint ignore:line */ export default factory; × Search results Close "},"offline_OfflineStream.js.html":{"id":"offline_OfflineStream.js.html","title":"Source: offline/OfflineStream.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: offline/OfflineStream.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import OfflineStreamProcessor from './OfflineStreamProcessor'; /** * Initialize and Manage Offline Stream for each type */ /** * @class OfflineStream * @description Initialize and Manage Offline Stream for each type * @param {Object} config - dependences * @ignore */ function OfflineStream(config) { config = config || {}; const context = this.context; const eventBus = config.eventBus; const events = config.events; const errors = config.errors; const constants = config.constants; const dashConstants = config.dashConstants; const settings = config.settings; const debug = config.debug; const errHandler = config.errHandler; const mediaPlayerModel = config.mediaPlayerModel; const abrController = config.abrController; const playbackController = config.playbackController; const adapter = config.adapter; const dashMetrics = config.dashMetrics; const baseURLController = config.baseURLController; const timelineConverter = config.timelineConverter; const segmentBaseController = config.segmentBaseController; const offlineStoreController = config.offlineStoreController; const manifestId = config.id; const startedCb = config.callbacks &amp;&amp; config.callbacks.started; const progressionCb = config.callbacks &amp;&amp; config.callbacks.progression; const finishedCb = config.callbacks &amp;&amp; config.callbacks.finished; const updateManifest = config.callbacks &amp;&amp; config.callbacks.updateManifestNeeded; let instance, offlineStreamProcessors, startedOfflineStreamProcessors, finishedOfflineStreamProcessors, streamInfo, representationsToUpdate, allMediasInfosList, progressionById; function setup() { resetInitialSettings(); } /** * Reset */ function resetInitialSettings() { streamInfo = null; offlineStreamProcessors = []; startedOfflineStreamProcessors = 0; finishedOfflineStreamProcessors = 0; allMediasInfosList = []; representationsToUpdate = []; progressionById = {}; } /** * Initialize offlinestream * @param {Object} initStreamInfo */ function initialize(initStreamInfo) { streamInfo = initStreamInfo; eventBus.on(events.DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance); } function getStreamId() { return streamInfo.id; } /** * Creates media infos list, so that user will be able to choose the representation he wants to download */ function getMediaInfos() { let mediaInfos = adapter.getAllMediaInfoForType(streamInfo, constants.VIDEO); mediaInfos = mediaInfos.concat(adapter.getAllMediaInfoForType(streamInfo, constants.AUDIO)); mediaInfos = mediaInfos.concat(adapter.getAllMediaInfoForType(streamInfo, constants.TEXT)); // mediaInfos = mediaInfos.concat(adapter.getAllMediaInfoForType(streamInfo, constants.MUXED)); // mediaInfos = mediaInfos.concat(adapter.getAllMediaInfoForType(streamInfo, constants.IMAGE)); eventBus.trigger(events.OFFLINE_RECORD_LOADEDMETADATA, { id: manifestId, mediaInfos: mediaInfos }); } /** * Initialize with choosen representations by user * @param {Object} mediasInfoList */ function initializeAllMediasInfoList(mediasInfoList) { allMediasInfosList = mediasInfoList; initializeMedia(streamInfo); } /** * Initialize media for each type * @param {Object} streamInfo */ function initializeMedia(streamInfo) { createOfflineStreamProcessorFor(constants.VIDEO,streamInfo); createOfflineStreamProcessorFor(constants.AUDIO,streamInfo); createOfflineStreamProcessorFor(constants.TEXT,streamInfo); createOfflineStreamProcessorFor(constants.MUXED,streamInfo); createOfflineStreamProcessorFor(constants.IMAGE,streamInfo); } function createOfflineStreamProcessorFor(type, streamInfo) { // filter mediaInfo according to choosen representation id let allMediaInfoForType = adapter.getAllMediaInfoForType(streamInfo, type); allMediaInfoForType.forEach((media) =&gt; { media.bitrateList = media.bitrateList.filter((bitrate) =&gt; { if (allMediasInfosList[type] &amp;&amp; allMediasInfosList[type].indexOf(bitrate.id) !== -1) { return true; } return false; }); }); allMediaInfoForType = allMediaInfoForType.filter((media) =&gt; { return (media.bitrateList &amp;&amp; media.bitrateList.length &gt; 0); }); // cration of an offline stream processor for each choosen representation allMediaInfoForType.forEach((mediaInfo) =&gt; { if (mediaInfo.bitrateList) { mediaInfo.bitrateList.forEach((bitrate) =&gt; { createStreamProcessor(mediaInfo, bitrate); }); } }); return allMediaInfoForType; } function createStreamProcessor (mediaInfo, bitrate) { let streamProcessor = OfflineStreamProcessor(context).create({ id: manifestId, streamInfo: streamInfo, debug: debug, events: events, errors: errors, eventBus: eventBus, constants: constants, dashConstants: dashConstants, settings: settings, type: mediaInfo.type, mimeType: mediaInfo.mimeType, bitrate: bitrate, errHandler: errHandler, mediaPlayerModel: mediaPlayerModel, abrController: abrController, playbackController: playbackController, adapter: adapter, dashMetrics: dashMetrics, baseURLController: baseURLController, timelineConverter: timelineConverter, offlineStoreController: offlineStoreController, segmentBaseController: segmentBaseController, callbacks: { completed: onStreamCompleted, progression: onStreamProgression } }); offlineStreamProcessors.push(streamProcessor); streamProcessor.initialize(mediaInfo); progressionById[bitrate.id] = null; } function onStreamCompleted() { finishedOfflineStreamProcessors++; if (finishedOfflineStreamProcessors === offlineStreamProcessors.length) { finishedCb({sender: this, id: manifestId, message: 'Downloading has been successfully completed for this stream !'}); } } function onStreamProgression(streamProcessor, downloadedSegments, availableSegments ) { progressionById[streamProcessor.getRepresentationId()] = { downloadedSegments, availableSegments }; let segments = 0; let allSegments = 0; let waitForAllProgress; for (var property in progressionById) { if (progressionById.hasOwnProperty(property)) { if (progressionById[property] === null) { waitForAllProgress = true; } else { segments += progressionById[property].downloadedSegments; allSegments += progressionById[property].availableSegments; } } } if (!waitForAllProgress &amp;&amp; progressionCb) { // all progression have been started, we can compute global progression if (allSegments &gt; 0) { progressionCb(instance, segments, allSegments); } } } function onDataUpdateCompleted(e) { if (e.currentRepresentation.segments &amp;&amp; e.currentRepresentation.segments.length &gt; 0) { representationsToUpdate.push(e.currentRepresentation); } let sp; // data are ready fr stream processor, let's start download for (let i = 0; i &lt; offlineStreamProcessors.length; i++ ) { if (offlineStreamProcessors[i].getRepresentationController().getType() === e.mediaType) { sp = offlineStreamProcessors[i]; break; } } if (sp) { checkIfAllOfflineStreamProcessorsStarted(); } } function checkIfAllOfflineStreamProcessorsStarted() { startedOfflineStreamProcessors++; if (startedOfflineStreamProcessors === offlineStreamProcessors.length) { startedCb({sender: this, id: manifestId, message: 'Downloading started for this stream !'}); if (representationsToUpdate.length &gt; 0) { updateManifest({sender: this, id: manifestId, representations: representationsToUpdate }); } else { startOfflineStreamProcessors(); } } } function getStreamInfo() { return streamInfo; } function getStartTime() { return streamInfo ? streamInfo.start : NaN; } function getDuration() { return streamInfo ? streamInfo.duration : NaN; } /** * Stop offline stream processors */ function stopOfflineStreamProcessors() { for (let i = 0; i &lt; offlineStreamProcessors.length; i++) { offlineStreamProcessors[i].stop(); } } /** * Start offline stream processors */ function startOfflineStreamProcessors() { for (let i = 0; i &lt; offlineStreamProcessors.length; i++) { offlineStreamProcessors[i].start(); } } function deactivate() { let ln = offlineStreamProcessors ? offlineStreamProcessors.length : 0; for (let i = 0; i &lt; ln; i++) { offlineStreamProcessors[i].removeExecutedRequestsBeforeTime(getStartTime() + getDuration()); offlineStreamProcessors[i].reset(); } } /** * Reset */ function reset() { stopOfflineStreamProcessors(); deactivate(); resetInitialSettings(); eventBus.off(events.DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance); } instance = { initialize: initialize, getStreamId: getStreamId, getMediaInfos: getMediaInfos, initializeAllMediasInfoList: initializeAllMediasInfoList, getStreamInfo: getStreamInfo, stopOfflineStreamProcessors: stopOfflineStreamProcessors, startOfflineStreamProcessors: startOfflineStreamProcessors, reset: reset }; setup(); return instance; } OfflineStream.__dashjs_factory_name = 'OfflineStream'; export default dashjs.FactoryMaker.getClassFactory(OfflineStream); /* jshint ignore:line */ × Search results Close "},"streaming_controllers_PlaybackController.js.html":{"id":"streaming_controllers_PlaybackController.js.html","title":"Source: streaming/controllers/PlaybackController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/PlaybackController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../constants/Constants'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents'; import MetricsConstants from '../constants/MetricsConstants'; const LIVE_UPDATE_PLAYBACK_TIME_INTERVAL_MS = 500; function PlaybackController() { const context = this.context; const eventBus = EventBus(context).getInstance(); let instance, logger, streamController, serviceDescriptionController, dashMetrics, adapter, videoModel, timelineConverter, wallclockTimeIntervalId, liveDelay, originalLiveDelay, streamInfo, isDynamic, playOnceInitialized, lastLivePlaybackTime, availabilityStartTime, availabilityTimeComplete, lowLatencyModeEnabled, seekTarget, internalSeek, playbackStalled, manifestUpdateInProgress, initialCatchupModeActivated, settings; function setup() { logger = Debug(context).getInstance().getLogger(instance); reset(); } /** * Reset all settings */ function reset() { pause(); playOnceInitialized = false; liveDelay = 0; originalLiveDelay = 0; availabilityStartTime = 0; manifestUpdateInProgress = false; availabilityTimeComplete = true; lowLatencyModeEnabled = false; initialCatchupModeActivated = false; seekTarget = NaN; if (videoModel) { eventBus.off(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance); eventBus.off(Events.LOADING_PROGRESS, _onFragmentLoadProgress, instance); eventBus.off(Events.MANIFEST_UPDATED, _onManifestUpdated, instance); eventBus.off(Events.STREAMS_COMPOSED, _onStreamsComposed, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, instance); eventBus.off(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, instance); eventBus.off(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, instance); eventBus.off(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance); stopUpdatingWallclockTime(); removeAllListeners(); } wallclockTimeIntervalId = null; videoModel = null; streamInfo = null; isDynamic = null; } /** * Initializes the PlaybackController. This function is called whenever the stream is switched. * @param {object} sInfo * @param {boolean} periodSwitch */ function initialize(sInfo, periodSwitch) { streamInfo = sInfo; if (periodSwitch !== true) { _initializeForFirstStream(); } } /** * Initializes the PlaybackController when the first stream is to be played. * @private */ function _initializeForFirstStream() { addAllListeners(); isDynamic = streamInfo.manifestInfo.isDynamic; playbackStalled = false; internalSeek = false; eventBus.on(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance); eventBus.on(Events.LOADING_PROGRESS, _onFragmentLoadProgress, instance); eventBus.on(Events.MANIFEST_UPDATED, _onManifestUpdated, instance); eventBus.on(Events.STREAMS_COMPOSED, _onStreamsComposed, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, instance, { priority: EventBus.EVENT_PRIORITY_HIGH }); eventBus.on(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, instance); eventBus.on(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, instance); eventBus.on(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance); if (playOnceInitialized) { playOnceInitialized = false; play(); } } /** * Returns stalled state * @return {boolean} */ function getPlaybackStalled() { return playbackStalled } /** * Returns remaining duration of a period * @param {object} sInfo * @return {number} */ function getTimeToStreamEnd(sInfo = null) { return parseFloat((getStreamEndTime(sInfo) - getTime()).toFixed(5)); } /** * Returns end time of a period * @param {object} sInfo * @return {number} */ function getStreamEndTime(sInfo) { const refInfo = sInfo ? sInfo : streamInfo; return refInfo.start + refInfo.duration; } /** * Triggers play() on the video element */ function play(adjustLiveDelay = false) { if (streamInfo &amp;&amp; videoModel &amp;&amp; videoModel.getElement()) { if (adjustLiveDelay &amp;&amp; isDynamic) { _adjustLiveDelayAfterUserInteraction(getTime()); } videoModel.play(); } else { playOnceInitialized = true; } } /** * Triggers pause() on the video element */ function pause() { if (streamInfo &amp;&amp; videoModel) { videoModel.pause(); } } /** * Triggers a seek to the specified media time. If internal is enabled there will be now \"seeked\" event dispatched * @param {number} time * @param {boolean} stickToBuffered * @param {boolean} internal * @param {boolean} adjustLiveDelay */ function seek(time, stickToBuffered = false, internal = false, adjustLiveDelay = false) { if (!streamInfo || !videoModel) return; let currentTime = !isNaN(seekTarget) ? seekTarget : videoModel.getTime(); if (time === currentTime) return; internalSeek = (internal === true); if (!internalSeek) { seekTarget = time; } logger.info('Requesting seek to time: ' + time + (internalSeek ? ' (internal)' : '')); // We adjust the current latency. If catchup is enabled we will maintain this new latency if (isDynamic &amp;&amp; adjustLiveDelay) { _adjustLiveDelayAfterUserInteraction(time); } videoModel.setCurrentTime(time, stickToBuffered); } /** * Seeks back to the live edge as defined by the originally calculated live delay * @param {boolean} stickToBuffered * @param {boolean} internal * @param {boolean} adjustLiveDelay */ function seekToOriginalLive(stickToBuffered = false, internal = false, adjustLiveDelay = false) { const dvrWindowEnd = _getDvrWindowEnd(); if (dvrWindowEnd === 0) { return; } liveDelay = originalLiveDelay; const seektime = dvrWindowEnd - liveDelay; seek(seektime, stickToBuffered, internal, adjustLiveDelay); } /** * Seeks to the live edge as currently defined by liveDelay * @param {boolean} stickToBuffered * @param {boolean} internal * @param {boolean} adjustLiveDelay */ function seekToCurrentLive(stickToBuffered = false, internal = false, adjustLiveDelay = false) { const dvrWindowEnd = _getDvrWindowEnd(); if (dvrWindowEnd === 0) { return; } const seektime = dvrWindowEnd - liveDelay; seek(seektime, stickToBuffered, internal, adjustLiveDelay); } function _getDvrWindowEnd() { if (!streamInfo || !videoModel || !isDynamic) { return; } const type = streamController &amp;&amp; streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO; const dvrInfo = dashMetrics.getCurrentDVRInfo(type); return dvrInfo &amp;&amp; dvrInfo.range ? dvrInfo.range.end : 0; } function _adjustLiveDelayAfterUserInteraction(time) { const now = new Date(timelineConverter.getClientReferenceTime()); const period = adapter.getRegularPeriods()[0]; const nowAsPresentationTime = timelineConverter.calcPresentationTimeFromWallTime(now, period); liveDelay = nowAsPresentationTime - time; } /** * Returns current time of video element * @return {number|null} */ function getTime() { return streamInfo &amp;&amp; videoModel ? videoModel.getTime() : null; } /** * Returns paused state of the video element * @return {boolean|null} */ function isPaused() { return streamInfo &amp;&amp; videoModel ? videoModel.isPaused() : null; } /** * Returns seeking state of the video element * @return {boolean|null} */ function isSeeking() { return streamInfo &amp;&amp; videoModel ? videoModel.isSeeking() : null; } /** * Returns stalled state of the video element * @return {boolean|null} */ function isStalled() { return streamInfo &amp;&amp; videoModel ? videoModel.isStalled() : null; } /** * Returns current playback rate of the video element * @return {number|null} */ function getPlaybackRate() { return streamInfo &amp;&amp; videoModel ? videoModel.getPlaybackRate() : null; } /** * Returns the played ranges of the video element * @return {array} */ function getPlayedRanges() { return streamInfo &amp;&amp; videoModel ? videoModel.getPlayedRanges() : null; } /** * Returns ended attribute of the video element * @return {boolean|null} */ function getEnded() { return streamInfo &amp;&amp; videoModel ? videoModel.getEnded() : null; } /** * Returns whether a stream is type dynamic or not * @return {boolean} */ function getIsDynamic() { return isDynamic; } /** * Returns the StreamController * @return {object} */ function getStreamController() { return streamController; } /** * Returns whether a manifest update is in progress * @return {boolean} */ function getIsManifestUpdateInProgress() { return manifestUpdateInProgress; } /** * Returns the availabilityStartTime * @return {number} */ function getAvailabilityStartTime() { return availabilityStartTime; } /** * Returns the current live delay. A seek triggered by the user adjusts this value. * @return {number} */ function getLiveDelay() { return liveDelay; } /** * Returns the original live delay as calculated at playback start */ function getOriginalLiveDelay() { return originalLiveDelay; } /** * Returns the current live latency * @return {number} */ function getCurrentLiveLatency() { if (!isDynamic || isNaN(availabilityStartTime)) { return NaN; } let currentTime = getTime(); if (isNaN(currentTime) || currentTime === 0) { return 0; } const now = new Date().getTime() + timelineConverter.getClientTimeOffset() * 1000; return Math.max(((now - availabilityStartTime - currentTime * 1000) / 1000).toFixed(3), 0); } /** * Computes the desirable delay for the live edge to avoid a risk of getting 404 when playing at the bleeding edge * @param {number} fragmentDuration - seconds? * @param {object} manifestInfo * @returns {number} object * @memberof PlaybackController# */ function computeAndSetLiveDelay(fragmentDuration, manifestInfo) { let delay, ret, startTime; const MIN_BUFFER_TIME_FACTOR = 4; const FRAGMENT_DURATION_FACTOR = 4; const adjustedFragmentDuration = !isNaN(fragmentDuration) &amp;&amp; isFinite(fragmentDuration) ? fragmentDuration : NaN; let suggestedPresentationDelay = adapter.getSuggestedPresentationDelay(); const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings(); // Live delay specified by the user if (!isNaN(settings.get().streaming.delay.liveDelay)) { delay = settings.get().streaming.delay.liveDelay; } // Live delay fragment count specified by the user else if (settings.get().streaming.delay.liveDelayFragmentCount !== null &amp;&amp; !isNaN(settings.get().streaming.delay.liveDelayFragmentCount) &amp;&amp; !isNaN(adjustedFragmentDuration)) { delay = adjustedFragmentDuration * settings.get().streaming.delay.liveDelayFragmentCount; } // Live delay set via ServiceDescription element else if (serviceDescriptionSettings &amp;&amp; !isNaN(serviceDescriptionSettings.liveDelay) &amp;&amp; serviceDescriptionSettings.liveDelay &gt; 0) { delay = serviceDescriptionSettings.liveDelay; } // Live delay set in the manifest using @suggestedPresentation Delay else if (settings.get().streaming.delay.useSuggestedPresentationDelay === true &amp;&amp; suggestedPresentationDelay !== null &amp;&amp; !isNaN(suggestedPresentationDelay) &amp;&amp; suggestedPresentationDelay &gt; 0) { delay = suggestedPresentationDelay; } // We found a fragment duration, use that to calculcate live delay else if (!isNaN(adjustedFragmentDuration)) { delay = adjustedFragmentDuration * FRAGMENT_DURATION_FACTOR; } // Fall back to @minBufferTime to calculate the live delay else { delay = manifestInfo &amp;&amp; !isNaN(manifestInfo.minBufferTime) ? manifestInfo.minBufferTime * MIN_BUFFER_TIME_FACTOR : streamInfo.manifestInfo.minBufferTime * MIN_BUFFER_TIME_FACTOR; } startTime = adapter.getAvailabilityStartTime(); if (startTime !== null) { availabilityStartTime = startTime; } if (manifestInfo &amp;&amp; manifestInfo.dvrWindowSize &gt; 0) { // Latency can not be higher than DVR window size ret = Math.min(delay, manifestInfo.dvrWindowSize); } else { ret = delay; } liveDelay = ret; originalLiveDelay = ret; return ret; } function setConfig(config) { if (!config) return; if (config.streamController) { streamController = config.streamController; } if (config.serviceDescriptionController) { serviceDescriptionController = config.serviceDescriptionController; } if (config.dashMetrics) { dashMetrics = config.dashMetrics; } if (config.adapter) { adapter = config.adapter; } if (config.videoModel) { videoModel = config.videoModel; } if (config.timelineConverter) { timelineConverter = config.timelineConverter; } if (config.settings) { settings = config.settings; } } /** * Compare the current time of the video against the DVR window. If we are out of the DVR window we need to seek. * @param {object} mediaType */ function updateCurrentTime(mediaType = null) { if (isPaused() || !isDynamic || videoModel.getReadyState() === 0 || isSeeking() || manifestUpdateInProgress) return; // Note: In some cases we filter certain media types completely (for instance due to an unsupported video codec). This happens after the first entry to the DVR metric has been added. // Now the DVR window for the filtered media type is not updated anymore. Consequently, always use a mediaType that is available to get a valid DVR window. if (!mediaType) { mediaType = streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO; } // Compare the current time of the video element against the range defined in the DVR window. const currentTime = getTime(); const actualTime = _getAdjustedPresentationTime(currentTime, mediaType); const timeChanged = (!isNaN(actualTime) &amp;&amp; actualTime !== currentTime); if (timeChanged &amp;&amp; !isSeeking() &amp;&amp; (isStalled() || playbackStalled || videoModel.getReadyState() === 1)) { logger.debug(`UpdateCurrentTime: Seek to actual time: ${actualTime} from currentTime: ${currentTime}`); seek(actualTime, false, false); } } /** * Adjust the presentation time based on the DVR window. If we are out of the DVR window we return a corrected time * @param {number} currentTime * @param {string} mediatype * @return {number} * @private */ function _getAdjustedPresentationTime(currentTime, mediatype) { const DVRMetrics = dashMetrics.getCurrentDVRInfo(mediatype); const DVRWindow = DVRMetrics ? DVRMetrics.range : null; let actualTime; if (!DVRWindow) { return NaN; } if (currentTime &gt; DVRWindow.end) { actualTime = Math.max(DVRWindow.end - liveDelay, DVRWindow.start); } else if (currentTime &gt; 0 &amp;&amp; currentTime + 0.250 &lt; DVRWindow.start &amp;&amp; Math.abs(currentTime - DVRWindow.start) &lt; 315360000) { // Checking currentTime plus 250ms as the 'timeupdate' is fired with a frequency between 4Hz and 66Hz // https://developer.mozilla.org/en-US/docs/Web/Events/timeupdate // http://w3c.github.io/html/single-page.html#offsets-into-the-media-resource // Checking also duration of the DVR makes sense. We detected temporary situations in which currentTime // is bad reported by the browser which causes playback to jump to start (315360000 = 1 year) if (lowLatencyModeEnabled) { actualTime = Math.max(DVRWindow.end - liveDelay, DVRWindow.start); } else { actualTime = DVRWindow.start; } } else { actualTime = currentTime; } return actualTime; } /** * Start interval handler for wallclock time update */ function startUpdatingWallclockTime() { if (wallclockTimeIntervalId !== null) return; wallclockTimeIntervalId = setInterval(() =&gt; { _onWallclockTime(); }, settings.get().streaming.wallclockTimeUpdateInterval); } /** * Stop the interval handler for the wallclock time update */ function stopUpdatingWallclockTime() { clearInterval(wallclockTimeIntervalId); wallclockTimeIntervalId = null; } function _onDataUpdateCompleted(e) { const representationInfo = adapter.convertRepresentationToRepresentationInfo(e.currentRepresentation); const info = representationInfo ? representationInfo.mediaInfo.streamInfo : null; if (info === null || streamInfo.id !== info.id) return; streamInfo = info; } function _onCanPlay() { eventBus.trigger(Events.CAN_PLAY); } function _onCanPlayThrough() { eventBus.trigger(Events.CAN_PLAY_THROUGH); } function _onBufferLevelStateChanged(e) { // do not stall playback when get an event from Stream that is not active if (e.streamId !== streamController.getActiveStreamInfo().id) { return; } playbackStalled = e.state === MetricsConstants.BUFFER_EMPTY; if (settings.get().streaming.buffer.setStallState) { videoModel.setStallState(e.mediaType, e.state === MetricsConstants.BUFFER_EMPTY); } } function _onPlaybackStart() { logger.info('Native video element event: play'); updateCurrentTime(); startUpdatingWallclockTime(); eventBus.trigger(Events.PLAYBACK_STARTED, { startTime: getTime() }); } function _onPlaybackWaiting() { logger.info('Native video element event: waiting'); eventBus.trigger(Events.PLAYBACK_WAITING, { playingTime: getTime() }); } function _onPlaybackPlaying() { logger.info('Native video element event: playing'); internalSeek = false; eventBus.trigger(Events.PLAYBACK_PLAYING, { playingTime: getTime() }); } function _onPlaybackPaused() { logger.info('Native video element event: pause'); eventBus.trigger(Events.PLAYBACK_PAUSED, { ended: getEnded() }); } function _onPlaybackSeeking() { // Check if internal seeking to be ignored if (internalSeek) { return; } let seekTime = getTime(); // On some browsers/devices, in case of live streams, setting current time on video element fails when there is no buffered data at requested time // Then re-set seek target time and video element will be seeked afterwhile once data is buffered (see BufferContoller) if (!isNaN(seekTarget) &amp;&amp; seekTarget !== seekTime) { seekTime = seekTarget; } seekTarget = NaN; logger.info('Seeking to: ' + seekTime); startUpdatingWallclockTime(); eventBus.trigger(Events.PLAYBACK_SEEKING, { seekTime: seekTime, streamId: streamInfo.id }); } function _onPlaybackSeeked() { logger.info('Native video element event: seeked'); internalSeek = false; eventBus.trigger(Events.PLAYBACK_SEEKED); } function _onPlaybackTimeUpdated() { if (streamInfo) { eventBus.trigger(Events.PLAYBACK_TIME_UPDATED, { timeToEnd: getTimeToStreamEnd(), time: getTime(), streamId: streamInfo.id }); } } function _onPlaybackProgress() { eventBus.trigger(Events.PLAYBACK_PROGRESS, { streamId: streamInfo.id }); } function _onPlaybackRateChanged() { const rate = getPlaybackRate(); logger.info('Native video element event: ratechange: ', rate); eventBus.trigger(Events.PLAYBACK_RATE_CHANGED, { playbackRate: rate }); } function _onPlaybackMetaDataLoaded() { logger.info('Native video element event: loadedmetadata'); eventBus.trigger(Events.PLAYBACK_METADATA_LOADED); startUpdatingWallclockTime(); } function _onPlaybackLoadedData() { logger.info('Native video element event: loadeddata'); eventBus.trigger(Events.PLAYBACK_LOADED_DATA); } // Event to handle the native video element ended event function _onNativePlaybackEnded() { logger.info('Native video element event: ended'); pause(); stopUpdatingWallclockTime(); const streamInfo = streamController ? streamController.getActiveStreamInfo() : null; if (!streamInfo) return; eventBus.trigger(Events.PLAYBACK_ENDED, { 'isLast': streamInfo.isLast }); } function _onVolumeChanged() { eventBus.trigger(Events.PLAYBACK_VOLUME_CHANGED); } // Handle DASH PLAYBACK_ENDED event function _onPlaybackEnded(e) { if (wallclockTimeIntervalId &amp;&amp; e.isLast) { // PLAYBACK_ENDED was triggered elsewhere, react. logger.info('onPlaybackEnded -- PLAYBACK_ENDED but native video element didn\\'t fire ended'); const seekTime = e.seekTime ? e.seekTime : getStreamEndTime(); videoModel.setCurrentTime(seekTime); pause(); stopUpdatingWallclockTime(); } } function _onPlaybackError(event) { const target = event.target || event.srcElement; eventBus.trigger(Events.PLAYBACK_ERROR, { error: target.error }); } function _onWallclockTime() { eventBus.trigger(Events.WALLCLOCK_TIME_UPDATED, { isDynamic: isDynamic, time: new Date() }); // Updates playback time for paused dynamic streams // (video element doesn't call timeupdate when the playback is paused) if (getIsDynamic()) { streamController.addDVRMetric(); if (isPaused()) { _updateLivePlaybackTime(); } else { updateCurrentTime(); } } } function _updateLivePlaybackTime() { const now = Date.now(); if (!lastLivePlaybackTime || now &gt; lastLivePlaybackTime + LIVE_UPDATE_PLAYBACK_TIME_INTERVAL_MS) { lastLivePlaybackTime = now; _onPlaybackTimeUpdated(); } } /** * Returns the combined minimum buffer level of all StreamProcessors. If a filter list is provided the types specified in the filter list are excluded. * @param {array} filterList StreamProcessor types to exclude * @return {null} */ function getBufferLevel(filterList = null) { let bufferLevel = null; streamController.getActiveStreamProcessors().forEach(p =&gt; { if (!filterList || filterList.length === 0 || filterList.indexOf(p.getType()) === -1) { const bl = p.getBufferLevel(); if (bufferLevel === null) { bufferLevel = bl; } else { bufferLevel = Math.min(bufferLevel, bl); } } }); return bufferLevel; } /** * Returns the value of lowLatencyModeEnabled * @return {boolean} lowLatencyModeEnabled */ function getLowLatencyModeEnabled() { return lowLatencyModeEnabled } function _onFragmentLoadProgress(e) { // If using fetch and stream mode is not available, readjust live latency so it is 20% higher than segment duration if (e.stream === false &amp;&amp; lowLatencyModeEnabled &amp;&amp; !isNaN(e.request.duration)) { const minDelay = 1.2 * e.request.duration; if (minDelay &gt; liveDelay) { logger.warn('Browser does not support fetch API with StreamReader. Increasing live delay to be 20% higher than segment duration:', minDelay.toFixed(2)); liveDelay = minDelay; originalLiveDelay = minDelay; } } } function onPlaybackStalled(e) { eventBus.trigger(Events.PLAYBACK_STALLED, { e: e }); } function _onStreamInitializing(e) { _checkEnableLowLatency(e.mediaInfo); } /** * We enable low latency playback if for the current representation availabilityTimeComplete is set to false * @param e * @private */ function _onRepresentationSwitch(e) { const activeStreamInfo = streamController.getActiveStreamInfo(); if (!e || !activeStreamInfo || !e.currentRepresentation || !e.streamId || e.streamId !== activeStreamInfo.id || !e.mediaType || (e.mediaType !== Constants.VIDEO &amp;&amp; e.mediaType !== Constants.AUDIO)) { return; } availabilityTimeComplete = e.currentRepresentation.availabilityTimeComplete; lowLatencyModeEnabled = !availabilityTimeComplete; // If we enable low latency mode for the first time we also enable the catchup mechanism. This can be deactivated again for instance if the user seeks within the DVR window. We leave deactivation up to the application but also do not activate automatically again. if (lowLatencyModeEnabled &amp;&amp; !initialCatchupModeActivated) { initialCatchupModeActivated = true; } } function getInitialCatchupModeActivated() { return initialCatchupModeActivated; } /** * A new manifest has been loaded, updating is still in progress. * @private */ function _onManifestUpdated() { manifestUpdateInProgress = true; } /** * Manifest update was completed * @private */ function _onStreamsComposed() { manifestUpdateInProgress = false; } function _checkEnableLowLatency(mediaInfo) { if (mediaInfo &amp;&amp; mediaInfo.supplementalProperties &amp;&amp; mediaInfo.supplementalProperties[Constants.SUPPLEMENTAL_PROPERTY_DVB_LL_SCHEME] === 'true') { logger.debug('Low Latency critical SupplementalProperty set: Enabling low Latency'); lowLatencyModeEnabled = true; } } function addAllListeners() { videoModel.addEventListener('canplay', _onCanPlay); videoModel.addEventListener('canplaythrough', _onCanPlayThrough); videoModel.addEventListener('play', _onPlaybackStart); videoModel.addEventListener('waiting', _onPlaybackWaiting); videoModel.addEventListener('playing', _onPlaybackPlaying); videoModel.addEventListener('pause', _onPlaybackPaused); videoModel.addEventListener('error', _onPlaybackError); videoModel.addEventListener('seeking', _onPlaybackSeeking); videoModel.addEventListener('seeked', _onPlaybackSeeked); videoModel.addEventListener('timeupdate', _onPlaybackTimeUpdated); videoModel.addEventListener('progress', _onPlaybackProgress); videoModel.addEventListener('ratechange', _onPlaybackRateChanged); videoModel.addEventListener('loadedmetadata', _onPlaybackMetaDataLoaded); videoModel.addEventListener('loadeddata', _onPlaybackLoadedData); videoModel.addEventListener('stalled', onPlaybackStalled); videoModel.addEventListener('ended', _onNativePlaybackEnded); videoModel.addEventListener('volumechange', _onVolumeChanged); } function removeAllListeners() { videoModel.removeEventListener('canplay', _onCanPlay); videoModel.removeEventListener('canplaythrough', _onCanPlayThrough); videoModel.removeEventListener('play', _onPlaybackStart); videoModel.removeEventListener('waiting', _onPlaybackWaiting); videoModel.removeEventListener('playing', _onPlaybackPlaying); videoModel.removeEventListener('pause', _onPlaybackPaused); videoModel.removeEventListener('error', _onPlaybackError); videoModel.removeEventListener('seeking', _onPlaybackSeeking); videoModel.removeEventListener('seeked', _onPlaybackSeeked); videoModel.removeEventListener('timeupdate', _onPlaybackTimeUpdated); videoModel.removeEventListener('progress', _onPlaybackProgress); videoModel.removeEventListener('ratechange', _onPlaybackRateChanged); videoModel.removeEventListener('loadedmetadata', _onPlaybackMetaDataLoaded); videoModel.removeEventListener('loadeddata', _onPlaybackLoadedData); videoModel.removeEventListener('stalled', onPlaybackStalled); videoModel.removeEventListener('ended', _onNativePlaybackEnded); videoModel.removeEventListener('volumechange', _onVolumeChanged); } instance = { initialize, setConfig, getTimeToStreamEnd, getBufferLevel, getPlaybackStalled, getTime, getLowLatencyModeEnabled, getInitialCatchupModeActivated, getIsManifestUpdateInProgress, getPlaybackRate, getPlayedRanges, getEnded, getIsDynamic, getStreamController, computeAndSetLiveDelay, getLiveDelay, getOriginalLiveDelay, getCurrentLiveLatency, play, isPaused, isStalled, pause, isSeeking, getStreamEndTime, seek, seekToOriginalLive, seekToCurrentLive, reset, updateCurrentTime, getAvailabilityStartTime }; setup(); return instance; } PlaybackController.__dashjs_factory_name = 'PlaybackController'; export default FactoryMaker.getSingletonFactory(PlaybackController); × Search results Close "},"streaming_vo_metrics_PlayList.js.html":{"id":"streaming_vo_metrics_PlayList.js.html","title":"Source: streaming/vo/metrics/PlayList.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/PlayList.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @classdesc a PlayList from ISO23009-1 Annex D, this Object holds reference to the playback session information * @ignore */ class PlayList { /** * @class */ constructor() { /** * Timestamp of the user action that starts the playback stream... * @public */ this.start = null; /** * Presentation time at which playout was requested by the user... * @public */ this.mstart = null; /** * Type of user action which triggered playout * - New playout request (e.g. initial playout or seeking) * - Resume from pause * - Other user request (e.g. user-requested quality change) * - Start of a metrics collection stream (hence earlier entries in the play list not collected) * @public */ this.starttype = null; /** * List of streams of continuous rendering of decoded samples. * @public */ this.trace = []; } } /* Public Static Constants */ PlayList.INITIAL_PLAYOUT_START_REASON = 'initial_playout'; PlayList.SEEK_START_REASON = 'seek'; PlayList.RESUME_FROM_PAUSE_START_REASON = 'resume'; PlayList.METRICS_COLLECTION_START_REASON = 'metrics_collection_start'; /** * @classdesc a PlayList.Trace from ISO23009-1 Annex D * @ignore */ class PlayListTrace { /** * @class */ constructor() { /** * The value of the Representation@id of the Representation from which the samples were taken. * @type {string} * @public */ this.representationid = null; /** * If not present, this metrics concerns the Representation as a whole. * If present, subreplevel indicates the greatest value of any * Subrepresentation@level being rendered. * @type {number} * @public */ this.subreplevel = null; /** * The time at which the first sample was rendered * @type {number} * @public */ this.start = null; /** * The presentation time of the first sample rendered. * @type {number} * @public */ this.mstart = null; /** * The duration of the continuously presented samples (which is the same in real time and media time). \"Continuously presented\" means that the media clock continued to advance at the playout speed throughout the interval. NOTE: the spec does not call out the units, but all other durations etc are in ms, and we use ms too. * @type {number} * @public */ this.duration = null; /** * The playback speed relative to normal playback speed (i.e.normal forward playback speed is 1.0). * @type {number} * @public */ this.playbackspeed = null; /** * The reason why continuous presentation of this Representation was stopped. * representation switch * rebuffering * user request * end of Period * end of Stream * end of content * end of a metrics collection period * * @type {string} * @public */ this.stopreason = null; } } PlayListTrace.REPRESENTATION_SWITCH_STOP_REASON = 'representation_switch'; PlayListTrace.REBUFFERING_REASON = 'rebuffering'; PlayListTrace.USER_REQUEST_STOP_REASON = 'user_request'; PlayListTrace.END_OF_PERIOD_STOP_REASON = 'end_of_period'; PlayListTrace.END_OF_CONTENT_STOP_REASON = 'end_of_content'; PlayListTrace.METRICS_COLLECTION_STOP_REASON = 'metrics_collection_end'; PlayListTrace.FAILURE_STOP_REASON = 'failure'; export { PlayList, PlayListTrace }; × Search results Close "},"streaming_PreBufferSink.js.html":{"id":"streaming_PreBufferSink.js.html","title":"Source: streaming/PreBufferSink.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/PreBufferSink.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Debug from '../core/Debug'; import FactoryMaker from '../core/FactoryMaker'; /** * This is a sink that is used to temporarily hold onto media chunks before a video element is added. * The discharge() function is used to get the chunks out of the PreBuffer for adding to a real SourceBuffer. * * @class PreBufferSink * @ignore * @implements FragmentSink */ function PreBufferSink(onAppendedCallback) { const context = this.context; let instance, logger, outstandingInit; let chunks = []; let onAppended = onAppendedCallback; function setup() { logger = Debug(context).getInstance().getLogger(instance); } function reset() { chunks = []; outstandingInit = null; onAppended = null; } function append(chunk) { if (chunk.segmentType !== 'InitializationSegment') { //Init segments are stored in the initCache. chunks.push(chunk); chunks.sort(function (a, b) { return a.start - b.start; }); outstandingInit = null; } else {//We need to hold an init chunk for when a corresponding media segment is being downloaded when the discharge happens. outstandingInit = chunk; } logger.debug('PreBufferSink appended chunk s: ' + chunk.start + '; e: ' + chunk.end); if (onAppended) { onAppended({ chunk: chunk }); } } function remove(start, end) { chunks = chunks.filter(a =&gt; !((isNaN(end) || a.start &lt; end) &amp;&amp; (isNaN(start) || a.end &gt; start))); //The opposite of the getChunks predicate. } //Nothing async, nothing to abort. function abort() { } function getAllBufferRanges() { let ranges = []; for (let i = 0; i &lt; chunks.length; i++) { let chunk = chunks[i]; if (ranges.length === 0 || chunk.start &gt; ranges[ranges.length - 1].end) { ranges.push({start: chunk.start, end: chunk.end}); } else { ranges[ranges.length - 1].end = chunk.end; } } //Implements TimeRanges interface. So acts just like sourceBuffer.buffered. const timeranges = { start: function (n) { return ranges[n].start; }, end: function (n) { return ranges[n].end; } }; Object.defineProperty(timeranges, 'length', { get: function () { return ranges.length; } }); return timeranges; } function updateTimestampOffset() { // Nothing to do } function getBuffer() { return this; } /** * Return the all chunks in the buffer the lie between times start and end. * Because a chunk cannot be split, this returns the full chunk if any part of its time lies in the requested range. * Chunks are removed from the buffer when they are discharged. * @function PreBufferSink#discharge * @param {?Number} start The start time from which to discharge from the buffer. If NaN, it is regarded as unbounded. * @param {?Number} end The end time from which to discharge from the buffer. If NaN, it is regarded as unbounded. * @returns {Array} The set of chunks from the buffer within the time ranges. */ function discharge(start, end) { const result = getChunksAt(start, end); if (outstandingInit) { result.push(outstandingInit); outstandingInit = null; } remove(start, end); return result; } function getChunksAt(start, end) { return chunks.filter(a =&gt; ((isNaN(end) || a.start &lt; end) &amp;&amp; (isNaN(start) || a.end &gt; start))); } function waitForUpdateEnd(callback) { callback(); } instance = { getAllBufferRanges: getAllBufferRanges, append: append, remove: remove, abort: abort, discharge: discharge, reset: reset, updateTimestampOffset: updateTimestampOffset, waitForUpdateEnd: waitForUpdateEnd, getBuffer: getBuffer }; setup(); return instance; } PreBufferSink.__dashjs_factory_name = 'PreBufferSink'; const factory = FactoryMaker.getClassFactory(PreBufferSink); export default factory; × Search results Close "},"streaming_protection_vo_ProtectionData.js.html":{"id":"streaming_protection_vo_ProtectionData.js.html","title":"Source: streaming/protection/vo/ProtectionData.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/vo/ProtectionData.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @classdesc Data provided for a particular piece of content to customize license server URLs, * license server HTTP request headers, clearkeys, or other content-specific data * @ignore */ class ProtectionData { /** * @param {string|Object} serverURL a license server URL to use with this key system. * When specified as a string, a single URL will be used regardless of message type. * When specified as an object, the object will have property names for each message * type ({@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|message * types defined here)} with the corresponding property value being the URL to use for * messages of that type * @param {Object} httpRequestHeaders headers to add to the http request * @param {Object} clearkeys defines a set of clear keys that are available to * the key system. Object properties are base64-encoded keyIDs (with no padding). * Corresponding property values are keys, base64-encoded (no padding). * @param {number|undefined} priority priority order of the current ProtectionData * @class */ constructor(serverURL, httpRequestHeaders, clearkeys, priority) { this.serverURL = serverURL; this.httpRequestHeaders = httpRequestHeaders; this.clearkeys = clearkeys; this.priority = priority === undefined ? -1 : priority; } } /** * License server URL * * @instance * @type string|Object * @name ProtectionData.serverURL * @readonly * @memberof ProtectionData */ /** * HTTP Request Headers for use in license requests. Each property name * in the object is a header name with its corresponding header value being * the property value * * @instance * @type Object * @name ProtectionData.httpRequestsHeaders * @readonly * @memberof ProtectionData */ /** * ClearKey key-pairs that can be used to decrypt the content * * @instance * @type Object * @name ProtectionData.clearkeys * @readonly * @memberof ProtectionData */ /** * priority * * @instance * @type Object * @name ProtectionData.priority * @readonly * @memberof ProtectionData */ export default ProtectionData; × Search results Close "},"streaming_protection_errors_ProtectionErrors.js.html":{"id":"streaming_protection_errors_ProtectionErrors.js.html","title":"Source: streaming/protection/errors/ProtectionErrors.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/errors/ProtectionErrors.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import ErrorsBase from '../../../core/errors/ErrorsBase'; /** * @class */ class ProtectionErrors extends ErrorsBase { constructor() { super(); /** * Generid key Error code */ this.MEDIA_KEYERR_CODE = 100; /** * Error code returned by keyerror api for ProtectionModel_01b */ this.MEDIA_KEYERR_UNKNOWN_CODE = 101; /** * Error code returned by keyerror api for ProtectionModel_01b */ this.MEDIA_KEYERR_CLIENT_CODE = 102; /** * Error code returned by keyerror api for ProtectionModel_01b */ this.MEDIA_KEYERR_SERVICE_CODE = 103; /** * Error code returned by keyerror api for ProtectionModel_01b */ this.MEDIA_KEYERR_OUTPUT_CODE = 104; /** * Error code returned by keyerror api for ProtectionModel_01b */ this.MEDIA_KEYERR_HARDWARECHANGE_CODE = 105; /** * Error code returned by keyerror api for ProtectionModel_01b */ this.MEDIA_KEYERR_DOMAIN_CODE = 106; /** * Error code returned when an error occured in keymessage event for ProtectionModel_01b */ this.MEDIA_KEY_MESSAGE_ERROR_CODE = 107; /** * Error code returned when challenge is invalid in keymessage event (event triggered by CDM) */ this.MEDIA_KEY_MESSAGE_NO_CHALLENGE_ERROR_CODE = 108; /** * Error code returned when License server certificate has not been successfully updated */ this.SERVER_CERTIFICATE_UPDATED_ERROR_CODE = 109; /** * Error code returned when license validity has expired */ this.KEY_STATUS_CHANGED_EXPIRED_ERROR_CODE = 110; /** * Error code returned when no licenser url is defined */ this.MEDIA_KEY_MESSAGE_NO_LICENSE_SERVER_URL_ERROR_CODE = 111; /** * Error code returned when key system access is denied */ this.KEY_SYSTEM_ACCESS_DENIED_ERROR_CODE = 112; /** * Error code returned when key session has not been successfully created */ this.KEY_SESSION_CREATED_ERROR_CODE = 113; /** * Error code returned when license request failed after a keymessage event has been triggered */ this.MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE = 114; this.MEDIA_KEYERR_UNKNOWN_MESSAGE = 'An unspecified error occurred. This value is used for errors that don\\'t match any of the other codes.'; this.MEDIA_KEYERR_CLIENT_MESSAGE = 'The Key System could not be installed or updated.'; this.MEDIA_KEYERR_SERVICE_MESSAGE = 'The message passed into update indicated an error from the license service.'; this.MEDIA_KEYERR_OUTPUT_MESSAGE = 'There is no available output device with the required characteristics for the content protection system.'; this.MEDIA_KEYERR_HARDWARECHANGE_MESSAGE = 'A hardware configuration change caused a content protection error.'; this.MEDIA_KEYERR_DOMAIN_MESSAGE = 'An error occurred in a multi-device domain licensing configuration. The most common error is a failure to join the domain.'; this.MEDIA_KEY_MESSAGE_ERROR_MESSAGE = 'Multiple key sessions were creates with a user-agent that does not support sessionIDs!! Unpredictable behavior ahead!'; this.MEDIA_KEY_MESSAGE_NO_CHALLENGE_ERROR_MESSAGE = 'DRM: Empty key message from CDM'; this.SERVER_CERTIFICATE_UPDATED_ERROR_MESSAGE = 'Error updating server certificate -- '; this.KEY_STATUS_CHANGED_EXPIRED_ERROR_MESSAGE = 'DRM: KeyStatusChange error! -- License has expired'; this.MEDIA_KEY_MESSAGE_NO_LICENSE_SERVER_URL_ERROR_MESSAGE = 'DRM: No license server URL specified!'; this.KEY_SYSTEM_ACCESS_DENIED_ERROR_MESSAGE = 'DRM: KeySystem Access Denied! -- '; this.KEY_SESSION_CREATED_ERROR_MESSAGE = 'DRM: unable to create session! --'; this.MEDIA_KEY_MESSAGE_LICENSER_ERROR_MESSAGE = 'DRM: licenser error! --'; } } let protectionErrors = new ProtectionErrors(); export default protectionErrors; × Search results Close "},"streaming_protection_ProtectionEvents.js.html":{"id":"streaming_protection_ProtectionEvents.js.html","title":"Source: streaming/protection/ProtectionEvents.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/ProtectionEvents.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import EventsBase from '../../core/events/EventsBase'; /** * @class */ class ProtectionEvents extends EventsBase { /** * @description Public facing external events to be used when including protection package. * All public events will be aggregated into the MediaPlayerEvents Class and can be accessed * via MediaPlayer.events. public_ is the prefix that we use to move event names to MediaPlayerEvents. */ constructor () { super(); /** * Event ID for events delivered when the protection set receives * a key message from the CDM * * @ignore */ this.INTERNAL_KEY_MESSAGE = 'internalKeyMessage'; /** * Event ID for events delivered when the status of one decryption keys has changed * @ignore */ this.INTERNAL_KEY_STATUS_CHANGED = 'internalkeyStatusChanged'; /** * Event ID for events delivered when a new key has been added * * @constant * @deprecated The latest versions of the EME specification no longer * use this event. {@MediaPlayer.models.protectionModel.eventList.KEY_STATUSES_CHANGED} * is preferred. * @event ProtectionEvents#KEY_ADDED */ this.KEY_ADDED = 'public_keyAdded'; /** * Event ID for events delivered when an error is encountered by the CDM * while processing a license server response message * @event ProtectionEvents#KEY_ERROR */ this.KEY_ERROR = 'public_keyError'; /** * Event ID for events delivered when the protection set receives * a key message from the CDM * @event ProtectionEvents#KEY_MESSAGE */ this.KEY_MESSAGE = 'public_keyMessage'; /** * Event ID for events delivered when a key session close * process has completed * @event ProtectionEvents#KEY_SESSION_CLOSED */ this.KEY_SESSION_CLOSED = 'public_keySessionClosed'; /** * Event ID for events delivered when a new key sessions creation * process has completed * @event ProtectionEvents#KEY_SESSION_CREATED */ this.KEY_SESSION_CREATED = 'public_keySessionCreated'; /** * Event ID for events delivered when a key session removal * process has completed * @event ProtectionEvents#KEY_SESSION_REMOVED */ this.KEY_SESSION_REMOVED = 'public_keySessionRemoved'; /** * Event ID for events delivered when the status of one or more * decryption keys has changed * @event ProtectionEvents#KEY_STATUSES_CHANGED */ this.KEY_STATUSES_CHANGED = 'public_keyStatusesChanged'; /** * Event ID for events delivered when a key system access procedure * has completed * @ignore */ this.KEY_SYSTEM_ACCESS_COMPLETE = 'public_keySystemAccessComplete'; /** * Event ID for events delivered when a key system selection procedure * completes * @event ProtectionEvents#KEY_SYSTEM_SELECTED */ this.KEY_SYSTEM_SELECTED = 'public_keySystemSelected'; /** * Event ID for events delivered when a license request procedure * has completed * @event ProtectionEvents#LICENSE_REQUEST_COMPLETE */ this.LICENSE_REQUEST_COMPLETE = 'public_licenseRequestComplete'; /** * Sending a license rquest * @event ProtectionEvents#LICENSE_REQUEST_SENDING */ this.LICENSE_REQUEST_SENDING = 'public_licenseRequestSending'; /** * Event ID for needkey/encrypted events * @ignore */ this.NEED_KEY = 'needkey'; /** * Event ID for events delivered when the Protection system is detected and created. * @event ProtectionEvents#PROTECTION_CREATED */ this.PROTECTION_CREATED = 'public_protectioncreated'; /** * Event ID for events delivered when the Protection system is destroyed. * @event ProtectionEvents#PROTECTION_DESTROYED */ this.PROTECTION_DESTROYED = 'public_protectiondestroyed'; /** * Event ID for events delivered when a new server certificate has * been delivered to the CDM * @ignore */ this.SERVER_CERTIFICATE_UPDATED = 'serverCertificateUpdated'; /** * Event ID for events delivered when the process of shutting down * a protection set has completed * @ignore */ this.TEARDOWN_COMPLETE = 'protectionTeardownComplete'; /** * Event ID for events delivered when a HTMLMediaElement has been * associated with the protection set * @ignore */ this.VIDEO_ELEMENT_SELECTED = 'videoElementSelected'; /** * Triggered when the key session has been updated successfully * @ignore */ this.KEY_SESSION_UPDATED = 'public_keySessionUpdated'; } } let protectionEvents = new ProtectionEvents(); export default protectionEvents; × Search results Close "},"streaming_protection_models_ProtectionModel.js.html":{"id":"streaming_protection_models_ProtectionModel.js.html","title":"Source: streaming/protection/models/ProtectionModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/models/ProtectionModel.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Defines the public interface for all ProtectionModel implementations. * * ProtectionModel implementations provide access to particular versions * of the Encrypted Media Extensions (EME) APIs that have been implemented * in a user agent. Developers wishing to add support for a new EME version * found in a target user-agent should add a new instance of this interface * to the * * Applications should not need direct access to this object. All interactions with * the protection system should be performed with * {@link module:ProtectionController} * * @interface ProtectionModel * @ignore */ const ProtectionModel = function () { }; /** * Returns an array of all initialization data currently used by * active sessions. * @function * @instance * @name getAllInitData * @memberof ProtectionModel * @returns {Array.&lt;ArrayBuffer&gt;} an array of initialization data buffers */ /** * Determine if the user-agent supports one of the given key systems and * content type configurations. Sends ENAME_KEY_SYSTEM_ACCESS_COMPLETE event * with a KeySystemAccess object as event data * * @function * @instance * @name requestKeySystemAccess * @memberof ProtectionModel * * @param {Array.&lt;Object&gt;} ksConfigurations array of desired key system * configurations in priority order (highest priority first) * @param {MediaPlayer.dependencies.protection.KeySystem} ksConfigurations.ks * the key system * @param {MediaPlayer.vo.protection.KeySystemConfiguration[]} ksConfigurations.configs * array of acceptable key system configurations * for this key system in priority order (highest priority first) */ /** * Selects the key system to use for all future operations on this * ProtectionModel. Sends ENAME_KEY_SYSTEM_SELECTED with no data * * @function * @instance * @name selectKeySystem * @memberof ProtectionModel * @param keySystemAccess {MediaPlayer.vo.protection.KeySystemAccess} the key * system access token representing a supported key system */ /** * Associate this protection model with a HTMLMediaElement * * @function * @instance * @name setMediaElement * @memberof ProtectionModel * @param mediaElement {HTMLMediaElement} the media element to * which we should associate this protection model and all current * key sessions */ /** * Creates a new key session using the given initData and type. Sends * KEY_SESSION_CREATED event with MediaPlayer.vo.protection.SessionToken * as data. * * @function * @instance * @name createKeySession * @memberof ProtectionModel * @param {ArrayBuffer} initData PSSH box for the currently selected * key system. * @param {ProtectionData} protData Protection data for the currently selected * key system. * @param {string} sessionType the desired session type. One of \"temporary\", * \"persistent-license\", \"persistent-release-message\". CDM implementations * are not required to support anything except \"temporary\" */ /** * Update the given key session with a key (or any other message * intended for the CDM) * * @function * @instance * @name updateKeySession * @memberof ProtectionModel * @param {MediaPlayer.vo.protection.SessionToken} sessionToken the session * token * @param {ArrayBuffer} message the message that should be delivered to the CDM * for this session */ /** * Loads the persisted key session data associated with the given sessionId * into a new session. Sends KEY_SESSION_CREATED event with * {@MediaPlayer.vo.protection.SessionToken} as data. * * @function * @instance * @name loadKeySession * @memberof ProtectionModel * @param {string} sessionID the session ID corresponding to the persisted * session data to be loaded * @param {ArrayBuffer} the corresponding initData PSSH box for the currently * selected key system. */ /** * Removes any persisted key session data associated with the given session. * Also closes the session. Sends KEY_SESSION_REMOVED and * ENAME_KEY_SESSION_CLOSED with sessionID as data * * @function * @instance * @name removeKeySession * @memberof ProtectionModel * @param {SessionToken} sessionToken the session * token */ /** * Close the given session and release all associated keys. Following * this call, the sessionToken becomes invalid. Sends KEY_SESSION_CLOSED * with sessionID as data * * @function * @instance * @name closeKeySession * @memberof ProtectionModel * @param sessionToken the session token */ /** * Sets the certificate to be used by the CDM for encrypting messages * * @function * @instance * @name setServerCertificate * @memberof ProtectionModel * @param {ArrayBuffer} serverCertificate */ /** * Currently selected key system. Will be null or undefined if no key * system has yet been selected * * @instance * @name keySystem * @memberof ProtectionModel * @readonly * @type MediaPlayer.dependencies.protection.KeySystem */ export default ProtectionModel; × Search results Close "},"streaming_protection_models_ProtectionModel_01b.js.html":{"id":"streaming_protection_models_ProtectionModel_01b.js.html","title":"Source: streaming/protection/models/ProtectionModel_01b.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/models/ProtectionModel_01b.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Initial implementation of EME * * Implemented by Google Chrome prior to v36 * * @implements ProtectionModel * @class */ import ProtectionKeyController from '../controllers/ProtectionKeyController'; import NeedKey from '../vo/NeedKey'; import DashJSError from '../../vo/DashJSError'; import KeyMessage from '../vo/KeyMessage'; import KeySystemConfiguration from '../vo/KeySystemConfiguration'; import KeySystemAccess from '../vo/KeySystemAccess'; import ProtectionErrors from '../errors/ProtectionErrors'; function ProtectionModel_01b(config) { config = config || {}; const context = this.context; const eventBus = config.eventBus;//Need to pass in here so we can use same instance since this is optional module const events = config.events; const debug = config.debug; const api = config.api; const errHandler = config.errHandler; let instance, logger, videoElement, keySystem, protectionKeyController, // With this version of the EME APIs, sessionIds are not assigned to // sessions until the first key message is received. We are assuming // that in the case of multiple sessions, key messages will be received // in the order that generateKeyRequest() is called. // Holding spot for newly-created sessions until we determine whether or // not the CDM supports sessionIds pendingSessions, // List of sessions that have been initialized. Only the first position will // be used in the case that the CDM does not support sessionIds sessions, // Not all CDMs support the notion of sessionIds. Without sessionIds // there is no way for us to differentiate between sessions, therefore // we must only allow a single session. Once we receive the first key // message we can set this flag to determine if more sessions are allowed moreSessionsAllowed, // This is our main event handler for all desired HTMLMediaElement events // related to EME. These events are translated into our API-independent // versions of the same events eventHandler; function setup() { logger = debug.getLogger(instance); videoElement = null; keySystem = null; pendingSessions = []; sessions = []; protectionKeyController = ProtectionKeyController(context).getInstance(); eventHandler = createEventHandler(); } function reset() { if (videoElement) { removeEventListeners(); } for (let i = 0; i &lt; sessions.length; i++) { closeKeySession(sessions[i]); } eventBus.trigger(events.TEARDOWN_COMPLETE); } function getAllInitData() { const retVal = []; for (let i = 0; i &lt; pendingSessions.length; i++) { retVal.push(pendingSessions[i].initData); } for (let i = 0; i &lt; sessions.length; i++) { retVal.push(sessions[i].initData); } return retVal; } function getSessions() { return sessions.concat(pendingSessions); } function requestKeySystemAccess(ksConfigurations) { return new Promise((resolve, reject) =&gt; { let ve = videoElement; if (!ve) { // Must have a video element to do this capability tests ve = document.createElement('video'); } // Try key systems in order, first one with supported key system configuration // is used let found = false; for (let ksIdx = 0; ksIdx &lt; ksConfigurations.length; ksIdx++) { const systemString = ksConfigurations[ksIdx].ks.systemString; const configs = ksConfigurations[ksIdx].configs; let supportedAudio = null; let supportedVideo = null; // Try key system configs in order, first one with supported audio/video // is used for (let configIdx = 0; configIdx &lt; configs.length; configIdx++) { //let audios = configs[configIdx].audioCapabilities; const videos = configs[configIdx].videoCapabilities; // Look for supported video container/codecs if (videos &amp;&amp; videos.length !== 0) { supportedVideo = []; // Indicates that we have a requested video config for (let videoIdx = 0; videoIdx &lt; videos.length; videoIdx++) { if (ve.canPlayType(videos[videoIdx].contentType, systemString) !== '') { supportedVideo.push(videos[videoIdx]); } } } // No supported audio or video in this configuration OR we have // requested audio or video configuration that is not supported if ((!supportedAudio &amp;&amp; !supportedVideo) || (supportedAudio &amp;&amp; supportedAudio.length === 0) || (supportedVideo &amp;&amp; supportedVideo.length === 0)) { continue; } // This configuration is supported found = true; const ksConfig = new KeySystemConfiguration(supportedAudio, supportedVideo); const ks = protectionKeyController.getKeySystemBySystemString(systemString); const keySystemAccess = new KeySystemAccess(ks, ksConfig) eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { data: keySystemAccess }); resolve({ data: keySystemAccess }); break; } } if (!found) { const errorMessage = 'Key system access denied! -- No valid audio/video content configurations detected!'; eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { error: errorMessage }); reject({ error: errorMessage }); } }) } function selectKeySystem(keySystemAccess) { keySystem = keySystemAccess.keySystem; return Promise.resolve(keySystem); } function setMediaElement(mediaElement) { if (videoElement === mediaElement) { return; } // Replacing the previous element if (videoElement) { removeEventListeners(); // Close any open sessions - avoids memory leak on LG webOS 2016/2017 TVs for (var i = 0; i &lt; sessions.length; i++) { closeKeySession(sessions[i]); } sessions = []; } videoElement = mediaElement; // Only if we are not detaching from the existing element if (videoElement) { videoElement.addEventListener(api.keyerror, eventHandler); videoElement.addEventListener(api.needkey, eventHandler); videoElement.addEventListener(api.keymessage, eventHandler); videoElement.addEventListener(api.keyadded, eventHandler); eventBus.trigger(events.VIDEO_ELEMENT_SELECTED); } } function createKeySession(ksInfo) { if (!keySystem) { throw new Error('Can not create sessions until you have selected a key system'); } // Determine if creating a new session is allowed if (moreSessionsAllowed || sessions.length === 0) { const newSession = { // Implements SessionToken sessionId: null, keyId: ksInfo.keyId, initData: ksInfo.initData, getKeyId: function () { return this.keyId; }, getSessionId: function () { return this.sessionId; }, getExpirationTime: function () { return NaN; }, getSessionType: function () { return 'temporary'; } }; pendingSessions.push(newSession); // Send our request to the CDM videoElement[api.generateKeyRequest](keySystem.systemString, new Uint8Array(ksInfo.initData)); return newSession; } else { throw new Error('Multiple sessions not allowed!'); } } function updateKeySession(sessionToken, message) { const sessionId = sessionToken.sessionId; if (!protectionKeyController.isClearKey(keySystem)) { // Send our request to the CDM videoElement[api.addKey](keySystem.systemString, new Uint8Array(message), new Uint8Array(sessionToken.initData), sessionId); } else { // For clearkey, message is a ClearKeyKeySet for (let i = 0; i &lt; message.keyPairs.length; i++) { videoElement[api.addKey](keySystem.systemString, message.keyPairs[i].key, message.keyPairs[i].keyID, sessionId); } } eventBus.trigger(events.KEY_SESSION_UPDATED); } function closeKeySession(sessionToken) { // Send our request to the CDM try { videoElement[api.cancelKeyRequest](keySystem.systemString, sessionToken.sessionId); } catch (error) { eventBus.trigger(events.KEY_SESSION_CLOSED, { data: null, error: 'Error closing session (' + sessionToken.sessionId + ') ' + error.message }); } } function setServerCertificate(/*serverCertificate*/) { /* Not supported */ } function loadKeySession(/*ksInfo*/) { /* Not supported */ } function removeKeySession(/*sessionToken*/) { /* Not supported */ } function createEventHandler() { return { handleEvent: function (event) { let sessionToken = null; switch (event.type) { case api.needkey: let initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData; eventBus.trigger(events.NEED_KEY, { key: new NeedKey(initData, 'cenc') }); break; case api.keyerror: sessionToken = findSessionByID(sessions, event.sessionId); if (!sessionToken) { sessionToken = findSessionByID(pendingSessions, event.sessionId); } if (sessionToken) { let code = ProtectionErrors.MEDIA_KEYERR_CODE; let msg = ''; switch (event.errorCode.code) { case 1: code = ProtectionErrors.MEDIA_KEYERR_UNKNOWN_CODE; msg += 'MEDIA_KEYERR_UNKNOWN - ' + ProtectionErrors.MEDIA_KEYERR_UNKNOWN_MESSAGE; break; case 2: code = ProtectionErrors.MEDIA_KEYERR_CLIENT_CODE; msg += 'MEDIA_KEYERR_CLIENT - ' + ProtectionErrors.MEDIA_KEYERR_CLIENT_MESSAGE; break; case 3: code = ProtectionErrors.MEDIA_KEYERR_SERVICE_CODE; msg += 'MEDIA_KEYERR_SERVICE - ' + ProtectionErrors.MEDIA_KEYERR_SERVICE_MESSAGE; break; case 4: code = ProtectionErrors.MEDIA_KEYERR_OUTPUT_CODE; msg += 'MEDIA_KEYERR_OUTPUT - ' + ProtectionErrors.MEDIA_KEYERR_OUTPUT_MESSAGE; break; case 5: code = ProtectionErrors.MEDIA_KEYERR_HARDWARECHANGE_CODE; msg += 'MEDIA_KEYERR_HARDWARECHANGE - ' + ProtectionErrors.MEDIA_KEYERR_HARDWARECHANGE_MESSAGE; break; case 6: code = ProtectionErrors.MEDIA_KEYERR_DOMAIN_CODE; msg += 'MEDIA_KEYERR_DOMAIN - ' + ProtectionErrors.MEDIA_KEYERR_DOMAIN_MESSAGE; break; } msg += ' System Code = ' + event.systemCode; // TODO: Build error string based on key error eventBus.trigger(events.KEY_ERROR, { error: new DashJSError(code, msg, sessionToken) }); } else { logger.error('No session token found for key error'); } break; case api.keyadded: sessionToken = findSessionByID(sessions, event.sessionId); if (!sessionToken) { sessionToken = findSessionByID(pendingSessions, event.sessionId); } if (sessionToken) { logger.debug('DRM: Key added.'); eventBus.trigger(events.KEY_ADDED, { data: sessionToken });//TODO not sure anything is using sessionToken? why there? } else { logger.debug('No session token found for key added'); } break; case api.keymessage: // If this CDM does not support session IDs, we will be limited // to a single session moreSessionsAllowed = (event.sessionId !== null) &amp;&amp; (event.sessionId !== undefined); // SessionIDs supported if (moreSessionsAllowed) { // Attempt to find an uninitialized token with this sessionId sessionToken = findSessionByID(sessions, event.sessionId); if (!sessionToken &amp;&amp; pendingSessions.length &gt; 0) { // This is the first message for our latest session, so set the // sessionId and add it to our list sessionToken = pendingSessions.shift(); sessions.push(sessionToken); sessionToken.sessionId = event.sessionId; eventBus.trigger(events.KEY_SESSION_CREATED, { data: sessionToken }); } } else if (pendingSessions.length &gt; 0) { // SessionIDs not supported sessionToken = pendingSessions.shift(); sessions.push(sessionToken); if (pendingSessions.length !== 0) { errHandler.error(new DashJSError(ProtectionErrors.MEDIA_KEY_MESSAGE_ERROR_CODE, ProtectionErrors.MEDIA_KEY_MESSAGE_ERROR_MESSAGE)); } } if (sessionToken) { let message = ArrayBuffer.isView(event.message) ? event.message.buffer : event.message; // For ClearKey, the spec mandates that you pass this message to the // addKey method, so we always save it to the token since there is no // way to tell which key system is in use sessionToken.keyMessage = message; eventBus.trigger(events.INTERNAL_KEY_MESSAGE, { data: new KeyMessage(sessionToken, message, event.defaultURL) }); } else { logger.warn('No session token found for key message'); } break; } } }; } /** * Helper function to retrieve the stored session token based on a given * sessionId value * * @param {Array} sessionArray - the array of sessions to search * @param {*} sessionId - the sessionId to search for * @returns {*} the session token with the given sessionId */ function findSessionByID(sessionArray, sessionId) { if (!sessionId || !sessionArray) { return null; } else { const len = sessionArray.length; for (let i = 0; i &lt; len; i++) { if (sessionArray[i].sessionId == sessionId) { return sessionArray[i]; } } return null; } } function removeEventListeners() { videoElement.removeEventListener(api.keyerror, eventHandler); videoElement.removeEventListener(api.needkey, eventHandler); videoElement.removeEventListener(api.keymessage, eventHandler); videoElement.removeEventListener(api.keyadded, eventHandler); } instance = { getAllInitData, getSessions, requestKeySystemAccess, selectKeySystem, setMediaElement, createKeySession, updateKeySession, closeKeySession, setServerCertificate, loadKeySession, removeKeySession, stop: reset, reset }; setup(); return instance; } ProtectionModel_01b.__dashjs_factory_name = 'ProtectionModel_01b'; export default dashjs.FactoryMaker.getClassFactory(ProtectionModel_01b); /* jshint ignore:line */ × Search results Close "},"streaming_protection_models_ProtectionModel_3Feb2014.js.html":{"id":"streaming_protection_models_ProtectionModel_3Feb2014.js.html","title":"Source: streaming/protection/models/ProtectionModel_3Feb2014.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/models/ProtectionModel_3Feb2014.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Implementation of the EME APIs as of the 3 Feb 2014 state of the specification. * * Implemented by Internet Explorer 11 (Windows 8.1) * * @implements ProtectionModel * @class */ import ProtectionKeyController from '../controllers/ProtectionKeyController'; import NeedKey from '../vo/NeedKey'; import DashJSError from '../../vo/DashJSError'; import ProtectionErrors from '../errors/ProtectionErrors'; import KeyMessage from '../vo/KeyMessage'; import KeySystemConfiguration from '../vo/KeySystemConfiguration'; import KeySystemAccess from '../vo/KeySystemAccess'; function ProtectionModel_3Feb2014(config) { config = config || {}; const context = this.context; const eventBus = config.eventBus;//Need to pass in here so we can use same instance since this is optional module const events = config.events; const debug = config.debug; const api = config.api; let instance, logger, videoElement, keySystem, mediaKeys, keySystemAccess, sessions, eventHandler, protectionKeyController; function setup() { logger = debug.getLogger(instance); videoElement = null; keySystem = null; mediaKeys = null; keySystemAccess = null; sessions = []; protectionKeyController = ProtectionKeyController(context).getInstance(); eventHandler = createEventHandler(); } function reset() { try { for (let i = 0; i &lt; sessions.length; i++) { closeKeySession(sessions[i]); } if (videoElement) { videoElement.removeEventListener(api.needkey, eventHandler); } eventBus.trigger(events.TEARDOWN_COMPLETE); } catch (error) { eventBus.trigger(events.TEARDOWN_COMPLETE, { error: 'Error tearing down key sessions and MediaKeys! -- ' + error.message }); } } function getAllInitData() { const retVal = []; for (let i = 0; i &lt; sessions.length; i++) { retVal.push(sessions[i].initData); } return retVal; } function getSessions() { return sessions; } function requestKeySystemAccess(ksConfigurations) { return new Promise((resolve, reject) =&gt; { // Try key systems in order, first one with supported key system configuration // is used let found = false; for (let ksIdx = 0; ksIdx &lt; ksConfigurations.length; ksIdx++) { const systemString = ksConfigurations[ksIdx].ks.systemString; const configs = ksConfigurations[ksIdx].configs; let supportedAudio = null; let supportedVideo = null; // Try key system configs in order, first one with supported audio/video // is used for (let configIdx = 0; configIdx &lt; configs.length; configIdx++) { const audios = configs[configIdx].audioCapabilities; const videos = configs[configIdx].videoCapabilities; // Look for supported audio container/codecs if (audios &amp;&amp; audios.length !== 0) { supportedAudio = []; // Indicates that we have a requested audio config for (let audioIdx = 0; audioIdx &lt; audios.length; audioIdx++) { if (window[api.MediaKeys].isTypeSupported(systemString, audios[audioIdx].contentType)) { supportedAudio.push(audios[audioIdx]); } } } // Look for supported video container/codecs if (videos &amp;&amp; videos.length !== 0) { supportedVideo = []; // Indicates that we have a requested video config for (let videoIdx = 0; videoIdx &lt; videos.length; videoIdx++) { if (window[api.MediaKeys].isTypeSupported(systemString, videos[videoIdx].contentType)) { supportedVideo.push(videos[videoIdx]); } } } // No supported audio or video in this configuration OR we have // requested audio or video configuration that is not supported if ((!supportedAudio &amp;&amp; !supportedVideo) || (supportedAudio &amp;&amp; supportedAudio.length === 0) || (supportedVideo &amp;&amp; supportedVideo.length === 0)) { continue; } // This configuration is supported found = true; const ksConfig = new KeySystemConfiguration(supportedAudio, supportedVideo); const ks = protectionKeyController.getKeySystemBySystemString(systemString); const keySystemAccess = new KeySystemAccess(ks, ksConfig); eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { data: keySystemAccess }); resolve({ data: keySystemAccess }); break; } } if (!found) { const errorMessage = 'Key system access denied! -- No valid audio/video content configurations detected!'; eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { error: errorMessage }); reject({ error: errorMessage }); } }) } function selectKeySystem(ksAccess) { return new Promise((resolve, reject) =&gt; { try { mediaKeys = ksAccess.mediaKeys = new window[api.MediaKeys](ksAccess.keySystem.systemString); keySystem = ksAccess.keySystem; keySystemAccess = ksAccess; if (videoElement) { setMediaKeys(); } resolve(keySystem); } catch (error) { reject({ error: 'Error selecting keys system (' + keySystem.systemString + ')! Could not create MediaKeys -- TODO' }); } }) } function setMediaElement(mediaElement) { if (videoElement === mediaElement) return; // Replacing the previous element if (videoElement) { videoElement.removeEventListener(api.needkey, eventHandler); } videoElement = mediaElement; // Only if we are not detaching from the existing element if (videoElement) { videoElement.addEventListener(api.needkey, eventHandler); if (mediaKeys) { setMediaKeys(); } } } function createKeySession(ksInfo) { if (!keySystem || !mediaKeys || !keySystemAccess) { throw new Error('Can not create sessions until you have selected a key system'); } // Use the first video capability for the contentType. // TODO: Not sure if there is a way to concatenate all capability data into a RFC6386-compatible format // If player is trying to playback Audio only stream - don't error out. let capabilities = null; if (keySystemAccess.ksConfiguration.videoCapabilities &amp;&amp; keySystemAccess.ksConfiguration.videoCapabilities.length &gt; 0) { capabilities = keySystemAccess.ksConfiguration.videoCapabilities[0]; } if (capabilities === null &amp;&amp; keySystemAccess.ksConfiguration.audioCapabilities &amp;&amp; keySystemAccess.ksConfiguration.audioCapabilities.length &gt; 0) { capabilities = keySystemAccess.ksConfiguration.audioCapabilities[0]; } if (capabilities === null) { throw new Error('Can not create sessions for unknown content types.'); } const contentType = capabilities.contentType; const session = mediaKeys.createSession(contentType, new Uint8Array(ksInfo.initData), ksInfo.cdmData ? new Uint8Array(ksInfo.cdmData) : null); const sessionToken = createSessionToken(session, ksInfo); // Add all event listeners session.addEventListener(api.error, sessionToken); session.addEventListener(api.message, sessionToken); session.addEventListener(api.ready, sessionToken); session.addEventListener(api.close, sessionToken); // Add to our session list sessions.push(sessionToken); logger.debug('DRM: Session created. SessionID = ' + sessionToken.getSessionId()); eventBus.trigger(events.KEY_SESSION_CREATED, { data: sessionToken }); } function updateKeySession(sessionToken, message) { const session = sessionToken.session; if (!protectionKeyController.isClearKey(keySystem)) { // Send our request to the key session session.update(new Uint8Array(message)); } else { // For clearkey, message is a ClearKeyKeySet session.update(new Uint8Array(message.toJWK())); } eventBus.trigger(events.KEY_SESSION_UPDATED); } /** * Close the given session and release all associated keys. Following * this call, the sessionToken becomes invalid * * @param {Object} sessionToken - the session token */ function closeKeySession(sessionToken) { const session = sessionToken.session; // Remove event listeners session.removeEventListener(api.error, sessionToken); session.removeEventListener(api.message, sessionToken); session.removeEventListener(api.ready, sessionToken); session.removeEventListener(api.close, sessionToken); // Remove from our session list for (let i = 0; i &lt; sessions.length; i++) { if (sessions[i] === sessionToken) { sessions.splice(i, 1); break; } } // Send our request to the key session session[api.release](); } function setServerCertificate(/*serverCertificate*/) { /* Not supported */ } function loadKeySession(/*ksInfo*/) { /* Not supported */ } function removeKeySession(/*sessionToken*/) { /* Not supported */ } function createEventHandler() { return { handleEvent: function (event) { switch (event.type) { case api.needkey: if (event.initData) { const initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData; eventBus.trigger(events.NEED_KEY, { key: new NeedKey(initData, 'cenc') }); } break; } } }; } // IE11 does not let you set MediaKeys until it has entered a certain // readyState, so we need this logic to ensure we don't set the keys // too early function setMediaKeys() { let boundDoSetKeys = null; const doSetKeys = function () { videoElement.removeEventListener('loadedmetadata', boundDoSetKeys); videoElement[api.setMediaKeys](mediaKeys); eventBus.trigger(events.VIDEO_ELEMENT_SELECTED); }; if (videoElement.readyState &gt;= 1) { doSetKeys(); } else { boundDoSetKeys = doSetKeys.bind(this); videoElement.addEventListener('loadedmetadata', boundDoSetKeys); } } // Function to create our session token objects which manage the EME // MediaKeySession and session-specific event handler function createSessionToken(keySession, ksInfo) { return { // Implements SessionToken session: keySession, keyId: ksInfo.keyId, initData: ksInfo.initData, getKeyId: function () { return this.keyId; }, getSessionId: function () { return this.session.sessionId; }, getExpirationTime: function () { return NaN; }, getSessionType: function () { return 'temporary'; }, // This is our main event handler for all desired MediaKeySession events // These events are translated into our API-independent versions of the // same events handleEvent: function (event) { switch (event.type) { case api.error: let errorStr = 'KeyError'; // TODO: Make better string from event eventBus.trigger(events.KEY_ERROR, { error: new DashJSError(ProtectionErrors.MEDIA_KEYERR_CODE, errorStr, this) }); break; case api.message: let message = ArrayBuffer.isView(event.message) ? event.message.buffer : event.message; eventBus.trigger(events.INTERNAL_KEY_MESSAGE, { data: new KeyMessage(this, message, event.destinationURL) }); break; case api.ready: logger.debug('DRM: Key added.'); eventBus.trigger(events.KEY_ADDED); break; case api.close: logger.debug('DRM: Session closed. SessionID = ' + this.getSessionId()); eventBus.trigger(events.KEY_SESSION_CLOSED, { data: this.getSessionId() }); break; } } }; } instance = { getAllInitData, getSessions, requestKeySystemAccess, selectKeySystem, setMediaElement, createKeySession, updateKeySession, closeKeySession, setServerCertificate, loadKeySession, removeKeySession, stop: reset, reset }; setup(); return instance; } ProtectionModel_3Feb2014.__dashjs_factory_name = 'ProtectionModel_3Feb2014'; export default dashjs.FactoryMaker.getClassFactory(ProtectionModel_3Feb2014); /* jshint ignore:line */ × Search results Close "},"streaming_protection_models_ProtectionModel_21Jan2015.js.html":{"id":"streaming_protection_models_ProtectionModel_21Jan2015.js.html","title":"Source: streaming/protection/models/ProtectionModel_21Jan2015.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/models/ProtectionModel_21Jan2015.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Most recent EME implementation * * Implemented by Google Chrome v36+ (Windows, OSX, Linux) * * @implements ProtectionModel * @class */ import ProtectionKeyController from '../controllers/ProtectionKeyController'; import NeedKey from '../vo/NeedKey'; import ProtectionErrors from '../errors/ProtectionErrors'; import DashJSError from '../../vo/DashJSError'; import KeyMessage from '../vo/KeyMessage'; import KeySystemAccess from '../vo/KeySystemAccess'; import ProtectionConstants from '../../constants/ProtectionConstants'; const SYSTEM_STRING_PRIORITY = {}; SYSTEM_STRING_PRIORITY[ProtectionConstants.PLAYREADY_KEYSTEM_STRING] = [ProtectionConstants.PLAYREADY_KEYSTEM_STRING, ProtectionConstants.PLAYREADY_RECOMMENDATION_KEYSTEM_STRING]; SYSTEM_STRING_PRIORITY[ProtectionConstants.WIDEVINE_KEYSTEM_STRING] = [ProtectionConstants.WIDEVINE_KEYSTEM_STRING]; SYSTEM_STRING_PRIORITY[ProtectionConstants.CLEARKEY_KEYSTEM_STRING] = [ProtectionConstants.CLEARKEY_KEYSTEM_STRING]; function ProtectionModel_21Jan2015(config) { config = config || {}; const context = this.context; const eventBus = config.eventBus;//Need to pass in here so we can use same instance since this is optional module const events = config.events; const debug = config.debug; let instance, logger, keySystem, videoElement, mediaKeys, sessions, eventHandler, protectionKeyController; function setup() { logger = debug.getLogger(instance); keySystem = null; videoElement = null; mediaKeys = null; sessions = []; protectionKeyController = ProtectionKeyController(context).getInstance(); eventHandler = createEventHandler(); } function reset() { const numSessions = sessions.length; let session; if (numSessions !== 0) { // Called when we are done closing a session. Success or fail const done = function (session) { removeSession(session); if (sessions.length === 0) { if (videoElement) { videoElement.removeEventListener('encrypted', eventHandler); videoElement.setMediaKeys(null).then(function () { eventBus.trigger(events.TEARDOWN_COMPLETE); }); } else { eventBus.trigger(events.TEARDOWN_COMPLETE); } } }; for (let i = 0; i &lt; numSessions; i++) { session = sessions[i]; (function (s) { // Override closed promise resolver session.session.closed.then(function () { done(s); }); // Close the session and handle errors, otherwise promise // resolver above will be called _closeKeySessionInternal(session).catch(function () { done(s); }); })(session); } } else { eventBus.trigger(events.TEARDOWN_COMPLETE); } } function stop() { // Close and remove not usable sessions let session; for (let i = 0; i &lt; sessions.length; i++) { session = sessions[i]; if (!session.getUsable()) { _closeKeySessionInternal(session).catch(function () { removeSession(session); }); } } } function getAllInitData() { const retVal = []; for (let i = 0; i &lt; sessions.length; i++) { if (sessions[i].initData) { retVal.push(sessions[i].initData); } } return retVal; } function getSessions() { return sessions; } function requestKeySystemAccess(ksConfigurations) { return new Promise((resolve, reject) =&gt; { _requestKeySystemAccessInternal(ksConfigurations, 0, resolve, reject); }) } /** * Initializes access to a key system. Once we found a valid configuration we get a mediaKeySystemAccess object * @param ksConfigurations * @param idx * @param resolve * @param reject * @private */ function _requestKeySystemAccessInternal(ksConfigurations, idx, resolve, reject) { // In case requestMediaKeySystemAccess is not available we can not proceed and dispatch an error if (navigator.requestMediaKeySystemAccess === undefined || typeof navigator.requestMediaKeySystemAccess !== 'function') { const msg = 'Insecure origins are not allowed'; eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, {error: msg}); reject({error: msg}); return; } // If a systemStringPriority is defined by the application we use these values. Otherwise we use the default system string // This is useful for DRM systems such as Playready for which multiple system strings are possible for instance com.microsoft.playready and com.microsoft.playready.recommendation const protDataSystemStringPriority = ksConfigurations[idx].protData &amp;&amp; ksConfigurations[idx].protData.systemStringPriority ? ksConfigurations[idx].protData.systemStringPriority : null; const configs = ksConfigurations[idx].configs; const currentKeySystem = ksConfigurations[idx].ks; let systemString = currentKeySystem.systemString; // Use the default values in case no values are provided by the application const systemStringsToApply = protDataSystemStringPriority ? protDataSystemStringPriority : SYSTEM_STRING_PRIORITY[systemString] ? SYSTEM_STRING_PRIORITY[systemString] : [systemString]; // Check all the available system strings and the available configurations for support _checkAccessForKeySystem(systemStringsToApply, configs) .then((mediaKeySystemAccess) =&gt; { const configuration = (typeof mediaKeySystemAccess.getConfiguration === 'function') ? mediaKeySystemAccess.getConfiguration() : null; const keySystemAccess = new KeySystemAccess(currentKeySystem, configuration); keySystemAccess.mksa = mediaKeySystemAccess; eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, {data: keySystemAccess}); resolve({data: keySystemAccess}); }) .catch((e) =&gt; { if (idx + 1 &lt; ksConfigurations.length) { _requestKeySystemAccessInternal(ksConfigurations, idx + 1, resolve, reject); } else { const errorMessage = 'Key system access denied! '; eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, {error: errorMessage + e.message}); reject({error: errorMessage + e.message}); } }) } /** * For a specific key system: Iterate over the possible system strings and resolve once a valid configuration was found * @param {array} systemStringsToApply * @param {object} configs * @return {Promise} * @private */ function _checkAccessForKeySystem(systemStringsToApply, configs) { return new Promise((resolve, reject) =&gt; { _checkAccessForSystemStrings(systemStringsToApply, configs, 0, resolve, reject); }) } /** * Recursively iterate over the possible system strings until a supported configuration is found or we ran out of options * @param {array} systemStringsToApply * @param {object} configs * @param {number} idx * @param {function} resolve * @param {function} reject * @private */ function _checkAccessForSystemStrings(systemStringsToApply, configs, idx, resolve, reject) { const systemString = systemStringsToApply[idx]; logger.debug(`Requesting key system access for system string ${systemString}`); navigator.requestMediaKeySystemAccess(systemString, configs) .then((mediaKeySystemAccess) =&gt; { mediaKeySystemAccess.selectedSystemString = systemString; resolve(mediaKeySystemAccess); }) .catch((e) =&gt; { if (idx + 1 &lt; systemStringsToApply.length) { _checkAccessForSystemStrings(systemStringsToApply, configs, idx + 1, resolve, reject); } else { reject(e); } }); } /** * Selects a key system by creating the mediaKeys and adding them to the video element * @param keySystemAccess * @return {Promise&lt;unknown&gt;} */ function selectKeySystem(keySystemAccess) { return new Promise((resolve, reject) =&gt; { keySystemAccess.mksa.createMediaKeys() .then((mkeys) =&gt; { keySystem = keySystemAccess.keySystem; mediaKeys = mkeys; if (videoElement) { return videoElement.setMediaKeys(mediaKeys) } else { return Promise.resolve(); } }) .then(() =&gt; { resolve(keySystem); }) .catch(function () { reject({error: 'Error selecting keys system (' + keySystemAccess.keySystem.systemString + ')! Could not create MediaKeys -- TODO'}); }); }) } function setMediaElement(mediaElement) { if (videoElement === mediaElement) return; // Replacing the previous element if (videoElement) { videoElement.removeEventListener('encrypted', eventHandler); if (videoElement.setMediaKeys) { videoElement.setMediaKeys(null); } } videoElement = mediaElement; // Only if we are not detaching from the existing element if (videoElement) { videoElement.addEventListener('encrypted', eventHandler); if (videoElement.setMediaKeys &amp;&amp; mediaKeys) { videoElement.setMediaKeys(mediaKeys); } } } function setServerCertificate(serverCertificate) { if (!keySystem || !mediaKeys) { throw new Error('Can not set server certificate until you have selected a key system'); } mediaKeys.setServerCertificate(serverCertificate).then(function () { logger.info('DRM: License server certificate successfully updated.'); eventBus.trigger(events.SERVER_CERTIFICATE_UPDATED); }).catch(function (error) { eventBus.trigger(events.SERVER_CERTIFICATE_UPDATED, {error: new DashJSError(ProtectionErrors.SERVER_CERTIFICATE_UPDATED_ERROR_CODE, ProtectionErrors.SERVER_CERTIFICATE_UPDATED_ERROR_MESSAGE + error.name)}); }); } /** * Create a key session, a session token and initialize a request by calling generateRequest * @param ksInfo */ function createKeySession(ksInfo) { if (!keySystem || !mediaKeys) { throw new Error('Can not create sessions until you have selected a key system'); } const session = mediaKeys.createSession(ksInfo.sessionType); const sessionToken = createSessionToken(session, ksInfo); // The \"keyids\" type is used for Clearkey when keys are provided directly in the protection data and a request to a license server is not needed const dataType = keySystem.systemString === ProtectionConstants.CLEARKEY_KEYSTEM_STRING &amp;&amp; (ksInfo.initData || (ksInfo.protData &amp;&amp; ksInfo.protData.clearkeys)) ? ProtectionConstants.INITIALIZATION_DATA_TYPE_KEYIDS : ProtectionConstants.INITIALIZATION_DATA_TYPE_CENC; session.generateRequest(dataType, ksInfo.initData).then(function () { logger.debug('DRM: Session created. SessionID = ' + sessionToken.getSessionId()); eventBus.trigger(events.KEY_SESSION_CREATED, {data: sessionToken}); }).catch(function (error) { removeSession(sessionToken); eventBus.trigger(events.KEY_SESSION_CREATED, { data: null, error: new DashJSError(ProtectionErrors.KEY_SESSION_CREATED_ERROR_CODE, ProtectionErrors.KEY_SESSION_CREATED_ERROR_MESSAGE + 'Error generating key request -- ' + error.name) }); }); } function updateKeySession(sessionToken, message) { const session = sessionToken.session; // Send our request to the key session if (protectionKeyController.isClearKey(keySystem)) { message = message.toJWK(); } session.update(message) .then(() =&gt; { eventBus.trigger(events.KEY_SESSION_UPDATED); }) .catch(function (error) { eventBus.trigger(events.KEY_ERROR, {error: new DashJSError(ProtectionErrors.MEDIA_KEYERR_CODE, 'Error sending update() message! ' + error.name, sessionToken)}); }); } function loadKeySession(ksInfo) { if (!keySystem || !mediaKeys) { throw new Error('Can not load sessions until you have selected a key system'); } const sessionId = ksInfo.sessionId; // Check if session Id is not already loaded or loading for (let i = 0; i &lt; sessions.length; i++) { if (sessionId === sessions[i].sessionId) { logger.warn('DRM: Ignoring session ID because we have already seen it!'); return; } } const session = mediaKeys.createSession(ksInfo.sessionType); const sessionToken = createSessionToken(session, ksInfo); // Load persisted session data into our newly created session object session.load(sessionId).then(function (success) { if (success) { logger.debug('DRM: Session loaded. SessionID = ' + sessionToken.getSessionId()); eventBus.trigger(events.KEY_SESSION_CREATED, {data: sessionToken}); } else { removeSession(sessionToken); eventBus.trigger(events.KEY_SESSION_CREATED, { data: null, error: new DashJSError(ProtectionErrors.KEY_SESSION_CREATED_ERROR_CODE, ProtectionErrors.KEY_SESSION_CREATED_ERROR_MESSAGE + 'Could not load session! Invalid Session ID (' + sessionId + ')') }); } }).catch(function (error) { removeSession(sessionToken); eventBus.trigger(events.KEY_SESSION_CREATED, { data: null, error: new DashJSError(ProtectionErrors.KEY_SESSION_CREATED_ERROR_CODE, ProtectionErrors.KEY_SESSION_CREATED_ERROR_MESSAGE + 'Could not load session (' + sessionId + ')! ' + error.name) }); }); } function removeKeySession(sessionToken) { const session = sessionToken.session; session.remove().then(function () { logger.debug('DRM: Session removed. SessionID = ' + sessionToken.getSessionId()); eventBus.trigger(events.KEY_SESSION_REMOVED, {data: sessionToken.getSessionId()}); }, function (error) { eventBus.trigger(events.KEY_SESSION_REMOVED, { data: null, error: 'Error removing session (' + sessionToken.getSessionId() + '). ' + error.name }); }); } function closeKeySession(sessionToken) { // Send our request to the key session _closeKeySessionInternal(sessionToken).catch(function (error) { removeSession(sessionToken); eventBus.trigger(events.KEY_SESSION_CLOSED, { data: null, error: 'Error closing session (' + sessionToken.getSessionId() + ') ' + error.name }); }); } function _closeKeySessionInternal(sessionToken) { const session = sessionToken.session; // Remove event listeners session.removeEventListener('keystatuseschange', sessionToken); session.removeEventListener('message', sessionToken); // Send our request to the key session return session.close(); } // This is our main event handler for all desired HTMLMediaElement events // related to EME. These events are translated into our API-independent // versions of the same events function createEventHandler() { return { handleEvent: function (event) { switch (event.type) { case 'encrypted': if (event.initData) { let initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData; eventBus.trigger(events.NEED_KEY, {key: new NeedKey(initData, event.initDataType)}); } break; } } }; } function removeSession(token) { // Remove from our session list for (let i = 0; i &lt; sessions.length; i++) { if (sessions[i] === token) { sessions.splice(i, 1); break; } } } function parseKeyStatus(args) { // Edge and Chrome implement different version of keystatues, param are not on same order let status, keyId; if (args &amp;&amp; args.length &gt; 0) { if (args[0]) { if (typeof args[0] === 'string') { status = args[0]; } else { keyId = args[0]; } } if (args[1]) { if (typeof args[1] === 'string') { status = args[1]; } else { keyId = args[1]; } } } return { status: status, keyId: keyId }; } // Function to create our session token objects which manage the EME // MediaKeySession and session-specific event handler function createSessionToken(session, ksInfo) { const token = { // Implements SessionToken session: session, keyId: ksInfo.keyId, initData: ksInfo.initData, sessionId: ksInfo.sessionId, sessionType: ksInfo.sessionType, // This is our main event handler for all desired MediaKeySession events // These events are translated into our API-independent versions of the // same events handleEvent: function (event) { switch (event.type) { case 'keystatuseschange': eventBus.trigger(events.KEY_STATUSES_CHANGED, {data: this}); event.target.keyStatuses.forEach(function () { let keyStatus = parseKeyStatus(arguments); switch (keyStatus.status) { case 'expired': eventBus.trigger(events.INTERNAL_KEY_STATUS_CHANGED, {error: new DashJSError(ProtectionErrors.KEY_STATUS_CHANGED_EXPIRED_ERROR_CODE, ProtectionErrors.KEY_STATUS_CHANGED_EXPIRED_ERROR_MESSAGE)}); break; default: eventBus.trigger(events.INTERNAL_KEY_STATUS_CHANGED, keyStatus); break; } }); break; case 'message': let message = ArrayBuffer.isView(event.message) ? event.message.buffer : event.message; eventBus.trigger(events.INTERNAL_KEY_MESSAGE, {data: new KeyMessage(this, message, undefined, event.messageType)}); break; } }, getKeyId: function () { return this.keyId; }, getSessionId: function () { return session.sessionId; }, getSessionType: function () { return this.sessionType; }, getExpirationTime: function () { return session.expiration; }, getKeyStatuses: function () { return session.keyStatuses; }, getUsable: function () { let usable = false; session.keyStatuses.forEach(function () { let keyStatus = parseKeyStatus(arguments); if (keyStatus.status === 'usable') { usable = true; } }); return usable; } }; // Add all event listeners session.addEventListener('keystatuseschange', token); session.addEventListener('message', token); // Register callback for session closed Promise session.closed.then(() =&gt; { removeSession(token); logger.debug('DRM: Session closed. SessionID = ' + token.getSessionId()); eventBus.trigger(events.KEY_SESSION_CLOSED, {data: token.getSessionId()}); }); // Add to our session list sessions.push(token); return token; } instance = { getAllInitData, getSessions, requestKeySystemAccess, selectKeySystem, setMediaElement, setServerCertificate, createKeySession, updateKeySession, loadKeySession, removeKeySession, closeKeySession, stop, reset }; setup(); return instance; } ProtectionModel_21Jan2015.__dashjs_factory_name = 'ProtectionModel_21Jan2015'; export default dashjs.FactoryMaker.getClassFactory(ProtectionModel_21Jan2015); /* jshint ignore:line */ × Search results Close "},"streaming_protection_Protection.js.html":{"id":"streaming_protection_Protection.js.html","title":"Source: streaming/protection/Protection.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/Protection.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import ProtectionController from './controllers/ProtectionController'; import ProtectionKeyController from './controllers/ProtectionKeyController'; import ProtectionEvents from './ProtectionEvents'; import ProtectionErrors from './errors/ProtectionErrors'; import ProtectionModel_21Jan2015 from './models/ProtectionModel_21Jan2015'; import ProtectionModel_3Feb2014 from './models/ProtectionModel_3Feb2014'; import ProtectionModel_01b from './models/ProtectionModel_01b'; const APIS_ProtectionModel_01b = [ // Un-prefixed as per spec { // Video Element generateKeyRequest: 'generateKeyRequest', addKey: 'addKey', cancelKeyRequest: 'cancelKeyRequest', // Events needkey: 'needkey', keyerror: 'keyerror', keyadded: 'keyadded', keymessage: 'keymessage' }, // Webkit-prefixed (early Chrome versions and Chrome with EME disabled in chrome://flags) { // Video Element generateKeyRequest: 'webkitGenerateKeyRequest', addKey: 'webkitAddKey', cancelKeyRequest: 'webkitCancelKeyRequest', // Events needkey: 'webkitneedkey', keyerror: 'webkitkeyerror', keyadded: 'webkitkeyadded', keymessage: 'webkitkeymessage' } ]; const APIS_ProtectionModel_3Feb2014 = [ // Un-prefixed as per spec // Chrome 38-39 (and some earlier versions) with chrome://flags -- Enable Encrypted Media Extensions { // Video Element setMediaKeys: 'setMediaKeys', // MediaKeys MediaKeys: 'MediaKeys', // MediaKeySession release: 'close', // Events needkey: 'needkey', error: 'keyerror', message: 'keymessage', ready: 'keyadded', close: 'keyclose' }, // MS-prefixed (IE11, Windows 8.1) { // Video Element setMediaKeys: 'msSetMediaKeys', // MediaKeys MediaKeys: 'MSMediaKeys', // MediaKeySession release: 'close', // Events needkey: 'msneedkey', error: 'mskeyerror', message: 'mskeymessage', ready: 'mskeyadded', close: 'mskeyclose' } ]; function Protection() { let instance; const context = this.context; /** * Create a ProtectionController and associated ProtectionModel for use with * a single piece of content. * * @param {Object} config * @return {ProtectionController} protection controller * */ function createProtectionSystem(config) { let controller = null; const protectionKeyController = ProtectionKeyController(context).getInstance(); protectionKeyController.setConfig({ debug: config.debug, BASE64: config.BASE64, settings: config.settings }); protectionKeyController.initialize(); let protectionModel = _getProtectionModel(config); if (!controller &amp;&amp; protectionModel) {//TODO add ability to set external controller if still needed at all? controller = ProtectionController(context).create({ protectionModel: protectionModel, protectionKeyController: protectionKeyController, eventBus: config.eventBus, debug: config.debug, events: config.events, BASE64: config.BASE64, constants: config.constants, cmcdModel: config.cmcdModel, customParametersModel : config.customParametersModel, settings: config.settings }); config.capabilities.setEncryptedMediaSupported(true); } return controller; } function _getProtectionModel(config) { const debug = config.debug; const logger = debug.getLogger(instance); const eventBus = config.eventBus; const errHandler = config.errHandler; const videoElement = config.videoModel ? config.videoModel.getElement() : null; if ((!videoElement || videoElement.onencrypted !== undefined) &amp;&amp; (!videoElement || videoElement.mediaKeys !== undefined)) { logger.info('EME detected on this user agent! (ProtectionModel_21Jan2015)'); return ProtectionModel_21Jan2015(context).create({ debug: debug, eventBus: eventBus, events: config.events }); } else if (_getAPI(videoElement, APIS_ProtectionModel_3Feb2014)) { logger.info('EME detected on this user agent! (ProtectionModel_3Feb2014)'); return ProtectionModel_3Feb2014(context).create({ debug: debug, eventBus: eventBus, events: config.events, api: _getAPI(videoElement, APIS_ProtectionModel_3Feb2014) }); } else if (_getAPI(videoElement, APIS_ProtectionModel_01b)) { logger.info('EME detected on this user agent! (ProtectionModel_01b)'); return ProtectionModel_01b(context).create({ debug: debug, eventBus: eventBus, errHandler: errHandler, events: config.events, api: _getAPI(videoElement, APIS_ProtectionModel_01b) }); } else { logger.warn('No supported version of EME detected on this user agent! - Attempts to play encrypted content will fail!'); return null; } } function _getAPI(videoElement, apis) { for (let i = 0; i &lt; apis.length; i++) { const api = apis[i]; // detect if api is supported by browser // check only first function in api -&gt; should be fine if (typeof videoElement[api[Object.keys(api)[0]]] !== 'function') { continue; } return api; } return null; } instance = { createProtectionSystem }; return instance; } Protection.__dashjs_factory_name = 'Protection'; const factory = dashjs.FactoryMaker.getClassFactory(Protection); /* jshint ignore:line */ factory.events = ProtectionEvents; factory.errors = ProtectionErrors; dashjs.FactoryMaker.updateClassFactory(Protection.__dashjs_factory_name, factory); /* jshint ignore:line */ export default factory; × Search results Close "},"streaming_vo_metrics_RepresentationSwitch.js.html":{"id":"streaming_vo_metrics_RepresentationSwitch.js.html","title":"Source: streaming/vo/metrics/RepresentationSwitch.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/RepresentationSwitch.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ class RepresentationSwitch { /** * @description This Object holds reference to the info at quality switch between two representations. */ constructor() { /** * Time of the switch event. * @public */ this.t = null; /** * The media presentation time of the earliest access unit * (out of all media content components) played out from * the Representation. * * @public */ this.mt = null; /** * Value of Representation@id identifying the switch-to Representation. * @public */ this.to = null; /** * If not present, this metrics concerns the Representation as a whole. * If present, lto indicates the value of SubRepresentation@level within * Representation identifying the switch-to level of the Representation. * * @public */ this.lto = null; } } export default RepresentationSwitch; × Search results Close "},"streaming_vo_metrics_RequestsQueue.js.html":{"id":"streaming_vo_metrics_RequestsQueue.js.html","title":"Source: streaming/vo/metrics/RequestsQueue.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/RequestsQueue.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ class RequestsQueue { /** * @description This Object holds reference to Fragment Model's request queues */ constructor() { /** * Array of all of the requests that have begun to load * This request may not make it into the executed queue if it is abandon due to ABR rules for example. * @public */ this.loadingRequests = []; /** * Array of the The requests that have completed * @public */ this.executedRequests = []; } } export default RequestsQueue; × Search results Close "},"streaming_controllers_ScheduleController.js.html":{"id":"streaming_controllers_ScheduleController.js.html","title":"Source: streaming/controllers/ScheduleController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/ScheduleController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../constants/Constants'; import FragmentModel from '../models/FragmentModel'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import MetricsConstants from '../constants/MetricsConstants'; import MediaPlayerEvents from '../MediaPlayerEvents'; function ScheduleController(config) { config = config || {}; const context = this.context; const eventBus = EventBus(context).getInstance(); const dashMetrics = config.dashMetrics; const mediaPlayerModel = config.mediaPlayerModel; const fragmentModel = config.fragmentModel; const abrController = config.abrController; const playbackController = config.playbackController; const textController = config.textController; const type = config.type; const bufferController = config.bufferController; const settings = config.settings; let instance, streamInfo, logger, currentRepresentationInfo, timeToLoadDelay, scheduleTimeout, hasVideoTrack, lastFragmentRequest, topQualityIndex, lastInitializedQuality, switchTrack, initSegmentRequired, checkPlaybackQuality; function setup() { logger = Debug(context).getInstance().getLogger(instance); resetInitialSettings(); streamInfo = config.streamInfo; } function initialize(_hasVideoTrack) { hasVideoTrack = _hasVideoTrack; eventBus.on(Events.BYTES_APPENDED_END_FRAGMENT, _onBytesAppended, instance); eventBus.on(Events.URL_RESOLUTION_FAILED, _onURLResolutionFailed, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_STARTED, _onPlaybackStarted, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_RATE_CHANGED, _onPlaybackRateChanged, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance); } function getType() { return type; } function getStreamId() { return streamInfo.id; } function setCurrentRepresentation(representationInfo) { currentRepresentationInfo = representationInfo; } function startScheduleTimer(value) { if (bufferController.getIsBufferingCompleted()) return; clearScheduleTimer(); const timeoutValue = !isNaN(value) ? value : 0; scheduleTimeout = setTimeout(schedule, timeoutValue); } function clearScheduleTimer() { if (scheduleTimeout) { clearTimeout(scheduleTimeout); scheduleTimeout = null; } } function hasTopQualityChanged() { const streamId = streamInfo.id; const newTopQualityIndex = abrController.getMaxAllowedIndexFor(type, streamId); if (isNaN(topQualityIndex) || topQualityIndex != newTopQualityIndex) { logger.info('Top quality ' + type + ' index has changed from ' + topQualityIndex + ' to ' + newTopQualityIndex); topQualityIndex = newTopQualityIndex; return true; } return false; } /** * Schedule the request for an init or a media segment */ function schedule() { try { // Check if we are supposed to stop scheduling if (_shouldClearScheduleTimer()) { clearScheduleTimer(); return; } if (_shouldScheduleNextRequest()) { let qualityChange = false; if (checkPlaybackQuality) { // in case the playback quality is supposed to be changed, the corresponding StreamProcessor will update the currentRepresentation. // The StreamProcessor will also start the schedule timer again once the quality switch has beeen prepared. Consequently, we only call _getNextFragment if the quality is not changed. qualityChange = abrController.checkPlaybackQuality(type, streamInfo.id); } if (!qualityChange) { _getNextFragment(); } } else { startScheduleTimer(playbackController.getLowLatencyModeEnabled() ? settings.get().streaming.scheduling.lowLatencyTimeout : settings.get().streaming.scheduling.defaultTimeout); } } catch (e) { startScheduleTimer(playbackController.getLowLatencyModeEnabled() ? settings.get().streaming.scheduling.lowLatencyTimeout : settings.get().streaming.scheduling.defaultTimeout); } } /** * Triggers the events to start requesting an init or a media segment. This will be picked up by the corresponding StreamProcessor. * @private */ function _getNextFragment() { // A quality changed occured or we are switching the AdaptationSet. In that case we need to load a new init segment if (initSegmentRequired || currentRepresentationInfo.quality !== lastInitializedQuality || switchTrack) { if (switchTrack) { logger.debug('Switch track for ' + type + ', representation id = ' + currentRepresentationInfo.id); switchTrack = false; } else { logger.debug('Quality has changed, get init request for representationid = ' + currentRepresentationInfo.id); } eventBus.trigger(Events.INIT_FRAGMENT_NEEDED, { representationId: currentRepresentationInfo.id, sender: instance }, { streamId: streamInfo.id, mediaType: type } ); checkPlaybackQuality = false; initSegmentRequired = false; } // Request a media segment instead else { logger.debug(`Media segment needed for ${type} and stream id ${streamInfo.id}`); eventBus.trigger(Events.MEDIA_FRAGMENT_NEEDED, {}, { streamId: streamInfo.id, mediaType: type } ); checkPlaybackQuality = true; } } /** * Check if we need to stop scheduling for now. * @return {boolean} * @private */ function _shouldClearScheduleTimer() { try { return (((type === Constants.TEXT) &amp;&amp; !textController.isTextEnabled()) || (playbackController.isPaused() &amp;&amp; (!playbackController.getStreamController().getInitialPlayback() || !playbackController.getStreamController().getAutoPlay()) &amp;&amp; !settings.get().streaming.scheduling.scheduleWhilePaused)); } catch (e) { return false; } } /** * Check if we can start scheduling the next request * @return {boolean} * @private */ function _shouldScheduleNextRequest() { try { return currentRepresentationInfo &amp;&amp; (isNaN(lastInitializedQuality) || switchTrack || hasTopQualityChanged() || _shouldBuffer()); } catch (e) { return false; } } /** * Check if the current buffer level is below our buffer target. * @return {boolean} * @private */ function _shouldBuffer() { if (!type || !currentRepresentationInfo) { return true; } const bufferLevel = dashMetrics.getCurrentBufferLevel(type); return bufferLevel &lt; getBufferTarget(); } /** * Determine the buffer target depending on the type and whether we have audio and video AdaptationSets available * @return {number} */ function getBufferTarget() { let bufferTarget = NaN; if (!type || !currentRepresentationInfo) { return bufferTarget; } if (type === Constants.TEXT) { bufferTarget = _getBufferTargetForFragmentedText(); } else if (type === Constants.AUDIO &amp;&amp; hasVideoTrack) { bufferTarget = _getBufferTargetForAudio(); } else { bufferTarget = _getGenericBufferTarget(); } return bufferTarget; } /** * Returns the buffer target for fragmented text tracks * @return {number} * @private */ function _getBufferTargetForFragmentedText() { try { if (textController.isTextEnabled()) { if (isNaN(currentRepresentationInfo.fragmentDuration)) { //fragmentDuration of currentRepresentationInfo is not defined, // call metrics function to have data in the latest scheduling info... // if no metric, returns 0. In this case, rule will return false. const schedulingInfo = dashMetrics.getCurrentSchedulingInfo(MetricsConstants.SCHEDULING_INFO); return schedulingInfo ? schedulingInfo.duration : 0; } else { return currentRepresentationInfo.fragmentDuration; } } else { // text is disabled, rule will return false return 0; } } catch (e) { return 0; } } /** * Returns the buffer target for audio tracks in case we have a video track available as well * @return {number} * @private */ function _getBufferTargetForAudio() { try { const videoBufferLevel = dashMetrics.getCurrentBufferLevel(Constants.VIDEO); // For multiperiod we need to consider that audio and video segments might have different durations. // This can lead to scenarios in which we completely buffered the video segments and the video buffer level for the current period is not changing anymore. However we might still need a small audio segment to finish buffering audio as well. // If we set the buffer time of audio equal to the video buffer time scheduling for the remaining audio segment will only be triggered when audio fragmentDuration &gt; videoBufferLevel. That will delay preloading of the upcoming period. // Should find a better solution than just adding 1 if (isNaN(currentRepresentationInfo.fragmentDuration)) { return videoBufferLevel + 1; } else { return Math.max(videoBufferLevel + 1, currentRepresentationInfo.fragmentDuration); } } catch (e) { return 0; } } /** * Determines the generic buffer target, for instance for video tracks * @return {number} * @private */ function _getGenericBufferTarget() { try { const streamInfo = currentRepresentationInfo.mediaInfo.streamInfo; if (abrController.isPlayingAtTopQuality(streamInfo)) { const isLongFormContent = streamInfo.manifestInfo.duration &gt;= settings.get().streaming.buffer.longFormContentDurationThreshold; return isLongFormContent ? settings.get().streaming.buffer.bufferTimeAtTopQualityLongForm : settings.get().streaming.buffer.bufferTimeAtTopQuality; } else { return mediaPlayerModel.getStableBufferTime(); } } catch (e) { return mediaPlayerModel.getStableBufferTime(); } } function setSwitchTrack(value) { switchTrack = value; } function getSwitchStrack() { return switchTrack; } function _onPlaybackTimeUpdated() { _completeQualityChange(true); } function _completeQualityChange(trigger) { if (playbackController &amp;&amp; fragmentModel) { const item = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_EXECUTED, time: playbackController.getTime(), threshold: 0 })[0]; if (item &amp;&amp; playbackController.getTime() &gt;= item.startTime) { if ((!lastFragmentRequest.mediaInfo || (item.mediaInfo.type === lastFragmentRequest.mediaInfo.type &amp;&amp; item.mediaInfo.id !== lastFragmentRequest.mediaInfo.id)) &amp;&amp; trigger) { eventBus.trigger(Events.TRACK_CHANGE_RENDERED, { mediaType: type, oldMediaInfo: lastFragmentRequest.mediaInfo, newMediaInfo: item.mediaInfo, streamId: streamInfo.id }); } if ((item.quality !== lastFragmentRequest.quality || item.adaptationIndex !== lastFragmentRequest.adaptationIndex) &amp;&amp; trigger) { logger.debug(`Quality change rendered for streamId ${streamInfo.id} and type ${type}`); eventBus.trigger(Events.QUALITY_CHANGE_RENDERED, { mediaType: type, oldQuality: lastFragmentRequest.quality, newQuality: item.quality, streamId: streamInfo.id }); } lastFragmentRequest = { mediaInfo: item.mediaInfo, quality: item.quality, adaptationIndex: item.adaptationIndex }; } } } function _onBytesAppended(e) { logger.debug(`Appended bytes for ${e.mediaType} and stream id ${streamInfo.id}`); // we save the last initialized quality. That way we make sure that the media fragments we are about to append match the init segment if (isNaN(e.index) || isNaN(lastInitializedQuality)) { lastInitializedQuality = e.quality; logger.info('[' + type + '] ' + 'lastInitializedRepresentationInfo changed to ' + e.quality); } startScheduleTimer(0); } function _onURLResolutionFailed() { fragmentModel.abortRequests(); clearScheduleTimer(); } function _onPlaybackStarted() { if (!settings.get().streaming.scheduling.scheduleWhilePaused) { startScheduleTimer(); } } function _onPlaybackRateChanged(e) { dashMetrics.updatePlayListTraceMetrics({ playbackspeed: e.playbackRate.toString() }); } function setTimeToLoadDelay(value) { timeToLoadDelay = value; } function getTimeToLoadDelay() { return timeToLoadDelay; } function setCheckPlaybackQuality(value) { checkPlaybackQuality = value; } function setInitSegmentRequired(value) { initSegmentRequired = value; } function resetInitialSettings() { checkPlaybackQuality = true; timeToLoadDelay = 0; lastInitializedQuality = NaN; lastFragmentRequest = { mediaInfo: undefined, quality: NaN, adaptationIndex: NaN }; topQualityIndex = NaN; switchTrack = false; initSegmentRequired = false; } function reset() { eventBus.off(Events.BYTES_APPENDED_END_FRAGMENT, _onBytesAppended, instance); eventBus.off(Events.URL_RESOLUTION_FAILED, _onURLResolutionFailed, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_STARTED, _onPlaybackStarted, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_RATE_CHANGED, _onPlaybackRateChanged, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance); clearScheduleTimer(); _completeQualityChange(false); resetInitialSettings(); streamInfo = null; } function getPlaybackController() { return playbackController; } instance = { initialize, getType, getStreamId, setCurrentRepresentation, setTimeToLoadDelay, getTimeToLoadDelay, setSwitchTrack, getSwitchStrack, startScheduleTimer, clearScheduleTimer, reset, getBufferTarget, getPlaybackController, setCheckPlaybackQuality, setInitSegmentRequired }; setup(); return instance; } ScheduleController.__dashjs_factory_name = 'ScheduleController'; export default FactoryMaker.getClassFactory(ScheduleController); × Search results Close "},"streaming_vo_metrics_SchedulingInfo.js.html":{"id":"streaming_vo_metrics_SchedulingInfo.js.html","title":"Source: streaming/vo/metrics/SchedulingInfo.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/SchedulingInfo.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ class SchedulingInfo { /** * @description This Object holds reference to the index handling of the current fragment being loaded or executed. */ constructor() { /** * Type of stream Audio | Video | FragmentedText * @public */ this.mediaType = null; /** * Time of the scheduling event. * @public */ this.t = null; /** * Type of fragment (initialization | media) * @public */ this.type = null; /** * Presentation start time of fragment * @public */ this.startTime = null; /** * Availability start time of fragment * @public */ this.availabilityStartTime = null; /** * Duration of fragment * @public */ this.duration = null; /** * Bit Rate Quality of fragment * @public */ this.quality = null; /** * Range of fragment * @public */ this.range = null; /** * Current state of fragment * @public */ this.state = null; } } export default SchedulingInfo; × Search results Close "},"dash_controllers_ServiceDescriptionController.js.html":{"id":"dash_controllers_ServiceDescriptionController.js.html","title":"Source: dash/controllers/ServiceDescriptionController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: dash/controllers/ServiceDescriptionController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import Constants from '../../streaming/constants/Constants'; import DashConstants from '../constants/DashConstants'; const SUPPORTED_SCHEMES = [Constants.SERVICE_DESCRIPTION_DVB_LL_SCHEME]; const MEDIA_TYPES = { VIDEO: 'video', AUDIO: 'audio', ANY: 'any', ALL: 'all' } function ServiceDescriptionController() { const context = this.context; let instance, serviceDescriptionSettings, prftOffsets, logger, adapter; function setup() { logger = Debug(context).getInstance().getLogger(instance); _resetInitialSettings(); } function setConfig(config) { if (!config) return; if (config.adapter) { adapter = config.adapter; } } function reset() { _resetInitialSettings(); } function _resetInitialSettings() { serviceDescriptionSettings = { liveDelay: NaN, liveCatchup: { maxDrift: NaN, playbackRate: NaN }, minBitrate: {}, maxBitrate: {}, initialBitrate: {} }; prftOffsets = []; } /** * Returns the service description settings for latency, catchup and bandwidth */ function getServiceDescriptionSettings() { return serviceDescriptionSettings } /** * Check for potential ServiceDescriptor elements in the MPD and update the settings accordingly * @param {object} manifestInfo * @private */ function applyServiceDescription(manifestInfo) { if (!manifestInfo || !manifestInfo.serviceDescriptions) { return; } const supportedServiceDescriptions = manifestInfo.serviceDescriptions.filter(sd =&gt; SUPPORTED_SCHEMES.includes(sd.schemeIdUri)); const allClientsServiceDescriptions = manifestInfo.serviceDescriptions.filter(sd =&gt; sd.schemeIdUri == null); let sd = (supportedServiceDescriptions.length &gt; 0) ? supportedServiceDescriptions[supportedServiceDescriptions.length - 1] : allClientsServiceDescriptions[allClientsServiceDescriptions.length - 1]; if (!sd) return; if (sd.latency &amp;&amp; sd.latency.target &gt; 0) { _applyServiceDescriptionLatency(sd); } if (sd.playbackRate &amp;&amp; sd.playbackRate.max &gt; 1.0) { _applyServiceDescriptionPlaybackRate(sd); } if (sd.operatingQuality) { _applyServiceDescriptionOperatingQuality(sd); } if (sd.operatingBandwidth) { _applyServiceDescriptionOperatingBandwidth(sd); } } /** * Adjust the latency targets for the service. * @param {object} sd - service description element * @private */ function _applyServiceDescriptionLatency(sd) { let params; if (sd.schemeIdUri === Constants.SERVICE_DESCRIPTION_DVB_LL_SCHEME) { params = _getDvbServiceDescriptionLatencyParameters(sd); } else { params = _getStandardServiceDescriptionLatencyParameters(sd); } if (prftOffsets.length &gt; 0) { let { to, id } = _calculateTimeOffset(params); // TS 103 285 Clause 10.20.4. 3) Subtract calculated offset from Latency@target converted from milliseconds // liveLatency does not consider ST@availabilityTimeOffset so leave out that step // Since maxDrift is a difference rather than absolute it does not need offset applied serviceDescriptionSettings.liveDelay = params.liveDelay - to; serviceDescriptionSettings.liveCatchup.maxDrift = params.maxDrift; logger.debug(` Found latency properties coming from service description. Applied time offset of ${to} from ProducerReferenceTime element with id ${id}. Live Delay: ${params.liveDelay - to}, Live catchup max drift: ${params.maxDrift} `); } else { serviceDescriptionSettings.liveDelay = params.liveDelay; serviceDescriptionSettings.liveCatchup.maxDrift = params.maxDrift; logger.debug(`Found latency properties coming from service description: Live Delay: ${params.liveDelay}, Live catchup max drift: ${params.maxDrift}`); } } /** * Get default parameters for liveDelay,maxDrift * @param {object} sd * @return {{maxDrift: (number|undefined), liveDelay: number, referenceId: (number|undefined)}} * @private */ function _getStandardServiceDescriptionLatencyParameters(sd) { const liveDelay = sd.latency.target / 1000; let maxDrift = !isNaN(sd.latency.max) &amp;&amp; sd.latency.max &gt; sd.latency.target ? (sd.latency.max - sd.latency.target + 500) / 1000 : NaN; const referenceId = sd.latency.referenceId || NaN; return { liveDelay, maxDrift, referenceId } } /** * Get DVB DASH parameters for liveDelay,maxDrift * @param sd * @return {{maxDrift: (number|undefined), liveDelay: number, referenceId: (number|undefined)}} * @private */ function _getDvbServiceDescriptionLatencyParameters(sd) { const liveDelay = sd.latency.target / 1000; let maxDrift = !isNaN(sd.latency.max) &amp;&amp; sd.latency.max &gt; sd.latency.target ? (sd.latency.max - sd.latency.target + 500) / 1000 : NaN; const referenceId = sd.latency.referenceId || NaN; return { liveDelay, maxDrift, referenceId } } /** * Adjust the playback rate targets for the service * @param {object} sd * @private */ function _applyServiceDescriptionPlaybackRate(sd) { const playbackRate = (Math.round((sd.playbackRate.max - 1.0) * 1000) / 1000) serviceDescriptionSettings.liveCatchup.playbackRate = playbackRate; logger.debug(`Found latency properties coming from service description: Live catchup playback rate: ${playbackRate}`); } /** * Used to specify a quality ranking. We do not support this yet. * @private */ function _applyServiceDescriptionOperatingQuality() { return; } /** * Adjust the operating quality targets for the service * @param {object} sd * @private */ function _applyServiceDescriptionOperatingBandwidth(sd) { // Aggregation of media types is not supported yet if (!sd || !sd.operatingBandwidth || !sd.operatingBandwidth.mediaType || sd.operatingBandwidth.mediaType === MEDIA_TYPES.ALL) { return; } const params = {}; params.minBandwidth = sd.operatingBandwidth.min; params.maxBandwidth = sd.operatingBandwidth.max; params.targetBandwidth = sd.operatingBandwidth.target; const mediaTypesToApply = []; if (sd.operatingBandwidth.mediaType === MEDIA_TYPES.VIDEO || sd.operatingBandwidth.mediaType === MEDIA_TYPES.AUDIO) { mediaTypesToApply.push(sd.operatingBandwidth.mediaType); } else if (sd.operatingBandwidth.mediaType === MEDIA_TYPES.ANY) { mediaTypesToApply.push(MEDIA_TYPES.AUDIO); mediaTypesToApply.push(MEDIA_TYPES.VIDEO); } mediaTypesToApply.forEach((mediaType) =&gt; { if (!isNaN(params.minBandwidth)) { _updateBandwidthSetting('minBitrate', mediaType, params.minBandwidth); } if (!isNaN(params.maxBandwidth)) { _updateBandwidthSetting('maxBitrate', mediaType, params.maxBandwidth); } if (!isNaN(params.targetBandwidth)) { _updateBandwidthSetting('initialBitrate', mediaType, params.targetBandwidth); } }) } /** * Update the bandwidth settings vor a specific field and media type * @param {string} field * @param {string} mediaType * @param {number} value * @private */ function _updateBandwidthSetting(field, mediaType, value) { try { // Service description values are specified in bps. Settings expect the value in kbps serviceDescriptionSettings[field][mediaType] = value / 1000; } catch (e) { logger.error(e); } } /** * Returns the current calculated time offsets based on ProducerReferenceTime elements * @returns {array} */ function getProducerReferenceTimeOffsets() { return prftOffsets; } /** * Calculates an array of time offsets each with matching ProducerReferenceTime id. * Call before applyServiceDescription if producer reference time elements should be considered. * @param {array} streamInfos * @returns {array} * @private */ function calculateProducerReferenceTimeOffsets(streamInfos) { try { let timeOffsets = []; if (streamInfos &amp;&amp; streamInfos.length &gt; 0) { const mediaTypes = [Constants.VIDEO, Constants.AUDIO, Constants.TEXT]; const astInSeconds = adapter.getAvailabilityStartTime() / 1000; streamInfos.forEach((streamInfo) =&gt; { const offsets = mediaTypes .reduce((acc, mediaType) =&gt; { acc = acc.concat(adapter.getAllMediaInfoForType(streamInfo, mediaType)); return acc; }, []) .reduce((acc, mediaInfo) =&gt; { const prts = adapter.getProducerReferenceTimes(streamInfo, mediaInfo); prts.forEach((prt) =&gt; { const voRepresentations = adapter.getVoRepresentations(mediaInfo); if (voRepresentations &amp;&amp; voRepresentations.length &gt; 0 &amp;&amp; voRepresentations[0].adaptation &amp;&amp; voRepresentations[0].segmentInfoType === DashConstants.SEGMENT_TEMPLATE) { const voRep = voRepresentations[0]; const d = new Date(prt[DashConstants.WALL_CLOCK_TIME]); const wallClockTime = d.getTime() / 1000; // TS 103 285 Clause 10.20.4 // 1) Calculate PRT0 // i) take the PRT@presentationTime and subtract any ST@presentationTimeOffset // ii) convert this time to seconds by dividing by ST@timescale // iii) Add this to start time of period that contains PRT. // N.B presentationTimeOffset is already divided by timescale at this point const prt0 = wallClockTime - (((prt[DashConstants.PRESENTATION_TIME] / voRep[DashConstants.TIMESCALE]) - voRep[DashConstants.PRESENTATION_TIME_OFFSET]) + streamInfo.start); // 2) Calculate TO between PRT at the start of MPD timeline and the AST const to = astInSeconds - prt0; // 3) Not applicable as liveLatency does not consider ST@availabilityTimeOffset acc.push({ id: prt[DashConstants.ID], to }); } }); return acc; }, []) timeOffsets = timeOffsets.concat(offsets); }) } prftOffsets = timeOffsets; } catch (e) { logger.error(e); prftOffsets = []; } }; /** * Calculates offset to apply to live delay as described in TS 103 285 Clause 10.20.4 * @param {object} sdLatency - service description latency element * @returns {number} * @private */ function _calculateTimeOffset(sdLatency) { let to = 0, id; let offset = prftOffsets.filter(prt =&gt; { return prt.id === sdLatency.referenceId; }); // If only one ProducerReferenceTime to generate one TO, then use that regardless of matching ids if (offset.length === 0) { to = (prftOffsets.length &gt; 0) ? prftOffsets[0].to : 0; id = prftOffsets[0].id || NaN; } else { // If multiple id matches, use the first but this should be invalid to = offset[0].to || 0; id = offset[0].id || NaN; } return { to, id } } instance = { getServiceDescriptionSettings, getProducerReferenceTimeOffsets, calculateProducerReferenceTimeOffsets, applyServiceDescription, reset, setConfig }; setup(); return instance; } ServiceDescriptionController.__dashjs_factory_name = 'ServiceDescriptionController'; export default FactoryMaker.getSingletonFactory(ServiceDescriptionController); × Search results Close "},"streaming_protection_vo_SessionToken.js.html":{"id":"streaming_protection_vo_SessionToken.js.html","title":"Source: streaming/protection/vo/SessionToken.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/protection/vo/SessionToken.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * All session identifiers (tokens) returned by ProtectionController as well as * ProtectionModel implementations are guaranteed to contain certain properties * regardless of the proprietary data each ProtectionModel will need to attach. * This interface defines the common APIs for session tokens available for * applications to access. * * @interface SessionToken * @ignore */ class SessionToken {} /** * The initialization data used to create this session * * @instance * @name initData * @memberof SessionToken * @type ArrayBuffer * @readonly */ /** * Returns the unique session ID designated to this session * * @function * @name SessionToken#getSessionId * @return {string} the session ID or the empty string if the implementation * does not support session IDs or the sessionID has not yet been established */ /** * The time, in milliseconds since 01 January, 1970 UTC, after which * the key(s) in the session will no longer be usable to decrypt * media data, or NaN if no such time exists * * @function * @name SessionToken#getExpirationTime * @returns {number} the expiration time or NaN if no expiration time exists * for this session */ /** * Returns a read-only map of key IDs known to the session to the * current status of the associated key. * * @function * @name SessionToken#getKeyStatuses * @returns {maplike&lt;BufferSource,MediaKeyStatus&gt;} the map of keys * in this session and their associated status */ /** * Returns the session type. Session types are defined * {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeySessionType|here} * * @function * @name SessionToken#getSessionType * @returns {string} The session type */ export default SessionToken; × Search results Close "},"streaming_Stream.js.html":{"id":"streaming_Stream.js.html","title":"Source: streaming/Stream.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/Stream.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from './constants/Constants'; import DashConstants from '../dash/constants/DashConstants'; import StreamProcessor from './StreamProcessor'; import FragmentController from './controllers/FragmentController'; import ThumbnailController from './thumbnail/ThumbnailController'; import EventBus from '../core/EventBus'; import Events from '../core/events/Events'; import Debug from '../core/Debug'; import Errors from '../core/errors/Errors'; import FactoryMaker from '../core/FactoryMaker'; import DashJSError from './vo/DashJSError'; import BoxParser from './utils/BoxParser'; import URLUtils from './utils/URLUtils'; import BlacklistController from './controllers/BlacklistController'; const MEDIA_TYPES = [Constants.VIDEO, Constants.AUDIO, Constants.TEXT, Constants.MUXED, Constants.IMAGE]; function Stream(config) { config = config || {}; const context = this.context; const eventBus = EventBus(context).getInstance(); const urlUtils = URLUtils(context).getInstance(); const manifestModel = config.manifestModel; const mediaPlayerModel = config.mediaPlayerModel; const dashMetrics = config.dashMetrics; const manifestUpdater = config.manifestUpdater; const adapter = config.adapter; const timelineConverter = config.timelineConverter; const capabilities = config.capabilities; const errHandler = config.errHandler; const abrController = config.abrController; const playbackController = config.playbackController; const eventController = config.eventController; const mediaController = config.mediaController; const protectionController = config.protectionController; const textController = config.textController; const videoModel = config.videoModel; let streamInfo = config.streamInfo; const settings = config.settings; let instance, logger, streamProcessors, isInitialized, isActive, hasFinishedBuffering, hasVideoTrack, hasAudioTrack, updateError, isUpdating, fragmentController, thumbnailController, segmentBlacklistController, preloaded, boxParser, debug, isEndedEventSignaled, trackChangedEvents; /** * Setup the stream */ function setup() { try { debug = Debug(context).getInstance(); logger = debug.getLogger(instance); resetInitialSettings(); boxParser = BoxParser(context).getInstance(); segmentBlacklistController = BlacklistController(context).create({ updateEventName: Events.SEGMENT_LOCATION_BLACKLIST_CHANGED, addBlacklistEventName: Events.SEGMENT_LOCATION_BLACKLIST_ADD }); fragmentController = FragmentController(context).create({ streamInfo: streamInfo, mediaPlayerModel: mediaPlayerModel, dashMetrics: dashMetrics, errHandler: errHandler, settings: settings, boxParser: boxParser, dashConstants: DashConstants, urlUtils: urlUtils }); } catch (e) { throw e; } } /** * Initialize the events */ function initialize() { registerEvents(); registerProtectionEvents(); textController.initializeForStream(streamInfo); eventBus.trigger(Events.STREAM_UPDATED, { streamInfo: streamInfo }); } /** * Register the streaming events */ function registerEvents() { eventBus.on(Events.BUFFERING_COMPLETED, onBufferingCompleted, instance); eventBus.on(Events.DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance); eventBus.on(Events.INBAND_EVENTS, onInbandEvents, instance); } /** * Unregister the streaming events */ function unRegisterEvents() { eventBus.off(Events.DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance); eventBus.off(Events.BUFFERING_COMPLETED, onBufferingCompleted, instance); eventBus.off(Events.INBAND_EVENTS, onInbandEvents, instance); } /** * Register the protection events */ function registerProtectionEvents() { if (protectionController) { eventBus.on(Events.KEY_ERROR, onProtectionError, instance); eventBus.on(Events.SERVER_CERTIFICATE_UPDATED, onProtectionError, instance); eventBus.on(Events.LICENSE_REQUEST_COMPLETE, onProtectionError, instance); eventBus.on(Events.KEY_SYSTEM_SELECTED, onProtectionError, instance); eventBus.on(Events.KEY_SESSION_CREATED, onProtectionError, instance); eventBus.on(Events.KEY_STATUSES_CHANGED, onProtectionError, instance); } } /** * Unregister the protection events */ function unRegisterProtectionEvents() { if (protectionController) { eventBus.off(Events.KEY_ERROR, onProtectionError, instance); eventBus.off(Events.SERVER_CERTIFICATE_UPDATED, onProtectionError, instance); eventBus.off(Events.LICENSE_REQUEST_COMPLETE, onProtectionError, instance); eventBus.off(Events.KEY_SYSTEM_SELECTED, onProtectionError, instance); eventBus.off(Events.KEY_SESSION_CREATED, onProtectionError, instance); eventBus.off(Events.KEY_STATUSES_CHANGED, onProtectionError, instance); } } /** * Returns the stream id * @return {*|null} */ function getStreamId() { return streamInfo ? streamInfo.id : null; } /** * Activates Stream by re-initializing some of its components * @param {MediaSource} mediaSource * @param {array} previousBufferSinks * @memberof Stream# */ function activate(mediaSource, previousBufferSinks) { return new Promise((resolve, reject) =&gt; { if (isActive) { resolve(previousBufferSinks); return; } if (getPreloaded()) { isActive = true; eventBus.trigger(Events.STREAM_ACTIVATED, { streamInfo }); resolve(previousBufferSinks); return; } _initializeMedia(mediaSource, previousBufferSinks) .then((bufferSinks) =&gt; { isActive = true; eventBus.trigger(Events.STREAM_ACTIVATED, { streamInfo }); resolve(bufferSinks); }) .catch((e) =&gt; { reject(e); }); }); } /** * * @param {object} mediaSource * @param {array} previousBufferSinks * @return {Promise&lt;Array&gt;} * @private */ function _initializeMedia(mediaSource, previousBufferSinks) { return _commonMediaInitialization(mediaSource, previousBufferSinks); } function startPreloading(mediaSource, previousBuffers) { return new Promise((resolve, reject) =&gt; { if (getPreloaded()) { reject(); return; } logger.info(`[startPreloading] Preloading next stream with id ${getId()}`); setPreloaded(true); _commonMediaInitialization(mediaSource, previousBuffers) .then(() =&gt; { for (let i = 0; i &lt; streamProcessors.length &amp;&amp; streamProcessors[i]; i++) { streamProcessors[i].setExplicitBufferingTime(getStartTime()); streamProcessors[i].getScheduleController().startScheduleTimer(); } resolve(); }) .catch(() =&gt; { setPreloaded(false); reject(); }); }); } /** * * @param {object} mediaSource * @param {array} previousBufferSinks * @return {Promise&lt;array&gt;} * @private */ function _commonMediaInitialization(mediaSource, previousBufferSinks) { return new Promise((resolve, reject) =&gt; { checkConfig(); isUpdating = true; _addInlineEvents(); let element = videoModel.getElement(); MEDIA_TYPES.forEach((mediaType) =&gt; { if (mediaType !== Constants.VIDEO || (!element || (element &amp;&amp; (/^VIDEO$/i).test(element.nodeName)))) { _initializeMediaForType(mediaType, mediaSource); } }); _createBufferSinks(previousBufferSinks) .then((bufferSinks) =&gt; { isUpdating = false; if (streamProcessors.length === 0) { const msg = 'No streams to play.'; errHandler.error(new DashJSError(Errors.MANIFEST_ERROR_ID_NOSTREAMS_CODE, msg, manifestModel.getValue())); logger.fatal(msg); } else { _checkIfInitializationCompleted(); } // All mediaInfos for texttracks are added to the TextSourceBuffer by now. We can start creating the tracks textController.createTracks(streamInfo); resolve(bufferSinks); }) .catch((e) =&gt; { reject(e); }); }); } /** * Initialize for a given media type. Creates a corresponding StreamProcessor * @param {string} type * @param {object} mediaSource * @private */ function _initializeMediaForType(type, mediaSource) { let allMediaForType = adapter.getAllMediaInfoForType(streamInfo, type); let embeddedMediaInfos = []; let mediaInfo = null; let initialMediaInfo; if (!allMediaForType || allMediaForType.length === 0) { logger.info('No ' + type + ' data.'); return; } if (type === Constants.VIDEO) { hasVideoTrack = true; } if (type === Constants.AUDIO) { hasAudioTrack = true; } for (let i = 0, ln = allMediaForType.length; i &lt; ln; i++) { mediaInfo = allMediaForType[i]; if (type === Constants.TEXT &amp;&amp; !!mediaInfo.isEmbedded) { textController.addEmbeddedTrack(streamInfo, mediaInfo); embeddedMediaInfos.push(mediaInfo); } if (_isMediaSupported(mediaInfo)) { mediaController.addTrack(mediaInfo); } } if (embeddedMediaInfos.length &gt; 0) { mediaController.setInitialMediaSettingsForType(type, streamInfo); textController.setInitialSettings(mediaController.getInitialSettings(type)); textController.addMediaInfosToBuffer(streamInfo, type, embeddedMediaInfos); } // Filter out embedded text track before creating StreamProcessor allMediaForType = allMediaForType.filter(mediaInfo =&gt; { return !mediaInfo.isEmbedded; }); if (allMediaForType.length === 0) { return; } if (type === Constants.IMAGE) { thumbnailController = ThumbnailController(context).create({ streamInfo: streamInfo, adapter: adapter, baseURLController: config.baseURLController, timelineConverter: config.timelineConverter, debug: debug, eventBus: eventBus, events: Events, dashConstants: DashConstants, dashMetrics: config.dashMetrics, segmentBaseController: config.segmentBaseController }); thumbnailController.initialize(); return; } eventBus.trigger(Events.STREAM_INITIALIZING, { streamInfo: streamInfo, mediaInfo: mediaInfo }); mediaController.setInitialMediaSettingsForType(type, streamInfo); let streamProcessor = _createStreamProcessor(allMediaForType, mediaSource); initialMediaInfo = mediaController.getCurrentTrackFor(type, streamInfo.id); if (initialMediaInfo) { abrController.updateTopQualityIndex(initialMediaInfo); // In case of mixed fragmented and embedded text tracks, check if initial selected text track is not an embedded track streamProcessor.selectMediaInfo((type !== Constants.TEXT || !initialMediaInfo.isEmbedded) ? initialMediaInfo : allMediaForType[0]); } } function _isMediaSupported(mediaInfo) { const type = mediaInfo ? mediaInfo.type : null; let msg; if (type === Constants.MUXED) { msg = 'Multiplexed representations are intentionally not supported, as they are not compliant with the DASH-AVC/264 guidelines'; logger.fatal(msg); errHandler.error(new DashJSError(Errors.MANIFEST_ERROR_ID_MULTIPLEXED_CODE, msg, manifestModel.getValue())); return false; } if (type === Constants.TEXT || type === Constants.IMAGE) { return true; } if (!!mediaInfo.contentProtection &amp;&amp; !capabilities.supportsEncryptedMedia()) { errHandler.error(new DashJSError(Errors.CAPABILITY_MEDIAKEYS_ERROR_CODE, Errors.CAPABILITY_MEDIAKEYS_ERROR_MESSAGE)); return false; } return true; } /** * Creates the StreamProcessor for a given media type. * @param {object} initialMediaInfo * @param {array} allMediaForType * @param {object} mediaSource * @private */ function _createStreamProcessor(allMediaForType, mediaSource) { const mediaInfo = (allMediaForType &amp;&amp; allMediaForType.length &gt; 0) ? allMediaForType[0] : null; let fragmentModel = fragmentController.getModel(mediaInfo ? mediaInfo.type : null); const type = mediaInfo ? mediaInfo.type : null; const mimeType = mediaInfo ? mediaInfo.mimeType : null; const isFragmented = mediaInfo ? mediaInfo.isFragmented : null; let streamProcessor = StreamProcessor(context).create({ streamInfo, type, mimeType, timelineConverter, adapter, manifestModel, mediaPlayerModel, fragmentModel, dashMetrics: config.dashMetrics, baseURLController: config.baseURLController, segmentBaseController: config.segmentBaseController, abrController, playbackController, mediaController, textController, errHandler, settings, boxParser, segmentBlacklistController }); streamProcessor.initialize(mediaSource, hasVideoTrack, isFragmented); streamProcessors.push(streamProcessor); for (let i = 0; i &lt; allMediaForType.length; i++) { streamProcessor.addMediaInfo(allMediaForType[i]); } if (type === Constants.TEXT) { textController.addMediaInfosToBuffer(streamInfo, type, allMediaForType, fragmentModel); } return streamProcessor; } /** * Creates the SourceBufferSink objects for all StreamProcessors * @param {array} previousBuffersSinks * @return {Promise&lt;object&gt;} * @private */ function _createBufferSinks(previousBuffersSinks) { return new Promise((resolve) =&gt; { const buffers = {}; const promises = streamProcessors.map((sp) =&gt; { return sp.createBufferSinks(previousBuffersSinks); }); Promise.all(promises) .then((bufferSinks) =&gt; { bufferSinks.forEach((sink) =&gt; { if (sink) { buffers[sink.getType()] = sink; } }); resolve(buffers); }) .catch(() =&gt; { resolve(buffers); }); }); } /** * Partially resets some of the Stream elements. This function is called when preloading of streams is canceled or a stream switch occurs. * @memberof Stream# * @param {boolean} keepBuffers */ function deactivate(keepBuffers) { let ln = streamProcessors ? streamProcessors.length : 0; const errored = false; for (let i = 0; i &lt; ln; i++) { let fragmentModel = streamProcessors[i].getFragmentModel(); fragmentModel.abortRequests(); fragmentModel.resetInitialSettings(); streamProcessors[i].reset(errored, keepBuffers); } if (textController) { textController.deactivateStream(streamInfo); } streamProcessors = []; isActive = false; hasFinishedBuffering = false; setPreloaded(false); setIsEndedEventSignaled(false); eventBus.trigger(Events.STREAM_DEACTIVATED, { streamInfo }); } function getIsActive() { return isActive; } function setMediaSource(mediaSource) { for (let i = 0; i &lt; streamProcessors.length;) { if (_isMediaSupported(streamProcessors[i].getMediaInfo())) { streamProcessors[i].setMediaSource(mediaSource); i++; } else { streamProcessors[i].reset(); streamProcessors.splice(i, 1); } } if (streamProcessors.length === 0) { const msg = 'No streams to play.'; errHandler.error(new DashJSError(Errors.MANIFEST_ERROR_ID_NOSTREAMS_CODE, msg + 'nostreams', manifestModel.getValue())); logger.fatal(msg); } } function resetInitialSettings(keepBuffers) { deactivate(keepBuffers); isInitialized = false; hasVideoTrack = false; hasAudioTrack = false; updateError = {}; isUpdating = false; isEndedEventSignaled = false; trackChangedEvents = []; } function reset(keepBuffers) { if (fragmentController) { fragmentController.reset(); fragmentController = null; } if (abrController &amp;&amp; streamInfo) { abrController.clearDataForStream(streamInfo.id); } if (segmentBlacklistController) { segmentBlacklistController.reset(); segmentBlacklistController = null; } resetInitialSettings(keepBuffers); streamInfo = null; unRegisterEvents(); unRegisterProtectionEvents(); } function getDuration() { return streamInfo ? streamInfo.duration : NaN; } function getIsEndedEventSignaled() { return isEndedEventSignaled; } function setIsEndedEventSignaled(value) { isEndedEventSignaled = value; } function getStartTime() { return streamInfo ? streamInfo.start : NaN; } function getId() { return streamInfo ? streamInfo.id : null; } function getStreamInfo() { return streamInfo; } function getHasAudioTrack() { return hasAudioTrack; } function getHasVideoTrack() { return hasVideoTrack; } function getThumbnailController() { return thumbnailController; } function checkConfig() { if (!videoModel || !abrController) { throw new Error(Constants.MISSING_CONFIG_ERROR); } } /** * @param {string} type * @returns {Array} * @memberof Stream# */ function getBitrateListFor(type) { checkConfig(); if (type === Constants.IMAGE) { if (!thumbnailController) { return []; } return thumbnailController.getBitrateList(); } const mediaInfo = getMediaInfo(type); return abrController.getBitrateList(mediaInfo); } function onProtectionError(event) { if (event.error) { errHandler.error(event.error); logger.fatal(event.error.message); } } function prepareTrackChange(e) { if (!isActive || !streamInfo) { return; } hasFinishedBuffering = false; let mediaInfo = e.newMediaInfo; let manifest = manifestModel.getValue(); adapter.setCurrentMediaInfo(streamInfo.id, mediaInfo.type, mediaInfo); let processor = getProcessorForMediaInfo(mediaInfo); if (!processor) return; let currentTime = playbackController.getTime(); logger.info('Stream - Process track changed at current time ' + currentTime); // Applies only for MSS streams if (manifest.refreshManifestOnSwitchTrack) { trackChangedEvents.push(e); if (!manifestUpdater.getIsUpdating()) { logger.debug('Stream - Refreshing manifest for switch track'); manifestUpdater.refreshManifest(); } } else { processor.selectMediaInfo(mediaInfo) .then(() =&gt; { if (mediaInfo.type === Constants.VIDEO || mediaInfo.type === Constants.AUDIO) { abrController.updateTopQualityIndex(mediaInfo); } processor.prepareTrackSwitch(); }); } } function prepareQualityChange(e) { const processor = _getProcessorByType(e.mediaType); if (processor) { processor.prepareQualityChange(e); } } function _addInlineEvents() { if (eventController) { const events = adapter.getEventsFor(streamInfo); if (events &amp;&amp; events.length &gt; 0) { eventController.addInlineEvents(events, streamInfo.id); } } } function _checkIfInitializationCompleted() { const ln = streamProcessors.length; const hasError = !!updateError.audio || !!updateError.video; let error = hasError ? new DashJSError(Errors.DATA_UPDATE_FAILED_ERROR_CODE, Errors.DATA_UPDATE_FAILED_ERROR_MESSAGE) : null; for (let i = 0; i &lt; ln; i++) { if (streamProcessors[i].isUpdating() || isUpdating) { return; } } if (protectionController) { // Need to check if streamProcessors exists because streamProcessors // could be cleared in case an error is detected while initializing DRM keysystem protectionController.clearMediaInfoArray(); for (let i = 0; i &lt; ln &amp;&amp; streamProcessors[i]; i++) { const type = streamProcessors[i].getType(); const mediaInfo = streamProcessors[i].getMediaInfo(); if (type === Constants.AUDIO || type === Constants.VIDEO || (type === Constants.TEXT &amp;&amp; mediaInfo.isFragmented)) { let mediaInfo = streamProcessors[i].getMediaInfo(); if (mediaInfo) { protectionController.initializeForMedia(mediaInfo); } } } protectionController.handleKeySystemFromManifest(); } if (error) { errHandler.error(error); } else if (!isInitialized) { isInitialized = true; videoModel.waitForReadyState(Constants.VIDEO_ELEMENT_READY_STATES.HAVE_METADATA, () =&gt; { eventBus.trigger(Events.STREAM_INITIALIZED, { streamInfo: streamInfo }); }) } } function getMediaInfo(type) { let streamProcessor = null; for (let i = 0; i &lt; streamProcessors.length; i++) { streamProcessor = streamProcessors[i]; if (streamProcessor.getType() === type) { return streamProcessor.getMediaInfo(); } } return null; } function onBufferingCompleted() { let processors = getProcessors(); const ln = processors.length; if (ln === 0) { logger.warn('onBufferingCompleted - can\\'t trigger STREAM_BUFFERING_COMPLETED because no streamProcessor is defined'); return; } // if there is at least one buffer controller that has not completed buffering yet do nothing for (let i = 0; i &lt; ln; i++) { //if audio or video buffer is not buffering completed state, do not send STREAM_BUFFERING_COMPLETED if (!processors[i].isBufferingCompleted() &amp;&amp; (processors[i].getType() === Constants.AUDIO || processors[i].getType() === Constants.VIDEO)) { logger.debug('onBufferingCompleted - One streamProcessor has finished but', processors[i].getType(), 'one is not buffering completed'); return; } } logger.debug('onBufferingCompleted - trigger STREAM_BUFFERING_COMPLETED'); hasFinishedBuffering = true; eventBus.trigger(Events.STREAM_BUFFERING_COMPLETED, { streamInfo: streamInfo }, { streamInfo }); } function onDataUpdateCompleted(e) { updateError[e.mediaType] = e.error; _checkIfInitializationCompleted(); } function onInbandEvents(e) { if (eventController) { eventController.addInbandEvents(e.events, streamInfo.id); } } function getProcessorForMediaInfo(mediaInfo) { if (!mediaInfo || !mediaInfo.type) { return null; } return _getProcessorByType(mediaInfo.type); } function _getProcessorByType(type) { if (!type) { return null; } let processors = getProcessors(); return processors.filter(function (processor) { return (processor.getType() === type); })[0]; } function getProcessors() { let arr = []; let type, streamProcessor; for (let i = 0; i &lt; streamProcessors.length; i++) { streamProcessor = streamProcessors[i]; type = streamProcessor.getType(); if (type === Constants.AUDIO || type === Constants.VIDEO || type === Constants.TEXT) { arr.push(streamProcessor); } } return arr; } function startScheduleControllers() { const ln = streamProcessors.length; for (let i = 0; i &lt; ln &amp;&amp; streamProcessors[i]; i++) { streamProcessors[i].getScheduleController().startScheduleTimer(); } } function updateData(updatedStreamInfo) { return new Promise((resolve) =&gt; { isUpdating = true; streamInfo = updatedStreamInfo; if (eventController) { _addInlineEvents(); } let promises = []; for (let i = 0, ln = streamProcessors.length; i &lt; ln; i++) { let streamProcessor = streamProcessors[i]; const currentMediaInfo = streamProcessor.getMediaInfo(); promises.push(streamProcessor.updateStreamInfo(streamInfo)); let allMediaForType = adapter.getAllMediaInfoForType(streamInfo, streamProcessor.getType()); // Check if AdaptationSet has not been removed in MPD update if (allMediaForType) { // Remove the current mediaInfo objects before adding the updated ones streamProcessor.clearMediaInfoArray(); for (let j = 0; j &lt; allMediaForType.length; j++) { const mInfo = allMediaForType[j]; streamProcessor.addMediaInfo(allMediaForType[j]); if (adapter.areMediaInfosEqual(currentMediaInfo, mInfo)) { abrController.updateTopQualityIndex(mInfo); promises.push(streamProcessor.selectMediaInfo(mInfo)) } } } } Promise.all(promises) .then(() =&gt; { promises = []; while (trackChangedEvents.length &gt; 0) { let trackChangedEvent = trackChangedEvents.pop(); let mediaInfo = trackChangedEvent.newMediaInfo; let processor = getProcessorForMediaInfo(trackChangedEvent.oldMediaInfo); if (!processor) return; promises.push(processor.prepareTrackSwitch()); processor.selectMediaInfo(mediaInfo); } return Promise.all(promises) }) .then(() =&gt; { isUpdating = false; _checkIfInitializationCompleted(); eventBus.trigger(Events.STREAM_UPDATED, { streamInfo: streamInfo }); resolve(); }) }) } function isMediaCodecCompatible(newStream, previousStream = null) { return compareCodecs(newStream, Constants.VIDEO, previousStream) &amp;&amp; compareCodecs(newStream, Constants.AUDIO, previousStream); } function isProtectionCompatible(newStream) { if (!newStream) { return true; } return _compareProtectionConfig(Constants.VIDEO, newStream) &amp;&amp; _compareProtectionConfig(Constants.AUDIO, newStream); } function _compareProtectionConfig(type, newStream) { const currentStreamInfo = getStreamInfo(); const newStreamInfo = newStream.getStreamInfo(); if (!newStreamInfo || !currentStreamInfo) { return true; } const newAdaptation = adapter.getAdaptationForType(newStreamInfo.index, type, newStreamInfo); const currentAdaptation = adapter.getAdaptationForType(currentStreamInfo.index, type, currentStreamInfo); if (!newAdaptation || !currentAdaptation) { // If there is no adaptation for neither the old or the new stream they're compatible return !newAdaptation &amp;&amp; !currentAdaptation; } // If the current period is unencrypted and the upcoming one is encrypted we need to reset sourcebuffers. return !(!_isAdaptationDrmProtected(currentAdaptation) &amp;&amp; _isAdaptationDrmProtected(newAdaptation)); } function _isAdaptationDrmProtected(adaptation) { if (!adaptation) { // If there is no adaptation for neither the old or the new stream they're compatible return false; } // If the current period is unencrypted and the upcoming one is encrypted we need to reset sourcebuffers. return !!(adaptation.ContentProtection || (adaptation.Representation &amp;&amp; adaptation.Representation.length &gt; 0 &amp;&amp; adaptation.Representation[0].ContentProtection)); } function compareCodecs(newStream, type, previousStream = null) { if (!newStream || !newStream.hasOwnProperty('getStreamInfo')) { return false; } const newStreamInfo = newStream.getStreamInfo(); const currentStreamInfo = previousStream ? previousStream.getStreamInfo() : getStreamInfo(); if (!newStreamInfo || !currentStreamInfo) { return false; } const newAdaptation = adapter.getAdaptationForType(newStreamInfo.index, type, newStreamInfo); const currentAdaptation = adapter.getAdaptationForType(currentStreamInfo.index, type, currentStreamInfo); if (!newAdaptation || !currentAdaptation) { // If there is no adaptation for neither the old or the new stream they're compatible return !newAdaptation &amp;&amp; !currentAdaptation; } const sameMimeType = newAdaptation &amp;&amp; currentAdaptation &amp;&amp; newAdaptation.mimeType === currentAdaptation.mimeType; const oldCodecs = currentAdaptation.Representation_asArray.map((representation) =&gt; { return representation.codecs; }); const newCodecs = newAdaptation.Representation_asArray.map((representation) =&gt; { return representation.codecs; }); const codecMatch = newCodecs.some((newCodec) =&gt; { return oldCodecs.indexOf(newCodec) &gt; -1; }); const partialCodecMatch = newCodecs.some((newCodec) =&gt; oldCodecs.some((oldCodec) =&gt; capabilities.codecRootCompatibleWithCodec(oldCodec, newCodec))); return codecMatch || (partialCodecMatch &amp;&amp; sameMimeType); } function setPreloaded(value) { preloaded = value; } function getPreloaded() { return preloaded; } function getHasFinishedBuffering() { return hasFinishedBuffering; } function getAdapter() { return adapter; } instance = { initialize, getStreamId, activate, deactivate, getIsActive, getDuration, getStartTime, getId, getStreamInfo, getHasAudioTrack, getHasVideoTrack, startPreloading, getThumbnailController, getBitrateListFor, updateData, reset, getProcessors, setMediaSource, isMediaCodecCompatible, isProtectionCompatible, getPreloaded, getIsEndedEventSignaled, setIsEndedEventSignaled, getAdapter, getHasFinishedBuffering, setPreloaded, startScheduleControllers, prepareTrackChange, prepareQualityChange }; setup(); return instance; } Stream.__dashjs_factory_name = 'Stream'; export default FactoryMaker.getClassFactory(Stream); × Search results Close "},"streaming_controllers_StreamController.js.html":{"id":"streaming_controllers_StreamController.js.html","title":"Source: streaming/controllers/StreamController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/StreamController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../constants/Constants'; import MetricsConstants from '../constants/MetricsConstants'; import Stream from '../Stream'; import ManifestUpdater from '../ManifestUpdater'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; import { PlayList, PlayListTrace } from '../vo/metrics/PlayList'; import Debug from '../../core/Debug'; import InitCache from '../utils/InitCache'; import URLUtils from '../utils/URLUtils'; import MediaPlayerEvents from '../MediaPlayerEvents'; import TimeSyncController from './TimeSyncController'; import MediaSourceController from './MediaSourceController'; import DashJSError from '../vo/DashJSError'; import Errors from '../../core/errors/Errors'; import EventController from './EventController'; import ConformanceViolationConstants from '../constants/ConformanceViolationConstants'; const PLAYBACK_ENDED_TIMER_INTERVAL = 200; const DVR_WAITING_OFFSET = 2; function StreamController() { const context = this.context; const eventBus = EventBus(context).getInstance(); let instance, logger, capabilities, capabilitiesFilter, manifestUpdater, manifestLoader, manifestModel, adapter, dashMetrics, mediaSourceController, timeSyncController, contentSteeringController, baseURLController, segmentBaseController, uriFragmentModel, abrController, mediaController, eventController, initCache, urlUtils, errHandler, timelineConverter, streams, activeStream, protectionController, textController, protectionData, autoPlay, isStreamSwitchingInProgress, hasMediaError, hasInitialisationError, mediaSource, videoModel, playbackController, serviceDescriptionController, mediaPlayerModel, customParametersModel, isPaused, initialPlayback, initialSteeringRequest, playbackEndedTimerInterval, bufferSinks, preloadingStreams, supportsChangeType, settings, firstLicenseIsFetched, waitForPlaybackStartTimeout, providedStartTime, errorInformation; function setup() { logger = Debug(context).getInstance().getLogger(instance); timeSyncController = TimeSyncController(context).getInstance(); mediaSourceController = MediaSourceController(context).getInstance(); initCache = InitCache(context).getInstance(); urlUtils = URLUtils(context).getInstance(); resetInitialSettings(); } function initialize(autoPl, protData) { _checkConfig(); autoPlay = autoPl; protectionData = protData; timelineConverter.initialize(); manifestUpdater = ManifestUpdater(context).create(); manifestUpdater.setConfig({ manifestModel: manifestModel, adapter: adapter, manifestLoader: manifestLoader, errHandler: errHandler, settings: settings }); manifestUpdater.initialize(); eventController = EventController(context).getInstance(); eventController.setConfig({ manifestUpdater: manifestUpdater, playbackController: playbackController, settings }); eventController.start(); timeSyncController.setConfig({ dashMetrics, baseURLController, errHandler, settings }); timeSyncController.initialize(); if (protectionController) { eventBus.trigger(Events.PROTECTION_CREATED, { controller: protectionController }); protectionController.setMediaElement(videoModel.getElement()); if (protectionData) { protectionController.setProtectionData(protectionData); } } registerEvents(); } function registerEvents() { eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_ERROR, _onPlaybackError, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_STARTED, _onPlaybackStarted, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_PAUSED, _onPlaybackPaused, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, instance); eventBus.on(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); eventBus.on(MediaPlayerEvents.MANIFEST_VALIDITY_CHANGED, _onManifestValidityChanged, instance); eventBus.on(MediaPlayerEvents.BUFFER_LEVEL_UPDATED, _onBufferLevelUpdated, instance); eventBus.on(MediaPlayerEvents.QUALITY_CHANGE_REQUESTED, _onQualityChanged, instance); if (Events.KEY_SESSION_UPDATED) { eventBus.on(Events.KEY_SESSION_UPDATED, _onKeySessionUpdated, instance); } eventBus.on(Events.MANIFEST_UPDATED, _onManifestUpdated, instance); eventBus.on(Events.STREAM_BUFFERING_COMPLETED, _onStreamBufferingCompleted, instance); eventBus.on(Events.TIME_SYNCHRONIZATION_COMPLETED, _onTimeSyncCompleted, instance); eventBus.on(Events.CURRENT_TRACK_CHANGED, _onCurrentTrackChanged, instance); eventBus.on(Events.SETTING_UPDATED_LIVE_DELAY, _onLiveDelaySettingUpdated, instance); eventBus.on(Events.SETTING_UPDATED_LIVE_DELAY_FRAGMENT_COUNT, _onLiveDelaySettingUpdated, instance); } function unRegisterEvents() { eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_ERROR, _onPlaybackError, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_STARTED, _onPlaybackStarted, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_PAUSED, _onPlaybackPaused, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, instance); eventBus.off(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); eventBus.off(MediaPlayerEvents.MANIFEST_VALIDITY_CHANGED, _onManifestValidityChanged, instance); eventBus.off(MediaPlayerEvents.BUFFER_LEVEL_UPDATED, _onBufferLevelUpdated, instance); eventBus.off(MediaPlayerEvents.QUALITY_CHANGE_REQUESTED, _onQualityChanged, instance); if (Events.KEY_SESSION_UPDATED) { eventBus.off(Events.KEY_SESSION_UPDATED, _onKeySessionUpdated, instance); } eventBus.off(Events.MANIFEST_UPDATED, _onManifestUpdated, instance); eventBus.off(Events.STREAM_BUFFERING_COMPLETED, _onStreamBufferingCompleted, instance); eventBus.off(Events.TIME_SYNCHRONIZATION_COMPLETED, _onTimeSyncCompleted, instance); eventBus.off(Events.CURRENT_TRACK_CHANGED, _onCurrentTrackChanged, instance); eventBus.off(Events.SETTING_UPDATED_LIVE_DELAY, _onLiveDelaySettingUpdated, instance); eventBus.off(Events.SETTING_UPDATED_LIVE_DELAY_FRAGMENT_COUNT, _onLiveDelaySettingUpdated, instance); } function _checkConfig() { if (!manifestLoader || !manifestLoader.hasOwnProperty('load') || !timelineConverter || !timelineConverter.hasOwnProperty('initialize') || !timelineConverter.hasOwnProperty('reset') || !timelineConverter.hasOwnProperty('getClientTimeOffset') || !manifestModel || !errHandler || !dashMetrics || !playbackController) { throw new Error(Constants.MISSING_CONFIG_ERROR); } } function _checkInitialize() { if (!manifestUpdater || !manifestUpdater.hasOwnProperty('setManifest')) { throw new Error('initialize function has to be called previously'); } } /** * Start the streaming session by loading the target manifest * @param {string} url * @param {number} startTime */ function load(url, startTime = NaN) { _checkConfig(); providedStartTime = startTime; manifestLoader.load(url); } /** * Start the streaming session by using the provided manifest object * @param {object} manifest * @param {number} startTime */ function loadWithManifest(manifest, startTime = NaN) { _checkInitialize(); providedStartTime = startTime; manifestUpdater.setManifest(manifest); } /** * When the UTC snychronization is completed we can compose the streams * @private */ function _onTimeSyncCompleted( /*e*/) { _composeStreams(); } /** * * @private */ function _onKeySessionUpdated() { firstLicenseIsFetched = true; } /** * Setup the stream objects after the stream start and each MPD reload. This function is called after the UTC sync has been done (TIME_SYNCHRONIZATION_COMPLETED) * @private */ function _composeStreams() { try { const streamsInfo = adapter.getStreamsInfo(); if (!activeStream &amp;&amp; streamsInfo.length === 0) { throw new Error('There are no periods in the MPD'); } if (activeStream &amp;&amp; streamsInfo.length &gt; 0) { dashMetrics.updateManifestUpdateInfo({ currentTime: playbackController.getTime(), buffered: videoModel.getBufferRange(), presentationStartTime: streamsInfo[0].start, clientTimeOffset: timelineConverter.getClientTimeOffset() }); } // Filter streams that are outdated and not included in the MPD anymore if (streams.length &gt; 0) { _filterOutdatedStreams(streamsInfo); } const promises = []; for (let i = 0, ln = streamsInfo.length; i &lt; ln; i++) { const streamInfo = streamsInfo[i]; promises.push(_initializeOrUpdateStream(streamInfo)); dashMetrics.addManifestUpdateStreamInfo(streamInfo); } Promise.all(promises) .then(() =&gt; { if (settings.get().streaming.applyContentSteering &amp;&amp; !activeStream &amp;&amp; contentSteeringController.shouldQueryBeforeStart()) { return contentSteeringController.loadSteeringData(); } return Promise.resolve(); }) .then(() =&gt; { if (!activeStream) { _initializeForFirstStream(streamsInfo); } eventBus.trigger(Events.STREAMS_COMPOSED); // Additional periods might have been added after an MPD update. Check again if we can start prebuffering. _checkIfPrebufferingCanStart(); }) .catch((e) =&gt; { throw e; }) } catch (e) { errHandler.error(new DashJSError(Errors.MANIFEST_ERROR_ID_NOSTREAMS_CODE, e.message + ' nostreamscomposed', manifestModel.getValue())); hasInitialisationError = true; reset(); } } /** * Called for each stream when composition is performed. Either a new instance of Stream is created or the existing one is updated. * @param {object} streamInfo * @private */ function _initializeOrUpdateStream(streamInfo) { let stream = getStreamById(streamInfo.id); // If the Stream object does not exist we probably loaded the manifest the first time or it was // introduced in the updated manifest, so we need to create a new Stream and perform all the initialization operations if (!stream) { stream = Stream(context).create({ manifestModel, mediaPlayerModel, dashMetrics, manifestUpdater, adapter, timelineConverter, capabilities, capabilitiesFilter, errHandler, baseURLController, segmentBaseController, textController, abrController, playbackController, eventController, mediaController, protectionController, videoModel, streamInfo, settings }); streams.push(stream); stream.initialize(); return Promise.resolve(); } else { return stream.updateData(streamInfo); } } /** * Initialize playback for the first period. * @param {array} streamsInfo * @private */ function _initializeForFirstStream(streamsInfo) { // Add the DVR window so we can calculate the right starting point addDVRMetric(); // If the start is in the future we need to wait const dvrRange = dashMetrics.getCurrentDVRInfo().range; if (dvrRange.end &lt; dvrRange.start) { if (waitForPlaybackStartTimeout) { clearTimeout(waitForPlaybackStartTimeout); } const waitingTime = Math.min((((dvrRange.end - dvrRange.start) * -1) + DVR_WAITING_OFFSET) * 1000, 2147483647); logger.debug(`Waiting for ${waitingTime} ms before playback can start`); eventBus.trigger(Events.AST_IN_FUTURE, { delay: waitingTime }); waitForPlaybackStartTimeout = setTimeout(() =&gt; { _initializeForFirstStream(streamsInfo); }, waitingTime); return; } // Calculate the producer reference time offsets if given if (settings.get().streaming.applyProducerReferenceTime) { serviceDescriptionController.calculateProducerReferenceTimeOffsets(streamsInfo); } // Apply Service description parameters. const manifestInfo = streamsInfo[0].manifestInfo; if (settings.get().streaming.applyServiceDescription) { serviceDescriptionController.applyServiceDescription(manifestInfo); } // Compute and set the live delay if (adapter.getIsDynamic()) { const fragmentDuration = _getFragmentDurationForLiveDelayCalculation(streamsInfo, manifestInfo); playbackController.computeAndSetLiveDelay(fragmentDuration, manifestInfo); } // Figure out the correct start time and the correct start period const startTime = _getInitialStartTime(); let initialStream = getStreamForTime(startTime); const startStream = initialStream !== null ? initialStream : streams[0]; eventBus.trigger(Events.INITIAL_STREAM_SWITCH, { startTime }); _switchStream(startStream, null, startTime); _startPlaybackEndedTimerInterval(); } /** * Switch from the current stream (period) to the next stream (period). * @param {object} stream * @param {object} previousStream * @param {number} seekTime * @private */ function _switchStream(stream, previousStream, seekTime) { try { if (isStreamSwitchingInProgress || !stream || (previousStream === stream &amp;&amp; stream.getIsActive())) { return; } isStreamSwitchingInProgress = true; eventBus.trigger(Events.PERIOD_SWITCH_STARTED, { fromStreamInfo: previousStream ? previousStream.getStreamInfo() : null, toStreamInfo: stream.getStreamInfo() }); let keepBuffers = false; activeStream = stream; if (previousStream) { keepBuffers = _canSourceBuffersBeReused(stream, previousStream); previousStream.deactivate(keepBuffers); } // Determine seek time when switching to new period // - seek at given seek time // - or seek at period start if upcoming period is not prebuffered seekTime = !isNaN(seekTime) ? seekTime : (!keepBuffers &amp;&amp; previousStream ? stream.getStreamInfo().start : NaN); logger.info(`Switch to stream ${stream.getId()}. Seektime is ${seekTime}, current playback time is ${playbackController.getTime()}. Seamless period switch is set to ${keepBuffers}`); preloadingStreams = preloadingStreams.filter((s) =&gt; { return s.getId() !== activeStream.getId(); }); playbackController.initialize(getActiveStreamInfo(), !!previousStream); if (videoModel.getElement()) { _openMediaSource(seekTime, keepBuffers); } } catch (e) { isStreamSwitchingInProgress = false; } } /** * Setup the Media Source. Open MSE and attach event listeners * @param {number} seekTime * @param {boolean} keepBuffers * @private */ function _openMediaSource(seekTime, keepBuffers) { let sourceUrl; function _onMediaSourceOpen() { // Manage situations in which a call to reset happens while MediaSource is being opened if (!mediaSource || mediaSource.readyState !== 'open') return; logger.debug('MediaSource is open!'); window.URL.revokeObjectURL(sourceUrl); mediaSource.removeEventListener('sourceopen', _onMediaSourceOpen); mediaSource.removeEventListener('webkitsourceopen', _onMediaSourceOpen); _setMediaDuration(); const dvrInfo = dashMetrics.getCurrentDVRInfo(); mediaSourceController.setSeekable(dvrInfo.range.start, dvrInfo.range.end); _activateStream(seekTime, keepBuffers); } function _open() { mediaSource.addEventListener('sourceopen', _onMediaSourceOpen, false); mediaSource.addEventListener('webkitsourceopen', _onMediaSourceOpen, false); sourceUrl = mediaSourceController.attachMediaSource(videoModel); logger.debug('MediaSource attached to element. Waiting on open...'); } if (!mediaSource) { mediaSource = mediaSourceController.createMediaSource(); _open(); } else { if (keepBuffers) { _activateStream(seekTime, keepBuffers); } else { mediaSourceController.detachMediaSource(videoModel); _open(); } } } /** * Activates a new stream. * @param {number} seekTime * @param {boolean} keepBuffers */ function _activateStream(seekTime, keepBuffers) { activeStream.activate(mediaSource, keepBuffers ? bufferSinks : undefined, seekTime) .then((sinks) =&gt; { // check if change type is supported by the browser if (sinks) { const keys = Object.keys(sinks); if (keys.length &gt; 0 &amp;&amp; sinks[keys[0]].getBuffer().changeType) { supportsChangeType = true; } bufferSinks = sinks; } // Set the initial time for this stream in the StreamProcessor if (!isNaN(seekTime)) { eventBus.trigger(Events.SEEK_TARGET, { time: seekTime }, { streamId: activeStream.getId() }); playbackController.seek(seekTime, false, true); activeStream.startScheduleControllers(); } isStreamSwitchingInProgress = false; eventBus.trigger(Events.PERIOD_SWITCH_COMPLETED, { toStreamInfo: getActiveStreamInfo() }); }); } /** * A playback seeking event was triggered. We need to disable the preloading streams and call the respective seeking handler. * We distinguish between inner period seeks and outer period seeks * @param {object} e * @private */ function _onPlaybackSeeking(e) { const oldTime = playbackController.getTime(); const newTime = e.seekTime; const seekToStream = getStreamForTime(newTime); if (!seekToStream || seekToStream === activeStream) { _cancelPreloading(oldTime, newTime); _handleInnerPeriodSeek(e); } else if (seekToStream &amp;&amp; seekToStream !== activeStream) { _cancelPreloading(oldTime, newTime, seekToStream); _handleOuterPeriodSeek(e, seekToStream); } _createPlaylistMetrics(PlayList.SEEK_START_REASON); } /** * Cancels the preloading of certain streams based on the position we are seeking to. * @param {number} oldTime * @param {number} newTime * @param {boolean} isInnerPeriodSeek * @private */ function _cancelPreloading(oldTime, newTime, seekToStream = null) { // Inner period seek forward if (oldTime &lt;= newTime &amp;&amp; !seekToStream) { _deactivateAllPreloadingStreams(); } // Inner period seek: If we seek backwards we might need to prune the period(s) that are currently being prebuffered. For now deactivate everything else if (oldTime &gt; newTime &amp;&amp; !seekToStream) { _deactivateAllPreloadingStreams(); } // Outer period seek: Deactivate everything for now else { _deactivateAllPreloadingStreams(); } } /** * Deactivates all preloading streams * @private */ function _deactivateAllPreloadingStreams() { if (preloadingStreams &amp;&amp; preloadingStreams.length &gt; 0) { preloadingStreams.forEach((s) =&gt; { s.deactivate(true); }); preloadingStreams = []; } } /** * Handle an inner period seek. Prepare all StreamProcessors for the seek. * @param {object} e * @private */ function _handleInnerPeriodSeek(e) { const streamProcessors = activeStream.getProcessors(); streamProcessors.forEach((sp) =&gt; { return sp.prepareInnerPeriodPlaybackSeeking(e); }); _flushPlaylistMetrics(PlayListTrace.USER_REQUEST_STOP_REASON); } /** * Handle an outer period seek. Dispatch the corresponding event to be handled in the BufferControllers and the ScheduleControllers * @param {object} e * @param {object} seekToStream * @private */ function _handleOuterPeriodSeek(e, seekToStream) { // Stop segment requests const seekTime = e &amp;&amp; !isNaN(e.seekTime) ? e.seekTime : NaN; const streamProcessors = activeStream.getProcessors(); const promises = streamProcessors.map((sp) =&gt; { // Cancel everything in case the active stream is still buffering return sp.prepareOuterPeriodPlaybackSeeking(e); }); Promise.all(promises) .then(() =&gt; { _switchStream(seekToStream, activeStream, seekTime); }) .catch((e) =&gt; { errHandler.error(e); }); } /** * A track change occured. We deactivate the preloading streams * @param {object} e * @private */ function _onCurrentTrackChanged(e) { // Track was changed in non active stream. No need to do anything, this only happens when a stream starts preloading if (e.newMediaInfo.streamInfo.id !== activeStream.getId()) { return; } // If the track was changed in the active stream we need to stop preloading and remove the already prebuffered stuff. Since we do not support preloading specific handling of specific AdaptationSets yet. _deactivateAllPreloadingStreams(); activeStream.prepareTrackChange(e); } /** * If the source buffer can be reused we can potentially start buffering the next period * @param {object} nextStream * @param {object} previousStream * @return {boolean} * @private */ function _canSourceBuffersBeReused(nextStream, previousStream) { try { // Seamless period switch allowed only if: // - none of the periods uses contentProtection. // - AND changeType method implemented by browser or periods use the same codec. return (settings.get().streaming.buffer.reuseExistingSourceBuffers &amp;&amp; (previousStream.isProtectionCompatible(nextStream) || firstLicenseIsFetched) &amp;&amp; (supportsChangeType || previousStream.isMediaCodecCompatible(nextStream, previousStream))); } catch (e) { return false; } } /** * Initiate the preloading of the next stream * @param {object} nextStream * @param {object} previousStream * @private */ function _onStreamCanLoadNext(nextStream, previousStream = null) { if (mediaSource &amp;&amp; !nextStream.getPreloaded()) { let seamlessPeriodSwitch = _canSourceBuffersBeReused(nextStream, previousStream); if (seamlessPeriodSwitch) { nextStream.startPreloading(mediaSource, bufferSinks) .then(() =&gt; { preloadingStreams.push(nextStream); }); } } } /** * Returns the corresponding stream object for a specific presentation time. * @param {number} time * @return {null|object} */ function getStreamForTime(time) { if (isNaN(time)) { return null; } const ln = streams.length; for (let i = 0; i &lt; ln; i++) { const stream = streams[i]; const streamEnd = parseFloat((stream.getStartTime() + stream.getDuration()).toFixed(5)); if (time &lt; streamEnd) { return stream; } } return null; } /** * Add the DVR window to the metric list. We need the DVR window to restrict the seeking and calculate the right start time. */ function addDVRMetric() { try { const isDynamic = adapter.getIsDynamic(); const streamsInfo = adapter.getStreamsInfo(); const manifestInfo = streamsInfo[0].manifestInfo; const time = playbackController.getTime(); const range = timelineConverter.calcTimeShiftBufferWindow(streams, isDynamic); const activeStreamProcessors = getActiveStreamProcessors(); if (typeof range.start === 'undefined' || typeof range.end === 'undefined') { return; } if (!activeStreamProcessors || activeStreamProcessors.length === 0) { dashMetrics.addDVRInfo(Constants.VIDEO, time, manifestInfo, range); } else { activeStreamProcessors.forEach((sp) =&gt; { dashMetrics.addDVRInfo(sp.getType(), time, manifestInfo, range); }); } } catch (e) { } } /** * The buffer level for a certain media type has been updated. If this is the initial playback and we want to autoplay the content we check if we can start playback now. * For livestreams we might have a drift of the target live delay compared to the current live delay because reaching the initial buffer level took time. * @param {object} e * @private */ function _onBufferLevelUpdated(e) { // check if this is the initial playback and we reached the buffer target. If autoplay is true we start playback if (initialPlayback &amp;&amp; autoPlay) { const initialBufferLevel = mediaPlayerModel.getInitialBufferLevel(); const excludedStreamProcessors = [Constants.TEXT]; if (isNaN(initialBufferLevel) || initialBufferLevel &lt;= playbackController.getBufferLevel(excludedStreamProcessors) || (adapter.getIsDynamic() &amp;&amp; initialBufferLevel &gt; playbackController.getLiveDelay())) { initialPlayback = false; _createPlaylistMetrics(PlayList.INITIAL_PLAYOUT_START_REASON); playbackController.play(); } } if (e &amp;&amp; e.mediaType) { dashMetrics.addBufferLevel(e.mediaType, new Date(), e.bufferLevel * 1000); } } /** * When the quality is changed in the currently active stream and we do an aggressive replacement we must stop prebuffering. This is similar to a replacing track switch * Otherwise preloading can go on. * @param e * @private */ function _onQualityChanged(e) { if (e.streamInfo.id === activeStream.getId() &amp;&amp; e.reason &amp;&amp; e.reason.forceReplace) { _deactivateAllPreloadingStreams(); } const stream = getStreamById(e.streamInfo.id); stream.prepareQualityChange(e); } /** * A setting related to the live delay was updated. Check if one of the latency values changed. If so, recalculate the live delay. * @private */ function _onLiveDelaySettingUpdated() { if (adapter.getIsDynamic() &amp;&amp; playbackController.getOriginalLiveDelay() !== 0) { const streamsInfo = adapter.getStreamsInfo() if (streamsInfo.length &gt; 0) { const manifestInfo = streamsInfo[0].manifestInfo; const fragmentDuration = _getFragmentDurationForLiveDelayCalculation(streamsInfo, manifestInfo); playbackController.computeAndSetLiveDelay(fragmentDuration, manifestInfo); } } } /** * When the playback time is updated we add the droppedFrames metric to the dash metric object * @private */ function _onPlaybackTimeUpdated(/*e*/) { if (hasVideoTrack()) { const playbackQuality = videoModel.getPlaybackQuality(); if (playbackQuality) { dashMetrics.addDroppedFrames(playbackQuality); } } } /** * Once playback starts add playlist metrics depending on whether this was the first playback or playback resumed after pause * @private */ function _onPlaybackStarted( /*e*/) { logger.debug('[onPlaybackStarted]'); if (!initialPlayback &amp;&amp; isPaused) { _createPlaylistMetrics(PlayList.RESUME_FROM_PAUSE_START_REASON); } if (initialPlayback) { initialPlayback = false; } if (initialSteeringRequest) { initialSteeringRequest = false; // If this is the initial playback attempt and we have not yet triggered content steering now is the time if (settings.get().streaming.applyContentSteering &amp;&amp; !contentSteeringController.shouldQueryBeforeStart()) { contentSteeringController.loadSteeringData(); } } isPaused = false; } /** * Once playback is paused flush metrics * @param {object} e * @private */ function _onPlaybackPaused(e) { logger.debug('[onPlaybackPaused]'); if (!e.ended) { isPaused = true; _flushPlaylistMetrics(PlayListTrace.USER_REQUEST_STOP_REASON); } } /** * Callback once a stream/period is completely buffered. We can either signal the end of the stream or start prebuffering the next period. * @param {object} e * @private */ function _onStreamBufferingCompleted(e) { logger.debug(`Stream with id ${e.streamInfo.id} finished buffering`); const isLast = e.streamInfo.isLast; if (mediaSource &amp;&amp; isLast) { logger.info('[onStreamBufferingCompleted] calls signalEndOfStream of mediaSourceController.'); mediaSourceController.signalEndOfStream(mediaSource); } else { _checkIfPrebufferingCanStart(); } } /** * Check if we can start prebuffering the next period. * @private */ function _checkIfPrebufferingCanStart() { // In multiperiod situations, we can start buffering the next stream if (!activeStream || !activeStream.getHasFinishedBuffering()) { return; } const upcomingStreams = _getNextStreams(activeStream); let i = 0; while (i &lt; upcomingStreams.length) { const stream = upcomingStreams[i]; const previousStream = i === 0 ? activeStream : upcomingStreams[i - 1]; // If the preloading for the current stream is not scheduled, but its predecessor has finished buffering we can start prebuffering this stream if (!stream.getPreloaded() &amp;&amp; previousStream.getHasFinishedBuffering()) { if (mediaSource) { _onStreamCanLoadNext(stream, previousStream); } } i += 1; } } /** * In some cases we need to fire the playback ended event manually * @private */ function _startPlaybackEndedTimerInterval() { if (!playbackEndedTimerInterval) { playbackEndedTimerInterval = setInterval(function () { if (!isStreamSwitchingInProgress &amp;&amp; playbackController.getTimeToStreamEnd() &lt;= 0 &amp;&amp; !playbackController.isSeeking()) { eventBus.trigger(Events.PLAYBACK_ENDED, { 'isLast': getActiveStreamInfo().isLast }); } }, PLAYBACK_ENDED_TIMER_INTERVAL); } } /** * Stop the check if the playback has ended * @private */ function _stopPlaybackEndedTimerInterval() { if (playbackEndedTimerInterval) { clearInterval(playbackEndedTimerInterval); playbackEndedTimerInterval = null; } } /** * Returns a playhead time, in seconds, converted to be relative * to the start of an identified stream/period or null if no such stream * @param {number} time * @param {string} id * @returns {number|null} */ function getTimeRelativeToStreamId(time, id) { let stream = null; let baseStart = 0; let streamStart = 0; let streamDur = null; for (let i = 0; i &lt; streams.length; i++) { stream = streams[i]; streamStart = stream.getStartTime(); streamDur = stream.getDuration(); // use start time, if not undefined or NaN or similar if (Number.isFinite(streamStart)) { baseStart = streamStart; } if (stream.getId() === id) { return time - baseStart; } else { // use duration if not undefined or NaN or similar if (Number.isFinite(streamDur)) { baseStart += streamDur; } } } return null; } /** * Returns the streamProcessors of the active stream. * @return {array} */ function getActiveStreamProcessors() { return activeStream ? activeStream.getProcessors() : []; } /** * Once playback has ended we switch to the next stream * @param {object} e */ function _onPlaybackEnded(e) { if (activeStream &amp;&amp; !activeStream.getIsEndedEventSignaled()) { activeStream.setIsEndedEventSignaled(true); const nextStream = _getNextStream(); if (nextStream) { logger.debug(`StreamController onEnded, found next stream with id ${nextStream.getStreamInfo().id}. Switching from ${activeStream.getStreamInfo().id} to ${nextStream.getStreamInfo().id}`); _switchStream(nextStream, activeStream, NaN); } else { logger.debug('StreamController no next stream found'); activeStream.setIsEndedEventSignaled(false); } _flushPlaylistMetrics(nextStream ? PlayListTrace.END_OF_PERIOD_STOP_REASON : PlayListTrace.END_OF_CONTENT_STOP_REASON); } if (e &amp;&amp; e.isLast) { _stopPlaybackEndedTimerInterval(); contentSteeringController.stopSteeringRequestTimer(); } } /** * Returns the next stream to be played relative to the stream provided. If no stream is provided we use the active stream. * In order to avoid rounding issues we should not use the duration of the periods. Instead find the stream with starttime closest to startTime of the previous stream. * @param {object} stream * @return {null|object} */ function _getNextStream(stream = null) { const refStream = stream ? stream : activeStream ? activeStream : null; if (!refStream) { return null; } const refStreamInfo = refStream.getStreamInfo(); const start = refStreamInfo.start; let i = 0; let targetIndex = -1; let lastDiff = NaN; while (i &lt; streams.length) { const s = streams[i]; const sInfo = s.getStreamInfo(); const diff = sInfo.start - start; if (diff &gt; 0 &amp;&amp; (isNaN(lastDiff) || diff &lt; lastDiff) &amp;&amp; refStreamInfo.id !== sInfo.id) { lastDiff = diff; targetIndex = i; } i += 1; } if (targetIndex &gt;= 0) { return streams[targetIndex]; } return null; } /** * Returns all upcoming streams relative to the provided stream. If no stream is provided we use the active stream. * @param {object} stream * @return {array} */ function _getNextStreams(stream = null) { try { const refStream = stream ? stream : activeStream ? activeStream : null; if (refStream) { const refStreamInfo = refStream.getStreamInfo(); return streams.filter(function (stream) { const sInfo = stream.getStreamInfo(); return sInfo.start &gt; refStreamInfo.start &amp;&amp; refStreamInfo.id !== sInfo.id; }); } } catch (e) { return []; } } /** * Sets the duration attribute of the MediaSource using the MediaSourceController. * @param {number} duration * @private */ function _setMediaDuration(duration) { const manifestDuration = duration ? duration : getActiveStreamInfo().manifestInfo.duration; mediaSourceController.setDuration(manifestDuration); } /** * Returns the active stream * @return {object} */ function getActiveStream() { return activeStream; } /** * Initial playback indicates if we have called play() for the first time yet. * @return {*} */ function getInitialPlayback() { return initialPlayback; } /** * Auto Play indicates if the stream starts automatically as soon as it is initialized. * @return {boolean} */ function getAutoPlay() { return autoPlay; } /** * Called once the first stream has been initialized. We only use this function to seek to the right start time. * @return {number} * @private */ function _getInitialStartTime() { // Seek new stream in priority order: // - at start time provided via the application // - at start time provided in URI parameters // - at stream/period start time (for static streams) or live start time (for dynamic streams) let startTime; const isDynamic = adapter.getIsDynamic(); if (isDynamic) { // For dynamic stream, start by default at (live edge - live delay) const dvrInfo = dashMetrics.getCurrentDVRInfo(); const liveEdge = dvrInfo &amp;&amp; dvrInfo.range ? dvrInfo.range.end : 0; // we are already in the right start period. so time should not be smaller than period@start and should not be larger than period@end startTime = liveEdge - playbackController.getOriginalLiveDelay(); // If start time in URI, take min value between live edge time and time from URI (capped by DVR window range) const dvrWindow = dvrInfo ? dvrInfo.range : null; if (dvrWindow) { // If start time was provided by the application as part of the call to initialize() or attachSource() use this value if (!isNaN(providedStartTime) || providedStartTime.toString().indexOf('posix:') !== -1) { logger.info(`Start time provided by the app: ${providedStartTime}`); const providedStartTimeAsPresentationTime = _getStartTimeFromProvidedData(true, providedStartTime) if (!isNaN(providedStartTimeAsPresentationTime)) { // Do not move closer to the live edge as defined by live delay startTime = Math.min(startTime, providedStartTimeAsPresentationTime); } } else { // #t shall be relative to period start const startTimeFromUri = _getStartTimeFromUriParameters(true); if (!isNaN(startTimeFromUri)) { logger.info(`Start time from URI parameters: ${startTimeFromUri}`); // Do not move closer to the live edge as defined by live delay startTime = Math.min(startTime, startTimeFromUri); } } // If calcFromSegmentTimeline is enabled we saw problems caused by the MSE.seekableRange when starting at dvrWindow.start. Apply a small offset to avoid this problem. const offset = settings.get().streaming.timeShiftBuffer.calcFromSegmentTimeline ? 0.1 : 0; startTime = Math.max(startTime, dvrWindow.start + offset); } } else { // For static stream, start by default at period start const streams = getStreams(); const streamInfo = streams[0].getStreamInfo(); startTime = streamInfo.start; // If start time was provided by the application as part of the call to initialize() or attachSource() use this value if (!isNaN(providedStartTime)) { logger.info(`Start time provided by the app: ${providedStartTime}`); const providedStartTimeAsPresentationTime = _getStartTimeFromProvidedData(false, providedStartTime) if (!isNaN(providedStartTimeAsPresentationTime)) { // Do not play earlier than the start of the first period startTime = Math.max(startTime, providedStartTimeAsPresentationTime); } } else { // If start time in URI, take max value between period start and time from URI (if in period range) const startTimeFromUri = _getStartTimeFromUriParameters(false); if (!isNaN(startTimeFromUri)) { logger.info(`Start time from URI parameters: ${startTimeFromUri}`); // Do not play earlier than the start of the first period startTime = Math.max(startTime, startTimeFromUri); } } } return startTime; } /** * 23009-1 Annex C.4 defines MPD anchors to use URI fragment syntax to start a presentation at a given time and a given state * @param {boolean} isDynamic * @return {number} * @private */ function _getStartTimeFromUriParameters(isDynamic) { const fragData = uriFragmentModel.getURIFragmentData(); if (!fragData || !fragData.t) { return NaN; } const refStream = getStreams()[0]; const referenceTime = refStream.getStreamInfo().start; fragData.t = fragData.t.split(',')[0]; return _getStartTimeFromString(isDynamic, fragData.t, referenceTime); } /** * Calculate start time using the value that was provided via the application as part of attachSource() or initialize() * @param {boolean} isDynamic * @param {number | string} providedStartTime * @return {number} * @private */ function _getStartTimeFromProvidedData(isDynamic, providedStartTime) { let referenceTime = 0; if (!isDynamic) { const refStream = getStreams()[0]; referenceTime = refStream.getStreamInfo().start; } return _getStartTimeFromString(isDynamic, providedStartTime, referenceTime); } function _getStartTimeFromString(isDynamic, targetValue, referenceTime) { // Consider only start time of MediaRange // TODO: consider end time of MediaRange to stop playback at provided end time // \"t=&lt;time&gt;\" : time is relative to 1st period start // \"t=posix:&lt;time&gt;\" : time is absolute start time as number of seconds since 01-01-1970 const period = adapter.getRegularPeriods()[0]; const targetString = targetValue.toString(); const posix = targetString.indexOf('posix:') !== -1 ? targetString.substring(6) === 'now' ? Date.now() / 1000 : parseFloat(targetString.substring(6)) : NaN; let startTime = (isDynamic &amp;&amp; !isNaN(posix)) ? timelineConverter.calcPresentationTimeFromWallTime(new Date(posix * 1000), period) : parseFloat(targetString) + referenceTime; return startTime; } /** * Streams that are no longer in the manifest can be filtered * @param {object} streamsInfo * @private */ function _filterOutdatedStreams(streamsInfo) { if (streamsInfo.length === 0) { logger.warn(`No periods included in the current manifest. Skipping the filtering of outdated stream objects.`); return; } streams = streams.filter((stream) =&gt; { const isStillIncluded = streamsInfo.filter((sInfo) =&gt; { return sInfo.id === stream.getId(); }).length &gt; 0; const shouldKeepStream = isStillIncluded || stream.getId() === activeStream.getId(); if (!shouldKeepStream) { logger.debug(`Removing stream ${stream.getId()}`); stream.reset(true); } return shouldKeepStream; }); } /** * In order to calculate the initial live delay we might required the duration of the segments. * @param {array} streamInfos * @param {object} manifestInfo * @return {number} * @private */ function _getFragmentDurationForLiveDelayCalculation(streamInfos, manifestInfo) { try { let fragmentDuration = NaN; // We use the maxFragmentDuration attribute if present if (manifestInfo &amp;&amp; !isNaN(manifestInfo.maxFragmentDuration) &amp;&amp; isFinite(manifestInfo.maxFragmentDuration)) { return manifestInfo.maxFragmentDuration; } // For single period manifests we can iterate over all AS and use the maximum segment length if (streamInfos &amp;&amp; streamInfos.length === 1) { const streamInfo = streamInfos[0]; const mediaTypes = [Constants.VIDEO, Constants.AUDIO, Constants.TEXT]; const fragmentDurations = mediaTypes .reduce((acc, mediaType) =&gt; { const mediaInfo = adapter.getMediaInfoForType(streamInfo, mediaType); if (mediaInfo &amp;&amp; mediaInfo.isFragmented !== false) { acc.push(mediaInfo); } return acc; }, []) .reduce((acc, mediaInfo) =&gt; { const voRepresentations = adapter.getVoRepresentations(mediaInfo); if (voRepresentations &amp;&amp; voRepresentations.length &gt; 0) { voRepresentations.forEach((voRepresentation) =&gt; { if (voRepresentation) { acc.push(voRepresentation); } }); } return acc; }, []) .reduce((acc, voRepresentation) =&gt; { const representation = adapter.convertRepresentationToRepresentationInfo(voRepresentation); if (representation &amp;&amp; representation.fragmentDuration &amp;&amp; !isNaN(representation.fragmentDuration)) { acc.push(representation.fragmentDuration); } return acc; }, []); fragmentDuration = Math.max(...fragmentDurations); } return isFinite(fragmentDuration) ? fragmentDuration : NaN; } catch (e) { return NaN; } } /** * Callback handler after the manifest has been updated. Trigger an update in the adapter and filter unsupported stuff. * Finally attempt UTC sync * @param {object} e * @private */ function _onManifestUpdated(e) { if (!e.error) { logger.info('Manifest updated... updating data system wide.'); //Since streams are not composed yet , need to manually look up useCalculatedLiveEdgeTime to detect if stream //is SegmentTimeline to avoid using time source const manifest = e.manifest; adapter.updatePeriods(manifest); let manifestUTCTimingSources = adapter.getUTCTimingSources(); if (adapter.getIsDynamic() &amp;&amp; (!manifestUTCTimingSources || manifestUTCTimingSources.length === 0)) { eventBus.trigger(MediaPlayerEvents.CONFORMANCE_VIOLATION, { level: ConformanceViolationConstants.LEVELS.WARNING, event: ConformanceViolationConstants.EVENTS.NO_UTC_TIMING_ELEMENT }); } let allUTCTimingSources = (!adapter.getIsDynamic()) ? manifestUTCTimingSources : manifestUTCTimingSources.concat(customParametersModel.getUTCTimingSources()); const isHTTPS = urlUtils.isHTTPS(e.manifest.url); //If https is detected on manifest then lets apply that protocol to only the default time source(s). In the future we may find the need to apply this to more then just default so left code at this level instead of in MediaPlayer. allUTCTimingSources.forEach(function (item) { if (item.value.replace(/.*?:\\/\\//g, '') === settings.get().streaming.utcSynchronization.defaultTimingSource.value.replace(/.*?:\\/\\//g, '')) { item.value = item.value.replace(isHTTPS ? new RegExp(/^(http:)?\\/\\//i) : new RegExp(/^(https:)?\\/\\//i), isHTTPS ? 'https://' : 'http://'); logger.debug('Matching default timing source protocol to manifest protocol: ', item.value); } }); // It is important to filter before initializing the baseUrlController. Otherwise we might end up with wrong references in case we remove AdaptationSets. capabilitiesFilter.filterUnsupportedFeatures(manifest) .then(() =&gt; { baseURLController.initialize(manifest); timeSyncController.attemptSync(allUTCTimingSources, adapter.getIsDynamic()); }); } else { hasInitialisationError = true; reset(); } } /** * Check if the stream has a video track * @return {boolean} */ function hasVideoTrack() { return activeStream ? activeStream.getHasVideoTrack() : false; } /** * Check if the stream has an audio track * @return {boolean} */ function hasAudioTrack() { return activeStream ? activeStream.getHasAudioTrack() : false; } function switchToVideoElement(seekTime) { if (activeStream) { playbackController.initialize(getActiveStreamInfo()); _openMediaSource(seekTime, false); } } function _flushPlaylistMetrics(reason, time) { time = time || new Date(); getActiveStreamProcessors().forEach(p =&gt; { p.finalisePlayList(time, reason); }); dashMetrics.addPlayList(); } function _createPlaylistMetrics(startReason) { dashMetrics.createPlaylistMetrics(playbackController.getTime() * 1000, startReason); } function _onPlaybackError(e) { if (!e.error) return; let msg = ''; switch (e.error.code) { case 1: msg = 'MEDIA_ERR_ABORTED'; break; case 2: msg = 'MEDIA_ERR_NETWORK'; break; case 3: msg = 'MEDIA_ERR_DECODE'; errorInformation.counts.mediaErrorDecode += 1; break; case 4: msg = 'MEDIA_ERR_SRC_NOT_SUPPORTED'; break; case 5: msg = 'MEDIA_ERR_ENCRYPTED'; break; default: msg = 'UNKNOWN'; break; } if (msg === 'MEDIA_ERR_DECODE' &amp;&amp; settings.get().errors.recoverAttempts.mediaErrorDecode &gt;= errorInformation.counts.mediaErrorDecode) { _handleMediaErrorDecode(); return; } hasMediaError = true; if (e.error.message) { msg += ' (' + e.error.message + ')'; } if (e.error.msExtendedCode) { msg += ' (0x' + (e.error.msExtendedCode &gt;&gt;&gt; 0).toString(16).toUpperCase() + ')'; } logger.fatal('Video Element Error: ' + msg); if (e.error) { logger.fatal(e.error); } errHandler.error(new DashJSError(e.error.code, msg)); reset(); } /** * Handles mediaError * @private */ function _handleMediaErrorDecode() { logger.warn('A MEDIA_ERR_DECODE occured: Resetting the MediaSource'); const time = playbackController.getTime(); // Deactivate the current stream. activeStream.deactivate(false); // Reset MSE logger.warn(`MediaSource has been resetted. Resuming playback from time ${time}`); _openMediaSource(time, false); } function getActiveStreamInfo() { return activeStream ? activeStream.getStreamInfo() : null; } function getIsStreamSwitchInProgress() { return isStreamSwitchingInProgress; } function getHasMediaOrInitialisationError() { return hasMediaError || hasInitialisationError; } function getStreamById(id) { for (let i = 0, ln = streams.length; i &lt; ln; i++) { if (streams[i].getId() === id) { return streams[i]; } } return null; } function _onManifestValidityChanged(e) { if (!isNaN(e.newDuration)) { _setMediaDuration(e.newDuration); } } function setConfig(config) { if (!config) return; if (config.capabilities) { capabilities = config.capabilities; } if (config.capabilitiesFilter) { capabilitiesFilter = config.capabilitiesFilter; } if (config.manifestLoader) { manifestLoader = config.manifestLoader; } if (config.manifestModel) { manifestModel = config.manifestModel; } if (config.mediaPlayerModel) { mediaPlayerModel = config.mediaPlayerModel; } if (config.customParametersModel) { customParametersModel = config.customParametersModel; } if (config.protectionController) { protectionController = config.protectionController; } if (config.adapter) { adapter = config.adapter; } if (config.dashMetrics) { dashMetrics = config.dashMetrics; } if (config.errHandler) { errHandler = config.errHandler; } if (config.timelineConverter) { timelineConverter = config.timelineConverter; } if (config.videoModel) { videoModel = config.videoModel; } if (config.playbackController) { playbackController = config.playbackController; } if (config.serviceDescriptionController) { serviceDescriptionController = config.serviceDescriptionController; } if (config.contentSteeringController) { contentSteeringController = config.contentSteeringController; } if (config.textController) { textController = config.textController; } if (config.abrController) { abrController = config.abrController; } if (config.mediaController) { mediaController = config.mediaController; } if (config.settings) { settings = config.settings; } if (config.baseURLController) { baseURLController = config.baseURLController; } if (config.uriFragmentModel) { uriFragmentModel = config.uriFragmentModel; } if (config.segmentBaseController) { segmentBaseController = config.segmentBaseController; } } function setProtectionData(protData) { protectionData = protData; if (protectionController) { protectionController.setProtectionData(protectionData); } } function resetInitialSettings() { streams = []; providedStartTime = NaN; protectionController = null; isStreamSwitchingInProgress = false; activeStream = null; hasMediaError = false; hasInitialisationError = false; initialPlayback = true; initialSteeringRequest = true; isPaused = false; autoPlay = true; playbackEndedTimerInterval = null; firstLicenseIsFetched = false; supportsChangeType = false; preloadingStreams = []; waitForPlaybackStartTimeout = null; errorInformation = { counts: { mediaErrorDecode: 0 } } } function reset() { _checkConfig(); timeSyncController.reset(); _flushPlaylistMetrics(hasMediaError || hasInitialisationError ? PlayListTrace.FAILURE_STOP_REASON : PlayListTrace.USER_REQUEST_STOP_REASON); for (let i = 0, ln = streams ? streams.length : 0; i &lt; ln; i++) { const stream = streams[i]; stream.reset(hasMediaError); } unRegisterEvents(); baseURLController.reset(); manifestUpdater.reset(); eventController.reset(); dashMetrics.clearAllCurrentMetrics(); manifestModel.setValue(null); manifestLoader.reset(); timelineConverter.reset(); initCache.reset(); if (mediaSource) { mediaSourceController.detachMediaSource(videoModel); mediaSource = null; } videoModel = null; if (protectionController) { protectionController = null; protectionData = null; if (manifestModel.getValue()) { eventBus.trigger(Events.PROTECTION_DESTROYED, { data: manifestModel.getValue().url }); } } _stopPlaybackEndedTimerInterval(); eventBus.trigger(Events.STREAM_TEARDOWN_COMPLETE); resetInitialSettings(); } function _onMetricAdded(e) { if (e.metric === MetricsConstants.DVR_INFO) { //Match media type? How can DVR window be different for media types? //Should we normalize and union the two? const targetMediaType = hasAudioTrack() ? Constants.AUDIO : Constants.VIDEO; if (e.mediaType === targetMediaType) { mediaSourceController.setSeekable(e.value.range.start, e.value.range.end); } } } function getStreams() { return streams; } instance = { initialize, getActiveStreamInfo, addDVRMetric, hasVideoTrack, hasAudioTrack, getStreamById, getStreamForTime, getTimeRelativeToStreamId, load, loadWithManifest, getActiveStreamProcessors, setConfig, setProtectionData, getIsStreamSwitchInProgress, switchToVideoElement, getHasMediaOrInitialisationError, getStreams, getActiveStream, getInitialPlayback, getAutoPlay, reset }; setup(); return instance; } StreamController.__dashjs_factory_name = 'StreamController'; export default FactoryMaker.getSingletonFactory(StreamController); × Search results Close "},"streaming_StreamProcessor.js.html":{"id":"streaming_StreamProcessor.js.html","title":"Source: streaming/StreamProcessor.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/StreamProcessor.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from './constants/Constants'; import DashConstants from '../dash/constants/DashConstants'; import MetricsConstants from './constants/MetricsConstants'; import FragmentModel from './models/FragmentModel'; import BufferController from './controllers/BufferController'; import NotFragmentedTextBufferController from './text/NotFragmentedTextBufferController'; import ScheduleController from './controllers/ScheduleController'; import RepresentationController from '../dash/controllers/RepresentationController'; import FactoryMaker from '../core/FactoryMaker'; import {checkInteger} from './utils/SupervisorTools'; import EventBus from '../core/EventBus'; import Events from '../core/events/Events'; import DashHandler from '../dash/DashHandler'; import Errors from '../core/errors/Errors'; import DashJSError from './vo/DashJSError'; import Debug from '../core/Debug'; import RequestModifier from './utils/RequestModifier'; import URLUtils from '../streaming/utils/URLUtils'; import BoxParser from './utils/BoxParser'; import {PlayListTrace} from './vo/metrics/PlayList'; import SegmentsController from '../dash/controllers/SegmentsController'; import {HTTPRequest} from './vo/metrics/HTTPRequest'; function StreamProcessor(config) { config = config || {}; let context = this.context; let eventBus = EventBus(context).getInstance(); let streamInfo = config.streamInfo; let type = config.type; let errHandler = config.errHandler; let mimeType = config.mimeType; let timelineConverter = config.timelineConverter; let adapter = config.adapter; let manifestModel = config.manifestModel; let mediaPlayerModel = config.mediaPlayerModel; let fragmentModel = config.fragmentModel; let abrController = config.abrController; let playbackController = config.playbackController; let mediaController = config.mediaController; let textController = config.textController; let dashMetrics = config.dashMetrics; let settings = config.settings; let boxParser = config.boxParser; let segmentBlacklistController = config.segmentBlacklistController; let instance, logger, isDynamic, mediaInfo, mediaInfoArr, bufferController, scheduleController, representationController, shouldUseExplicitTimeForRequest, qualityChangeInProgress, dashHandler, segmentsController, bufferingTime; function setup() { logger = Debug(context).getInstance().getLogger(instance); resetInitialSettings(); eventBus.on(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance, { priority: EventBus.EVENT_PRIORITY_HIGH }); // High priority to be notified before Stream eventBus.on(Events.INIT_FRAGMENT_NEEDED, _onInitFragmentNeeded, instance); eventBus.on(Events.MEDIA_FRAGMENT_NEEDED, _onMediaFragmentNeeded, instance); eventBus.on(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, instance); eventBus.on(Events.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance); eventBus.on(Events.BUFFER_CLEARED, _onBufferCleared, instance); eventBus.on(Events.SEEK_TARGET, _onSeekTarget, instance); eventBus.on(Events.FRAGMENT_LOADING_ABANDONED, _onFragmentLoadingAbandoned, instance); eventBus.on(Events.FRAGMENT_LOADING_COMPLETED, _onFragmentLoadingCompleted, instance); eventBus.on(Events.QUOTA_EXCEEDED, _onQuotaExceeded, instance); eventBus.on(Events.SET_FRAGMENTED_TEXT_AFTER_DISABLED, _onSetFragmentedTextAfterDisabled, instance); eventBus.on(Events.SET_NON_FRAGMENTED_TEXT, _onSetNonFragmentedText, instance); eventBus.on(Events.SOURCE_BUFFER_ERROR, _onSourceBufferError, instance); } function initialize(mediaSource, hasVideoTrack, isFragmented) { segmentsController = SegmentsController(context).create({ events: Events, eventBus, streamInfo, timelineConverter, dashConstants: DashConstants, segmentBaseController: config.segmentBaseController, type }); dashHandler = DashHandler(context).create({ streamInfo, type, timelineConverter, dashMetrics, mediaPlayerModel, baseURLController: config.baseURLController, errHandler, segmentsController, settings, boxParser, events: Events, eventBus, errors: Errors, debug: Debug(context).getInstance(), requestModifier: RequestModifier(context).getInstance(), dashConstants: DashConstants, constants: Constants, urlUtils: URLUtils(context).getInstance() }); isDynamic = streamInfo.manifestInfo.isDynamic; // Create/initialize controllers dashHandler.initialize(isDynamic); abrController.registerStreamType(type, instance); representationController = RepresentationController(context).create({ streamInfo, type, abrController, dashMetrics, playbackController, timelineConverter, dashConstants: DashConstants, events: Events, eventBus, errors: Errors, isDynamic, segmentsController }); bufferController = _createBufferControllerForType(type, isFragmented); if (bufferController) { bufferController.initialize(mediaSource); } scheduleController = ScheduleController(context).create({ streamInfo, type, mimeType, adapter, dashMetrics, mediaPlayerModel, fragmentModel, abrController, playbackController, textController, mediaController, bufferController, settings }); scheduleController.initialize(hasVideoTrack); bufferingTime = 0; shouldUseExplicitTimeForRequest = false; } function getStreamId() { return streamInfo.id; } function getType() { return type; } function getIsTextTrack() { return adapter.getIsTextTrack(representationController.getData()); } function resetInitialSettings() { mediaInfoArr = []; mediaInfo = null; bufferingTime = 0; shouldUseExplicitTimeForRequest = false; qualityChangeInProgress = false; } function reset(errored, keepBuffers) { if (dashHandler) { dashHandler.reset(); } if (bufferController) { bufferController.reset(errored, keepBuffers); bufferController = null; } if (scheduleController) { scheduleController.reset(); scheduleController = null; } if (representationController) { representationController.reset(); representationController = null; } if (segmentsController) { segmentsController = null; } if (abrController) { abrController.unRegisterStreamType(getStreamId(), type); } eventBus.off(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance); eventBus.off(Events.INIT_FRAGMENT_NEEDED, _onInitFragmentNeeded, instance); eventBus.off(Events.MEDIA_FRAGMENT_NEEDED, _onMediaFragmentNeeded, instance); eventBus.off(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, instance); eventBus.off(Events.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance); eventBus.off(Events.BUFFER_CLEARED, _onBufferCleared, instance); eventBus.off(Events.SEEK_TARGET, _onSeekTarget, instance); eventBus.off(Events.FRAGMENT_LOADING_ABANDONED, _onFragmentLoadingAbandoned, instance); eventBus.off(Events.FRAGMENT_LOADING_COMPLETED, _onFragmentLoadingCompleted, instance); eventBus.off(Events.SET_FRAGMENTED_TEXT_AFTER_DISABLED, _onSetFragmentedTextAfterDisabled, instance); eventBus.off(Events.SET_NON_FRAGMENTED_TEXT, _onSetNonFragmentedText, instance); eventBus.off(Events.QUOTA_EXCEEDED, _onQuotaExceeded, instance); eventBus.off(Events.SOURCE_BUFFER_ERROR, _onSourceBufferError, instance); resetInitialSettings(); type = null; streamInfo = null; } function isUpdating() { return representationController ? representationController.isUpdating() : false; } /** * When a seek within the corresponding period occurs this function initiates the clearing of the buffer and sets the correct buffering time. * @param {object} e * @private */ function prepareInnerPeriodPlaybackSeeking(e) { return new Promise((resolve) =&gt; { // Stop segment requests until we have figured out for which time we need to request a segment. We don't want to replace existing segments. scheduleController.clearScheduleTimer(); fragmentModel.abortRequests(); // Abort operations to the SourceBuffer Sink and reset the BufferControllers isBufferingCompleted state. bufferController.prepareForPlaybackSeek() .then(() =&gt; { // Clear the buffer. We need to prune everything which is not in the target interval. const clearRanges = bufferController.getAllRangesWithSafetyFactor(e.seekTime); // When everything has been pruned go on return bufferController.clearBuffers(clearRanges); }) .then(() =&gt; { // Figure out the correct segment request time. const continuousBufferTime = bufferController.getContinuousBufferTimeForTargetTime(e.seekTime); // If the buffer is continuous and exceeds the duration of the period we are still done buffering. We need to trigger the buffering completed event in order to start prebuffering upcoming periods again if (!isNaN(continuousBufferTime) &amp;&amp; !isNaN(streamInfo.duration) &amp;&amp; isFinite(streamInfo.duration) &amp;&amp; continuousBufferTime &gt;= streamInfo.start + streamInfo.duration) { bufferController.setIsBufferingCompleted(true); resolve(); } else { const targetTime = isNaN(continuousBufferTime) ? e.seekTime : continuousBufferTime; setExplicitBufferingTime(targetTime); bufferController.setSeekTarget(targetTime); const promises = []; // append window has been reset by abort() operation. Set the correct values again promises.push(bufferController.updateAppendWindow()); // Timestamp offset couldve been changed by preloading period const representationInfo = getRepresentationInfo(); promises.push(bufferController.updateBufferTimestampOffset(representationInfo)); Promise.all(promises) .then(() =&gt; { // We might have aborted the append operation of an init segment. Append init segment again. scheduleController.setInitSegmentRequired(true); // Right after a seek we should not immediately check the playback quality scheduleController.setCheckPlaybackQuality(false); scheduleController.startScheduleTimer(); resolve(); }); } }) .catch((e) =&gt; { logger.error(e); }); }); } /** * Seek outside of the current period. * @return {Promise&lt;unknown&gt;} */ function prepareOuterPeriodPlaybackSeeking() { return new Promise((resolve, reject) =&gt; { try { // Stop scheduling scheduleController.clearScheduleTimer(); // Abort all ongoing requests fragmentModel.abortRequests(); // buffering not complete anymore and abort current append operation to SourceBuffer bufferController.prepareForPlaybackSeek() .then(() =&gt; { // Clear the buffers completely. return bufferController.pruneAllSafely(); }) .then(() =&gt; { resolve(); }); } catch (e) { reject(e); } }); } /** * ScheduleController indicates that an init segment needs to be fetched. * @param {object} e * @param {boolean} rescheduleIfNoRequest - Defines whether we reschedule in case no valid request could be generated * @private */ function _onInitFragmentNeeded(e, rescheduleIfNoRequest = true) { // Event propagation may have been stopped (see MssHandler) if (!e.sender) return; if (playbackController.getIsManifestUpdateInProgress()) { _noValidRequest(); return; } if (getIsTextTrack() &amp;&amp; !textController.isTextEnabled()) return; if (bufferController &amp;&amp; e.representationId) { if (!bufferController.appendInitSegmentFromCache(e.representationId)) { const rep = representationController.getCurrentRepresentation(); // Dummy init segment (fragmented tracks without initialization segment) if (rep.range === 0) { _onMediaFragmentNeeded(); return; } // Init segment not in cache, send new request const request = dashHandler ? dashHandler.getInitRequest(mediaInfo, rep) : null; if (request) { fragmentModel.executeRequest(request); } else if (rescheduleIfNoRequest) { scheduleController.setInitSegmentRequired(true); _noValidRequest(); } } } } /** * ScheduleController indicates that a media segment is needed * @param {boolean} rescheduleIfNoRequest - Defines whether we reschedule in case no valid request could be generated * @private */ function _onMediaFragmentNeeded(e, rescheduleIfNoRequest = true) { // Don't schedule next fragments while updating manifest or pruning to avoid buffer inconsistencies if (playbackController.getIsManifestUpdateInProgress() || bufferController.getIsPruningInProgress()) { _noValidRequest(); return; } let request = _getFragmentRequest(); if (request) { shouldUseExplicitTimeForRequest = false; _mediaRequestGenerated(request); } else { _noMediaRequestGenerated(rescheduleIfNoRequest); } } /** * If we generated a valid media request we can execute the request. In some cases the segment might be blacklisted. * @param {object} request * @private */ function _mediaRequestGenerated(request) { if (!isNaN(request.startTime + request.duration)) { bufferingTime = request.startTime + request.duration; } request.delayLoadingTime = new Date().getTime() + scheduleController.getTimeToLoadDelay(); scheduleController.setTimeToLoadDelay(0); if (!_shouldIgnoreRequest(request)) { logger.debug(`Next fragment request url for stream id ${streamInfo.id} and media type ${type} is ${request.url}`); fragmentModel.executeRequest(request); } else { logger.warn(`Fragment request url ${request.url} for stream id ${streamInfo.id} and media type ${type} is on the ignore list and will be skipped`); _noValidRequest(); } } /** * We could not generate a valid request. Check if the media is finished, we are stuck in a gap or simply need to wait for the next segment to be available. * @param {boolean} rescheduleIfNoRequest * @private */ function _noMediaRequestGenerated(rescheduleIfNoRequest) { const representation = representationController.getCurrentRepresentation(); // If this statement is true we might be stuck. A static manifest does not change and we did not find a valid request for the target time // There is no point in trying again. We need to adjust the time in order to find a valid request. This can happen if the user/app seeked into a gap. // For dynamic manifests this can also happen especially if we jump over the gap in the previous period and are using SegmentTimeline and in case there is a positive eptDelta at the beginning of the period we are stuck. if (settings.get().streaming.gaps.enableSeekFix &amp;&amp; (shouldUseExplicitTimeForRequest || playbackController.getTime() === 0)) { let adjustedTime; if (!isDynamic) { adjustedTime = dashHandler.getValidTimeAheadOfTargetTime(bufferingTime, mediaInfo, representation, settings.get().streaming.gaps.threshold); } else if (isDynamic &amp;&amp; representation.segmentInfoType === DashConstants.SEGMENT_TIMELINE) { // If we find a valid request ahead of the current time then we are in a gap. Segments are only added at the end of the timeline adjustedTime = dashHandler.getValidTimeAheadOfTargetTime(bufferingTime, mediaInfo, representation, settings.get().streaming.gaps.threshold,); } if (!isNaN(adjustedTime) &amp;&amp; adjustedTime !== bufferingTime) { if (playbackController.isSeeking() || playbackController.getTime() === 0) { // If we are seeking then playback is stalled. Do a seek to get out of this situation logger.warn(`Adjusting playback time ${adjustedTime} because of gap in the manifest. Seeking by ${adjustedTime - bufferingTime}`); playbackController.seek(adjustedTime, false, false); } else { // If we are not seeking we should still be playing but we cant find anything to buffer. So we adjust the buffering time and leave the gap jump to the GapController logger.warn(`Adjusting buffering time ${adjustedTime} because of gap in the manifest. Adjusting time by ${adjustedTime - bufferingTime}`); setExplicitBufferingTime(adjustedTime) if (rescheduleIfNoRequest) { _noValidRequest(); } } return; } } // Check if the media is finished. If so, no need to schedule another request const isLastSegmentRequested = dashHandler.isLastSegmentRequested(representation, bufferingTime); if (isLastSegmentRequested) { const segmentIndex = dashHandler.getCurrentIndex(); logger.debug(`Segment requesting for stream ${streamInfo.id} has finished`); eventBus.trigger(Events.STREAM_REQUESTING_COMPLETED, { segmentIndex }, { streamId: streamInfo.id, mediaType: type }); bufferController.segmentRequestingCompleted(segmentIndex); scheduleController.clearScheduleTimer(); return; } if (rescheduleIfNoRequest) { _noValidRequest(); } } /** * In certain situations we need to ignore a request. For instance, if a segment is blacklisted because it caused an MSE error. * @private */ function _shouldIgnoreRequest(request) { let blacklistUrl = request.url; if (request.range) { blacklistUrl = blacklistUrl.concat('_', request.range); } return segmentBlacklistController.contains(blacklistUrl) } /** * Get the init or media segment request using the DashHandler. * @return {null|FragmentRequest|null} * @private */ function _getFragmentRequest() { const representationInfo = getRepresentationInfo(); let request; if (isNaN(bufferingTime) || (getType() === Constants.TEXT &amp;&amp; !textController.isTextEnabled())) { return null; } // Use time just whenever is strictly needed const useTime = shouldUseExplicitTimeForRequest; if (dashHandler) { const representation = representationController &amp;&amp; representationInfo ? representationController.getRepresentationForQuality(representationInfo.quality) : null; if (useTime) { request = dashHandler.getSegmentRequestForTime(mediaInfo, representation, bufferingTime); } else { request = dashHandler.getNextSegmentRequest(mediaInfo, representation); } } return request; } /** * Whenever we can not generate a valid request we restart scheduling according to the timeouts defined in the settings. * @private */ function _noValidRequest() { scheduleController.startScheduleTimer(playbackController.getLowLatencyModeEnabled() ? settings.get().streaming.scheduling.lowLatencyTimeout : settings.get().streaming.scheduling.defaultTimeout); } function _onDataUpdateCompleted(e) { if (!e.error) { // Update representation if no error scheduleController.setCurrentRepresentation(adapter.convertRepresentationToRepresentationInfo(e.currentRepresentation)); if (!bufferController.getIsBufferingCompleted()) { bufferController.updateBufferTimestampOffset(e.currentRepresentation); } } } function _onBufferLevelStateChanged(e) { dashMetrics.addBufferState(type, e.state, scheduleController.getBufferTarget()); if (e.state === MetricsConstants.BUFFER_EMPTY &amp;&amp; !playbackController.isSeeking()) { logger.info('Buffer is empty! Stalling!'); dashMetrics.pushPlayListTraceMetrics(new Date(), PlayListTrace.REBUFFERING_REASON); } } function _onBufferCleared(e) { // Remove executed requests not buffered anymore fragmentModel.syncExecutedRequestsWithBufferedRange( bufferController.getBuffer().getAllBufferRanges(), streamInfo.duration); // If buffer removed ahead current time (QuotaExceededError or automatic buffer pruning) then adjust current index handler time if (e.quotaExceeded &amp;&amp; e.from &gt; playbackController.getTime()) { setExplicitBufferingTime(e.from); } // (Re)start schedule once buffer has been pruned after a QuotaExceededError if (e.hasEnoughSpaceToAppend &amp;&amp; e.quotaExceeded) { scheduleController.startScheduleTimer(); } } /** * This function is called when the corresponding SourceBuffer encountered an error. * We blacklist the last segment assuming it caused the error * @param {object} e * @private */ function _onSourceBufferError(e) { if (!e || !e.lastRequestAppended || !e.lastRequestAppended.url) { return; } let blacklistUrl = e.lastRequestAppended.url; if (e.lastRequestAppended.range) { blacklistUrl = blacklistUrl.concat('_', e.lastRequestAppended.range); } logger.warn(`Blacklisting segment with url ${blacklistUrl}`); segmentBlacklistController.add(blacklistUrl); } /** * The quality has changed which means we have switched to a different representation. * If we want to aggressively replace existing parts in the buffer we need to make sure that the new quality is higher than the already buffered one. * @param {object} e * @private */ function prepareQualityChange(e) { logger.debug(`Preparing quality switch for type ${type}`); const newQuality = e.newQuality; qualityChangeInProgress = true; // Stop scheduling until we are done with preparing the quality switch scheduleController.clearScheduleTimer(); const representationInfo = getRepresentationInfo(newQuality); scheduleController.setCurrentRepresentation(representationInfo); representationController.prepareQualityChange(newQuality); // Abort the current request to avoid inconsistencies and in case a rule such as AbandonRequestRule has forced a quality switch. A quality switch can also be triggered manually by the application. // If we update the buffer values now, or initialize a request to the new init segment, the currently downloading media segment might \"work\" with wrong values. // Everything that is already in the buffer queue is ok and will be handled by the corresponding function below depending on the switch mode. fragmentModel.abortRequests(); // In any case we need to update the MSE.timeOffset bufferController.updateBufferTimestampOffset(representationInfo) .then(() =&gt; { // If the switch should occur immediately we need to replace existing stuff in the buffer if (e.reason &amp;&amp; e.reason.forceReplace) { _prepareReplacementQualitySwitch(); } // If fast switch is enabled we check if we are supposed to replace existing stuff in the buffer else if (settings.get().streaming.buffer.fastSwitchEnabled) { _prepareForFastQualitySwitch(representationInfo); } // Default quality switch. We append the new quality to the already buffered stuff else { _prepareForDefaultQualitySwitch(); } dashMetrics.pushPlayListTraceMetrics(new Date(), PlayListTrace.REPRESENTATION_SWITCH_STOP_REASON); dashMetrics.createPlaylistTraceMetrics(representationInfo.id, playbackController.getTime() * 1000, playbackController.getPlaybackRate()); }) } function _prepareReplacementQualitySwitch() { // Inform other classes like the GapController that we are replacing existing stuff eventBus.trigger(Events.BUFFER_REPLACEMENT_STARTED, { mediaType: type, streamId: streamInfo.id }, { mediaType: type, streamId: streamInfo.id }); // Abort appending segments to the buffer. Also adjust the appendWindow as we might have been in the progress of prebuffering stuff. bufferController.prepareForReplacementQualitySwitch() .then(() =&gt; { _bufferClearedForReplacement(); qualityChangeInProgress = false; }) .catch(() =&gt; { _bufferClearedForReplacement(); qualityChangeInProgress = false; }); } function _prepareForFastQualitySwitch(representationInfo) { // if we switch up in quality and need to replace existing parts in the buffer we need to adjust the buffer target const time = playbackController.getTime(); let safeBufferLevel = 1.5 * (!isNaN(representationInfo.fragmentDuration) ? representationInfo.fragmentDuration : 1); const request = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_EXECUTED, time: time + safeBufferLevel, threshold: 0 })[0]; if (request &amp;&amp; !getIsTextTrack()) { const bufferLevel = bufferController.getBufferLevel(); const abandonmentState = abrController.getAbandonmentStateFor(streamInfo.id, type); // The quality we originally requested was lower than the new quality if (request.quality &lt; representationInfo.quality &amp;&amp; bufferLevel &gt;= safeBufferLevel &amp;&amp; abandonmentState !== MetricsConstants.ABANDON_LOAD) { const targetTime = time + safeBufferLevel; setExplicitBufferingTime(targetTime); scheduleController.setCheckPlaybackQuality(false); scheduleController.startScheduleTimer(); } else { _prepareForDefaultQualitySwitch(); } } else { scheduleController.startScheduleTimer(); } qualityChangeInProgress = false; } function _prepareForDefaultQualitySwitch() { // We might have aborted the current request. We need to set an explicit buffer time based on what we already have in the buffer. _bufferClearedForNonReplacement() qualityChangeInProgress = false; } /** * We have canceled the download of a fragment and need to adjust the buffer time or reload an init segment * @param {object} e */ function _onFragmentLoadingAbandoned(e) { logger.info('onFragmentLoadingAbandoned request: ' + e.request.url + ' has been aborted'); // we only need to handle this if we are not seeking, not switching the tracks and not switching the quality if (!playbackController.isSeeking() &amp;&amp; !scheduleController.getSwitchStrack() &amp;&amp; !qualityChangeInProgress) { logger.info('onFragmentLoadingAbandoned request: ' + e.request.url + ' has to be downloaded again, origin is not seeking process or switch track call'); // in case of an init segment we force the download of an init segment if (e.request &amp;&amp; e.request.isInitializationRequest()) { scheduleController.setInitSegmentRequired(true); } // in case of a media segment we reset the buffering time else { setExplicitBufferingTime(e.request.startTime + (e.request.duration / 2)); } // In case of a seek the schedule controller was stopped and will be started once the buffer has been pruned. scheduleController.startScheduleTimer(0); } } /** * When a fragment has been loaded we need to start the schedule timer again in case of an error. * @param {object} e */ function _onFragmentLoadingCompleted(e) { logger.info('OnFragmentLoadingCompleted for stream id ' + streamInfo.id + ' and media type ' + type + ' - Url:', e.request ? e.request.url : 'undefined', e.request.range ? ', Range:' + e.request.range : ''); if (getIsTextTrack()) { scheduleController.startScheduleTimer(0); } if (e.error &amp;&amp; e.request.serviceLocation) { _handleFragmentLoadingError(e); } } /** * If we encountered an error when loading the fragment we need to handle it according to the segment type * @private */ function _handleFragmentLoadingError(e) { logger.info(`Fragment loading completed with an error`); if (!e || !e.request || !e.request.type) { return; } // In case there are baseUrls that can still be tried a valid request can be generated. If no valid request can be generated we ran out of baseUrls. // Consequently, we need to signal that we dont want to retry in case no valid request could be generated otherwise we keep trying with the same url infinitely. // Init segment could not be loaded. If we have multiple baseUrls we still have a chance to get a valid segment. if (e.request.type === HTTPRequest.INIT_SEGMENT_TYPE) { _onInitFragmentNeeded({ representationId: e.request.representationId, sender: {} }, false) } // Media segment could not be loaded else if (e.request.type === HTTPRequest.MEDIA_SEGMENT_TYPE) { setExplicitBufferingTime(e.request.startTime + (e.request.duration / 2)); _onMediaFragmentNeeded({}, false); } } /** * Callback function triggered by the TextController whenever a track is changed for fragmented text. Will only be triggered if textracks have previously been disabled. * @private */ function _onSetFragmentedTextAfterDisabled() { setExplicitBufferingTime(playbackController.getTime()); getScheduleController().startScheduleTimer(); } /** * Callback function triggered by the TextController whenever a track is changed for non fragmented text * @param {object} e * @private */ function _onSetNonFragmentedText(e) { const currentTrackInfo = e.currentTrackInfo; if (!currentTrackInfo) { return; } const mInfo = mediaInfoArr.find((info) =&gt; { return info.index === currentTrackInfo.index &amp;&amp; info.lang === currentTrackInfo.lang; }); if (mInfo) { selectMediaInfo(mInfo) .then(() =&gt; { bufferController.setIsBufferingCompleted(false); setExplicitBufferingTime(playbackController.getTime()); scheduleController.setInitSegmentRequired(true); scheduleController.startScheduleTimer(); }); } } function _onQuotaExceeded(e) { // Stop scheduler (will be restarted once buffer is pruned) setExplicitBufferingTime(e.quotaExceededTime); scheduleController.clearScheduleTimer(); } function getRepresentationController() { return representationController; } function getBuffer() { return bufferController ? bufferController.getBuffer() : null; } function getBufferController() { return bufferController; } function getFragmentModel() { return fragmentModel; } function updateStreamInfo(newStreamInfo) { streamInfo = newStreamInfo; if (!isBufferingCompleted()) { return bufferController.updateAppendWindow(); } return Promise.resolve(); } function getStreamInfo() { return streamInfo; } /** * Called once the StreamProcessor is initialized and when the track is switched. We only have one StreamProcessor per media type. So we need to adjust the mediaInfo once we switch/select a track. * @param {object} newMediaInfo */ function selectMediaInfo(newMediaInfo) { if (newMediaInfo !== mediaInfo &amp;&amp; (!newMediaInfo || !mediaInfo || (newMediaInfo.type === mediaInfo.type))) { mediaInfo = newMediaInfo; } const newRealAdaptation = adapter.getRealAdaptation(streamInfo, mediaInfo); const voRepresentations = adapter.getVoRepresentations(mediaInfo); if (representationController) { const realAdaptation = representationController.getData(); const maxQuality = abrController.getMaxAllowedIndexFor(type, streamInfo.id); const minIdx = abrController.getMinAllowedIndexFor(type, streamInfo.id); let quality, averageThroughput; let bitrate = null; if ((realAdaptation === null || (realAdaptation.id !== newRealAdaptation.id)) &amp;&amp; type !== Constants.TEXT) { averageThroughput = abrController.getThroughputHistory().getAverageThroughput(type, isDynamic); bitrate = averageThroughput || abrController.getInitialBitrateFor(type, streamInfo.id); quality = abrController.getQualityForBitrate(mediaInfo, bitrate, streamInfo.id); } else { quality = abrController.getQualityFor(type, streamInfo.id); } if (minIdx !== undefined &amp;&amp; quality &lt; minIdx) { quality = minIdx; } if (quality &gt; maxQuality) { quality = maxQuality; } return representationController.updateData(newRealAdaptation, voRepresentations, type, mediaInfo.isFragmented, quality); } else { return Promise.resolve(); } } function addMediaInfo(newMediaInfo) { if (mediaInfoArr.indexOf(newMediaInfo) === -1) { mediaInfoArr.push(newMediaInfo); } } function clearMediaInfoArray() { mediaInfoArr = []; } function getMediaInfo() { return mediaInfo; } function getMediaSource() { return bufferController.getMediaSource(); } function setMediaSource(mediaSource) { bufferController.setMediaSource(mediaSource); } function getScheduleController() { return scheduleController; } /** * Get a specific voRepresentation. If quality parameter is defined, this function will return the voRepresentation for this quality. * Otherwise, this function will return the current voRepresentation used by the representationController. * @param {number} quality - quality index of the voRepresentaion expected. */ function getRepresentationInfo(quality) { let voRepresentation; if (quality !== undefined) { checkInteger(quality); voRepresentation = representationController ? representationController.getRepresentationForQuality(quality) : null; } else { voRepresentation = representationController ? representationController.getCurrentRepresentation() : null; } return adapter.convertRepresentationToRepresentationInfo(voRepresentation); } function isBufferingCompleted() { return bufferController ? bufferController.getIsBufferingCompleted() : false; } function getBufferLevel() { return bufferController ? bufferController.getBufferLevel() : 0; } /** * Probe the next request. This is used in the CMCD model to get information about the upcoming request. Note: No actual request is performed here. * @return {FragmentRequest|null} */ function probeNextRequest() { const representationInfo = getRepresentationInfo(); const representation = representationController &amp;&amp; representationInfo ? representationController.getRepresentationForQuality(representationInfo.quality) : null; let request = dashHandler.getNextSegmentRequestIdempotent( mediaInfo, representation ); return request; } function _onMediaFragmentLoaded(e) { const chunk = e.chunk; const bytes = chunk.bytes; const quality = chunk.quality; const currentRepresentation = getRepresentationInfo(quality); const voRepresentation = representationController &amp;&amp; currentRepresentation ? representationController.getRepresentationForQuality(currentRepresentation.quality) : null; // If we switch tracks this event might be fired after the representations in the RepresentationController have been updated according to the new MediaInfo. // In this case there will be no currentRepresentation and voRepresentation matching the \"old\" quality if (currentRepresentation &amp;&amp; voRepresentation) { const eventStreamMedia = adapter.getEventsFor(currentRepresentation.mediaInfo, null, streamInfo); const eventStreamTrack = adapter.getEventsFor(currentRepresentation, voRepresentation, streamInfo); if (eventStreamMedia &amp;&amp; eventStreamMedia.length &gt; 0 || eventStreamTrack &amp;&amp; eventStreamTrack.length &gt; 0) { const request = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_EXECUTED, quality: quality, index: chunk.index })[0]; const events = _handleInbandEvents(bytes, request, eventStreamMedia, eventStreamTrack); eventBus.trigger(Events.INBAND_EVENTS, { events: events }, { streamId: streamInfo.id } ); } } } function _handleInbandEvents(data, request, mediaInbandEvents, trackInbandEvents) { try { const eventStreams = {}; const 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 */ const inbandEvents = mediaInbandEvents.concat(trackInbandEvents); for (let i = 0, ln = inbandEvents.length; i &lt; ln; i++) { eventStreams[inbandEvents[i].schemeIdUri + '/' + inbandEvents[i].value] = inbandEvents[i]; } const isoFile = BoxParser(context).getInstance().parse(data); const eventBoxes = isoFile.getBoxes('emsg'); if (!eventBoxes || eventBoxes.length === 0) { return events; } const sidx = isoFile.getBox('sidx'); const mediaAnchorTime = sidx &amp;&amp; !isNaN(sidx.earliest_presentation_time) &amp;&amp; !isNaN(sidx.timescale) ? sidx.earliest_presentation_time / sidx.timescale : request &amp;&amp; !isNaN(request.mediaStartTime) ? request.mediaStartTime : 0; const fragmentMediaStartTime = Math.max(mediaAnchorTime, 0); const voRepresentation = representationController.getCurrentRepresentation(); for (let i = 0, ln = eventBoxes.length; i &lt; ln; i++) { const event = adapter.getEvent(eventBoxes[i], eventStreams, fragmentMediaStartTime, voRepresentation); if (event) { events.push(event); } } return events; } catch (e) { return []; } } function createBufferSinks(previousBufferSinks) { const buffer = getBuffer(); if (buffer) { return Promise.resolve(buffer); } return bufferController ? bufferController.createBufferSink(mediaInfo, previousBufferSinks) : Promise.resolve(null); } function prepareTrackSwitch() { return new Promise((resolve) =&gt; { logger.debug(`Preparing track switch for type ${type}`); const shouldReplace = type === Constants.TEXT || (settings.get().streaming.trackSwitchMode[type] === Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE &amp;&amp; playbackController.getTimeToStreamEnd(streamInfo) &gt; settings.get().streaming.buffer.stallThreshold); // when buffering is completed and we are not supposed to replace anything do nothing. // Still we need to trigger preloading again and call change type in case user seeks back before transitioning to next period if (bufferController.getIsBufferingCompleted() &amp;&amp; !shouldReplace) { bufferController.prepareForNonReplacementTrackSwitch(mediaInfo.codec) .then(() =&gt; { eventBus.trigger(Events.BUFFERING_COMPLETED, {}, { streamId: streamInfo.id, mediaType: type }) }) .catch(() =&gt; { eventBus.trigger(Events.BUFFERING_COMPLETED, {}, { streamId: streamInfo.id, mediaType: type }) }) resolve(); return; } // We stop the schedule controller and signal a track switch. That way we request a new init segment next scheduleController.clearScheduleTimer(); scheduleController.setSwitchTrack(true); // when we are supposed to replace it does not matter if buffering is already completed if (shouldReplace) { // Inform other classes like the GapController that we are replacing existing stuff eventBus.trigger(Events.BUFFER_REPLACEMENT_STARTED, { mediaType: type, streamId: streamInfo.id }, { mediaType: type, streamId: streamInfo.id }); // Abort the current request it will be removed from the buffer anyways fragmentModel.abortRequests(); // Abort appending segments to the buffer. Also adjust the appendWindow as we might have been in the progress of prebuffering stuff. bufferController.prepareForReplacementTrackSwitch(mediaInfo.codec) .then(() =&gt; { // Timestamp offset couldve been changed by preloading period const representationInfo = getRepresentationInfo(); return bufferController.updateBufferTimestampOffset(representationInfo); }) .then(() =&gt; { _bufferClearedForReplacement(); resolve(); }) .catch(() =&gt; { _bufferClearedForReplacement(); resolve(); }); } else { // We do not replace anything that is already in the buffer. Still we need to prepare the buffer for the track switch bufferController.prepareForNonReplacementTrackSwitch(mediaInfo.codec) .then(() =&gt; { _bufferClearedForNonReplacement(); resolve(); }) .catch(() =&gt; { _bufferClearedForNonReplacement(); resolve(); }); } }) } /** * For an instant track switch we need to adjust the buffering time after the buffer has been pruned. * @private */ function _bufferClearedForReplacement() { const targetTime = playbackController.getTime(); if (settings.get().streaming.buffer.flushBufferAtTrackSwitch) { // For some devices (like chromecast) it is necessary to seek the video element to reset the internal decoding buffer, // otherwise audio track switch will be effective only once after previous buffered track is consumed playbackController.seek(targetTime + 0.001, false, true); } setExplicitBufferingTime(targetTime); bufferController.setSeekTarget(targetTime); scheduleController.startScheduleTimer(); } function _bufferClearedForNonReplacement() { const time = playbackController.getTime(); const continuousBufferTime = bufferController.getContinuousBufferTimeForTargetTime(time); const targetTime = isNaN(continuousBufferTime) ? time : continuousBufferTime; setExplicitBufferingTime(targetTime); scheduleController.startScheduleTimer(); } function _createBufferControllerForType(type, isFragmented) { let controller = null; if (!type) { errHandler.error(new DashJSError(Errors.MEDIASOURCE_TYPE_UNSUPPORTED_CODE, Errors.MEDIASOURCE_TYPE_UNSUPPORTED_MESSAGE + 'not properly defined')); return null; } if (type === Constants.TEXT &amp;&amp; !isFragmented) { controller = NotFragmentedTextBufferController(context).create({ streamInfo, type, mimeType, fragmentModel, textController, errHandler, settings }); } else { controller = BufferController(context).create({ streamInfo, type, mediaPlayerModel, manifestModel, fragmentModel, errHandler, mediaController, representationController, adapter, textController, abrController, playbackController, settings }); } return controller; } function _onSeekTarget(e) { if (e &amp;&amp; !isNaN(e.time)) { setExplicitBufferingTime(e.time); bufferController.setSeekTarget(e.time); } } function setExplicitBufferingTime(value) { bufferingTime = value; shouldUseExplicitTimeForRequest = true; } function finalisePlayList(time, reason) { dashMetrics.pushPlayListTraceMetrics(time, reason); } instance = { initialize, getStreamId, getType, isUpdating, getBufferController, getFragmentModel, getScheduleController, getRepresentationController, getRepresentationInfo, getBufferLevel, isBufferingCompleted, createBufferSinks, updateStreamInfo, getStreamInfo, selectMediaInfo, clearMediaInfoArray, addMediaInfo, prepareTrackSwitch, prepareQualityChange, getMediaInfo, getMediaSource, setMediaSource, getBuffer, setExplicitBufferingTime, finalisePlayList, probeNextRequest, prepareInnerPeriodPlaybackSeeking, prepareOuterPeriodPlaybackSeeking, reset }; setup(); return instance; } StreamProcessor.__dashjs_factory_name = 'StreamProcessor'; export default FactoryMaker.getClassFactory(StreamProcessor); × Search results Close "},"streaming_vo_metrics_TCPConnection.js.html":{"id":"streaming_vo_metrics_TCPConnection.js.html","title":"Source: streaming/vo/metrics/TCPConnection.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/vo/metrics/TCPConnection.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ class TCPConnection { /** * @description This Object holds reference to the current tcp connection */ constructor() { /** * Identifier of the TCP connection on which the HTTP request was sent. * @public */ this.tcpid = null; /** * IP Address of the interface over which the client is receiving the TCP data. * @public */ this.dest = null; /** * Real-Time | The time at which the connection was opened (sending time of the initial SYN or connect socket operation). * @public */ this.topen = null; /** * Real-Time | The time at which the connection was closed (sending or reception time of FIN or RST or close socket operation). * @public */ this.tclose = null; /** * Connect time in ms (time from sending the initial SYN to receiving the ACK or completion of the connect socket operation). * @public */ this.tconnect = null; } } export default TCPConnection; × Search results Close "},"streaming_text_TextController.js.html":{"id":"streaming_text_TextController.js.html","title":"Source: streaming/text/TextController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/text/TextController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../constants/Constants'; import FactoryMaker from '../../core/FactoryMaker'; import TextSourceBuffer from './TextSourceBuffer'; import TextTracks from './TextTracks'; import VTTParser from '../utils/VTTParser'; import TTMLParser from '../utils/TTMLParser'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents'; import {checkParameterType} from '../utils/SupervisorTools'; function TextController(config) { let context = this.context; const adapter = config.adapter; const errHandler = config.errHandler; const manifestModel = config.manifestModel; const mediaController = config.mediaController; const videoModel = config.videoModel; const settings = config.settings; let instance, streamData, textSourceBuffers, textTracks, vttParser, ttmlParser, eventBus, defaultSettings, initialSettingsSet, allTracksAreDisabled, forceTextStreaming, textTracksAdded, disableTextBeforeTextTracksAdded; function setup() { defaultSettings = null; forceTextStreaming = false; textTracksAdded = false; initialSettingsSet = false; disableTextBeforeTextTracksAdded = false; vttParser = VTTParser(context).getInstance(); ttmlParser = TTMLParser(context).getInstance(); eventBus = EventBus(context).getInstance(); resetInitialSettings(); } function initialize() { eventBus.on(Events.CURRENT_TRACK_CHANGED, _onCurrentTrackChanged, instance); eventBus.on(Events.TEXT_TRACKS_QUEUE_INITIALIZED, _onTextTracksAdded, instance); } function initializeForStream(streamInfo) { const streamId = streamInfo.id; const tracks = TextTracks(context).create({ videoModel, streamInfo }); tracks.initialize(); textTracks[streamId] = tracks; const textSourceBuffer = TextSourceBuffer(context).create({ errHandler, adapter, manifestModel, mediaController, videoModel, textTracks: tracks, vttParser, ttmlParser, streamInfo }); textSourceBuffer.initialize(); textSourceBuffers[streamId] = textSourceBuffer; streamData[streamId] = {}; streamData[streamId].lastEnabledIndex = -1; } /** * All media infos have been added. Start creating the track objects * @param {object} streamInfo */ function createTracks(streamInfo) { const streamId = streamInfo.id; if (!textTracks[streamId]) { return; } textTracks[streamId].createTracks(); } /** * Adds the new mediaInfo objects to the textSourceBuffer. * @param {object} streamInfo * @param {array} mInfos * @param {string|null} mimeType * @param {object} fragmentModel */ function addMediaInfosToBuffer(streamInfo, type, mInfos, fragmentModel = null) { const streamId = streamInfo.id; if (!textSourceBuffers[streamId]) { return; } textSourceBuffers[streamId].addMediaInfos(type, mInfos, fragmentModel); } function getTextSourceBuffer(streamInfo) { const streamId = streamInfo.id; if (textSourceBuffers &amp;&amp; textSourceBuffers[streamId]) { return textSourceBuffers[streamId]; } } function getAllTracksAreDisabled() { return allTracksAreDisabled; } function addEmbeddedTrack(streamInfo, mediaInfo) { const streamId = streamInfo.id; if (!textSourceBuffers[streamId]) { return; } textSourceBuffers[streamId].addEmbeddedTrack(mediaInfo); } function setInitialSettings(settings) { defaultSettings = settings; initialSettingsSet = true; } function _onTextTracksAdded(e) { let tracks = e.tracks; let index = e.index; const streamId = e.streamId; const textDefaultEnabled = settings.get().streaming.text.defaultEnabled; if ((textDefaultEnabled === false &amp;&amp; !isTextEnabled()) || disableTextBeforeTextTracksAdded) { // disable text at startup if explicitly configured with setTextDefaultEnabled(false) or if there is no defaultSettings (configuration or from domStorage) setTextTrack(streamId, -1); } else { if (defaultSettings) { tracks.some((item, idx) =&gt; { // matchSettings is compatible with setTextDefaultLanguage and setInitialSettings if (mediaController.matchSettings(defaultSettings, item)) { setTextTrack(streamId, idx); index = idx; return true; } }); } allTracksAreDisabled = false; } streamData[streamId].lastEnabledIndex = index; eventBus.trigger(MediaPlayerEvents.TEXT_TRACKS_ADDED, { enabled: isTextEnabled(), index: index, tracks: tracks, streamId }); textTracksAdded = true; } function _onCurrentTrackChanged(event) { if (!initialSettingsSet &amp;&amp; event &amp;&amp; event.newMediaInfo) { let mediaInfo = event.newMediaInfo; if (mediaInfo.type === Constants.TEXT) { defaultSettings = { lang: mediaInfo.lang, role: mediaInfo.roles[0], index: mediaInfo.index, codec: mediaInfo.codec, accessibility: mediaInfo.accessibility[0] }; } } } function enableText(streamId, enable) { checkParameterType(enable, 'boolean'); if (isTextEnabled() !== enable) { // change track selection if (enable) { // apply last enabled track setTextTrack(streamId, streamData[streamId].lastEnabledIndex); } if (!enable) { // keep last index and disable text track streamData[streamId].lastEnabledIndex = getCurrentTrackIdx(streamId); if (!textTracksAdded) { disableTextBeforeTextTracksAdded = true; } else { setTextTrack(streamId, -1); } } } } function isTextEnabled() { let enabled = true; if (allTracksAreDisabled &amp;&amp; !forceTextStreaming) { enabled = false; } return enabled; } // when set to true ScheduleController will allow schedule of chunks even if tracks are all disabled. Allowing streaming to hidden track for external players to work with. function enableForcedTextStreaming(enable) { checkParameterType(enable, 'boolean'); forceTextStreaming = enable; } function setTextTrack(streamId, idx) { // For external time text file, the only action needed to change a track is marking the track mode to showing. // Fragmented text tracks need the additional step of calling TextController.setTextTrack(); allTracksAreDisabled = idx === -1; if (allTracksAreDisabled &amp;&amp; mediaController) { mediaController.saveTextSettingsDisabled(); } let oldTrackIdx = getCurrentTrackIdx(streamId); // No change, no action required if (oldTrackIdx === idx || !textTracks[streamId]) { return; } textTracks[streamId].setModeForTrackIdx(oldTrackIdx, Constants.TEXT_HIDDEN); textTracks[streamId].setCurrentTrackIdx(idx); textTracks[streamId].setModeForTrackIdx(idx, Constants.TEXT_SHOWING); let currentTrackInfo = textTracks[streamId].getCurrentTrackInfo(); if (currentTrackInfo &amp;&amp; currentTrackInfo.isFragmented &amp;&amp; !currentTrackInfo.isEmbedded) { _setFragmentedTextTrack(streamId, currentTrackInfo, oldTrackIdx); } else if (currentTrackInfo &amp;&amp; !currentTrackInfo.isFragmented) { _setNonFragmentedTextTrack(streamId, currentTrackInfo); } mediaController.setTrack(currentTrackInfo); } function _setFragmentedTextTrack(streamId, currentTrackInfo, oldTrackIdx) { if (!textSourceBuffers[streamId]) { return; } let config = textSourceBuffers[streamId].getConfig(); let fragmentedTracks = config.fragmentedTracks; for (let i = 0; i &lt; fragmentedTracks.length; i++) { let mediaInfo = fragmentedTracks[i]; if (currentTrackInfo.lang === mediaInfo.lang &amp;&amp; (mediaInfo.id ? currentTrackInfo.id === mediaInfo.id : currentTrackInfo.index === mediaInfo.index)) { let currentFragTrack = mediaController.getCurrentTrackFor(Constants.TEXT, streamId); if (mediaInfo.id ? currentFragTrack.id !== mediaInfo.id : currentFragTrack.index !== mediaInfo.index) { textTracks[streamId].deleteCuesFromTrackIdx(oldTrackIdx); textSourceBuffers[streamId].setCurrentFragmentedTrackIdx(i); } else if (oldTrackIdx === -1) { // in fragmented use case, if the user selects the older track (the one selected before disabled text track) // no CURRENT_TRACK_CHANGED event will be triggered because the mediaInfo in the StreamProcessor is equal to the one we are selecting // For that reason we reactivate the StreamProcessor and the ScheduleController eventBus.trigger(Events.SET_FRAGMENTED_TEXT_AFTER_DISABLED, {}, { streamId, mediaType: Constants.TEXT }); } } } } function _setNonFragmentedTextTrack(streamId, currentTrackInfo) { eventBus.trigger(Events.SET_NON_FRAGMENTED_TEXT, { currentTrackInfo }, { streamId, mediaType: Constants.TEXT }); } function getCurrentTrackIdx(streamId) { return textTracks[streamId].getCurrentTrackIdx(); } function deactivateStream(streamInfo) { if (!streamInfo) { return; } const streamId = streamInfo.id; if (textSourceBuffers[streamId]) { textSourceBuffers[streamId].resetMediaInfos(); } if (textTracks[streamId]) { textTracks[streamId].deleteAllTextTracks(); } } function resetInitialSettings() { textSourceBuffers = {}; textTracks = {}; streamData = {}; allTracksAreDisabled = true; textTracksAdded = false; disableTextBeforeTextTracksAdded = false; } function reset() { resetInitialSettings(); eventBus.off(Events.CURRENT_TRACK_CHANGED, _onCurrentTrackChanged, instance); eventBus.off(Events.TEXT_TRACKS_QUEUE_INITIALIZED, _onTextTracksAdded, instance); Object.keys(textSourceBuffers).forEach((key) =&gt; { textSourceBuffers[key].resetEmbedded(); textSourceBuffers[key].reset(); }); } instance = { deactivateStream, initialize, initializeForStream, createTracks, getTextSourceBuffer, getAllTracksAreDisabled, addEmbeddedTrack, setInitialSettings, enableText, isTextEnabled, setTextTrack, getCurrentTrackIdx, enableForcedTextStreaming, addMediaInfosToBuffer, reset }; setup(); return instance; } TextController.__dashjs_factory_name = 'TextController'; export default FactoryMaker.getClassFactory(TextController); × Search results Close "},"streaming_text_TextSourceBuffer.js.html":{"id":"streaming_text_TextSourceBuffer.js.html","title":"Source: streaming/text/TextSourceBuffer.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/text/TextSourceBuffer.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import Constants from '../constants/Constants'; import {HTTPRequest} from '../vo/metrics/HTTPRequest'; import TextTrackInfo from '../vo/TextTrackInfo'; import BoxParser from '../utils/BoxParser'; import CustomTimeRanges from '../utils/CustomTimeRanges'; import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import EmbeddedTextHtmlRender from './EmbeddedTextHtmlRender'; import ISOBoxer from 'codem-isoboxer'; import cea608parser from '../../../externals/cea608-parser'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import DashJSError from '../vo/DashJSError'; import Errors from '../../core/errors/Errors'; function TextSourceBuffer(config) { const errHandler = config.errHandler; const manifestModel = config.manifestModel; const mediaController = config.mediaController; const videoModel = config.videoModel; const textTracks = config.textTracks; const vttParser = config.vttParser; const ttmlParser = config.ttmlParser; const streamInfo = config.streamInfo; const context = this.context; const eventBus = EventBus(context).getInstance(); let embeddedInitialized = false; let instance, logger, boxParser, parser, mediaInfos, fragmentModel, initializationSegmentReceived, timescale, fragmentedTracks, firstFragmentedSubtitleStart, currFragmentedTrackIdx, embeddedTracks, embeddedTimescale, embeddedLastSequenceNumber, embeddedCea608FieldParsers, embeddedTextHtmlRender; function setup() { logger = Debug(context).getInstance().getLogger(instance); boxParser = BoxParser(context).getInstance(); resetInitialSettings(); } function getStreamId() { return streamInfo.id; } function _resetFragmented() { fragmentModel = null; timescale = NaN; fragmentedTracks = []; firstFragmentedSubtitleStart = null; initializationSegmentReceived = false; } function resetInitialSettings() { _resetFragmented(); mediaInfos = []; parser = null; } function initialize() { if (!embeddedInitialized) { _initEmbedded(); } } /** * There might be media infos of different types. For instance text and fragmentedText. * @param {string} type * @param {array} mInfos * @param {object} fModel */ function addMediaInfos(type, mInfos, fModel) { mediaInfos = mediaInfos.concat(mInfos); if (type === Constants.TEXT &amp;&amp; mInfos[0].isFragmented &amp;&amp; !mInfos[0].isEmbedded) { fragmentModel = fModel; instance.buffered = CustomTimeRanges(context).create(); fragmentedTracks = mediaController.getTracksFor(Constants.TEXT, streamInfo.id).filter(track =&gt; track.isFragmented); const currFragTrack = mediaController.getCurrentTrackFor(Constants.TEXT, streamInfo.id); for (let i = 0; i &lt; fragmentedTracks.length; i++) { if (fragmentedTracks[i] === currFragTrack) { setCurrentFragmentedTrackIdx(i); break; } } } for (let i = 0; i &lt; mInfos.length; i++) { _createTextTrackFromMediaInfo(mInfos[i]); } } /** * Create a new track based on the mediaInfo information * @param {object} mediaInfo * @private */ function _createTextTrackFromMediaInfo(mediaInfo) { const textTrackInfo = new TextTrackInfo(); const trackKindMap = { subtitle: 'subtitles', caption: 'captions' }; //Dash Spec has no \"s\" on end of KIND but HTML needs plural. for (let key in mediaInfo) { textTrackInfo[key] = mediaInfo[key]; } textTrackInfo.labels = mediaInfo.labels; textTrackInfo.defaultTrack = getIsDefault(mediaInfo); textTrackInfo.isFragmented = mediaInfo.isFragmented; textTrackInfo.isEmbedded = !!mediaInfo.isEmbedded; textTrackInfo.isTTML = _checkTtml(mediaInfo); textTrackInfo.kind = _getKind(mediaInfo, trackKindMap); textTracks.addTextTrack(textTrackInfo); } function abort() { } function reset() { resetInitialSettings(); mediaInfos = []; boxParser = null; } function _onVideoChunkReceived(e) { const chunk = e.chunk; if (chunk.mediaInfo.embeddedCaptions) { append(chunk.bytes, chunk); } } function _initEmbedded() { embeddedTracks = []; currFragmentedTrackIdx = null; embeddedTimescale = 0; embeddedCea608FieldParsers = []; embeddedLastSequenceNumber = null; embeddedInitialized = true; embeddedTextHtmlRender = EmbeddedTextHtmlRender(context).getInstance(); eventBus.on(Events.VIDEO_CHUNK_RECEIVED, _onVideoChunkReceived, instance); eventBus.on(Events.BUFFER_CLEARED, onVideoBufferCleared, instance); } function resetEmbedded() { eventBus.off(Events.VIDEO_CHUNK_RECEIVED, _onVideoChunkReceived, instance); eventBus.off(Events.BUFFER_CLEARED, onVideoBufferCleared, instance); if (textTracks) { textTracks.deleteAllTextTracks(); } embeddedInitialized = false; embeddedTracks = []; embeddedCea608FieldParsers = [null, null]; embeddedLastSequenceNumber = null; } function addEmbeddedTrack(mediaInfo) { if (!embeddedInitialized) { return; } if (mediaInfo) { if (mediaInfo.id === Constants.CC1 || mediaInfo.id === Constants.CC3) { for (let i = 0; i &lt; embeddedTracks.length; i++) { if (embeddedTracks[i].id === mediaInfo.id) { return; } } embeddedTracks.push(mediaInfo); } else { logger.warn('Embedded track ' + mediaInfo.id + ' not supported!'); } } } function getConfig() { const config = { fragmentModel: fragmentModel, fragmentedTracks: fragmentedTracks, videoModel: videoModel }; return config; } function setCurrentFragmentedTrackIdx(idx) { currFragmentedTrackIdx = idx; } function _checkTtml(mediaInfo) { return (mediaInfo.codec &amp;&amp; mediaInfo.codec.search(Constants.STPP) &gt;= 0) || (mediaInfo.mimeType &amp;&amp; mediaInfo.mimeType.search(Constants.TTML) &gt;= 0); } function _getKind(mediaInfo, trackKindMap) { let kind = (mediaInfo.roles &amp;&amp; mediaInfo.roles.length &gt; 0) ? trackKindMap[mediaInfo.roles[0]] : trackKindMap.caption; kind = (kind === trackKindMap.caption || kind === trackKindMap.subtitle) ? kind : trackKindMap.caption; return kind; } function append(bytes, chunk) { const mediaInfo = chunk.mediaInfo; const mediaType = mediaInfo.type; const mimeType = mediaInfo.mimeType; const codecType = mediaInfo.codec || mimeType; if (!codecType) { logger.error('No text type defined'); return; } if (mediaInfo.codec.indexOf('application/mp4') !== -1) { _appendFragmentedText(bytes, chunk, codecType); } else if (mediaType === Constants.VIDEO) { _appendEmbeddedText(bytes, chunk); } else { _appendText(bytes, chunk, codecType); } } function _appendFragmentedText(bytes, chunk, codecType) { let sampleList, samplesInfo; if (chunk.segmentType === 'InitializationSegment') { initializationSegmentReceived = true; timescale = boxParser.getMediaTimescaleFromMoov(bytes); } else { if (!initializationSegmentReceived) { return; } samplesInfo = boxParser.getSamplesInfo(bytes); sampleList = samplesInfo.sampleList; if (sampleList.length &gt; 0) { firstFragmentedSubtitleStart = sampleList[0].cts - chunk.start * timescale; } if (codecType.search(Constants.STPP) &gt;= 0) { _appendFragmentedSttp(bytes, sampleList, codecType); } else { _appendFragmentedWebVtt(bytes, sampleList); } } } function _appendFragmentedSttp(bytes, sampleList, codecType) { let i, j; parser = parser !== null ? parser : getParser(codecType); for (i = 0; i &lt; sampleList.length; i++) { const sample = sampleList[i]; const sampleStart = sample.cts; const timestampOffset = _getTimestampOffset(); const start = timestampOffset + sampleStart / timescale; const end = start + sample.duration / timescale; instance.buffered.add(start, end); const dataView = new DataView(bytes, sample.offset, sample.subSizes[0]); let ccContent = ISOBoxer.Utils.dataViewToString(dataView, Constants.UTF8); const images = []; let subOffset = sample.offset + sample.subSizes[0]; for (j = 1; j &lt; sample.subSizes.length; j++) { const inData = new Uint8Array(bytes, subOffset, sample.subSizes[j]); const raw = String.fromCharCode.apply(null, inData); images.push(raw); subOffset += sample.subSizes[j]; } try { const manifest = manifestModel.getValue(); // Only used for Miscrosoft Smooth Streaming support - caption time is relative to sample time. In this case, we apply an offset. const offsetTime = manifest.ttmlTimeIsRelative ? sampleStart / timescale : 0; const result = parser.parse(ccContent, offsetTime, sampleStart / timescale, (sampleStart + sample.duration) / timescale, images); textTracks.addCaptions(currFragmentedTrackIdx, timestampOffset, result); } catch (e) { fragmentModel.removeExecutedRequestsBeforeTime(); this.remove(); logger.error('TTML parser error: ' + e.message); } } } function _appendFragmentedWebVtt(bytes, sampleList) { let i, j, k; const captionArray = []; for (i = 0; i &lt; sampleList.length; i++) { const sample = sampleList[i]; sample.cts -= firstFragmentedSubtitleStart; const timestampOffset = _getTimestampOffset(); const start = timestampOffset + sample.cts / timescale; const end = start + sample.duration / timescale; instance.buffered.add(start, end); const sampleData = bytes.slice(sample.offset, sample.offset + sample.size); // There are boxes inside the sampleData, so we need a ISOBoxer to get at it. const sampleBoxes = ISOBoxer.parseBuffer(sampleData); for (j = 0; j &lt; sampleBoxes.boxes.length; j++) { const box1 = sampleBoxes.boxes[j]; logger.debug('VTT box1: ' + box1.type); if (box1.type === 'vtte') { continue; //Empty box } if (box1.type === 'vttc') { logger.debug('VTT vttc boxes.length = ' + box1.boxes.length); for (k = 0; k &lt; box1.boxes.length; k++) { const box2 = box1.boxes[k]; logger.debug('VTT box2: ' + box2.type); if (box2.type === 'payl') { const cue_text = box2.cue_text; logger.debug('VTT cue_text = ' + cue_text); const start_time = sample.cts / timescale; const end_time = (sample.cts + sample.duration) / timescale; captionArray.push({ start: start_time, end: end_time, data: cue_text, styles: {} }); logger.debug('VTT ' + start_time + '-' + end_time + ' : ' + cue_text); } } } } } if (captionArray.length &gt; 0) { textTracks.addCaptions(currFragmentedTrackIdx, 0, captionArray); } } function _appendText(bytes, chunk, codecType) { let result, ccContent; const dataView = new DataView(bytes, 0, bytes.byteLength); ccContent = ISOBoxer.Utils.dataViewToString(dataView, Constants.UTF8); try { result = getParser(codecType).parse(ccContent, 0); textTracks.addCaptions(textTracks.getCurrentTrackIdx(), 0, result); if (instance.buffered) { instance.buffered.add(chunk.start, chunk.end); } } catch (e) { errHandler.error(new DashJSError(Errors.TIMED_TEXT_ERROR_ID_PARSE_CODE, Errors.TIMED_TEXT_ERROR_MESSAGE_PARSE + e.message, ccContent)); } } function _appendEmbeddedText(bytes, chunk) { let i, samplesInfo; // Init segment if (chunk.segmentType === HTTPRequest.INIT_SEGMENT_TYPE) { if (embeddedTimescale === 0) { embeddedTimescale = boxParser.getMediaTimescaleFromMoov(bytes); } } // MediaSegment else if (chunk.segmentType === HTTPRequest.MEDIA_SEGMENT_TYPE) { if (embeddedTimescale === 0) { logger.warn('CEA-608: No timescale for embeddedTextTrack yet'); return; } samplesInfo = boxParser.getSamplesInfo(bytes); const sequenceNumber = samplesInfo.lastSequenceNumber; if (!embeddedCea608FieldParsers[0] &amp;&amp; !embeddedCea608FieldParsers[1]) { _setupCeaParser(); } if (embeddedTimescale) { if (embeddedLastSequenceNumber !== null &amp;&amp; sequenceNumber !== embeddedLastSequenceNumber + samplesInfo.numSequences) { for (i = 0; i &lt; embeddedCea608FieldParsers.length; i++) { if (embeddedCea608FieldParsers[i]) { embeddedCea608FieldParsers[i].reset(); } } } const allCcData = _extractCea608Data(bytes, samplesInfo.sampleList); for (let fieldNr = 0; fieldNr &lt; embeddedCea608FieldParsers.length; fieldNr++) { const ccData = allCcData.fields[fieldNr]; const fieldParser = embeddedCea608FieldParsers[fieldNr]; if (fieldParser) { for (i = 0; i &lt; ccData.length; i++) { fieldParser.addData(ccData[i][0] / embeddedTimescale, ccData[i][1]); } } } embeddedLastSequenceNumber = sequenceNumber; } } } function _setupCeaParser() { // Time to setup the CEA-608 parsing let trackIdx; for (let i = 0; i &lt; embeddedTracks.length; i++) { trackIdx = textTracks.getTrackIdxForId(embeddedTracks[i].id); if (trackIdx === -1) { logger.warn('CEA-608: data before track is ready.'); return; } const handler = _makeCueAdderForIndex(trackIdx); embeddedCea608FieldParsers[i] = new cea608parser.Cea608Parser(i + 1, { newCue: handler }, null); } } function _makeCueAdderForIndex(trackIndex) { function newCue(startTime, endTime, captionScreen) { let captionsArray; if (videoModel.getTTMLRenderingDiv()) { captionsArray = embeddedTextHtmlRender.createHTMLCaptionsFromScreen(videoModel.getElement(), startTime, endTime, captionScreen); } else { const text = captionScreen.getDisplayText(); captionsArray = [{ start: startTime, end: endTime, data: text, styles: {} }]; } if (captionsArray) { textTracks.addCaptions(trackIndex, 0, captionsArray); } } return newCue; } /** * Extract CEA-608 data from a buffer of data. * @param {ArrayBuffer} data * @param {Array} samples cue information * @returns {Object|null} ccData corresponding to one segment. */ function _extractCea608Data(data, samples) { if (samples.length === 0) { return null; } const allCcData = { splits: [], fields: [[], []] }; const raw = new DataView(data); for (let i = 0; i &lt; samples.length; i++) { const sample = samples[i]; const cea608Ranges = cea608parser.findCea608Nalus(raw, sample.offset, sample.size); let lastSampleTime = null; let idx = 0; for (let j = 0; j &lt; cea608Ranges.length; j++) { const ccData = cea608parser.extractCea608DataFromRange(raw, cea608Ranges[j]); for (let k = 0; k &lt; 2; k++) { if (ccData[k].length &gt; 0) { if (sample.cts !== lastSampleTime) { idx = 0; } else { idx += 1; } const timestampOffset = _getTimestampOffset(); allCcData.fields[k].push([sample.cts + (timestampOffset * embeddedTimescale), ccData[k], idx]); lastSampleTime = sample.cts; } } } } // Sort by sampleTime ascending order // If two packets have the same sampleTime, use them in the order // they were received allCcData.fields.forEach(function sortField(field) { field.sort(function (a, b) { if (a[0] === b[0]) { return a[2] - b[2]; } return a[0] - b[0]; }); }); return allCcData; } function _getTimestampOffset() { return !isNaN(instance.timestampOffset) ? instance.timestampOffset : 0; } function getIsDefault(mediaInfo) { //TODO How to tag default. currently same order as listed in manifest. // Is there a way to mark a text adaptation set as the default one? DASHIF meeting talk about using role which is being used for track KIND // Eg subtitles etc. You can have multiple role tags per adaptation Not defined in the spec yet. let isDefault = false; if (embeddedTracks.length &gt; 1 &amp;&amp; mediaInfo.isEmbedded) { isDefault = (mediaInfo.id &amp;&amp; mediaInfo.id === Constants.CC1); // CC1 if both CC1 and CC3 exist } else if (embeddedTracks.length === 1) { if (mediaInfo.id &amp;&amp; typeof mediaInfo.id === 'string' &amp;&amp; mediaInfo.id.substring(0, 2) === 'CC') { // Either CC1 or CC3 isDefault = true; } } else if (embeddedTracks.length === 0) { isDefault = (mediaInfo.index === mediaInfos[0].index); } return isDefault; } function getParser(codecType) { let parser; if (codecType.search(Constants.VTT) &gt;= 0) { parser = vttParser; } else if (codecType.search(Constants.TTML) &gt;= 0 || codecType.search(Constants.STPP) &gt;= 0) { parser = ttmlParser; } return parser; } function remove(start, end) { //if start and end are not defined, remove all if ((start === undefined) &amp;&amp; (start === end)) { start = instance.buffered.start(0); end = instance.buffered.end(instance.buffered.length - 1); } instance.buffered.remove(start, end); textTracks.deleteCuesFromTrackIdx(currFragmentedTrackIdx, start, end); } function onVideoBufferCleared(e) { embeddedTracks.forEach(function (track) { const trackIdx = textTracks.getTrackIdxForId(track.id); if (trackIdx &gt;= 0) { textTracks.deleteCuesFromTrackIdx(trackIdx, e.from, e.to); } }); } function resetMediaInfos() { mediaInfos = []; } instance = { initialize, addMediaInfos, resetMediaInfos, getStreamId, append, abort, addEmbeddedTrack, resetEmbedded, getConfig, setCurrentFragmentedTrackIdx, remove, reset }; setup(); return instance; } TextSourceBuffer.__dashjs_factory_name = 'TextSourceBuffer'; export default FactoryMaker.getClassFactory(TextSourceBuffer); × Search results Close "},"dash_utils_TimelineConverter.js.html":{"id":"dash_utils_TimelineConverter.js.html","title":"Source: dash/utils/TimelineConverter.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: dash/utils/TimelineConverter.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; import DashConstants from '../constants/DashConstants'; import DashManifestModel from '../models/DashManifestModel'; import Settings from '../../core/Settings'; import Constants from '../../streaming/constants/Constants'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents'; import ConformanceViolationConstants from '../../streaming/constants/ConformanceViolationConstants'; function TimelineConverter() { const context = this.context; const eventBus = EventBus(context).getInstance(); const settings = Settings(context).getInstance(); let instance, dashManifestModel, timelineAnchorAvailabilityOffset, // In case we calculate the TSBD using _calcTimeShiftBufferWindowForDynamicTimelineManifest we use the segments as anchor times. We apply this offset when calculating if a segment is available or not. clientServerTimeShift; function setup() { dashManifestModel = DashManifestModel(context).getInstance(); reset(); } function initialize() { resetInitialSettings(); eventBus.on(Events.UPDATE_TIME_SYNC_OFFSET, _onUpdateTimeSyncOffset, this); } function getClientTimeOffset() { return clientServerTimeShift; } function setClientTimeOffset(value) { clientServerTimeShift = value; } /** * Returns a \"now\" reference time for the client to compare the availability time of a segment against. * Takes the client/server drift into account */ function getClientReferenceTime() { return Date.now() - (timelineAnchorAvailabilityOffset * 1000) + (clientServerTimeShift * 1000); } function _calcAvailabilityTimeFromPresentationTime(presentationEndTime, representation, isDynamic, calculateAvailabilityEndTime) { let availabilityTime; let mpd = representation.adaptation.period.mpd; const availabilityStartTime = mpd.availabilityStartTime; if (calculateAvailabilityEndTime) { //@timeShiftBufferDepth specifies the duration of the time shifting buffer that is guaranteed // to be available for a Media Presentation with type 'dynamic'. // When not present, the value is infinite. if (isDynamic &amp;&amp; mpd.timeShiftBufferDepth !== Number.POSITIVE_INFINITY) { // SAET = SAST + TSBD + seg@duration availabilityTime = new Date(availabilityStartTime.getTime() + ((presentationEndTime + mpd.timeShiftBufferDepth) * 1000)); } else { availabilityTime = mpd.availabilityEndTime; } } else { if (isDynamic) { // SAST = Period@start + seg@presentationStartTime + seg@duration // ASAST = SAST - ATO const availabilityTimeOffset = representation.availabilityTimeOffset; // presentationEndTime = Period@start + seg@presentationStartTime + Segment@duration availabilityTime = new Date(availabilityStartTime.getTime() + (presentationEndTime - availabilityTimeOffset) * 1000); } else { // in static mpd, all segments are available at the same time availabilityTime = availabilityStartTime; } } return availabilityTime; } function calcAvailabilityStartTimeFromPresentationTime(presentationEndTime, representation, isDynamic) { return _calcAvailabilityTimeFromPresentationTime(presentationEndTime, representation, isDynamic); } function calcAvailabilityEndTimeFromPresentationTime(presentationEndTime, representation, isDynamic) { return _calcAvailabilityTimeFromPresentationTime(presentationEndTime, representation, isDynamic, true); } function calcPresentationTimeFromWallTime(wallTime, period) { return ((wallTime.getTime() - period.mpd.availabilityStartTime.getTime() + clientServerTimeShift * 1000) / 1000); } function calcPresentationTimeFromMediaTime(mediaTime, representation) { const periodStart = representation.adaptation.period.start; const presentationOffset = representation.presentationTimeOffset; return mediaTime + (periodStart - presentationOffset); } function calcMediaTimeFromPresentationTime(presentationTime, representation) { const periodStart = representation.adaptation.period.start; const presentationOffset = representation.presentationTimeOffset; return presentationTime - periodStart + presentationOffset; } function calcWallTimeForSegment(segment, isDynamic) { let suggestedPresentationDelay, displayStartTime, wallTime; if (isDynamic) { suggestedPresentationDelay = segment.representation.adaptation.period.mpd.suggestedPresentationDelay; displayStartTime = segment.presentationStartTime + suggestedPresentationDelay; wallTime = new Date(segment.availabilityStartTime.getTime() + (displayStartTime * 1000)); } return wallTime; } /** * Calculates the timeshiftbuffer range. This range might overlap multiple periods and is not limited to period boundaries. However, we make sure that the range is potentially covered by period. * @param {Array} streams * @param {boolean} isDynamic * @return {} */ function calcTimeShiftBufferWindow(streams, isDynamic) { // Static manifests. The availability window is equal to the DVR window if (!isDynamic) { return _calcTimeshiftBufferForStaticManifest(streams); } // Specific use case of SegmentTimeline if (settings.get().streaming.timeShiftBuffer.calcFromSegmentTimeline) { const data = _calcTimeShiftBufferWindowForDynamicTimelineManifest(streams); _adjustTimelineAnchorAvailabilityOffset(data.now, data.range); return data.range; } return _calcTimeShiftBufferWindowForDynamicManifest(streams); } function _calcTimeshiftBufferForStaticManifest(streams) { // Static Range Finder. We iterate over all periods and return the total duration const range = { start: NaN, end: NaN }; let duration = 0; let start = NaN; streams.forEach((stream) =&gt; { const streamInfo = stream.getStreamInfo(); duration += streamInfo.duration; if (isNaN(start) || streamInfo.start &lt; start) { start = streamInfo.start; } }); range.start = start; range.end = start + duration; return range; } function _calcTimeShiftBufferWindowForDynamicManifest(streams) { const range = { start: NaN, end: NaN }; if (!streams || streams.length === 0) { return range; } const voPeriod = streams[0].getAdapter().getRegularPeriods()[0]; const now = calcPresentationTimeFromWallTime(new Date(), voPeriod); const timeShiftBufferDepth = voPeriod.mpd.timeShiftBufferDepth; const start = !isNaN(timeShiftBufferDepth) ? now - timeShiftBufferDepth : 0; // check if we find a suitable period for that starttime. Otherwise we use the time closest to that range.start = _adjustTimeBasedOnPeriodRanges(streams, start); range.end = !isNaN(range.start) &amp;&amp; now &lt; range.start ? now : _adjustTimeBasedOnPeriodRanges(streams, now, true); if (!isNaN(timeShiftBufferDepth) &amp;&amp; range.end &lt; now - timeShiftBufferDepth) { range.end = NaN; } // If we have SegmentTimeline as a reference we can verify that the calculated DVR window is at least partially included in the DVR window exposed by the timeline. // If that is not the case we stick to the DVR window defined by SegmentTimeline if (settings.get().streaming.timeShiftBuffer.fallbackToSegmentTimeline) { const timelineRefData = _calcTimeShiftBufferWindowForDynamicTimelineManifest(streams); if (timelineRefData.range.end &lt; range.start) { eventBus.trigger(MediaPlayerEvents.CONFORMANCE_VIOLATION, { level: ConformanceViolationConstants.LEVELS.WARNING, event: ConformanceViolationConstants.EVENTS.INVALID_DVR_WINDOW }); _adjustTimelineAnchorAvailabilityOffset(timelineRefData.now, timelineRefData.range); return timelineRefData.range; } } return range; } function _calcTimeShiftBufferWindowForDynamicTimelineManifest(streams) { const range = { start: NaN, end: NaN }; const voPeriod = streams[0].getAdapter().getRegularPeriods()[0]; const now = calcPresentationTimeFromWallTime(new Date(), voPeriod); if (!streams || streams.length === 0) { return { range, now }; } streams.forEach((stream) =&gt; { const adapter = stream.getAdapter(); const mediaInfo = adapter.getMediaInfoForType(stream.getStreamInfo(), Constants.VIDEO) || adapter.getMediaInfoForType(stream.getStreamInfo(), Constants.AUDIO); const voRepresentations = adapter.getVoRepresentations(mediaInfo); const voRepresentation = voRepresentations[0]; let periodRange = { start: NaN, end: NaN }; if (voRepresentation) { if (voRepresentation.segmentInfoType === DashConstants.SEGMENT_TIMELINE) { periodRange = _calcRangeForTimeline(voRepresentation); } else { const currentVoPeriod = voRepresentation.adaptation.period; periodRange.start = currentVoPeriod.start; periodRange.end = Math.max(now, currentVoPeriod.start + currentVoPeriod.duration); } } if (!isNaN(periodRange.start) &amp;&amp; (isNaN(range.start) || range.start &gt; periodRange.start)) { range.start = periodRange.start; } if (!isNaN(periodRange.end) &amp;&amp; (isNaN(range.end) || range.end &lt; periodRange.end)) { range.end = periodRange.end; } }); range.end = Math.min(now, range.end); const adjustedEndTime = _adjustTimeBasedOnPeriodRanges(streams, range.end, true); // if range is NaN all periods are in the future. we should return range.start &gt; range.end in this case range.end = isNaN(adjustedEndTime) ? range.end : adjustedEndTime; range.start = voPeriod &amp;&amp; voPeriod.mpd &amp;&amp; voPeriod.mpd.timeShiftBufferDepth &amp;&amp; !isNaN(voPeriod.mpd.timeShiftBufferDepth) &amp;&amp; !isNaN(range.end) ? Math.max(range.end - voPeriod.mpd.timeShiftBufferDepth, range.start) : range.start; range.start = _adjustTimeBasedOnPeriodRanges(streams, range.start); return { range, now }; } function _adjustTimelineAnchorAvailabilityOffset(now, range) { timelineAnchorAvailabilityOffset = now - range.end; } function _adjustTimeBasedOnPeriodRanges(streams, time, isEndOfDvrWindow = false) { try { let i = 0; let found = false; let adjustedTime = NaN; while (!found &amp;&amp; i &lt; streams.length) { const streamInfo = streams[i].getStreamInfo(); // We found a period which contains the target time. if (streamInfo.start &lt;= time &amp;&amp; (!isFinite(streamInfo.duration) || (streamInfo.start + streamInfo.duration &gt;= time))) { adjustedTime = time; found = true; } // Adjust the time for the start of the DVR window. The current period starts after the target time. We use the starttime of this period as adjusted time else if (!isEndOfDvrWindow &amp;&amp; (streamInfo.start &gt; time &amp;&amp; (isNaN(adjustedTime) || streamInfo.start &lt; adjustedTime))) { adjustedTime = streamInfo.start; } // Adjust the time for the end of the DVR window. The current period ends before the targettime. We use the end time of this period as the adjusted time else if (isEndOfDvrWindow &amp;&amp; ((streamInfo.start + streamInfo.duration) &lt; time &amp;&amp; (isNaN(adjustedTime) || (streamInfo.start + streamInfo.duration &gt; adjustedTime)))) { adjustedTime = streamInfo.start + streamInfo.duration; } i += 1; } return adjustedTime; } catch (e) { return time; } } function _calcRangeForTimeline(voRepresentation) { const adaptation = voRepresentation.adaptation.period.mpd.manifest.Period_asArray[voRepresentation.adaptation.period.index].AdaptationSet_asArray[voRepresentation.adaptation.index]; const representation = dashManifestModel.getRepresentationFor(voRepresentation.index, adaptation); const timeline = representation.SegmentTemplate.SegmentTimeline; const timescale = representation.SegmentTemplate.timescale; const segments = timeline.S_asArray; const range = { start: 0, end: 0 }; let d = 0; let segment, repeat, i, len; range.start = calcPresentationTimeFromMediaTime(segments[0].t / timescale, voRepresentation); for (i = 0, len = segments.length; i &lt; len; i++) { segment = segments[i]; repeat = 0; if (segment.hasOwnProperty('r')) { repeat = segment.r; } d += segment.d * (1 + repeat); } range.end = calcPresentationTimeFromMediaTime((segments[0].t + d) / timescale, voRepresentation); return range; } function calcPeriodRelativeTimeFromMpdRelativeTime(representation, mpdRelativeTime) { const periodStartTime = representation.adaptation.period.start; return mpdRelativeTime - periodStartTime; } function _onUpdateTimeSyncOffset(e) { if (e.offset !== undefined &amp;&amp; !isNaN(e.offset)) { setClientTimeOffset(e.offset / 1000); } } function resetInitialSettings() { clientServerTimeShift = 0; timelineAnchorAvailabilityOffset = 0; } function reset() { eventBus.off(Events.UPDATE_TIME_SYNC_OFFSET, _onUpdateTimeSyncOffset, this); resetInitialSettings(); } instance = { initialize, getClientTimeOffset, setClientTimeOffset, getClientReferenceTime, calcAvailabilityStartTimeFromPresentationTime, calcAvailabilityEndTimeFromPresentationTime, calcPresentationTimeFromWallTime, calcPresentationTimeFromMediaTime, calcPeriodRelativeTimeFromMpdRelativeTime, calcMediaTimeFromPresentationTime, calcWallTimeForSegment, calcTimeShiftBufferWindow, reset }; setup(); return instance; } TimelineConverter.__dashjs_factory_name = 'TimelineConverter'; export default FactoryMaker.getSingletonFactory(TimelineConverter); × Search results Close "},"streaming_controllers_TimeSyncController.js.html":{"id":"streaming_controllers_TimeSyncController.js.html","title":"Source: streaming/controllers/TimeSyncController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/TimeSyncController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import DashJSError from './../vo/DashJSError'; import {HTTPRequest} from '../vo/metrics/HTTPRequest'; import EventBus from './../../core/EventBus'; import Events from './../../core/events/Events'; import Errors from './../../core/errors/Errors'; import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import URLUtils from '../utils/URLUtils'; const HTTP_TIMEOUT_MS = 5000; const DEFAULT_MAXIMUM_ALLOWED_DRIFT = 100; const DEFAULT_TIME_BETWEEN_SYNC_ATTEMPTS_ADJUSTMENT_FACTOR = 2; const DEFAULT_BACKGROUND_ATTEMPTS = 2; const DEFAULT_TIME_BETWEEN_SYNC_ATTEMPTS = 30; const DEFAULT_MINIMUM_TIME_BETWEEN_BACKGROUND_SYNC_ATTEMPTS = 30; const DEFAULT_MAXIMUM_TIME_BETWEEN_SYNC = 600; const DEFAULT_MINIMUM_TIME_BETWEEN_SYNC = 2; function TimeSyncController() { const context = this.context; const eventBus = EventBus(context).getInstance(); const urlUtils = URLUtils(context).getInstance(); let instance, logger, isSynchronizing, isBackgroundSynchronizing, settings, handlers, dashMetrics, backgroundSyncTimeOffsets, timingSources, timeOfLastSync, timeOfLastBackgroundSync, lastOffset, lastTimingSource, internalTimeBetweenSyncAttempts, errHandler, baseURLController; function setup() { logger = Debug(context).getInstance().getLogger(instance); eventBus.on(Events.ATTEMPT_BACKGROUND_SYNC, _onAttemptBackgroundSync, instance); } function setConfig(config) { if (!config) return; if (config.dashMetrics) { dashMetrics = config.dashMetrics; } if (config.baseURLController) { baseURLController = config.baseURLController; } if (config.errHandler) { errHandler = config.errHandler; } if (config.settings) { settings = config.settings; } } function _resetInitialSettings() { backgroundSyncTimeOffsets = []; timingSources = []; timeOfLastSync = null; timeOfLastBackgroundSync = null; lastTimingSource = null; lastOffset = NaN; isSynchronizing = false; isBackgroundSynchronizing = false; internalTimeBetweenSyncAttempts = settings.get().streaming.utcSynchronization.timeBetweenSyncAttempts; } /** * Register the timing handler depending on the schemeIdUris. This method is called once when the StreamController is initialized */ function initialize() { _resetInitialSettings(); // a list of known schemeIdUris and a method to call with @value handlers = { 'urn:mpeg:dash:utc:http-head:2014': _httpHeadHandler, 'urn:mpeg:dash:utc:http-xsdate:2014': _httpHandler.bind(null, _xsdatetimeDecoder), 'urn:mpeg:dash:utc:http-iso:2014': _httpHandler.bind(null, _iso8601Decoder), 'urn:mpeg:dash:utc:direct:2014': _directHandler, // some specs referencing early ISO23009-1 drafts incorrectly use // 2012 in the URI, rather than 2014. support these for now. 'urn:mpeg:dash:utc:http-head:2012': _httpHeadHandler, 'urn:mpeg:dash:utc:http-xsdate:2012': _httpHandler.bind(null, _xsdatetimeDecoder), 'urn:mpeg:dash:utc:http-iso:2012': _httpHandler.bind(null, _iso8601Decoder), 'urn:mpeg:dash:utc:direct:2012': _directHandler, // it isn't clear how the data returned would be formatted, and // no public examples available so http-ntp not supported for now. // presumably you would do an arraybuffer type xhr and decode the // binary data returned but I would want to see a sample first. 'urn:mpeg:dash:utc:http-ntp:2014': _notSupportedHandler, // not clear how this would be supported in javascript (in browser) 'urn:mpeg:dash:utc:ntp:2014': _notSupportedHandler, 'urn:mpeg:dash:utc:sntp:2014': _notSupportedHandler }; } /** * Sync against a timing source. T * @param {array} tSources * @param {boolean} isDynamic */ function attemptSync(tSources, isDynamic) { timingSources = tSources; // Stop if we are already synchronizing if (isSynchronizing) { return; } // No synchronization required we can signal the completion immediately if (!_shouldPerformSynchronization(isDynamic)) { eventBus.trigger(Events.TIME_SYNCHRONIZATION_COMPLETED); return; } isSynchronizing = true; _attemptRecursiveSync(); } /** * Does a synchronization in the background in case the last offset should be verified or a 404 occurs */ function _onAttemptBackgroundSync() { if (!settings.get().streaming.utcSynchronization.enabled || isSynchronizing || isBackgroundSynchronizing || !lastTimingSource || !lastTimingSource.value || !lastTimingSource.schemeIdUri || isNaN(lastOffset) || isNaN(settings.get().streaming.utcSynchronization.backgroundAttempts)) { return; } if (timeOfLastBackgroundSync &amp;&amp; ((Date.now() - timeOfLastBackgroundSync) / 1000) &lt; DEFAULT_MINIMUM_TIME_BETWEEN_BACKGROUND_SYNC_ATTEMPTS) { return; } backgroundSyncTimeOffsets = []; isBackgroundSynchronizing = true; const backgroundAttempts = !isNaN(settings.get().streaming.utcSynchronization.backgroundAttempts) ? settings.get().streaming.utcSynchronization.backgroundAttempts : DEFAULT_BACKGROUND_ATTEMPTS; _attemptBackgroundSync(backgroundAttempts); } /** * Perform a defined number of background attempts * @param {number} attempts * @private */ function _attemptBackgroundSync(attempts) { try { if (attempts &lt;= 0) { _completeBackgroundTimeSyncSequence(); return; } const deviceTimeBeforeSync = Date.now(); handlers[lastTimingSource.schemeIdUri]( lastTimingSource.value, function (serverTime) { // the timing source returned something useful const deviceTimeAfterSync = Date.now(); const offset = _calculateOffset(deviceTimeBeforeSync, deviceTimeAfterSync, serverTime); backgroundSyncTimeOffsets.push(offset); _attemptBackgroundSync(attempts - 1); }, function () { _completeBackgroundTimeSyncSequence(); } ); } catch (e) { _completeBackgroundTimeSyncSequence(); } } /** * Sync against a timing source. This method is called recursively if the time sync for the first entry in timingSources fails. * @param {number} sourceIndex */ function _attemptRecursiveSync(sourceIndex = null) { // if called with no sourceIndex, use zero (highest priority) let index = sourceIndex || 0; // the sources should be ordered in priority from the manifest. // try each in turn, from the top, until either something // sensible happens, or we run out of sources to try. if (!timingSources || timingSources.length === 0 || index &gt;= timingSources.length) { _onComplete(); return; } let source = timingSources[index]; if (source) { // check if there is a handler for this @schemeIdUri if (handlers.hasOwnProperty(source.schemeIdUri)) { // if so, call it with its @value const deviceTimeBeforeSync = new Date().getTime(); handlers[source.schemeIdUri]( source.value, function (serverTime) { // the timing source returned something useful const deviceTimeAfterSync = new Date().getTime(); const offset = _calculateOffset(deviceTimeBeforeSync, deviceTimeAfterSync, serverTime); lastTimingSource = source; _onComplete(offset); }, function () { // the timing source was probably uncontactable // or returned something we can't use - try again // with the remaining sources _attemptRecursiveSync(index + 1); } ); } else { // an unknown schemeIdUri must have been found // try again with the remaining sources _attemptRecursiveSync(index + 1); } } else { // no valid time source could be found, just use device time _onComplete(); } } /** * Calculate the offset between client and server. Account for the roundtrip time * @param {number} deviceTimeBeforeSync * @param {number} deviceTimeAfterSync * @param {number} serverTime * @return {number} * @private */ function _calculateOffset(deviceTimeBeforeSync, deviceTimeAfterSync, serverTime) { const deviceReferenceTime = deviceTimeAfterSync - ((deviceTimeAfterSync - deviceTimeBeforeSync) / 2); return serverTime - deviceReferenceTime; } /** * Checks if a synchronization is required * @param {boolean} isDynamic * @return {boolean} * @private */ function _shouldPerformSynchronization(isDynamic) { try { if (!isDynamic || !settings.get().streaming.utcSynchronization.enabled) { return false; } const timeBetweenSyncAttempts = !isNaN(internalTimeBetweenSyncAttempts) ? internalTimeBetweenSyncAttempts : DEFAULT_TIME_BETWEEN_SYNC_ATTEMPTS; if (!timeOfLastSync || !timeBetweenSyncAttempts || isNaN(timeBetweenSyncAttempts)) { return true; } return ((Date.now() - timeOfLastSync) / 1000) &gt;= timeBetweenSyncAttempts; } catch (e) { return true; } } /** * Callback after sync has been completed * @param {number} offset * @private */ function _onComplete(offset = NaN) { let failed = isNaN(offset); if (failed &amp;&amp; settings.get().streaming.utcSynchronization.useManifestDateHeaderTimeSource) { //Before falling back to binary search , check if date header exists on MPD. if so, use for a time source. _checkForDateHeader(); } else { _completeTimeSyncSequence(failed, offset); } } /** * Takes xsdatetime and returns milliseconds since UNIX epoch. May not be necessary as xsdatetime is very similar to ISO 8601 which is natively understood by javascript Date parser * @param {string} xsdatetimeStr * @return {number} * @private */ function _alternateXsdatetimeDecoder(xsdatetimeStr) { // taken from DashParser - should probably refactor both uses const SECONDS_IN_MIN = 60; const MINUTES_IN_HOUR = 60; const MILLISECONDS_IN_SECONDS = 1000; let datetimeRegex = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(?::([0-9]*)(\\.[0-9]*)?)?(?:([+\\-])([0-9]{2})([0-9]{2}))?/; let utcDate, timezoneOffset; let match = datetimeRegex.exec(xsdatetimeStr); // If the string does not contain a timezone offset different browsers can interpret it either // as UTC or as a local time so we have to parse the string manually to normalize the given date value for // all browsers utcDate = Date.UTC( parseInt(match[1], 10), parseInt(match[2], 10) - 1, // months start from zero parseInt(match[3], 10), parseInt(match[4], 10), parseInt(match[5], 10), (match[6] &amp;&amp; (parseInt(match[6], 10) || 0)), (match[7] &amp;&amp; parseFloat(match[7]) * MILLISECONDS_IN_SECONDS) || 0 ); // If the date has timezone offset take it into account as well if (match[9] &amp;&amp; match[10]) { timezoneOffset = parseInt(match[9], 10) * MINUTES_IN_HOUR + parseInt(match[10], 10); utcDate += (match[8] === '+' ? -1 : +1) * timezoneOffset * SECONDS_IN_MIN * MILLISECONDS_IN_SECONDS; } return new Date(utcDate).getTime(); } /** * Try to use the built in parser, since xsdate is a constrained ISO8601 which is supported natively by Date.parse. if that fails, try a regex-based version used elsewhere in this application. * @param {string} xsdatetimeStr * @return {number} */ function _xsdatetimeDecoder(xsdatetimeStr) { let parsedDate = Date.parse(xsdatetimeStr); if (isNaN(parsedDate)) { parsedDate = _alternateXsdatetimeDecoder(xsdatetimeStr); } return parsedDate; } /** * Takes ISO 8601 timestamp and returns milliseconds since UNIX epoch * @param {string} isoStr * @return {number} */ function _iso8601Decoder(isoStr) { return Date.parse(isoStr); } /** * Takes RFC 1123 timestamp (which is same as ISO8601) and returns milliseconds since UNIX epoch * @param {string} dateStr * @return {number} */ function _rfc1123Decoder(dateStr) { return Date.parse(dateStr); } /** * Handler for unsupported scheme ids. * @param {string} url * @param {function} onSuccessCB * @param {function} onFailureCB * @private */ function _notSupportedHandler(url, onSuccessCB, onFailureCB) { onFailureCB(); } /** * Direct handler * @param {string} xsdatetimeStr * @param {function} onSuccessCB * @param {function} onFailureCB */ function _directHandler(xsdatetimeStr, onSuccessCB, onFailureCB) { let time = _xsdatetimeDecoder(xsdatetimeStr); if (!isNaN(time)) { onSuccessCB(time); return; } onFailureCB(); } /** * Generic http handler * @param {function} decoder * @param {string} url * @param {function} onSuccessCB * @param {function} onFailureCB * @param {boolean} isHeadRequest * @private */ function _httpHandler(decoder, url, onSuccessCB, onFailureCB, isHeadRequest) { let oncomplete, onload; let complete = false; let req = new XMLHttpRequest(); let verb = isHeadRequest ? HTTPRequest.HEAD : HTTPRequest.GET; let urls = url.match(/\\S+/g); // according to ISO 23009-1, url could be a white-space // separated list of URLs. just handle one at a time. url = urls.shift(); oncomplete = function () { if (complete) { return; } // we only want to pass through here once per xhr, // regardless of whether the load was successful. complete = true; // if there are more urls to try, call self. if (urls.length) { _httpHandler(decoder, urls.join(' '), onSuccessCB, onFailureCB, isHeadRequest); } else { onFailureCB(); } }; onload = function () { let time, result; if (req.status === 200) { time = isHeadRequest ? req.getResponseHeader('Date') : req.response; result = decoder(time); // decoder returns NaN if non-standard input if (!isNaN(result)) { onSuccessCB(result); complete = true; } } }; if (urlUtils.isRelative(url)) { // passing no path to resolve will return just MPD BaseURL/baseUri const baseUrl = baseURLController.resolve(); if (baseUrl) { url = urlUtils.resolve(url, baseUrl.url); } } req.open(verb, url); req.timeout = HTTP_TIMEOUT_MS || 0; req.onload = onload; req.onloadend = oncomplete; req.send(); } /** * Handler for http-head schemeIdUri * @param {string} url * @param {function} onSuccessCB * @param {function} onFailureCB * @private */ function _httpHeadHandler(url, onSuccessCB, onFailureCB) { _httpHandler(_rfc1123Decoder, url, onSuccessCB, onFailureCB, true); } /** * Checks if a date header is present in the MPD response and calculates the offset based on the header * @private */ function _checkForDateHeader() { let dateHeaderValue = dashMetrics.getLatestMPDRequestHeaderValueByID('Date'); let dateHeaderTime = dateHeaderValue !== null ? new Date(dateHeaderValue).getTime() : Number.NaN; if (!isNaN(dateHeaderTime)) { const offsetToDeviceTimeMs = dateHeaderTime - Date.now(); _completeTimeSyncSequence(false, offsetToDeviceTimeMs); } else { _completeTimeSyncSequence(true); } } /** * Triggers the event to signal that the time synchronization was completed * @param {boolean} failed * @param {number} offset * @private */ function _completeTimeSyncSequence(failed, offset) { // Adjust the time of the next sync based on the drift between current offset and last offset if (!isNaN(lastOffset) &amp;&amp; !isNaN(offset) &amp;&amp; !failed) { _adjustTimeBetweenSyncAttempts(offset); } // Update the internal data if (!failed &amp;&amp; !isNaN(offset)) { timeOfLastSync = Date.now(); isSynchronizing = false; // if this is the first sync we are doing perform background syncs as well to confirm current offset const shouldAttemptBackgroundSync = isNaN(lastOffset); lastOffset = offset; if (shouldAttemptBackgroundSync) { _onAttemptBackgroundSync(); } logger.debug(`Completed UTC sync. Setting client - server offset to ${offset}`); } if (failed) { lastTimingSource = null; isSynchronizing = false; errHandler.error(new DashJSError(Errors.TIME_SYNC_FAILED_ERROR_CODE, Errors.TIME_SYNC_FAILED_ERROR_MESSAGE)); } // Notify other classes eventBus.trigger(Events.UPDATE_TIME_SYNC_OFFSET, { offset: offset, }); eventBus.trigger(Events.TIME_SYNCHRONIZATION_COMPLETED); } function _adjustTimeBetweenSyncAttempts(offset) { try { const isOffsetDriftWithinThreshold = _isOffsetDriftWithinThreshold(offset); const timeBetweenSyncAttempts = !isNaN(internalTimeBetweenSyncAttempts) ? internalTimeBetweenSyncAttempts : DEFAULT_TIME_BETWEEN_SYNC_ATTEMPTS; const timeBetweenSyncAttemptsAdjustmentFactor = !isNaN(settings.get().streaming.utcSynchronization.timeBetweenSyncAttemptsAdjustmentFactor) ? settings.get().streaming.utcSynchronization.timeBetweenSyncAttemptsAdjustmentFactor : DEFAULT_TIME_BETWEEN_SYNC_ATTEMPTS_ADJUSTMENT_FACTOR; const maximumTimeBetweenSyncAttempts = !isNaN(settings.get().streaming.utcSynchronization.maximumTimeBetweenSyncAttempts) ? settings.get().streaming.utcSynchronization.maximumTimeBetweenSyncAttempts : DEFAULT_MAXIMUM_TIME_BETWEEN_SYNC; const minimumTimeBetweenSyncAttempts = !isNaN(settings.get().streaming.utcSynchronization.minimumTimeBetweenSyncAttempts) ? settings.get().streaming.utcSynchronization.minimumTimeBetweenSyncAttempts : DEFAULT_MINIMUM_TIME_BETWEEN_SYNC; let adjustedTimeBetweenSyncAttempts; if (isOffsetDriftWithinThreshold) { // The drift between the current offset and the last offset is within the allowed threshold. Increase sync time adjustedTimeBetweenSyncAttempts = Math.min(timeBetweenSyncAttempts * timeBetweenSyncAttemptsAdjustmentFactor, maximumTimeBetweenSyncAttempts); logger.debug(`Increasing timeBetweenSyncAttempts to ${adjustedTimeBetweenSyncAttempts}`); } else { // Drift between the current offset and the last offset is not within the allowed threshold. Decrease sync time adjustedTimeBetweenSyncAttempts = Math.max(timeBetweenSyncAttempts / timeBetweenSyncAttemptsAdjustmentFactor, minimumTimeBetweenSyncAttempts); logger.debug(`Decreasing timeBetweenSyncAttempts to ${adjustedTimeBetweenSyncAttempts}`); } internalTimeBetweenSyncAttempts = adjustedTimeBetweenSyncAttempts; } catch (e) { } } /** * Callback after all background syncs have been completed. * @private */ function _completeBackgroundTimeSyncSequence() { if (!backgroundSyncTimeOffsets || backgroundSyncTimeOffsets.length === 0) { return; } const averageOffset = backgroundSyncTimeOffsets.reduce((acc, curr) =&gt; { return acc + curr; }, 0) / backgroundSyncTimeOffsets.length; if (!_isOffsetDriftWithinThreshold(averageOffset)) { logger.debug(`Completed background UTC sync. Setting client - server offset to ${averageOffset}`); lastOffset = averageOffset; eventBus.trigger(Events.UPDATE_TIME_SYNC_OFFSET, { offset: lastOffset }); } else { logger.debug(`Completed background UTC sync. Offset is within allowed threshold and is not adjusted.`); } isBackgroundSynchronizing = false; timeOfLastBackgroundSync = Date.now(); } function _isOffsetDriftWithinThreshold(offset) { try { if (isNaN(lastOffset)) { return true; } const maxAllowedDrift = settings.get().streaming.utcSynchronization.maximumAllowedDrift &amp;&amp; !isNaN(settings.get().streaming.utcSynchronization.maximumAllowedDrift) ? settings.get().streaming.utcSynchronization.maximumAllowedDrift : DEFAULT_MAXIMUM_ALLOWED_DRIFT; const lowerBound = lastOffset - maxAllowedDrift; const upperBound = lastOffset + maxAllowedDrift; return offset &gt;= lowerBound &amp;&amp; offset &lt;= upperBound; } catch (e) { return true; } } function reset() { _resetInitialSettings(); eventBus.off(Events.ATTEMPT_BACKGROUND_SYNC, _onAttemptBackgroundSync, instance); } instance = { initialize, attemptSync, setConfig, reset }; setup(); return instance; } TimeSyncController.__dashjs_factory_name = 'TimeSyncController'; const factory = FactoryMaker.getSingletonFactory(TimeSyncController); factory.HTTP_TIMEOUT_MS = HTTP_TIMEOUT_MS; FactoryMaker.updateSingletonFactory(TimeSyncController.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_utils_TTMLParser.js.html":{"id":"streaming_utils_TTMLParser.js.html","title":"Source: streaming/utils/TTMLParser.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/utils/TTMLParser.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import {fromXML, generateISD} from 'imsc'; import MediaPlayerEvents from '../MediaPlayerEvents'; import ConformanceViolationConstants from '../constants/ConformanceViolationConstants'; function TTMLParser() { const context = this.context; const eventBus = EventBus(context).getInstance(); /* * This TTML parser follows \"EBU-TT-D SUBTITLING DISTRIBUTION FORMAT - tech3380\" spec - https://tech.ebu.ch/docs/tech/tech3380.pdf. * */ let instance, logger; let cueCounter = 0; // Used to give every cue a unique ID. function setup() { logger = Debug(context).getInstance().getLogger(instance); } function getCueID() { const id = 'cue_TTML_' + cueCounter; cueCounter++; return id; } /** * Parse the raw data and process it to return the HTML element representing the cue. * Return the region to be processed and controlled (hide/show) by the caption controller. * @param {string} data - raw data received from the TextSourceBuffer * @param {number} offsetTime - offset time to apply to cue time * @param {integer} startTimeSegment - startTime for the current segment * @param {integer} endTimeSegment - endTime for the current segment * @param {Array} images - images array referenced by subs MP4 box */ function parse(data, offsetTime, startTimeSegment, endTimeSegment, images) { let errorMsg = ''; const captionArray = []; let startTime, endTime, i; const content = {}; const embeddedImages = {}; let currentImageId = ''; let accumulated_image_data = ''; let metadataHandler = { onOpenTag: function (ns, name, attrs) { // cope with existing non-compliant content if (attrs[' imagetype'] &amp;&amp; !attrs[' imageType']) { eventBus.trigger(MediaPlayerEvents.CONFORMANCE_VIOLATION, { level: ConformanceViolationConstants.LEVELS.ERROR, event: ConformanceViolationConstants.EVENTS.NON_COMPLIANT_SMPTE_IMAGE_ATTRIBUTE }); attrs[' imageType'] = attrs[' imagetype']; } if (name === 'image' &amp;&amp; (ns === 'http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt' || ns === 'http://www.smpte-ra.org/schemas/2052-1/2013/smpte-tt')) { if (!attrs[' imageType'] || attrs[' imageType'].value !== 'PNG') { logger.warn('smpte-tt imageType != PNG. Discarded'); return; } currentImageId = attrs['http://www.w3.org/XML/1998/namespace id'].value; } }, onCloseTag: function () { if (currentImageId) { embeddedImages[currentImageId] = accumulated_image_data.trim(); } accumulated_image_data = ''; currentImageId = ''; }, onText: function (contents) { if (currentImageId) { accumulated_image_data = accumulated_image_data + contents; } } }; if (!data) { errorMsg = 'no ttml data to parse'; throw new Error(errorMsg); } content.data = data; eventBus.trigger(Events.TTML_TO_PARSE, content); const imsc1doc = fromXML(content.data, function (msg) { errorMsg = msg; }, metadataHandler); eventBus.trigger(Events.TTML_PARSED, { ttmlString: content.data, ttmlDoc: imsc1doc }); const mediaTimeEvents = imsc1doc.getMediaTimeEvents(); for (i = 0; i &lt; mediaTimeEvents.length; i++) { let isd = generateISD(imsc1doc, mediaTimeEvents[i], function (error) { errorMsg = error; }); if (isd.contents.some(topLevelContents =&gt; topLevelContents.contents.length)) { //be sure that mediaTimeEvents values are in the mp4 segment time ranges. startTime = (mediaTimeEvents[i] + offsetTime) &lt; startTimeSegment ? startTimeSegment : (mediaTimeEvents[i] + offsetTime); endTime = (mediaTimeEvents[i + 1] + offsetTime) &gt; endTimeSegment ? endTimeSegment : (mediaTimeEvents[i + 1] + offsetTime); if (startTime &lt; endTime) { captionArray.push({ start: startTime, end: endTime, type: 'html', cueID: getCueID(), isd: isd, images: images, embeddedImages: embeddedImages }); } } } if (errorMsg !== '') { logger.error(errorMsg); throw new Error(errorMsg); } return captionArray; } instance = { parse: parse }; setup(); return instance; } TTMLParser.__dashjs_factory_name = 'TTMLParser'; export default FactoryMaker.getSingletonFactory(TTMLParser); × Search results Close "},"core_Utils.js.html":{"id":"core_Utils.js.html","title":"Source: core/Utils.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: core/Utils.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @class * @ignore */ import path from 'path-browserify' import { UAParser } from 'ua-parser-js' class Utils { static mixin(dest, source, copy) { let s; let empty = {}; if (dest) { for (let name in source) { if (source.hasOwnProperty(name)) { s = source[name]; if (!(name in dest) || (dest[name] !== s &amp;&amp; (!(name in empty) || empty[name] !== s))) { if (typeof dest[name] === 'object' &amp;&amp; dest[name] !== null) { dest[name] = Utils.mixin(dest[name], s, copy); } else { dest[name] = copy(s); } } } } } return dest; } static clone(src) { if (!src || typeof src !== 'object') { return src; // anything } let r; if (src instanceof Array) { // array r = []; for (let i = 0, l = src.length; i &lt; l; ++i) { if (i in src) { r.push(Utils.clone(src[i])); } } } else { r = {}; } return Utils.mixin(r, src, Utils.clone); } static addAditionalQueryParameterToUrl(url, params) { try { if (!params || params.length === 0) { return url; } let modifiedUrl = new URL(url); params.forEach((param) =&gt; { if (param.key &amp;&amp; param.value) { modifiedUrl.searchParams.set(param.key, param.value); } }); return modifiedUrl.href; } catch (e) { return url; } } static parseHttpHeaders(headerStr) { let headers = {}; if (!headerStr) { return headers; } // Trim headerStr to fix a MS Edge bug with xhr.getAllResponseHeaders method // which send a string starting with a \"\\n\" character let headerPairs = headerStr.trim().split('\\u000d\\u000a'); for (let i = 0, ilen = headerPairs.length; i &lt; ilen; i++) { let headerPair = headerPairs[i]; let index = headerPair.indexOf('\\u003a\\u0020'); if (index &gt; 0) { headers[headerPair.substring(0, index)] = headerPair.substring(index + 2); } } return headers; } static generateUuid() { let dt = new Date().getTime(); const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = (dt + Math.random() * 16) % 16 | 0; dt = Math.floor(dt / 16); return (c == 'x' ? r : (r &amp; 0x3 | 0x8)).toString(16); }); return uuid; } static generateHashCode(string) { let hash = 0; if (string.length === 0) { return hash; } for (let i = 0; i &lt; string.length; i++) { const chr = string.charCodeAt(i); hash = ((hash &lt;&lt; 5) - hash) + chr; hash |= 0; } return hash; } /** * Compares both urls and returns a relative url (target relative to original) * @param {string} original * @param {string} target * @return {string|*} */ static getRelativeUrl(originalUrl, targetUrl) { try { const original = new URL(originalUrl); const target = new URL(targetUrl); // Unify the protocol to compare the origins original.protocol = target.protocol; if (original.origin !== target.origin) { return targetUrl; } // Use the relative path implementation of the path library. We need to cut off the actual filename in the end to get the relative path let relativePath = path.relative(original.pathname.substr(0, original.pathname.lastIndexOf('/')), target.pathname.substr(0, target.pathname.lastIndexOf('/'))); // In case the relative path is empty (both path are equal) return the filename only. Otherwise add a slash in front of the filename const startIndexOffset = relativePath.length === 0 ? 1 : 0; relativePath += target.pathname.substr(target.pathname.lastIndexOf('/') + startIndexOffset, target.pathname.length - 1); // Build the other candidate, e.g. the 'host relative' path that starts with \"/\", and return the shortest of the two candidates. if (target.pathname.length &lt; relativePath.length) { return target.pathname; } return relativePath; } catch (e) { return targetUrl } } static parseUserAgent(ua = null) { try { const uaString = ua === null ? typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase() : '' : ''; return UAParser(uaString); } catch(e) { return {}; } } } export default Utils; × Search results Close "},"streaming_controllers_XlinkController.js.html":{"id":"streaming_controllers_XlinkController.js.html","title":"Source: streaming/controllers/XlinkController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Source: streaming/controllers/XlinkController.js /** * 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 * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2013, Dash Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import XlinkLoader from '../XlinkLoader'; import EventBus from '../../core/EventBus'; import Events from '../../core/events/Events'; import FactoryMaker from '../../core/FactoryMaker'; import X2JS from '../../../externals/xml2json'; import URLUtils from '../utils/URLUtils'; import DashConstants from '../../dash/constants/DashConstants'; const RESOLVE_TYPE_ONLOAD = 'onLoad'; const RESOLVE_TYPE_ONACTUATE = 'onActuate'; const RESOLVE_TO_ZERO = 'urn:mpeg:dash:resolve-to-zero:2013'; function XlinkController(config) { config = config || {}; let context = this.context; let eventBus = EventBus(context).getInstance(); const urlUtils = URLUtils(context).getInstance(); let instance, matchers, iron, manifest, converter, xlinkLoader; function setup() { eventBus.on(Events.XLINK_ELEMENT_LOADED, onXlinkElementLoaded, instance); xlinkLoader = XlinkLoader(context).create({ errHandler: config.errHandler, dashMetrics: config.dashMetrics, mediaPlayerModel: config.mediaPlayerModel, requestModifier: config.requestModifier, settings: config.settings }); } function setMatchers(value) { if (value) { matchers = value; } } function setIron(value) { if (value) { iron = value; } } /** * &lt;p&gt;Triggers the resolution of the xlink.onLoad attributes in the manifest file &lt;/p&gt; * @param {Object} mpd - the manifest */ function resolveManifestOnLoad(mpd) { let elements; // First resolve all periods, so unnecessary requests inside onLoad Periods with Default content are avoided converter = new X2JS({ escapeMode: false, attributePrefix: '', arrayAccessForm: 'property', emptyNodeForm: 'object', stripWhitespaces: false, enableToStringFunc: false, ignoreRoot: true, matchers: matchers }); manifest = mpd; if (manifest.Period_asArray) { elements = getElementsToResolve(manifest.Period_asArray, manifest, DashConstants.PERIOD, RESOLVE_TYPE_ONLOAD); resolve(elements, DashConstants.PERIOD, RESOLVE_TYPE_ONLOAD); } else { eventBus.trigger(Events.XLINK_READY, {manifest: manifest}); } } function reset() { eventBus.off(Events.XLINK_ELEMENT_LOADED, onXlinkElementLoaded, instance); if (xlinkLoader) { xlinkLoader.reset(); xlinkLoader = null; } } function resolve(elements, type, resolveType) { let resolveObject = {}; let element, url; resolveObject.elements = elements; resolveObject.type = type; resolveObject.resolveType = resolveType; // If nothing to resolve, directly call allElementsLoaded if (resolveObject.elements.length === 0) { onXlinkAllElementsLoaded(resolveObject); } for (let i = 0; i &lt; resolveObject.elements.length; i++) { element = resolveObject.elements[i]; if (urlUtils.isHTTPURL(element.url)) { url = element.url; } else { url = element.originalContent.BaseURL + element.url; } xlinkLoader.load(url, element, resolveObject); } } function onXlinkElementLoaded(event) { let element, resolveObject; const openingTag = '&lt;response&gt;'; const closingTag = '&lt;/response&gt;'; let mergedContent = ''; element = event.element; resolveObject = event.resolveObject; // if the element resolved into content parse the content if (element.resolvedContent) { let index = 0; // we add a parent elements so the converter is able to parse multiple elements of the same type which are not wrapped inside a container if (element.resolvedContent.indexOf('&lt;?xml') === 0) { index = element.resolvedContent.indexOf('?&gt;') + 2; //find the closing position of the xml declaration, if it exists. } mergedContent = element.resolvedContent.substr(0,index) + openingTag + element.resolvedContent.substr(index) + closingTag; element.resolvedContent = converter.xml_str2json(mergedContent); } if (isResolvingFinished(resolveObject)) { onXlinkAllElementsLoaded(resolveObject); } } // We got to wait till all elements of the current queue are resolved before merging back function onXlinkAllElementsLoaded (resolveObject) { let elements = []; let i, obj; mergeElementsBack(resolveObject); if (resolveObject.resolveType === RESOLVE_TYPE_ONACTUATE) { eventBus.trigger(Events.XLINK_READY, { manifest: manifest }); } if (resolveObject.resolveType === RESOLVE_TYPE_ONLOAD) { switch (resolveObject.type) { // Start resolving the other elements. We can do Adaptation Set and EventStream in parallel case DashConstants.PERIOD: for (i = 0; i &lt; manifest[DashConstants.PERIOD + '_asArray'].length; i++) { obj = manifest[DashConstants.PERIOD + '_asArray'][i]; if (obj.hasOwnProperty(DashConstants.ADAPTATION_SET + '_asArray')) { elements = elements.concat(getElementsToResolve(obj[DashConstants.ADAPTATION_SET + '_asArray'], obj, DashConstants.ADAPTATION_SET, RESOLVE_TYPE_ONLOAD)); } if (obj.hasOwnProperty(DashConstants.EVENT_STREAM + '_asArray')) { elements = elements.concat(getElementsToResolve(obj[DashConstants.EVENT_STREAM + '_asArray'], obj, DashConstants.EVENT_STREAM, RESOLVE_TYPE_ONLOAD)); } } resolve(elements, DashConstants.ADAPTATION_SET, RESOLVE_TYPE_ONLOAD); break; case DashConstants.ADAPTATION_SET: // TODO: Resolve SegmentList here eventBus.trigger(Events.XLINK_READY, { manifest: manifest }); break; } } } // Returns the elements with the specific resolve Type function getElementsToResolve(elements, parentElement, type, resolveType) { let toResolve = []; let element, i, xlinkObject; // first remove all the resolve-to-zero elements for (i = elements.length - 1; i &gt;= 0; i--) { element = elements[i]; if (element.hasOwnProperty('xlink:href') &amp;&amp; element['xlink:href'] === RESOLVE_TO_ZERO) { elements.splice(i, 1); } } // now get the elements with the right resolve type for (i = 0; i &lt; elements.length; i++) { element = elements[i]; if (element.hasOwnProperty('xlink:href') &amp;&amp; element.hasOwnProperty('xlink:actuate') &amp;&amp; element['xlink:actuate'] === resolveType) { xlinkObject = createXlinkObject(element['xlink:href'], parentElement, type, i, resolveType, element); toResolve.push(xlinkObject); } } return toResolve; } function mergeElementsBack(resolveObject) { let resolvedElements = []; let element, type, obj, i, j, k; // Start merging back from the end because of index shifting. Note that the elements with the same parent have to be ordered by index ascending for (i = resolveObject.elements.length - 1; i &gt;= 0; i --) { element = resolveObject.elements[i]; type = element.type + '_asArray'; // Element couldn't be resolved or is TODO Inappropriate target: Remove all Xlink attributes if (!element.resolvedContent || isInappropriateTarget()) { delete element.originalContent['xlink:actuate']; delete element.originalContent['xlink:href']; resolvedElements.push(element.originalContent); } // Element was successfully resolved else if (element.resolvedContent) { for (j = 0; j &lt; element.resolvedContent[type].length; j++) { //TODO Contains another Xlink attribute with xlink:actuate set to onload. Remove all xLink attributes obj = element.resolvedContent[type][j]; resolvedElements.push(obj); } } // Replace the old elements in the parent with the resolved ones element.parentElement[type].splice(element.index, 1); for (k = 0; k &lt; resolvedElements.length; k++) { element.parentElement[type].splice(element.index + k, 0, resolvedElements[k]); } resolvedElements = []; } if (resolveObject.elements.length &gt; 0) { iron.run(manifest); } } function createXlinkObject(url, parentElement, type, index, resolveType, originalContent) { return { url: url, parentElement: parentElement, type: type, index: index, resolveType: resolveType, originalContent: originalContent, resolvedContent: null, resolved: false }; } // Check if all pending requests are finished function isResolvingFinished(elementsToResolve) { let i, obj; for (i = 0; i &lt; elementsToResolve.elements.length; i++) { obj = elementsToResolve.elements[i]; if (obj.resolved === false) { return false; } } return true; } // TODO : Do some syntax check here if the target is valid or not function isInappropriateTarget() { return false; } instance = { resolveManifestOnLoad: resolveManifestOnLoad, setMatchers: setMatchers, setIron: setIron, reset: reset }; setup(); return instance; } XlinkController.__dashjs_factory_name = 'XlinkController'; export default FactoryMaker.getClassFactory(XlinkController); × Search results Close "},"global.html":{"id":"global.html","title":"Global","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Global Members &lt;constant&gt; LICENSE_SERVER_MANIFEST_CONFIGURATIONS 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 rights, including patent rights, and no such rights are granted under this license. Copyright (c) 2013, Dash Industry Forum. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Dash Industry Forum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Source: streaming/protection/CommonEncryption.js, line 32 Type Definitions MediaType The media types Type: \"video\" | \"audio\" | \"text\" | \"image\" Source: streaming/MediaPlayer.js, line 86 × Search results Close "},"modules.list.html":{"id":"modules.list.html","title":"Modules","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Modules Classes Errors MediaPlayerEvents MediaPlayerModel MetricsReportingEvents MssErrors OfflineErrors OfflineEvents ProtectionErrors ProtectionEvents Events ADAPTATION_SET_REMOVED_NO_CAPABILITIES Event that is dispatched whenever an adaptation set is removed due to all representations not being supported. Source: streaming/MediaPlayerEvents.js, line 400 AST_IN_FUTURE Triggered when playback will not start yet as the MPD's availabilityStartTime is in the future. Check delay property in payload to determine time before playback will start. Source: streaming/MediaPlayerEvents.js, line 44 BUFFER_EMPTY Triggered when the video element's buffer state changes to stalled. Check mediaType in payload to determine type (Video, Audio, FragmentedText). Source: streaming/MediaPlayerEvents.js, line 52 BUFFER_LEVEL_STATE_CHANGED Triggered when the video element's buffer state changes, either stalled or loaded. Check payload for state. Source: streaming/MediaPlayerEvents.js, line 66 BUFFER_LEVEL_UPDATED Triggered when the buffer level of a media type has been updated Source: streaming/MediaPlayerEvents.js, line 72 BUFFER_LOADED Triggered when the video element's buffer state changes to loaded. Check mediaType in payload to determine type (Video, Audio, FragmentedText). Source: streaming/MediaPlayerEvents.js, line 59 CAN_PLAY Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the HAVE_ENOUGH_DATA readyState. Source: streaming/MediaPlayerEvents.js, line 250 CAN_PLAY_THROUGH This corresponds to the CAN_PLAY_THROUGH readyState. Source: streaming/MediaPlayerEvents.js, line 258 CAPTION_CONTAINER_RESIZE Triggered when the caption container is resized. Source: streaming/MediaPlayerEvents.js, line 244 CAPTION_RENDERED Triggered when a caption is rendered. Source: streaming/MediaPlayerEvents.js, line 238 CONFORMANCE_VIOLATION Event that is dispatched whenever the player encounters a potential conformance validation that might lead to unexpected/not optimal behavior Source: streaming/MediaPlayerEvents.js, line 388 CONTENT_STEERING_REQUEST_COMPLETED Triggered when a content steering request has completed. Source: streaming/MediaPlayerEvents.js, line 405 DYNAMIC_TO_STATIC Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand). Source: streaming/MediaPlayerEvents.js, line 78 ERROR Triggered when there is an error from the element or MSE source buffer. Source: streaming/MediaPlayerEvents.js, line 84 EVENT_MODE_ON_RECEIVE Dash events are triggered as soon as they were parsed. Source: streaming/MediaPlayerEvents.js, line 382 EVENT_MODE_ON_START Dash events are triggered at their respective start points on the timeline. Source: streaming/MediaPlayerEvents.js, line 376 FRAGMENT_LOADING_ABANDONED Triggered when a fragment download is abandoned due to detection of slow download base on the ABR abandon rule.. Source: streaming/MediaPlayerEvents.js, line 106 FRAGMENT_LOADING_COMPLETED Triggered when a fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 89 FRAGMENT_LOADING_PROGRESS Triggered when a partial fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 95 FRAGMENT_LOADING_STARTED Triggered when a fragment download has started. Source: streaming/MediaPlayerEvents.js, line 100 LOG Triggered when module:Debug logger methods are called. Source: streaming/MediaPlayerEvents.js, line 112 MANIFEST_LOADED Triggered when the manifest load is complete Source: streaming/MediaPlayerEvents.js, line 118 MANIFEST_VALIDITY_CHANGED Manifest validity changed - As a result of an MPD validity expiration event. Source: streaming/MediaPlayerEvents.js, line 370 METRIC_ADDED Triggered every time a new metric is added. Source: streaming/MediaPlayerEvents.js, line 136 METRIC_CHANGED Triggered when an individual metric is added, updated or cleared. Source: streaming/MediaPlayerEvents.js, line 130 METRIC_UPDATED Triggered every time a metric is updated. Source: streaming/MediaPlayerEvents.js, line 142 METRICS_CHANGED Triggered anytime there is a change to the overall metrics. Source: streaming/MediaPlayerEvents.js, line 124 PERIOD_SWITCH_COMPLETED Triggered at the stream end of a period. Source: streaming/MediaPlayerEvents.js, line 154 PERIOD_SWITCH_STARTED Triggered when a new stream (period) starts. Source: streaming/MediaPlayerEvents.js, line 148 PLAYBACK_ENDED Sent when playback completes. Source: streaming/MediaPlayerEvents.js, line 264 PLAYBACK_ERROR Sent when an error occurs. The element's error attribute contains more information. Source: streaming/MediaPlayerEvents.js, line 270 PLAYBACK_LOADED_DATA The event is fired when the frame at the current playback position of the media has finished loading; often the first frame Source: streaming/MediaPlayerEvents.js, line 290 PLAYBACK_METADATA_LOADED The media's metadata has finished loading; all attributes now contain as much useful information as they're going to. Source: streaming/MediaPlayerEvents.js, line 283 PLAYBACK_NOT_ALLOWED Sent when playback is not allowed (for example if user gesture is needed). Source: streaming/MediaPlayerEvents.js, line 277 PLAYBACK_PAUSED Sent when playback is paused. Source: streaming/MediaPlayerEvents.js, line 297 PLAYBACK_PLAYING Sent when the media begins to play (either for the first time, after having been paused, or after ending and then restarting). Source: streaming/MediaPlayerEvents.js, line 303 PLAYBACK_PROGRESS Sent periodically to inform interested parties of progress downloading the media. Information about the current amount of the media that has been downloaded is available in the media element's buffered attribute. Source: streaming/MediaPlayerEvents.js, line 311 PLAYBACK_RATE_CHANGED Sent when the playback speed changes. Source: streaming/MediaPlayerEvents.js, line 319 PLAYBACK_SEEKED Sent when a seek operation completes. Source: streaming/MediaPlayerEvents.js, line 325 PLAYBACK_SEEKING Sent when a seek operation begins. Source: streaming/MediaPlayerEvents.js, line 331 PLAYBACK_STALLED Sent when the video element reports stalled Source: streaming/MediaPlayerEvents.js, line 337 PLAYBACK_STARTED Sent when playback of the media starts after having been paused; that is, when playback is resumed after a prior pause event. Source: streaming/MediaPlayerEvents.js, line 343 PLAYBACK_TIME_UPDATED The time indicated by the element's currentTime attribute has changed. Source: streaming/MediaPlayerEvents.js, line 351 PLAYBACK_VOLUME_CHANGED Sent when the video element reports that the volume has changed Source: streaming/MediaPlayerEvents.js, line 357 PLAYBACK_WAITING Sent when the media playback has stopped because of a temporary lack of data. Source: streaming/MediaPlayerEvents.js, line 363 QUALITY_CHANGE_RENDERED Triggered when the new ABR quality is being rendered on-screen. Source: streaming/MediaPlayerEvents.js, line 166 QUALITY_CHANGE_REQUESTED Triggered when an ABR up /down switch is initiated; either by user in manual mode or auto mode via ABR rules. Source: streaming/MediaPlayerEvents.js, line 160 REPRESENTATION_SWITCH Event that is dispatched whenever the player switches to a different representation Source: streaming/MediaPlayerEvents.js, line 394 STREAM_ACTIVATED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 190 STREAM_DEACTIVATED Triggered when a stream (period) is deactivated Source: streaming/MediaPlayerEvents.js, line 196 STREAM_INITIALIZED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 202 STREAM_INITIALIZING Triggered when a stream (period) is being loaded Source: streaming/MediaPlayerEvents.js, line 178 STREAM_TEARDOWN_COMPLETE Triggered when the player has been reset. Source: streaming/MediaPlayerEvents.js, line 208 STREAM_UPDATED Triggered when a stream (period) is loaded Source: streaming/MediaPlayerEvents.js, line 184 TEXT_TRACK_ADDED Triggered when a text track is added to the video element's TextTrackList Source: streaming/MediaPlayerEvents.js, line 220 TEXT_TRACKS_ADDED Triggered once all text tracks detected in the MPD are added to the video element. Source: streaming/MediaPlayerEvents.js, line 214 TRACK_CHANGE_RENDERED Triggered when the new track is being rendered. Source: streaming/MediaPlayerEvents.js, line 172 TTML_PARSED Triggered when a ttml chunk is parsed. Source: streaming/MediaPlayerEvents.js, line 226 TTML_TO_PARSE Triggered when a ttml chunk has to be parsed. Source: streaming/MediaPlayerEvents.js, line 232 CMCD_DATA_GENERATED Triggered when CMCD data was generated for a HTTP request Source: streaming/metrics/MetricsReportingEvents.js, line 44 OFFLINE_RECORD_FINISHED Triggered when all record has been downloaded Source: offline/events/OfflineEvents.js, line 28 OFFLINE_RECORD_LOADEDMETADATA Triggered when all mediaInfo has been loaded Source: offline/events/OfflineEvents.js, line 10 OFFLINE_RECORD_STARTED Triggered when a record is initialized and download is started Source: offline/events/OfflineEvents.js, line 16 OFFLINE_RECORD_STOPPED Triggered when the user stop downloading a record Source: offline/events/OfflineEvents.js, line 22 KEY_ADDED Event ID for events delivered when a new key has been added Deprecated: The latest versions of the EME specification no longer use this event. {@MediaPlayer.models.protectionModel.eventList.KEY_STATUSES_CHANGED} is preferred. Source: streaming/protection/ProtectionEvents.js, line 58 KEY_ERROR Event ID for events delivered when an error is encountered by the CDM while processing a license server response message Source: streaming/protection/ProtectionEvents.js, line 68 KEY_MESSAGE Event ID for events delivered when the protection set receives a key message from the CDM Source: streaming/protection/ProtectionEvents.js, line 75 KEY_SESSION_CLOSED Event ID for events delivered when a key session close process has completed Source: streaming/protection/ProtectionEvents.js, line 82 KEY_SESSION_CREATED Event ID for events delivered when a new key sessions creation process has completed Source: streaming/protection/ProtectionEvents.js, line 89 KEY_SESSION_REMOVED Event ID for events delivered when a key session removal process has completed Source: streaming/protection/ProtectionEvents.js, line 96 KEY_STATUSES_CHANGED Event ID for events delivered when the status of one or more decryption keys has changed Source: streaming/protection/ProtectionEvents.js, line 103 KEY_SYSTEM_SELECTED Event ID for events delivered when a key system selection procedure completes Source: streaming/protection/ProtectionEvents.js, line 117 LICENSE_REQUEST_COMPLETE Event ID for events delivered when a license request procedure has completed Source: streaming/protection/ProtectionEvents.js, line 124 LICENSE_REQUEST_SENDING Sending a license rquest Source: streaming/protection/ProtectionEvents.js, line 131 PROTECTION_CREATED Event ID for events delivered when the Protection system is detected and created. Source: streaming/protection/ProtectionEvents.js, line 143 PROTECTION_DESTROYED Event ID for events delivered when the Protection system is destroyed. Source: streaming/protection/ProtectionEvents.js, line 149 × Search results Close "},"classes.list.html":{"id":"classes.list.html","title":"Classes","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Classes Classes Errors MediaPlayerEvents MediaPlayerModel MetricsReportingEvents MssErrors OfflineErrors OfflineEvents ProtectionErrors ProtectionEvents Events ADAPTATION_SET_REMOVED_NO_CAPABILITIES Event that is dispatched whenever an adaptation set is removed due to all representations not being supported. Source: streaming/MediaPlayerEvents.js, line 400 AST_IN_FUTURE Triggered when playback will not start yet as the MPD's availabilityStartTime is in the future. Check delay property in payload to determine time before playback will start. Source: streaming/MediaPlayerEvents.js, line 44 BUFFER_EMPTY Triggered when the video element's buffer state changes to stalled. Check mediaType in payload to determine type (Video, Audio, FragmentedText). Source: streaming/MediaPlayerEvents.js, line 52 BUFFER_LEVEL_STATE_CHANGED Triggered when the video element's buffer state changes, either stalled or loaded. Check payload for state. Source: streaming/MediaPlayerEvents.js, line 66 BUFFER_LEVEL_UPDATED Triggered when the buffer level of a media type has been updated Source: streaming/MediaPlayerEvents.js, line 72 BUFFER_LOADED Triggered when the video element's buffer state changes to loaded. Check mediaType in payload to determine type (Video, Audio, FragmentedText). Source: streaming/MediaPlayerEvents.js, line 59 CAN_PLAY Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the HAVE_ENOUGH_DATA readyState. Source: streaming/MediaPlayerEvents.js, line 250 CAN_PLAY_THROUGH This corresponds to the CAN_PLAY_THROUGH readyState. Source: streaming/MediaPlayerEvents.js, line 258 CAPTION_CONTAINER_RESIZE Triggered when the caption container is resized. Source: streaming/MediaPlayerEvents.js, line 244 CAPTION_RENDERED Triggered when a caption is rendered. Source: streaming/MediaPlayerEvents.js, line 238 CONFORMANCE_VIOLATION Event that is dispatched whenever the player encounters a potential conformance validation that might lead to unexpected/not optimal behavior Source: streaming/MediaPlayerEvents.js, line 388 CONTENT_STEERING_REQUEST_COMPLETED Triggered when a content steering request has completed. Source: streaming/MediaPlayerEvents.js, line 405 DYNAMIC_TO_STATIC Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand). Source: streaming/MediaPlayerEvents.js, line 78 ERROR Triggered when there is an error from the element or MSE source buffer. Source: streaming/MediaPlayerEvents.js, line 84 EVENT_MODE_ON_RECEIVE Dash events are triggered as soon as they were parsed. Source: streaming/MediaPlayerEvents.js, line 382 EVENT_MODE_ON_START Dash events are triggered at their respective start points on the timeline. Source: streaming/MediaPlayerEvents.js, line 376 FRAGMENT_LOADING_ABANDONED Triggered when a fragment download is abandoned due to detection of slow download base on the ABR abandon rule.. Source: streaming/MediaPlayerEvents.js, line 106 FRAGMENT_LOADING_COMPLETED Triggered when a fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 89 FRAGMENT_LOADING_PROGRESS Triggered when a partial fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 95 FRAGMENT_LOADING_STARTED Triggered when a fragment download has started. Source: streaming/MediaPlayerEvents.js, line 100 LOG Triggered when module:Debug logger methods are called. Source: streaming/MediaPlayerEvents.js, line 112 MANIFEST_LOADED Triggered when the manifest load is complete Source: streaming/MediaPlayerEvents.js, line 118 MANIFEST_VALIDITY_CHANGED Manifest validity changed - As a result of an MPD validity expiration event. Source: streaming/MediaPlayerEvents.js, line 370 METRIC_ADDED Triggered every time a new metric is added. Source: streaming/MediaPlayerEvents.js, line 136 METRIC_CHANGED Triggered when an individual metric is added, updated or cleared. Source: streaming/MediaPlayerEvents.js, line 130 METRIC_UPDATED Triggered every time a metric is updated. Source: streaming/MediaPlayerEvents.js, line 142 METRICS_CHANGED Triggered anytime there is a change to the overall metrics. Source: streaming/MediaPlayerEvents.js, line 124 PERIOD_SWITCH_COMPLETED Triggered at the stream end of a period. Source: streaming/MediaPlayerEvents.js, line 154 PERIOD_SWITCH_STARTED Triggered when a new stream (period) starts. Source: streaming/MediaPlayerEvents.js, line 148 PLAYBACK_ENDED Sent when playback completes. Source: streaming/MediaPlayerEvents.js, line 264 PLAYBACK_ERROR Sent when an error occurs. The element's error attribute contains more information. Source: streaming/MediaPlayerEvents.js, line 270 PLAYBACK_LOADED_DATA The event is fired when the frame at the current playback position of the media has finished loading; often the first frame Source: streaming/MediaPlayerEvents.js, line 290 PLAYBACK_METADATA_LOADED The media's metadata has finished loading; all attributes now contain as much useful information as they're going to. Source: streaming/MediaPlayerEvents.js, line 283 PLAYBACK_NOT_ALLOWED Sent when playback is not allowed (for example if user gesture is needed). Source: streaming/MediaPlayerEvents.js, line 277 PLAYBACK_PAUSED Sent when playback is paused. Source: streaming/MediaPlayerEvents.js, line 297 PLAYBACK_PLAYING Sent when the media begins to play (either for the first time, after having been paused, or after ending and then restarting). Source: streaming/MediaPlayerEvents.js, line 303 PLAYBACK_PROGRESS Sent periodically to inform interested parties of progress downloading the media. Information about the current amount of the media that has been downloaded is available in the media element's buffered attribute. Source: streaming/MediaPlayerEvents.js, line 311 PLAYBACK_RATE_CHANGED Sent when the playback speed changes. Source: streaming/MediaPlayerEvents.js, line 319 PLAYBACK_SEEKED Sent when a seek operation completes. Source: streaming/MediaPlayerEvents.js, line 325 PLAYBACK_SEEKING Sent when a seek operation begins. Source: streaming/MediaPlayerEvents.js, line 331 PLAYBACK_STALLED Sent when the video element reports stalled Source: streaming/MediaPlayerEvents.js, line 337 PLAYBACK_STARTED Sent when playback of the media starts after having been paused; that is, when playback is resumed after a prior pause event. Source: streaming/MediaPlayerEvents.js, line 343 PLAYBACK_TIME_UPDATED The time indicated by the element's currentTime attribute has changed. Source: streaming/MediaPlayerEvents.js, line 351 PLAYBACK_VOLUME_CHANGED Sent when the video element reports that the volume has changed Source: streaming/MediaPlayerEvents.js, line 357 PLAYBACK_WAITING Sent when the media playback has stopped because of a temporary lack of data. Source: streaming/MediaPlayerEvents.js, line 363 QUALITY_CHANGE_RENDERED Triggered when the new ABR quality is being rendered on-screen. Source: streaming/MediaPlayerEvents.js, line 166 QUALITY_CHANGE_REQUESTED Triggered when an ABR up /down switch is initiated; either by user in manual mode or auto mode via ABR rules. Source: streaming/MediaPlayerEvents.js, line 160 REPRESENTATION_SWITCH Event that is dispatched whenever the player switches to a different representation Source: streaming/MediaPlayerEvents.js, line 394 STREAM_ACTIVATED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 190 STREAM_DEACTIVATED Triggered when a stream (period) is deactivated Source: streaming/MediaPlayerEvents.js, line 196 STREAM_INITIALIZED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 202 STREAM_INITIALIZING Triggered when a stream (period) is being loaded Source: streaming/MediaPlayerEvents.js, line 178 STREAM_TEARDOWN_COMPLETE Triggered when the player has been reset. Source: streaming/MediaPlayerEvents.js, line 208 STREAM_UPDATED Triggered when a stream (period) is loaded Source: streaming/MediaPlayerEvents.js, line 184 TEXT_TRACK_ADDED Triggered when a text track is added to the video element's TextTrackList Source: streaming/MediaPlayerEvents.js, line 220 TEXT_TRACKS_ADDED Triggered once all text tracks detected in the MPD are added to the video element. Source: streaming/MediaPlayerEvents.js, line 214 TRACK_CHANGE_RENDERED Triggered when the new track is being rendered. Source: streaming/MediaPlayerEvents.js, line 172 TTML_PARSED Triggered when a ttml chunk is parsed. Source: streaming/MediaPlayerEvents.js, line 226 TTML_TO_PARSE Triggered when a ttml chunk has to be parsed. Source: streaming/MediaPlayerEvents.js, line 232 CMCD_DATA_GENERATED Triggered when CMCD data was generated for a HTTP request Source: streaming/metrics/MetricsReportingEvents.js, line 44 OFFLINE_RECORD_FINISHED Triggered when all record has been downloaded Source: offline/events/OfflineEvents.js, line 28 OFFLINE_RECORD_LOADEDMETADATA Triggered when all mediaInfo has been loaded Source: offline/events/OfflineEvents.js, line 10 OFFLINE_RECORD_STARTED Triggered when a record is initialized and download is started Source: offline/events/OfflineEvents.js, line 16 OFFLINE_RECORD_STOPPED Triggered when the user stop downloading a record Source: offline/events/OfflineEvents.js, line 22 KEY_ADDED Event ID for events delivered when a new key has been added Deprecated: The latest versions of the EME specification no longer use this event. {@MediaPlayer.models.protectionModel.eventList.KEY_STATUSES_CHANGED} is preferred. Source: streaming/protection/ProtectionEvents.js, line 58 KEY_ERROR Event ID for events delivered when an error is encountered by the CDM while processing a license server response message Source: streaming/protection/ProtectionEvents.js, line 68 KEY_MESSAGE Event ID for events delivered when the protection set receives a key message from the CDM Source: streaming/protection/ProtectionEvents.js, line 75 KEY_SESSION_CLOSED Event ID for events delivered when a key session close process has completed Source: streaming/protection/ProtectionEvents.js, line 82 KEY_SESSION_CREATED Event ID for events delivered when a new key sessions creation process has completed Source: streaming/protection/ProtectionEvents.js, line 89 KEY_SESSION_REMOVED Event ID for events delivered when a key session removal process has completed Source: streaming/protection/ProtectionEvents.js, line 96 KEY_STATUSES_CHANGED Event ID for events delivered when the status of one or more decryption keys has changed Source: streaming/protection/ProtectionEvents.js, line 103 KEY_SYSTEM_SELECTED Event ID for events delivered when a key system selection procedure completes Source: streaming/protection/ProtectionEvents.js, line 117 LICENSE_REQUEST_COMPLETE Event ID for events delivered when a license request procedure has completed Source: streaming/protection/ProtectionEvents.js, line 124 LICENSE_REQUEST_SENDING Sending a license rquest Source: streaming/protection/ProtectionEvents.js, line 131 PROTECTION_CREATED Event ID for events delivered when the Protection system is detected and created. Source: streaming/protection/ProtectionEvents.js, line 143 PROTECTION_DESTROYED Event ID for events delivered when the Protection system is destroyed. Source: streaming/protection/ProtectionEvents.js, line 149 × Search results Close "},"index.html":{"id":"index.html","title":"Index","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Build status (CircleCI): Join #dashjs on Slack! Migration from v3.x to v4.0 If you are migrating from dash.js v3.x to dash.js v4.x please read the migration document found here. Overview A reference client implementation for the playback of MPEG DASH via JavaScript and compliant browsers. Learn more about DASH IF Reference Client on our wiki. If your intent is to use the player code without contributing back to this project, then use the MASTER branch which holds the approved and stable public releases. If your goal is to improve or extend the code and contribute back to this project, then you should make your changes in, and submit a pull request against, the DEVELOPMENT branch. Read our CONTRIBUTION.md file for a walk-through of the contribution process. All new work should be in the development branch. Master is now reserved for tagged builds. Demo and reference players All these reference builds and minified files are available under both http and https. Samples Multiple dash.js samples covering a wide set of common use cases. Reference players The released pre-built reference players if you want direct access without writing any Javascript. The nightly build of the /dev branch reference player, is pre-release but contains the latest fixes. It is a good place to start if you are debugging playback problems. CDN hosted files The latest minified files have been hosted on a global CDN and are free to use in production: dash.all.min.js dash.all.debug.js In addition, all the releases are available under the following urls. Replace \"vx.x.x\" with the release version, for instance \"v3.1.0\". http://cdn.dashjs.org/vx.x.x/dash.all.min.js http://cdn.dashjs.org/vx.x.x/dash.all.debug.js Documentation Full API Documentation is available describing all public methods, interfaces, properties, and events. For help, join our Slack channel, our email list and read our wiki. Tutorials Detailed information on specific topics can be found in our tutorials: Low latency streaming UTCTiming Clock synchronization Digital Rights Management (DRM) and license acquisition Buffer and scheduling logic Getting Started The standard setup method uses javascript to initialize and provide video details to dash.js. MediaPlayerFactory provides an alternative declarative setup syntax. Standard Setup Create a video element somewhere in your html. For our purposes, make sure the controls attribute is present. &lt;video id=\"videoPlayer\" controls&gt;&lt;/video&gt; Add dash.all.min.js to the end of the body. &lt;body&gt; ... &lt;script src=\"yourPathToDash/dash.all.min.js\"&gt;&lt;/script&gt; &lt;/body&gt; Now comes the good stuff. We need to create a MediaPlayer and initialize it. var url = \"https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd\"; var player = dashjs.MediaPlayer().create(); player.initialize(document.querySelector(\"#videoPlayer\"), url, true); When it is all done, it should look similar to this: &lt;!doctype html&gt; &lt;html&gt; &lt;head&gt; &lt;title&gt;Dash.js Rocks&lt;/title&gt; &lt;style&gt; video { width: 640px; height: 360px; } &lt;/style&gt; &lt;/head&gt; &lt;body&gt; &lt;div&gt; &lt;video id=\"videoPlayer\" controls&gt;&lt;/video&gt; &lt;/div&gt; &lt;script src=\"yourPathToDash/dash.all.min.js\"&gt;&lt;/script&gt; &lt;script&gt; (function(){ var url = \"https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd\"; var player = dashjs.MediaPlayer().create(); player.initialize(document.querySelector(\"#videoPlayer\"), url, true); })(); &lt;/script&gt; &lt;/body&gt; &lt;/html&gt; Module Setup We publish dash.js to npm. Examples of how to use dash.js in different module bundlers can be found in the samples/modules directory. MediaPlayerFactory Setup An alternative way to build a Dash.js player in your web page is to use the MediaPlayerFactory. The MediaPlayerFactory will automatically instantiate and initialize the MediaPlayer module on appropriately tagged video elements. Create a video element somewhere in your html and provide the path to your mpd file as src. Also ensure that your video element has the data-dashjs-player attribute on it. &lt;video data-dashjs-player autoplay src=\"https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd\" controls&gt; &lt;/video&gt; Add dash.all.min.js to the end of the body. &lt;body&gt; ... &lt;script src=\"yourPathToDash/dash.all.min.js\"&gt;&lt;/script&gt; &lt;/body&gt; When it is all done, it should look similar to this: &lt;!doctype html&gt; &lt;html&gt; &lt;head&gt; &lt;title&gt;Dash.js Rocks&lt;/title&gt; &lt;style&gt; video { width: 640px; height: 360px; } &lt;/style&gt; &lt;/head&gt; &lt;body&gt; &lt;div&gt; &lt;video data-dashjs-player autoplay src=\"https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd\" controls&gt; &lt;/video&gt; &lt;/div&gt; &lt;script src=\"yourPathToDash/dash.all.min.js\"&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt; Quick Start for Developers Install Core Dependencies install nodejs Checkout project repository (default branch: development) git clone https://github.com/Dash-Industry-Forum/dash.js.git Install dependencies npm install Build, watch file changes and launch samples page, which has links that point to reference player and to other examples (basic examples, captioning, ads, live, etc). npm run start Other Tasks to Build / Run Tests on Commandline. Build distribution files (minification included) npm run build Build and watch distribution files npm run dev Run linter on source files (linter is also applied when building files) npm run lint Run unit tests npm run test Generate API jsdoc npm run doc Troubleshooting In case the build process is failing make sure to use an up-to-date node.js version. The build process was successfully tested with node.js version 14.16.1. License dash.js is released under BSD license Tested With × Search results Close "},"Errors.html":{"id":"Errors.html","title":"Class: Errors","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: Errors Errors Errors declaration new Errors() Source: core/errors/Errors.js, line 36 Members APPEND_ERROR_CODE Error code returned when the append operation in the SourceBuffer failed Source: core/errors/Errors.js, line 83 CAPABILITY_MEDIAKEYS_ERROR_CODE Error code returned when Protected contents are not supported Source: core/errors/Errors.js, line 103 CAPABILITY_MEDIASOURCE_ERROR_CODE Error code returned when MediaSource is not supported by the browser Source: core/errors/Errors.js, line 98 DATA_UPDATE_FAILED_ERROR_CODE Error code returned when updating the internal objects after loading an MPD failed Source: core/errors/Errors.js, line 93 DOWNLOAD_ERROR_ID_CONTENT_CODE Error code returned when loading the media content failed Source: core/errors/Errors.js, line 118 DOWNLOAD_ERROR_ID_INITIALIZATION_CODE Error code returned when loading the init segment failed Source: core/errors/Errors.js, line 123 DOWNLOAD_ERROR_ID_MANIFEST_CODE Error code returned when loading the manifest failed Source: core/errors/Errors.js, line 108 DOWNLOAD_ERROR_ID_SIDX_CODE Error code returned when loading the sidx failed Source: core/errors/Errors.js, line 113 DOWNLOAD_ERROR_ID_XLINK_CODE Error code returned when loading the XLink content failed Source: core/errors/Errors.js, line 128 FRAGMENT_LOADER_LOADING_FAILURE_ERROR_CODE Error code returned when loading a fragment failed Source: core/errors/Errors.js, line 68 FRAGMENT_LOADER_NULL_REQUEST_ERROR_CODE Error code returned when the FragmentLoader did not receive a request object Source: core/errors/Errors.js, line 73 MANIFEST_ERROR_ID_MULTIPLEXED_CODE Error code returned when a 'muxed' media type has been detected in the manifest. This type is not supported Source: core/errors/Errors.js, line 149 MANIFEST_ERROR_ID_NOSTREAMS_CODE Error code returned when no stream (period) has been detected in the manifest Source: core/errors/Errors.js, line 138 MANIFEST_ERROR_ID_PARSE_CODE Error code returned when parsing the MPD resulted in a logical error Source: core/errors/Errors.js, line 133 MANIFEST_LOADER_LOADING_FAILURE_ERROR_CODE Error code returned when a manifest loading error occurs Source: core/errors/Errors.js, line 48 MANIFEST_LOADER_PARSING_FAILURE_ERROR_CODE Error code returned when a manifest parsing error occurs Source: core/errors/Errors.js, line 43 MEDIASOURCE_TYPE_UNSUPPORTED_CODE Error code returned when a media source type is not supported Source: core/errors/Errors.js, line 154 REMOVE_ERROR_CODE Error code returned when the remove operation in the SourceBuffer failed Source: core/errors/Errors.js, line 88 SEGMENT_BASE_LOADER_ERROR_CODE Error code returned when no segment ranges could be determined from the sidx box Source: core/errors/Errors.js, line 58 TIME_SYNC_FAILED_ERROR_CODE Error code returned when the time synchronization failed Source: core/errors/Errors.js, line 63 TIMED_TEXT_ERROR_ID_PARSE_CODE Error code returned when something wrong has happened during parsing and appending subtitles (TTML or VTT) Source: core/errors/Errors.js, line 143 URL_RESOLUTION_FAILED_GENERIC_ERROR_CODE Error code returned when the BaseUrl resolution failed Source: core/errors/Errors.js, line 78 XLINK_LOADER_LOADING_FAILURE_ERROR_CODE Error code returned when a xlink loading error occurs Source: core/errors/Errors.js, line 53 × Search results Close "},"MediaPlayerEvents.html":{"id":"MediaPlayerEvents.html","title":"Class: MediaPlayerEvents","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: MediaPlayerEvents MediaPlayerEvents new MediaPlayerEvents() Public facing external events to be used when developing a player that implements dash.js. Implements: EventsBase Source: streaming/MediaPlayerEvents.js, line 37 Events ADAPTATION_SET_REMOVED_NO_CAPABILITIES Event that is dispatched whenever an adaptation set is removed due to all representations not being supported. Source: streaming/MediaPlayerEvents.js, line 400 AST_IN_FUTURE Triggered when playback will not start yet as the MPD's availabilityStartTime is in the future. Check delay property in payload to determine time before playback will start. Source: streaming/MediaPlayerEvents.js, line 44 BUFFER_EMPTY Triggered when the video element's buffer state changes to stalled. Check mediaType in payload to determine type (Video, Audio, FragmentedText). Source: streaming/MediaPlayerEvents.js, line 52 BUFFER_LEVEL_STATE_CHANGED Triggered when the video element's buffer state changes, either stalled or loaded. Check payload for state. Source: streaming/MediaPlayerEvents.js, line 66 BUFFER_LEVEL_UPDATED Triggered when the buffer level of a media type has been updated Source: streaming/MediaPlayerEvents.js, line 72 BUFFER_LOADED Triggered when the video element's buffer state changes to loaded. Check mediaType in payload to determine type (Video, Audio, FragmentedText). Source: streaming/MediaPlayerEvents.js, line 59 CAN_PLAY Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the HAVE_ENOUGH_DATA readyState. Source: streaming/MediaPlayerEvents.js, line 250 CAN_PLAY_THROUGH This corresponds to the CAN_PLAY_THROUGH readyState. Source: streaming/MediaPlayerEvents.js, line 258 CAPTION_CONTAINER_RESIZE Triggered when the caption container is resized. Source: streaming/MediaPlayerEvents.js, line 244 CAPTION_RENDERED Triggered when a caption is rendered. Source: streaming/MediaPlayerEvents.js, line 238 CONFORMANCE_VIOLATION Event that is dispatched whenever the player encounters a potential conformance validation that might lead to unexpected/not optimal behavior Source: streaming/MediaPlayerEvents.js, line 388 CONTENT_STEERING_REQUEST_COMPLETED Triggered when a content steering request has completed. Source: streaming/MediaPlayerEvents.js, line 405 DYNAMIC_TO_STATIC Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand). Source: streaming/MediaPlayerEvents.js, line 78 ERROR Triggered when there is an error from the element or MSE source buffer. Source: streaming/MediaPlayerEvents.js, line 84 EVENT_MODE_ON_RECEIVE Dash events are triggered as soon as they were parsed. Source: streaming/MediaPlayerEvents.js, line 382 EVENT_MODE_ON_START Dash events are triggered at their respective start points on the timeline. Source: streaming/MediaPlayerEvents.js, line 376 FRAGMENT_LOADING_ABANDONED Triggered when a fragment download is abandoned due to detection of slow download base on the ABR abandon rule.. Source: streaming/MediaPlayerEvents.js, line 106 FRAGMENT_LOADING_COMPLETED Triggered when a fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 89 FRAGMENT_LOADING_PROGRESS Triggered when a partial fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 95 FRAGMENT_LOADING_STARTED Triggered when a fragment download has started. Source: streaming/MediaPlayerEvents.js, line 100 LOG Triggered when module:Debug logger methods are called. Source: streaming/MediaPlayerEvents.js, line 112 MANIFEST_LOADED Triggered when the manifest load is complete Source: streaming/MediaPlayerEvents.js, line 118 MANIFEST_VALIDITY_CHANGED Manifest validity changed - As a result of an MPD validity expiration event. Source: streaming/MediaPlayerEvents.js, line 370 METRIC_ADDED Triggered every time a new metric is added. Source: streaming/MediaPlayerEvents.js, line 136 METRIC_CHANGED Triggered when an individual metric is added, updated or cleared. Source: streaming/MediaPlayerEvents.js, line 130 METRIC_UPDATED Triggered every time a metric is updated. Source: streaming/MediaPlayerEvents.js, line 142 METRICS_CHANGED Triggered anytime there is a change to the overall metrics. Source: streaming/MediaPlayerEvents.js, line 124 PERIOD_SWITCH_COMPLETED Triggered at the stream end of a period. Source: streaming/MediaPlayerEvents.js, line 154 PERIOD_SWITCH_STARTED Triggered when a new stream (period) starts. Source: streaming/MediaPlayerEvents.js, line 148 PLAYBACK_ENDED Sent when playback completes. Source: streaming/MediaPlayerEvents.js, line 264 PLAYBACK_ERROR Sent when an error occurs. The element's error attribute contains more information. Source: streaming/MediaPlayerEvents.js, line 270 PLAYBACK_LOADED_DATA The event is fired when the frame at the current playback position of the media has finished loading; often the first frame Source: streaming/MediaPlayerEvents.js, line 290 PLAYBACK_METADATA_LOADED The media's metadata has finished loading; all attributes now contain as much useful information as they're going to. Source: streaming/MediaPlayerEvents.js, line 283 PLAYBACK_NOT_ALLOWED Sent when playback is not allowed (for example if user gesture is needed). Source: streaming/MediaPlayerEvents.js, line 277 PLAYBACK_PAUSED Sent when playback is paused. Source: streaming/MediaPlayerEvents.js, line 297 PLAYBACK_PLAYING Sent when the media begins to play (either for the first time, after having been paused, or after ending and then restarting). Source: streaming/MediaPlayerEvents.js, line 303 PLAYBACK_PROGRESS Sent periodically to inform interested parties of progress downloading the media. Information about the current amount of the media that has been downloaded is available in the media element's buffered attribute. Source: streaming/MediaPlayerEvents.js, line 311 PLAYBACK_RATE_CHANGED Sent when the playback speed changes. Source: streaming/MediaPlayerEvents.js, line 319 PLAYBACK_SEEKED Sent when a seek operation completes. Source: streaming/MediaPlayerEvents.js, line 325 PLAYBACK_SEEKING Sent when a seek operation begins. Source: streaming/MediaPlayerEvents.js, line 331 PLAYBACK_STALLED Sent when the video element reports stalled Source: streaming/MediaPlayerEvents.js, line 337 PLAYBACK_STARTED Sent when playback of the media starts after having been paused; that is, when playback is resumed after a prior pause event. Source: streaming/MediaPlayerEvents.js, line 343 PLAYBACK_TIME_UPDATED The time indicated by the element's currentTime attribute has changed. Source: streaming/MediaPlayerEvents.js, line 351 PLAYBACK_VOLUME_CHANGED Sent when the video element reports that the volume has changed Source: streaming/MediaPlayerEvents.js, line 357 PLAYBACK_WAITING Sent when the media playback has stopped because of a temporary lack of data. Source: streaming/MediaPlayerEvents.js, line 363 QUALITY_CHANGE_RENDERED Triggered when the new ABR quality is being rendered on-screen. Source: streaming/MediaPlayerEvents.js, line 166 QUALITY_CHANGE_REQUESTED Triggered when an ABR up /down switch is initiated; either by user in manual mode or auto mode via ABR rules. Source: streaming/MediaPlayerEvents.js, line 160 REPRESENTATION_SWITCH Event that is dispatched whenever the player switches to a different representation Source: streaming/MediaPlayerEvents.js, line 394 STREAM_ACTIVATED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 190 STREAM_DEACTIVATED Triggered when a stream (period) is deactivated Source: streaming/MediaPlayerEvents.js, line 196 STREAM_INITIALIZED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 202 STREAM_INITIALIZING Triggered when a stream (period) is being loaded Source: streaming/MediaPlayerEvents.js, line 178 STREAM_TEARDOWN_COMPLETE Triggered when the player has been reset. Source: streaming/MediaPlayerEvents.js, line 208 STREAM_UPDATED Triggered when a stream (period) is loaded Source: streaming/MediaPlayerEvents.js, line 184 TEXT_TRACK_ADDED Triggered when a text track is added to the video element's TextTrackList Source: streaming/MediaPlayerEvents.js, line 220 TEXT_TRACKS_ADDED Triggered once all text tracks detected in the MPD are added to the video element. Source: streaming/MediaPlayerEvents.js, line 214 TRACK_CHANGE_RENDERED Triggered when the new track is being rendered. Source: streaming/MediaPlayerEvents.js, line 172 TTML_PARSED Triggered when a ttml chunk is parsed. Source: streaming/MediaPlayerEvents.js, line 226 TTML_TO_PARSE Triggered when a ttml chunk has to be parsed. Source: streaming/MediaPlayerEvents.js, line 232 × Search results Close "},"MediaPlayerModel.html":{"id":"MediaPlayerModel.html","title":"Class: MediaPlayerModel","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: MediaPlayerModel MediaPlayerModel new MediaPlayerModel() We use this model as a wrapper/proxy between Settings.js and classes that are using parameters from Settings.js. In some cases we require additional logic to be applied and the settings might need to be adjusted before being used. Source: streaming/models/MediaPlayerModel.js, line 48 Methods &lt;inner&gt; getAbrBitrateParameter(field, mediaType) Returns the min,max or initial bitrate for a specific media type. Parameters: Name Type Description field string mediaType string Source: streaming/models/MediaPlayerModel.js, line 120 &lt;inner&gt; getCatchupMaxDrift() Returns the maximum drift allowed before applying a seek back to the live edge when the catchup mode is enabled Source: streaming/models/MediaPlayerModel.js, line 73 Returns: Type number &lt;inner&gt; getCatchupModeEnabled() Returns whether the catchup mode is activated via the settings or internally in the PlaybackController Source: streaming/models/MediaPlayerModel.js, line 107 Returns: Type boolean &lt;inner&gt; getCatchupPlaybackRate() Returns the maximum playback rate to be used when applying the catchup mechanism Source: streaming/models/MediaPlayerModel.js, line 90 Returns: Type number &lt;inner&gt; getInitialBufferLevel() Returns the initial buffer level taking the stable buffer time into account Source: streaming/models/MediaPlayerModel.js, line 143 Returns: Type number &lt;inner&gt; getRetryAttemptsForType(type) Returns the number of retry attempts for a specific media type Parameters: Name Type Description type Source: streaming/models/MediaPlayerModel.js, line 169 Returns: Type number &lt;inner&gt; getRetryIntervalsForType(type) Returns the retry interval for a specific media type Parameters: Name Type Description type Source: streaming/models/MediaPlayerModel.js, line 180 Returns: Type number &lt;inner&gt; getStableBufferTime() Returns the stable buffer time taking the live delay into account Source: streaming/models/MediaPlayerModel.js, line 157 Returns: Type number × Search results Close "},"MetricsReportingEvents.html":{"id":"MetricsReportingEvents.html","title":"Class: MetricsReportingEvents","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: MetricsReportingEvents MetricsReportingEvents new MetricsReportingEvents() Implements: EventsBase Source: streaming/metrics/MetricsReportingEvents.js, line 37 Events CMCD_DATA_GENERATED Triggered when CMCD data was generated for a HTTP request Source: streaming/metrics/MetricsReportingEvents.js, line 44 × Search results Close "},"module-DashAdapter.html":{"id":"module-DashAdapter.html","title":"Module: DashAdapter","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Module: DashAdapter The DashAdapter module can be accessed using the MediaPlayer API getDashAdapter() Source: dash/DashAdapter.js, line 43 Methods getAdaptationForType(periodIndex, type, streamInfo) Returns the AdaptationSet for a given period index and a given mediaType. Parameters: Name Type Description periodIndex number type MediaType streamInfo object Source: dash/DashAdapter.js, line 163 Returns: adaptation Type null | object getAllMediaInfoForType(streamInfo, type, externalManifest) Returns all the mediaInfos for a given mediaType and the corresponding streamInfo. Parameters: Name Type Description streamInfo object type MediaType externalManifest object Set to null or undefined if no external manifest is to be used Source: dash/DashAdapter.js, line 287 Returns: mediaArr Type Array getAvailabilityStartTime(externalManifest) Returns the availabilityStartTime as specified in the manifest Parameters: Name Type Description externalManifest object Omit this value if no external manifest should be used Source: dash/DashAdapter.js, line 593 Returns: availabilityStartTime Type string getBandwidthForRepresentation(representationId, periodIdx) Returns the bandwidth for a given representation id and the corresponding period index Parameters: Name Type Description representationId number periodIdx number Source: dash/DashAdapter.js, line 787 Returns: bandwidth Type number getCodec(adaptation, representationId, addResolutionInfo) Returns the codec for a given adaptation set and a given representation id. Parameters: Name Type Description adaptation object representationId number addResolutionInfo boolean Defines whether to include resolution information in the output Source: dash/DashAdapter.js, line 775 Returns: codec Type String getContentSteering(manifest) Returns the ContentSteering element of the MPD Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 653 Returns: contentSteering Type object getDuration(externalManifest) Returns the duration of the MPD Parameters: Name Type Description externalManifest object Omit this value if no external manifest should be used Source: dash/DashAdapter.js, line 617 Returns: duration Type number getIndexForRepresentation(representationId, periodIdx) Returns the index for a given representation id Parameters: Name Type Description representationId string periodIdx number Source: dash/DashAdapter.js, line 804 Returns: index Type number getIsDynamic(externalManifest) Returns a boolean indicating if the manifest is dynamic or not Parameters: Name Type Description externalManifest object Omit this value if no external manifest should be used Source: dash/DashAdapter.js, line 605 Returns: Type boolean getIsMain(adaptation) Checks if the role of the specified AdaptationSet is set to main Parameters: Name Type Description adaptation object Source: dash/DashAdapter.js, line 148 Returns: Type boolean getLocation(manifest) Returns the location element of the MPD Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 664 Returns: location Type String getManifestUpdatePeriod(manifest, latencyOfLastUpdate) Returns the manifest update period used for dynamic manifests Parameters: Name Type Default Description manifest object latencyOfLastUpdate number 0 Source: dash/DashAdapter.js, line 676 Returns: manifestUpdatePeriod Type NaN | number getMaxIndexForBufferType(bufferType, periodIdx) This method returns the current max index based on what is defined in the MPD. Parameters: Name Type Description bufferType string String 'audio' or 'video', periodIdx number Make sure this is the period index not id Source: dash/DashAdapter.js, line 818 Returns: Type number getMediaInfoForType(streamInfo, type) Returns a MediaInfo object for a given media type and the corresponding streamInfo. Parameters: Name Type Description streamInfo object type MediaType Source: dash/DashAdapter.js, line 124 Returns: mediaInfo Type null | MediaInfo getMpd(externalManifest) Returns an MPD object Parameters: Name Type Description externalManifest object Omit this value if no external manifest should be used Source: dash/DashAdapter.js, line 641 Returns: MPD Type object getPatchLocation(manifest) Returns the patch location of the MPD if one exists and it is still valid Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 698 Returns: patch location Type String | null getProducerReferenceTimes(streamInfo, mediaInfo) Returns the ProducerReferenceTimes as saved in the DashManifestModel if present Parameters: Name Type Description streamInfo object mediaInfo object Source: dash/DashAdapter.js, line 396 Returns: producerReferenceTimes Type object getPublishTime(manifest) Returns the publish time from the manifest Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 687 Returns: publishTime Type Date | null getRealAdaptation(streamInfo, mediaInfo) Returns the AdaptationSet as saved in the DashManifestModel Parameters: Name Type Description streamInfo object mediaInfo object Source: dash/DashAdapter.js, line 373 Returns: realAdaptation Type object getRegularPeriods(externalManifest) Returns all periods of the MPD Parameters: Name Type Description externalManifest object Omit this value if no external manifest should be used Source: dash/DashAdapter.js, line 629 Returns: periods Type Array getSuggestedPresentationDelay() Returns the suggestedPresentationDelay as specified in the manifest Source: dash/DashAdapter.js, line 581 Returns: suggestedPresentationDelay Type String getUTCTimingSources() Returns the UTC Timing Sources specified in the manifest Source: dash/DashAdapter.js, line 570 Returns: utcTimingSources Type Array getVoRepresentations(mediaInfo) Returns all voRepresentations for a given mediaInfo Parameters: Name Type Description mediaInfo object Source: dash/DashAdapter.js, line 439 Returns: voReps Type Array × Search results Close "},"module-DashMetrics.html":{"id":"module-DashMetrics.html","title":"Module: DashMetrics","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Module: DashMetrics The DashMetrics module can be accessed using the MediaPlayer API getDashMetrics() Source: dash/DashMetrics.js, line 43 Methods getCurrent(metrics, metricName) Returns the latest metrics for a given metric list and specific metric name Parameters: Name Type Description metrics MetricsList metricName string Source: dash/DashMetrics.js, line 232 Returns: Type * getCurrentBufferLevel(mediaType) Returns the current buffer level for a given media type Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 117 Returns: Type number getCurrentBufferState(mediaType) Returns the current buffer state for a given media type Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 105 Returns: Type number getCurrentDroppedFrames() Returns the number of dropped frames Source: dash/DashMetrics.js, line 246 Returns: Type * getCurrentDVRInfo(mediaType) Returns the current DVR window Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 388 Returns: Type * getCurrentHttpRequest(mediaType) Returns the latest HTTP request for a given media type Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 168 Returns: Type * getCurrentManifestUpdate() Returns the current manifest update information Source: dash/DashMetrics.js, line 299 Returns: Type * getCurrentRepresentationSwitch(mediaType) Returns the latest Representation switch for a given media type Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 79 Returns: Type * getCurrentSchedulingInfo(mediaType) Returns the current scheduling info for a given media type Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 268 Returns: Type * getHttpRequests(mediaType) Returns all HTTP requests for a given media type Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 203 Returns: Type * getLatestFragmentRequestHeaderValueByID(mediaType, id) Returns the value for a specific request headers used in the latest fragment request Parameters: Name Type Description mediaType MediaType id string Source: dash/DashMetrics.js, line 447 Returns: Type * getLatestMPDRequestHeaderValueByID(id) Returns the value for a specific request headers used in the latest MPD request Parameters: Name Type Description id string Source: dash/DashMetrics.js, line 414 Returns: Type * × Search results Close "},"module-MediaPlayer.html":{"id":"module-MediaPlayer.html","title":"Module: MediaPlayer","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Module: MediaPlayer The MediaPlayer is the primary dash.js Module and a Facade to build your player around. It will allow you access to all the important dash.js properties/methods via the public API and all the events to build a robust DASH media player. Source: streaming/MediaPlayer.js, line 91 Members &lt;inner, constant&gt; ELEMENT_NOT_ATTACHED_ERROR :string error string thrown when a function is called before the dash.js has received a reference of an HTML5 video element Type: string Source: streaming/MediaPlayer.js, line 108 &lt;inner, constant&gt; MEDIA_PLAYER_NOT_INITIALIZED_ERROR :string error string thrown when a function is called before the dash.js has been fully initialized. Type: string Source: streaming/MediaPlayer.js, line 118 &lt;inner, constant&gt; PLAYBACK_NOT_INITIALIZED_ERROR :string error string thrown when a function is called before the dash.js has been fully initialized Type: string Source: streaming/MediaPlayer.js, line 103 &lt;inner, constant&gt; SOURCE_NOT_ATTACHED_ERROR :string error string thrown when a function is called before the dash.js has received a valid source stream. Type: string Source: streaming/MediaPlayer.js, line 113 &lt;inner, constant&gt; STREAMING_NOT_INITIALIZED_ERROR :string error string thrown when a function is called before the dash.js has been fully initialized Type: string Source: streaming/MediaPlayer.js, line 98 Methods addABRCustomRule(type, rulename, rule) Add a custom ABR Rule Rule will be apply on next stream if a stream is being played Parameters: Name Type Description type string rule type (one of ['qualitySwitchRules','abandonFragmentRules']) rulename string name of rule (used to identify custom rule). If one rule of same name has been added, then existing rule will be updated rule object the rule object instance Source: streaming/MediaPlayer.js, line 1054 Throws: BAD_ARGUMENT_ERROR if called with invalid arguments. addUTCTimingSource(schemeIdUri, value) Allows you to set a scheme and server source for UTC live edge detection for dynamic streams. If UTCTiming is defined in the manifest, it will take precedence over any time source manually added. If you have exposed the Date header, use the method clearDefaultUTCTimingSources(). This will allow the date header on the manifest to be used instead of a time server Parameters: Name Type Description schemeIdUri string urn:mpeg:dash:utc:http-head:2014 urn:mpeg:dash:utc:http-xsdate:2014 urn:mpeg:dash:utc:http-iso:2014 urn:mpeg:dash:utc:direct:2014 Some specs referencing early ISO23009-1 drafts incorrectly use 2012 in the URI, rather than 2014. support these for now. urn:mpeg:dash:utc:http-head:2012 urn:mpeg:dash:utc:http-xsdate:2012 urn:mpeg:dash:utc:http-iso:2012 urn:mpeg:dash:utc:direct:2012 value string Path to a time source. Default Value: schemeIdUri:urn:mpeg:dash:utc:http-xsdate:2014 value:http://time.akamai.com/?iso&amp;ms/li&gt; Source: streaming/MediaPlayer.js, line 1115 See: removeUTCTimingSource() attachProtectionController(value) Will override dash.js protection controller. Parameters: Name Type Description value ProtectionController valid protection controller instance. Source: streaming/MediaPlayer.js, line 1685 attachSource(urlOrManifest, startTime) Use this method to set a source URL to a valid MPD manifest file OR a previously downloaded and parsed manifest object. Optionally, can also provide protection information Parameters: Name Type Description urlOrManifest string | Object A URL to a valid MPD manifest file, or a parsed manifest object. startTime number | string For VoD content the start time is relative to the start time of the first period. For live content If the parameter starts from prefix posix: it signifies the absolute time range defined in seconds of Coordinated Universal Time (ITU-R TF.460-6). This is the number of seconds since 01-01-1970 00:00:00 UTC. Fractions of seconds may be optionally specified down to the millisecond level. If no posix prefix is used the starttime is relative to MPD@availabilityStartTime Source: streaming/MediaPlayer.js, line 1827 Throws: MEDIA_PLAYER_NOT_INITIALIZED_ERROR if called before initialize function attachTTMLRenderingDiv(div) Use this method to attach an HTML5 div for dash.js to render rich TTML subtitles. Parameters: Name Type Description div HTMLDivElement An unstyled div placed after the video element. It will be styled to match the video size and overlay z-order. Source: streaming/MediaPlayer.js, line 1414 Throws: ELEMENT_NOT_ATTACHED_ERROR if called before attachView function attachView(element) Use this method to attach an HTML5 VideoElement for dash.js to operate upon. Parameters: Name Type Description element Object An HTMLMediaElement that has already been defined in the DOM (or equivalent stub). Source: streaming/MediaPlayer.js, line 1372 Throws: MEDIA_PLAYER_NOT_INITIALIZED_ERROR if called before initialize function clearDefaultUTCTimingSources() Allows you to clear the stored array of time sources. Example use: If you have exposed the Date header, calling this method will allow the date header on the manifest to be used instead of the time server. Example use: Calling this method, assuming there is not an exposed date header on the manifest, will default back to using a binary search to discover the live edge Source: streaming/MediaPlayer.js, line 1144 See: restoreDefaultUTCTimingSources() convertToTimeCode(value) A utility method which converts seconds into TimeCode (i.e. 300 --&gt; 05:00). Parameters: Name Type Description value number A number in seconds to be converted into a formatted time code. Source: streaming/MediaPlayer.js, line 1919 Returns: A formatted time code string. Type string destroy() Completely destroys the media player and frees all memory. Source: streaming/MediaPlayer.js, line 453 duration() Duration of the media's playback, in seconds. Source: streaming/MediaPlayer.js, line 849 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: The current duration of the media. For a dynamic stream this will return DVRWindow.end - DVRWindow.start Type number durationAsUTC() Use this method to get the current duration as an absolute value, the time in seconds since midnight UTC, Jan 1 1970. Note - this property only has meaning for live streams. Source: streaming/MediaPlayer.js, line 891 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: The current duration as UTC timestamp. Type number enableForcedTextStreaming(enable) Enable/disable text When enabling dash will keep downloading and process fragmented text tracks even if all tracks are in mode \"hidden\" Parameters: Name Type Description enable boolean true to enable text streaming even if all text tracks are hidden. Source: streaming/MediaPlayer.js, line 1278 enableText(enable) Enable/disable text When enabling text, dash will choose the previous selected text track Parameters: Name Type Description enable boolean true to enable text, false otherwise (same as setTextTrack(-1)) Source: streaming/MediaPlayer.js, line 1260 extend(parentNameString, childInstance, override) This method should be used to extend or replace internal dash.js objects. There are two ways to extend dash.js (determined by the override argument): If you set override to true any public method or property in your custom object will override the dash.js parent object's property(ies) and will be used instead but the dash.js parent module will still be created. If you set override to false your object will completely replace the dash.js object. (Note: This is how it was in 1.x of Dash.js with Dijon). When you extend you get access to this.context, this.factory and this.parent to operate with in your custom object. this.context - can be used to pass context for singleton access. this.factory - can be used to call factory.getSingletonInstance(). this.parent - is the reference of the parent object to call other public methods. (this.parent is excluded if you extend with override set to false or option 2) You must call extend before you call initialize Parameters: Name Type Description parentNameString string name of parent module childInstance Object overriding object override boolean replace only some methods (true) or the whole object (false) Source: streaming/MediaPlayer.js, line 1953 See: initialize() formatUTC(time, locales, hour12, withDate) A utility methods which converts UTC timestamp value into a valid time and date string. Parameters: Name Type Default Description time number UTC timestamp to be converted into date and time. locales string a region identifier (i.e. en_US). hour12 boolean 12 vs 24 hour. Set to true for 12 hour time formatting. withDate boolean false default is false. Set to true to append current date to UTC time format. Source: streaming/MediaPlayer.js, line 1902 Returns: A formatted time and date string. Type string getActiveStream() This method returns the active stream Source: streaming/MediaPlayer.js, line 1964 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function getAutoPlay() Source: streaming/MediaPlayer.js, line 1021 Returns: The current autoPlay state. Type boolean getAverageThroughput(type) Returns the average throughput computed in the ABR logic Parameters: Name Type Description type MediaType Source: streaming/MediaPlayer.js, line 1173 Returns: value Type number getBitrateInfoListFor(type) Parameters: Name Type Description type MediaType Source: streaming/MediaPlayer.js, line 1435 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: Type Array getBufferLength(type) The length of the buffer for a given media type, in seconds. Valid media types are \"video\", \"audio\" and \"text\". If no type is passed in, then the minimum of video, audio and text buffer length is returned. NaN is returned if an invalid type is requested, the presentation does not contain that type, or if no arguments are passed and the presentation does not include any adaption sets of valid media type. Parameters: Name Type Description type MediaType 'video', 'audio' or 'text' Source: streaming/MediaPlayer.js, line 733 Returns: The length of the buffer for the given media type, in seconds, or NaN Type number getCurrentLiveLatency() Source: streaming/MediaPlayer.js, line 1031 Throws: MEDIA_PLAYER_NOT_INITIALIZED_ERROR if called before initialize function Returns: Current live stream latency in seconds. It is the difference between now time and time position at the playback head. Type number | NaN getCurrentTrackFor(type) Parameters: Name Type Description type MediaType Source: streaming/MediaPlayer.js, line 1507 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: MediaInfo Type Object | null getDashAdapter() Returns the DashAdapter.js Module. Source: streaming/MediaPlayer.js, line 1980 See: module:DashAdapter Returns: Type Object getDashMetrics() Returns the DashMetrics.js Module. You use this Module to get access to all the public metrics stored in dash.js Source: streaming/MediaPlayer.js, line 1240 See: module:DashMetrics Returns: Type Object getDebug() Use this method to access the dash.js logging class. Source: streaming/MediaPlayer.js, line 515 Returns: Type Debug getDVRSeekOffset(value) This method should only be used with a live stream that has a valid timeShiftBufferLength (DVR Window). NOTE - If you do not need the raw offset value (i.e. media analytics, tracking, etc) consider using the seek() method which will calculate this value for you and set the video element's currentTime property all in one simple call. Parameters: Name Type Description value number A relative time, in seconds, based on the return value of the duration() method is expected. Source: streaming/MediaPlayer.js, line 780 See: seek() Returns: A value that is relative the available range within the timeShiftBufferLength (DVR Window). Type number getDVRWindowSize() The timeShiftBufferLength (DVR Window), in seconds. Source: streaming/MediaPlayer.js, line 760 Returns: The window of allowable play time behind the live point of a live stream as defined in the manifest. Type number getInitialMediaSettingsFor(type) This method returns media settings that is used to pick the initial track. Format of the settings is following: {lang: langValue, index: indexValue, viewpoint: viewpointValue, audioChannelConfiguration: audioChannelConfigurationValue, accessibility: accessibilityValue, role: roleValue} Parameters: Name Type Description type MediaType Source: streaming/MediaPlayer.js, line 1553 Throws: MEDIA_PLAYER_NOT_INITIALIZED_ERROR if called before initialize function Returns: Type Object getLowLatencyModeEnabled() Returns a boolean that indicates whether the player is operating in low latency mode. Source: streaming/MediaPlayer.js, line 645 Returns: Type boolean getOfflineController() Detects if Offline is included and returns an instance of OfflineController.js Source: streaming/MediaPlayer.js, line 1220 getPlaybackRate() Returns the current playback rate. Source: streaming/MediaPlayer.js, line 668 Returns: Type number getProtectionController() Detects if Protection is included and returns an instance of ProtectionController.js Source: streaming/MediaPlayer.js, line 1675 getQualityFor(type) Gets the current download quality for media type video, audio or images. For video and audio types the ABR rules update this value before every new download unless autoSwitchBitrate is set to false. For 'image' type, thumbnails, there is no ABR algorithm and quality is set manually. Parameters: Name Type Description type MediaType 'video', 'audio' or 'image' (thumbnails) Source: streaming/MediaPlayer.js, line 934 See: setQualityFor() Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: the quality index, 0 corresponding to the lowest bitrate Type number getSettings() Get the current settings object being used on the player. Source: streaming/MediaPlayer.js, line 1854 Returns: The settings object being used. Type PlayerSettings getSource() Returns the source string or manifest that was attached by calling attachSource() Source: streaming/MediaPlayer.js, line 1793 Throws: SOURCE_NOT_ATTACHED_ERROR if called before attachSource function Returns: Type string | manifest getStreamsFromManifest(manifest) This method returns the list of all available streams from a given manifest Parameters: Name Type Description manifest Object Source: streaming/MediaPlayer.js, line 1451 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: list of StreamInfo Type Array getTargetLiveDelay() Returns the target live delay Source: streaming/MediaPlayer.js, line 804 Returns: The target live delay Type number getTopBitrateInfoFor(type) Gets the top quality BitrateInfo checking portal limit and max allowed. It calls getMaxAllowedIndexFor internally Parameters: Name Type Description type MediaType 'video' or 'audio' Source: streaming/MediaPlayer.js, line 915 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: Type BitrateInfo | null getTracksFor(type) This method returns the list of all available tracks for a given media type Parameters: Name Type Description type MediaType Source: streaming/MediaPlayer.js, line 1466 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: list of MediaInfo Type Array getTracksForTypeFromManifest(type, manifest, streamInfo) This method returns the list of all available tracks for a given media type and streamInfo from a given manifest Parameters: Name Type Description type MediaType manifest Object streamInfo Object Source: streaming/MediaPlayer.js, line 1489 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: list of MediaInfo Type Array getTTMLRenderingDiv() Returns instance of Div that was attached by calling attachTTMLRenderingDiv() Source: streaming/MediaPlayer.js, line 1402 Returns: Type Object getVersion() Current version of Dash.js Source: streaming/MediaPlayer.js, line 504 Returns: the current dash.js version string. Type string getVideoElement() Returns instance of Video Element that was attached by calling attachView() Source: streaming/MediaPlayer.js, line 1357 Throws: ELEMENT_NOT_ATTACHED_ERROR if called before attachView function Returns: Type Object getVolume() Returns the current audio volume, from 0.0 (silent) to 1.0 (loudest). Source: streaming/MediaPlayer.js, line 714 Returns: Type number getXHRWithCredentialsForType(type) Gets whether withCredentials on XHR requests for a particular request type is true or false Parameters: Name Type Description type string one of HTTPRequest.*_TYPE Source: streaming/MediaPlayer.js, line 1203 Returns: Type boolean initialize( [view] [, source] [, autoPlay], startTime) Upon creating the MediaPlayer you must call initialize before you call anything else. There is one exception to this rule. It is crucial to call extend() with all your extensions prior to calling initialize. ALL arguments are optional and there are individual methods to set each argument later on. The args in this method are just for convenience and should only be used for a simple player setup. Parameters: Name Type Argument Description view HTML5MediaElement &lt;optional&gt; Optional arg to set the video element. attachView() source string &lt;optional&gt; Optional arg to set the media source. attachSource() autoPlay boolean &lt;optional&gt; Optional arg to set auto play. setAutoPlay() startTime number | string For VoD content the start time is relative to the start time of the first period. For live content If the parameter starts from prefix posix: it signifies the absolute time range defined in seconds of Coordinated Universal Time (ITU-R TF.460-6). This is the number of seconds since 01-01-1970 00:00:00 UTC. Fractions of seconds may be optionally specified down to the millisecond level. If no posix prefix is used the starttime is relative to MPD@availabilityStartTime Source: streaming/MediaPlayer.js, line 270 See: attachSource() setAutoPlay() isDynamic() Returns a Boolean that indicates whether the media is in the process of dynamic. Source: streaming/MediaPlayer.js, line 632 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: Type boolean isMuted() A Boolean that determines whether audio is muted. Source: streaming/MediaPlayer.js, line 690 Returns: Type boolean isPaused() Returns a Boolean that indicates whether the Video Element is paused. Source: streaming/MediaPlayer.js, line 566 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: Type boolean isReady() The ready state of the MediaPlayer based on both the video element and MPD source being defined. Source: streaming/MediaPlayer.js, line 467 See: attachView() attachSource() Returns: The current ready state of the MediaPlayer Type boolean isSeeking() Returns a Boolean that indicates whether the media is in the process of seeking to a new position. Source: streaming/MediaPlayer.js, line 618 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: Type boolean isTextEnabled() Return if text is enabled Source: streaming/MediaPlayer.js, line 1295 Returns: return true if text is enabled, false otherwise Type boolean off(type, listener, scope) Use the off method to remove listeners for public events found in MediaPlayer.events. MediaPlayerEvents Parameters: Name Type Description type string MediaPlayerEvents listener function callback method when the event fires. scope Object context of the listener so it can be removed properly. Source: streaming/MediaPlayer.js, line 494 on(type, listener, scope, options) Use the on method to listen for public events found in MediaPlayer.events. MediaPlayerEvents Parameters: Name Type Description type string MediaPlayerEvents listener function callback method when the event fires. scope Object context of the listener so it can be removed properly. options Object object to define various options such as priority and mode Source: streaming/MediaPlayer.js, line 481 pause() This method will call pause on the native Video Element. Source: streaming/MediaPlayer.js, line 552 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function play() The play method initiates playback of the media defined by the attachSource() method. This method will call play on the native Video Element. Source: streaming/MediaPlayer.js, line 536 See: attachSource() Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function provideThumbnail(time, callback) Provide the thumbnail at time position. This can be asynchronous, so you must provide a callback ro retrieve thumbnails informations Parameters: Name Type Description time number A relative time, in seconds, based on the return value of the duration() method is expected callback function A Callback function provided when retrieving thumbnail the given time position. Thumbnail object is null in case there are is not a thumbnails representation or if it doesn't contain a thumbnail for the given time position. Source: streaming/MediaPlayer.js, line 1725 registerCustomCapabilitiesFilter(filter) Registers a custom capabilities filter. This enables application to filter representations to use. The provided callback function shall return a boolean based on whether or not to use the representation. The filters are applied in the order they are registered. Parameters: Name Type Description filter function the custom capabilities filter callback Source: streaming/MediaPlayer.js, line 1588 registerLicenseRequestFilter(filter) Registers a license request filter. This enables application to manipulate/overwrite any request parameter and/or request data. The provided callback function shall return a promise that shall be resolved once the filter process is completed. The filters are applied in the order they are registered. Parameters: Name Type Description filter function the license request filter callback Source: streaming/MediaPlayer.js, line 1626 registerLicenseResponseFilter(filter) Registers a license response filter. This enables application to manipulate/overwrite the response data The provided callback function shall return a promise that shall be resolved once the filter process is completed. The filters are applied in the order they are registered. Parameters: Name Type Description filter function the license response filter callback Source: streaming/MediaPlayer.js, line 1638 removeABRCustomRule(rulename) Remove a custom ABR Rule Parameters: Name Type Description rulename string name of the rule to be removed Source: streaming/MediaPlayer.js, line 1065 removeAllABRCustomRule() Remove all ABR custom rules Source: streaming/MediaPlayer.js, line 1074 removeUTCTimingSource(schemeIdUri, value) Allows you to remove a UTC time source. Both schemeIdUri and value need to match the Dash.vo.UTCTiming properties in order for the entry to be removed from the array Parameters: Name Type Description schemeIdUri string see addUTCTimingSource() value string see addUTCTimingSource() Source: streaming/MediaPlayer.js, line 1129 See: clearDefaultUTCTimingSources() Throws: BAD_ARGUMENT_ERROR if called with invalid arguments, schemeIdUri and value are not string type. reset() Sets the MPD source and the video element to null. You can also reset the MediaPlayer by calling attachSource with a new source file. This call does not destroy the MediaPlayer. To destroy the MediaPlayer and free all of its memory, call destroy(). Source: streaming/MediaPlayer.js, line 423 resetSettings() Resets the settings object back to the default. Source: streaming/MediaPlayer.js, line 1887 restoreDefaultUTCTimingSources() Allows you to restore the default time sources after calling clearDefaultUTCTimingSources() Default Value: schemeIdUri:urn:mpeg:dash:utc:http-xsdate:2014 value:http://time.akamai.com/?iso&amp;ms Source: streaming/MediaPlayer.js, line 1161 See: addUTCTimingSource() retrieveManifest(url, callback) Allows application to retrieve a manifest. Manifest loading is asynchro nous and requires the app-provided callback function Parameters: Name Type Description url string url the manifest url callback function A Callback function provided when retrieving manifests Source: streaming/MediaPlayer.js, line 1766 seek(value) Sets the currentTime property of the attached video element. If it is a live stream with a timeShiftBufferLength, then the DVR window offset will be automatically calculated. Parameters: Name Type Description value number A relative time, in seconds, based on the return value of the duration() method is expected. For dynamic streams duration() returns DVRWindow.end - DVRWindow.start. Consequently, the value provided to this function should be relative to DVRWindow.start. Source: streaming/MediaPlayer.js, line 585 See: getDVRSeekOffset() Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function BAD_ARGUMENT_ERROR if called with an invalid argument, not number type or is NaN. setAutoPlay(value) Set to false to prevent stream from auto-playing when the view is attached. Parameters: Name Type Description value boolean Default Value: true Source: streaming/MediaPlayer.js, line 1011 See: attachView() Throws: BAD_ARGUMENT_ERROR if called with an invalid argument, not boolean type. setConfig( [config]) Configure media player with customs controllers. Helpful for tests Parameters: Name Type Argument Description config object &lt;optional&gt; controllers configuration Source: streaming/MediaPlayer.js, line 199 setCurrentTrack(track) Parameters: Name Type Description track MediaInfo instance of MediaInfo Source: streaming/MediaPlayer.js, line 1566 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function setInitialMediaSettingsFor(type, value) This method allows to set media settings that will be used to pick the initial track. Format of the settings is following: {lang: langValue (can be either a string primitive, a string object, or a RegExp object to match), index: indexValue, viewpoint: viewpointValue, audioChannelConfiguration: audioChannelConfigurationValue, accessibility: accessibilityValue, role: roleValue} Parameters: Name Type Description type MediaType value Object Source: streaming/MediaPlayer.js, line 1531 Throws: MEDIA_PLAYER_NOT_INITIALIZED_ERROR if called before initialize function setMute(value) Use this method to set the native Video Element's muted state. Takes a Boolean that determines whether audio is muted. true if the audio is muted and false otherwise. Parameters: Name Type Description value boolean Source: streaming/MediaPlayer.js, line 679 Throws: BAD_ARGUMENT_ERROR if called with an invalid argument, not boolean type. setPlaybackRate(value) Use this method to set the native Video Element's playback rate. Parameters: Name Type Description value number Source: streaming/MediaPlayer.js, line 658 setProtectionData(value) Sets Protection Data required to setup the Protection Module (DRM). Protection Data must be set before initializing MediaPlayer or, once initialized, before PROTECTION_CREATED event is fired. Parameters: Name Type Description value ProtectionDataSet object containing property names corresponding to key system name strings and associated values being instances of. Source: streaming/MediaPlayer.js, line 1700 See: initialize() dashjs.Protection.events.PROTECTION_CREATED setQualityFor(type, value, forceReplace) Sets the current quality for media type instead of letting the ABR Heuristics automatically selecting it. This value will be overwritten by the ABR rules unless autoSwitchBitrate is set to false. Parameters: Name Type Default Description type MediaType 'video', 'audio' or 'image' value number the quality index, 0 corresponding to the lowest bitrate forceReplace boolean false true if segments have to be replaced by segments of the new quality Source: streaming/MediaPlayer.js, line 962 See: getQualityFor() Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function setTextTrack(idx) Use this method to change the current text track for both external time text files and fragmented text tracks. There is no need to set the track mode on the video object to switch a track when using this method. Parameters: Name Type Description idx number Index of track based on the order of the order the tracks are added Use -1 to disable all tracks. (turn captions off). Use module:MediaPlayer#dashjs.MediaPlayer.events.TEXT_TRACK_ADDED. Source: streaming/MediaPlayer.js, line 1314 See: dashjs.MediaPlayer.events.TEXT_TRACK_ADDED Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function setVolume(value) A double indicating the audio volume, from 0.0 (silent) to 1.0 (loudest). Parameters: Name Type Description value number Source: streaming/MediaPlayer.js, line 701 Throws: BAD_ARGUMENT_ERROR if called with an invalid argument, not number type, or is NaN or not between 0 and 1. setXHRWithCredentialsForType(type, value) Sets whether withCredentials on XHR requests for a particular request type is true or false Parameters: Name Type Description type string one of HTTPRequest.*_TYPE value boolean Default Value: false Source: streaming/MediaPlayer.js, line 1190 time(streamId) Current time of the playhead, in seconds. If called with no arguments then the returned time value is time elapsed since the start point of the first stream, or if it is a live stream, then the time will be based on the return value of the duration() method. However if a stream ID is supplied then time is relative to the start of that stream, or is null if there is no such stream id in the manifest. Parameters: Name Type Description streamId string The ID of a stream that the returned playhead time must be relative to the start of. If undefined, then playhead time is relative to the first stream. Source: streaming/MediaPlayer.js, line 824 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: The current playhead time of the media, or null. Type number timeAsUTC() Use this method to get the current playhead time as an absolute value, the time in seconds since midnight UTC, Jan 1 1970. Note - this property only has meaning for live streams. If called before play() has begun, it will return a value of NaN. Source: streaming/MediaPlayer.js, line 872 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: The current playhead time as UTC timestamp. Type number unregisterCustomCapabilitiesFilter(filter) Unregisters a custom capabilities filter. Parameters: Name Type Description filter function the custom capabilities filter callback Source: streaming/MediaPlayer.js, line 1598 unregisterLicenseRequestFilter(filter) Unregisters a license request filter. Parameters: Name Type Description filter function the license request filter callback Source: streaming/MediaPlayer.js, line 1648 unregisterLicenseResponseFilter(filter) Unregisters a license response filter. Parameters: Name Type Description filter function the license response filter callback Source: streaming/MediaPlayer.js, line 1658 updatePortalSize() Update the video element size variables Should be called on window resize (or any other time player is resized). Fullscreen does trigger a window resize event. Once windowResizeEventCalled = true, abrController.checkPortalSize() will use element size variables rather than querying clientWidth every time. Source: streaming/MediaPlayer.js, line 988 updateSettings(settingsObj) Update the current settings object being used on the player. Anything left unspecified is not modified. This function does not update the entire object, only properties in the passed in object are updated. This means that updateSettings({a: x}) and updateSettings({b: y}) are functionally equivalent to updateSettings({a: x, b: y}). If the default values are required again, @seeresetSettings. Parameters: Name Type Description settingsObj PlayerSettings An object corresponding to the settings definition. Source: streaming/MediaPlayer.js, line 1877 Example player.updateSettings({ streaming: { lowLatencyEnabled: false, abr: { maxBitrate: { audio: 100, video: 1000 } } } }); × Search results Close "},"module-OfflineController.html":{"id":"module-OfflineController.html","title":"Module: OfflineController","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Module: OfflineController Provides access to offline stream recording and playback functionality. This module can be accessed using the MediaPlayer API getOfflineController() Source: offline/controllers/OfflineController.js, line 41 Methods &lt;static&gt; loadRecordsFromStorage() Loads records from storage This methods has to be called first, to be sure that all downloads have been loaded Source: offline/controllers/OfflineController.js, line 210 Returns: asynchronously resolved Type Promise createRecord(manifestURL) Create a new content record in storage and download manifest from url Parameters: Name Type Description manifestURL string the content manifest url Source: offline/controllers/OfflineController.js, line 254 Returns: asynchronously resolved with record identifier Type Promise deleteRecord(id) Deletes a record from storage Parameters: Name Type Description id string record identifier Source: offline/controllers/OfflineController.js, line 324 getAllRecords() Get all records from storage Source: offline/controllers/OfflineController.js, line 232 Returns: asynchronously resolved with records Type Promise getRecordProgression(id) Get download progression of a record Parameters: Name Type Description id string record identifier Source: offline/controllers/OfflineController.js, line 339 Returns: percentage progression Type number resetRecords() Reset all records Source: offline/controllers/OfflineController.js, line 352 resumeRecord(id) Resume downloading of the record Parameters: Name Type Description id string record identifier Source: offline/controllers/OfflineController.js, line 310 startRecord(id, mediaInfos) Start downloading the record with selected tracks representations Parameters: Name Type Description id string record identifier mediaInfos Array.&lt;MediaInfo&gt; the selected tracks representations Source: offline/controllers/OfflineController.js, line 282 stopRecord(id) Stop downloading of the record Parameters: Name Type Description id string record identifier Source: offline/controllers/OfflineController.js, line 296 × Search results Close "},"module-ProtectionController.html":{"id":"module-ProtectionController.html","title":"Module: ProtectionController","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Module: ProtectionController Provides access to media protection information and functionality. Each ProtectionController manages a single MediaPlayer.models.ProtectionModel which encapsulates a set of protection information (EME APIs, selected key system, key sessions). The APIs of ProtectionController mostly align with the latest EME APIs. Key system selection is mostly automated when combined with app-overrideable functionality provided in ProtectionKeyController. Source: streaming/protection/controllers/ProtectionController.js, line 51 To Do: ProtectionController does almost all of its tasks automatically after init() is called. Applications might want more control over this process and want to go through each step manually (key system selection, session creation, session maintenance). This module can be accessed using the MediaPlayer API getProtectionController() Methods handleKeySystemFromManifest() Once all mediaInfo objects have been added to our mediaInfoArray we can select a key system or check if the kid has changed and we need to trigger a new license request Source: streaming/protection/controllers/ProtectionController.js, line 137 initializeForMedia( [mediaInfo]) Initialize this protection system for a given media type. Parameters: Name Type Argument Description mediaInfo StreamInfo &lt;optional&gt; Media information Source: streaming/protection/controllers/ProtectionController.js, line 118 setMediaElement(element) Associate this protection system with the given HTMLMediaElement. This causes the system to register for needkey/encrypted events from the given element and provides a destination for setting of MediaKeys Parameters: Name Type Description element HTMLMediaElement the media element to which the protection system should be associated Source: streaming/protection/controllers/ProtectionController.js, line 518 setRobustnessLevel(level) Sets the robustness level for video and audio capabilities. Optional to remove Chrome warnings. Possible values are SW_SECURE_CRYPTO, SW_SECURE_DECODE, HW_SECURE_CRYPTO, HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL. Parameters: Name Type Description level string the robustness level Source: streaming/protection/controllers/ProtectionController.js, line 549 setServerCertificate(serverCertificate) Sets a server certificate for use by the CDM when signing key messages intended for a particular license server. This will fire an error event if a key system has not yet been selected. Parameters: Name Type Description serverCertificate ArrayBuffer a CDM-specific license server certificate Source: streaming/protection/controllers/ProtectionController.js, line 503 Fires: ProtectionController#event:ServerCertificateUpdated setSessionType(value) Sets the session type to use when creating key sessions. Either \"temporary\" or \"persistent-license\". Default is \"temporary\". Parameters: Name Type Description value string the session type Source: streaming/protection/controllers/ProtectionController.js, line 537 stop() Stop method is called when current playback is stopped/resetted. Source: streaming/protection/controllers/ProtectionController.js, line 574 × Search results Close "},"module-Settings.html":{"id":"module-Settings.html","title":"Module: Settings","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Module: Settings Define the configuration parameters of Dash.js MediaPlayer. Source: core/Settings.js, line 39 See: PlayerSettings for further information about the supported configuration properties. Type Definitions AbrSettings Type: Object Properties: Name Type Argument Default Description movingAverageMethod string &lt;optional&gt; \"slidingWindow\" Sets the moving average method used for smoothing throughput estimates. Valid methods are \"slidingWindow\" and \"ewma\". The call has no effect if an invalid method is passed. The sliding window moving average method computes the average throughput using the last four segments downloaded. If the stream is live (as opposed to VOD), then only the last three segments are used. If wide variations in throughput are detected, the number of segments can be dynamically increased to avoid oscillations. The exponentially weighted moving average (EWMA) method computes the average using exponential smoothing. Two separate estimates are maintained, a fast one with a three-second half life and a slow one with an eight-second half life. The throughput estimate at any time is the minimum of the fast and slow estimates. This allows a fast reaction to a bandwidth drop and prevents oscillations on bandwidth spikes. ABRStrategy string &lt;optional&gt; \"abrDynamic\" Returns the current ABR strategy being used: \"abrDynamic\", \"abrBola\" or \"abrThroughput\". trackSwitchMode object &lt;optional&gt; {video: \"neverReplace\", audio: \"alwaysReplace\"} additionalAbrRules object &lt;optional&gt; {insufficientBufferRule: false,switchHistoryRule: true,droppedFramesRule: true,abandonRequestsRule: false} Enable/Disable additional ABR rules in case ABRStrategy is set to \"abrDynamic\", \"abrBola\" or \"abrThroughput\". bandwidthSafetyFactor number &lt;optional&gt; 0.9 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). useDefaultABRRules boolean &lt;optional&gt; true Should the default ABR rules be used, or the custom ones added. useDeadTimeLatency boolean &lt;optional&gt; 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 transfer time will be used. limitBitrateByPortal boolean &lt;optional&gt; false If true, the size of the video portal will limit the max chosen video resolution. usePixelRatioInLimitBitrateByPortal boolean &lt;optional&gt; false Sets whether to take into account the device's pixel ratio when defining the portal dimensions. Useful on, for example, retina displays. maxBitrate module:Settings~AudioVideoSettings &lt;optional&gt; {audio: -1, video: -1} The maximum bitrate that the ABR algorithms will choose. This value is specified in kbps. Use -1 for no limit. minBitrate module:Settings~AudioVideoSettings &lt;optional&gt; {audio: -1, video: -1} The minimum bitrate that the ABR algorithms will choose. This value is specified in kbps. Use -1 for no limit. maxRepresentationRatio module:Settings~AudioVideoSettings &lt;optional&gt; {audio: 1, video: 1} When switching multi-bitrate content (auto or manual mode) this property specifies the maximum representation allowed, as a proportion of the size of the representation set. You can set or remove this cap at anytime before or during playback. To clear this setting you set the value to 1. If both this and maxAllowedBitrate are defined, maxAllowedBitrate is evaluated first, then maxAllowedRepresentation, i.e. the lowest value from executing these rules is used. This feature is typically used to reserve higher representations for playback only when connected over a fast connection. initialBitrate module:Settings~AudioVideoSettings &lt;optional&gt; {audio: -1, video: -1} Explicitly set the starting bitrate for audio or video. This value is specified in kbps. Use -1 to let the player decide. initialRepresentationRatio module:Settings~AudioVideoSettings &lt;optional&gt; {audio: -1, video: -1} Explicitly set the initial representation ratio. If initalBitrate is specified, this is ignored. autoSwitchBitrate module:Settings~AudioVideoSettings &lt;optional&gt; {audio: true, video: true} Indicates whether the player should enable ABR algorithms to switch the bitrate. fetchThroughputCalculationMode string &lt;optional&gt; \"abrFetchThroughputCalculationDownloadedData\" 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. Source: core/Settings.js, line 534 AudioVideoSettings Type: Object Properties: Name Type Argument Description audio number | boolean | string &lt;optional&gt; Configuration for audio media type of tracks. video number | boolean | string &lt;optional&gt; Configuration for video media type of tracks. Source: core/Settings.js, line 314 Buffer Type: Object Properties: Name Type Argument Default Description enableSeekDecorrelationFix boolean &lt;optional&gt; false Enables a workaround for playback start on some devices, e.g. WebOS 4.9. It is necessary because some browsers do not support setting currentTime on video element to a value that is outside of current buffer. If you experience unexpected seeking triggered by BufferController, you can try setting this value to false. fastSwitchEnabled boolean &lt;optional&gt; true When enabled, after an ABR up-switch in quality, instead of requesting and appending the next fragment at the end of the current buffer range it is requested and appended closer to the current time. When enabled, The maximum time to render a higher quality is current time + (1.5 * fragment duration). Note, When ABR down-switch is detected, we appended the lower quality at the end of the buffer range to preserve the higher quality media for as long as possible. If enabled, it should be noted there are a few cases when the client will not replace inside buffer range but rather just append at the end. When the buffer level is less than one fragment duration. The client is in an Abandonment State due to recent fragment abandonment event. Known issues: In IE11 with auto switching off, if a user switches to a quality they can not download in time the 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. flushBufferAtTrackSwitch boolean &lt;optional&gt; false When enabled, after a track switch and in case buffer is being replaced, 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. reuseExistingSourceBuffers boolean &lt;optional&gt; true Enable reuse of existing MediaSource Sourcebuffers during period transition. bufferPruningInterval number &lt;optional&gt; 10 The interval of pruning buffer in seconds. bufferToKeep number &lt;optional&gt; 20 This value influences the buffer pruning logic. Allows you to modify the buffer that is kept in source buffer in seconds. 0|-----------bufferToPrune-----------|-----bufferToKeep-----|currentTime| bufferTimeAtTopQuality number &lt;optional&gt; 30 The time that the internal buffer target will be set to once playing the top quality. If there are multiple bitrates in your adaptation, and the media is playing at the highest bitrate, then we try to build a larger buffer at the top quality to increase stability and to maintain media quality. bufferTimeAtTopQualityLongForm number &lt;optional&gt; 60 The time that the internal buffer target will be set to once playing the top quality for long form content. longFormContentDurationThreshold number &lt;optional&gt; 600 The threshold which defines if the media is considered long form content. This will directly affect the buffer targets when playing back at the top quality. initialBufferLevel number &lt;optional&gt; NaN Initial buffer level before playback starts stableBufferTime number &lt;optional&gt; 12 The time that the internal buffer target will be set to post startup/seeks (NOT top quality). When the time is set higher than the default you will have to wait longer to see automatic bitrate switches but will have a larger buffer which will increase stability. stallThreshold number &lt;optional&gt; 0.3 Stall threshold used in BufferController.js to determine whether a track should still be changed and which buffer range to prune. useAppendWindow boolean &lt;optional&gt; true Specifies if the appendWindow attributes of the MSE SourceBuffers should be set according to content duration from manifest. setStallState boolean &lt;optional&gt; true Specifies if we fire manual waiting events once the stall threshold is reached avoidCurrentTimeRangePruning boolean &lt;optional&gt; false Avoids pruning of the buffered range that contains the current playback time. That buffered range is likely to have been enqueued for playback. Pruning it causes a flush and reenqueue in WPE and WebKitGTK based browsers. This stresses the video decoder and can cause stuttering on embedded platforms. Source: core/Settings.js, line 249 CachingInfoSettings Type: Object Properties: Name Type Argument Description enable boolean &lt;optional&gt; Enable or disable the caching feature. ttl number &lt;optional&gt; Time to live. A value defined in milliseconds representing how log to cache the settings for. Source: core/Settings.js, line 363 Capabilities Type: Object Properties: Name Type Argument Default Description filterUnsupportedEssentialProperties boolean &lt;optional&gt; true Enable to filter all the AdaptationSets and Representations which contain an unsupported &lt;EssentialProperty&gt; element. useMediaCapabilitiesApi boolean &lt;optional&gt; false Enable to use the MediaCapabilities API to check whether codecs are supported. If disabled MSE.isTypeSupported will be used instead. Source: core/Settings.js, line 526 CmcdSettings Type: Object Properties: Name Type Argument Default Description enable boolean &lt;optional&gt; false Enable or disable the CMCD reporting. sid string &lt;optional&gt; GUID identifying the current playback session. Should be in UUID format. If not specified a UUID will be automatically generated. cid string &lt;optional&gt; A unique string to identify the current content. If not specified it will be a hash of the MPD url. rtp number &lt;optional&gt; The requested maximum throughput that the client considers sufficient for delivery of the asset. If not specified this value will be dynamically calculated in the CMCDModel based on the current buffer level. rtpSafetyFactor number &lt;optional&gt; This value is used as a factor for the rtp value calculation: rtp = minBandwidth * rtpSafetyFactor If not specified this value defaults to 5. Note that this value is only used when no static rtp value is defined. mode number &lt;optional&gt; The method to use to attach cmcd metrics to the requests. 'query' to use query parameters, 'header' to use http headers. If not specified this value defaults to 'query'. enabledKeys Array.&lt;string&gt; &lt;optional&gt; This value is used to specify the desired CMCD parameters. Parameters not included in this list are not reported. Source: core/Settings.js, line 612 DebugSettings Type: Object Properties: Name Type Argument Default Description logLevel number &lt;optional&gt; dashjs.Debug.LOG_LEVEL_WARNING Sets up the log level. The levels are cumulative. For example, if you set the log level to dashjs.Debug.LOG_LEVEL_WARNING all warnings, errors and fatals will be logged. Possible values. dashjs.Debug.LOG_LEVEL_NONE No message is written in the browser console. dashjs.Debug.LOG_LEVEL_FATAL Log fatal errors. An error is considered fatal when it causes playback to fail completely. dashjs.Debug.LOG_LEVEL_ERROR Log error messages. dashjs.Debug.LOG_LEVEL_WARNING Log warning messages. dashjs.Debug.LOG_LEVEL_INFO Log info messages. dashjs.Debug.LOG_LEVEL_DEBUG Log debug messages. dispatchEvent boolean &lt;optional&gt; false Enable to trigger a Events.LOG event whenever log output is generated. Note this will be dispatched regardless of log level. Source: core/Settings.js, line 322 ErrorSettings Type: Object Properties: Name Type Argument Default Description recoverAttempts object &lt;optional&gt; {mediaErrorDecode: 5} Defines the maximum number of recover attempts for specific media errors. For mediaErrorDecode the player will reset the MSE and skip the blacklisted segment that caused the decode error. The resulting gap will be handled by the GapController. Source: core/Settings.js, line 355 Gaps Type: Object Properties: Name Type Argument Default Description jumpGaps boolean &lt;optional&gt; true Sets whether player should jump small gaps (discontinuities) in the buffer. jumpLargeGaps boolean &lt;optional&gt; true Sets whether player should jump large gaps (discontinuities) in the buffer. smallGapLimit number &lt;optional&gt; 1.5 Time in seconds for a gap to be considered small. threshold number &lt;optional&gt; 0.3 Threshold at which the gap handling is executed. If currentRangeEnd - currentTime &lt; threshold the gap jump will be triggered. For live stream the jump might be delayed to keep a consistent live edge. Note that the amount of buffer at which platforms automatically stall might differ. enableSeekFix boolean &lt;optional&gt; true Enables the adjustment of the seek target once no valid segment request could be generated for a specific seek time. This can happen if the user seeks to a position for which there is a gap in the timeline. enableStallFix boolean &lt;optional&gt; false If playback stalled in a buffered range this fix will perform a seek by the value defined in stallSeek to trigger playback again. stallSeek number &lt;optional&gt; 0.1 Value to be used in case enableStallFix is set to true Source: core/Settings.js, line 373 LiveCatchupSettings Type: Object Properties: Name Type Argument Default Description maxDrift number &lt;optional&gt; NaN 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. playbackRate number &lt;optional&gt; NaN 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 NaN to turn off live catch up feature. Note: Catch-up mechanism is only applied when playing low latency live streams. playbackBufferMin number &lt;optional&gt; NaN Use this parameter to specify the minimum buffer which is used for LoL+ based playback rate reduction. enabled boolean &lt;optional&gt; false Use this parameter to enable the catchup mode for non low-latency streams. mode string &lt;optional&gt; \"liveCatchupModeDefault\" 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. Source: core/Settings.js, line 448 LiveDelay Type: Object Properties: Name Type Argument Default Description liveDelayFragmentCount number &lt;optional&gt; NaN Changing this value will lower or increase live stream latency. The detected segment duration will be multiplied by this value to define a time in seconds to delay a live stream from the live edge. Lowering this value will lower latency but may decrease the player's ability to build a stable buffer. liveDelay number &lt;optional&gt; Equivalent in seconds of setLiveDelayFragmentCount. Lowering this value will lower latency but may decrease the player's ability to build a stable buffer. This value should be less than the manifest duration by a couple of segment durations to avoid playback issues. If set, this parameter will take precedence over setLiveDelayFragmentCount and manifest info. useSuggestedPresentationDelay boolean &lt;optional&gt; true Set to true if you would like to overwrite the default live delay and honor the SuggestedPresentationDelay attribute in by the manifest. Source: core/Settings.js, line 229 Metrics Type: Object Properties: Name Type Argument Default Description metricsMaxListDepth number &lt;optional&gt; 100 Maximum number of metrics that are persisted per type. Source: core/Settings.js, line 642 PlayerSettings Type: Object Properties: Name Type Argument Description debug module:Settings~DebugSettings &lt;optional&gt; Debug related settings. errors module:Settings~ErrorSettings &lt;optional&gt; Error related settings streaming module:Settings~StreamingSettings &lt;optional&gt; Streaming related settings. Source: core/Settings.js, line 45 Example // Full settings object settings = { debug: { logLevel: Debug.LOG_LEVEL_WARNING, dispatchEvent: false }, streaming: { abandonLoadTimeout: 10000, wallclockTimeUpdateInterval: 100, manifestUpdateRetryInterval: 100, cacheInitSegments: true, applyServiceDescription: true, applyProducerReferenceTime: true, applyContentSteering: true, eventControllerRefreshDelay: 100, enableManifestDurationMismatchFix: true, capabilities: { filterUnsupportedEssentialProperties: true, useMediaCapabilitiesApi: false }, timeShiftBuffer: { calcFromSegmentTimeline: false, fallbackToSegmentTimeline: true }, metrics: { maxListDepth: 100 }, delay: { liveDelayFragmentCount: NaN, liveDelay: NaN, useSuggestedPresentationDelay: true }, protection: { keepProtectionMediaKeys: false, ignoreEmeEncryptedEvent: false, detectPlayreadyMessageFormat: true, }, buffer: { enableSeekDecorrelationFix: true, fastSwitchEnabled: true, flushBufferAtTrackSwitch: false, reuseExistingSourceBuffers: true, bufferPruningInterval: 10, bufferToKeep: 20, bufferTimeAtTopQuality: 30, bufferTimeAtTopQualityLongForm: 60, initialBufferLevel: NaN, stableBufferTime: 12, longFormContentDurationThreshold: 600, stallThreshold: 0.5, useAppendWindow: true, setStallState: true, avoidCurrentTimeRangePruning: false }, gaps: { jumpGaps: true, jumpLargeGaps: true, smallGapLimit: 1.5, threshold: 0.3, enableSeekFix: true, enableStallFix: false, stallSeek: 0.1 }, utcSynchronization: { enabled: true, useManifestDateHeaderTimeSource: true, backgroundAttempts: 2, timeBetweenSyncAttempts: 30, maximumTimeBetweenSyncAttempts: 600, minimumTimeBetweenSyncAttempts: 2, timeBetweenSyncAttemptsAdjustmentFactor: 2, maximumAllowedDrift: 100, enableBackgroundSyncAfterSegmentDownloadError: true, defaultTimingSource: { scheme: 'urn:mpeg:dash:utc:http-xsdate:2014', value: 'http://time.akamai.com/?iso&amp;ms' } }, scheduling: { defaultTimeout: 300, lowLatencyTimeout: 100, scheduleWhilePaused: true }, text: { defaultEnabled: true }, liveCatchup: { maxDrift: NaN, playbackRate: NaN, playbackBufferMin: 0.5, enabled: false, mode: Constants.LIVE_CATCHUP_MODE_DEFAULT }, lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, cacheLoadThresholds: { video: 50, audio: 5 }, trackSwitchMode: { audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE, video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE }, selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY, fragmentRequestTimeout: 0, retryIntervals: { [HTTPRequest.MPD_TYPE]: 500, [HTTPRequest.XLINK_EXPANSION_TYPE]: 500, [HTTPRequest.MEDIA_SEGMENT_TYPE]: 1000, [HTTPRequest.INIT_SEGMENT_TYPE]: 1000, [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 1000, [HTTPRequest.INDEX_SEGMENT_TYPE]: 1000, [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 1000, [HTTPRequest.LICENSE]: 1000, [HTTPRequest.OTHER_TYPE]: 1000, lowLatencyReductionFactor: 10 }, retryAttempts: { [HTTPRequest.MPD_TYPE]: 3, [HTTPRequest.XLINK_EXPANSION_TYPE]: 1, [HTTPRequest.MEDIA_SEGMENT_TYPE]: 3, [HTTPRequest.INIT_SEGMENT_TYPE]: 3, [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 3, [HTTPRequest.INDEX_SEGMENT_TYPE]: 3, [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 3, [HTTPRequest.LICENSE]: 3, [HTTPRequest.OTHER_TYPE]: 3, lowLatencyMultiplyFactor: 5 }, abr: { movingAverageMethod: Constants.MOVING_AVERAGE_SLIDING_WINDOW, ABRStrategy: Constants.ABR_STRATEGY_DYNAMIC, additionalAbrRules: { insufficientBufferRule: false, switchHistoryRule: true, droppedFramesRule: true, abandonRequestsRule: false }, bandwidthSafetyFactor: 0.9, useDefaultABRRules: true, useDeadTimeLatency: true, limitBitrateByPortal: false, usePixelRatioInLimitBitrateByPortal: false, maxBitrate: { audio: -1, video: -1 }, minBitrate: { audio: -1, video: -1 }, maxRepresentationRatio: { audio: 1, video: 1 }, initialBitrate: { audio: -1, video: -1 }, initialRepresentationRatio: { audio: -1, video: -1 }, autoSwitchBitrate: { audio: true, video: true }, fetchThroughputCalculationMode: Constants.ABR_FETCH_THROUGHPUT_CALCULATION_DOWNLOADED_DATA }, cmcd: { enabled: false, sid: null, cid: null, rtp: null, rtpSafetyFactor: 5, mode: Constants.CMCD_MODE_QUERY, enabledKeys: ['br', 'd', 'ot', 'tb' , 'bl', 'dl', 'mtp', 'nor', 'nrr', 'su' , 'bs', 'rtp' , 'cid', 'pr', 'sf', 'sid', 'st', 'v'] } }, errors: { recoverAttempts: { mediaErrorDecode: 5 } } } Protection Type: Object Properties: Name Type Argument Default Description keepProtectionMediaKeys boolean &lt;optional&gt; false Set the value for the ProtectionController and MediaKeys life cycle. If true, the ProtectionController and then created MediaKeys and MediaKeySessions will be preserved during the MediaPlayer lifetime. ignoreEmeEncryptedEvent boolean If set to true the player will ignore \"encrypted\" and \"needkey\" events thrown by the EME. detectPlayreadyMessageFormat boolean If set to true the player will use the raw unwrapped message from the Playready CDM Source: core/Settings.js, line 513 RequestTypeSettings Type: Object Properties: Name Type Argument Description MPD number &lt;optional&gt; Manifest type of requests. XLinkExpansion number &lt;optional&gt; XLink expansion type of requests. InitializationSegment number &lt;optional&gt; Request to retrieve an initialization segment. IndexSegment number &lt;optional&gt; Request to retrieve an index segment (SegmentBase). MediaSegment number &lt;optional&gt; Request to retrieve a media segment (video/audio/image/text chunk). BitstreamSwitchingSegment number &lt;optional&gt; Bitrate stream switching type of request. FragmentInfoSegment number &lt;optional&gt; Request to retrieve a FragmentInfo segment (specific to Smooth Streaming live streams). other number &lt;optional&gt; Other type of request. lowLatencyReductionFactor number &lt;optional&gt; For low latency mode, values of type of request are divided by lowLatencyReductionFactor. Note: It's not type of request. lowLatencyMultiplyFactor number &lt;optional&gt; For low latency mode, values of type of request are multiplied by lowLatencyMultiplyFactor. Note: It's not type of request. Source: core/Settings.js, line 485 Scheduling Type: Object Properties: Name Type Argument Default Description defaultTimeout number &lt;optional&gt; 300 Default timeout between two consecutive segment scheduling attempts lowLatencyTimeout number &lt;optional&gt; Default timeout between two consecutive low-latency segment scheduling attempts scheduleWhilePaused boolean &lt;optional&gt; true Set to true if you would like dash.js to keep downloading fragments in the background when the video element is paused. Source: core/Settings.js, line 432 StreamingSettings Type: Object Properties: Name Type Argument Default Description abandonLoadTimeout number &lt;optional&gt; 10000 A timeout value in seconds, which during the ABRController will block switch-up events. This will only take effect after an abandoned fragment event occurs. wallclockTimeUpdateInterval number &lt;optional&gt; 50 How frequently the wallclockTimeUpdated internal event is triggered (in milliseconds). manifestUpdateRetryInterval number &lt;optional&gt; 100 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. cacheInitSegments boolean &lt;optional&gt; true Enables the caching of init segments to avoid requesting the init segments before each representation switch. applyServiceDescription boolean &lt;optional&gt; true Set to true if dash.js should use the parameters defined in ServiceDescription elements applyProducerReferenceTime boolean &lt;optional&gt; true Set to true if dash.js should use the parameters defined in ProducerReferenceTime elements in combination with ServiceDescription elements. applyContentSteering boolean &lt;optional&gt; true Set to true if dash.js should apply content steering during playback. eventControllerRefreshDelay number &lt;optional&gt; 100 For multi-period streams, overwrite the manifest mediaPresentationDuration attribute with the sum of period durations if the manifest mediaPresentationDuration is greater than the sum of period durations enableManifestDurationMismatchFix boolean &lt;optional&gt; true Defines the delay in milliseconds between two consecutive checks for events to be fired. metrics module:Settings~Metrics Metric settings delay module:Settings~LiveDelay Live Delay settings timeShiftBuffer module:Settings~TimeShiftBuffer TimeShiftBuffer settings protection module:Settings~Protection DRM related settings capabilities module:Settings~Capabilities Capability related settings buffer module:Settings~Buffer Buffer related settings gaps module:Settings~Gaps Gap related settings utcSynchronization module:Settings~UtcSynchronizationSettings Settings related to UTC clock synchronization scheduling module:Settings~Scheduling Settings related to segment scheduling text module:Settings~Text Settings related to Subtitles and captions liveCatchup module:Settings~LiveCatchupSettings Settings related to live catchup. lastBitrateCachingInfo module:Settings~CachingInfoSettings &lt;optional&gt; {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. The default expiration is one hour, defined in milliseconds. If expired, the default initial bit rate (closest to 1000 kbps) will be used for that session and a new bit rate will be stored during that session. cacheLoadThresholds module:Settings~AudioVideoSettings &lt;optional&gt; {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. trackSwitchMode module:Settings~AudioVideoSettings &lt;optional&gt; {video: \"neverReplace\", audio: \"alwaysReplace\"} For a given media type defines if existing segments in the buffer should be overwritten once the track is switched. For instance if the user switches the audio language the existing segments in the audio buffer will be replaced when setting this value to \"alwaysReplace\". Possible values Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE Replace existing segments in the buffer Constants.TRACK_SWITCH_MODE_NEVER_REPLACE Do not replace existing segments in the buffer selectionModeForInitialTrack string &lt;optional&gt; \"highestBitrate\" 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: Possible values Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY This mode makes the player select the track with the highest selectionPriority as defined in the manifest. If not selectionPriority is given we fallback to TRACK_SELECTION_MODE_HIGHEST_BITRATE. This mode is a default mode. Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE This mode makes the player select the track with a highest bitrate. Constants.TRACK_SELECTION_MODE_FIRST_TRACK This mode makes the player select the first track found in the manifest. Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY This mode makes the player select the track with the lowest bitrate per pixel average. Constants.TRACK_SELECTION_MODE_WIDEST_RANGE This mode makes the player select the track with a widest range of bitrates. fragmentRequestTimeout number &lt;optional&gt; 0 Time in milliseconds before timing out on loading a media fragment. Fragments that timeout are retried as if they failed. retryIntervals module:Settings~RequestTypeSettings &lt;optional&gt; Time in milliseconds of which to reload a failed file load attempt. For low latency mode these values are divided by lowLatencyReductionFactor. retryAttempts module:Settings~RequestTypeSettings &lt;optional&gt; 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. abr module:Settings~AbrSettings Adaptive Bitrate algorithm related settings. cmcd module:Settings~CmcdSettings Settings related to Common Media Client Data reporting. Source: core/Settings.js, line 648 Text Type: Object Properties: Name Type Argument Default Description defaultEnabled number &lt;optional&gt; true Enable/disable subtitle rendering by default. Source: core/Settings.js, line 442 TimeShiftBuffer Type: Object Properties: Name Type Argument Default Description calcFromSegmentTimeline boolean &lt;optional&gt; false Enable calculation of the DVR window for SegmentTimeline manifests based on the entries in &lt;SegmentTimeline&gt;. @property {boolean} [fallbackToSegmentTimeline=true] In case the MPD uses &lt;SegmentTimeline\\ and no segment is found within the DVR window the DVR window is calculated based on the entries in &lt;SegmentTimeline&gt;. Source: core/Settings.js, line 221 UtcSynchronizationSettings Type: Object Properties: Name Type Argument Default Description enabled boolean &lt;optional&gt; true Enables or disables the UTC clock synchronization useManifestDateHeaderTimeSource boolean &lt;optional&gt; true Allows you to enable the use of the Date Header, if exposed with CORS, as a timing source for live edge detection. The use of the date header will happen only after the other timing source that take precedence fail or are omitted as described. backgroundAttempts number &lt;optional&gt; 2 Number of synchronization attempts to perform in the background after an initial synchronization request has been done. This is used to verify that the derived client-server offset is correct. The background requests are async and done in parallel to the start of the playback. This value is also used to perform a resync after 404 errors on segments. timeBetweenSyncAttempts number &lt;optional&gt; 30 The time in seconds between two consecutive sync attempts. Note: This value is used as an initial starting value. The internal value of the TimeSyncController is adjusted during playback based on the drift between two consecutive synchronization attempts. Note: A sync is only performed after an MPD update. In case the @minimumUpdatePeriod is larger than this value the sync will be delayed until the next MPD update. maximumTimeBetweenSyncAttempts number &lt;optional&gt; 600 The maximum time in seconds between two consecutive sync attempts. minimumTimeBetweenSyncAttempts number &lt;optional&gt; 2 The minimum time in seconds between two consecutive sync attempts. timeBetweenSyncAttemptsAdjustmentFactor number &lt;optional&gt; 2 The factor used to multiply or divide the timeBetweenSyncAttempts parameter after a sync. The maximumAllowedDrift defines whether this value is used as a factor or a dividend. maximumAllowedDrift number &lt;optional&gt; 100 The maximum allowed drift specified in milliseconds between two consecutive synchronization attempts. enableBackgroundSyncAfterSegmentDownloadError boolean &lt;optional&gt; true Enables or disables the background sync after the player ran into a segment download error. defaultTimingSource object &lt;optional&gt; {scheme:'urn:mpeg:dash:utc:http-xsdate:2014',value: 'http://time.akamai.com/?iso&amp;ms'} The default timing source to be used. The timing sources in the MPD take precedence over this one. Source: core/Settings.js, line 393 × Search results Close "},"MssErrors.html":{"id":"MssErrors.html","title":"Class: MssErrors","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: MssErrors MssErrors new MssErrors() Source: mss/errors/MssErrors.js, line 37 Members MSS_NO_TFRF_CODE Error code returned when no tfrf box is detected in MSS live stream Source: mss/errors/MssErrors.js, line 43 MSS_UNSUPPORTED_CODEC_CODE Error code returned when one of the codecs defined in the manifest is not supported Source: mss/errors/MssErrors.js, line 48 × Search results Close "},"OfflineErrors.html":{"id":"OfflineErrors.html","title":"Class: OfflineErrors","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: OfflineErrors OfflineErrors Offline Errors declaration new OfflineErrors() Source: offline/errors/OfflineErrors.js, line 36 Members OFFLINE_ERROR Error code returned when an error occurs in offline module Source: offline/errors/OfflineErrors.js, line 44 × Search results Close "},"OfflineEvents.html":{"id":"OfflineEvents.html","title":"Class: OfflineEvents","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: OfflineEvents OfflineEvents These are offline events that should be sent to the player level. new OfflineEvents() Source: offline/events/OfflineEvents.js, line 6 Events OFFLINE_RECORD_FINISHED Triggered when all record has been downloaded Source: offline/events/OfflineEvents.js, line 28 OFFLINE_RECORD_LOADEDMETADATA Triggered when all mediaInfo has been loaded Source: offline/events/OfflineEvents.js, line 10 OFFLINE_RECORD_STARTED Triggered when a record is initialized and download is started Source: offline/events/OfflineEvents.js, line 16 OFFLINE_RECORD_STOPPED Triggered when the user stop downloading a record Source: offline/events/OfflineEvents.js, line 22 × Search results Close "},"ProtectionErrors.html":{"id":"ProtectionErrors.html","title":"Class: ProtectionErrors","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: ProtectionErrors ProtectionErrors new ProtectionErrors() Source: streaming/protection/errors/ProtectionErrors.js, line 36 Members KEY_SESSION_CREATED_ERROR_CODE Error code returned when key session has not been successfully created Source: streaming/protection/errors/ProtectionErrors.js, line 96 KEY_STATUS_CHANGED_EXPIRED_ERROR_CODE Error code returned when license validity has expired Source: streaming/protection/errors/ProtectionErrors.js, line 84 KEY_SYSTEM_ACCESS_DENIED_ERROR_CODE Error code returned when key system access is denied Source: streaming/protection/errors/ProtectionErrors.js, line 92 MEDIA_KEY_MESSAGE_ERROR_CODE Error code returned when an error occured in keymessage event for ProtectionModel_01b Source: streaming/protection/errors/ProtectionErrors.js, line 72 MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE Error code returned when license request failed after a keymessage event has been triggered Source: streaming/protection/errors/ProtectionErrors.js, line 100 MEDIA_KEY_MESSAGE_NO_CHALLENGE_ERROR_CODE Error code returned when challenge is invalid in keymessage event (event triggered by CDM) Source: streaming/protection/errors/ProtectionErrors.js, line 76 MEDIA_KEY_MESSAGE_NO_LICENSE_SERVER_URL_ERROR_CODE Error code returned when no licenser url is defined Source: streaming/protection/errors/ProtectionErrors.js, line 88 MEDIA_KEYERR_CLIENT_CODE Error code returned by keyerror api for ProtectionModel_01b Source: streaming/protection/errors/ProtectionErrors.js, line 51 MEDIA_KEYERR_CODE Generid key Error code Source: streaming/protection/errors/ProtectionErrors.js, line 43 MEDIA_KEYERR_DOMAIN_CODE Error code returned by keyerror api for ProtectionModel_01b Source: streaming/protection/errors/ProtectionErrors.js, line 67 MEDIA_KEYERR_HARDWARECHANGE_CODE Error code returned by keyerror api for ProtectionModel_01b Source: streaming/protection/errors/ProtectionErrors.js, line 63 MEDIA_KEYERR_OUTPUT_CODE Error code returned by keyerror api for ProtectionModel_01b Source: streaming/protection/errors/ProtectionErrors.js, line 59 MEDIA_KEYERR_SERVICE_CODE Error code returned by keyerror api for ProtectionModel_01b Source: streaming/protection/errors/ProtectionErrors.js, line 55 MEDIA_KEYERR_UNKNOWN_CODE Error code returned by keyerror api for ProtectionModel_01b Source: streaming/protection/errors/ProtectionErrors.js, line 47 SERVER_CERTIFICATE_UPDATED_ERROR_CODE Error code returned when License server certificate has not been successfully updated Source: streaming/protection/errors/ProtectionErrors.js, line 80 × Search results Close "},"ProtectionEvents.html":{"id":"ProtectionEvents.html","title":"Class: ProtectionEvents","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEvents Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BUFFER_EMPTYMediaPlayerEvents#event:BUFFER_LEVEL_STATE_CHANGEDMediaPlayerEvents#event:BUFFER_LEVEL_UPDATEDMediaPlayerEvents#event:BUFFER_LOADEDMediaPlayerEvents#event:CAN_PLAYMediaPlayerEvents#event:CAN_PLAY_THROUGHMediaPlayerEvents#event:CAPTION_CONTAINER_RESIZEMediaPlayerEvents#event:CAPTION_RENDEREDMediaPlayerEvents#event:CONFORMANCE_VIOLATIONMediaPlayerEvents#event:CONTENT_STEERING_REQUEST_COMPLETEDMediaPlayerEvents#event:DYNAMIC_TO_STATICMediaPlayerEvents#event:ERRORMediaPlayerEvents#event:EVENT_MODE_ON_RECEIVEMediaPlayerEvents#event:EVENT_MODE_ON_STARTMediaPlayerEvents#event:FRAGMENT_LOADING_ABANDONEDMediaPlayerEvents#event:FRAGMENT_LOADING_COMPLETEDMediaPlayerEvents#event:FRAGMENT_LOADING_PROGRESSMediaPlayerEvents#event:FRAGMENT_LOADING_STARTEDMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_VALIDITY_CHANGEDMediaPlayerEvents#event:METRIC_ADDEDMediaPlayerEvents#event:METRIC_CHANGEDMediaPlayerEvents#event:METRIC_UPDATEDMediaPlayerEvents#event:METRICS_CHANGEDMediaPlayerEvents#event:PERIOD_SWITCH_COMPLETEDMediaPlayerEvents#event:PERIOD_SWITCH_STARTEDMediaPlayerEvents#event:PLAYBACK_ENDEDMediaPlayerEvents#event:PLAYBACK_ERRORMediaPlayerEvents#event:PLAYBACK_LOADED_DATAMediaPlayerEvents#event:PLAYBACK_METADATA_LOADEDMediaPlayerEvents#event:PLAYBACK_NOT_ALLOWEDMediaPlayerEvents#event:PLAYBACK_PAUSEDMediaPlayerEvents#event:PLAYBACK_PLAYINGMediaPlayerEvents#event:PLAYBACK_PROGRESSMediaPlayerEvents#event:PLAYBACK_RATE_CHANGEDMediaPlayerEvents#event:PLAYBACK_SEEKEDMediaPlayerEvents#event:PLAYBACK_SEEKINGMediaPlayerEvents#event:PLAYBACK_STALLEDMediaPlayerEvents#event:PLAYBACK_STARTEDMediaPlayerEvents#event:PLAYBACK_TIME_UPDATEDMediaPlayerEvents#event:PLAYBACK_VOLUME_CHANGEDMediaPlayerEvents#event:PLAYBACK_WAITINGMediaPlayerEvents#event:QUALITY_CHANGE_RENDEREDMediaPlayerEvents#event:QUALITY_CHANGE_REQUESTEDMediaPlayerEvents#event:REPRESENTATION_SWITCHMediaPlayerEvents#event:STREAM_ACTIVATEDMediaPlayerEvents#event:STREAM_DEACTIVATEDMediaPlayerEvents#event:STREAM_INITIALIZEDMediaPlayerEvents#event:STREAM_INITIALIZINGMediaPlayerEvents#event:STREAM_TEARDOWN_COMPLETEMediaPlayerEvents#event:STREAM_UPDATEDMediaPlayerEvents#event:TEXT_TRACK_ADDEDMediaPlayerEvents#event:TEXT_TRACKS_ADDEDMediaPlayerEvents#event:TRACK_CHANGE_RENDEREDMediaPlayerEvents#event:TTML_PARSEDMediaPlayerEvents#event:TTML_TO_PARSEMetricsReportingEvents#event:CMCD_DATA_GENERATEDOfflineEvents#event:OFFLINE_RECORD_FINISHEDOfflineEvents#event:OFFLINE_RECORD_LOADEDMETADATAOfflineEvents#event:OFFLINE_RECORD_STARTEDOfflineEvents#event:OFFLINE_RECORD_STOPPEDProtectionEvents#event:KEY_ADDEDProtectionEvents#event:KEY_ERRORProtectionEvents#event:KEY_MESSAGEProtectionEvents#event:KEY_SESSION_CLOSEDProtectionEvents#event:KEY_SESSION_CREATEDProtectionEvents#event:KEY_SESSION_REMOVEDProtectionEvents#event:KEY_STATUSES_CHANGEDProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: ProtectionEvents ProtectionEvents new ProtectionEvents() Public facing external events to be used when including protection package. All public events will be aggregated into the MediaPlayerEvents Class and can be accessed via MediaPlayer.events. public_ is the prefix that we use to move event names to MediaPlayerEvents. Source: streaming/protection/ProtectionEvents.js, line 35 Events KEY_ADDED Event ID for events delivered when a new key has been added Deprecated: The latest versions of the EME specification no longer use this event. {@MediaPlayer.models.protectionModel.eventList.KEY_STATUSES_CHANGED} is preferred. Source: streaming/protection/ProtectionEvents.js, line 58 KEY_ERROR Event ID for events delivered when an error is encountered by the CDM while processing a license server response message Source: streaming/protection/ProtectionEvents.js, line 68 KEY_MESSAGE Event ID for events delivered when the protection set receives a key message from the CDM Source: streaming/protection/ProtectionEvents.js, line 75 KEY_SESSION_CLOSED Event ID for events delivered when a key session close process has completed Source: streaming/protection/ProtectionEvents.js, line 82 KEY_SESSION_CREATED Event ID for events delivered when a new key sessions creation process has completed Source: streaming/protection/ProtectionEvents.js, line 89 KEY_SESSION_REMOVED Event ID for events delivered when a key session removal process has completed Source: streaming/protection/ProtectionEvents.js, line 96 KEY_STATUSES_CHANGED Event ID for events delivered when the status of one or more decryption keys has changed Source: streaming/protection/ProtectionEvents.js, line 103 KEY_SYSTEM_SELECTED Event ID for events delivered when a key system selection procedure completes Source: streaming/protection/ProtectionEvents.js, line 117 LICENSE_REQUEST_COMPLETE Event ID for events delivered when a license request procedure has completed Source: streaming/protection/ProtectionEvents.js, line 124 LICENSE_REQUEST_SENDING Sending a license rquest Source: streaming/protection/ProtectionEvents.js, line 131 PROTECTION_CREATED Event ID for events delivered when the Protection system is detected and created. Source: streaming/protection/ProtectionEvents.js, line 143 PROTECTION_DESTROYED Event ID for events delivered when the Protection system is destroyed. Source: streaming/protection/ProtectionEvents.js, line 149 × Search results Close "}}
    </script>

    <script type="text/javascript">
        $(document).ready(function() {
            Searcher.init();
        });

        $(window).on("message", function(msg) {
            var msgData = msg.originalEvent.data;

            if (msgData.msgid != "docstrap.quicksearch.start") {
                return;
            }

            var results = Searcher.search(msgData.searchTerms);

            window.parent.postMessage({"results": results, "msgid": "docstrap.quicksearch.done"}, "*");
        });
    </script>
</body>
</html>