UNPKG

dashjs

Version:

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

32 lines 1.88 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_models_AastLowLatencyThroughputModel.js.html":{"id":"streaming_models_AastLowLatencyThroughputModel.js.html","title":"Source: streaming/models/AastLowLatencyThroughputModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/AastLowLatencyThroughputModel.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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; function AastLowLatencyThroughputModel() { 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.representation.mediaInfo.bitrateList.find(item =&gt; item.id === request.representation.id); 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.representation.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 = { addMeasurement, getEstimatedDownloadDurationMS, getThroughputCapacityDelayMS, setup, }; setup() return instance; } AastLowLatencyThroughputModel.__dashjs_factory_name = 'AastLowLatencyThroughputModel'; export default FactoryMaker.getSingletonFactory(AastLowLatencyThroughputModel); × Search results Close "},"streaming_controllers_AbrController.js.html":{"id":"streaming_controllers_AbrController.js.html","title":"Source: streaming/controllers/AbrController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Constants from '../constants/Constants.js'; import MetricsConstants from '../constants/MetricsConstants.js'; import FragmentModel from '../models/FragmentModel.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import RulesContext from '../rules/RulesContext.js'; import SwitchRequest from '../rules/SwitchRequest.js'; import SwitchRequestHistory from '../rules/SwitchRequestHistory.js'; import DroppedFramesHistory from '../rules/DroppedFramesHistory.js'; import Debug from '../../core/Debug.js'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; const DEFAULT_VIDEO_BITRATE = 1000; const DEFAULT_BITRATE = 100; function AbrController() { const context = this.context; const debug = Debug(context).getInstance(); const eventBus = EventBus(context).getInstance(); let instance, logger, abrRulesCollection, streamController, streamProcessorDict, abandonmentStateDict, abandonmentTimeout, windowResizeEventCalled, adapter, videoModel, mediaPlayerModel, customParametersModel, cmsdModel, domStorage, playbackRepresentationId, switchRequestHistory, droppedFramesHistory, throughputController, dashMetrics, settings; function setup() { logger = debug.getLogger(instance); resetInitialSettings(); } /** * Initialize everything that is not period specific. We only have one instance of the ABR Controller for all periods. */ function initialize() { droppedFramesHistory = DroppedFramesHistory(context).create(); switchRequestHistory = SwitchRequestHistory(context).create(); 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] = {}; } streamProcessorDict[streamId][type] = streamProcessor; if (!abandonmentStateDict[streamId]) { abandonmentStateDict[streamId] = {}; } abandonmentStateDict[streamId][type] = {}; abandonmentStateDict[streamId][type].state = MetricsConstants.ALLOW_LOAD; // Do not change current value if it has been set before const currentState = abrRulesCollection.getBolaState(type) if (currentState === undefined) { abrRulesCollection.setBolaState(type, settings.get().streaming.abr.rules.bolaRule.active &amp;&amp; !_shouldApplyDynamicAbrStrategy()); } } /** * Remove all parameters that belong to a specific period * @param {string} streamId * @param {string} type */ function unRegisterStreamType(streamId, type) { try { if (streamProcessorDict[streamId] &amp;&amp; streamProcessorDict[streamId][type]) { delete streamProcessorDict[streamId][type]; } if (abandonmentStateDict[streamId] &amp;&amp; abandonmentStateDict[streamId][type]) { delete abandonmentStateDict[streamId][type]; } } catch (e) { } } function resetInitialSettings() { abandonmentStateDict = {}; streamProcessorDict = {}; if (windowResizeEventCalled === undefined) { windowResizeEventCalled = false; } if (droppedFramesHistory) { droppedFramesHistory.reset(); } if (switchRequestHistory) { switchRequestHistory.reset(); } playbackRepresentationId = undefined; droppedFramesHistory = undefined; switchRequestHistory = undefined; clearTimeout(abandonmentTimeout); abandonmentTimeout = null; } function reset() { resetInitialSettings(); eventBus.off(MediaPlayerEvents.QUALITY_CHANGE_RENDERED, _onQualityChangeRendered, instance); eventBus.off(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); eventBus.off(Events.LOADING_PROGRESS, _onFragmentLoadProgress, instance); if (abrRulesCollection) { abrRulesCollection.reset(); } } function setConfig(config) { if (!config) return; if (config.streamController) { streamController = config.streamController; } if (config.throughputController) { throughputController = config.throughputController; } if (config.domStorage) { domStorage = config.domStorage; } if (config.mediaPlayerModel) { mediaPlayerModel = config.mediaPlayerModel; } if (config.customParametersModel) { customParametersModel = config.customParametersModel; } if (config.cmsdModel) { cmsdModel = config.cmsdModel } 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 getOptimalRepresentationForBitrate(mediaInfo, bitrate, includeCompatibleMediaInfos = true) { const possibleVoRepresentations = getPossibleVoRepresentations(mediaInfo, includeCompatibleMediaInfos); if (!possibleVoRepresentations || possibleVoRepresentations.length === 0) { return null; } // If bitrate should be as small as possible return the Representation with the lowest bitrate if (bitrate &lt;= 0) { return possibleVoRepresentations.sort((a, b) =&gt; { return a.bandwidth - b.bandwidth; })[0] } // Get all Representations that have lower or equal bitrate than our target bitrate const targetRepresentations = possibleVoRepresentations.filter((rep) =&gt; { return rep.bitrateInKbit &lt;= bitrate }); if (!targetRepresentations || targetRepresentations.length === 0) { return possibleVoRepresentations[0]; } return targetRepresentations[targetRepresentations.length - 1]; } function getRepresentationByAbsoluteIndex(absoluteIndex, mediaInfo, includeCompatibleMediaInfos = true) { if (isNaN(absoluteIndex) || absoluteIndex &lt; 0) { return null; } const possibleVoRepresentations = getPossibleVoRepresentations(mediaInfo, includeCompatibleMediaInfos); return possibleVoRepresentations.find((rep) =&gt; { return rep.absoluteIndex === absoluteIndex }) } function getPossibleVoRepresentations(mediaInfo, includeCompatibleMediaInfos = true) { let voRepresentations = []; if (!mediaInfo) { return voRepresentations; } const mediaInfos = _getPossibleMediaInfos(mediaInfo) mediaInfos.forEach((mediaInfo) =&gt; { let currentVoRepresentations = adapter.getVoRepresentations(mediaInfo); if (currentVoRepresentations &amp;&amp; currentVoRepresentations.length &gt; 0) { voRepresentations = voRepresentations.concat(currentVoRepresentations) } }) // Now sort by quality (usually simply by bitrate) voRepresentations = _sortByCalculatedQualityRank(voRepresentations); // Filter the list of options based on the provided settings voRepresentations = _filterByAllowedSettings(voRepresentations) // Add an absolute index after filtering voRepresentations.forEach((rep, index) =&gt; { rep.absoluteIndex = index }) // Filter the Representations in case we do not want to include compatible Media Infos // We can not apply the filter before otherwise the absolute index would be wrong if (!includeCompatibleMediaInfos) { voRepresentations = voRepresentations.filter((rep) =&gt; { return adapter.areMediaInfosEqual(rep.mediaInfo, mediaInfo); }) } return voRepresentations; } function _getPossibleMediaInfos(mediaInfo) { try { const possibleMediaInfos = []; if (mediaInfo) { possibleMediaInfos.push(mediaInfo); } // If AS switching is disabled return only the current MediaInfo if (!settings.get().streaming.abr.enableSupplementalPropertyAdaptationSetSwitching || !mediaInfo.adaptationSetSwitchingCompatibleIds || mediaInfo.adaptationSetSwitchingCompatibleIds.length === 0) { return possibleMediaInfos } // Otherwise add everything that is compatible const mediaInfoArr = streamProcessorDict[mediaInfo.streamInfo.id][mediaInfo.type].getAllMediaInfos() const compatibleMediaInfos = mediaInfoArr.filter((entry) =&gt; { return mediaInfo.adaptationSetSwitchingCompatibleIds.includes(entry.id) }) return possibleMediaInfos.concat(compatibleMediaInfos); } catch (e) { return [mediaInfo] } } /** * @param {Representation[]} voRepresentations * @return {Representation[]} */ function _filterByAllowedSettings(voRepresentations) { try { voRepresentations = _filterByPossibleBitrate(voRepresentations); voRepresentations = _filterByPortalSize(voRepresentations); voRepresentations = _filterByCmsdMaxBitrate(voRepresentations); return voRepresentations; } catch (e) { logger.error(e); return voRepresentations } } /** * Returns all RepresentationInfo objects that have at least one bitrate that fulfills the constraint * @param {Representation[]} voRepresentations * @return {Representation[]} */ function _filterByPossibleBitrate(voRepresentations) { try { const filteredArray = voRepresentations.filter((voRepresentation) =&gt; { const type = voRepresentation.mediaInfo.type; const representationBitrate = voRepresentation.bitrateInKbit; const maxBitrate = mediaPlayerModel.getAbrBitrateParameter('maxBitrate', type); const minBitrate = mediaPlayerModel.getAbrBitrateParameter('minBitrate', type); if (maxBitrate &gt; -1 &amp;&amp; representationBitrate &gt; maxBitrate) { return false; } return !(minBitrate &gt; -1 &amp;&amp; representationBitrate &lt; minBitrate); }) if (filteredArray.length &gt; 0) { return filteredArray } return voRepresentations } catch (e) { logger.error(e); return voRepresentations } } /** * @param {Representation[]} voRepresentations * @return {Representation[]} * @private */ function _filterByPortalSize(voRepresentations) { try { if (!settings.get().streaming.abr.limitBitrateByPortal) { return voRepresentations; } const { elementWidth } = videoModel.getVideoElementSize(); const filteredArray = voRepresentations.filter((voRepresentation) =&gt; { return voRepresentation.mediaInfo.type !== Constants.VIDEO || voRepresentation.width &lt;= elementWidth; }) if (filteredArray.length &gt; 0) { return filteredArray } return voRepresentations } catch (e) { logger.error(e); return voRepresentations } } /** * @param {Representation[]} voRepresentations * @return {Representation[]} */ function _filterByCmsdMaxBitrate(voRepresentations) { try { // Check CMSD max suggested bitrate only for video segments if (!settings.get().streaming.cmsd.enabled || !settings.get().streaming.cmsd.abr.applyMb) { return voRepresentations } const filteredArray = voRepresentations.filter((voRepresentation) =&gt; { const type = voRepresentation.mediaInfo.type; let maxCmsdBitrate = cmsdModel.getMaxBitrate(type); if (type !== Constants.VIDEO || maxCmsdBitrate &lt; 0) { return true } // Subtract audio bitrate const streamId = voRepresentation.mediaInfo.streamInfo.id; const streamProcessor = streamProcessorDict[streamId][Constants.AUDIO]; const representation = streamProcessor.getRepresentation(); const audioBitrate = representation.bitrateInKbit; maxCmsdBitrate -= audioBitrate ? audioBitrate : 0; return voRepresentation.bitrateInKbit &lt;= maxCmsdBitrate }) if (filteredArray.length &gt; 0) { return filteredArray } return voRepresentations } catch (e) { logger.error(e); return voRepresentations } } /** * Calculate a quality rank based on bandwidth, codec and qualityRanking. Lower value means better quality. * @param voRepresentations * @private */ function _sortByCalculatedQualityRank(voRepresentations) { // All Representations must have a qualityRanking otherwise we ignore it // QualityRanking only applies to Representations within one AS. If we merged multiple AS based on the adaptation-set-switching-2016 supplemental property we can not apply this logic let firstMediaInfo = null; const filteredRepresentations = voRepresentations.filter((rep) =&gt; { if (!firstMediaInfo) { firstMediaInfo = rep.mediaInfo; } return !isNaN(rep.qualityRanking) &amp;&amp; adapter.areMediaInfosEqual(firstMediaInfo, rep.mediaInfo); }) if (filteredRepresentations.length === voRepresentations.length) { voRepresentations.sort((a, b) =&gt; { return b.qualityRanking - a.qualityRanking; }) } else { voRepresentations.sort((a, b) =&gt; { return a.bandwidth - b.bandwidth; }) } return voRepresentations } /** * 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, currentRequest: e.request, throughputController, videoModel }); const switchRequest = abrRulesCollection.shouldAbandonFragment(rulesContext); if (switchRequest &amp;&amp; switchRequest.representation !== SwitchRequest.NO_CHANGE) { _onSegmentDownloadShouldBeAbandoned(e, streamId, type, streamProcessor, switchRequest); } } function _onSegmentDownloadShouldBeAbandoned(e, streamId, type, streamProcessor, switchRequest) { 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; switchRequestHistory.reset(); setPlaybackQuality(type, streamController.getActiveStreamInfo(), switchRequest.representation, 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 (playbackRepresentationId !== undefined) { droppedFramesHistory.push(e.streamId, playbackRepresentationId, videoModel.getPlaybackQuality()); } playbackRepresentationId = e.newRepresentation.id; } } /** * When the buffer level is updated we check if we need to change the ABR strategy * @param e * @private */ function _onMetricAdded(e) { if (_shouldApplyDynamicAbrStrategy() &amp;&amp; e.metric === MetricsConstants.BUFFER_LEVEL &amp;&amp; (e.mediaType === Constants.AUDIO || e.mediaType === Constants.VIDEO)) { _updateDynamicAbrStrategy(e.mediaType, 0.001 * e.value.level); } } /** * Returns the initial bitrate for a specific media type * @param {string} type * @returns {number} A value of the initial bitrate, kbps * @memberof AbrController# */ function getInitialBitrateFor(type) { if (type === Constants.TEXT) { return NaN; } let configBitrate = mediaPlayerModel.getAbrBitrateParameter('initialBitrate', type); if (configBitrate &gt; 0) { return configBitrate; } let savedBitrate = NaN; if (domStorage &amp;&amp; domStorage.hasOwnProperty('getSavedBitrateSettings')) { savedBitrate = domStorage.getSavedBitrateSettings(type); } if (!isNaN(savedBitrate)) { return savedBitrate } const averageThroughput = throughputController.getAverageThroughput(type); if (!isNaN(averageThroughput) &amp;&amp; averageThroughput &gt; 0) { return averageThroughput } return (type === Constants.VIDEO) ? DEFAULT_VIDEO_BITRATE : DEFAULT_BITRATE; } /** * 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, playbackRepresentationId, playbackQuality); } } if (!settings.get().streaming.abr.autoSwitchBitrate[type]) { return false; } const streamProcessor = streamProcessorDict[streamId][type]; const currentRepresentation = streamProcessor.getRepresentation(); const rulesContext = RulesContext(context).create({ abrController: instance, throughputController, switchRequestHistory, droppedFramesHistory, streamProcessor, videoModel }); const switchRequest = abrRulesCollection.getBestPossibleSwitchRequest(rulesContext); if (!switchRequest || !switchRequest.representation) { return false; } let newRepresentation = switchRequest.representation; switchRequestHistory.push({ currentRepresentation, newRepresentation }); if (newRepresentation.id !== currentRepresentation.id &amp;&amp; (abandonmentStateDict[streamId][type].state === MetricsConstants.ALLOW_LOAD || newRepresentation.absoluteIndex &lt; currentRepresentation.absoluteIndex)) { _changeQuality(currentRepresentation, newRepresentation, switchRequest.reason); return true; } return false; } catch (e) { logger.error(e); return false; } } /** * 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 {Representation} representation * @param {string} reason * @param {string} rule */ function setPlaybackQuality(type, streamInfo, representation, reason = {}) { if (!streamInfo || !streamInfo.id || !type || !streamProcessorDict || !streamProcessorDict[streamInfo.id] || !streamProcessorDict[streamInfo.id][type] || !representation) { return; } const streamProcessor = streamProcessorDict[streamInfo.id][type]; const currentRepresentation = streamProcessor.getRepresentation(); if (!currentRepresentation || representation.id !== currentRepresentation.id) { _changeQuality(currentRepresentation, representation, reason); } } /** * * @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 {Representation} oldRepresentation * @param {Representation} newRepresentation * @param {string} reason * @private */ function _changeQuality(oldRepresentation, newRepresentation, reason) { const streamId = newRepresentation.mediaInfo.streamInfo.id; const type = newRepresentation.mediaInfo.type; if (type &amp;&amp; streamProcessorDict[streamId] &amp;&amp; streamProcessorDict[streamId][type]) { const streamInfo = streamProcessorDict[streamId][type].getStreamInfo(); const bufferLevel = dashMetrics.getCurrentBufferLevel(type); const isAdaptationSetSwitch = oldRepresentation !== null &amp;&amp; !adapter.areMediaInfosEqual(oldRepresentation.mediaInfo, newRepresentation.mediaInfo); const oldBitrate = oldRepresentation ? oldRepresentation.bitrateInKbit : 0; logger.info(`[AbrController]: Switching quality in period ${streamId} for media type ${type}. Switch from bitrate ${oldBitrate} to bitrate ${newRepresentation.bitrateInKbit}. Current buffer level: ${bufferLevel}. Reason:` + (reason ? JSON.stringify(reason) : '/')); eventBus.trigger(Events.QUALITY_CHANGE_REQUESTED, { oldRepresentation: oldRepresentation, newRepresentation: newRepresentation, reason, streamInfo, mediaType: type, isAdaptationSetSwitch }, { streamId: streamInfo.id, mediaType: type } ); const bitrate = throughputController.getAverageThroughput(type); if (!isNaN(bitrate)) { domStorage.setSavedBitrateSettings(type, bitrate); } } } /** * If both BOLA and Throughput Rule are active we switch dynamically between both of them * @returns {boolean} * @private */ function _shouldApplyDynamicAbrStrategy() { return settings.get().streaming.abr.rules.bolaRule.active &amp;&amp; settings.get().streaming.abr.rules.throughputRule.active } /** * Switch between BOLA and ThroughputRule * @param mediaType * @param bufferLevel * @private */ function _updateDynamicAbrStrategy(mediaType, bufferLevel) { try { const bufferTimeDefault = mediaPlayerModel.getBufferTimeDefault(); const switchOnThreshold = bufferTimeDefault; const switchOffThreshold = 0.5 * bufferTimeDefault; const useBufferABR = abrRulesCollection.getBolaState(mediaType) const newUseBufferABR = bufferLevel &gt; (useBufferABR ? switchOffThreshold : switchOnThreshold); // use hysteresis to avoid oscillating rules abrRulesCollection.setBolaState(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); } } /** * Checks if the provided Representation has the lowest possible quality * @param representation * @returns {boolean} */ function isPlayingAtLowestQuality(representation) { const voRepresentations = getPossibleVoRepresentations(representation.mediaInfo, true); return voRepresentations[0].id === representation.id } /** * Checks if the provided Representation has the highest possible quality * @param representation * @returns {boolean} */ function isPlayingAtTopQuality(representation) { if (!representation) { return true; } const voRepresentations = getPossibleVoRepresentations(representation.mediaInfo, true); return voRepresentations[voRepresentations.length - 1].id === representation.id; } function setWindowResizeEventCalled(value) { windowResizeEventCalled = value; } function clearDataForStream(streamId) { if (droppedFramesHistory) { droppedFramesHistory.clearForStream(streamId); } if (streamProcessorDict[streamId]) { delete streamProcessorDict[streamId]; } if (switchRequestHistory) { switchRequestHistory.clearForStream(streamId); } if (abandonmentStateDict[streamId]) { delete abandonmentStateDict[streamId]; } } instance = { checkPlaybackQuality, clearDataForStream, getAbandonmentStateFor, getInitialBitrateFor, getOptimalRepresentationForBitrate, getPossibleVoRepresentations, getRepresentationByAbsoluteIndex, initialize, isPlayingAtLowestQuality, isPlayingAtTopQuality, registerStreamType, reset, setConfig, setPlaybackQuality, setWindowResizeEventCalled, unRegisterStreamType, }; setup(); return instance; } AbrController.__dashjs_factory_name = 'AbrController'; const factory = FactoryMaker.getSingletonFactory(AbrController); 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import InsufficientBufferRule from './InsufficientBufferRule.js'; import AbandonRequestsRule from './AbandonRequestsRule.js'; import DroppedFramesRule from './DroppedFramesRule.js'; import SwitchHistoryRule from './SwitchHistoryRule.js'; import BolaRule from './BolaRule.js'; import L2ARule from './L2ARule.js'; import LoLPRule from './lolp/LoLpRule.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; import SwitchRequest from '../SwitchRequest.js'; import EventBus from '../../../core/EventBus.js'; import Events from '../../../core/events/Events.js'; import Constants from '../../constants/Constants.js'; 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; const eventBus = EventBus(context).getInstance(); let instance, qualitySwitchRules, abandonFragmentRules, shouldUseBolaRuleByMediaType; function initialize() { qualitySwitchRules = []; abandonFragmentRules = []; shouldUseBolaRuleByMediaType = {}; _updateRules(); eventBus.on(Events.SETTING_UPDATED_ABR_ACTIVE_RULES, _onAbrSettingsActiveRulesUpdated, instance); } /** * Adds and removes rules to/from the respective rules arrays * @private */ function _updateRules() { let qualitySwitchRulesList = Object.values(Constants.QUALITY_SWITCH_RULES) qualitySwitchRulesList.forEach((ruleName) =&gt; { qualitySwitchRules = _handleRuleUpdate(ruleName, qualitySwitchRules) }) let abandonFragmentRulesList = Object.values(Constants.ABANDON_FRAGMENT_RULES) abandonFragmentRulesList.forEach((ruleName) =&gt; { abandonFragmentRules = _handleRuleUpdate(ruleName, abandonFragmentRules) }) // add custom ABR rules if any const customRules = customParametersModel.getAbrCustomRules(); customRules.forEach(function (rule) { if (rule.type === Constants.RULES_TYPES.QUALITY_SWITCH_RULES) { qualitySwitchRules.push(rule.rule(context).create()); } if (rule.type === Constants.RULES_TYPES.ABANDON_FRAGMENT_RULES) { abandonFragmentRulesList.push(rule.rule(context).create()); } }); // If we still got no rule for quality switch use Throughput and Bola if (qualitySwitchRules.length === 0) { qualitySwitchRules.push( BolaRule(context).create({ dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, settings: settings }) ); qualitySwitchRules.push( ThroughputRule(context).create({ dashMetrics: dashMetrics }) ); } } function _handleRuleUpdate(ruleName, rulesCollection) { // we use camel case in the settings while the rules start with a capital latter. Not ideal but convert between these formats const attribute = ruleName.charAt(0).toLowerCase() + ruleName.slice(1); if (settings.get().streaming.abr.rules[attribute].active &amp;&amp; !_arrayContainsRule(rulesCollection, ruleName)) { rulesCollection.push( _createRuleInstance(ruleName) ); return rulesCollection } else if (!settings.get().streaming.abr.rules[attribute].active) { return _removeRuleFromArray(rulesCollection, ruleName) } return rulesCollection } function _createRuleInstance(rule) { switch (rule) { case Constants.QUALITY_SWITCH_RULES.BOLA_RULE: return BolaRule(context).create({ dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, settings: settings }) case Constants.QUALITY_SWITCH_RULES.THROUGHPUT_RULE: return ThroughputRule(context).create({ dashMetrics: dashMetrics }) case Constants.QUALITY_SWITCH_RULES.INSUFFICIENT_BUFFER_RULE: return InsufficientBufferRule(context).create({ dashMetrics: dashMetrics, settings }) case Constants.QUALITY_SWITCH_RULES.SWITCH_HISTORY_RULE: return SwitchHistoryRule(context).create() case Constants.QUALITY_SWITCH_RULES.DROPPED_FRAMES_RULE: return DroppedFramesRule(context).create() case Constants.QUALITY_SWITCH_RULES.LEARN_TO_ADAPT_RULE: return L2ARule(context).create({ dashMetrics: dashMetrics, settings: settings }) case Constants.QUALITY_SWITCH_RULES.LOL_PLUS_RULE: return LoLPRule(context).create({ dashMetrics: dashMetrics }) case Constants.ABANDON_FRAGMENT_RULES.ABANDON_REQUEST_RULE: return AbandonRequestsRule(context).create({ dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, settings: settings }) } } function _arrayContainsRule(arr, ruleName) { return arr.filter((rule) =&gt; { return rule.getClassName() === ruleName }).length &gt; 0 } function _removeRuleFromArray(arr, ruleName) { return arr.filter((rule) =&gt; { return rule.getClassName() !== ruleName }) } function _getRulesWithChange(srArray) { return srArray.filter(sr =&gt; sr.representation !== SwitchRequest.NO_CHANGE); } /** * * @param {array} srArray * @return {object} SwitchRequest */ function getMinSwitchRequest(srArray) { const values = {}; let newSwitchReq = null; let i, len, currentSwitchRequest; if (srArray.length === 0) { return; } values[SwitchRequest.PRIORITY.STRONG] = null; values[SwitchRequest.PRIORITY.WEAK] = null; values[SwitchRequest.PRIORITY.DEFAULT] = null; for (i = 0, len = srArray.length; i &lt; len; i += 1) { currentSwitchRequest = srArray[i]; if (currentSwitchRequest.representation !== SwitchRequest.NO_CHANGE) { // We only use the new quality in case the bitrate is lower than the already saved one or if no new quality has been selected for the respective priority if (values[currentSwitchRequest.priority] === null || (values[currentSwitchRequest.priority].representation !== SwitchRequest.NO_CHANGE &amp;&amp; currentSwitchRequest.representation.bitrateInKbit &lt; values[currentSwitchRequest.priority].representation.bitrateInKbit)) { values[currentSwitchRequest.priority] = currentSwitchRequest; } } } if (values[SwitchRequest.PRIORITY.WEAK] &amp;&amp; values[SwitchRequest.PRIORITY.WEAK].representation !== SwitchRequest.NO_CHANGE) { newSwitchReq = values[SwitchRequest.PRIORITY.WEAK]; } if (values[SwitchRequest.PRIORITY.DEFAULT] &amp;&amp; values[SwitchRequest.PRIORITY.DEFAULT].representation !== SwitchRequest.NO_CHANGE) { newSwitchReq = values[SwitchRequest.PRIORITY.DEFAULT]; } if (values[SwitchRequest.PRIORITY.STRONG] &amp;&amp; values[SwitchRequest.PRIORITY.STRONG].representation !== SwitchRequest.NO_CHANGE) { newSwitchReq = values[SwitchRequest.PRIORITY.STRONG]; } return newSwitchReq } function getBestPossibleSwitchRequest(rulesContext) { if (!rulesContext) { return SwitchRequest(context).create() } // Only Throughput or Bola are active at the same time. const activeQualitySwitchRules = qualitySwitchRules.filter((rule) =&gt; { const ruleName = rule.getClassName(); if (ruleName !== Constants.QUALITY_SWITCH_RULES.BOLA_RULE &amp;&amp; ruleName !== Constants.QUALITY_SWITCH_RULES.THROUGHPUT_RULE) { return true } const mediaType = rulesContext.getMediaType(); return (shouldUseBolaRuleByMediaType[mediaType] &amp;&amp; ruleName === Constants.QUALITY_SWITCH_RULES.BOLA_RULE) || (!shouldUseBolaRuleByMediaType[mediaType] &amp;&amp; ruleName === Constants.QUALITY_SWITCH_RULES.THROUGHPUT_RULE) }) const switchRequestArray = activeQualitySwitchRules.map(rule =&gt; rule.getSwitchRequest(rulesContext)); const activeRules = _getRulesWithChange(switchRequestArray); const maxQuality = getMinSwitchRequest(activeRules); return maxQuality || SwitchRequest(context).create(); } function shouldAbandonFragment(rulesContext) { if (!rulesContext) { return SwitchRequest(context).create() } const abandonRequestArray = abandonFragmentRules.map(rule =&gt; rule.shouldAbandon(rulesContext)); const activeRules = _getRulesWithChange(abandonRequestArray); const shouldAbandon = getMinSwitchRequest(activeRules); if (shouldAbandon) { shouldAbandon.reason.forceAbandon = true } 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 = []; shouldUseBolaRuleByMediaType = {} eventBus.off(Events.SETTING_UPDATED_ABR_ACTIVE_RULES, _onAbrSettingsActiveRulesUpdated, instance); } function getQualitySwitchRules() { return qualitySwitchRules; } function getAbandonFragmentRules() { return abandonFragmentRules } function setBolaState(mediaType, value) { shouldUseBolaRuleByMediaType[mediaType] = value } function getBolaState(mediaType) { return shouldUseBolaRuleByMediaType[mediaType] } function _onAbrSettingsActiveRulesUpdated() { _updateRules() } instance = { getAbandonFragmentRules, getBestPossibleSwitchRequest, getBolaState, getMinSwitchRequest, getQualitySwitchRules, initialize, reset, setBolaState, shouldAbandonFragment, }; return instance; } ABRRulesCollection.__dashjs_factory_name = 'ABRRulesCollection'; const factory = FactoryMaker.getClassFactory(ABRRulesCollection); FactoryMaker.updateSingletonFactory(ABRRulesCollection.__dashjs_factory_name, factory); export default factory; × Search results Close "},"streaming_rules_abr_BolaRule.js.html":{"id":"streaming_rules_abr_BolaRule.js.html","title":"Source: streaming/rules/abr/BolaRule.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/BolaRule.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) 2016, 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. */ // For a description of the BOLA adaptive bitrate (ABR) algorithm, see http://arxiv.org/abs/1601.06748 import MetricsConstants from '../../constants/MetricsConstants.js'; import SwitchRequest from '../SwitchRequest.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; import {HTTPRequest} from '../../vo/metrics/HTTPRequest.js'; import EventBus from '../../../core/EventBus.js'; import Events from '../../../core/events/Events.js'; import Debug from '../../../core/Debug.js'; import MediaPlayerEvents from '../../MediaPlayerEvents.js'; import Constants from '../../constants/Constants.js'; import AbrController from '../../controllers/AbrController.js'; // BOLA_STATE_ONE_BITRATE : If there is only one bitrate (or initialization failed), always return NO_CHANGE. // BOLA_STATE_STARTUP : Set placeholder buffer such that we download fragments at most recently measured throughput. // BOLA_STATE_STEADY : Buffer primed, we switch to steady operation. // TODO: add BOLA_STATE_SEEK and tune BOLA behavior on seeking const BOLA_STATE_ONE_BITRATE = 'BOLA_STATE_ONE_BITRATE'; const BOLA_STATE_STARTUP = 'BOLA_STATE_STARTUP'; const BOLA_STATE_STEADY = 'BOLA_STATE_STEADY'; const MINIMUM_BUFFER_S = 10; // BOLA should never add artificial delays if buffer is less than MINIMUM_BUFFER_S. const MINIMUM_BUFFER_PER_BITRATE_LEVEL_S = 2; // E.g. if there are 5 bitrates, BOLA switches to top bitrate at buffer = 10 + 5 * 2 = 20s. // If Schedule Controller does not allow buffer to reach that level, it can be achieved through the placeholder buffer level. const PLACEHOLDER_BUFFER_DECAY = 0.99; // Make sure placeholder buffer does not stick around too long. function BolaRule(config) { config = config || {}; const context = this.context; const dashMetrics = config.dashMetrics; const mediaPlayerModel = config.mediaPlayerModel; const eventBus = EventBus(context).getInstance(); const abrController = AbrController(context).getInstance(); let instance, logger, bolaStateDict; function setup() { logger = Debug(context).getInstance().getLogger(instance); resetInitialSettings(); eventBus.on(MediaPlayerEvents.BUFFER_EMPTY, _onBufferEmpty, instance); eventBus.on(MediaPlayerEvents.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.on(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); eventBus.on(MediaPlayerEvents.QUALITY_CHANGE_REQUESTED, _onQualityChangeRequested, instance); eventBus.on(MediaPlayerEvents.FRAGMENT_LOADING_ABANDONED, _onFragmentLoadingAbandoned, instance); eventBus.on(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, instance); } /** * If we rebuffer, we don't want the placeholder buffer to artificially raise BOLA quality * @param {object} e * @private */ function _onBufferEmpty(e) { const mediaType = e.mediaType; const streamId = e.streamId; // if audio buffer runs empty (due to track switch for example) then reset placeholder buffer only for audio (to avoid decrease video BOLA quality) const stateDict = mediaType === Constants.AUDIO ? [Constants.AUDIO] : bolaStateDict[streamId]; for (const mediaType in stateDict) { if (bolaStateDict[streamId] &amp;&amp; bolaStateDict[streamId].hasOwnProperty(mediaType) &amp;&amp; bolaStateDict[streamId][mediaType].state === BOLA_STATE_STEADY) { bolaStateDict[streamId][mediaType].placeholderBuffer = 0; } } } /** * Clear BOLA parameters for each media type once we seek. By setting to BOLA_STATE_STARTUP we use the throughput to get the possible quality. * @private */ function _onPlaybackSeeking(e) { // TODO: 1. Verify what happens if we seek mid-fragment. // TODO: 2. If e.g. we have 10s fragments and seek, we might want to download the first fragment at a lower quality to restart playback quickly. const streamId = e.streamId for (const mediaType in bolaStateDict[streamId]) { if (bolaStateDict[streamId].hasOwnProperty(mediaType)) { const bolaState = bolaStateDict[streamId][mediaType]; if (bolaState.state !== BOLA_STATE_ONE_BITRATE) { bolaState.state = BOLA_STATE_STARTUP; // TODO: BOLA_STATE_SEEK? _clearBolaStateOnSeek(bolaState); } } } } /** * Handle situations in which the downloaded quality differs from what the BOLA algorithm recommended * @param 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 bolaState = bolaStateDict[e.streamId] &amp;&amp; bolaStateDict[e.streamId][e.mediaType] ? bolaStateDict[e.streamId][e.mediaType] : null; if (bolaState &amp;&amp; bolaState.state !== BOLA_STATE_ONE_BITRATE) { bolaState.lastSegmentRequestTimeMs = e.value.trequest.getTime(); bolaState.lastSegmentFinishTimeMs = e.value._tfinish.getTime(); _checkNewSegment(bolaState, e.mediaType); } } } /** * Useful to store change requests when abandoning a download. * @param e * @private */ function _onQualityChangeRequested(e) { if (e &amp;&amp; bolaStateDict[e.streamId] &amp;&amp; bolaStateDict[e.streamId][e.mediaType]) { const bolaState = bolaStateDict[e.streamId][e.mediaType]; if (bolaState &amp;&amp; bolaState.state !== BOLA_STATE_ONE_BITRATE) { bolaState.currentRepresentation = e.newRepresentation; } } } /** * * @param rulesContext * @returns {{}} * @private */ function _getInitialBolaState(rulesContext) { const initialState = {}; const mediaInfo = rulesContext.getMediaInfo(); const representations = abrController.getPossibleVoRepresentations(mediaInfo, true); const bitrates = representations.map(r =&gt; r.bandwidth); let utilities = bitrates.map(b =&gt; Math.log(b)); utilities = utilities.map(u =&gt; u - utilities[0] + 1); // normalize const bufferTimeDefault = mediaPlayerModel.getBufferTimeDefault(); const params = _calculateBolaParameters(bufferTimeDefault, representations, utilities); // only happens when there is only one bitrate level if (!params) { initialState.state = BOLA_STATE_ONE_BITRATE; } else { initialState.state = BOLA_STATE_STARTUP; initialState.representations = representations; initialState.utilities = utilities; initialState.bufferTimeDefault = bufferTimeDefault; initialState.Vp = params.Vp; initialState.gp = params.gp; initialState.currentRepresentation = null; _clearBolaStateOnSeek(initialState); } return initialState; } /** * NOTE: in live streaming, the real buffer level can drop below minimumBufferS, but bola should not stick to lowest bitrate by using a placeholder buffer level * @param bufferTimeDefault * @param representations * @param utilities * @returns {{gp: number, Vp: number}|null} * @private */ function _calculateBolaParameters(bufferTimeDefault, representations, utilities) { const highestUtilityIndex = utilities.reduce((highestIndex, u, uIndex) =&gt; (u &gt; utilities[highestIndex] ? uIndex : highestIndex), 0); // if highestUtilityIndex === 0, then always use lowest bitrate if (highestUtilityIndex === 0) { return null; } const bufferTime = Math.max(bufferTimeDefault, MINIMUM_BUFFER_S + MINIMUM_BUFFER_PER_BITRATE_LEVEL_S * representations.length); // TODO: Investigate if following can be better if utilities are not the default Math.log utilities. // If using Math.log utilities, we can choose Vp and gp to always prefer bitrates[0] at minimumBufferS and bitrates[max] at bufferTarget. // (Vp * (utility + gp) - bufferLevel) / bitrate has the maxima described when: // Vp * (utilities[0] + gp - 1) === minimumBufferS and Vp * (utilities[max] + gp - 1) === bufferTarget // giving: const gp = (utilities[highestUtilityIndex] - 1) / (bufferTime / MINIMUM_BUFFER_S - 1); const Vp = MINIMUM_BUFFER_S / gp; // note that expressions for gp and Vp assume utilities[0] === 1, which is true because of normalization return { gp: gp, Vp: Vp }; } /** * * @param bolaState * @private */ function _clearBolaStateOnSeek(bolaState) { bolaState.placeholderBuffer = 0; bolaState.mostAdvancedSegmentStart = NaN; bolaState.lastSegmentWasReplacement = false; bolaState.lastSegmentStart = NaN; bolaState.lastSegmentDurationS = NaN; bolaState.lastSegmentRequestTimeMs = NaN; bolaState.lastSegmentFinishTimeMs = NaN; } /** * If the buffer target is changed (can this happen mid-stream?), then adjust BOLA parameters accordingly. * @param bolaState * @param mediaType * @private */ function _checkBolaStateBufferTimeDefault(bolaState, mediaType) { const bufferTimeDefault = mediaPlayerModel.getBufferTimeDefault(); if (bolaState.bufferTimeDefault !== bufferTimeDefault) { const params = _calculateBolaParameters(bufferTimeDefault, bolaState.representations, bolaState.utilities); if (params.Vp !== bolaState.Vp || params.gp !== bolaState.gp) { // correct placeholder buffer using two criteria: // 1. do not change effective buffer level at effectiveBufferLevel === MINIMUM_BUFFER_S ( === Vp * gp ) // 2. scale placeholder buffer by Vp subject to offset indicated in 1. const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType); let effectiveBufferLevel = bufferLevel + bolaState.placeholderBuffer; effectiveBufferLevel -= MINIMUM_BUFFER_S; effectiveBufferLevel *= params.Vp / bolaState.Vp; effectiveBufferLevel += MINIMUM_BUFFER_S; bolaState.bufferTimeDefault = bufferTimeDefault; bolaState.Vp = params.Vp; bolaState.gp = params.gp; bolaState.placeholderBuffer = Math.max(0, effectiveBufferLevel - bufferLevel); } } } /** * The core idea of BOLA. * @param bolaState * @param bufferLevel * @returns {Representation} * @private */ function _getRepresentationFromBufferLevel(bolaState, bufferLevel) { const bitrateCount = bolaState.representations.length; let quality = NaN; let score = NaN; for (let i = 0; i &lt; bitrateCount; ++i) { let s = (bolaState.Vp * (bolaState.utilities[i] + bolaState.gp) - bufferLevel) / bolaState.representations[i].bandwidth; if (isNaN(score) || s &gt;= score) { score = s; quality = i; } } return bolaState.representations[quality]; } /** * Maximum buffer level which prefers to download at quality rather than wait * @param bolaState * @param representation * @returns {number} * @private */ function _maxBufferLevelForRepresentation(bolaState, representation) { return bolaState.Vp * (bolaState.utilities[representation.absoluteIndex] + bolaState.gp); } /** * The placeholder buffer increases the effective buffer that is used to calculate the bitrate. * There are two main reasons we might want to increase the placeholder buffer: * * 1. When a segment finishes downloading, we would expect to get a call on getSwitchRequest() regarding the quality for * the next segment. However, there might be a delay before the next call. E.g. when streaming live content, the * next segment might not be available yet. If the call to getSwitchRequest() does happens after a delay, we don't * want the delay to change the BOLA decision - we only want to factor download time to decide on bitrate level. * * 2. It is possible to get a call to getSwitchRequest() without having a segment download. The buffer target in dash.js * is different for top-quality segments and lower-quality segments. If getSwitchRequest() returns a lower-than-top * quality, then the buffer controller might decide not to download a segment. When dash.js is ready for the next * segment, getSwitchRequest() will be called again. We don't want this extra delay to factor in the bitrate decision. * @param bolaState * @param mediaType * @private */ function _updatePlaceholderBuffer(bolaState, mediaType) { const nowMs = Date.now(); if (!isNaN(bolaState.lastSegmentFinishTimeMs)) { // compensate for non-bandwidth-derived delays, e.g., live streaming availability, buffer controller const delay = 0.001 * (nowMs - bolaState.lastSegmentFinishTimeMs); bolaState.placeholderBuffer += Math.max(0, delay); } else if (!isNaN(bolaState.lastCallTimeMs)) { // no download after last call, compensate for delay between calls const delay = 0.001 * (nowMs - bolaState.lastCallTimeMs); bolaState.placeholderBuffer += Math.max(0, delay); } bolaState.lastCallTimeMs = nowMs; bolaState.lastSegmentStart = NaN; bolaState.lastSegmentRequestTimeMs = NaN; bolaState.lastSegmentFinishTimeMs = NaN; _checkBolaStateBufferTimeDefault(bolaState, mediaType); } function _onMediaFragmentLoaded(e) { if (e &amp;&amp; e.chunk &amp;&amp; e.chunk.representation.mediaInfo &amp;&amp; bolaStateDict[e.streamId]) { const bolaState = bolaStateDict[e.streamId][e.chunk.representation.mediaInfo.type]; if (bolaState &amp;&amp; bolaState.state !== BOLA_STATE_ONE_BITRATE) { const start = e.chunk.start; if (isNaN(bolaState.mostAdvancedSegmentStart) || start &gt; bolaState.mostAdvancedSegmentStart) { bolaState.mostAdvancedSegmentStart = start; bolaState.lastSegmentWasReplacement = false; } else { bolaState.lastSegmentWasReplacement = true; } bolaState.lastSegmentStart = start; bolaState.lastSegmentDurationS = e.chunk.duration; bolaState.currentRepresentation = e.chunk.representation; _checkNewSegment(bolaState, e.chunk.representation.mediaInfo.type); } } } /** * When a new segment is downloaded, we get two notifications: onMediaFragmentLoaded() and onMetricAdded(). It is * possible that the quality for the downloaded segment was lower (not higher) than the quality indicated by BOLA. * This might happen because of other rules such as the DroppedFramesRule. When this happens, we trim the * placeholder buffer to make BOLA more stable. This mechanism also avoids inflating the buffer when BOLA itself * decides not to increase the quality to avoid oscillations. * * We should also check for replacement segments (fast switching). In this case, a segment is downloaded but does * not grow the actual buffer. Fast switching might cause the buffer to deplete, causing BOLA to drop the bitrate. * We avoid this by growing the placeholder buffer. * @param bolaState * @param mediaType */ function _checkNewSegment(bolaState, mediaType) { if (!isNaN(bolaState.lastSegmentStart) &amp;&amp; !isNaN(bolaState.lastSegmentRequestTimeMs) &amp;&amp; !isNaN(bolaState.placeholderBuffer)) { bolaState.placeholderBuffer *= PLACEHOLDER_BUFFER_DECAY; // Find what maximum buffer corresponding to last segment was, and ensure placeholder is not relatively larger. if (!isNaN(bolaState.lastSegmentFinishTimeMs)) { const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType); const bufferAtLastSegmentRequest = bufferLevel + 0.001 * (bolaState.lastSegmentFinishTimeMs - bolaState.lastSegmentRequestTimeMs); // estimate const maxEffectiveBufferForLastSegment = _maxBufferLevelForRepresentation(bolaState, bolaState.currentRepresentation); const maxPlaceholderBuffer = Math.max(0, maxEffectiveBufferForLastSegment - bufferAtLastSegmentRequest); bolaState.placeholderBuffer = Math.min(maxPlaceholderBuffer, bolaState.placeholderBuffer); } // then see if we should grow placeholder buffer if (bolaState.lastSegmentWasReplacement &amp;&amp; !isNaN(bolaState.lastSegmentDurationS)) { // compensate for segments that were downloaded but did not grow the buffer bolaState.placeholderBuffer += bolaState.lastSegmentDurationS; } bolaState.lastSegmentStart = NaN; bolaState.lastSegmentRequestTimeMs = NaN; } } /** * The minimum buffer level that would cause BOLA to choose target quality rather than a lower bitrate * @param bolaState * @param representation * @returns {number} * @private */ function _minBufferLevelForRepresentation(bolaState, representation) { const absoluteIndex = representation.absoluteIndex const qBitrate = representation.bandwidth; const qUtility = bolaState.utilities[absoluteIndex]; let min = 0; // for each bitrate less than bitrates[absoluteIndex], BOLA should prefer quality (unless other bitrate has higher utility) for (let i = absoluteIndex - 1; i &gt;= 0; --i) { if (bolaState.utilities[i] &lt; bolaState.utilities[absoluteIndex]) { const iBitrate = bolaState.representations[i].bandwidth; const iUtility = bolaState.utilities[i]; const level = bolaState.Vp * (bolaState.gp + (qBitrate * iUtility - iBitrate * qUtility) / (qBitrate - iBitrate)); min = Math.max(min, level); // we want min to be small but at least level(i) for all i } } return min; } /** * * @param e * @private */ function _onFragmentLoadingAbandoned(e) { if (e &amp;&amp; bolaStateDict[e.streamId]) { const bolaState = bolaStateDict[e.streamId][e.mediaType]; if (bolaState &amp;&amp; bolaState.state !== BOLA_STATE_ONE_BITRATE) { // deflate placeholderBuffer - note that we want to be conservative when abandoning const bufferLevel = dashMetrics.getCurrentBufferLevel(e.mediaType); let wantEffectiveBufferLevel; if (bolaState.currentRepresentation.absoluteIndex &gt; 0) { // deflate to point where BOLA just chooses newQuality over newQuality-1 wantEffectiveBufferLevel = _minBufferLevelForRepresentation(bolaState, bolaState.currentRepresentation); } else { wantEffectiveBufferLevel = MINIMUM_BUFFER_S; } const maxPlaceholderBuffer = Math.max(0, wantEffectiveBufferLevel - bufferLevel); bolaState.placeholderBuffer = Math.min(bolaState.placeholderBuffer, maxPlaceholderBuffer); } } } /** * At startup we decide on the best quality based on the throughput. The placeholderBuffer is adjusted accordingly. * @param switchRequest * @param rulesContext * @param bolaState * @private */ function _handleBolaStateStartup(switchRequest, rulesContext, bolaState) { const mediaType = rulesContext.getMediaType(); const throughputController = rulesContext.getThroughputController(); const safeThroughput = throughputController.getSafeAverageThroughput(mediaType); if (isNaN(safeThroughput)) { return } const mediaInfo = rulesContext.getMediaInfo(); const representation = abrController.getOptimalRepresentationForBitrate(mediaInfo, safeThroughput, true); const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType); switchRequest.representation = representation; switchRequest.reason.throughput = safeThroughput; bolaState.placeholderBuffer = Math.max(0, _minBufferLevelForRepresentation(bolaState, representation) - bufferLevel); bolaState.currentRepresentation = representation; if (!isNaN(bolaState.lastSegmentDurationS) &amp;&amp; bufferLevel &gt;= bolaState.lastSegmentDurationS) { bolaState.state = BOLA_STATE_STEADY; } } /** * * @param switchRequest * @param rulesContext * @param bolaState * @private */ function _handleBolaStateSteady(switchRequest, rulesContext, bolaState) { const mediaType = rulesContext.getMediaType(); const throughputController = rulesContext.getThroughputController(); const mediaInfo = rulesContext.getMediaInfo(); const safeThroughput = throughputController.getSafeAverageThroughput(mediaType); const scheduleController = rulesContext.getScheduleController(); _updatePlaceholderBuffer(bolaState, mediaType); const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType); // NB: The placeholder buffer is added to bufferLevel to come up with a bitrate. // This might lead BOLA to be too optimistic and to choose a bitrate that would lead to rebuffering - // if the real buffer bufferLevel runs out, the placeholder buffer cannot prevent rebuffering. // However, the InsufficientBufferRule takes care of this scenario. let representation = _getRepresentationFromBufferLevel(bolaState, bufferLevel + bolaState.placeholderBuffer); // we want to avoid oscillations // We implement the \"BOLA-O\" variant: when network bandwidth lies between two encoded bitrate levels, stick to the lowest level. const representationForThroughput = abrController.getOptimalRepresentationForBitrate(mediaInfo, safeThroughput, true); if (representation.absoluteIndex &gt; bolaState.currentRepresentation.absoluteIndex &amp;&amp; representation.absoluteIndex &gt; representationForThroughput.absoluteIndex) { // only intervene if we are trying to *increase* quality to an *unsustainable* level // we are only avoid oscillations - do not drop below last quality representation = representationForThroughput.absoluteIndex &gt; bolaState.currentRepresentation.absoluteIndex ? representationForThroughput : bolaState.currentRepresentation; } // We do not want to overfill buffer with low quality chunks. // Note that there will be no delay if buffer level is below MINIMUM_BUFFER_S, probably even with some margin higher than MINIMUM_BUFFER_S. let delayS = Math.max(0, bufferLevel + bolaState.placeholderBuffer - _maxBufferLevelForRepresentation(bolaState, representation)); // First reduce placeholder buffer, then tell schedule controller to pause. if (delayS &lt;= bolaState.placeholderBuffer) { bolaState.placeholderBuffer -= delayS; delayS = 0; } else { delayS -= bolaState.placeholderBuffer; bolaState.placeholderBuffer = 0; if (!abrController.isPlayingAtTopQuality(representation)) { // At top quality, allow schedule controller to decide how far to fill buffer. scheduleController.setTimeToLoadDelay(1000 * delayS); } else { delayS = 0; } } switchRequest.representation = representation; switchRequest.reason.throughput = safeThroughput; switchRequest.reason.bufferLevel = bufferLevel; switchRequest.reason.placeholderBuffer = bolaState.placeholderBuffer; switchRequest.reason.delay = delayS; bolaState.currentRepresentation = representation; } /** * Bad state we should not have arrived here. Try to recover. * @param switchRequest * @param rulesContext * @param bolaState */ function _handleBolaStateBad(switchRequest, rulesContext, bolaState) { logger.debug('BOLA ABR rule invoked in bad state.'); const mediaInfo = rulesContext.getMediaInfo(); const mediaType = rulesContext.getMediaType(); const throughputController = rulesContext.getThroughputController(); const safeThroughput = throughputController.getSafeAverageThroughput(mediaType); switchRequest.representation = abrController.getOptimalRepresentationForBitrate(mediaInfo, safeThroughput, true); switchRequest.reason.state = bolaState.state; switchRequest.reason.throughput = safeThroughput; bolaState.state = BOLA_STATE_STARTUP; _clearBolaStateOnSeek(bolaState); } function getSwitchRequest(rulesContext) { try { const switchRequest = SwitchRequest(context).create(); const scheduleController = rulesContext.getScheduleController(); scheduleController.setTimeToLoadDelay(0); switchRequest.rule = this.getClassName(); switchRequest.reason = switchRequest.reason || {}; const bolaState = _getBolaState(rulesContext); switchRequest.reason.state = bolaState.state; switch (bolaState.state) { case BOLA_STATE_ONE_BITRATE: break; case BOLA_STATE_STARTUP: _handleBolaStateStartup(switchRequest, rulesContext, bolaState); break; case BOLA_STATE_STEADY: _handleBolaStateSteady(switchRequest, rulesContext, bolaState) break; default: _handleBolaStateBad(switchRequest, rulesContext, bolaState) break; } return switchRequest; } catch (e) { logger.error(e); return SwitchRequest(context).create(); } } function _getBolaState(rulesContext) { const mediaType = rulesContext.getMediaType(); const streamId = rulesContext.getStreamInfo().id; if (!bolaStateDict[streamId]) { bolaStateDict[streamId] = {}; } let bolaState = bolaStateDict[streamId][mediaType]; if (!bolaState) { bolaState = _getInitialBolaState(rulesContext); bolaStateDict[streamId][mediaType] = bolaState; } else if (bolaState.state !== BOLA_STATE_ONE_BITRATE) { _checkBolaStateBufferTimeDefault(bolaState, mediaType); } return bolaState; } function resetInitialSettings() { bolaStateDict = {}; } function reset() { resetInitialSettings(); eventBus.off(MediaPlayerEvents.BUFFER_EMPTY, _onBufferEmpty, instance); eventBus.off(MediaPlayerEvents.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); eventBus.off(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); eventBus.off(MediaPlayerEvents.QUALITY_CHANGE_REQUESTED, _onQualityChangeRequested, instance); eventBus.off(MediaPlayerEvents.FRAGMENT_LOADING_ABANDONED, _onFragmentLoadingAbandoned, instance); eventBus.off(Events.MEDIA_FRAGMENT_LOADED, _onMediaFragmentLoaded, instance); } instance = { getSwitchRequest, reset }; setup(); return instance; } BolaRule.__dashjs_factory_name = 'BolaRule'; export default FactoryMaker.getClassFactory(BolaRule); × 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import IsoFile from './IsoFile.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import ISOBoxer from 'codem-isoboxer'; import IsoBoxSearchInfo from '../vo/IsoBoxSearchInfo.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import MetricsConstants from '../constants/MetricsConstants.js'; import FragmentModel from '../models/FragmentModel.js'; import SourceBufferSink from '../SourceBufferSink.js'; import PreBufferSink from '../PreBufferSink.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Debug from '../../core/Debug.js'; import InitCache from '../utils/InitCache.js'; import DashJSError from '../vo/DashJSError.js'; import Errors from '../../core/errors/Errors.js'; import {HTTPRequest} from '../vo/metrics/HTTPRequest.js'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js'; 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 textController = config.textController; 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, dischargeBuffer, isPrebuffering, dischargeFragments, 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 * @param {object} mediaInfo */ function setMediaSource(value, mediaInfo = null) { return new Promise((resolve, reject) =&gt; { mediaSource = value; // if we have a prebuffer, we should prepare to discharge it, and make a new sourceBuffer ready if (sourceBufferSink &amp;&amp; mediaInfo &amp;&amp; typeof sourceBufferSink.discharge === 'function') { dischargeBuffer = sourceBufferSink; createBufferSink(mediaInfo) .then(() =&gt; { resolve(); }) .catch((e) =&gt; { reject(e); }) } else { resolve(); } }) } /** * Creates a SourceBufferSink object * @param {object} mediaInfo * @param {array} oldBufferSinks * @return {Promise&lt;Object&gt;} SourceBufferSink */ function createBufferSink(mediaInfo, oldBufferSinks = []) { return new Promise((resolve, reject) =&gt; { if (!initCache || !mediaInfo) { resolve(null); return; } if (mediaSource) { isPrebuffering = false; _initializeSinkForMseBuffering(mediaInfo, oldBufferSinks) .then((sink) =&gt; { resolve(sink); }) .catch((e) =&gt; { reject(e); }) } else { isPrebuffering = true; _initializeSinkForPrebuffering() .then((sink) =&gt; { resolve(sink); }) .catch((e) =&gt; { reject(e); }) } }); } function _initializeSinkForPrebuffering() { return new Promise((resolve, reject) =&gt; { sourceBufferSink = PreBufferSink(context).create(_onAppended.bind(this)); updateBufferTimestampOffset(representationController.getCurrentRepresentation()) .then(() =&gt; { resolve(sourceBufferSink); }) .catch(() =&gt; { reject(); }) }) } function _initializeSinkForMseBuffering(mediaInfo, oldBufferSinks) { return new Promise((resolve, reject) =&gt; { sourceBufferSink = SourceBufferSink(context).create({ mediaSource, textController, eventBus }); _initializeSink(mediaInfo, oldBufferSinks) .then(() =&gt; { return updateBufferTimestampOffset(representationController.getCurrentRepresentation()); }) .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) { const selectedVoRepresentation = representationController.getCurrentRepresentation(); if (oldBufferSinks &amp;&amp; oldBufferSinks[type] &amp;&amp; (type === Constants.VIDEO || type === Constants.AUDIO)) { return sourceBufferSink.initializeForStreamSwitch(mediaInfo, selectedVoRepresentation, oldBufferSinks[type]); } else { return sourceBufferSink.initializeForFirstUse(streamInfo, mediaInfo, selectedVoRepresentation); } } function dischargePreBuffer() { if (sourceBufferSink &amp;&amp; dischargeBuffer &amp;&amp; typeof dischargeBuffer.discharge === 'function') { const ranges = dischargeBuffer.getAllBufferRanges(); if (ranges.length &gt; 0) { let rangeStr = 'Beginning ' + type + 'PreBuffer discharge, adding buffer for:'; for (let i = 0; i &lt; ranges.length; i++) { rangeStr += ' start: ' + ranges.start(i) + ', end: ' + ranges.end(i) + ';'; } logger.debug(rangeStr); } else { logger.debug('PreBuffer discharge requested, but there were no media segments in the PreBuffer.'); } //A list of fragments to supress bytesAppended events for. This makes transferring from a prebuffer to a sourcebuffer silent. dischargeFragments = []; let chunks = dischargeBuffer.discharge(); let lastInit = null; for (let j = 0; j &lt; chunks.length; j++) { const chunk = chunks[j]; if (chunk.segmentType !== HTTPRequest.INIT_SEGMENT_TYPE) { const initChunk = initCache.extract(chunk.streamId, chunk.representation.id); if (initChunk) { if (lastInit !== initChunk) { dischargeFragments.push(initChunk); sourceBufferSink.append(initChunk); lastInit = initChunk; } } } dischargeFragments.push(chunk); sourceBufferSink.append(chunk); } dischargeBuffer.reset(); dischargeBuffer = null; } } /** * 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.representation.id, ' 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.representation.id, ' 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 * @param {object} request * @private */ function _appendToBuffer(chunk, request = null) { sourceBufferSink.append(chunk, request) .then((e) =&gt; { _onAppended(e); }) .catch((e) =&gt; { _onAppended(e); }); if (chunk.representation.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(); } let suppressAppendedEvent = false; if (dischargeFragments) { if (dischargeFragments.indexOf(appendedBytesInfo) &gt; 0) { suppressAppendedEvent = true; } dischargeFragments = null; } if (appendedBytesInfo &amp;&amp; !suppressAppendedEvent) { _triggerEvent(Events.BYTES_APPENDED_END_FRAGMENT, { startTime: appendedBytesInfo.start, index: appendedBytesInfo.index, bufferedRanges: ranges, segmentType: appendedBytesInfo.segmentType, mediaType: type, representationId: appendedBytesInfo.representation.id }); } } /** * 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) || isPrebuffering) 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); } } function prepareForPlaybackSeek() { if (isBufferingCompleted) { setIsBufferingCompleted(false); } // Abort the current request and empty all possible segments to be appended return sourceBufferSink.abort(); } function prepareForForceReplacementQualitySwitch(voRepresentation) { return new Promise((resolve, reject) =&gt; { sourceBufferSink.abort() .then(() =&gt; { return updateAppendWindow(); }) .then(() =&gt; { return pruneAllSafely(); }) .then(() =&gt; { // In any case we need to update the MSE.timeOffset return updateBufferTimestampOffset(voRepresentation) }) .then(() =&gt; { setIsBufferingCompleted(false); resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function prepareForReplacementTrackSwitch(representation) { return new Promise((resolve, reject) =&gt; { sourceBufferSink.abort() .then(() =&gt; { return updateAppendWindow(); }) .then(() =&gt; { if (settings.get().streaming.buffer.useChangeTypeForTrackSwitch) { return sourceBufferSink.changeType(representation); } return Promise.resolve(); }) .then(() =&gt; { return pruneAllSafely(); }) .then(() =&gt; { setIsBufferingCompleted(false); resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function prepareForNonReplacementTrackSwitch(selectedRepresentation) { return new Promise((resolve, reject) =&gt; { updateAppendWindow() .then(() =&gt; { if (settings.get().streaming.buffer.useChangeTypeForTrackSwitch) { return sourceBufferSink.changeType(selectedRepresentation); } return Promise.resolve(); }) .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 // we keep everything that is within bufferToKeepAhead but only if the buffer is continuous. // Otherwise we have gaps once the seek is done which might trigger an unintentional gap jump const endOfBuffer = ranges.end(ranges.length - 1) + BUFFER_END_THRESHOLD; const continuousBufferTime = getContinuousBufferTimeForTargetTime(targetTime); // This is the maximum range we keep ahead const isLongFormContent = streamInfo.manifestInfo.duration &gt;= settings.get().streaming.buffer.longFormContentDurationThreshold; const bufferToKeepAhead = isLongFormContent ? settings.get().streaming.buffer.bufferTimeAtTopQualityLongForm : settings.get().streaming.buffer.bufferTimeAtTopQuality; // Define the start time from which we will prune. If there is no continuous range from the targettime we start immediately at the target time // Otherwise we set the start point to the end of the continuous range taking the maximum buffer to keep ahead into account let rangeStart = !isNaN(continuousBufferTime) ? Math.min(continuousBufferTime, targetTime + bufferToKeepAhead) : targetTime; // Check if we are done buffering, no need to prune then if (rangeStart &gt;= ranges.end(ranges.length - 1)) { return null } // 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; ranges.end(ranges.length - 1)) { 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 hasBufferAtTime(time) { try { const ranges = sourceBufferSink.getAllBufferRanges(); if (!ranges || ranges.length === 0) { return false; } let i = 0; while (i &lt; ranges.length) { const start = ranges.start(i); const end = ranges.end(i); if (time &gt;= start &amp;&amp; time &lt;= end) { return true; } i += 1; } return false } catch (e) { logger.error(e); return false; } } 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) { let referenceTime = playbackController.getTime() || 0; // In case we are prebuffering we dont have a current time yet if (isPrebuffering) { referenceTime = !isNaN(seekTarget) ? seekTarget : 0; } 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(referenceTime, 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); if (!sourceBufferSink) { return; } 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(voRepresentation) { return new Promise((resolve) =&gt; { if (!voRepresentation || voRepresentation.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(voRepresentation.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) { 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; isPrebuffering = false; 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 = { appendInitSegmentFromCache, clearBuffers, createBufferSink, dischargePreBuffer, getAllRangesWithSafetyFactor, getBuffer, getBufferControllerType, getBufferLevel, getContinuousBufferTimeForTargetTime, getIsBufferingCompleted, getIsPruningInProgress, getMediaSource, getRangeAt, getStreamId, getType, hasBufferAtTime, initialize, prepareForForceReplacementQualitySwitch, prepareForNonReplacementTrackSwitch, prepareForPlaybackSeek, prepareForReplacementTrackSwitch, pruneAllSafely, pruneBuffer, reset, segmentRequestingCompleted, setIsBufferingCompleted, setMediaSource, setSeekTarget, updateAppendWindow, updateBufferTimestampOffset, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import {THUMBNAILS_SCHEME_ID_URIS} from '../thumbnail/ThumbnailTracks.js'; import Constants from '../constants/Constants.js'; 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; } } function isProtectionCompatible(previousStream, newStream) { if (!newStream) { return true; } return _compareProtectionConfig(Constants.VIDEO, previousStream, newStream) &amp;&amp; _compareProtectionConfig(Constants.AUDIO, previousStream, newStream); } function _compareProtectionConfig(type, previousStream, newStream) { const previousMediaInfo = previousStream.getCurrentMediaInfoForType(type); const newMediaInfo = newStream.getCurrentMediaInfoForType(type); if (!previousMediaInfo || !newMediaInfo) { return true; } // If the current period is unencrypted and the upcoming one is encrypted we need to reset sourcebuffers. return !(!previousMediaInfo.hasProtectedRepresentations &amp;&amp; newMediaInfo.hasProtectedRepresentations); } /** * 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; } } instance = { isProtectionCompatible, setConfig, setEncryptedMediaSupported, supportsCodec, supportsEncryptedMedia, supportsEssentialProperty, supportsMediaSource, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Debug from '../../core/Debug.js'; import EventBus from '../../core/EventBus.js'; import Constants from '../constants/Constants.js'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; import Events from '../../core/events/Events.js'; import MetricsConstants from '../constants/MetricsConstants.js'; import Utils from '../../core/Utils.js'; 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(); _checkPlaybackRates(); } 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); eventBus.on(Events.SETTING_UPDATED_PLAYBACK_RATE_MIN, _checkPlaybackRates, instance); eventBus.on(Events.SETTING_UPDATED_PLAYBACK_RATE_MAX, _checkPlaybackRates, instance); eventBus.on(MediaPlayerEvents.STREAM_INITIALIZED, _checkPlaybackRates, 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, _onPlaybackSeeked, instance); eventBus.off(Events.SETTING_UPDATED_CATCHUP_ENABLED, _onCatchupSettingUpdated, instance); eventBus.off(Events.SETTING_UPDATED_PLAYBACK_RATE_MIN, _checkPlaybackRates, instance); eventBus.off(Events.SETTING_UPDATED_PLAYBACK_RATE_MAX, _checkPlaybackRates, instance); eventBus.off(MediaPlayerEvents.STREAM_INITIALIZED, _checkPlaybackRates, 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.getCatchupPlaybackRates().max &gt; 0) || (mediaPlayerModel.getCatchupPlaybackRates().min &lt; 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 liveCatchupPlaybackRates = mediaPlayerModel.getCatchupPlaybackRates(); 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(liveCatchupPlaybackRates, currentLiveLatency, targetLiveDelay, playbackBufferMin, bufferLevel); } else { // Default playback control: Based on target and current latency newRate = _calculateNewPlaybackRateDefault(liveCatchupPlaybackRates, currentLiveLatency, targetLiveDelay, bufferLevel); } // 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 / liveCatchupPlaybackRates.max); // 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 {object} liveCatchUpPlaybackRates * @param {number} liveCatchUpPlaybackRates.min - minimum playback rate decrease limit * @param {number} liveCatchUpPlaybackRates.max - maximum playback rate increase limit * @param {number} currentLiveLatency * @param {number} liveDelay * @param {number} bufferLevel * @param {number} currentPlaybackRate * @return {number} * @private */ function _calculateNewPlaybackRateDefault(liveCatchUpPlaybackRates, 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 deltaLatency = currentLiveLatency - liveDelay; const cpr = (deltaLatency &lt; 0) ? Math.abs(liveCatchUpPlaybackRates.min) : liveCatchUpPlaybackRates.max; 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 {object} liveCatchUpPlaybackRates * @param {number} liveCatchUpPlaybackRates.min - minimum playback rate decrease limit * @param {number} liveCatchUpPlaybackRates.max - maximum playback rate increase limit * @param {number} currentLiveLatency * @param {number} liveDelay * @param {number} playbackBufferMin * @param {number} bufferLevel * @param {number} currentPlaybackRate * @return {number} * @private */ function _calculateNewPlaybackRateLolP(liveCatchUpPlaybackRates, currentLiveLatency, liveDelay, playbackBufferMin, bufferLevel) { let newRate; // Hybrid: Buffer-based if (bufferLevel &lt; playbackBufferMin) { // Buffer in danger, slow down const cpr = Math.abs(liveCatchUpPlaybackRates.min); // Absolute value as negative delta value will be used. 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 const cpr = liveCatchUpPlaybackRates.max; // 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 } function _checkPlaybackRates() { mediaPlayerModel.getCatchupPlaybackRates(true); } 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 */ export default { /** * @constant {string} STREAM Stream media type. Mainly used to report metrics relative to the full stream * @memberof Constants# * @static */ STREAM: 'stream', /** * @constant {string} VIDEO Video media type * @memberof Constants# * @static */ VIDEO: 'video', /** * @constant {string} AUDIO Audio media type * @memberof Constants# * @static */ AUDIO: 'audio', /** * @constant {string} TEXT Text media type * @memberof Constants# * @static */ TEXT: 'text', /** * @constant {string} MUXED Muxed (video/audio in the same chunk) media type * @memberof Constants# * @static */ MUXED: 'muxed', /** * @constant {string} IMAGE Image media type * @memberof Constants# * @static */ IMAGE: 'image', /** * @constant {string} STPP STTP Subtitles format * @memberof Constants# * @static */ STPP: 'stpp', /** * @constant {string} TTML STTP Subtitles format * @memberof Constants# * @static */ TTML: 'ttml', /** * @constant {string} VTT STTP Subtitles format * @memberof Constants# * @static */ VTT: 'vtt', /** * @constant {string} WVTT STTP Subtitles format * @memberof Constants# * @static */ WVTT: 'wvtt', /** * @constant {string} Content Steering * @memberof Constants# * @static */ CONTENT_STEERING: 'contentSteering', /** * @constant {string} LIVE_CATCHUP_MODE_DEFAULT Throughput calculation based on moof parsing * @memberof Constants# * @static */ LIVE_CATCHUP_MODE_DEFAULT: 'liveCatchupModeDefault', /** * @constant {string} LIVE_CATCHUP_MODE_LOLP Throughput calculation based on moof parsing * @memberof Constants# * @static */ LIVE_CATCHUP_MODE_LOLP: 'liveCatchupModeLoLP', /** * @constant {string} MOVING_AVERAGE_SLIDING_WINDOW Moving average sliding window * @memberof Constants# * @static */ MOVING_AVERAGE_SLIDING_WINDOW: 'slidingWindow', /** * @constant {string} EWMA Exponential moving average * @memberof Constants# * @static */ MOVING_AVERAGE_EWMA: 'ewma', /** * @constant {string} BAD_ARGUMENT_ERROR Invalid Arguments type of error * @memberof Constants# * @static */ BAD_ARGUMENT_ERROR: 'Invalid Arguments', /** * @constant {string} MISSING_CONFIG_ERROR Missing configuration parameters type of error * @memberof Constants# * @static */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY: 'highestSelectionPriority', /** * @constant {string} CMCD_MODE_QUERY specifies to attach CMCD metrics as query parameters. * @memberof Constants# * @static */ CMCD_MODE_QUERY: 'query', /** * @constant {string} CMCD_MODE_HEADER specifies to attach CMCD metrics as HTTP headers. * @memberof Constants# * @static */ CMCD_MODE_HEADER: 'header', INITIALIZE: 'initialize', TEXT_SHOWING: 'showing', TEXT_HIDDEN: 'hidden', ACCESSIBILITY_CEA608_SCHEME: 'urn:scte:dash:cc:cea-608:2015', CC1: 'CC1', CC3: 'CC3', UTF8: 'utf-8', SCHEME_ID_URI: 'schemeIdUri', START_TIME: 'starttime', SERVICE_DESCRIPTION_DVB_LL_SCHEME: 'urn:dvb:dash:lowlatency:scope:2019', SUPPLEMENTAL_PROPERTY_DVB_LL_SCHEME: 'urn:dvb:dash:lowlatency:critical:2019', XML: 'XML', ARRAY_BUFFER: 'ArrayBuffer', DVB_REPORTING_URL: 'dvb:reportingUrl', DVB_PROBABILITY: 'dvb:probability', VIDEO_ELEMENT_READY_STATES: { HAVE_NOTHING: 0, HAVE_METADATA: 1, HAVE_CURRENT_DATA: 2, HAVE_FUTURE_DATA: 3, HAVE_ENOUGH_DATA: 4 }, FILE_LOADER_TYPES: { FETCH: 'fetch_loader', XHR: 'xhr_loader' }, THROUGHPUT_TYPES: { LATENCY: 'throughput_type_latency', BANDWIDTH: 'throughput_type_bandwidth' }, THROUGHPUT_CALCULATION_MODES: { EWMA: 'throughputCalculationModeEwma', ZLEMA: 'throughputCalculationModeZlema', ARITHMETIC_MEAN: 'throughputCalculationModeArithmeticMean', BYTE_SIZE_WEIGHTED_ARITHMETIC_MEAN: 'throughputCalculationModeByteSizeWeightedArithmeticMean', DATE_WEIGHTED_ARITHMETIC_MEAN: 'throughputCalculationModeDateWeightedArithmeticMean', HARMONIC_MEAN: 'throughputCalculationModeHarmonicMean', BYTE_SIZE_WEIGHTED_HARMONIC_MEAN: 'throughputCalculationModeByteSizeWeightedHarmonicMean', DATE_WEIGHTED_HARMONIC_MEAN: 'throughputCalculationModeDateWeightedHarmonicMean', }, LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE: { MOOF_PARSING: 'lowLatencyDownloadTimeCalculationModeMoofParsing', DOWNLOADED_DATA: 'lowLatencyDownloadTimeCalculationModeDownloadedData', AAST: 'lowLatencyDownloadTimeCalculationModeAast', }, RULES_TYPES: { QUALITY_SWITCH_RULES: 'qualitySwitchRules', ABANDON_FRAGMENT_RULES: 'abandonFragmentRules' }, QUALITY_SWITCH_RULES: { BOLA_RULE: 'BolaRule', THROUGHPUT_RULE: 'ThroughputRule', INSUFFICIENT_BUFFER_RULE: 'InsufficientBufferRule', SWITCH_HISTORY_RULE: 'SwitchHistoryRule', DROPPED_FRAMES_RULE: 'DroppedFramesRule', LEARN_TO_ADAPT_RULE: 'L2ARule', LOL_PLUS_RULE: 'LoLPRule' }, ABANDON_FRAGMENT_RULES: { ABANDON_REQUEST_RULE: 'AbandonRequestsRule' } } × Search results Close "},"dash_controllers_ContentSteeringController.js.html":{"id":"dash_controllers_ContentSteeringController.js.html","title":"Source: dash/controllers/ContentSteeringController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/ContentSteeringController.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.js'; import Debug from '../../core/Debug.js'; import URLLoader from '../../streaming/net/URLLoader.js'; import Errors from '../../core/errors/Errors.js'; import ContentSteeringRequest from '../vo/ContentSteeringRequest.js'; import ContentSteeringResponse from '../vo/ContentSteeringResponse.js'; import DashConstants from '../constants/DashConstants.js'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js'; import URLUtils from '../../streaming/utils/URLUtils.js'; import BaseURL from '../vo/BaseURL.js'; import MpdLocation from '../vo/MpdLocation.js'; import Utils from '../../core/Utils.js'; const QUERY_PARAMETER_KEYS = { THROUGHPUT: '_DASH_throughput', PATHWAY: '_DASH_pathway', URL: 'url' }; const THROUGHPUT_SAMPLES = 4; function ContentSteeringController() { const context = this.context; const urlUtils = URLUtils(context).getInstance(); let instance, logger, currentSteeringResponseData, serviceLocationList, throughputList, nextRequestTimer, urlLoader, errHandler, dashMetrics, mediaPlayerModel, manifestModel, serviceDescriptionController, throughputController, eventBus, adapter; function setup() { logger = Debug(context).getInstance().getLogger(instance); _resetInitialSettings(); } function setConfig(config) { if (!config) return; if (config.adapter) { adapter = config.adapter; } if (config.errHandler) { errHandler = config.errHandler; } if (config.dashMetrics) { dashMetrics = config.dashMetrics; } if (config.mediaPlayerModel) { mediaPlayerModel = config.mediaPlayerModel; } if (config.manifestModel) { manifestModel = config.manifestModel; } if (config.serviceDescriptionController) { serviceDescriptionController = config.serviceDescriptionController; } if (config.throughputController) { throughputController = config.throughputController; } if (config.eventBus) { eventBus = config.eventBus; } } /** * Initialize the steering controller by instantiating classes and registering observer callback */ function initialize() { urlLoader = URLLoader(context).create({ errHandler, dashMetrics, mediaPlayerModel, errors: Errors }); eventBus.on(MediaPlayerEvents.FRAGMENT_LOADING_STARTED, _onFragmentLoadingStarted, instance); eventBus.on(MediaPlayerEvents.MANIFEST_LOADING_STARTED, _onManifestLoadingStarted, instance); eventBus.on(MediaPlayerEvents.THROUGHPUT_MEASUREMENT_STORED, _onThroughputMeasurementStored, instance); } /** * When loading of a fragment starts we store its serviceLocation in our list * @param {object} e * @private */ function _onFragmentLoadingStarted(e) { _addToServiceLocationList(e, 'baseUrl'); } /** * When loading of a manifest starts we store its serviceLocation in our list * @param {object} e * @private */ function _onManifestLoadingStarted(e) { _addToServiceLocationList(e, 'location') } /** * When a throughput measurement was stored in ThroughputModel we save it * @param {object} e * @private */ function _onThroughputMeasurementStored(e) { if (!e || !e.throughputValues || !e.throughputValues.serviceLocation) { return; } _storeThroughputForServiceLocation(e.throughputValues.serviceLocation, e.throughputValues); } /** * Helper function to store a throughput value from the corresponding serviceLocation * @param {string} serviceLocation * @param {number} throughput * @private */ function _storeThroughputForServiceLocation(serviceLocation, throughput) { if (!throughputList[serviceLocation]) { throughputList[serviceLocation] = []; } throughputList[serviceLocation].push(throughput) if (throughputList[serviceLocation].length &gt; THROUGHPUT_SAMPLES) { throughputList[serviceLocation].shift(); } } /** * Adds a new service location entry to our list * @param {object} e * @param {string} type * @private */ function _addToServiceLocationList(e, type) { if (e &amp;&amp; e.request &amp;&amp; e.request.serviceLocation) { const serviceLocation = e.request.serviceLocation; if (serviceLocationList[type].all.indexOf(serviceLocation) === -1) { serviceLocationList[type].all.push(serviceLocation) } serviceLocationList[type].current = serviceLocation; } } /** * Query DashAdapter and Service Description Controller to get the steering information defined in the manifest * @returns {object} */ function getSteeringDataFromManifest() { const manifest = manifestModel.getValue() let contentSteeringData = adapter.getContentSteering(manifest); if (!contentSteeringData) { contentSteeringData = serviceDescriptionController.getServiceDescriptionSettings().contentSteering; } return contentSteeringData; } /** * Should query steering server prior to playback start * @returns {boolean} */ function shouldQueryBeforeStart() { const steeringDataFromManifest = getSteeringDataFromManifest(); return !!steeringDataFromManifest &amp;&amp; steeringDataFromManifest.queryBeforeStart; } /** * Load the steering data from the steering server * @returns {Promise} */ function loadSteeringData() { return new Promise((resolve) =&gt; { try { const steeringDataFromManifest = getSteeringDataFromManifest(); if (!steeringDataFromManifest || !steeringDataFromManifest.serverUrl) { resolve(); return; } const url = _getSteeringServerUrl(steeringDataFromManifest); const request = new ContentSteeringRequest(url); urlLoader.load({ request: request, success: (data) =&gt; { _handleSteeringResponse(data); eventBus.trigger(MediaPlayerEvents.CONTENT_STEERING_REQUEST_COMPLETED, { currentSteeringResponseData, url }); resolve(); }, error: (e, error, statusText, response) =&gt; { _handleSteeringResponseError(e, response); resolve(e); }, complete: () =&gt; { // Clear everything except for the current entry serviceLocationList.baseUrl.all = _getClearedServiceLocationListAfterSteeringRequest(serviceLocationList.baseUrl); serviceLocationList.location.all = _getClearedServiceLocationListAfterSteeringRequest(serviceLocationList.location); } }); } catch (e) { resolve(e); } }) } /** * Return the cleared data of our serviceLocationList after the steering request was completed * @param {object} data * @returns {Object[]} * @private */ function _getClearedServiceLocationListAfterSteeringRequest(data) { if (!data.all || data.all.length === 0 || !data.current) { return []; } return data.all.filter((entry) =&gt; { return entry === data.current; }) } /** * Returns the adjusted steering server url enhanced by pathway and throughput parameter * @param {object} steeringDataFromManifest * @returns {string} * @private */ function _getSteeringServerUrl(steeringDataFromManifest) { let url = steeringDataFromManifest.serverUrl; if (currentSteeringResponseData &amp;&amp; currentSteeringResponseData.reloadUri) { if (urlUtils.isRelative(currentSteeringResponseData.reloadUri)) { url = urlUtils.resolve(currentSteeringResponseData.reloadUri, steeringDataFromManifest.serverUrl); } else { url = currentSteeringResponseData.reloadUri; } } const additionalQueryParameter = []; const serviceLocations = serviceLocationList.baseUrl.all.concat(serviceLocationList.location.all); if (serviceLocations.length &gt; 0) { // Derive throughput for each service Location const data = serviceLocations.map((serviceLocation) =&gt; { const throughput = _calculateThroughputForServiceLocation(serviceLocation); return { serviceLocation, throughput } }) // Sort in descending order to put all elements without throughput (-1) in the end data.sort((a, b) =&gt; { return b.throughput - a.throughput }) let pathwayString = ''; let throughputString = ''; data.forEach((entry, index) =&gt; { if (index !== 0) { pathwayString = `${pathwayString},`; if (entry.throughput &gt; -1) { throughputString = `${throughputString},`; } } pathwayString = `${pathwayString}${entry.serviceLocation}`; if (entry.throughput &gt; -1) { throughputString = `${throughputString}${entry.throughput}`; } }) additionalQueryParameter.push({ key: QUERY_PARAMETER_KEYS.PATHWAY, value: `\"${pathwayString}\"` }); additionalQueryParameter.push({ key: QUERY_PARAMETER_KEYS.THROUGHPUT, value: throughputString }); } url = Utils.addAditionalQueryParameterToUrl(url, additionalQueryParameter); return url; } /** * Calculate the arithmetic mean of the last throughput samples * @param {string} serviceLocation * @returns {number} * @private */ function _calculateThroughputForServiceLocation(serviceLocation) { if (!serviceLocation || !throughputList[serviceLocation] || throughputList[serviceLocation].length === 0) { return -1; } const throughput = throughputController.getArithmeticMean(throughputList[serviceLocation], throughputList[serviceLocation].length, true); return parseInt(throughput * 1000); } /** * Parse the steering response and create instance of model ContentSteeringResponse * @param {object} data * @private */ function _handleSteeringResponse(data) { if (!data || !data[DashConstants.CONTENT_STEERING_RESPONSE.VERSION] || parseInt(data[DashConstants.CONTENT_STEERING_RESPONSE.VERSION]) !== 1) { return; } // Update the data for other classes to use currentSteeringResponseData = new ContentSteeringResponse(); currentSteeringResponseData.version = data[DashConstants.CONTENT_STEERING_RESPONSE.VERSION]; if (data[DashConstants.CONTENT_STEERING_RESPONSE.TTL] &amp;&amp; !isNaN(data[DashConstants.CONTENT_STEERING_RESPONSE.TTL])) { currentSteeringResponseData.ttl = data[DashConstants.CONTENT_STEERING_RESPONSE.TTL]; } if (data[DashConstants.CONTENT_STEERING_RESPONSE.RELOAD_URI]) { currentSteeringResponseData.reloadUri = data[DashConstants.CONTENT_STEERING_RESPONSE.RELOAD_URI] } if (data[DashConstants.CONTENT_STEERING_RESPONSE.PATHWAY_PRIORITY]) { currentSteeringResponseData.pathwayPriority = data[DashConstants.CONTENT_STEERING_RESPONSE.PATHWAY_PRIORITY] } if (data[DashConstants.CONTENT_STEERING_RESPONSE.PATHWAY_CLONES]) { currentSteeringResponseData.pathwayClones = data[DashConstants.CONTENT_STEERING_RESPONSE.PATHWAY_CLONES] currentSteeringResponseData.pathwayClones = currentSteeringResponseData.pathwayClones.filter((pathwayClone) =&gt; { return _isValidPathwayClone(pathwayClone); }) } _startSteeringRequestTimer(); } /** * Checks if object is a valid PathwayClone * @param {object} pathwayClone * @returns {boolean} * @private */ function _isValidPathwayClone(pathwayClone) { return pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.BASE_ID] &amp;&amp; pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.ID] &amp;&amp; pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.URI_REPLACEMENT] &amp;&amp; pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.URI_REPLACEMENT][DashConstants.CONTENT_STEERING_RESPONSE.HOST] } /** * Returns synthesized BaseURL elements based on Pathway Cloning * @param {BaseURL[]}referenceElements * @returns {BaseURL[]} */ function getSynthesizedBaseUrlElements(referenceElements) { try { const synthesizedElements = _getSynthesizedElements(referenceElements); return synthesizedElements.map((element) =&gt; { const synthesizedBaseUrl = new BaseURL(element.synthesizedUrl, element.serviceLocation) synthesizedBaseUrl.queryParams = element.queryParams; synthesizedBaseUrl.dvb_priority = element.reference.dvb_priority; synthesizedBaseUrl.dvb_weight = element.reference.dvb_weight; synthesizedBaseUrl.availabilityTimeOffset = element.reference.availabilityTimeOffset; synthesizedBaseUrl.availabilityTimeComplete = element.reference.availabilityTimeComplete; return synthesizedBaseUrl; }) } catch (e) { logger.error(e); return []; } } /** * Returns synthesized Location elements based on Pathway Cloning * @param {MpdLocation[]} referenceElements * @returns {MpdLocation[]} */ function getSynthesizedLocationElements(referenceElements) { try { const synthesizedElements = _getSynthesizedElements(referenceElements); return synthesizedElements.map((element) =&gt; { const synthesizedLocation = new MpdLocation(element.synthesizedUrl, element.serviceLocation) synthesizedLocation.queryParams = element.queryParams; return synthesizedLocation; }) } catch (e) { logger.error(e); return []; } } /** * Helper function to synthesize elements * @param {array} referenceElements * @returns {array} * @private */ function _getSynthesizedElements(referenceElements) { try { const synthesizedElements = []; if (!referenceElements || referenceElements.length === 0 || !currentSteeringResponseData || !currentSteeringResponseData.pathwayClones || currentSteeringResponseData.pathwayClones.length === 0) { return synthesizedElements; } currentSteeringResponseData.pathwayClones.forEach((pathwayClone) =&gt; { let baseElements = referenceElements.filter((source) =&gt; { return pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.BASE_ID] === source.serviceLocation; }) let reference = null; if (baseElements &amp;&amp; baseElements.length &gt; 0) { reference = baseElements[0]; } if (reference) { const referenceUrl = new URL(reference.url); let host = pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.URI_REPLACEMENT][DashConstants.CONTENT_STEERING_RESPONSE.HOST]; host = Utils.stringHasProtocol(host) ? host : `${referenceUrl.protocol}//${host}`; const synthesizedElement = { synthesizedUrl: `${host}${referenceUrl.pathname}`, serviceLocation: pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.ID], queryParams: pathwayClone[DashConstants.CONTENT_STEERING_RESPONSE.URI_REPLACEMENT][DashConstants.CONTENT_STEERING_RESPONSE.PARAMS], reference }; synthesizedElements.push(synthesizedElement); } }); return synthesizedElements; } catch (e) { logger.error(e); return []; } } /** * Start timeout for next steering request * @private */ function _startSteeringRequestTimer() { // Start timer for next request if (currentSteeringResponseData &amp;&amp; currentSteeringResponseData.ttl &amp;&amp; !isNaN(currentSteeringResponseData.ttl)) { if (nextRequestTimer) { clearTimeout(nextRequestTimer); } nextRequestTimer = setTimeout(() =&gt; { loadSteeringData(); }, currentSteeringResponseData.ttl * 1000); } } /** * Stop timeout for next steering request */ function stopSteeringRequestTimer() { if (nextRequestTimer) { clearTimeout(nextRequestTimer); } nextRequestTimer = null; } /** * Handle errors that occured when querying the steering server * @param {object} e * @param {object} response * @private */ function _handleSteeringResponseError(e, response) { try { logger.warn(`Error fetching data from content steering server`, e); const statusCode = response.status; switch (statusCode) { // 410 response code. Stop steering case 410: break; // 429 Too Many Requests. Replace existing TTL value with Retry-After header if present case 429: const retryAfter = response &amp;&amp; response.getResponseHeader ? response.getResponseHeader('retry-after') : null; if (retryAfter !== null) { if (!currentSteeringResponseData) { currentSteeringResponseData = {}; } currentSteeringResponseData.ttl = parseInt(retryAfter); } _startSteeringRequestTimer(); break; default: _startSteeringRequestTimer(); break; } } catch (e) { logger.error(e); } } /** * Returns the currentSteeringResponseData * @returns {ContentSteeringResponse} */ function getCurrentSteeringResponseData() { return currentSteeringResponseData; } function reset() { _resetInitialSettings(); eventBus.off(MediaPlayerEvents.FRAGMENT_LOADING_STARTED, _onFragmentLoadingStarted, instance); eventBus.off(MediaPlayerEvents.MANIFEST_LOADING_STARTED, _onManifestLoadingStarted, instance); eventBus.off(MediaPlayerEvents.THROUGHPUT_MEASUREMENT_STORED, _onThroughputMeasurementStored, instance); } function _resetInitialSettings() { currentSteeringResponseData = null; throughputList = {}; serviceLocationList = { baseUrl: { current: null, all: [] }, location: { current: null, all: [] } }; stopSteeringRequestTimer() } instance = { reset, setConfig, loadSteeringData, getCurrentSteeringResponseData, shouldQueryBeforeStart, getSteeringDataFromManifest, stopSteeringRequestTimer, getSynthesizedBaseUrlElements, getSynthesizedLocationElements, initialize }; setup(); return instance; } ContentSteeringController.__dashjs_factory_name = 'ContentSteeringController'; export default FactoryMaker.getSingletonFactory(ContentSteeringController); × 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Settings from '../../core/Settings.js'; import {checkParameterType} from '../utils/SupervisorTools.js'; import Constants from '../constants/Constants.js'; const DEFAULT_XHR_WITH_CREDENTIALS = false; function CustomParametersModel() { let instance, utcTimingSources, xhrWithCredentials, requestInterceptors, responseInterceptors, 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() { requestInterceptors = []; responseInterceptors = []; 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 !== Constants.RULES_TYPES.ABANDON_FRAGMENT_RULES &amp;&amp; type !== Constants.RULES_TYPES.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; } /** * Adds a request interceptor. This enables application to monitor, manipulate, overwrite any request parameter and/or request data. * The provided callback function shall return a promise with updated request that shall be resolved once the process of the request is completed. * The interceptors are applied in the order they are added. * @param {function} interceptor - the request interceptor callback */ function addRequestInterceptor(interceptor) { requestInterceptors.push(interceptor); } /** * Adds a response interceptor. This enables application to monitor, manipulate, overwrite the response data * The provided callback function shall return a promise with updated response that shall be resolved once the process of the response is completed. * The interceptors are applied in the order they are added. * @param {function} interceptor - the response interceptor callback */ function addResponseInterceptor(interceptor) { responseInterceptors.push(interceptor); } /** * Unregisters a request interceptor. * @param {function} interceptor - the request interceptor callback */ function removeRequestInterceptor(interceptor) { _unregisterFilter(requestInterceptors, interceptor); } /** * Unregisters a response interceptor. * @param {function} interceptor - the request interceptor callback */ function removeResponseInterceptor(interceptor) { _unregisterFilter(responseInterceptors, interceptor); } /** * Returns all request interceptors * @return {array} */ function getRequestInterceptors() { return requestInterceptors; } /** * Returns all response interceptors * @return {array} */ function getResponseInterceptors() { return responseInterceptors; } /** * 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, addRequestInterceptor, addResponseInterceptor, removeRequestInterceptor, removeResponseInterceptor, getRequestInterceptors, getResponseInterceptors, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest.js'; import FactoryMaker from '../core/FactoryMaker.js'; import MediaPlayerEvents from '../streaming/MediaPlayerEvents.js'; import { replaceIDForTemplate, replaceTokenForTemplate, unescapeDollarsInTemplate } from './utils/SegmentsUtils.js'; import DashConstants from './constants/DashConstants.js'; const DEFAULT_ADJUST_SEEK_TIME_THRESHOLD = 0.5; const SEGMENT_START_TIME_DELTA = 0.001; 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, queryParams = {}; if (!baseURL || (destination === baseURL.url) || (!urlUtils.isRelative(destination))) { url = destination; } else { url = baseURL.url; serviceLocation = baseURL.serviceLocation; queryParams = baseURL.queryParams; if (destination) { url = urlUtils.resolve(destination, url); } } if (urlUtils.isRelative(url)) { return false; } request.url = url; request.serviceLocation = serviceLocation; request.queryParams = queryParams; 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.representation = representation; 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.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.bandwidth = representation.bandwidth; 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.index = segment.index; request.adaptationIndex = representation.adaptation.index; request.representation = representation; 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) { if (!representation || !representation.segmentInfoType) { return null; } let indexToRequest = lastSegment ? lastSegment.index + 1 : 0; return _getRequest(mediaInfo, representation, indexToRequest); } function repeatSegmentRequest(mediaInfo, representation) { if (!representation || !representation.segmentInfoType) { return null; } let indexToRequest = lastSegment ? lastSegment.index : 0; return _getRequest(mediaInfo, representation, indexToRequest); } function _getRequest(mediaInfo, representation, indexToRequest) { let request = null; 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 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 * @return {number} */ 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; } // If we have a duration look until the end of the duration, otherwise maximum 30 seconds const end = isFinite(representation.adaptation.period.duration) ? 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) { // Apply delta to segment start time to get around rounding issues return targetRequest.startTime + SEGMENT_START_TIME_DELTA; } 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 = { getCurrentIndex, getInitRequest, getNextSegmentRequest, getNextSegmentRequestIdempotent, getSegmentRequestForTime, getStreamId, getStreamInfo, getType, getValidTimeAheadOfTargetTime, initialize, isLastSegmentRequested, repeatSegmentRequest, reset, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * 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, there is * not enough data, or if the value exceeds the maximum safe integer value * @memberof EBMLParser */ function getMatroskaUint(size) { if (size &gt; 4) { return getMatroskaUintLarge(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 &gt;&gt;&gt; 0; } /** * 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, there is * not enough data, or if the value exceeds the maximum safe integer value */ function getMatroskaUintLarge(size) { const limit = Math.floor(Number.MAX_SAFE_INTEGER / 256); let val = 0; for (let i = 0; i &lt; size; i += 1) { if (val &gt; limit) { throw new Error('Value exceeds safe integer limit'); } val *= 256; const n = data.getUint8(pos + i); if (val &gt; Number.MAX_SAFE_INTEGER - n) { throw new Error('Value exceeds safe integer limit'); } val += n; } 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Debug from '../../core/Debug.js'; import EventBus from '../../core/EventBus.js'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js'; import XHRLoader from '../net/XHRLoader.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FragmentRequest from '../vo/FragmentRequest.js'; 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 req1.representation.id === req2.representation.id; }; 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(); } instance = { abortRequests, executeRequest, getRequests, getStreamId, getType, isFragmentLoaded, isFragmentLoadedOrPending, removeExecutedRequestsAfterTime, removeExecutedRequestsBeforeTime, reset, resetInitialSettings, syncExecutedRequestsWithBufferedRange, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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_HttpLoaderRequest.js.html":{"id":"streaming_vo_HttpLoaderRequest.js.html","title":"Source: streaming/vo/HttpLoaderRequest.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/HttpLoaderRequest.js class HttpLoaderRequest { constructor(params) { /** * Request URL */ this.url = params.url; /** * HTTP Request method, e.g. GET */ this.method = params.method; /** * Indicates whether cross-site Access-Control requests should be made */ this.withCredentials = params.withCredentials; /** * The request object e.g an instance of FragmentRequest */ this.request = params.request; /** * Callback function */ this.onload = params.onload; /** * Callback function */ this.onloadend = params.onloadend; /** * Callback function */ this.onerror = params.onerror; /** * Callback function */ this.progress = params.progress; /** * Callback function */ this.ontimeout = params.ontimeout; /** * Instance of the loader either Fetch or XHR */ this.loader = params.loader; /** * Timeout in ms */ this.timeout = params.timeout; /** * Additional headers */ this.headers = params.headers; /** * Save the response here * @type {{}} */ this.response = {}; /** * An instance of reader to be used for the reading the Response object when using the FetchAPI. See : https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/getReader */ this.reader = null; } } export default HttpLoaderRequest × 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 = []; /** * The CMSD static and dynamic values retrieved from CMSD response headers. * @public */ this.cmsd = null; /** * 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; /** * The values derived from the ResourceTimingAPI. */ this._resourceTimingValues = 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 */ import localforage from 'localforage'; import {XmlEntities as entities} from 'html-entities'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Events from '../../../core/events/Events.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; import Debug from '../../../core/Debug.js'; import SwitchRequest from '../SwitchRequest.js'; import Constants from '../../constants/Constants.js'; import MetricsConstants from '../../constants/MetricsConstants.js'; import MediaPlayerEvents from '../../MediaPlayerEvents.js'; import Settings from '../../../core/Settings.js'; function InsufficientBufferRule(config) { config = config || {}; const context = this.context; const eventBus = EventBus(context).getInstance(); const dashMetrics = config.dashMetrics; const settings = Settings(context).getInstance(); 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); } /** * 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 getSwitchRequest(rulesContext) { const switchRequest = SwitchRequest(context).create(); switchRequest.rule = this.getClassName(); if (!rulesContext || !rulesContext.hasOwnProperty('getMediaType')) { return switchRequest; } const mediaType = rulesContext.getMediaType(); const currentBufferState = dashMetrics.getCurrentBufferState(mediaType); const voRepresentation = rulesContext.getRepresentation(); const fragmentDuration = voRepresentation.fragmentDuration; const scheduleController = rulesContext.getScheduleController(); const playbackController = scheduleController.getPlaybackController(); if (!_shouldExecuteRule(playbackController, mediaType, fragmentDuration)) { return switchRequest; } const mediaInfo = rulesContext.getMediaInfo(); const abrController = rulesContext.getAbrController(); if (currentBufferState &amp;&amp; currentBufferState.state === MetricsConstants.BUFFER_EMPTY) { logger.debug('[' + mediaType + '] Switch to index 0; buffer is empty.'); switchRequest.representation = abrController.getOptimalRepresentationForBitrate(mediaInfo, 0, true); switchRequest.reason = { message: '[InsufficientBufferRule]: Switching to lowest Representation because buffer is empty' }; } else { const throughputController = rulesContext.getThroughputController(); const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType); const throughput = throughputController.getAverageThroughput(mediaType, null, NaN); const safeThroughput = throughput * settings.get().streaming.abr.rules.insufficientBufferRule.parameters.throughputSafetyFactor; const bitrate = safeThroughput * bufferLevel / fragmentDuration switchRequest.representation = abrController.getOptimalRepresentationForBitrate(mediaInfo, bitrate, true); switchRequest.reason = { message: '[InsufficientBufferRule]: Limiting maximum bitrate to avoid a buffer underrun.', bitrate }; } return switchRequest; } function _shouldExecuteRule(playbackController, mediaType, fragmentDuration) { const lowLatencyEnabled = playbackController.getLowLatencyModeEnabled(); return !lowLatencyEnabled &amp;&amp; bufferStateDict[mediaType].ignoreCount &lt;= 0 &amp;&amp; fragmentDuration; } function _resetInitialSettings() { const segmentIgnoreCount = settings.get().streaming.abr.rules.insufficientBufferRule.parameters.segmentIgnoreCount bufferStateDict = {}; bufferStateDict[Constants.VIDEO] = { ignoreCount: segmentIgnoreCount }; bufferStateDict[Constants.AUDIO] = { ignoreCount: segmentIgnoreCount }; } 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 = { getSwitchRequest, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import ClearKeyKeySet from '../vo/ClearKeyKeySet.js'; import CommonEncryption from '../CommonEncryption.js'; import ProtectionConstants from '../../constants/ProtectionConstants.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import ClearKeyKeySet from '../vo/ClearKeyKeySet.js'; import CommonEncryption from '../CommonEncryption.js'; import ProtectionConstants from '../../constants/ProtectionConstants.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import ProtectionConstants from '../../constants/ProtectionConstants.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import SwitchRequest from '../SwitchRequest.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; import {HTTPRequest} from '../../vo/metrics/HTTPRequest.js'; import EventBus from '../../../core/EventBus.js'; import Events from '../../../core/events/Events.js'; import Debug from '../../../core/Debug.js'; import Constants from '../../constants/Constants.js'; const L2A_STATE_ONE_BITRATE = 'L2A_STATE_ONE_BITRATE'; // If there is only one bitrate (or initialization failed), always return NO_CHANGE. const L2A_STATE_STARTUP = 'L2A_STATE_STARTUP'; // Set placeholder buffer such that we download fragments at most recently measured throughput. const L2A_STATE_STEADY = 'L2A_STATE_STEADY'; // Buffer primed, we switch to steady operation. 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 REACT = 2; 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); } /** * 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(); initialState.state = L2A_STATE_STARTUP; initialState.currentRepresentation = null; _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; l2AState.lastSegmentUrl = ''; } /** * 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.representation &amp;&amp; e.chunk.representation.mediaInfo) { const l2AState = l2AStateDict[e.chunk.representation.mediaInfo.type]; const l2AParameters = l2AParameterDict[e.chunk.representation.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.currentRepresentation = e.chunk.representation; _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; } } /** * 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; } /** * * @param rulesContext * @param switchRequest * @param l2AState * @private */ function _handleStartupState(rulesContext, switchRequest, l2AState) { const mediaInfo = rulesContext.getMediaInfo(); const mediaType = rulesContext.getMediaType(); const throughputController = rulesContext.getThroughputController(); const safeThroughput = throughputController.getSafeAverageThroughput(mediaType); if (isNaN(safeThroughput)) { // still starting up - not enough information return switchRequest; } const abrController = rulesContext.getAbrController(); const representation = abrController.getOptimalRepresentationForBitrate(mediaInfo, safeThroughput, true);//During strat-up phase abr.controller is responsible for bitrate decisions. const bufferLevel = dashMetrics.getCurrentBufferLevel(mediaType, true); const l2AParameter = l2AParameterDict[mediaType]; const possibleRepresentations = abrController.getPossibleVoRepresentations(mediaInfo, true); switchRequest.representation = representation; switchRequest.reason.throughput = safeThroughput; l2AState.currentRepresentation = representation; 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; possibleRepresentations.length; ++i) { const rep = possibleRepresentations[i]; if (rep.id === l2AState.currentRepresentation.id) { l2AParameter.prev_w[i] = 1; } else { l2AParameter.prev_w[i] = 0; } } } } function _handleSteadyState(rulesContext, switchRequest, l2AState) { let diff1 = []; //Used to calculate the difference between consecutive decisions (w-w_prev) const throughputController = rulesContext.getThroughputController(); const mediaType = rulesContext.getMediaType(); let lastThroughput = throughputController.getAverageThroughput(mediaType, Constants.THROUGHPUT_CALCULATION_MODES.ARITHMETIC_MEAN, 1); let currentHttpRequest = dashMetrics.getCurrentHttpRequest(mediaType); let selectedRepresentation = null; const l2AParameter = l2AParameterDict[mediaType]; //To avoid division with 0 (avoid infinity) in case of an absolute network outage if (lastThroughput &lt; 1) { lastThroughput = 1; } // Note that for SegmentBase addressing the request url does not change. // As this is not relevant for low latency streaming at this point the check below is sufficient if (currentHttpRequest.url === l2AState.lastSegmentUrl || currentHttpRequest.type === HTTPRequest.INIT_SEGMENT_TYPE) { // No change to inputs or init segment so use previously calculated quality selectedRepresentation = l2AState.currentRepresentation; } else { // Recalculate Q let V = l2AState.lastSegmentDurationS; let sign = 1; //Main adaptation logic of L2A-LL const abrController = rulesContext.getAbrController(); const mediaInfo = rulesContext.getMediaInfo(); const possibleRepresentations = abrController.getPossibleVoRepresentations(mediaInfo, true); const videoModel = rulesContext.getVideoModel(); let currentPlaybackRate = videoModel.getPlaybackRate(); const alpha = Math.max(Math.pow(HORIZON, 1), VL * Math.sqrt(HORIZON));// Step size, used for gradient descent exploration granularity for (let i = 0; i &lt; possibleRepresentations.length; ++i) { const rep = possibleRepresentations[i]; // In this case buffer would deplete, leading to a stall, which increases latency and thus the particular probability of selection of bitrate[i] should be decreased. if (currentPlaybackRate * rep.bitrateInKbit &gt; lastThroughput) { 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 * rep.bitrateInKbit / 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; possibleRepresentations.length; ++i) { diff1[i] = l2AParameter.w[i] - l2AParameter.prev_w[i]; l2AParameter.prev_w[i] = l2AParameter.w[i]; } // Lagrangian multiplier Q calculation: const bitrates = possibleRepresentations.map((rep) =&gt; { return rep.bandwidth; }) 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; bitrates.length; ++i) { temp[i] = Math.abs(bitrates[i] - _dotmultiplication(l2AParameter.w, bitrates)); } // Quality is calculated based on the probability distribution w (the output of L2A) const absoluteIndex = temp.indexOf(Math.min(...temp)); selectedRepresentation = abrController.getRepresentationByAbsoluteIndex(absoluteIndex, mediaInfo, true); // We employ a cautious -stepwise- ascent if (selectedRepresentation.absoluteIndex &gt; l2AState.currentRepresentation.absoluteIndex) { if (bitrates[l2AState.currentRepresentation.absoluteIndex + 1] &lt;= lastThroughput) { selectedRepresentation = abrController.getRepresentationByAbsoluteIndex(l2AState.currentRepresentation.absoluteIndex + 1, mediaInfo, true); } } // Provision against bitrate over-estimation, by re-calibrating the Lagrangian multiplier Q, to be taken into account for the next chunk if (selectedRepresentation.bitrateInKbit &gt;= lastThroughput) { l2AParameter.Q = REACT * Math.max(VL, l2AParameter.Q); } l2AState.lastSegmentUrl = currentHttpRequest.url; } switchRequest.representation = selectedRepresentation; l2AState.currentRepresentation = switchRequest.representation; } function _handleErrorState(rulesContext, switchRequest, l2AState) { const abrController = rulesContext.getAbrController(); const mediaInfo = rulesContext.getMediaInfo(); const mediaType = rulesContext.getMediaType(); const throughputController = rulesContext.getThroughputController(); const safeThroughput = throughputController.getSafeAverageThroughput(mediaType); switchRequest.representation = abrController.getOptimalRepresentationForBitrate(mediaInfo, safeThroughput, true);//During strat-up phase abr.controller is responsible for bitrate decisions. switchRequest.reason.throughput = safeThroughput; l2AState.state = L2A_STATE_STARTUP; _clearL2AStateOnSeek(l2AState); } /** * Returns a switch request object indicating which quality is to be played * @param {object} rulesContext * @return {object} */ function getSwitchRequest(rulesContext) { try { const switchRequest = SwitchRequest(context).create(); switchRequest.rule = this.getClassName(); const mediaType = rulesContext.getMediaType(); const scheduleController = rulesContext.getScheduleController(); switchRequest.reason = switchRequest.reason || {}; // L2A decides bitrate only for video. Audio to be included in decision process in a later stage if ((mediaType === Constants.AUDIO)) { return switchRequest; } scheduleController.setTimeToLoadDelay(0); const l2AState = _getL2AState(rulesContext); const l2AParameter = l2AParameterDict[mediaType]; if (!l2AParameter) { return switchRequest; } switchRequest.reason.state = l2AState.state; switch (l2AState.state) { case L2A_STATE_ONE_BITRATE: break; case L2A_STATE_STARTUP: _handleStartupState(rulesContext, switchRequest, l2AState); break; case L2A_STATE_STEADY: _handleSteadyState(rulesContext, switchRequest, l2AState); break; default: _handleErrorState(rulesContext, switchRequest, l2AState) } return switchRequest; } catch (e) { logger.error(e); return SwitchRequest(context).create(); } } /** * 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); } instance = { getSwitchRequest, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Debug from '../../../../core/Debug.js'; 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, x) { for (let i = 0; i &lt; somBitrateNeurons.length; i++) { let somNeuron = somBitrateNeurons[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.representation.bandwidth &lt; currentNeuron.representation.bandwidth &amp;&amp; n.representation.bandwidth &gt; maxSuitableBitrate &amp;&amp; currentThroughput &gt; n.representation.bandwidth) { // possible downshiftable neuron maxSuitableBitrate = n.representation.bandwidth; result = n; } } } return result; } /** * * @param {object} abrController * @param {object} mediaInfo * @param {number} throughput * @param {number} latency * @param {number} currentBufferLevel * @param {number} playbackRate * @param {object} currentRepresentation * @param {object} dynamicWeightsSelector * @return {null|*} */ function getNextQuality(abrController, mediaInfo, throughput, latency, currentBufferLevel, playbackRate, currentRepresentation, dynamicWeightsSelector) { // For Dynamic Weights Selector let currentLatency = latency; let currentThroughput = throughput; _setSomBitrateNeurons(mediaInfo, abrController); // 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; // 10K + video encoding is the recommended throughput const throughputDelta = 10000; let currentNeuron = somBitrateNeurons.find(entry =&gt; entry.representation.id === currentRepresentation.id); let downloadTime = (currentNeuron.representation.bandwidth * dynamicWeightsSelector.getSegmentDuration()) / currentThroughput; let rebuffer = Math.max(0, (downloadTime - currentBufferLevel)); // check buffer for possible stall if (currentBufferLevel - downloadTime &lt; dynamicWeightsSelector.getMinBuffer()) { logger.debug(`Buffer is low for bitrate= ${currentNeuron.representation.bandwidth} downloadTime=${downloadTime} currentBuffer=${currentBufferLevel} rebuffer=${rebuffer}`); return _getDownShiftNeuron(currentNeuron, currentThroughput).representation; } switch (weightSelectionMode) { case WEIGHT_SELECTION_MODES.MANUAL: _manualWeightSelection(); break; case WEIGHT_SELECTION_MODES.RANDOM: _randomWeightSelection(); break; case WEIGHT_SELECTION_MODES.DYNAMIC: _dynamicWeightSelection(dynamicWeightsSelector, currentLatency, currentBufferLevel, rebuffer, currentThroughput, playbackRate); break; default: _dynamicWeightSelection(dynamicWeightsSelector, currentLatency, currentBufferLevel, rebuffer, currentThroughput, playbackRate); } let minDistance = null; let targetRepresentation = null; let winnerNeuron = null; for (let i = 0; i &lt; somBitrateNeurons.length; i++) { let somNeuron = somBitrateNeurons[i]; let somNeuronState = somNeuron.state; let somData = [somNeuronState.throughput, somNeuronState.latency, somNeuronState.rebuffer, somNeuronState.switch]; let distanceWeights = weights.slice(); let nextBuffer = dynamicWeightsSelector.getNextBufferWithBitrate(somNeuron.representation.bandwidth, currentBufferLevel, currentThroughput); let isBufferLow = nextBuffer &lt; dynamicWeightsSelector.getMinBuffer(); if (isBufferLow) { logger.debug(`Buffer is low for bitrate=${somNeuron.representation.bandwidth} downloadTime=${downloadTime} currentBuffer=${currentBufferLevel} nextBuffer=${nextBuffer}`); } // special condition downshift immediately if (somNeuron.representation.bandwidth &gt; throughput - throughputDelta || isBufferLow) { if (somNeuron.representation.bandwidth !== minBitrate) { // encourage to pick smaller bitrates throughputWeight=100 distanceWeights[0] = 100; } } // calculate the distance with the target let distance = _getDistance(somData, [throughputNormalized, targetLatency, targetRebufferLevel, 0], distanceWeights); if (minDistance === null || distance &lt; minDistance) { minDistance = distance; targetRepresentation = somNeuron.representation; 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.representation.bandwidth - winnerNeuron.representation.bandwidth) / bitrateNormalizationFactor; _updateNeurons(currentNeuron, [throughputNormalized, latency, rebuffer, bitrateSwitch]); // update bmu and neighbours with targetQoE=1, targetLatency=0 _updateNeurons(winnerNeuron, [throughputNormalized, targetLatency, targetRebufferLevel, bitrateSwitch]); return targetRepresentation; } /** * 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 * @private */ function _randomWeightSelection() { weights = _getXavierWeights(somBitrateNeurons.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, currentLatency, currentBuffer, rebuffer, currentThroughput, playbackRate) { if (!weights) { weights = sortedCenters[sortedCenters.length - 1]; } // Dynamic Weights Selector (step 2/2: find weights) let weightVector = dynamicWeightsSelector.findWeightVector(somBitrateNeurons, 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 * @param abrController * @return {array} * @private */ function _setSomBitrateNeurons(mediaInfo, abrController) { if (!somBitrateNeurons) { somBitrateNeurons = []; const possibleRepresentations = abrController.getPossibleVoRepresentations(mediaInfo, true); const bitrateList = possibleRepresentations.map((r) =&gt; r.bandwidth); minBitrate = Math.min(...bitrateList); bitrateNormalizationFactor = _getMagnitude(bitrateList); possibleRepresentations.forEach((rep) =&gt; { let neuron = { representation: rep, state: { // normalize throughputs throughput: rep.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} somBitrateNeurons * @return {array} * @private */ function _getInitialKmeansPlusPlusCenters(somBitrateNeurons) { let centers = []; let randomDataSet = _getRandomData(Math.pow(somBitrateNeurons.length, 2)); centers.push(randomDataSet[0]); let distanceWeights = [1, 1, 1, 1]; for (let k = 1; k &lt; somBitrateNeurons.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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 response * * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 "},"streaming_utils_LocationSelector.js.html":{"id":"streaming_utils_LocationSelector.js.html","title":"Source: streaming/utils/LocationSelector.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/LocationSelector.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) 2023, 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 Events from '../../core/events/Events.js'; import BlacklistController from '../controllers/BlacklistController.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Settings from '../../core/Settings.js'; import ContentSteeringController from '../../dash/controllers/ContentSteeringController.js'; function LocationSelector() { const context = this.context; const settings = Settings(context).getInstance(); let instance, blacklistController, contentSteeringController; function setup() { blacklistController = BlacklistController(context).create({ updateEventName: Events.SERVICE_LOCATION_LOCATION_BLACKLIST_CHANGED, addBlacklistEventName: Events.SERVICE_LOCATION_LOCATION_BLACKLIST_ADD }); contentSteeringController = ContentSteeringController(context).getInstance(); } function setConfig(config) { if (config.blacklistController) { blacklistController = config.blacklistController; } if (config.contentSteeringController) { contentSteeringController = config.contentSteeringController; } } /** * * @param {MpdLocation[]} mpdLocations * @returns {*} */ function select(mpdLocations) { if (!mpdLocations || mpdLocations.length === 0) { return null; } let mpdLocation = null; if (settings.get().streaming.applyContentSteering) { mpdLocation = _selectByContentSteering(mpdLocations) } if (!mpdLocation) { mpdLocation = _selectByDefault(mpdLocations); } return mpdLocation; } function _selectByContentSteering(mpdLocations) { // Search in the response data of the steering server const currentSteeringResponseData = contentSteeringController.getCurrentSteeringResponseData(); if (currentSteeringResponseData &amp;&amp; currentSteeringResponseData.pathwayPriority &amp;&amp; currentSteeringResponseData.pathwayPriority.length &gt; 0) { return _findMpdLocation(currentSteeringResponseData.pathwayPriority, mpdLocations); } return null; } function _findMpdLocation(pathwayPriority = [], mpdLocations = []) { let i = 0; let target = null; while (i &lt; pathwayPriority.length) { const curr = pathwayPriority[i]; const idx = mpdLocations.findIndex((elem) =&gt; { return elem.serviceLocation &amp;&amp; elem.serviceLocation === curr; }) if (idx !== -1 &amp;&amp; !blacklistController.contains(mpdLocations[idx].serviceLocation)) { target = mpdLocations[idx] break; } i += 1; } return target; } function _selectByDefault(mpdLocations) { return mpdLocations[0]; } function reset() { blacklistController.reset(); } instance = { select, setConfig, reset }; setup(); return instance; } LocationSelector.__dashjs_factory_name = 'LocationSelector'; export default FactoryMaker.getClassFactory(LocationSelector); × Search results Close "},"core_Logger.js.html":{"id":"core_Logger.js.html","title":"Source: core/Logger.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FactoryMaker from '../../../../core/FactoryMaker.js'; import LearningAbrController from './LearningAbrController.js'; import LoLpQoeEvaluator from './LoLpQoEEvaluator.js'; import SwitchRequest from '../../SwitchRequest.js'; import MetricsConstants from '../../../constants/MetricsConstants.js'; import LoLpWeightSelector from './LoLpWeightSelector.js'; import Constants from '../../../constants/Constants.js'; 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 getSwitchRequest(rulesContext) { try { let switchRequest = SwitchRequest(context).create(); switchRequest.rule = this.getClassName(); let mediaType = rulesContext.getMediaInfo().type; let abrController = rulesContext.getAbrController(); const streamInfo = rulesContext.getStreamInfo(); let currentRepresentation = rulesContext.getRepresentation(); const mediaInfo = rulesContext.getMediaInfo(); const bufferStateVO = dashMetrics.getCurrentBufferState(mediaType); const scheduleController = rulesContext.getScheduleController(); const currentBufferLevel = dashMetrics.getCurrentBufferLevel(mediaType, true); const playbackController = scheduleController.getPlaybackController(); let latency = playbackController.getCurrentLiveLatency(); if ((mediaType === Constants.AUDIO)) { return switchRequest; } if (!latency) { latency = 0; } const playbackRate = playbackController.getPlaybackRate(); const throughputController = rulesContext.getThroughputController(); const throughput = throughputController.getSafeAverageThroughput(mediaType); 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 const possibleRepresentations = abrController.getPossibleVoRepresentations(mediaInfo, true); let bandwidths = possibleRepresentations.map(r =&gt; r.bandwidth); let segmentDuration = rulesContext.getRepresentation().fragmentDuration; let minBitrateKbps = Math.min(...bandwidths) / 1000.0; // min bitrate level let maxBitrateKbps = Math.max(...bandwidths) / 1000.0; // max bitrate level // Learning rule pre-calculations let currentBitrate = currentRepresentation.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.representation = learningController.getNextQuality( abrController, mediaInfo, throughput * 1000, latency, currentBufferLevel, playbackRate, currentRepresentation, dynamicWeightsSelector ); switchRequest.reason = { throughput: throughput, latency: latency }; switchRequest.priority = SwitchRequest.PRIORITY.STRONG; scheduleController.setTimeToLoadDelay(0); 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 = { getSwitchRequest, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; 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 {number|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.representation.bandwidth * 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.representation.bandwidth, weightedRebuffer, weightedLatency, playbackRate); if ((maxQoE === null || totalQoE &gt; maxQoE) &amp;&amp; _checkConstraints(currentLatency, nextBuffer, deltaLatency)) { maxQoE = totalQoE; winnerWeights = weightVector; winnerBitrate = neuron.representation.bandwidth; } }); }); // 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_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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ManifestUpdateRepresentationInfo 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; /** * Holds reference to @presentationTimeOffset * @public */ this.presentationTimeOffset = null; /** * Holds reference to @startNumber * @public */ this.startNumber = 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Events from '../../core/events/Events.js'; import EventBus from '../../core/EventBus.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Debug from '../../core/Debug.js'; import {bcp47Normalize} from 'bcp-47-normalize'; import {extendedFilter} from 'bcp-47-match'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; function MediaController() { const context = this.context; const eventBus = EventBus(context).getInstance(); let instance, logger, tracks, settings, initialSettings, lastSelectedTracks, lastSelectedRepresentations, customParametersModel, mediaPlayerModel, videoModel, domStorage; function setup() { logger = Debug(context).getInstance().getLogger(instance); reset(); } function setConfig(config) { if (!config) return; if (config.domStorage) { domStorage = config.domStorage; } if (config.settings) { settings = config.settings; } if (config.customParametersModel) { customParametersModel = config.customParametersModel; } if (config.mediaPlayerModel) { mediaPlayerModel = config.mediaPlayerModel; } if (config.videoModel) { videoModel = config.videoModel; } } function initialize() { _registerEvents(); } function _registerEvents() { eventBus.on(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitched, instance); } function _unRegisterEvents() { eventBus.off(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitched, instance); } /** * Save the last selected bitrate for each media type. In case we transition to a new period and have multiple AdaptationSets that we can choose * from we choose the one with a bitrate closest to the current one. * @param e * @private */ function _onRepresentationSwitched(e) { if (!e || !e.currentRepresentation || !e.currentRepresentation.mediaInfo || !e.currentRepresentation.mediaInfo.type) { return } const type = e.currentRepresentation.mediaInfo.type; lastSelectedRepresentations[type] = e.currentRepresentation; } /** * @param {string} type * @param {StreamInfo} streamInfo * @memberof MediaController# */ function setInitialMediaSettingsForType(type, streamInfo) { let settings = lastSelectedTracks[type] || getInitialSettings(type); const possibleTracks = getTracksFor(type, streamInfo.id); let filteredTracks = []; if (!settings) { settings = domStorage.getSavedMediaSettings(type); setInitialSettings(type, settings); } if (!possibleTracks || (possibleTracks.length === 0)) return; if (settings) { filteredTracks = Array.from(possibleTracks); logger.info('Filtering ' + filteredTracks.length + ' ' + type + ' tracks based on settings'); filteredTracks = filterTracksBySettings(filteredTracks, matchSettingsLang, settings); filteredTracks = filterTracksBySettings(filteredTracks, matchSettingsIndex, settings); filteredTracks = filterTracksBySettings(filteredTracks, matchSettingsViewPoint, settings); if (!(type === Constants.AUDIO &amp;&amp; !!lastSelectedTracks[type])) { filteredTracks = filterTracksBySettings(filteredTracks, matchSettingsRole, settings); } filteredTracks = filterTracksBySettings(filteredTracks, matchSettingsAccessibility, settings); filteredTracks = filterTracksBySettings(filteredTracks, matchSettingsAudioChannelConfig, settings); logger.info('Filtering ' + type + ' tracks ended, found ' + filteredTracks.length + ' matching track(s).'); } // We did not apply any filter. We can select from all possible tracks if (filteredTracks.length === 0) { setTrack(selectInitialTrack(type, possibleTracks)); } // We have some tracks based on the filtering we did. else { // More than one possibility if (filteredTracks.length &gt; 1) { setTrack(selectInitialTrack(type, filteredTracks)); } // Only one possibility use this one else { setTrack(filteredTracks[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 (areTracksEqual(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; areTracksEqual(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; !areTracksEqual(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 areTracksEqual(t1, t2) { if (!t1 &amp;&amp; !t2) { return true; } if (!t1 || !t2) { return false; } const sameId = t1.id === t2.id; const sameViewpoint = JSON.stringify(t1.viewpoint) === JSON.stringify(t2.viewpoint); const sameLang = t1.lang === t2.lang; const sameCodec = t1.codec === t2.codec; const sameRoles = JSON.stringify(t1.roles) === JSON.stringify(t2.roles); const sameAccessibility = JSON.stringify(t1.accessibility) === JSON.stringify(t2.accessibility); const sameAudioChannelConfiguration = JSON.stringify(t1.audioChannelConfiguration) === JSON.stringify(t2.audioChannelConfiguration); return (sameId &amp;&amp; sameCodec &amp;&amp; sameViewpoint &amp;&amp; sameLang &amp;&amp; sameRoles &amp;&amp; sameAccessibility &amp;&amp; sameAudioChannelConfiguration); } /** * @memberof MediaController# */ function reset() { tracks = {}; lastSelectedTracks = {}; lastSelectedRepresentations = {}; resetInitialSettings(); _unRegisterEvents(); } 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 filterTracksBySettings(tracks, filterFn, settings) { let tracksAfterMatcher = []; tracks.forEach(function (track) { if (filterFn(settings, track)) { tracksAfterMatcher.push(track); } }); if (tracksAfterMatcher.length !== 0) { return tracksAfterMatcher; } else { logger.info('Filter-Function (' + filterFn.name + ') resulted in no tracks; setting ignored'); } return tracks; } function matchSettingsLang(settings, track) { return !settings.lang || (settings.lang instanceof RegExp) ? (track.lang.match(settings.lang)) : track.lang !== '' ? (extendedFilter(track.lang, bcp47Normalize(settings.lang)).length &gt; 0) : false; } function matchSettingsIndex(settings, track) { return (settings.index === undefined) || (settings.index === null) || (track.index === settings.index); } function matchSettingsViewPoint(settings, track) { const matchViewPoint = !settings.viewpoint || !!track.viewpoint.filter(function (item) { return _compareDescriptorType(item, settings.viewpoint); })[0]; return matchViewPoint; } function matchSettingsRole(settings, track, isTrackActive = false) { const matchRole = !settings.role || !!track.roles.filter(function (item) { return _compareDescriptorType(item, settings.role); })[0]; return (matchRole || (track.type === Constants.AUDIO &amp;&amp; isTrackActive)); } function matchSettingsAccessibility(settings, track) { let matchAccessibility; if (!settings.accessibility) { // if no accessibility is requested (or request is empty string), // match only those tracks having no accessibility element present matchAccessibility = !track.accessibility.length; } else { matchAccessibility = !!track.accessibility.filter(function (item) { return _compareDescriptorType(item, settings.accessibility); })[0]; } return matchAccessibility; } function matchSettingsAudioChannelConfig(settings, track) { let matchAudioChannelConfiguration = !settings.audioChannelConfiguration || !!track.audioChannelConfiguration.filter(function (item) { return _compareDescriptorType(item, settings.audioChannelConfiguration); })[0]; return matchAudioChannelConfiguration; } 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 || !!track.viewpoint.filter(function (item) { return _compareDescriptorType(item, settings.viewpoint); })[0]; const matchRole = !settings.role || !!track.roles.filter(function (item) { return _compareDescriptorType(item, settings.role); })[0]; let matchAccessibility = !settings.accessibility || !!track.accessibility.filter(function (item) { return _compareDescriptorType(item, settings.accessibility); })[0]; let matchAudioChannelConfiguration = !settings.audioChannelConfiguration || !!track.audioChannelConfiguration.filter(function (item) { return _compareDescriptorType(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, mediaInfos) { if (type === Constants.TEXT) return mediaInfos[0]; let tmpArr; const customInitialTrackSelectionFunction = customParametersModel.getCustomInitialTrackSelectionFunction(); tmpArr = _initialFilterMediaInfosByAllowedSettings(mediaInfos); // If we have a custom function that selects the track we use this one if (customInitialTrackSelectionFunction &amp;&amp; typeof customInitialTrackSelectionFunction === 'function') { tmpArr = customInitialTrackSelectionFunction(tmpArr); } // If we know the current selected bitrate for the media type we select the AdaptationSet that comes closest to this. This should only be relevant for multiperiod when we transition to the next period. else if (lastSelectedRepresentations[type]) { tmpArr = _trackSelectionModeClosestBitrate(tmpArr, type) } // Use the track selection function that is defined in the settings else { let mode = settings.get().streaming.selectionModeForInitialTrack; switch (mode) { case Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY: tmpArr = _trackSelectionModeHighestSelectionPriority(tmpArr); break; case Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE: tmpArr = _trackSelectionModeHighestBitrate(tmpArr); break; case Constants.TRACK_SELECTION_MODE_FIRST_TRACK: tmpArr = _trackSelectionModeFirstTrack(tmpArr); break; case Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY: tmpArr = _trackSelectionModeHighestEfficiency(tmpArr); break; case Constants.TRACK_SELECTION_MODE_WIDEST_RANGE: tmpArr = _trackSelectionModeWidestRange(tmpArr); break; default: logger.warn(`Track selection mode ${mode} is not supported. Falling back to TRACK_SELECTION_MODE_FIRST_TRACK`); tmpArr = _trackSelectionModeFirstTrack(tmpArr); break; } } return tmpArr.length &gt; 0 ? tmpArr[0] : mediaInfos[0]; } /** * @param {MediaInfo[]} mediaInfos * @return {MediaInfo[]} */ function _initialFilterMediaInfosByAllowedSettings(mediaInfos) { try { let tmpArr; tmpArr = _filterMediaInfosByPossibleBitrate(mediaInfos); tmpArr = _filterMediaInfosByPortalSize(tmpArr); return tmpArr; } catch (e) { logger.error(e); return mediaInfos } } /** * Returns all MediaInfo objects that have at least one bitrate that fulfills the constraint. * If all fail the constraint we return the original array. * @param {MediaInfo[]} mediaInfos * @return {MediaInfo[]} */ function _filterMediaInfosByPossibleBitrate(mediaInfos) { try { const filteredArray = mediaInfos.filter((mediaInfo) =&gt; { const type = mediaInfo.type; return mediaInfo.bitrateList.some((bitrateInfo) =&gt; { const maxBitrate = mediaPlayerModel.getAbrBitrateParameter('maxBitrate', type); const minBitrate = mediaPlayerModel.getAbrBitrateParameter('minBitrate', type); if (maxBitrate &gt; -1 &amp;&amp; bitrateInfo.bandwidth &gt; maxBitrate * 1000) { return false; } return !(minBitrate &gt; -1 &amp;&amp; bitrateInfo.bandwidth &lt; minBitrate * 1000); }) }) if (filteredArray.length &gt; 0) { return filteredArray } return mediaInfos } catch (e) { logger.error(e); return mediaInfos } } /** * @param {MediaInfo[]} mediaInfos * @return {MediaInfo[]} * @private */ function _filterMediaInfosByPortalSize(mediaInfos) { try { if (!settings.get().streaming.abr.limitBitrateByPortal) { return mediaInfos; } const { elementWidth } = videoModel.getVideoElementSize(); const filteredArray = mediaInfos.filter((mediaInfo) =&gt; { return mediaInfo.type !== Constants.VIDEO || mediaInfo.bitrateList.some((bitrateInfo) =&gt; { return bitrateInfo.width &lt;= elementWidth }); }) if (filteredArray.length &gt; 0) { return filteredArray } return mediaInfos } catch (e) { logger.error(e); return mediaInfos } } /** * Find the track that has a bitrate that matches the currenly selected one * @param tracks * @param type * @returns {*} * @private */ function _trackSelectionModeClosestBitrate(tracks, type) { if (!tracks || tracks.length === 0 || !type || !lastSelectedRepresentations[type]) { return tracks } const targetBitrate = lastSelectedRepresentations[type].bandwidth; if (!targetBitrate || isNaN(targetBitrate)) { return tracks; } let current = { min: NaN, track: null }; tracks.forEach((track) =&gt; { track.bitrateList.forEach((entry) =&gt; { const diff = Math.abs(entry.bandwidth - targetBitrate); if (isNaN(current.min) || diff &lt; current.min) { current.min = diff; current.track = track; } }) }) return current.track ? [current.track] : tracks } 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 _compareDescriptorType(v1, v2) { if (v1 &amp;&amp; v2) { let t1 = JSON.stringify({ schemeIdUri: v1.schemeIdUri, value: v1.value }) let t2 = JSON.stringify({ schemeIdUri: v2.schemeIdUri, value: v2.value }) return t1 === t2; } return false; } function createTrackInfo() { const storeLastSettings = settings.get().streaming.saveLastMediaSettingsForCurrentStreamingSession; return { audio: { list: [], storeLastSettings, current: null }, video: { list: [], storeLastSettings, current: null }, text: { list: [], storeLastSettings, current: null }, image: { list: [], storeLastSettings, current: null } }; } instance = { addTrack, areTracksEqual, getCurrentTrackFor, getInitialSettings, getTracksFor, getTracksWithHighestBitrate, getTracksWithHighestEfficiency, getTracksWithWidestRange, initialize, isCurrentTrack, matchSettings, matchSettingsAccessibility, matchSettingsAudioChannelConfig, matchSettingsIndex, matchSettingsLang, matchSettingsRole, matchSettingsViewPoint, reset, saveTextSettingsDisabled, selectInitialTrack, setConfig, setInitialMediaSettingsForType, setInitialSettings, setTrack, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * @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 BaseURLs have been updated. * @event MediaPlayerEvents#BASE_URLS_UPDATED */ this.BASE_URLS_UPDATED = 'baseUrlsUpdated'; /** * 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 started * @event MediaPlayerEvents#MANIFEST_LOADING_STARTED */ this.MANIFEST_LOADING_STARTED = 'manifestLoadingStarted'; /** * Triggered when the manifest loading is finished, providing the request object information * @event MediaPlayerEvents#MANIFEST_LOADING_FINISHED */ this.MANIFEST_LOADING_FINISHED = 'manifestLoadingFinished'; /** * Triggered when the manifest load is complete, providing the payload * @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 throughput measurement based on the last segment request has been stored * @event MediaPlayerEvents#THROUGHPUT_MEASUREMENT_STORED */ this.THROUGHPUT_MEASUREMENT_STORED = 'throughputMeasurementStored'; /** * 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'; /** * Triggered when an inband prft (ProducerReferenceTime) boxes has been received. * @event MediaPlayerEvents#INBAND_PRFT */ this.INBAND_PRFT = 'inbandPrft'; } } 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 Debug from '../../core/Debug.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Settings from '../../core/Settings.js'; 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_MIN = -0.5; const DEFAULT_CATCHUP_PLAYBACK_RATE_MAX = 0.5; const CATCHUP_PLAYBACK_RATE_MIN_LIMIT = -0.5; const CATCHUP_PLAYBACK_RATE_MAX_LIMIT = 1; /** * 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, logger, playbackController, serviceDescriptionController; const context = this.context; const settings = Settings(context).getInstance(); function setup() { logger = Debug(context).getInstance().getLogger(instance); } function setConfig(config) { if (config.playbackController) { playbackController = config.playbackController; } if (config.serviceDescriptionController) { serviceDescriptionController = config.serviceDescriptionController; } } /** * Checks the supplied min playback rate is a valid vlaue and within supported limits * @param {number} rate - Supplied min playback rate * @param {boolean} log - wether to shown warning or not * @returns {number} corrected min playback rate */ function _checkMinPlaybackRate(rate, log) { if (isNaN(rate)) return 0; if (rate &gt; 0) { if (log) { logger.warn(`Supplied minimum playback rate is a positive value when it should be negative or 0. The supplied rate will not be applied and set to 0: 100% playback speed.`) } return 0; } if (rate &lt; CATCHUP_PLAYBACK_RATE_MIN_LIMIT) { if (log) { logger.warn(`Supplied minimum playback rate is out of range and will be limited to ${CATCHUP_PLAYBACK_RATE_MIN_LIMIT}: ${CATCHUP_PLAYBACK_RATE_MIN_LIMIT * 100}% playback speed.`); } return CATCHUP_PLAYBACK_RATE_MIN_LIMIT; } return rate; }; /** * Checks the supplied max playback rate is a valid vlaue and within supported limits * @param {number} rate - Supplied max playback rate * @param {boolean} log - wether to shown warning or not * @returns {number} corrected max playback rate */ function _checkMaxPlaybackRate(rate, log) { if (isNaN(rate)) return 0; if (rate &lt; 0) { if (log) { logger.warn(`Supplied maximum playback rate is a negative value when it should be negative or 0. The supplied rate will not be applied and set to 0: 100% playback speed.`) } return 0; } if (rate &gt; CATCHUP_PLAYBACK_RATE_MAX_LIMIT) { if (log) { logger.warn(`Supplied maximum playback rate is out of range and will be limited to ${CATCHUP_PLAYBACK_RATE_MAX_LIMIT}: ${(1 + CATCHUP_PLAYBACK_RATE_MAX_LIMIT) * 100}% playback speed.`); } return CATCHUP_PLAYBACK_RATE_MAX_LIMIT; } return rate; }; /** * 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 minimum and maximum playback rates to be used when applying the catchup mechanism * If only one of the min/max values has been set then the other will default to 0 (no playback rate change). * @return {number} */ function getCatchupPlaybackRates(log) { const settingsPlaybackRate = settings.get().streaming.liveCatchup.playbackRate; if (!isNaN(settingsPlaybackRate.min) || !isNaN(settingsPlaybackRate.max)) { return { min: _checkMinPlaybackRate(settingsPlaybackRate.min, log), max: _checkMaxPlaybackRate(settingsPlaybackRate.max, log), } } const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings(); if (serviceDescriptionSettings &amp;&amp; serviceDescriptionSettings.liveCatchup &amp;&amp; (!isNaN(serviceDescriptionSettings.liveCatchup.playbackRate.min) || !isNaN(serviceDescriptionSettings.liveCatchup.playbackRate.max))) { const sdPlaybackRate = serviceDescriptionSettings.liveCatchup.playbackRate; return { min: _checkMinPlaybackRate(sdPlaybackRate.min, log), max: _checkMaxPlaybackRate(sdPlaybackRate.max, log), } } return { min: DEFAULT_CATCHUP_PLAYBACK_RATE_MIN, max: DEFAULT_CATCHUP_PLAYBACK_RATE_MAX } } /** * 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(getBufferTimeDefault(), initialBufferLevel); } /** * Returns the stable buffer time taking the live delay into account * @return {number} */ function getBufferTimeDefault() { let bufferTimeDefault = settings.get().streaming.buffer.bufferTimeDefault &gt; 0 ? settings.get().streaming.buffer.bufferTimeDefault : 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(bufferTimeDefault, liveDelay) : bufferTimeDefault; } /** * 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, getBufferTimeDefault, getInitialBufferLevel, getRetryAttemptsForType, getRetryIntervalsForType, getCatchupPlaybackRates, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Constants from './constants/Constants.js'; import DashConstants from '../dash/constants/DashConstants.js'; import MetricsConstants from './constants/MetricsConstants.js'; import PlaybackController from './controllers/PlaybackController.js'; import StreamController from './controllers/StreamController.js'; import GapController from './controllers/GapController.js'; import CatchupController from './controllers/CatchupController.js'; import ServiceDescriptionController from '../dash/controllers/ServiceDescriptionController.js'; import ContentSteeringController from '../dash/controllers/ContentSteeringController.js'; import MediaController from './controllers/MediaController.js'; import BaseURLController from './controllers/BaseURLController.js'; import ManifestLoader from './ManifestLoader.js'; import ErrorHandler from './utils/ErrorHandler.js'; import Capabilities from './utils/Capabilities.js'; import CapabilitiesFilter from './utils/CapabilitiesFilter.js'; import URIFragmentModel from './models/URIFragmentModel.js'; import ManifestModel from './models/ManifestModel.js'; import MediaPlayerModel from './models/MediaPlayerModel.js'; import AbrController from './controllers/AbrController.js'; import SchemeLoaderFactory from './net/SchemeLoaderFactory.js'; import VideoModel from './models/VideoModel.js'; import CmcdModel from './models/CmcdModel.js'; import CmsdModel from './models/CmsdModel.js'; import DOMStorage from './utils/DOMStorage.js'; import Debug from './../core/Debug.js'; import Errors from './../core/errors/Errors.js'; import EventBus from './../core/EventBus.js'; import Events from './../core/events/Events.js'; import MediaPlayerEvents from './MediaPlayerEvents.js'; import FactoryMaker from '../core/FactoryMaker.js'; import Settings from '../core/Settings.js'; import {getVersionString} from '../core/Version.js'; //Dash import SegmentBaseController from '../dash/controllers/SegmentBaseController.js'; import DashAdapter from '../dash/DashAdapter.js'; import DashMetrics from '../dash/DashMetrics.js'; import TimelineConverter from '../dash/utils/TimelineConverter.js'; import { HTTPRequest } from './vo/metrics/HTTPRequest.js'; import BASE64 from '../../externals/base64.js'; import ISOBoxer from 'codem-isoboxer'; import DashJSError from './vo/DashJSError.js'; import {checkParameterType} from './utils/SupervisorTools.js'; import ManifestUpdater from './ManifestUpdater.js'; import URLUtils from '../streaming/utils/URLUtils.js'; import BoxParser from './utils/BoxParser.js'; import TextController from './text/TextController.js'; import CustomParametersModel from './models/CustomParametersModel.js'; import ThroughputController from './controllers/ThroughputController.js'; /** * 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!'; /** * @constant {string} ARRAY_NOT_SUPPORTED_ERROR error string thrown when settings object was called using an array. * @inner */ const ARRAY_NOT_SUPPORTED_ERROR = 'Array type not supported for settings!'; 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, providedStartTime, abrController, throughputController, schemeLoaderFactory, timelineConverter, mediaController, protectionController, metricsReportingController, mssHandler, offlineController, adapter, mediaPlayerModel, customParametersModel, errHandler, baseURLController, capabilities, capabilitiesFilter, streamController, textController, gapController, playbackController, serviceDescriptionController, contentSteeringController, catchupController, dashMetrics, manifestModel, cmcdModel, cmsdModel, videoModel, uriFragmentModel, domStorage, segmentBaseController; /* --------------------------------------------------------------------------- INIT FUNCTIONS --------------------------------------------------------------------------- */ function setup() { logger = debug.getLogger(instance); mediaPlayerInitialized = false; playbackInitialized = false; streamingInitialized = false; autoPlay = true; providedStartTime = NaN; 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.throughputController) { throughputController = config.throughputController } 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 (!throughputController) { throughputController = ThroughputController(context).getInstance(); } if (!abrController) { abrController = AbrController(context).getInstance(); } 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(); cmsdModel = CmsdModel(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, contentSteeringController }); 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(), errors: Errors }); } // configure controllers mediaController.setConfig({ domStorage, settings, mediaPlayerModel, customParametersModel, videoModel }); mediaPlayerModel.setConfig({ playbackController, serviceDescriptionController }); contentSteeringController.setConfig({ adapter, errHandler, dashMetrics, mediaPlayerModel, manifestModel, serviceDescriptionController, throughputController, eventBus }) 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 --------------------------------------------------------------------------- */ /** * Causes the player to begin streaming the media as set by the {@link module:MediaPlayer#attachSource attachSource()} * method in preparation for playing. It specifically does not require a view to be attached with {@link module:MediaPlayer#attachSource attachView()} to begin preloading. * When a view is attached after preloading, the buffered data is transferred to the attached mediaSource buffers. * * @see {@link module:MediaPlayer#attachSource attachSource()} * @see {@link module:MediaPlayer#attachView attachView()} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~SOURCE_NOT_ATTACHED_ERROR SOURCE_NOT_ATTACHED_ERROR} if called before attachSource function * @instance */ function preload() { if (videoModel.getElement() || streamingInitialized) { return; } if (source) { _initializePlayback(providedStartTime); } else { throw SOURCE_NOT_ATTACHED_ERROR; } } /** * 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; } if (value &lt; 0) { value = 0; } let s = playbackController.getIsDynamic() ? getDVRSeekOffset(value) : value; // For VoD limit the seek to the duration of the content const videoElement = getVideoElement(); if (!playbackController.getIsDynamic() &amp;&amp; videoElement.duration) { s = Math.min(videoElement.duration, s); } 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()); } /* --------------------------------------------------------------------------- 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 ThroughputController in kbit/s * * @param {MediaType} type * @param {string} calculationMode * @param {number} sampleSize * @return {number} value * @memberof module:MediaPlayer * @instance */ function getAverageThroughput(type, calculationMode = null, sampleSize = NaN) { return throughputController ? throughputController.getAverageThroughput(type, calculationMode, sampleSize) : 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(providedStartTime); } } if (playbackInitialized) { //Reset if we have been playing before, so this is a new element. _resetPlaybackControllers(); } _initializePlayback(providedStartTime); } /** * 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); } function attachVttRenderingDiv(div) { if (!videoModel.getElement()) { throw ELEMENT_NOT_ATTACHED_ERROR; } videoModel.setVttRenderingDiv(div); } /* --------------------------------------------------------------------------- QUALITY AND TRACK MANAGEMENT --------------------------------------------------------------------------- */ /** * 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 {Representation | null} the quality index, 0 corresponding to the lowest bitrate * @memberof module:MediaPlayer * @see {@link module:MediaPlayer#getCurrentRepresentationForType getCurrentRepresentationForType()} * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getCurrentRepresentationForType(type) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } if (type !== Constants.IMAGE &amp;&amp; type !== Constants.VIDEO &amp;&amp; type !== Constants.AUDIO) { return null; } const activeStream = getActiveStream(); if (!activeStream) { return null; } if (type === Constants.IMAGE) { const thumbnailController = activeStream.getThumbnailController(); return !thumbnailController ? -1 : thumbnailController.getCurrentTrack(); } return activeStream.getCurrentRepresentationForType(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 * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function setRepresentationForTypeById(type, id, forceReplace = false) { if (type !== Constants.IMAGE &amp;&amp; type !== Constants.VIDEO &amp;&amp; type !== Constants.AUDIO) { return; } if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } const activeStream = getActiveStream(); if (!activeStream) { return; } if (type === Constants.IMAGE) { const thumbnailController = activeStream.getThumbnailController(); if (thumbnailController) { thumbnailController.setTrackById(id); } } else { const representation = activeStream.getRepresentationForTypeById(type, id); if (representation) { abrController.setPlaybackQuality(type, streamController.getActiveStreamInfo(), representation, { 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. * * @param {MediaType} type - 'video', 'audio' or 'image' * @param {number} value - the quality index, 0 corresponding to the lowest absolute index * @param {boolean} forceReplace - true if segments have to be replaced by segments of the new quality * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function setRepresentationForTypeByIndex(type, index, forceReplace = false) { if (type !== Constants.IMAGE &amp;&amp; type !== Constants.VIDEO &amp;&amp; type !== Constants.AUDIO) { return; } if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } const activeStream = getActiveStream(); if (!activeStream) { return; } if (type === Constants.IMAGE) { const thumbnailController = activeStream.getThumbnailController(); if (thumbnailController) { thumbnailController.setTrackByIndex(index); } } else { const representation = activeStream.getRepresentationForTypeByIndex(type, index); if (representation) { abrController.setPlaybackQuality(type, streamController.getActiveStreamInfo(), representation, { forceReplace }); } } } /** * @param {MediaType} type * @param {string} streamId * @returns {Array} * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function getRepresentationsByType(type, streamId = null) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } let stream = streamId ? streamController.getStreamById(streamId) : getActiveStream(); return stream ? stream.getRepresentationsByType(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 (object:{schemeIdUri,value} or value-primitive), * audioChannelConfiguration: audioChannelConfigurationValue (object:{schemeIdUri,value} or value-primitive (assumes schemeIdUri='urn:mpeg:mpegB:cicp:ChannelConfiguration')), * accessibility: accessibilityValue (object:{schemeIdUri,value} or value-primitive (assumes schemeIdUri='urn:mpeg:dash:role:2011')), * role: roleValue (object:{schemeIdUri,value} or value-primitive (assumes schemeIdUri='urn:mpeg:dash:role:2011')) * } * * @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; } let sanitizedValue = _sanitizeSettings(value); mediaController.setInitialSettings(type, sanitizedValue); } /** * 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} * @param {boolean} [noSettingsSave] - specify if settings from the track must not be saved for incoming track selection * @memberof module:MediaPlayer * @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function * @instance */ function setCurrentTrack(track, noSettingsSave = false) { if (!streamingInitialized) { throw STREAMING_NOT_INITIALIZED_ERROR; } mediaController.setTrack(track, noSettingsSave); } /* --------------------------------------------------------------------------- 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); } /** * Adds a request interceptor. This enables application to monitor, manipulate, overwrite any request parameter and/or request data. * The provided callback function shall return a promise with updated request that shall be resolved once the process of the request is completed. * The interceptors are applied in the order they are added. * @param {function} interceptor - the request interceptor callback * @memberof module:MediaPlayer * @instance */ function addRequestInterceptor(interceptor) { customParametersModel.addRequestInterceptor(interceptor); } /** * Removes a request interceptor. * @param {function} interceptor - the request interceptor callback * @memberof module:MediaPlayer * @instance */ function removeRequestInterceptor(interceptor) { customParametersModel.removeRequestInterceptor(interceptor); } /** * Adds a response interceptor. This enables application to monitor, manipulate, overwrite the response data * The provided callback function shall return a promise with updated response that shall be resolved once the process of the response is completed. * The interceptors are applied in the order they are added. * @param {function} interceptor - the response interceptor * @memberof module:MediaPlayer * @instance */ function addResponseInterceptor(interceptor) { customParametersModel.addResponseInterceptor(interceptor); } /** * Removes a response interceptor. * @param {function} interceptor - the request interceptor * @memberof module:MediaPlayer * @instance */ function removeResponseInterceptor(interceptor) { customParametersModel.removeResponseInterceptor(interceptor); } /** * 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 asynchronous 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); } if (startTime == null) { startTime = NaN; } if (!isNaN(startTime)) { startTime = Math.max(0, startTime); } providedStartTime = startTime; source = urlOrManifest; if (streamingInitialized || playbackInitialized) { _resetPlaybackControllers(); } if (isReady()) { _initializePlayback(providedStartTime); } } /** * 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(); } } /** * Returns all BaseURLs that are available including synthesized elements (e.g by content steering) * @returns {BaseURL[]} */ function getAvailableBaseUrls() { const manifest = manifestModel.getValue(); if (!manifest) { return []; } return baseURLController.getBaseUrls(manifest); } /** * Returns the available location elements including synthesized elements (e.g by content steering) * @returns {MpdLocation[]} */ function getAvailableLocations() { const manifest = manifestModel.getValue(); if (!manifest) { return []; } const manifestLocations = adapter.getLocation(manifest); const synthesizedElements = contentSteeringController.getSynthesizedLocationElements(manifestLocations); return manifestLocations.concat(synthesizedElements); } //*********************************** // PRIVATE METHODS //*********************************** function _resetPlaybackControllers() { playbackInitialized = false; streamingInitialized = false; adapter.reset(); streamController.reset(); gapController.reset(); catchupController.reset(); playbackController.reset(); serviceDescriptionController.reset(); contentSteeringController.reset(); abrController.reset(); throughputController.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(); cmsdModel.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, throughputController, 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 }) throughputController.setConfig({ settings, playbackController }) abrController.setConfig({ streamController, domStorage, mediaPlayerModel, customParametersModel, throughputController, cmsdModel, dashMetrics, adapter, videoModel, settings }); cmcdModel.setConfig({ abrController, dashMetrics, playbackController, throughputController }); cmsdModel.setConfig({}); // initializes controller mediaController.initialize(); throughputController.initialize(); abrController.initialize(); streamController.initialize(autoPlay, protectionData); textController.initialize(); gapController.initialize(); catchupController.initialize(); cmcdModel.initialize(); cmsdModel.initialize(); contentSteeringController.initialize(); segmentBaseController.initialize(); } function _createManifestLoader() { return ManifestLoader(context).create({ debug: debug, errHandler: errHandler, dashMetrics: dashMetrics, mediaPlayerModel: mediaPlayerModel, 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, adapter, manifestLoader, errHandler, contentSteeringController }); 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; } function _sanitizeSettings(value) { const defaults = settings.get().streaming.defaultSchemeIdUri; let output = {}; function __sanitizeDescriptorType(name, val, defaultSchemeIdUri) { let out = {}; if (val) { if (val instanceof Array) { throw ARRAY_NOT_SUPPORTED_ERROR; } else if (val instanceof Object) { out.schemeIdUri = val.schemeIdUri ? val.schemeIdUri : ''; out.value = val.value ? val.value : ''; } else { out.schemeIdUri = defaultSchemeIdUri; out.value = val; logger.warn('No schemeIdUri provided for ' + name + ', using default \\\"' + defaultSchemeIdUri + '\\\"'); } return out; } return null; } if (value.lang) output.lang = value.lang; if (value.index) output.index = value.index; if (value.viewpoint) output.viewpoint = __sanitizeDescriptorType('viewpoint', value.viewpoint, defaults.viewpoint); if (value.audioChannelConfiguration) output.audioChannelConfiguration = __sanitizeDescriptorType('audioChannelConfiguration', value.audioChannelConfiguration, defaults.audioChannelConfiguration); if (value.role) output.role = __sanitizeDescriptorType('role', value.role, defaults.role); if (value.accessibility) output.accessibility = __sanitizeDescriptorType('accessibility', value.accessibility, defaults.accessibility); return output; } /** * * @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 = { addABRCustomRule, addRequestInterceptor, addResponseInterceptor, addUTCTimingSource, attachProtectionController, attachSource, attachTTMLRenderingDiv, attachView, attachVttRenderingDiv, clearDefaultUTCTimingSources, convertToTimeCode, destroy, duration, durationAsUTC, enableForcedTextStreaming, enableText, extend, formatUTC, getABRCustomRules, getActiveStream, getAutoPlay, getAvailableBaseUrls, getAvailableLocations, getAverageThroughput, getBufferLength, getCurrentLiveLatency, getCurrentSteeringResponseData, getCurrentTextTrackIndex, getCurrentTrackFor, getDVRSeekOffset, getDVRWindowSize, getDashAdapter, getDashMetrics, getDebug, getInitialMediaSettingsFor, getLowLatencyModeEnabled, getOfflineController, getPlaybackRate, getProtectionController, getCurrentRepresentationForType, getRepresentationsByType, getSettings, getSource, getStreamsFromManifest, getTTMLRenderingDiv, getTargetLiveDelay, getTracksFor, getTracksForTypeFromManifest, getVersion, getVideoElement, getVolume, getXHRWithCredentialsForType, initialize, isDynamic, isMuted, isPaused, isReady, isSeeking, isTextEnabled, off, on, pause, play, preload, provideThumbnail, registerCustomCapabilitiesFilter, registerLicenseRequestFilter, registerLicenseResponseFilter, removeABRCustomRule, removeAllABRCustomRule, removeRequestInterceptor, removeResponseInterceptor, removeUTCTimingSource, reset, resetCustomInitialTrackSelectionFunction, resetSettings, restoreDefaultUTCTimingSources, retrieveManifest, seek, seekToOriginalLive, setAutoPlay, setConfig, setCurrentTrack, setCustomInitialTrackSelectionFunction, setInitialMediaSettingsFor, setMute, setPlaybackRate, setProtectionData, setRepresentationForTypeByIndex, setRepresentationForTypeById, setTextTrack, setVolume, setXHRWithCredentialsForType, time, timeAsUTC, triggerSteeringRequest, unregisterCustomCapabilitiesFilter, unregisterLicenseRequestFilter, unregisterLicenseResponseFilter, updateSettings, updateSource, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import MetricsReportingEvents from './MetricsReportingEvents.js'; import MetricsCollectionController from './controllers/MetricsCollectionController.js'; import MetricsHandlerFactory from './metrics/MetricsHandlerFactory.js'; import ReportingFactory from './reporting/ReportingFactory.js'; 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.initialize(); 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import MediaInfo from './vo/MediaInfo.js'; import StreamInfo from './vo/StreamInfo.js'; import ManifestInfo from './vo/ManifestInfo.js'; import Event from './vo/Event.js'; import FactoryMaker from '../core/FactoryMaker.js'; import DashManifestModel from './models/DashManifestModel.js'; import PatchManifestModel from './models/PatchManifestModel.js'; import Representation from './vo/Representation.js'; 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, 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 }); } } /** * 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 = getMainAdaptationForType(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 getMainAdaptationForType(type, streamInfo) { const index = streamInfo ? streamInfo.index : 0; const adaptations = dashManifestModel.getAdaptationsForType(voPeriods[index].mpd.manifest, index, type); if (!adaptations || adaptations.length === 0) return null; if (adaptations.length &gt; 1 &amp;&amp; streamInfo) { 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} * @memberof module:DashAdapter * @instance */ function areMediaInfosEqual(mInfoOne, mInfoTwo) { if (!mInfoOne || !mInfoTwo) { return false; } const sameId = mInfoOne.id === mInfoTwo.id; const sameCodec = mInfoOne.codec === mInfoTwo.codec; const sameViewpoint = JSON.stringify(mInfoOne.viewpoint) === JSON.stringify(mInfoTwo.viewpoint); const sameLang = mInfoOne.lang === mInfoTwo.lang; const sameRoles = JSON.stringify(mInfoOne.roles) === JSON.stringify(mInfoTwo.roles); const sameAccessibility = JSON.stringify(mInfoOne.accessibility) === JSON.stringify(mInfoTwo.accessibility); const sameAudioChannelConfiguration = JSON.stringify(mInfoOne.audioChannelConfiguration) === JSON.stringify(mInfoTwo.audioChannelConfiguration); 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.schemeIdUri === constants.ACCESSIBILITY_CEA608_SCHEME) { if (accessibility.value === '') { convertVideoInfoToEmbeddedTextInfo(media, constants.CC1, 'eng'); mediaArr.push(media); media = null; } else { let value = accessibility.value; 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 (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} * @memberOf module:DashAdapter * @instance */ 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, mediaInfo); 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 Representation * @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 Representation) { const period = getPeriodForStreamInfo(streamInfo, voPeriods) events = dashManifestModel.getEventStreamForRepresentation(manifest, voRepresentation, period); } } return events; } /** * 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 {number} 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 locations of the MPD if existing and if they are still valid * @param {object} manifest * @returns {PatchLocation[]} patch location * @memberOf module:DashAdapter * @instance */ function getPatchLocation(manifest) { const patchLocations = dashManifestModel.getPatchLocation(manifest); const publishTime = dashManifestModel.getPublishTime(manifest); // short-circuit when no patch location or publish time exists if (!patchLocations || patchLocations.length === 0 || !publishTime) { return []; } return patchLocations.filter((patchLocation) =&gt; { // check if the patch location has expired, if so do not consider it return isNaN(patchLocation.ttl) || (publishTime.getTime() + patchLocation.ttl &gt; new Date().getTime()) }) } /** * 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} * @memberOf module:DashAdapter * @instance */ function getIsPatch(manifest) { return patchManifestModel.getIsPatch(manifest); } /** * Returns the base urls for a given element * @param {object} node * @returns {BaseURL[]} * @memberOf module:DashAdapter * @instance * @ignore */ function getBaseURLsFromElement(node) { return dashManifestModel.getBaseURLsFromElement(node); } /** * Returns the function to sort the Representations * @returns {function} * @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); } /** * Returns the voPeriod object for a given id * @param {String} id * @returns {object|null} * @memberOf module:DashAdapter * @instance */ 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} * @memberOf module:DashAdapter * @instance */ function getIsTypeOf(adaptation, type) { return dashManifestModel.getIsTypeOf(adaptation, type); } function reset() { voPeriods = []; } /** * Checks if the supplied manifest is compatible for application of the supplied patch * @param {object} manifest * @param {object} patch * @return {boolean} * @memberOf module:DashAdapter * @instance */ 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 * @memberOf module:DashAdapter * @instance */ 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] || []).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 if (!Array.isArray(target[name])) { delete target[name]; } else if (relativePosition != -1) { // if we did have a positional reference we need to purge from array set and restore X2JS proper semantics let targetArray = target[name]; targetArray.splice(relativePosition, 1); if (targetArray.length &gt; 0) { target[name] = targetArray; } else { // all nodes of this type deleted, remove entry delete target[name]; } } } // 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] || []; 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] = 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[adaptation.period.index].AdaptationSet[adaptation.index]; 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); mediaInfo.segmentAlignment = dashManifestModel.getSegmentAlignment(realAdaptation); mediaInfo.subSegmentAlignment = dashManifestModel.getSubSegmentAlignment(realAdaptation); mediaInfo.viewpoint = dashManifestModel.getViewpointForAdaptation(realAdaptation); mediaInfo.accessibility = dashManifestModel.getAccessibilityForAdaptation(realAdaptation); if (mediaInfo.accessibility.filter(function (accessibility) { if (accessibility.schemeIdUri &amp;&amp; (accessibility.schemeIdUri.search('cea-608') &gt;= 0) &amp;&amp; typeof (cea608parser) !== 'undefined') return true; })[0]) mediaInfo.embeddedCaptions = true; mediaInfo.audioChannelConfiguration = dashManifestModel.getAudioChannelConfigurationForAdaptation(realAdaptation); if (mediaInfo.audioChannelConfiguration.length === 0 &amp;&amp; realAdaptation.Representation &amp;&amp; realAdaptation.Representation.length &gt; 0) { mediaInfo.audioChannelConfiguration = dashManifestModel.getAudioChannelConfigurationForRepresentation(realAdaptation.Representation[0]); } mediaInfo.roles = dashManifestModel.getRolesForAdaptation(realAdaptation); 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.getSupplementalPropertiesForAdaptation(realAdaptation); if ((!mediaInfo.supplementalProperties || mediaInfo.supplementalProperties.length === 0) &amp;&amp; realAdaptation.Representation &amp;&amp; realAdaptation.Representation.length &gt; 0) { let arr = realAdaptation.Representation.map(repr =&gt; { return dashManifestModel.getSupplementalPropertiesForRepresentation(repr); }); if (arr.every(v =&gt; JSON.stringify(v) === JSON.stringify(arr[0]))) { // only output Representation.supplementalProperties to mediaInfo, if they are present on all Representations mediaInfo.supplementalProperties = arr[0]; } } mediaInfo.isFragmented = dashManifestModel.getIsFragmented(realAdaptation); mediaInfo.isEmbedded = false; mediaInfo.hasProtectedRepresentations = dashManifestModel.getAdaptationHasProtectedRepresentations(realAdaptation); // Save IDs of AS that we can switch to try { const adaptationSetSwitching = mediaInfo.supplementalProperties.filter((sp) =&gt; { return sp.schemeIdUri === DashConstants.ADAPTATION_SET_SWITCHING_SCHEME_ID_URI }); if (adaptationSetSwitching &amp;&amp; adaptationSetSwitching.length &gt; 0) { const ids = adaptationSetSwitching[0].value.toString().split(',') mediaInfo.adaptationSetSwitchingCompatibleIds = ids.map((id) =&gt; { return id }) } } catch (e) { return mediaInfo; } 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 = [{ schemeIdUri: 'urn:mpeg:dash:role:2011', value: '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.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[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; for (adaptationSetArrayIndex = 0; adaptationSetArrayIndex &lt; adaptationSetArray.length; adaptationSetArrayIndex = adaptationSetArrayIndex + 1) { adaptationSet = adaptationSetArray[adaptationSetArrayIndex]; representationArray = adaptationSet.Representation; 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; } // #endregion PRIVATE FUNCTIONS instance = { applyPatchToManifest, getMainAdaptationForType, areMediaInfosEqual, getAllMediaInfoForType, getAvailabilityStartTime, getBandwidthForRepresentation, getBaseURLsFromElement, getCodec, getContentSteering, getDuration, getEssentialPropertiesForRepresentation, getEvent, getEventsFor, getIndexForRepresentation, getIsDVB, getIsDynamic, getIsPatch, getIsTextTrack, getIsTypeOf, getLocation, getManifestUpdatePeriod, getMediaInfoForType, getMpd, getPatchLocation, getPeriodById, getProducerReferenceTimes, getPublishTime, getRealAdaptation, getRealPeriodByIndex, getRegularPeriods, getRepresentationSortFunction, getStreamsInfo, getSuggestedPresentationDelay, getUTCTimingSources, getVoRepresentations, isPatchValid, reset, setConfig, updatePeriods, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest.js'; import FactoryMaker from '../core/FactoryMaker.js'; import MetricsConstants from '../streaming/constants/MetricsConstants.js'; import Round10 from './utils/Round10.js'; import MetricsModel from '../streaming/models/MetricsModel.js'; import Utils from '../core/Utils.js'; import {PlayList, PlayListTrace} from '../streaming/vo/metrics/PlayList.js'; /** * @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.bandwidth, 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.startDate, request.endDate); } /** * @param {object} request * @param {string} responseUrl * @param {number} responseStatus * @param {object} responseHeaders * @param {object} traces * @param {object} cmsd * @memberof module:DashMetrics * @instance * @ignore */ function addHttpRequest(request, responseUrl, responseStatus, responseHeaders, traces,cmsd) { const response = { status: responseStatus, headers: responseHeaders, url: responseUrl }; metricsModel.addHttpRequest(request, response, traces, cmsd); } /** * @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, mediaType); } } /** * 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; playListTraceMetrics.duration = endTime.getTime() - startTime.getTime(); 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Events from './events/Events.js'; import FactoryMaker from './FactoryMaker.js'; 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 &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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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_FetchLoader.js.html":{"id":"streaming_net_FetchLoader.js.html","title":"Source: streaming/net/FetchLoader.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/FetchLoader.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.js'; import Settings from '../../core/Settings.js'; import Constants from '../constants/Constants.js'; import AastLowLatencyThroughputModel from '../models/AastLowLatencyThroughputModel.js'; /** * @module FetchLoader * @ignore * @description Manages download of resources via HTTP using fetch. */ function FetchLoader() { const context = this.context; const aastLowLatencyThroughputModel = AastLowLatencyThroughputModel(context).getInstance(); const settings = Settings(context).getInstance(); let instance, dashMetrics, boxParser; function setConfig(cfg) { dashMetrics = cfg.dashMetrics; boxParser = cfg.boxParser } /** * Load request * @param {CommonMediaLibrary.request.CommonMediaRequest} httpRequest * @param {CommonMediaLibrary.request.CommonMediaResponse} httpResponse */ function load(httpRequest, httpResponse) { // Variables will be used in the callback functions const fragmentRequest = httpRequest.customData.request; const headers = new Headers(); if (httpRequest.headers) { for (let header in httpRequest.headers) { let value = httpRequest.headers[header]; if (value) { headers.append(header, value); } } } let abortController; if (typeof window.AbortController === 'function') { abortController = new AbortController(); /*jshint ignore:line*/ httpRequest.customData.abortController = abortController; abortController.signal.onabort = httpRequest.customData.onabort; } httpRequest.customData.abort = abort.bind(httpRequest); const reqOptions = { method: httpRequest.method, headers: headers, credentials: httpRequest.credentials, signal: abortController ? abortController.signal : undefined }; const calculationMode = settings.get().streaming.abr.throughput.lowLatencyDownloadTimeCalculationMode; const requestTime = performance.now(); let throughputCapacityDelayMS = 0; new Promise((resolve) =&gt; { if (calculationMode === Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.AAST &amp;&amp; aastLowLatencyThroughputModel) { throughputCapacityDelayMS = aastLowLatencyThroughputModel.getThroughputCapacityDelayMS(fragmentRequest, dashMetrics.getCurrentBufferLevel(fragmentRequest.mediaType) * 1000); if (throughputCapacityDelayMS) { // safely delay the \"fetch\" call a bit to be able to measure the throughput capacity of the line. // this will lead to first few chunks downloaded at max network speed return setTimeout(resolve, throughputCapacityDelayMS); } } resolve(); }) .then(() =&gt; { let markBeforeFetch = performance.now(); fetch(httpRequest.url, reqOptions) .then((response) =&gt; { httpResponse.status = response.status; httpResponse.statusText = response.statusText; httpResponse.url = response.url; if (!response.ok) { httpRequest.customData.onerror(); } const responseHeaders = {}; for (const key of response.headers.keys()) { responseHeaders[key] = response.headers.get(key); } httpResponse.headers = responseHeaders; const totalBytes = parseInt(response.headers.get('Content-Length'), 10); let bytesReceived = 0; let signaledFirstByte = false; let receivedData = new Uint8Array(); let offset = 0; if (calculationMode === Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.AAST &amp;&amp; aastLowLatencyThroughputModel) { _aastProcessResponse(markBeforeFetch, httpRequest, requestTime, throughputCapacityDelayMS, responseHeaders, response); } else { httpRequest.customData.reader = response.body.getReader(); } let downloadedData = []; let moofStartTimeData = []; let mdatEndTimeData = []; let lastChunkWasFinished = true; /** * Callback function for the reader. * @param value - some data. Always undefined when done is true. * @param done - true if the stream has already given you all its data. */ const _processResult = ({ value, done }) =&gt; { // Bug fix Parse whenever data is coming [value] better than 1ms looking that increase CPU if (done) { _handleRequestComplete() return; } if (value &amp;&amp; value.length &gt; 0) { _handleDataReceived(value) } _read(httpRequest, httpResponse, _processResult); }; /** * Once a request is completed throw final progress event with the calculated bytes and download time * @private */ function _handleRequestComplete() { if (receivedData) { if (calculationMode !== Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.AAST) { // If there is pending data, call progress so network metrics // are correctly generated // Same structure as https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequestEventTarget/ let calculatedThroughput = null; let calculatedTime = null; if (calculationMode === Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING) { calculatedThroughput = _calculateThroughputByChunkData(moofStartTimeData, mdatEndTimeData); if (calculatedThroughput) { calculatedTime = bytesReceived * 8 / calculatedThroughput; } } else if (calculationMode === Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.DOWNLOADED_DATA) { calculatedTime = calculateDownloadedTime(downloadedData, bytesReceived); } httpRequest.customData.onprogress({ loaded: bytesReceived, total: isNaN(totalBytes) ? bytesReceived : totalBytes, lengthComputable: true, time: calculatedTime }); } httpResponse.data = receivedData.buffer; } httpRequest.customData.onload(); httpRequest.customData.onloadend(); } /** * Called every time we received data * @param value * @private */ function _handleDataReceived(value) { receivedData = _concatTypedArray(receivedData, value); bytesReceived += value.length; downloadedData.push({ ts: performance.now(), bytes: value.length }); if (calculationMode === Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING &amp;&amp; lastChunkWasFinished) { // Parse the payload and capture the 'moof' box const boxesInfo = boxParser.findLastTopIsoBoxCompleted(['moof'], receivedData, offset); if (boxesInfo.found) { // Store the beginning time of each chunk download in array StartTimeData lastChunkWasFinished = false; moofStartTimeData.push({ ts: performance.now(), bytes: value.length }); } } const boxesInfo = boxParser.findLastTopIsoBoxCompleted(['moov', 'mdat'], receivedData, offset); if (boxesInfo.found) { const endOfLastBox = boxesInfo.lastCompletedOffset + boxesInfo.size; // Store the end time of each chunk download with its size in array EndTimeData if (calculationMode === Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING &amp;&amp; !lastChunkWasFinished) { lastChunkWasFinished = true; mdatEndTimeData.push({ ts: performance.now(), bytes: receivedData.length }); } // Make the data that we received available for playback // If we are going to pass full buffer, avoid copying it and pass // complete buffer. Otherwise, clone the part of the buffer that is completed // and adjust remaining buffer. A clone is needed because ArrayBuffer of a typed-array // keeps a reference to the original data let data; if (endOfLastBox === receivedData.length) { data = receivedData; receivedData = new Uint8Array(); } else { data = new Uint8Array(receivedData.subarray(0, endOfLastBox)); receivedData = receivedData.subarray(endOfLastBox); } // Announce progress but don't track traces. Throughput measures are quite unstable // when they are based in small amount of data httpRequest.customData.onprogress({ data: data.buffer, lengthComputable: false, noTrace: true }); offset = 0; } else { offset = boxesInfo.lastCompletedOffset; // Call progress, so it generates traces that will be later used to know when the first byte // were received if (!signaledFirstByte) { httpRequest.customData.onprogress({ lengthComputable: false, noTrace: true }); signaledFirstByte = true; } } } _read(httpRequest, httpResponse, _processResult); }) .catch(function (e) { if (httpRequest.customData.onerror) { httpRequest.customData.onerror(e); } }); }); } function _aastProcessResponse(markBeforeFetch, httpRequest, requestTime, throughputCapacityDelayMS, responseHeaders, response) { let markA = markBeforeFetch; let markB = 0; function fetchMeassurement(stream) { const reader = stream.getReader(); const measurement = []; const fragmentRequest = httpRequest.customData.request; reader.read() .then(function processFetch(args) { const value = args.value; const done = args.done; markB = performance.now(); if (value &amp;&amp; value.length) { const chunkDownloadDurationMS = markB - markA; const chunkBytes = value.length; measurement.push({ chunkDownloadTimeRelativeMS: markB - markBeforeFetch, chunkDownloadDurationMS, chunkBytes, kbps: Math.round(8 * chunkBytes / (chunkDownloadDurationMS / 1000)), bufferLevel: dashMetrics.getCurrentBufferLevel(fragmentRequest.mediaType) }); } if (done) { const fetchDuration = markB - markBeforeFetch; const bytesAllChunks = measurement.reduce((prev, curr) =&gt; prev + curr.chunkBytes, 0); aastLowLatencyThroughputModel.addMeasurement(fragmentRequest, fetchDuration, measurement, requestTime, throughputCapacityDelayMS, responseHeaders); httpRequest.progress({ loaded: bytesAllChunks, total: bytesAllChunks, lengthComputable: true, time: aastLowLatencyThroughputModel.getEstimatedDownloadDurationMS(fragmentRequest) }); return; } markA = performance.now(); return reader.read().then(processFetch); }); } // tee'ing streams is supported by all current major browsers // https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/tee const [forMeasure, forConsumer] = response.body.tee(); fetchMeassurement(forMeasure); httpRequest.customData.reader = forConsumer.getReader(); } /** * Reads the response of the request. For details refer to https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read * @param httpRequest * @param processResult * @private */ function _read(httpRequest, httpResponse, processResult) { httpRequest.customData.reader.read() .then(processResult) .catch(function (e) { if (httpRequest.customData.onerror &amp;&amp; httpResponse.status === 200) { // Error, but response code is 200, trigger error httpRequest.customData.onerror(e); } }); } /** * Creates a new Uint8 array and adds the existing data as well as new data * @param receivedData * @param data * @returns {Uint8Array|*} * @private */ function _concatTypedArray(receivedData, data) { if (receivedData.length === 0) { return data; } const result = new Uint8Array(receivedData.length + data.length); result.set(receivedData); // set(typedarray, targetOffset) result.set(data, receivedData.length); return result; } /** * Use the AbortController to abort a request * @param request */ function abort() { // this = httpRequest (CommonMediaRequest) if (this.customData.abortController) { // For firefox and edge this.customData.abortController.abort(); } else if (this.customData.reader) { // For Chrome try { this.customData.reader.cancel(); this.onabort(); } catch (e) { // throw exceptions (TypeError) when reader was previously closed, // for example, because a network issue } } } /** * Default throughput calculation * @param downloadedData * @param bytesReceived * @returns {number|null} * @private */ function calculateDownloadedTime(downloadedData, bytesReceived) { try { downloadedData = downloadedData.filter(data =&gt; data.bytes &gt; ((bytesReceived / 4) / downloadedData.length)); if (downloadedData.length &gt; 1) { let time = 0; const avgTimeDistance = (downloadedData[downloadedData.length - 1].ts - downloadedData[0].ts) / downloadedData.length; downloadedData.forEach((data, index) =&gt; { // To be counted the data has to be over a threshold const next = downloadedData[index + 1]; if (next) { const distance = next.ts - data.ts; time += distance &lt; avgTimeDistance ? distance : 0; } }); return time; } return null; } catch (e) { return null; } } /** * Moof based throughput calculation * @param startTimeData * @param endTimeData * @returns {number|null} * @private */ function _calculateThroughputByChunkData(startTimeData, endTimeData) { try { let datum, datumE; // Filter the last chunks in a segment in both arrays [StartTimeData and EndTimeData] datum = startTimeData.filter((data, i) =&gt; i &lt; startTimeData.length - 1); datumE = endTimeData.filter((dataE, i) =&gt; i &lt; endTimeData.length - 1); let chunkThroughputs = []; // Compute the average throughput of the filtered chunk data if (datum.length &gt; 1) { let shortDurationBytesReceived = 0; let shortDurationStartTime = 0; for (let i = 0; i &lt; datum.length; i++) { if (datum[i] &amp;&amp; datumE[i]) { let chunkDownloadTime = datumE[i].ts - datum[i].ts; if (chunkDownloadTime &gt; 1) { chunkThroughputs.push((8 * datumE[i].bytes) / chunkDownloadTime); shortDurationStartTime = 0; } else { if (shortDurationStartTime === 0) { shortDurationStartTime = datum[i].ts; shortDurationBytesReceived = 0; } let cumulatedChunkDownloadTime = datumE[i].ts - shortDurationStartTime; if (cumulatedChunkDownloadTime &gt; 1) { shortDurationBytesReceived += datumE[i].bytes; chunkThroughputs.push((8 * shortDurationBytesReceived) / cumulatedChunkDownloadTime); shortDurationStartTime = 0; } else { // continue cumulating short duration data shortDurationBytesReceived += datumE[i].bytes; } } } } if (chunkThroughputs.length &gt; 0) { const sumOfChunkThroughputs = chunkThroughputs.reduce((a, b) =&gt; a + b, 0); return sumOfChunkThroughputs / chunkThroughputs.length; } } return null; } catch (e) { return null; } } instance = { load, abort, setConfig, calculateDownloadedTime }; return instance; } FetchLoader.__dashjs_factory_name = 'FetchLoader'; const factory = FactoryMaker.getClassFactory(FetchLoader); export default factory; × 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FetchLoader from './FetchLoader.js'; import {HTTPRequest} from '../vo/metrics/HTTPRequest.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import DashJSError from '../vo/DashJSError.js'; import CmcdModel from '../models/CmcdModel.js'; import CmsdModel from '../models/CmsdModel.js'; import Utils from '../../core/Utils.js'; import Debug from '../../core/Debug.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import Settings from '../../core/Settings.js'; import Constants from '../constants/Constants.js'; import CustomParametersModel from '../models/CustomParametersModel.js'; /** * @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 boxParser = cfg.boxParser; const errors = cfg.errors; const requestTimeout = cfg.requestTimeout || 0; const eventBus = EventBus(context).getInstance(); const settings = Settings(context).getInstance(); let instance, httpRequests, delayedRequests, retryRequests, downloadErrorToRequestTypeMap, cmcdModel, cmsdModel, xhrLoader, fetchLoader, customParametersModel, logger; function setup() { logger = Debug(context).getInstance().getLogger(instance); httpRequests = []; delayedRequests = []; retryRequests = []; cmcdModel = CmcdModel(context).getInstance(); cmsdModel = CmsdModel(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 }; } /** * 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) { const retryAttempts = mediaPlayerModel.getRetryAttemptsForType(config.request.type); return _internalLoad(config, retryAttempts); } else { if (config.error) { config.error(config.request, 'error'); } return Promise.resolve(); } } /** * Initiates or re-initiates a download of the resource * @param {object} config * @param {number} remainingAttempts * @private */ function _internalLoad(config, remainingAttempts) { /** * Fired when a request has completed, whether successfully (after load) or unsuccessfully (after abort or error). */ const _onloadend = function () { // Remove the request from our list of requests if (httpRequests.indexOf(httpRequest) !== -1) { httpRequests.splice(httpRequests.indexOf(httpRequest), 1); } if (progressTimeout) { clearTimeout(progressTimeout); progressTimeout = null; } }; /** * Fired when a request has started to load data. * @param event */ const _onprogress = function (event) { const currentTime = new Date(); // If we did not transfer all data yet and this is the first time we are getting a progress event we use this time as firstByteDate. if (firstProgress) { firstProgress = false; // event.loaded: the amount of data currently transferred // event.total: the total amount of data to be transferred. // If lengthComputable is false within the XMLHttpRequestProgressEvent, that means the server never sent a Content-Length header in the response. if (!event.lengthComputable || (event.lengthComputable &amp;&amp; event.total !== event.loaded)) { requestObject.firstByteDate = currentTime; httpResponse.resourceTiming.responseStart = currentTime.getTime(); } } // lengthComputable indicating if the resource concerned by the ProgressEvent has a length that can be calculated. If not, the ProgressEvent.total property has no significant value. if (event.lengthComputable) { requestObject.bytesLoaded = httpResponse.length = event.loaded; requestObject.bytesTotal = httpResponse.resourceTiming.encodedBodySize = event.total; httpResponse.length = event.total; httpResponse.resourceTiming.encodedBodySize = event.loaded; } if (!event.noTrace) { traces.push({ s: lastTraceTime, d: event.time ? event.time : currentTime.getTime() - lastTraceTime.getTime(), b: [event.loaded ? event.loaded - lastTraceReceivedCount : 0], // event.loaded: When downloading a resource using HTTP, this value is specified in bytes (not bits), and only represents the part of the content itself, not headers and other overhead t: event.throughput }); requestObject.traces = traces; lastTraceTime = currentTime; lastTraceReceivedCount = event.loaded; } if (progressTimeout) { clearTimeout(progressTimeout); progressTimeout = null; } if (settings.get().streaming.fragmentRequestProgressTimeout &gt; 0) { progressTimeout = setTimeout(function () { // No more progress =&gt; abort request and treat as an error logger.warn('Abort request ' + httpRequest.url + ' due to progress timeout'); loader.abort(httpRequest); _onloadend(); }, settings.get().streaming.fragmentRequestProgressTimeout); } if (config.progress &amp;&amp; event) { config.progress(event); } }; const _oncomplete = function() { // Update request timing info requestObject.startDate = requestStartTime; requestObject.endDate = new Date(); requestObject.firstByteDate = requestObject.firstByteDate || requestStartTime; httpResponse.resourceTiming.responseEnd = requestObject.endDate.getTime(); // If enabled the ResourceTimingApi we add the corresponding information to the request object. // These values are more accurate and can be used by the ThroughputController later _addResourceTimingValues(httpRequest, httpResponse); } /** * Fired when an XMLHttpRequest transaction completes. * This includes status codes such as 404. We handle errors in the _onError function. */ const _onload = function () { _oncomplete(); _applyResponseInterceptors(httpResponse).then((_httpResponse) =&gt; { httpResponse = _httpResponse; _addHttpRequestMetric(httpRequest, httpResponse, traces); if (requestObject.type === HTTPRequest.MPD_TYPE) { dashMetrics.addManifestUpdate(requestObject); eventBus.trigger(Events.MANIFEST_LOADING_FINISHED, { requestObject }); } if (httpResponse.status &gt;= 200 &amp;&amp; httpResponse.status &lt;= 299) { if (config.success) { config.success(httpResponse.data, httpResponse.statusText, httpResponse.url); } if (config.complete) { config.complete(requestObject, httpResponse.statusText); } } else { _onerror(); } }); }; /** * Fired when a request has been aborted, for example because the program called XMLHttpRequest.abort(). */ const _onabort = function () { _oncomplete(); _addHttpRequestMetric(httpRequest, httpResponse, traces); if (progressTimeout) { clearTimeout(progressTimeout); progressTimeout = null; } if (config.abort) { config.abort(requestObject); } }; /** * Fired when progress is terminated due to preset time expiring. * @param event */ const _ontimeout = function (event) { _oncomplete(); let timeoutMessage; // We know how much we already downloaded by looking at the timeout event 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); _addHttpRequestMetric(httpRequest, httpResponse, traces); _retriggerRequest(); }; /** * Fired when the request encountered an error. */ const _onerror = function () { // 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 (httpResponse.status === 404 &amp;&amp; settings.get().streaming.utcSynchronization.enableBackgroundSyncAfterSegmentDownloadError &amp;&amp; requestObject.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) {} _retriggerRequest(); } const _loadRequest = function(loader, httpRequest, httpResponse) { return new Promise((resolve) =&gt; { _applyRequestInterceptors(httpRequest).then((_httpRequest) =&gt; { httpRequest = _httpRequest; httpRequest.customData.onload = _onload; httpRequest.customData.onloadend = _onloadend; httpRequest.customData.onerror = _onloadend; httpRequest.customData.onprogress = _onprogress; httpRequest.customData.onabort = _onabort; httpRequest.customData.ontimeout = _ontimeout; httpResponse.resourceTiming.startTime = Date.now(); loader.load(httpRequest, httpResponse); resolve(); }); }); } /** * Retriggers the request in case we did not exceed the number of retry attempts * @private */ const _retriggerRequest = function () { if (remainingAttempts &gt; 0) { 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(requestObject.type)); } else { if (requestObject.type === HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE) { return; } errHandler.error(new DashJSError(downloadErrorToRequestTypeMap[requestObject.type], requestObject.url + ' is not available', { request: requestObject, response: httpResponse })); if (config.error) { config.error(requestObject, 'error', httpResponse.statusText, httpResponse); } if (config.complete) { config.complete(requestObject, httpResponse.statusText); } } } // Main code after inline functions const requestObject = config.request; const traces = []; let firstProgress, requestStartTime, lastTraceTime, lastTraceReceivedCount, progressTimeout; let httpRequest; // CommonMediaLibrary.request.CommonMediaRequest let httpResponse; // CommonMediaLibrary.request.CommonMediaResponse requestObject.bytesLoaded = NaN; requestObject.bytesTotal = NaN; requestObject.firstByteDate = null; requestObject.traces = []; firstProgress = true; requestStartTime = new Date(); lastTraceTime = requestStartTime; lastTraceReceivedCount = 0; progressTimeout = null; if (!dashMetrics || !errHandler) { throw new Error('config object is not correct or missing'); } const loaderInformation = _getLoader(requestObject); const loader = loaderInformation.loader; requestObject.fileLoaderType = loaderInformation.fileLoaderType; requestObject.headers = {}; _updateRequestUrlAndHeaders(requestObject); if (requestObject.range) { requestObject.headers['Range'] = 'bytes=' + requestObject.range; } const withCredentials = customParametersModel.getXHRWithCredentialsForType(requestObject.type); httpRequest = /* CommonMediaRequest */{ url: requestObject.url, method: HTTPRequest.GET, responseType: requestObject.responseType, headers: requestObject.headers, credentials: withCredentials ? 'include' : 'omit', timeout: requestTimeout, cmcd: cmcdModel.getCmcdData(requestObject), customData: { request: requestObject } }; // Init response (CommonMediaLibrary.request.CommoneMediaResponse) httpResponse = { request: httpRequest, resourceTiming: { startTime: Date.now(), encodedBodySize: 0 } }; // Adds the ability to delay single fragment loading time to control buffer. let now = new Date().getTime(); if (isNaN(requestObject.delayLoadingTime) || now &gt;= requestObject.delayLoadingTime) { // no delay - just send httpRequests.push(httpRequest); return _loadRequest(loader, httpRequest, httpResponse); } else { // delay let delayedRequest = { httpRequest, httpResponse }; 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; httpRequests.push(delayedRequest.httpRequest); _loadRequest(loader, delayedRequest.httpRequest, delayedRequest.httpResponse); } catch (e) { delayedRequest.httpRequest.onerror(); } }, (requestObject.delayLoadingTime - now)); return Promise.resolve(); } } function _applyRequestInterceptors(httpRequest) { const interceptors = customParametersModel.getRequestInterceptors(); if (!interceptors) return Promise.resolve(httpRequest); return interceptors.reduce((prev, next) =&gt; { return prev.then((request) =&gt; { return next(request); }); }, Promise.resolve(httpRequest)); } function _applyResponseInterceptors(response) { const interceptors = customParametersModel.getResponseInterceptors(); if (!interceptors) return Promise.resolve(response); return interceptors.reduce((prev, next) =&gt; { return prev.then(resp =&gt; { return next(resp); }); }, Promise.resolve(response)); } function _addHttpRequestMetric(httpRequest, httpResponse, traces) { const requestObject = httpRequest.customData.request; const cmsd = settings.get().streaming.cmsd &amp;&amp; settings.get().streaming.cmsd.enabled ? cmsdModel.parseResponseHeaders(httpResponse.headers, requestObject.mediaType) : null; dashMetrics.addHttpRequest(requestObject, httpResponse.url, httpResponse.status, httpResponse.headers, traces, cmsd); } /** * Adds the values from the Resource Timing API, see https://developer.mozilla.org/en-US/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API * @param requestObject * @private */ function _addResourceTimingValues(httpRequest, httpResponse) { if (!settings.get().streaming.abr.throughput.useResourceTimingApi) { return; } // Check performance support. We do not support range requests, needs to figure out how to find the right resource here. if (typeof performance === 'undefined' || httpRequest.range) { return; } // Get a list of \"resource\" performance entries const resources = performance.getEntriesByType('resource'); if (resources === undefined || resources.length &lt;= 0) { return; } // Find the right resource let i = 0; let resource = null; while (i &lt; resources.length) { if (resources[i].name === httpRequest.url) { resource = resources[i]; break; } i += 1; } // Check if PerformanceResourceTiming values are usable // Note: to allow seeing cross-origin timing information, the Timing-Allow-Origin HTTP response header needs to be set // See https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming#cross-origin_timing_information if (!_areResourceTimingValuesUsable(resource)) { return; } httpRequest.customData.request.resourceTimingValues = resource; // Update CommonMediaResponse Resource Timing info httpResponse.resourceTiming.startTime = resource.startTime; httpResponse.resourceTiming.encodedBodySize = resource.encodedBodySize; httpResponse.resourceTiming.responseStart = resource.startTime; httpResponse.resourceTiming.responseEnd = resource.responseEnd; httpResponse.resourceTiming.duration = resource.duration; } /** * Checks if we got usable ResourceTimingAPI values * @param httpRequest * @returns {boolean} * @private */ function _areResourceTimingValuesUsable(resource) { return resource &amp;&amp; !isNaN(resource.responseStart) &amp;&amp; resource.responseStart &gt; 0 &amp;&amp; !isNaN(resource.responseEnd) &amp;&amp; resource.responseEnd &gt; 0 &amp;&amp; !isNaN(resource.transferSize) &amp;&amp; resource.transferSize &gt; 0 } /** * Returns either the FetchLoader or the XHRLoader depending on the request type and playback mode. * @param {object} request * @return {*} * @private */ function _getLoader(request) { let loader; let fileLoaderType; 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) { if (!fetchLoader) { fetchLoader = FetchLoader(context).create(); fetchLoader.setConfig({ dashMetrics, boxParser }); } loader = fetchLoader; fileLoaderType = Constants.FILE_LOADER_TYPES.FETCH; } else { if (!xhrLoader) { xhrLoader = XHRLoader(context).create(); } loader = xhrLoader; fileLoaderType = Constants.FILE_LOADER_TYPES.XHR; } return { loader, fileLoaderType }; } /** * Updates the request url and headers according to CMCD and content steering (pathway cloning) * @param request * @private */ function _updateRequestUrlAndHeaders(request) { 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); request.url = Utils.addAditionalQueryParameterToUrl(request.url, additionalQueryParameter); } else if (cmcdMode === Constants.CMCD_MODE_HEADER) { request.headers = Object.assign(request.headers, cmcdModel.getHeaderParameters(request)); } } // Add queryParams that came from pathway cloning if (request.queryParams) { const queryParams = Object.keys(request.queryParams).map((key) =&gt; { return { key, value: request.queryParams[key] } }) request.url = Utils.addAditionalQueryParameterToUrl(request.url, queryParams); } } /** * Generates the additional query parameters to be appended to the request url * @param {object} request * @return {array} * @private */ function _getAdditionalQueryParameter(request) { try { const additionalQueryParameter = []; const cmcdQueryParameter = cmcdModel.getQueryParameter(request); if (cmcdQueryParameter) { additionalQueryParameter.push(cmcdQueryParameter); } return additionalQueryParameter; } catch (e) { return []; } } /** * 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 = []; httpRequests.forEach(req =&gt; { const reqData = req.customData if (!reqData) { return } // MSS patch: ignore FragmentInfo requests if (reqData.request &amp;&amp; reqData.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 reqData.onloadend = reqData.onerror = reqData.onprogress = undefined; if (reqData.abort) { reqData.abort(); } }); httpRequests = []; } instance = { load, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import OfflineStoreController from './OfflineStoreController.js'; import OfflineDownload from '../OfflineDownload.js'; import IndexDBOfflineLoader from '../net/IndexDBOfflineLoader.js'; import OfflineUrlUtils from '../utils/OfflineUrlUtils.js'; import OfflineEvents from '../events/OfflineEvents.js'; import OfflineErrors from '../errors/OfflineErrors.js'; import OfflineRecord from '../vo/OfflineDownloadVo.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import MediaCapability from '../vo/MediaCapability.js'; import KeySystemConfiguration from '../vo/KeySystemConfiguration.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; import DashJSError from '../../vo/DashJSError.js'; import LicenseRequest from '../vo/LicenseRequest.js'; import LicenseResponse from '../vo/LicenseResponse.js'; import {HTTPRequest} from '../../vo/metrics/HTTPRequest.js'; import Utils from '../../../core/Utils.js'; import Constants from '../../constants/Constants.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; 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 * @private */ 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import KeySystemClearKey from './../drm/KeySystemClearKey.js'; import KeySystemW3CClearKey from './../drm/KeySystemW3CClearKey.js'; import KeySystemWidevine from './../drm/KeySystemWidevine.js'; import KeySystemPlayReady from './../drm/KeySystemPlayReady.js'; import DRMToday from './../servers/DRMToday.js'; import PlayReady from './../servers/PlayReady.js'; import Widevine from './../servers/Widevine.js'; import ClearKey from './../servers/ClearKey.js'; import ProtectionConstants from '../../constants/ProtectionConstants.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Utils from './Utils.js'; import Debug from '../core/Debug.js'; import Constants from '../streaming/constants/Constants.js'; import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest.js'; import EventBus from './EventBus.js'; import Events from './events/Events.js'; /** @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: false, * applyServiceDescription: true, * applyProducerReferenceTime: true, * applyContentSteering: true, * eventControllerRefreshDelay: 100, * enableManifestDurationMismatchFix: true, * parseInbandPrft: false, * enableManifestTimescaleMismatchFix: false, * 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, * bufferTimeDefault: 18, * longFormContentDurationThreshold: 600, * stallThreshold: 0.3, * useAppendWindow: true, * setStallState: true, * avoidCurrentTimeRangePruning: false, * useChangeTypeForTrackSwitch: true * }, * 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: 500, * lowLatencyTimeout: 0, * scheduleWhilePaused: true * }, * text: { * defaultEnabled: true, * extendSegmentedCues: true, * webvtt: { * customRenderingEnabled: false * } * }, * liveCatchup: { * maxDrift: NaN, * playbackRate: {min: NaN, max: NaN}, * playbackBufferMin: 0.5, * enabled: null, * mode: Constants.LIVE_CATCHUP_MODE_DEFAULT * }, * lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, * lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, * saveLastMediaSettingsForCurrentStreamingSession: true, * 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, * fragmentRequestProgressTimeout: -1, * manifestRequestTimeout: 10000, * 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: { * limitBitrateByPortal: false, * usePixelRatioInLimitBitrateByPortal: false, * rules: { * throughputRule: { * active: true * }, * bolaRule: { * active: true * }, * insufficientBufferRule: { * active: true, * parameters: { * throughputSafetyFactor: 0.7, * segmentIgnoreCount: 2 * } * }, * switchHistoryRule: { * active: true, * parameters: { * sampleSize: 8, * switchPercentageThreshold: 0.075 * } * }, * droppedFramesRule: { * active: true, * parameters: { * minimumSampleSize: 375, * droppedFramesPercentageThreshold: 0.15 * } * }, * abandonRequestsRule: { * active: true, * parameters: { * abandonDurationMultiplier: 1.8, * minSegmentDownloadTimeThresholdInMs: 500, * minThroughputSamplesThreshold: 6 * } * }, * l2ARule: { * active: false * }, * loLPRule: { * active: false * } * }, * throughput: { * averageCalculationMode: Constants.THROUGHPUT_CALCULATION_MODES.EWMA, * lowLatencyDownloadTimeCalculationMode: Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING, * useResourceTimingApi: true, * useNetworkInformationApi: { * xhr: false, * fetch: true * }, * useDeadTimeLatency: true, * bandwidthSafetyFactor: 0.9, * sampleSettings: { * live: 3, * vod: 4, * enableSampleSizeAdjustment: true, * decreaseScale: 0.7, * increaseScale: 1.3, * maxMeasurementsToKeep: 20, * averageLatencySampleAmount: 4, * }, * ewma: { * throughputSlowHalfLifeSeconds: 8, * throughputFastHalfLifeSeconds: 3, * latencySlowHalfLifeCount: 2, * latencyFastHalfLifeCount: 1 * } * }, * maxBitrate: { * audio: -1, * video: -1 * }, * minBitrate: { * audio: -1, * video: -1 * }, * initialBitrate: { * audio: -1, * video: -1 * }, * autoSwitchBitrate: { * audio: true, * video: true * } * }, * 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'] * }, * cmsd: { * enabled: false, * abr: { * applyMb: false, * etpWeightRatio: 0 * } * }, * defaultSchemeIdUri: { * viewpoint: '', * audioChannelConfiguration: 'urn:mpeg:mpegB:cicp:ChannelConfiguration', * role: 'urn:mpeg:dash:role:2011', * accessibility: 'urn:mpeg:dash:role:2011' * } * }, * 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=NaN] * 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} [bufferTimeDefault=18] * The time that the internal buffer target will be set to when not playing at the top quality. * @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} [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. * @property {boolean} [useChangeTypeForTrackSwitch=true] * If this flag is set to true then dash.js will use the MSE v.2 API call \"changeType()\" before switching to a different track. * Note that some platforms might not implement the changeType functio. dash.js is checking for the availability before trying to call it. */ /** * @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=500] * Default timeout between two consecutive segment scheduling attempts * @property {number} [lowLatencyTimeout=0] * 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 {boolean} [defaultEnabled=true] * Enable/disable subtitle rendering by default. * @property {boolean} [extendSegmentedCues=true] * Enable/disable patching of segmented cues in order to merge as a single cue by extending cue end time. * @property {object} [webvtt={customRenderingEnabled=false}] * Enables the custom rendering for WebVTT captions. For details refer to the \"Subtitles and Captions\" sample section of dash.js. * Custom WebVTT rendering requires the external library vtt.js that can be found in the contrib folder. */ /** * @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={min: NaN, max: NaN}] * Use this parameter to set the minimum and maximum catch up rates, as percentages, 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 min catch up rate are in the range -0.5 to 0 (-50% to 0% playback rate decrease) * * Valid values for max catch up rate are in the range 0 to 1 (0% to 100% playback rate increase). * * Set min and max to NaN to turn off live catch up feature. * * These playback rate limits take precedence over any PlaybackRate values in ServiceDescription elements in an MPD. If only one of the min/max properties is given a value, the property without a value will not fall back to a ServiceDescription value. Its default value of NaN will be used. * * Note: Catch-up mechanism is only applied when playing low latency live streams. * @property {number} [playbackBufferMin=0.5] * Use this parameter to specify the minimum buffer which is used for LoL+ based playback rate reduction. * * * @property {boolean} [enabled=null] * 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=false] * If set to true the player will ignore \"encrypted\" and \"needkey\" events thrown by the EME. * * @property {boolean} [detectPlayreadyMessageFormat=true] * 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 {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~AbrRules} [rules] * Enable/Disable individual ABR rules. Note that if the throughputRule and the bolaRule are activated at the same time we switch to a dynamic mode. * In the dynamic mode either ThroughputRule or BolaRule are active but not both at the same time. * * l2ARule and loLPRule are ABR rules that are designed for low latency streams. They are tested as standalone rules meaning the other rules should be deactivated when choosing these rules. * @property {module:Settings~ThroughputSettings} [throughput] * Settings related to throughput calculation * @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} [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} [autoSwitchBitrate={audio: true, video: true}] * Indicates whether the player should enable ABR algorithms to switch the bitrate. */ /** * @typedef {Object} AbrRules * @property {module:Settings~ThroughputRule} [throughputRule] * Configuration of the Throughput rule * @property {module:Settings~BolaRule} [bolaRule] * Configuration of the BOLA rule * @property {module:Settings~InsufficientBufferRule} [insufficientBufferRule] * Configuration of the Insufficient Buffer rule * @property {module:Settings~SwitchHistoryRule} [switchHistoryRule] * Configuration of the Switch History rule * @property {module:Settings~DroppedFramesRule} [droppedFramesRule] * Configuration of the Dropped Frames rule * @property {module:Settings~AbandonRequestsRule} [abandonRequestsRule] * Configuration of the Abandon Requests rule * @property {module:Settings~L2ARule} [l2ARule] * Configuration of the L2A rule * @property {module:Settings~LoLPRule} [loLPRule] * Configuration of the LoLP rule */ /** * @typedef {Object} ThroughputRule * @property {boolean} [active=true] * Enable or disable the rule */ /** * @typedef {Object} BolaRule * @property {boolean} [active=true] * Enable or disable the rule */ /** * @typedef {Object} InsufficientBufferRule * @property {boolean} [active=true] * Enable or disable the rule * @property {object} [parameters={throughputSafetyFactor=0.7, segmentIgnoreCount=2}] * Configures the rule specific parameters. * * - `throughputSafetyFactor`: The safety factor that is applied to the derived throughput, see example in the Description. * - `segmentIgnoreCount`: This rule is not taken into account until the first segmentIgnoreCount media segments have been appended to the buffer. */ /** * @typedef {Object} SwitchHistoryRule * @property {boolean} [active=true] * Enable or disable the rule * @property {object} [parameters={sampleSize=8, switchPercentageThreshold=0.075}] * Configures the rule specific parameters. * * - `sampleSize`: Number of switch requests (\"no switch\", because of the selected Representation is already playing or \"actual switches\") required before the rule is applied * - `switchPercentageThreshold`: Ratio of actual quality drops compared to no drops before a quality down-switch is triggered */ /** * @typedef {Object} DroppedFramesRule * @property {boolean} [active=true] * Enable or disable the rule * @property {object} [parameters={minimumSampleSize=375, droppedFramesPercentageThreshold=0.15}] * Configures the rule specific parameters. * * - `minimumSampleSize`: Sum of rendered and dropped frames required for each Representation before the rule kicks in. * - `droppedFramesPercentageThreshold`: Minimum percentage of dropped frames to trigger a quality down switch. Values are defined in the range of 0 - 1. */ /** * @typedef {Object} AbandonRequestsRule * @property {boolean} [active=true] * Enable or disable the rule * @property {object} [parameters={abandonDurationMultiplier=1.8, minSegmentDownloadTimeThresholdInMs=500, minThroughputSamplesThreshold=6}] * Configures the rule specific parameters. * * - `abandonDurationMultiplier`: Factor to multiply with the segment duration to compare against the estimated remaining download time of the current segment. See code example above. * - `minSegmentDownloadTimeThresholdInMs`: The AbandonRequestRule only kicks if the download time of the current segment exceeds this value. * - `minThroughputSamplesThreshold`: Minimum throughput samples (equivalent to number of progress events) required before the AbandonRequestRule kicks in. */ /** * @typedef {Object} L2ARule * @property {boolean} [active=true] * Enable or disable the rule */ /** * @typedef {Object} LoLPRule * @property {boolean} [active=true] * Enable or disable the rule */ /** * @typedef {Object} ThroughputSettings * @property {string} [averageCalculationMode=Constants.THROUGHPUT_CALCULATION_MODES.EWMA] * Defines the default mode for calculating the throughput based on the samples collected during playback. * * For arithmetic and harmonic mean calculations we use a sliding window with the values defined in \"sampleSettings\" * * For exponential weighted moving average calculation the default values can be changed in \"ewma\" * @property {string} [lowLatencyDownloadTimeCalculationMode=Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING] * Defines the effective download time estimation method we use for low latency streams that utilize the Fetch API and chunked transfer coding * @property {boolean} [useResourceTimingApi=true] * If set to true the ResourceTimingApi is used to derive the download time and the number of downloaded bytes. * This option has no effect for low latency streaming as the download time equals the segment duration in most of the cases and therefor does not provide reliable values * @property {object} [useNetworkInformationApi = { xhr=false, fetch=true}] * If set to true the NetworkInformationApi is used to derive the current throughput. Browser support is limited, only available in Chrome and Edge. * Applies to standard (XHR requests) and/or low latency streaming (Fetch API requests). * @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 {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 {object} [sampleSettings = {live=3,vod=4,enableSampleSizeAdjustment=true,decreaseScale=0.7,increaseScale=1.3,maxMeasurementsToKeep=20,averageLatencySampleAmount=4}] * When deriving the throughput based on the arithmetic or harmonic mean these settings define: * - `live`: Number of throughput samples to use (sample size) for live streams * - `vod`: Number of throughput samples to use (sample size) for VoD streams * - `enableSampleSizeAdjustment`: Adjust the sample sizes if throughput samples vary a lot * - `decreaseScale`: Increase sample size by one if the ratio of current and previous sample is below or equal this value * - `increaseScale`: Increase sample size by one if the ratio of current and previous sample is higher or equal this value * - `maxMeasurementsToKeep`: Number of samples to keep before sliding samples out of the window * - `averageLatencySampleAmount`: Number of latency samples to use (sample size) * @property {object} [ewma={throughputSlowHalfLifeSeconds=8,throughputFastHalfLifeSeconds=3,latencySlowHalfLifeCount=2,latencyFastHalfLifeCount=1}] * When deriving the throughput based on the exponential weighted moving average these settings define: * - `throughputSlowHalfLifeSeconds`: Number by which the weight of the current throughput measurement is divided, see ThroughputModel._updateEwmaValues * - `throughputFastHalfLifeSeconds`: Number by which the weight of the current throughput measurement is divided, see ThroughputModel._updateEwmaValues * - `latencySlowHalfLifeCount`: Number by which the weight of the current latency is divided, see ThroughputModel._updateEwmaValues * - `latencyFastHalfLifeCount`: Number by which the weight of the current latency is divided, see ThroughputModel._updateEwmaValues */ /** * @typedef {Object} 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=5] * 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=\"query\"] * 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} module:Settings~CmsdSettings * @property {boolean} [enabled=false] * Enable or disable the CMSD response headers parsing. * @property {module:Settings~CmsdAbrSettings} [abr] * Sets additional ABR rules based on CMSD response headers. */ /** * @typedef {Object} CmsdAbrSettings * @property {boolean} [applyMb=false] * Set to true if dash.js should apply CMSD maximum suggested bitrate in ABR logic. * @property {number} [etpWeightRatio=0] * Sets the weight ratio (between 0 and 1) that shall be applied on CMSD estimated throuhgput compared to measured throughput when calculating throughput. */ /** * @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=100] * 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=false] * 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] * Overwrite the manifest segments base information timescale attributes with the timescale set in initialization segments * @property {boolean} [enableManifestTimescaleMismatchFix=false] * Defines the delay in milliseconds between two consecutive checks for events to be fired. * @property {boolean} [parseInbandPrft=false] * Set to true if dash.js should parse inband prft boxes (ProducerReferenceTime) and trigger events. * @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~CachingInfoSettings} [lastMediaSettingsCachingInfo={enabled: true, ttl: 360000}] * Set to false if you would like to disable the last media settings from being stored to localStorage during playback and used to set the initial track for subsequent playback within the expiration window. * * The default expiration is one hour, defined in milliseconds. * @property {boolean} [saveLastMediaSettingsForCurrentStreamingSession=true] * Set to true if dash.js should save media settings from last selected track for incoming track selection during current streaming 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=\"highestSelectionPriority\"] * 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=20000] * Time in milliseconds before timing out on loading a media fragment. * * @property {number} [fragmentRequestProgressTimeout=-1] * Time in milliseconds before timing out on loading progress of a media fragment. * * @property {number} [manifestRequestTimeout=10000] * Time in milliseconds before timing out on loading a manifest. * * Fragments that timeout are retried as if they failed. * @property {module:Settings~RequestTypeSettings} [retryIntervals] * Time in milliseconds of which to reload a failed file load attempt. * * For low latency mode these values are divided by lowLatencyReductionFactor. * @property {module:Settings~RequestTypeSettings} [retryAttempts] * Total number of retry attempts that will occur on a file load before it fails. * * For low latency mode these values are multiplied by lowLatencyMultiplyFactor. * @property {module:Settings~AbrSettings} abr * Adaptive Bitrate algorithm related settings. * @property {module:Settings~CmcdSettings} cmcd * Settings related to Common Media Client Data reporting. * @property {module:Settings~CmsdSettings} cmsd * Settings related to Common Media Server Data parsing. * @property {module:Settings~defaultSchemeIdUri} defaultSchemeIdUri * Default schemeIdUri for descriptor type elements * These strings are used when not provided with setInitialMediaSettingsFor() */ /** * @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, 'streaming.liveCatchup.playbackRate.min': Events.SETTING_UPDATED_PLAYBACK_RATE_MIN, 'streaming.liveCatchup.playbackRate.max': Events.SETTING_UPDATED_PLAYBACK_RATE_MAX, 'streaming.abr.rules.throughputRule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, 'streaming.abr.rules.bolaRule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, 'streaming.abr.rules.insufficientBufferRule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, 'streaming.abr.rules.switchHistoryRule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, 'streaming.abr.rules.droppedFramesRule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, 'streaming.abr.rules.abandonRequestsRule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, 'streaming.abr.rules.l2ARule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, 'streaming.abr.rules.loLPRule.active': Events.SETTING_UPDATED_ABR_ACTIVE_RULES, }; /** * @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, parseInbandPrft: false, enableManifestTimescaleMismatchFix: false, 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, bufferTimeDefault: 18, longFormContentDurationThreshold: 600, stallThreshold: 0.3, useAppendWindow: true, setStallState: true, avoidCurrentTimeRangePruning: false, useChangeTypeForTrackSwitch: true }, 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, extendSegmentedCues: true, webvtt: { customRenderingEnabled: false } }, liveCatchup: { maxDrift: NaN, playbackRate: { min: NaN, max: NaN }, playbackBufferMin: 0.5, enabled: null, mode: Constants.LIVE_CATCHUP_MODE_DEFAULT }, lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, saveLastMediaSettingsForCurrentStreamingSession: true, 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, fragmentRequestProgressTimeout: -1, manifestRequestTimeout: 10000, 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: { limitBitrateByPortal: false, usePixelRatioInLimitBitrateByPortal: false, enableSupplementalPropertyAdaptationSetSwitching: true, rules: { throughputRule: { active: true }, bolaRule: { active: true }, insufficientBufferRule: { active: true, parameters: { throughputSafetyFactor: 0.7, segmentIgnoreCount: 2 } }, switchHistoryRule: { active: true, parameters: { sampleSize: 8, switchPercentageThreshold: 0.075 } }, droppedFramesRule: { active: true, parameters: { minimumSampleSize: 375, droppedFramesPercentageThreshold: 0.15 } }, abandonRequestsRule: { active: true, parameters: { abandonDurationMultiplier: 1.8, minSegmentDownloadTimeThresholdInMs: 500, minThroughputSamplesThreshold: 6 } }, l2ARule: { active: false }, loLPRule: { active: false } }, throughput: { averageCalculationMode: Constants.THROUGHPUT_CALCULATION_MODES.EWMA, lowLatencyDownloadTimeCalculationMode: Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING, useResourceTimingApi: true, useNetworkInformationApi: { xhr: false, fetch: true }, useDeadTimeLatency: true, bandwidthSafetyFactor: 0.9, sampleSettings: { live: 3, vod: 4, enableSampleSizeAdjustment: true, decreaseScale: 0.7, increaseScale: 1.3, maxMeasurementsToKeep: 20, averageLatencySampleAmount: 4, }, ewma: { throughputSlowHalfLifeSeconds: 8, throughputFastHalfLifeSeconds: 3, latencySlowHalfLifeCount: 2, latencyFastHalfLifeCount: 1, weightDownloadTimeMultiplicationFactor: 0.0015 } }, maxBitrate: { audio: -1, video: -1 }, minBitrate: { audio: -1, video: -1 }, initialBitrate: { audio: -1, video: -1 }, autoSwitchBitrate: { audio: true, video: true } }, 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'] }, cmsd: { enabled: false, abr: { applyMb: false, etpWeightRatio: 0 } }, defaultSchemeIdUri: { viewpoint: '', audioChannelConfiguration: 'urn:mpeg:mpegB:cicp:ChannelConfiguration', role: 'urn:mpeg:dash:role:2011', accessibility: 'urn:mpeg:dash:role:2011' } }, 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_utils_TimeUtils.js.html":{"id":"streaming_utils_TimeUtils.js.html","title":"Source: streaming/utils/TimeUtils.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/TimeUtils.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.js'; /** * @module TimeUtils * @ignore * @description Provides utility functions for time manipulation/conversion */ function TimeUtils() { let instance; /** * Convert NTP timestamp into an UTC timestamp * @return {number} * @param {number} ntpTimestamp * @memberof module:TimeUtils * @instance */ function ntpToUTC(ntpTimeStamp) { const start = new Date(Date.UTC(1900, 0, 1, 0, 0, 0)); return new Date(start.getTime() + ntpTimeStamp).getTime(); } instance = { ntpToUTC }; return instance; } TimeUtils.__dashjs_factory_name = 'TimeUtils'; export default FactoryMaker.getSingletonFactory(TimeUtils); × 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; /** * 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import DefaultURLUtils from './DefaultURLUtils.js'; /** * @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 "},"streaming_net_XHRLoader.js.html":{"id":"streaming_net_XHRLoader.js.html","title":"Source: streaming/net/XHRLoader.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/XHRLoader.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.js'; import Utils from '../../core/Utils.js'; /** * @module XHRLoader * @ignore * @description Manages download of resources via HTTP. */ function XHRLoader() { let instance; let xhr; /** * Load request * @param {CommonMediaLibrary.request.CommonMediaRequest} httpRequest * @param {CommonMediaLibrary.request.CommonMediaResponse} httpResponse */ function load(httpRequest, httpResponse) { xhr = new XMLHttpRequest(); xhr.open(httpRequest.method, httpRequest.url, true); if (httpRequest.responseType) { xhr.responseType = httpRequest.responseType; } if (httpRequest.headers) { for (let header in httpRequest.headers) { let value = httpRequest.headers[header]; if (value) { xhr.setRequestHeader(header, value); } } } xhr.withCredentials = httpRequest.credentials === 'include'; xhr.timeout = httpRequest.timeout; xhr.onload = function(e) { httpResponse.url = this.responseURL; httpResponse.status = this.status; httpResponse.statusText = this.statusText; httpResponse.headers = Utils.parseHttpHeaders(this.getAllResponseHeaders()); httpResponse.data = this.response; httpRequest.customData.onload(e); } xhr.onloadend = httpRequest.customData.onloadend; xhr.onerror = httpRequest.customData.onerror; xhr.onprogress = httpRequest.customData.onprogress; xhr.onabort = httpRequest.customData.onabort; xhr.ontimeout = httpRequest.customData.ontimeout; xhr.send(); httpRequest.customData.abort = abort.bind(this); return true; } function abort() { xhr.onloadend = xhr.onerror = xhr.onprogress = null; // Ignore events from aborted requests. xhr.abort(); } function getXhr() { return xhr } instance = { load, abort, getXhr }; return instance; } XHRLoader.__dashjs_factory_name = 'XHRLoader'; const factory = FactoryMaker.getClassFactory(XHRLoader); 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import OfflineStream from './OfflineStream.js'; import OfflineIndexDBManifestParser from './utils/OfflineIndexDBManifestParser.js'; import OfflineErrors from './errors/OfflineErrors.js'; import DashParser from '../dash/parser/DashParser.js'; 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); // initialize 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.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) // initialize 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 */ import {XmlEntities as Entities} from 'html-entities'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import RepresentationController from '../dash/controllers/RepresentationController.js'; import FragmentModel from '../streaming/models/FragmentModel.js'; import FragmentLoader from '../streaming/FragmentLoader.js'; import URLUtils from '../streaming/utils/URLUtils.js'; import SegmentsController from '../dash/controllers/SegmentsController.js'; 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, 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, 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.find((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(voRepresentations, mediaInfo.isFragmented, quality.id); } 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Debug from '../../core/Debug.js'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js'; import MetricsConstants from '../constants/MetricsConstants.js'; 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.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.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 || !videoModel.getElement()) 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 voRepresentation = e.currentRepresentation; const info = voRepresentation ? voRepresentation.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 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.find(item =&gt; item.schemeIdUri === Constants.SUPPLEMENTAL_PROPERTY_DVB_LL_SCHEME)) { 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FactoryMaker from '../core/FactoryMaker.js'; /** * 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 }); } return Promise.resolve(); } 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. return Promise.resolve(); } //Nothing async, nothing to abort. function abort() { return Promise.resolve(); } 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() { return Promise.resolve(); } 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, append, remove, abort, discharge, reset, updateTimestampOffset, waitForUpdateEnd, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * @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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; /** * @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 * @event ProtectionEvents#KEY_SYSTEM_ACCESS_COMPLETE */ 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import NeedKey from '../vo/NeedKey.js'; import DashJSError from '../../vo/DashJSError.js'; import KeyMessage from '../vo/KeyMessage.js'; import KeySystemConfiguration from '../vo/KeySystemConfiguration.js'; import KeySystemAccess from '../vo/KeySystemAccess.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import NeedKey from '../vo/NeedKey.js'; import DashJSError from '../../vo/DashJSError.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; import KeyMessage from '../vo/KeyMessage.js'; import KeySystemConfiguration from '../vo/KeySystemConfiguration.js'; import KeySystemAccess from '../vo/KeySystemAccess.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import NeedKey from '../vo/NeedKey.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; import DashJSError from '../../vo/DashJSError.js'; import KeyMessage from '../vo/KeyMessage.js'; import KeySystemAccess from '../vo/KeySystemAccess.js'; import ProtectionConstants from '../../constants/ProtectionConstants.js'; 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) { _closeKeySessionInternal(session) 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) 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) { if (!sessionToken || !sessionToken.session) { return Promise.resolve; } 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import ProtectionKeyController from './controllers/ProtectionKeyController.js'; import ProtectionEvents from './ProtectionEvents.js'; import ProtectionErrors from './errors/ProtectionErrors.js'; import ProtectionModel_21Jan2015 from './models/ProtectionModel_21Jan2015.js'; import ProtectionModel_3Feb2014 from './models/ProtectionModel_3Feb2014.js'; import ProtectionModel_01b from './models/ProtectionModel_01b.js'; 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 "},"dash_controllers_RepresentationController.js.html":{"id":"dash_controllers_RepresentationController.js.html","title":"Source: dash/controllers/RepresentationController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/RepresentationController.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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js'; import {getTimeBasedSegment} from '../utils/SegmentsUtils.js'; function RepresentationController(config) { config = config || {}; const eventBus = config.eventBus; const events = config.events; const abrController = config.abrController; const dashMetrics = config.dashMetrics; const playbackController = config.playbackController; const timelineConverter = config.timelineConverter; const type = config.type; const streamInfo = config.streamInfo; const segmentsController = config.segmentsController; const isDynamic = config.isDynamic; let instance, voAvailableRepresentations, currentVoRepresentation; function setup() { resetInitialSettings(); eventBus.on(MediaPlayerEvents.MANIFEST_VALIDITY_CHANGED, onManifestValidityChanged, instance); } function getStreamId() { return streamInfo.id; } function getType() { return type; } function checkConfig() { if (!abrController || !dashMetrics || !playbackController || !timelineConverter) { throw new Error(Constants.MISSING_CONFIG_ERROR); } } function getCurrentRepresentation() { return currentVoRepresentation; } function resetInitialSettings() { voAvailableRepresentations = []; } function reset() { eventBus.off(MediaPlayerEvents.MANIFEST_VALIDITY_CHANGED, onManifestValidityChanged, instance); resetInitialSettings(); } function updateData(availableRepresentations, isFragmented, selectedRepresentationId) { return new Promise((resolve, reject) =&gt; { voAvailableRepresentations = availableRepresentations; const selectedRepresentation = getRepresentationById(selectedRepresentationId); _setCurrentVoRepresentation(selectedRepresentation); if (type !== Constants.VIDEO &amp;&amp; type !== Constants.AUDIO &amp;&amp; (type !== Constants.TEXT || !isFragmented)) { endDataUpdate(); resolve(); return; } const promises = []; for (let i = 0, ln = voAvailableRepresentations.length; i &lt; ln; i++) { const currentRep = voAvailableRepresentations[i]; promises.push(_updateRepresentation(currentRep)); } Promise.all(promises) .then(() =&gt; { _onAllRepresentationsUpdated(); resolve(); }) .catch((e) =&gt; { reject(e); }) }) } function _onAllRepresentationsUpdated() { abrController.setPlaybackQuality(type, streamInfo, currentVoRepresentation); const dvrInfo = dashMetrics.getCurrentDVRInfo(type); if (dvrInfo) { dashMetrics.updateManifestUpdateInfo({ latency: dvrInfo.range.end - playbackController.getTime() }); } endDataUpdate(); } function _updateRepresentation(currentRep) { return new Promise((resolve, reject) =&gt; { const hasInitialization = currentRep.hasInitialization(); const hasSegments = currentRep.hasSegments(); // If representation has initialization and segments information we are done // otherwise, it means that a request has to be made to get initialization and/or segments information const promises = []; promises.push(segmentsController.updateInitData(currentRep, hasInitialization)); promises.push(segmentsController.updateSegmentData(currentRep, hasSegments)); Promise.all(promises) .then((data) =&gt; { if (data[0] &amp;&amp; !data[0].error) { currentRep = _onInitLoaded(currentRep, data[0]); } if (data[1] &amp;&amp; !data[1].error) { currentRep = _onSegmentsLoaded(currentRep, data[1]); } currentRep.fragmentDuration = currentRep.segmentDuration ? currentRep.segmentDuration : currentRep.segments &amp;&amp; currentRep.segments.length &gt; 0 ? currentRep.segments[0].duration : NaN; _setMediaFinishedInformation(currentRep); _onRepresentationUpdated(currentRep); resolve(); }) .catch((e) =&gt; { reject(e); }); }); } function _setMediaFinishedInformation(representation) { representation.mediaFinishedInformation = segmentsController.getMediaFinishedInformation(representation); } function _onInitLoaded(representation, e) { if (!e || e.error || !e.representation) { return representation; } return e.representation; } function _onSegmentsLoaded(representation, e) { if (!e || e.error) return; const fragments = e.segments; const segments = []; let count = 0; let i, len, s, seg; for (i = 0, len = fragments ? fragments.length : 0; i &lt; len; i++) { s = fragments[i]; seg = getTimeBasedSegment( timelineConverter, isDynamic, representation, s.startTime, s.duration, s.timescale, s.media, s.mediaRange, count); if (seg) { segments.push(seg); seg = null; count++; } } if (segments.length &gt; 0) { representation.segments = segments; } return representation; } function _addRepresentationSwitch(currentRepresentation) { checkConfig(); const now = new Date(); const currentVideoTimeMs = playbackController.getTime() * 1000; if (currentRepresentation) { dashMetrics.addRepresentationSwitch(currentRepresentation.adaptation.type, now, currentVideoTimeMs, currentRepresentation.id); } eventBus.trigger(MediaPlayerEvents.REPRESENTATION_SWITCH, { mediaType: type, streamId: streamInfo.id, currentRepresentation, }, { streamId: streamInfo.id, mediaType: type }) } function getRepresentationById(id) { if (!voAvailableRepresentations || voAvailableRepresentations.length === 0) { return null; } const reps = voAvailableRepresentations.filter((rep) =&gt; { return rep.id === id; }) if (reps.length &gt; 0) { return reps[0] } return null; } function endDataUpdate(error) { eventBus.trigger(events.DATA_UPDATE_COMPLETED, { currentRepresentation: currentVoRepresentation, error: error }, { streamId: streamInfo.id, mediaType: type } ); } function _onRepresentationUpdated(r) { let manifestUpdateInfo = dashMetrics.getCurrentManifestUpdate(); let alreadyAdded = false; let repInfo; if (manifestUpdateInfo) { for (let i = 0; i &lt; manifestUpdateInfo.representationInfo.length; i++) { repInfo = manifestUpdateInfo.representationInfo[i]; if (repInfo.index === r.index &amp;&amp; repInfo.mediaType === getType()) { alreadyAdded = true; break; } } if (!alreadyAdded) { dashMetrics.addManifestUpdateRepresentationInfo(r, getType()); } } } /** * We get the new selected Representation which will not hold the ranges and the segment references in case of SegmentBase. * In any case use the id to find the right Representation instance in our array of Representations. * @param newRep */ function prepareQualityChange(newRep) { const voRepresentations = voAvailableRepresentations.filter((rep) =&gt; { return rep.id === newRep.id; }) if (voRepresentations.length &gt; 0) { _setCurrentVoRepresentation(voRepresentations[0]); } } function _setCurrentVoRepresentation(value) { if (!currentVoRepresentation || currentVoRepresentation.id !== value.id) { _addRepresentationSwitch(value); } currentVoRepresentation = value; } function onManifestValidityChanged(e) { if (e.newDuration) { const representation = getCurrentRepresentation(); if (representation &amp;&amp; representation.adaptation.period) { const period = representation.adaptation.period; period.duration = e.newDuration; } } } instance = { getCurrentRepresentation, getRepresentationById, getStreamId, getType, prepareQualityChange, reset, updateData, }; setup(); return instance; } RepresentationController.__dashjs_factory_name = 'RepresentationController'; export default FactoryMaker.getClassFactory(RepresentationController); × 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FragmentModel from '../models/FragmentModel.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Debug from '../../core/Debug.js'; import MetricsConstants from '../constants/MetricsConstants.js'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; 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 representationController = config.representationController const settings = config.settings; let instance, streamInfo, logger, timeToLoadDelay, scheduleTimeout, hasVideoTrack, lastFragmentRequest, lastInitializedRepresentationId, switchTrack, initSegmentRequired, checkPlaybackQuality; function setup() { logger = Debug(context).getInstance().getLogger(instance); resetInitialSettings(); streamInfo = config.streamInfo; } function initialize(_hasVideoTrack) { hasVideoTrack = _hasVideoTrack; 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 startScheduleTimer(value) { //return if both buffering and playback have ended if (bufferController.getIsBufferingCompleted()) { return; } clearScheduleTimer(); const timeoutValue = !isNaN(value) ? value : 0; scheduleTimeout = setTimeout(schedule, timeoutValue); } function clearScheduleTimer() { if (scheduleTimeout) { clearTimeout(scheduleTimeout); scheduleTimeout = null; } } /** * 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() { const currentRepresentation = representationController.getCurrentRepresentation(); // A quality changed occured or we are switching the AdaptationSet. In that case we need to load a new init segment if (initSegmentRequired || currentRepresentation.id !== lastInitializedRepresentationId || switchTrack) { if (switchTrack) { logger.debug('Switch track for ' + type + ', representation id = ' + currentRepresentation.id); switchTrack = false; } else { logger.debug('Quality has changed, get init request for representationid = ' + currentRepresentation.id); } eventBus.trigger(Events.INIT_FRAGMENT_NEEDED, { representationId: currentRepresentation.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 { const currentRepresentation = representationController.getCurrentRepresentation(); return currentRepresentation &amp;&amp; (lastInitializedRepresentationId == null || switchTrack || _shouldBuffer()); } catch (e) { return false; } } /** * Check if the current buffer level is below our buffer target. * @return {boolean} * @private */ function _shouldBuffer() { const currentRepresentation = representationController.getCurrentRepresentation(); if (!type || !currentRepresentation) { 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; const currentRepresentation = representationController.getCurrentRepresentation(); if (!type || !currentRepresentation) { 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()) { const currentRepresentation = representationController.getCurrentRepresentation(); if (isNaN(currentRepresentation.fragmentDuration)) { // 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 currentRepresentation.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); const currentRepresentation = representationController.getCurrentRepresentation(); // 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(currentRepresentation.fragmentDuration)) { return videoBufferLevel + 1; } else { return Math.max(videoBufferLevel + 1, currentRepresentation.fragmentDuration); } } catch (e) { return 0; } } /** * Determines the generic buffer target, for instance for video tracks or when we got an audio only stream * @return {number} * @private */ function _getGenericBufferTarget() { try { const currentRepresentation = representationController.getCurrentRepresentation(); const streamInfo = currentRepresentation.mediaInfo.streamInfo; if (abrController.isPlayingAtTopQuality(currentRepresentation)) { 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.getBufferTimeDefault(); } } catch (e) { return mediaPlayerModel.getBufferTimeDefault(); } } function setSwitchTrack(value) { switchTrack = value; } function getSwitchTrack() { 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.representation || (item.representation.mediaInfo.type === lastFragmentRequest.representation.mediaInfo.type &amp;&amp; item.representation.mediaInfo.index !== lastFragmentRequest.representation.mediaInfo.index)) &amp;&amp; trigger) { logger.debug(`Track change rendered for streamId ${streamInfo.id} and type ${type}`); eventBus.trigger(Events.TRACK_CHANGE_RENDERED, { mediaType: type, oldMediaInfo: lastFragmentRequest &amp;&amp; lastFragmentRequest.representation &amp;&amp; lastFragmentRequest.representation.mediaInfo ? lastFragmentRequest.representation.mediaInfo : null, newMediaInfo: item.representation.mediaInfo, streamId: streamInfo.id }); } if ((!lastFragmentRequest.representation || (item.representation.id !== lastFragmentRequest.representation.id)) &amp;&amp; trigger) { logger.debug(`Quality change rendered for streamId ${streamInfo.id} and type ${type}`); eventBus.trigger(Events.QUALITY_CHANGE_RENDERED, { mediaType: type, oldRepresentation: lastFragmentRequest.representation ? lastFragmentRequest.representation : null, newRepresentation: item.representation, streamId: streamInfo.id }); } lastFragmentRequest.representation = item.representation } } } 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 setLastInitializedRepresentationId(value) { lastInitializedRepresentationId = value; } function resetInitialSettings() { checkPlaybackQuality = true; timeToLoadDelay = 0; lastInitializedRepresentationId = null; lastFragmentRequest = { representation: null, }; switchTrack = false; initSegmentRequired = false; } function reset() { 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, setTimeToLoadDelay, getTimeToLoadDelay, setSwitchTrack, getSwitchTrack, startScheduleTimer, clearScheduleTimer, reset, getBufferTarget, getPlaybackController, setCheckPlaybackQuality, setInitSegmentRequired, setLastInitializedRepresentationId, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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; /** * Bandwidth of fragment * @public */ this.bandwidth = 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Debug from '../../core/Debug.js'; import Constants from '../../streaming/constants/Constants.js'; import DashConstants from '../constants/DashConstants.js'; 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: { min: NaN, max: NaN }, }, minBitrate: {}, maxBitrate: {}, initialBitrate: {}, contentSteering: null }; 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) { _applyServiceDescriptionPlaybackRate(sd); } if (sd.operatingQuality) { _applyServiceDescriptionOperatingQuality(sd); } if (sd.operatingBandwidth) { _applyServiceDescriptionOperatingBandwidth(sd); } if (sd.contentSteering) { _applyServiceDescriptionContentSteering(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) { // Convert each playback rate into a difference from 1. i.e 0.8 becomes -0.2. const min = sd.playbackRate.min ? (Math.round((sd.playbackRate.min - 1.0) * 1000) / 1000) : NaN; const max = sd.playbackRate.max ? (Math.round((sd.playbackRate.max - 1.0) * 1000) / 1000) : NaN; serviceDescriptionSettings.liveCatchup.playbackRate.min = min; serviceDescriptionSettings.liveCatchup.playbackRate.max = max; logger.debug(`Found latency properties coming from service description: Live catchup min playback rate: ${min}`); logger.debug(`Found latency properties coming from service description: Live catchup max playback rate: ${max}`); } /** * 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); } } /** * Add information about content steering element. Handling is up to the ContentSteeringController * @param {object} sd * @private */ function _applyServiceDescriptionContentSteering(sd) { serviceDescriptionSettings.contentSteering = sd.contentSteering; } /** * 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import DashConstants from '../dash/constants/DashConstants.js'; import StreamProcessor from './StreamProcessor.js'; import FragmentController from './controllers/FragmentController.js'; import ThumbnailController from './thumbnail/ThumbnailController.js'; import EventBus from '../core/EventBus.js'; import Events from '../core/events/Events.js'; import Debug from '../core/Debug.js'; import Errors from '../core/errors/Errors.js'; import FactoryMaker from '../core/FactoryMaker.js'; import DashJSError from './vo/DashJSError.js'; import BoxParser from './utils/BoxParser.js'; import URLUtils from './utils/URLUtils.js'; import BlacklistController from './controllers/BlacklistController.js'; 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 throughputController = config.throughputController; 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, 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.INBAND_EVENTS, onInbandEvents, instance); } /** * Unregister the streaming events */ function unRegisterEvents() { 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); }); }); } 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 _initializeMedia(mediaSource, previousBufferSinks) { return _commonMediaInitialization(mediaSource, previousBufferSinks); } /** * * @param {object} mediaSource * @param {array} previousBufferSinks * @return {Promise&lt;array&gt;} * @private */ function _commonMediaInitialization(mediaSource, previousBufferSinks) { return new Promise((resolve, reject) =&gt; { checkConfig(); _addInlineEvents(); let element = videoModel.getElement(); const promises = []; MEDIA_TYPES.forEach((mediaType) =&gt; { // If we are preloading without a video element we can not start texttrack handling. if (!(mediaType === Constants.TEXT &amp;&amp; !mediaSource) &amp;&amp; (mediaType !== Constants.VIDEO || (!element || (element &amp;&amp; (/^VIDEO$/i).test(element.nodeName))))) { promises.push(_initializeMediaForType(mediaType, mediaSource)); } }); Promise.all(promises) .then(() =&gt; { return _createBufferSinks(previousBufferSinks) }) .then((bufferSinks) =&gt; { 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 { _initializationCompleted(); } if (mediaSource) { // 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); }); }); } /** * We call this function if segments have been preloaded without a video element. Once the video element is attached MSE is available * @param mediaSource * @returns {Promise&lt;unknown&gt;} */ function initializeForTextWithMediaSource(mediaSource) { return new Promise((resolve, reject) =&gt; { _initializeMediaForType(Constants.TEXT, mediaSource) .then(() =&gt; { return createBufferSinkForText() }) .then(() =&gt; { textController.createTracks(streamInfo); resolve() }) .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 Promise.resolve(); } 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.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 Promise.resolve(); } 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 Promise.resolve(); } 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) { // In case of mixed fragmented and embedded text tracks, check if initial selected text track is not an embedded track return streamProcessor.selectMediaInfo((type !== Constants.TEXT || !initialMediaInfo.isEmbedded) ? initialMediaInfo : allMediaForType[0]); } return Promise.resolve(); } 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 {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, throughputController, mediaController, textController, errHandler, settings, boxParser, segmentBlacklistController }); streamProcessor.initialize(mediaSource, hasVideoTrack, isFragmented); streamProcessors.push(streamProcessor); streamProcessor.setMediaInfoArray(allMediaForType); 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); }); }); } function createBufferSinkForText() { const sp = _getProcessorByType(Constants.TEXT); if (sp) { return sp.createBufferSinks() } return Promise.resolve(); } /** * 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) { return new Promise((resolve, reject) =&gt; { const promises = []; for (let i = 0; i &lt; streamProcessors.length;) { if (_isMediaSupported(streamProcessors[i].getMediaInfo())) { promises.push(streamProcessors[i].setMediaSource(mediaSource)); i++; } else { streamProcessors[i].reset(); streamProcessors.splice(i, 1); } } Promise.all(promises) .then(() =&gt; { for (let i = 0; i &lt; streamProcessors.length; i++) { //Adding of new tracks to a stream processor isn't guaranteed by the spec after the METADATA_LOADED state //so do this after the buffers are created above. streamProcessors[i].dischargePreBuffer(); } 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); } resolve(); }) .catch((e) =&gt; { logger.error(e); reject(e); }) }) } function resetInitialSettings(keepBuffers) { deactivate(keepBuffers); isInitialized = false; hasVideoTrack = false; hasAudioTrack = 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 getRepresentationsByType(type) { checkConfig(); if (type === Constants.IMAGE) { if (!thumbnailController) { return []; } return thumbnailController.getPossibleVoRepresentations(); } const mediaInfo = getMediaInfo(type); return abrController.getPossibleVoRepresentations(mediaInfo, true); } /** * @param {string} type * @param {string} id * @returns {Array} * @memberof Stream# */ function getRepresentationForTypeById(type, id) { let possibleVoRepresentations; if (type === Constants.IMAGE) { if (!thumbnailController) { return null; } possibleVoRepresentations = thumbnailController.getPossibleVoRepresentations(); } else { const mediaInfo = getMediaInfo(type); possibleVoRepresentations = abrController.getPossibleVoRepresentations(mediaInfo, true); } if (!possibleVoRepresentations || possibleVoRepresentations.length === 0) { return null } const targetReps = possibleVoRepresentations.filter((rep) =&gt; { return rep.id === id }) return targetReps &amp;&amp; targetReps.length &gt; 0 ? targetReps[0] : null; } /** * @param {string} type * @param {number} index * @returns {Array} * @memberof Stream# */ function getRepresentationForTypeByIndex(type, index) { let possibleVoRepresentations; if (type === Constants.IMAGE) { if (!thumbnailController) { return null; } possibleVoRepresentations = thumbnailController.getPossibleVoRepresentations(); } else { const mediaInfo = getMediaInfo(type); possibleVoRepresentations = abrController.getPossibleVoRepresentations(mediaInfo, true); } index = Math.max(Math.min(index, possibleVoRepresentations.length - 1), 0) return possibleVoRepresentations[index]; } 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(); 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; { 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 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 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; { 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()); // Filter out embedded text track before updating media info in StreamProcessor allMediaForType = allMediaForType.filter(mediaInfo =&gt; { return !mediaInfo.isEmbedded; }); // Check if AdaptationSet has not been removed in MPD update streamProcessor.setMediaInfoArray(allMediaForType); if (allMediaForType) { for (let j = 0; j &lt; allMediaForType.length; j++) { if (adapter.areMediaInfosEqual(currentMediaInfo, allMediaForType[j])) { promises.push(streamProcessor.selectMediaInfo(allMediaForType[j])) } } } } Promise.all(promises) .then(() =&gt; { let promises = []; // Only relevant for MSS 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()); promises.push(processor.selectMediaInfo(mediaInfo)); } return Promise.all(promises) }) .then(() =&gt; { _initializationCompleted(); eventBus.trigger(Events.STREAM_UPDATED, { streamInfo: streamInfo }); resolve(); }) .catch((e) =&gt; { errHandler.error(e); }) }) } function _initializationCompleted() { const ln = streamProcessors.length; 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 (!isInitialized) { isInitialized = true; videoModel.waitForReadyState(Constants.VIDEO_ELEMENT_READY_STATES.HAVE_METADATA, () =&gt; { eventBus.trigger(Events.STREAM_INITIALIZED, { streamInfo: streamInfo }); }) } } function setPreloaded(value) { preloaded = value; } function getPreloaded() { return preloaded; } function getHasFinishedBuffering() { return hasFinishedBuffering; } function getAdapter() { return adapter; } function getCurrentRepresentationForType(type) { const sp = _getProcessorByType(type); if (!sp) { return null; } return sp.getRepresentation(); } function getCurrentMediaInfoForType(type) { const sp = _getProcessorByType(type); if (!sp) { return null; } return sp.getMediaInfo(); } instance = { activate, deactivate, getAdapter, getCurrentMediaInfoForType, getCurrentRepresentationForType, getDuration, getHasAudioTrack, getHasFinishedBuffering, getHasVideoTrack, getId, getIsActive, getIsEndedEventSignaled, getPreloaded, getProcessors, getRepresentationForTypeById, getRepresentationForTypeByIndex, getRepresentationsByType, getStartTime, getStreamId, getStreamInfo, getThumbnailController, initialize, initializeForTextWithMediaSource, prepareQualityChange, prepareTrackChange, reset, setIsEndedEventSignaled, setMediaSource, setPreloaded, startPreloading, startScheduleControllers, updateData, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import MetricsConstants from '../constants/MetricsConstants.js'; import Stream from '../Stream.js'; import ManifestUpdater from '../ManifestUpdater.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import {PlayList, PlayListTrace} from '../vo/metrics/PlayList.js'; import Debug from '../../core/Debug.js'; import InitCache from '../utils/InitCache.js'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; import TimeSyncController from './TimeSyncController.js'; import MediaSourceController from './MediaSourceController.js'; import DashJSError from '../vo/DashJSError.js'; import Errors from '../../core/errors/Errors.js'; import EventController from './EventController.js'; import ConformanceViolationConstants from '../constants/ConformanceViolationConstants.js'; 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, throughputController, mediaController, eventController, initCache, 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(); resetInitialSettings(); } function initialize(autoPl, protData) { _checkConfig(); autoPlay = autoPl; protectionData = protData; timelineConverter.initialize(); manifestUpdater = ManifestUpdater(context).create(); manifestUpdater.setConfig({ manifestModel, adapter, manifestLoader, errHandler, settings, contentSteeringController }); 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*/) { _composePeriods(); } /** * * @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 _composePeriods() { 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; { return new Promise((resolve, reject) =&gt; { if (!activeStream) { _initializeForFirstStream(streamsInfo, resolve, reject); } else { resolve(); } }); }) .then(() =&gt; { 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, throughputController, 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, resolve, reject) { try { // 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, resolve, reject); }, 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); } // Apply content steering _applyContentSteeringBeforeStart() .then(() =&gt; { const manifest = manifestModel.getValue(); if (manifest) { baseURLController.update(manifest) } _calculateStartTimeAndSwitchStream() resolve(); }) .catch((e) =&gt; { logger.error(e); _calculateStartTimeAndSwitchStream(); resolve(); }) } catch (e) { reject(e); } } function _applyContentSteeringBeforeStart() { if (settings.get().streaming.applyContentSteering &amp;&amp; contentSteeringController.shouldQueryBeforeStart()) { return contentSteeringController.loadSteeringData(); } return Promise.resolve(); } function _calculateStartTimeAndSwitchStream() { // 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 we have a video element we are not preloading into a virtual buffer if (videoModel.getElement()) { _openMediaSource(seekTime, keepBuffers, false); } else { _activateStream(seekTime, keepBuffers); } } catch (e) { isStreamSwitchingInProgress = false; } } /** * Setup the Media Source. Open MSE and attach event listeners * @param {number} seekTime * @param {boolean} keepBuffers * @param {boolean} streamActivated * @private */ function _openMediaSource(seekTime, keepBuffers, streamActivated = false) { 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); if (streamActivated) { if (!isNaN(seekTime)) { playbackController.seek(seekTime, true, true); } // Set the media source for all StreamProcessors activeStream.setMediaSource(mediaSource) .then(() =&gt; { // Start text processing now that we have a video element activeStream.initializeForTextWithMediaSource(mediaSource); }) } else { _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 newTime = e.seekTime; const seekToStream = getStreamForTime(newTime); if (!seekToStream || seekToStream === activeStream) { _cancelPreloading(); _handleInnerPeriodSeek(e); } else if (seekToStream &amp;&amp; seekToStream !== activeStream) { _cancelPreloading(seekToStream); _handleOuterPeriodSeek(e, seekToStream); } _createPlaylistMetrics(PlayList.SEEK_START_REASON); } /** * Cancels the preloading of certain streams based on the position we are seeking to. * @param {object} seekToStream * @private */ function _cancelPreloading(seekToStream = null) { // Inner period seek if (!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 is implemented return (settings.get().streaming.buffer.reuseExistingSourceBuffers &amp;&amp; (capabilities.isProtectionCompatible(previousStream, nextStream) || firstLicenseIsFetched) &amp;&amp; (supportsChangeType &amp;&amp; settings.get().streaming.buffer.useChangeTypeForTrackSwitch)); } 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 &amp;&amp; activeStream) { 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; return (isDynamic &amp;&amp; !isNaN(posix)) ? timelineConverter.calcPresentationTimeFromWallTime(new Date(posix * 1000), period) : parseFloat(targetString) + referenceTime; } /** * 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 segmentDuration = NaN; // We use the maxFragmentDuration attribute if present if (manifestInfo &amp;&amp; !isNaN(manifestInfo.maxFragmentDuration) &amp;&amp; isFinite(manifestInfo.maxFragmentDuration)) { return manifestInfo.maxFragmentDuration; } return isFinite(segmentDuration) ? segmentDuration : 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); // 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); 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()); 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, true); } } 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, 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.throughputController) { throughputController = config.throughputController; } 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 = { addDVRMetric, getActiveStream, getActiveStreamInfo, getActiveStreamProcessors, getAutoPlay, getHasMediaOrInitialisationError, getInitialPlayback, getIsStreamSwitchInProgress, getStreamById, getStreamForTime, getStreams, getTimeRelativeToStreamId, hasAudioTrack, hasVideoTrack, initialize, load, loadWithManifest, reset, setConfig, setProtectionData, switchToVideoElement, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import DashConstants from '../dash/constants/DashConstants.js'; import MetricsConstants from './constants/MetricsConstants.js'; import FragmentModel from './models/FragmentModel.js'; import BufferController from './controllers/BufferController.js'; import NotFragmentedTextBufferController from './text/NotFragmentedTextBufferController.js'; import ScheduleController from './controllers/ScheduleController.js'; import RepresentationController from '../dash/controllers/RepresentationController.js'; import FactoryMaker from '../core/FactoryMaker.js'; import {checkInteger} from './utils/SupervisorTools.js'; import EventBus from '../core/EventBus.js'; import Events from '../core/events/Events.js'; import MediaPlayerEvents from './MediaPlayerEvents.js'; import DashHandler from '../dash/DashHandler.js'; import Errors from '../core/errors/Errors.js'; import DashJSError from './vo/DashJSError.js'; import Debug from '../core/Debug.js'; import URLUtils from '../streaming/utils/URLUtils.js'; import {PlayListTrace} from './vo/metrics/PlayList.js'; import SegmentsController from '../dash/controllers/SegmentsController.js'; import {HTTPRequest} from './vo/metrics/HTTPRequest.js'; import TimeUtils from './utils/TimeUtils.js'; 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, currentMediaInfo, mediaInfoArr, bufferController, scheduleController, representationController, shouldUseExplicitTimeForRequest, shouldRepeatRequest, qualityChangeInProgress, dashHandler, segmentsController, bufferingTime, pendingSwitchToVoRepresentation; function setup() { logger = Debug(context).getInstance().getLogger(instance); resetInitialSettings(); eventBus.on(Events.INIT_FRAGMENT_NEEDED, _onInitFragmentNeeded, instance); eventBus.on(Events.MEDIA_FRAGMENT_NEEDED, _onMediaFragmentNeeded, instance); eventBus.on(Events.INIT_FRAGMENT_LOADED, _onInitFragmentLoaded, 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); eventBus.on(Events.BYTES_APPENDED_END_FRAGMENT, _onBytesAppended, 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(), 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, adapter, 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, representationController, settings }); scheduleController.initialize(hasVideoTrack); bufferingTime = 0; shouldUseExplicitTimeForRequest = false; shouldRepeatRequest = false; } function getStreamId() { return streamInfo.id; } function getType() { return type; } function resetInitialSettings() { mediaInfoArr = []; currentMediaInfo = null; bufferingTime = 0; shouldUseExplicitTimeForRequest = false; shouldRepeatRequest = false; qualityChangeInProgress = false; pendingSwitchToVoRepresentation = null; } 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.INIT_FRAGMENT_NEEDED, _onInitFragmentNeeded, instance); eventBus.off(Events.MEDIA_FRAGMENT_NEEDED, _onMediaFragmentNeeded, instance); eventBus.off(Events.INIT_FRAGMENT_LOADED, _onInitFragmentLoaded, 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); eventBus.off(Events.BYTES_APPENDED_END_FRAGMENT, _onBytesAppended, instance); resetInitialSettings(); type = null; streamInfo = null; } function setMediaInfoArray(value) { mediaInfoArr = value; } /** * 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 * @returns {Promise&lt;any&gt;} */ function prepareInnerPeriodPlaybackSeeking(e) { return new Promise((resolve) =&gt; { // If we seek to a buffered area we can keep requesting where we left before the seek // If we seek back then forwards buffering will stop until we are below our buffer goal // If we seek forwards then pruneBuffer() will make sure that the bufferToKeep setting is respected const hasBufferAtTargetTime = bufferController.hasBufferAtTime(e.seekTime); if (hasBufferAtTargetTime) { bufferController.pruneBuffer(); const continuousBufferTime = bufferController.getContinuousBufferTimeForTargetTime(e.seekTime); if (_shouldSetBufferingComplete(continuousBufferTime)) { bufferController.setIsBufferingCompleted(true); } resolve(); return; } // 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 (_shouldSetBufferingComplete(continuousBufferTime)) { 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 could've been changed by preloading period const voRepresentation = getRepresentation(); promises.push(bufferController.updateBufferTimestampOffset(voRepresentation)); 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); }); }) } function _shouldSetBufferingComplete(continuousBufferTime) { return !isNaN(continuousBufferTime) &amp;&amp; !isNaN(streamInfo.duration) &amp;&amp; isFinite(streamInfo.duration) &amp;&amp; continuousBufferTime &gt;= streamInfo.start + streamInfo.duration } /** * 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 (currentMediaInfo.isText &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(currentMediaInfo, rep) : null; if (request) { fragmentModel.executeRequest(request); } else if (rescheduleIfNoRequest) { scheduleController.setInitSegmentRequired(true); _noValidRequest(); } } } } /** * ScheduleController indicates that a media segment is needed * @param {object} e * @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; shouldRepeatRequest = 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} with request range ${request.range}`); 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, currentMediaInfo, 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, currentMediaInfo, 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() { let request; if (isNaN(bufferingTime) || (getType() === Constants.TEXT &amp;&amp; !textController.isTextEnabled())) { return null; } if (dashHandler) { const representation = getRepresentation(); if (shouldUseExplicitTimeForRequest) { request = dashHandler.getSegmentRequestForTime(currentMediaInfo, representation, bufferingTime); } else if (shouldRepeatRequest) { request = dashHandler.repeatSegmentRequest(currentMediaInfo, representation); } else { request = dashHandler.getNextSegmentRequest(currentMediaInfo, 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() { const currentRepresentation = representationController.getCurrentRepresentation() if (!bufferController.getIsBufferingCompleted()) { bufferController.updateBufferTimestampOffset(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); } function _onBytesAppended(e) { logger.debug(`Appended bytes for ${e.mediaType} and stream id ${e.streamId}`); // 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 (e.segmentType === HTTPRequest.INIT_SEGMENT_TYPE) { const lastInitializedRepresentationId = e.representationId; scheduleController.setLastInitializedRepresentationId(lastInitializedRepresentationId); logger.info('[' + type + '] ' + 'lastInitializedRepresentationId changed to ' + lastInitializedRepresentationId); } if (pendingSwitchToVoRepresentation) { _prepareForDefaultQualitySwitch(pendingSwitchToVoRepresentation) } else { scheduleController.startScheduleTimer(0); } } /** * 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, targetRepresentation = null) { return new Promise((resolve) =&gt; { if (representationController) { // Switching to a new AdaptationSet as part of a quality switch if (targetRepresentation) { currentMediaInfo = newMediaInfo; } // Switching to a new AS else if ((currentMediaInfo === null || (!adapter.areMediaInfosEqual(currentMediaInfo, newMediaInfo)))) { currentMediaInfo = newMediaInfo; const bitrate = abrController.getInitialBitrateFor(type); targetRepresentation = abrController.getOptimalRepresentationForBitrate(currentMediaInfo, bitrate, false); } // MPD update quality remains the same else { currentMediaInfo = newMediaInfo; targetRepresentation = representationController.getCurrentRepresentation() } // Update Representation Controller with the new data const voRepresentations = abrController.getPossibleVoRepresentations(currentMediaInfo, false); const representationId = targetRepresentation.id; return representationController.updateData(voRepresentations, currentMediaInfo.isFragmented, representationId) .then(() =&gt; { _onDataUpdateCompleted() resolve(); }) .catch((e) =&gt; { logger.error(e); resolve() }) } else { return Promise.resolve(); } }) } /** * 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 */ function prepareQualityChange(e) { if (!e.newRepresentation) { return; } if (pendingSwitchToVoRepresentation) { logger.warn(`Canceling queued representation switch to ${pendingSwitchToVoRepresentation.id} for ${type}`); } if (e.isAdaptationSetSwitch) { logger.debug(`Preparing quality switch to different AdaptationSet for type ${type}`); _prepareAdaptationSwitchQualityChange(e) } else { logger.debug(`Preparing quality within the same AdaptationSet for type ${type}`); _prepareNonAdaptationSwitchQualityChange(e) } } function _prepareNonAdaptationSwitchQualityChange(e) { const newRepresentation = e.newRepresentation; qualityChangeInProgress = true; // Stop scheduling until we are done with preparing the quality switch scheduleController.clearScheduleTimer(); // Update selected Representation in RepresentationController representationController.prepareQualityChange(newRepresentation); _handleDifferentSwitchTypes(e, newRepresentation); } function _prepareAdaptationSwitchQualityChange(e) { const newRepresentation = e.newRepresentation; qualityChangeInProgress = true; // Stop scheduling until we are done with preparing the quality switch scheduleController.clearScheduleTimer(); // Informing ScheduleController about AS switch scheduleController.setSwitchTrack(true); const newMediaInfo = newRepresentation.mediaInfo; currentMediaInfo = newMediaInfo; selectMediaInfo(newMediaInfo, newRepresentation) .then(() =&gt; { _handleDifferentSwitchTypes(e, newRepresentation); }) } function _handleDifferentSwitchTypes(e, newRepresentation) { // If the switch should occur immediately we need to replace existing stuff in the buffer if (e.reason &amp;&amp; e.reason.forceReplace) { _prepareForForceReplacementQualitySwitch(newRepresentation); } // We abandoned a current request else if (e &amp;&amp; e.reason &amp;&amp; e.reason.forceAbandon) { _prepareForAbandonQualitySwitch(newRepresentation) } // 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(newRepresentation, e); } // Default quality switch. We append the new quality to the already buffered stuff else { _prepareForDefaultQualitySwitch(newRepresentation); } dashMetrics.pushPlayListTraceMetrics(new Date(), PlayListTrace.REPRESENTATION_SWITCH_STOP_REASON); dashMetrics.createPlaylistTraceMetrics(newRepresentation.id, playbackController.getTime() * 1000, playbackController.getPlaybackRate()); } function _prepareForForceReplacementQualitySwitch(voRepresentation) { // 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(); // 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 }); scheduleController.setCheckPlaybackQuality(false); // Abort appending segments to the buffer. Also adjust the appendWindow as we might have been in the progress of prebuffering stuff. bufferController.prepareForForceReplacementQualitySwitch(voRepresentation) .then(() =&gt; { _bufferClearedForReplacement(); qualityChangeInProgress = false; }) .catch(() =&gt; { _bufferClearedForReplacement(); qualityChangeInProgress = false; }); } function _prepareForFastQualitySwitch(voRepresentation) { // 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(voRepresentation.fragmentDuration) ? voRepresentation.fragmentDuration : 1); const request = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_EXECUTED, time: time + safeBufferLevel, threshold: 0 })[0]; if (request &amp;&amp; !currentMediaInfo.isText) { const bufferLevel = bufferController.getBufferLevel(); const abandonmentState = abrController.getAbandonmentStateFor(streamInfo.id, type); // The new quality is higher than the one we originally requested if (request.bandwidth &lt; voRepresentation.bandwidth &amp;&amp; bufferLevel &gt;= safeBufferLevel &amp;&amp; abandonmentState === MetricsConstants.ALLOW_LOAD) { bufferController.updateBufferTimestampOffset(voRepresentation) .then(() =&gt; { // Abort the current request to avoid inconsistencies. 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 fragmentModel.abortRequests(); const targetTime = time + safeBufferLevel; setExplicitBufferingTime(targetTime); scheduleController.setCheckPlaybackQuality(false); scheduleController.startScheduleTimer(); qualityChangeInProgress = false; }) .catch(() =&gt; { qualityChangeInProgress = false; }) } // If we have buffered a higher quality we do not replace anything. We might cancel the current request due to abandon request rule else { _prepareForDefaultQualitySwitch(voRepresentation); } } else { _prepareForDefaultQualitySwitch(voRepresentation); } } function _prepareForDefaultQualitySwitch(voRepresentation) { // We are not canceling the current request. Check if there is still an ongoing request. If so we wait for the request to be finished and the media to be appended const ongoingRequests = fragmentModel.getRequests({ state: FragmentModel.FRAGMENT_MODEL_LOADING }) if (ongoingRequests &amp;&amp; ongoingRequests.length &gt; 0) { logger.debug('Preparing for default quality switch: Waiting for ongoing segment request to be finished before applying switch.') pendingSwitchToVoRepresentation = voRepresentation; return; } bufferController.updateBufferTimestampOffset(voRepresentation) .then(() =&gt; { scheduleController.setCheckPlaybackQuality(false); if (currentMediaInfo.segmentAlignment || currentMediaInfo.subSegmentAlignment) { scheduleController.startScheduleTimer(); } else { _bufferClearedForNonReplacement() } pendingSwitchToVoRepresentation = null; qualityChangeInProgress = false; }) .catch(() =&gt; { pendingSwitchToVoRepresentation = null; qualityChangeInProgress = false; }) } function _prepareForAbandonQualitySwitch(voRepresentation) { bufferController.updateBufferTimestampOffset(voRepresentation) .then(() =&gt; { fragmentModel.abortRequests(); shouldRepeatRequest = true; scheduleController.setCheckPlaybackQuality(false); scheduleController.startScheduleTimer(); qualityChangeInProgress = false; }) .catch(() =&gt; { 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.getSwitchTrack() &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 (currentMediaInfo.isText) { 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 dischargePreBuffer() { bufferController.dischargePreBuffer(); } function getFragmentModel() { return fragmentModel; } function updateStreamInfo(newStreamInfo) { streamInfo = newStreamInfo; if (!isBufferingCompleted()) { return bufferController.updateAppendWindow(); } return Promise.resolve(); } function getStreamInfo() { return streamInfo; } function getMediaInfo() { return currentMediaInfo; } function getAllMediaInfos() { return mediaInfoArr; } function getMediaSource() { return bufferController.getMediaSource(); } function setMediaSource(mediaSource) { return bufferController.setMediaSource(mediaSource, currentMediaInfo); } 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} id - id of the voRepresentation. * @return {object} voRepresentation */ function getRepresentation(id = NaN) { let voRepresentation; if (!isNaN(id)) { checkInteger(id); voRepresentation = representationController ? representationController.getRepresentationById(id) : null; } else { voRepresentation = representationController ? representationController.getCurrentRepresentation() : null; } return 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 voRepresentation = getRepresentation(); return dashHandler.getNextSegmentRequestIdempotent( currentMediaInfo, voRepresentation ); } function _onInitFragmentLoaded(e) { if (!settings.get().streaming.enableManifestTimescaleMismatchFix) { return; } const chunk = e.chunk; const bytes = chunk.bytes; const representationId = chunk.representation.id; const currentRepresentation = getRepresentation(representationId); if (currentRepresentation) { currentRepresentation.timescale = boxParser.getMediaTimescaleFromMoov(bytes); } } function _onMediaFragmentLoaded(e) { const chunk = e.chunk; const bytes = chunk.bytes; const representationId = chunk.representation.id; const currentRepresentation = getRepresentation(representationId); // 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) { let isoFile; // Check for inband prft on media segment (if enabled) if (settings.get().streaming.parseInbandPrft &amp;&amp; e.request.type === HTTPRequest.MEDIA_SEGMENT_TYPE) { isoFile = isoFile ? isoFile : boxParser.parse(bytes); const timescale = currentRepresentation.timescale; const prfts = _handleInbandPrfts(isoFile, timescale); if (prfts &amp;&amp; prfts.length) { eventBus.trigger(MediaPlayerEvents.INBAND_PRFT, { data: prfts }, { streamId: streamInfo.id, mediaType: type } ); } } const eventStreamMedia = adapter.getEventsFor(currentRepresentation.mediaInfo, null, streamInfo); const eventStreamTrack = adapter.getEventsFor(currentRepresentation, currentRepresentation, streamInfo); if (eventStreamMedia &amp;&amp; eventStreamMedia.length &gt; 0 || eventStreamTrack &amp;&amp; eventStreamTrack.length &gt; 0) { const request = e.request; isoFile = isoFile ? isoFile : boxParser.parse(bytes); const events = _handleInbandEvents(isoFile, request, eventStreamMedia, eventStreamTrack); eventBus.trigger(Events.INBAND_EVENTS, { events: events }, { streamId: streamInfo.id } ); } } } function _handleInbandPrfts(isoFile, timescale) { const prftBoxes = isoFile.getBoxes('prft'); const prfts = []; prftBoxes.forEach(prft =&gt; { prfts.push(_parsePrftBox(prft, timescale)); }); return prfts; } function _parsePrftBox(prft, timescale) { // Get prft type according to box flags let type = 'unknown'; switch (prft.flags) { case 0: type = DashConstants.PRODUCER_REFERENCE_TIME_TYPE.ENCODER; break; case 16: type = DashConstants.PRODUCER_REFERENCE_TIME_TYPE.APPLICATION; break; case 24: type = DashConstants.PRODUCER_REFERENCE_TIME_TYPE.CAPTURED; break; default: break; } // Get NPT timestamp according to IETF RFC 5905, relative to 1/1/1900 let ntpTimestamp = (prft.ntp_timestamp_sec * 1000) + (prft.ntp_timestamp_frac / 2 ** 32 * 1000); ntpTimestamp = TimeUtils(context).getInstance().ntpToUTC(ntpTimestamp); const mediaTime = (prft.media_time / timescale); return { type, ntpTimestamp, mediaTime } } function _handleInbandEvents(isoFile, 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 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(currentMediaInfo, 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) { const representation = representationController.getCurrentRepresentation() bufferController.prepareForNonReplacementTrackSwitch(representation) .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. const representation = getRepresentation() bufferController.prepareForReplacementTrackSwitch(representation) .then(() =&gt; { // Timestamp offset couldve been changed by preloading period return bufferController.updateBufferTimestampOffset(representation); }) .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 const representation = getRepresentation() bufferController.prepareForNonReplacementTrackSwitch(representation) .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, 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 = { createBufferSinks, dischargePreBuffer, finalisePlayList, getAllMediaInfos, getBuffer, getBufferController, getBufferLevel, getFragmentModel, getMediaInfo, getMediaSource, getRepresentationController, getRepresentation, getScheduleController, getStreamId, getStreamInfo, getType, initialize, isBufferingCompleted, prepareInnerPeriodPlaybackSeeking, prepareOuterPeriodPlaybackSeeking, prepareQualityChange, prepareTrackSwitch, probeNextRequest, reset, setMediaInfoArray, selectMediaInfo, setExplicitBufferingTime, setMediaSource, updateStreamInfo, }; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import TextSourceBuffer from './TextSourceBuffer.js'; import TextTracks from './TextTracks.js'; import VTTParser from '../utils/VTTParser.js'; import VttCustomRenderingParser from '../utils/VttCustomRenderingParser.js'; import TTMLParser from '../utils/TTMLParser.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js'; import {checkParameterType} from '../utils/SupervisorTools.js'; 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, vttCustomRenderingParser, ttmlParser, eventBus, allTracksAreDisabled, forceTextStreaming, textTracksAdded, disableTextBeforeTextTracksAdded; function setup() { forceTextStreaming = false; textTracksAdded = false; disableTextBeforeTextTracksAdded = false; vttParser = VTTParser(context).getInstance(); vttCustomRenderingParser = VttCustomRenderingParser(context).getInstance(); ttmlParser = TTMLParser(context).getInstance(); eventBus = EventBus(context).getInstance(); resetInitialSettings(); } function initialize() { eventBus.on(Events.TEXT_TRACKS_QUEUE_INITIALIZED, _onTextTracksAdded, instance); if (settings.get().streaming.text.webvtt.customRenderingEnabled) { eventBus.on(Events.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance); eventBus.on(Events.PLAYBACK_SEEKING, _onPlaybackSeeking, instance); } } function initializeForStream(streamInfo) { const streamId = streamInfo.id; const tracks = TextTracks(context).create({ videoModel, settings, streamInfo }); tracks.initialize(); textTracks[streamId] = tracks; const textSourceBuffer = TextSourceBuffer(context).create({ errHandler, adapter, manifestModel, mediaController, videoModel, textTracks: tracks, vttParser, vttCustomRenderingParser, ttmlParser, streamInfo, settings }); 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 _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 { const currentTrack = mediaController.getCurrentTrackFor(Constants.TEXT, streamId); if (currentTrack) { const defaultSettings = { lang: currentTrack.lang, role: currentTrack.roles[0], index: currentTrack.index, codec: currentTrack.codec, accessibility: currentTrack.accessibility[0] }; 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 _onPlaybackTimeUpdated(e) { try { const streamId = e.streamId; if (!textTracks[streamId] || isNaN(e.time)) { return; } textTracks[streamId].manualCueProcessing(e.time); } catch (err) { } } function _onPlaybackSeeking(e) { try { const streamId = e.streamId; if (!textTracks[streamId]) { return; } textTracks[streamId].disableManualTracks(); } catch (e) { } } 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); } } } return true } 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; return true } 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].disableManualTracks(); 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.TEXT_TRACKS_QUEUE_INITIALIZED, _onTextTracksAdded, instance); if (settings.get().streaming.text.webvtt.customRenderingEnabled) { eventBus.off(Events.PLAYBACK_TIME_UPDATED, _onPlaybackTimeUpdated, instance); eventBus.off(Events.PLAYBACK_SEEKING, _onPlaybackSeeking, instance) } Object.keys(textSourceBuffers).forEach((key) =&gt; { textSourceBuffers[key].resetEmbedded(); textSourceBuffers[key].reset(); }); } instance = { deactivateStream, initialize, initializeForStream, createTracks, getTextSourceBuffer, getAllTracksAreDisabled, addEmbeddedTrack, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import {HTTPRequest} from '../vo/metrics/HTTPRequest.js'; import TextTrackInfo from '../vo/TextTrackInfo.js'; import BoxParser from '../utils/BoxParser.js'; import CustomTimeRanges from '../utils/CustomTimeRanges.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Debug from '../../core/Debug.js'; import EmbeddedTextHtmlRender from './EmbeddedTextHtmlRender.js'; import ISOBoxer from 'codem-isoboxer'; import cea608parser from '../../../externals/cea608-parser.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import DashJSError from '../vo/DashJSError.js'; import Errors from '../../core/errors/Errors.js'; 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 vttCustomRenderingParser = config.vttCustomRenderingParser; const ttmlParser = config.ttmlParser; const streamInfo = config.streamInfo; const settings = config.settings; 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.representation.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].value] : trackKindMap.caption; kind = (kind === trackKindMap.caption || kind === trackKindMap.subtitle) ? kind : trackKindMap.caption; return kind; } function append(bytes, chunk) { const mediaInfo = chunk.representation.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); let entry = { styles: {} }; for (k = 0; k &lt; box1.boxes.length; k++) { const box2 = box1.boxes[k]; logger.debug('VTT box2: ' + box2.type); // Mandatory cue payload lines if (box2.type === 'payl') { entry.start = sample.cts / timescale; entry.end = (sample.cts + sample.duration) / timescale; entry.data = box2.cue_text; } // The styling information else if (box2.type === 'sttg' &amp;&amp; box2.settings &amp;&amp; box2.settings !== '') { try { const stylings = box2.settings.split(' '); entry.styles = vttParser.getCaptionStyles(stylings); } catch (e) { } } } if (entry &amp;&amp; entry.data) { captionArray.push(entry); logger.debug(`VTT ${entry.start} - ${entry.end} : ${entry.data}`); } } } } 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 = settings.get().streaming.text.webvtt.customRenderingEnabled &amp;&amp; vttCustomRenderingParser ? vttCustomRenderingParser : 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 "},"streaming_controllers_ThroughputController.js.html":{"id":"streaming_controllers_ThroughputController.js.html","title":"Source: streaming/controllers/ThroughputController.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/ThroughputController.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) 2017, 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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import ThroughputModel from '../models/ThroughputModel.js'; import MetricsConstants from '../constants/MetricsConstants.js'; import {HTTPRequest} from '../vo/metrics/HTTPRequest.js'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; import EventBus from '../../core/EventBus.js'; /** * @constructor */ function ThroughputController() { const context = this.context; const eventBus = EventBus(context).getInstance(); let throughputModel, playbackController, settings; function initialize() { throughputModel = ThroughputModel(context).create({ settings }); _registerEvents(); } function setConfig(config) { if (config.settings) { settings = config.settings; } if (config.playbackController) { playbackController = config.playbackController; } } function _registerEvents() { eventBus.on(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); if (performance) { performance.addEventListener( 'resourcetimingbufferfull', _onResourceTimingBufferFull, ); } } function _resetEvents() { eventBus.off(MediaPlayerEvents.METRIC_ADDED, _onMetricAdded, instance); if (performance) { performance.removeEventListener( 'resourcetimingbufferfull', _onResourceTimingBufferFull, ); } } function _onResourceTimingBufferFull() { performance.clearResourceTimings(); } /** * Push new values to the throughput model once an HTTP request completed * @param {object} e * @private */ function _onMetricAdded(e) { if (e.metric === MetricsConstants.HTTP_REQUEST &amp;&amp; e.value &amp;&amp; (e.value.type === HTTPRequest.MPD_TYPE || (e.value.type === HTTPRequest.MEDIA_SEGMENT_TYPE &amp;&amp; (e.mediaType === Constants.AUDIO || e.mediaType === Constants.VIDEO)))) { throughputModel.addEntry(e.mediaType, e.value); } } /** * Get average value * @param {string} throughputType * @param {string} mediaType * @param {string|null} calculationMode * @param {number} sampleSize * @return {number} * @private */ function _getAverage(throughputType, mediaType, calculationMode = null, sampleSize = NaN) { let dict = null; let ewmaHalfLife = throughputModel.getEwmaHalfLife(); let halfLife = null; let useMin = true; if (!calculationMode) { calculationMode = settings.get().streaming.abr.throughput.averageCalculationMode; } switch (throughputType) { // Set the parameters for the standard bandwidth calculation based on throughput values for a media type case Constants.THROUGHPUT_TYPES.BANDWIDTH: dict = calculationMode === Constants.THROUGHPUT_CALCULATION_MODES.EWMA ? throughputModel.getEwmaThroughputDict(mediaType) : throughputModel.getThroughputDict(mediaType); halfLife = ewmaHalfLife.bandwidthHalfLife; useMin = true; sampleSize = !isNaN(sampleSize) ? sampleSize : playbackController.getIsDynamic() ? settings.get().streaming.abr.throughput.sampleSettings.live : settings.get().streaming.abr.throughput.sampleSettings.vod; break; // Set the parameters for the standard latency calculation based on throughput values for a media type case Constants.THROUGHPUT_TYPES.LATENCY: dict = calculationMode === Constants.THROUGHPUT_CALCULATION_MODES.EWMA ? throughputModel.getEwmaLatencyDict(mediaType) : throughputModel.getLatencyDict(mediaType); halfLife = ewmaHalfLife.latencyHalfLife; useMin = false; sampleSize = !isNaN(sampleSize) ? sampleSize : settings.get().streaming.abr.throughput.sampleSettings.averageLatencySampleAmount; break; } if (!dict || dict.length === 0) { return NaN; } let adjustedSampleSize; switch (calculationMode) { case Constants.THROUGHPUT_CALCULATION_MODES.ARITHMETIC_MEAN: adjustedSampleSize = _getAdjustedSampleSize(dict, sampleSize, throughputType); return getArithmeticMean(dict, adjustedSampleSize); case Constants.THROUGHPUT_CALCULATION_MODES.BYTE_SIZE_WEIGHTED_ARITHMETIC_MEAN: adjustedSampleSize = _getAdjustedSampleSize(dict, sampleSize, throughputType); return getByteSizeWeightedArithmeticMean(dict, adjustedSampleSize); case Constants.THROUGHPUT_CALCULATION_MODES.DATE_WEIGHTED_ARITHMETIC_MEAN: adjustedSampleSize = _getAdjustedSampleSize(dict, sampleSize, throughputType); return getDateWeightedArithmeticMean(dict, adjustedSampleSize); case Constants.THROUGHPUT_CALCULATION_MODES.HARMONIC_MEAN: adjustedSampleSize = _getAdjustedSampleSize(dict, sampleSize, throughputType); return getHarmonicMean(dict, adjustedSampleSize); case Constants.THROUGHPUT_CALCULATION_MODES.BYTE_SIZE_WEIGHTED_HARMONIC_MEAN: adjustedSampleSize = _getAdjustedSampleSize(dict, sampleSize, throughputType); return getByteSizeWeightedHarmonicMean(dict, adjustedSampleSize); case Constants.THROUGHPUT_CALCULATION_MODES.DATE_WEIGHTED_HARMONIC_MEAN: adjustedSampleSize = _getAdjustedSampleSize(dict, sampleSize, throughputType); return getDateWeightedHarmonicMean(dict, adjustedSampleSize); case Constants.THROUGHPUT_CALCULATION_MODES.EWMA: return getEwma(dict, halfLife, useMin); case Constants.THROUGHPUT_CALCULATION_MODES.ZLEMA: adjustedSampleSize = _getAdjustedSampleSize(dict, sampleSize, throughputType); return getZlema(dict, adjustedSampleSize); } } /** * @param {array} dict * @param {number} sampleSize * @param {string} type * @return {number} * @private */ function _getAdjustedSampleSize(dict, sampleSize, type) { if (!dict) { sampleSize = 0; } else if (sampleSize &gt;= dict.length) { sampleSize = dict.length; } else if (type === Constants.THROUGHPUT_TYPES.BANDWIDTH &amp;&amp; settings.get().streaming.abr.throughput.sampleSettings.enableSampleSizeAdjustment) { // if throughput samples vary a lot, average over a wider sample for (let i = 1; i &lt; sampleSize; ++i) { const ratio = dict[dict.length - i].value / dict[dict.length - i - 1].value; if (ratio &gt;= settings.get().streaming.abr.throughput.sampleSettings.increaseScale || ratio &lt;= settings.get().streaming.abr.throughput.sampleSettings.decreaseScale) { sampleSize += 1; if (sampleSize === dict.length) { // cannot increase sampleSize beyond arr.length break; } } } } return sampleSize; } /** * Calculate the arithmetic mean of the values provided via the dict * @param {array} dict * @param {number} sampleSize * @return {number|*} * @private */ function getArithmeticMean(dict, sampleSize) { let arr = dict; if (sampleSize === 0 || !arr || arr.length === 0) { return NaN; } // Extract the last n elements arr = arr.slice(-sampleSize); return arr.reduce((total, entry) =&gt; { return total + entry.value }, 0) / arr.length; } /** * Calculates the byte size weighted arithmetic mean of the values provided via the dict * @param {array} dict * @param {number} sampleSize * @return {number|*} * @private */ function getByteSizeWeightedArithmeticMean(dict, sampleSize) { let arr = dict; if (sampleSize === 0 || !arr || arr.length === 0) { return NaN; } // Extract the last n elements arr = arr.slice(-sampleSize); let divideBy = 0; return arr.reduce((total, entry) =&gt; { let weight = Math.sqrt(entry.downloadedBytes); divideBy += weight; return total + entry.value * weight }, 0) / divideBy; } /** * Calculates the time weighted arithmetic mean of the values provided via the dict * @param {array} dict * @param {number} sampleSize * @return {number|*} * @private */ function getDateWeightedArithmeticMean(dict, sampleSize) { let arr = dict; if (sampleSize === 0 || !arr || arr.length === 0) { return NaN; } // Extract the last n elements arr = arr.slice(-sampleSize); let divideBy = 0; return arr.reduce((total, entry, index) =&gt; { let weight = index + 1; divideBy += weight; return total + entry.value * weight }, 0) / divideBy; } /** * Calculate the harmonic mean of the values provided via the dict * @param {array} dict * @param {number} sampleSize * @return {number|*} * @private */ function getHarmonicMean(dict, sampleSize) { let arr = dict; if (sampleSize === 0 || !arr || arr.length === 0) { return NaN; } // Extract the last n elements arr = arr.slice(-sampleSize); const value = arr.reduce((total, entry) =&gt; { return total + 1 / entry.value }, 0); return arr.length / value } /** * Calculate the harmonic mean of the values provided via the dict * @param {array} dict * @param {number} sampleSize * @return {number|*} * @private */ function getByteSizeWeightedHarmonicMean(dict, sampleSize) { let arr = dict; if (sampleSize === 0 || !arr || arr.length === 0) { return NaN; } // Extract the last n elements arr = arr.slice(-sampleSize); let dividend = 0; const value = arr.reduce((total, entry) =&gt; { let weight = Math.sqrt(entry.downloadedBytes); dividend += weight; return total + (1 / entry.value) * weight }, 0); return dividend / value } /** * Calculates the time weighted harmonic mean of the values provided via the dict * @param {array} dict * @param {number} sampleSize * @return {number|*} * @private */ function getDateWeightedHarmonicMean(dict, sampleSize) { let arr = dict; if (sampleSize === 0 || !arr || arr.length === 0) { return NaN; } // Extract the last n elements arr = arr.slice(-sampleSize); let dividend = 0; const value = arr.reduce((total, entry, index) =&gt; { let weight = index + 1; dividend += weight; return total + (1 / entry.value) * weight }, 0); return dividend / value } /** * Calculated the exponential weighted moving average for the values provided via the dict * @param {object} dict * @param {object} halfLife * @param {boolean} useMin - Whether to apply Math.min of the fastEstimate and the slowEstimate * @return {number} * @private */ function getEwma(dict, halfLife, useMin = true) { if (!dict || dict.totalWeight &lt;= 0) { return NaN; } // to correct for startup, divide by zero factor = 1 - Math.pow(0.5, ewmaObj.totalWeight / halfLife) const fastEstimate = dict.fastEstimate / (1 - Math.pow(0.5, dict.totalWeight / halfLife.fast)); const slowEstimate = dict.slowEstimate / (1 - Math.pow(0.5, dict.totalWeight / halfLife.slow)); return useMin ? Math.min(fastEstimate, slowEstimate) : Math.max(fastEstimate, slowEstimate); } /** * Calculates the Zero-Lag Exponential Moving Average * @param {array} dict * @param {number} sampleSize * @returns {number} */ function getZlema(dict, sampleSize) { if (sampleSize === 0 || !dict || dict.length === 0) { return NaN; } // Extract the last n elements let values = dict.slice(-sampleSize).map((entry) =&gt; { return entry.value; }) let alpha = 2 / (values.length + 1); let ema = values[values.length - 1]; let zlema = values[values.length - 1]; for (let i = 0; i &lt; values.length; i++) { ema = alpha * values[i] + (1 - alpha) * ema; zlema = alpha * ema + (1 - alpha) * zlema; } return zlema; } /** * Returns the average throughput based on the provided calculation mode. The returned value is depicted in kbit/s * @param {string} mediaType * @param {string | null} calculationMode * @param {number | NaN} sampleSize * @return {number} */ function getAverageThroughput(mediaType, calculationMode = null, sampleSize = NaN) { const value = _getAverage(Constants.THROUGHPUT_TYPES.BANDWIDTH, mediaType, calculationMode, sampleSize); return Math.round(value); } /** * Returns the average throughout applying the bandwidth safety factor provided in the settings. The returned value is depicted in kbit/s * @param {string} mediaType * @param {string | null} calculationMode * @param {number | NaN} sampleSize * @return {number} */ function getSafeAverageThroughput(mediaType, calculationMode = null, sampleSize = NaN) { let average = getAverageThroughput(mediaType, calculationMode, sampleSize); if (!isNaN(average)) { average *= settings.get().streaming.abr.throughput.bandwidthSafetyFactor; } return average; } /** * Returns the average latency based on the provided calculation mode * @param {string} mediaType * @param {string | null} calculationMode * @param {number | NaN} sampleSize * @return {number} */ function getAverageLatency(mediaType, calculationMode = null, sampleSize = NaN) { const value = _getAverage(Constants.THROUGHPUT_TYPES.LATENCY, mediaType, calculationMode, sampleSize); return Math.round(value); } /** * Returns the raw throughput measurements without calculating the average * @param mediaType * @returns {*} */ function getRawThroughputData(mediaType) { if (!mediaType) { return [] } return throughputModel.getThroughputDict(mediaType); } function reset() { throughputModel.reset(); _resetEvents(); } const instance = { getArithmeticMean, getAverageLatency, getAverageThroughput, getByteSizeWeightedArithmeticMean, getByteSizeWeightedHarmonicMean, getDateWeightedArithmeticMean, getDateWeightedHarmonicMean, getEwma, getHarmonicMean, getRawThroughputData, getSafeAverageThroughput, getZlema, initialize, reset, setConfig }; return instance; } ThroughputController.__dashjs_factory_name = 'ThroughputController'; export default FactoryMaker.getSingletonFactory(ThroughputController); × Search results Close "},"streaming_models_ThroughputModel.js.html":{"id":"streaming_models_ThroughputModel.js.html","title":"Source: streaming/models/ThroughputModel.js","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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/ThroughputModel.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) 2017, 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.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Debug from '../../core/Debug.js'; import {HTTPRequest} from '../vo/metrics/HTTPRequest.js'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; import EventBus from '../../core/EventBus.js'; /** * Throughput generally stored in kbit/s * Latency generally stored in ms * @param {object} config * @constructor */ function ThroughputModel(config) { config = config || {}; const context = this.context; const debug = Debug(context).getInstance(); const settings = config.settings; const eventBus = EventBus(context).getInstance(); let throughputDict, latencyDict, ewmaThroughputDict, ewmaLatencyDict, ewmaHalfLife, logger; function setup() { logger = debug.getLogger(instance); ewmaHalfLife = { bandwidthHalfLife: { fast: settings.get().streaming.abr.throughput.ewma.throughputFastHalfLifeSeconds, slow: settings.get().streaming.abr.throughput.ewma.throughputSlowHalfLifeSeconds }, latencyHalfLife: { fast: settings.get().streaming.abr.throughput.ewma.latencyFastHalfLifeCount, slow: settings.get().streaming.abr.throughput.ewma.latencySlowHalfLifeCount } }; reset(); } /** * Use the provided request to add new entries for throughput and latency. Update the EWMA state as well. * @param {MediaType} mediaType * @param {object} httpRequest */ function addEntry(mediaType, httpRequest) { try { if (!mediaType || !httpRequest || !httpRequest.trace || !httpRequest.trace.length) { return; } _createSettingsForMediaType(mediaType); const latencyInMs = (httpRequest.tresponse.getTime() - httpRequest.trequest.getTime()) || 1; let throughputValues = _calculateThroughputValues(httpRequest, latencyInMs); throughputValues.latencyInMs = latencyInMs; if (isNaN(throughputValues.value) || !isFinite(throughputValues.value)) { return; } // Get estimated throughput (etp, in kbits/s) from CMSD response headers if (httpRequest.cmsd) { const etp = httpRequest.cmsd.dynamic &amp;&amp; httpRequest.cmsd.dynamic.etp ? httpRequest.cmsd.dynamic.etp : null; if (etp) { // Apply weight ratio on etp const etpWeightRatio = settings.get().streaming.cmsd.abr.etpWeightRatio; if (etpWeightRatio &gt; 0 &amp;&amp; etpWeightRatio &lt;= 1) { throughputValues.value = (throughputValues.value * (1 - etpWeightRatio)) + (etp * etpWeightRatio); } } } const cacheReferenceTime = (httpRequest._tfinish.getTime() - httpRequest.trequest.getTime()); if (_isCachedResponse(mediaType, cacheReferenceTime, httpRequest)) { logger.debug(`${mediaType} Assuming segment ${httpRequest.url} came from cache, ignoring it for throughput calculation`); return; } logger.debug(`Added throughput entry for ${mediaType}: ${throughputValues.value} kbit/s`) throughputValues.serviceLocation = httpRequest._serviceLocation; throughputDict[mediaType].push(throughputValues); latencyDict[mediaType].push({ value: latencyInMs }); _cleanupDict(mediaType); eventBus.trigger(MediaPlayerEvents.THROUGHPUT_MEASUREMENT_STORED, { throughputValues }) if (httpRequest.type !== HTTPRequest.MPD_TYPE) { _updateEwmaValues(ewmaThroughputDict[mediaType], throughputValues.value, settings.get().streaming.abr.throughput.ewma.weightDownloadTimeMultiplicationFactor * throughputValues.downloadTimeInMs, ewmaHalfLife.bandwidthHalfLife); _updateEwmaValues(ewmaLatencyDict[mediaType], latencyInMs, 1, ewmaHalfLife.latencyHalfLife); } } catch (e) { logger.error(e); } } /** * Returns the throughput in kbit/s , the download time in ms and the downloaded bytes for an HTTP request * @param {object} httpRequest * @param {number} latencyInMs * @return {object} * @private */ function _calculateThroughputValues(httpRequest, latencyInMs) { // Low latency is enabled, we used the fetch API and received chunks if (httpRequest._fileLoaderType &amp;&amp; httpRequest._fileLoaderType === Constants.FILE_LOADER_TYPES.FETCH) { return _calculateThroughputValuesForFetch(httpRequest); } // Standard case, we used standard XHR requests else { return _calculateThroughputValuesForXhr(httpRequest, latencyInMs); } } /** * Calculates the throughput for requests using the Fetch API * @param {object} httpRequest * @param {number} latencyInMs * @return {number} * @private */ function _calculateThroughputValuesForFetch(httpRequest) { const downloadedBytes = httpRequest.trace.reduce((prev, curr) =&gt; prev + curr.b[0], 0); const downloadTimeInMs = httpRequest.trace.reduce((prev, curr) =&gt; prev + curr.d, 0); let throughputInKbit = NaN; if (settings.get().streaming.abr.throughput.useNetworkInformationApi.fetch) { throughputInKbit = _deriveThroughputFromNetworkApi() } if (isNaN(throughputInKbit)) { throughputInKbit = Math.round((8 * downloadedBytes) / downloadTimeInMs); // bits/ms = kbits/s } return { downloadedBytes, value: throughputInKbit, downloadTimeInMs }; } /** * Returns the throughput in kbit/s and the download time in ms for requests using XHR * @param {object} httpRequest * @param {number} latencyInMs * @return {object} * @private */ function _calculateThroughputValuesForXhr(httpRequest, latencyInMs) { let downloadedBytes = NaN; let downloadTimeInMs = NaN; let deriveThroughputViaResourceTimingApi = false; // Calculate the throughput using the ResourceTimingAPI if available if (settings.get().streaming.abr.throughput.useResourceTimingApi &amp;&amp; httpRequest._resourceTimingValues) { downloadedBytes = httpRequest._resourceTimingValues.transferSize; downloadTimeInMs = httpRequest._resourceTimingValues.responseEnd - httpRequest._resourceTimingValues.responseStart; deriveThroughputViaResourceTimingApi = true; } // Use the standard throughput calculation if we can not use the Resource Timing API else { // We need at least two entries in the traces. The first entry includes the latency and the XHR progress event was thrown once bytes have already been received. // The second progress event can be set in relation to the first progress event and therefor gives us more accurate values if (httpRequest.trace.length &lt;= 1) { return { throughput: NaN, downloadTimeInMs: NaN } } downloadedBytes = httpRequest.trace.reduce((prev, curr) =&gt; prev + curr.b[0], 0) - httpRequest.trace[0].b[0]; downloadTimeInMs = Math.max(httpRequest.trace.reduce((prev, curr) =&gt; prev + curr.d, 0) - httpRequest.trace[0].d, 1); } // If available and enabled use the Network Information API let throughputInKbit = NaN; if (!deriveThroughputViaResourceTimingApi &amp;&amp; settings.get().streaming.abr.throughput.useNetworkInformationApi.xhr) { throughputInKbit = _deriveThroughputFromNetworkApi() } if (isNaN(throughputInKbit)) { const referenceTimeInMs = settings.get().streaming.abr.throughput.useDeadTimeLatency ? downloadTimeInMs : downloadTimeInMs + latencyInMs; throughputInKbit = Math.round((8 * downloadedBytes) / referenceTimeInMs) // bits/ms = kbits/s } return { downloadedBytes, value: throughputInKbit, downloadTimeInMs }; } /** * Return the current estimated bandwidth based on NetworkInformation.downlink if the API is available * @returns {*|number} * @private */ function _deriveThroughputFromNetworkApi() { // NetworkInformation.downlink: Returns the effective bandwidth estimate in megabits per second, rounded to the nearest multiple of 25 kilobits per seconds. if (navigator &amp;&amp; navigator.connection &amp;&amp; !isNaN(navigator.connection.downlink) &amp;&amp; navigator.connection.downlink &gt; 0) { return navigator.connection.downlink * 1000 } return NaN } /** * Check if the response was cached. * @param {MediaType} mediaType * @param {number} cacheReferenceTime * @param {object} httpRequest * @return {boolean} * @private */ function _isCachedResponse(mediaType, cacheReferenceTime, httpRequest) { if (settings.get().streaming.abr.throughput.useResourceTimingApi &amp;&amp; httpRequest._resourceTimingValues) { return httpRequest._resourceTimingValues.transferSize === 0 &amp;&amp; httpRequest._resourceTimingValues.decodedBodySize &gt; 0 } if (isNaN(cacheReferenceTime)) { return false; } if (mediaType === Constants.VIDEO) { return cacheReferenceTime &lt; settings.get().streaming.cacheLoadThresholds[Constants.VIDEO]; } else if (mediaType === Constants.AUDIO) { return cacheReferenceTime &lt; settings.get().streaming.cacheLoadThresholds[Constants.AUDIO]; } } /** * * @param {object} ewmaObj * @param {number} value * @param {number} weight * @param {object} halfLife * @private */ function _updateEwmaValues(ewmaObj, value, weight, halfLife) { // Note about startup: // Estimates start at 0, so early values are underestimated. // This effect is countered in getAverageEwma() by dividing the estimates by: // 1 - Math.pow(0.5, ewmaObj.totalWeight / halfLife) const fastAlpha = Math.pow(0.5, weight / halfLife.fast); ewmaObj.fastEstimate = (1 - fastAlpha) * value + fastAlpha * ewmaObj.fastEstimate; const slowAlpha = Math.pow(0.5, weight / halfLife.slow); ewmaObj.slowEstimate = (1 - slowAlpha) * value + slowAlpha * ewmaObj.slowEstimate; ewmaObj.totalWeight += weight; } /** * Shift old entries once we reached the threshold * @param {MediaType} mediaType * @private */ function _cleanupDict(mediaType) { if (throughputDict[mediaType].length &gt; settings.get().streaming.abr.throughput.sampleSettings.maxMeasurementsToKeep) { throughputDict[mediaType].shift(); } if (latencyDict[mediaType].length &gt; settings.get().streaming.abr.throughput.sampleSettings.maxMeasurementsToKeep) { latencyDict[mediaType].shift(); } } /** * Setup the dict objects for a specific media type * @param mediaType * @private */ function _createSettingsForMediaType(mediaType) { throughputDict[mediaType] = throughputDict[mediaType] || []; latencyDict[mediaType] = latencyDict[mediaType] || []; ewmaThroughputDict[mediaType] = ewmaThroughputDict[mediaType] || { fastEstimate: 0, slowEstimate: 0, totalWeight: 0 }; ewmaLatencyDict[mediaType] = ewmaLatencyDict[mediaType] || { fastEstimate: 0, slowEstimate: 0, totalWeight: 0 }; } function getThroughputDict(mediaType) { if (!mediaType) { return throughputDict } return throughputDict[mediaType]; } function getEwmaThroughputDict(mediaType) { if (!mediaType) { return ewmaThroughputDict } return ewmaThroughputDict[mediaType] } function getLatencyDict(mediaType) { if (!mediaType) { return latencyDict } return latencyDict[mediaType]; } function getEwmaLatencyDict(mediaType) { if (!mediaType) { return ewmaLatencyDict } return ewmaLatencyDict[mediaType]; } function getEwmaHalfLife() { return ewmaHalfLife; } /** * Reset all values */ function reset() { throughputDict = {}; latencyDict = {}; ewmaThroughputDict = {}; ewmaLatencyDict = {}; } const instance = { addEntry, getThroughputDict, getEwmaThroughputDict, getEwmaLatencyDict, getEwmaHalfLife, getLatencyDict, reset }; setup(); return instance; } ThroughputModel.__dashjs_factory_name = 'ThroughputModel'; export default FactoryMaker.getClassFactory(ThroughputModel); × 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import DashConstants from '../constants/DashConstants.js'; import DashManifestModel from '../models/DashManifestModel.js'; import Settings from '../../core/Settings.js'; import Constants from '../../streaming/constants/Constants.js'; import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js'; import ConformanceViolationConstants from '../../streaming/constants/ConformanceViolationConstants.js'; 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; { let voRepresentation = stream.getCurrentRepresentationForType(Constants.VIDEO); if (!voRepresentation) { voRepresentation = stream.getCurrentRepresentationForType(Constants.AUDIO) } // If we still got not voRepresentation we are in the startup phase and nothing was selected yet. Use the default Representation if (!voRepresentation) { const adapter = stream.getAdapter(); const mediaInfo = adapter.getMediaInfoForType(stream.getStreamInfo(), Constants.VIDEO) || adapter.getMediaInfoForType(stream.getStreamInfo(), Constants.AUDIO); const voRepresentations = adapter.getVoRepresentations(mediaInfo); 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[voRepresentation.adaptation.period.index].AdaptationSet[voRepresentation.adaptation.index]; const representation = dashManifestModel.getRepresentationFor(voRepresentation.index, adaptation); const base = representation.SegmentTemplate || representation.SegmentList; const timeline = base.SegmentTimeline; const timescale = base.timescale; const segments = timeline.S; const range = { start: 0, end: 0 }; const segmentTime = segments[0].t; const hasValidSegmentTime = !isNaN(segmentTime); const enhancedSegmentTime = hasValidSegmentTime ? segmentTime : 0; let d = 0; let segment, repeat, i, len; if (hasValidSegmentTime) { range.start = calcPresentationTimeFromMediaTime(enhancedSegmentTime / 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((enhancedSegmentTime + 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import {HTTPRequest} from '../vo/metrics/HTTPRequest.js'; import EventBus from './../../core/EventBus.js'; import Events from './../../core/events/Events.js'; import Errors from './../../core/errors/Errors.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import Debug from '../../core/Debug.js'; import URLUtils from '../utils/URLUtils.js'; 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import Debug from '../../core/Debug.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import {fromXML, generateISD} from 'imsc'; import MediaPlayerEvents from '../MediaPlayerEvents.js'; import ConformanceViolationConstants from '../constants/ConformanceViolationConstants.js'; 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; endTime = 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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} originalUrl * @param {string} targetUrl * @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 {}; } } /** * Checks for existence of \"http\" or \"https\" in a string * @param string * @returns {boolean} */ static stringHasProtocol(string) { return (/(http(s?)):\\/\\//i.test(string)) } } 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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.js'; import EventBus from '../../core/EventBus.js'; import Events from '../../core/events/Events.js'; import FactoryMaker from '../../core/FactoryMaker.js'; import URLUtils from '../utils/URLUtils.js'; import DashConstants from '../../dash/constants/DashConstants.js'; 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, parser, manifest, xlinkLoader; function setup() { eventBus.on(Events.XLINK_ELEMENT_LOADED, onXlinkElementLoaded, instance); xlinkLoader = XlinkLoader(context).create({ errHandler: config.errHandler, dashMetrics: config.dashMetrics, mediaPlayerModel: config.mediaPlayerModel, settings: config.settings }); } function setParser(value) { if (value) { parser = 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 manifest = mpd; if (manifest.Period) { elements = getElementsToResolve(manifest.Period, 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 = parser.parseXml(mergedContent).response; } 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].length; i++) { obj = manifest[DashConstants.PERIOD][i]; if (obj.hasOwnProperty(DashConstants.ADAPTATION_SET)) { elements = elements.concat(getElementsToResolve(obj[DashConstants.ADAPTATION_SET], obj, DashConstants.ADAPTATION_SET, RESOLVE_TYPE_ONLOAD)); } if (obj.hasOwnProperty(DashConstants.EVENT_STREAM)) { elements = elements.concat(getElementsToResolve(obj[DashConstants.EVENT_STREAM], 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; // 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) { parser.getIron().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, setParser: setParser, 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 84 × Search results Close "},"modules.list.html":{"id":"modules.list.html","title":"Modules","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ThroughputController ThroughputModel 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 424 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 BASE_URLS_UPDATED Triggered when the BaseURLs have been updated. Source: streaming/MediaPlayerEvents.js, line 52 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 58 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 72 BUFFER_LEVEL_UPDATED Triggered when the buffer level of a media type has been updated Source: streaming/MediaPlayerEvents.js, line 78 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 65 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 274 CAN_PLAY_THROUGH This corresponds to the CAN_PLAY_THROUGH readyState. Source: streaming/MediaPlayerEvents.js, line 282 CAPTION_CONTAINER_RESIZE Triggered when the caption container is resized. Source: streaming/MediaPlayerEvents.js, line 268 CAPTION_RENDERED Triggered when a caption is rendered. Source: streaming/MediaPlayerEvents.js, line 262 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 412 CONTENT_STEERING_REQUEST_COMPLETED Triggered when a content steering request has completed. Source: streaming/MediaPlayerEvents.js, line 430 DYNAMIC_TO_STATIC Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand). Source: streaming/MediaPlayerEvents.js, line 84 ERROR Triggered when there is an error from the element or MSE source buffer. Source: streaming/MediaPlayerEvents.js, line 90 EVENT_MODE_ON_RECEIVE Dash events are triggered as soon as they were parsed. Source: streaming/MediaPlayerEvents.js, line 406 EVENT_MODE_ON_START Dash events are triggered at their respective start points on the timeline. Source: streaming/MediaPlayerEvents.js, line 400 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 112 FRAGMENT_LOADING_COMPLETED Triggered when a fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 95 FRAGMENT_LOADING_PROGRESS Triggered when a partial fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 101 FRAGMENT_LOADING_STARTED Triggered when a fragment download has started. Source: streaming/MediaPlayerEvents.js, line 106 INBAND_PRFT Triggered when an inband prft (ProducerReferenceTime) boxes has been received. Source: streaming/MediaPlayerEvents.js, line 436 LOG Triggered when module:Debug logger methods are called. Source: streaming/MediaPlayerEvents.js, line 118 MANIFEST_LOADED Triggered when the manifest load is complete, providing the payload Source: streaming/MediaPlayerEvents.js, line 136 MANIFEST_LOADING_FINISHED Triggered when the manifest loading is finished, providing the request object information Source: streaming/MediaPlayerEvents.js, line 130 MANIFEST_LOADING_STARTED Triggered when the manifest load is started Source: streaming/MediaPlayerEvents.js, line 124 MANIFEST_VALIDITY_CHANGED Manifest validity changed - As a result of an MPD validity expiration event. Source: streaming/MediaPlayerEvents.js, line 394 METRIC_ADDED Triggered every time a new metric is added. Source: streaming/MediaPlayerEvents.js, line 154 METRIC_CHANGED Triggered when an individual metric is added, updated or cleared. Source: streaming/MediaPlayerEvents.js, line 148 METRIC_UPDATED Triggered every time a metric is updated. Source: streaming/MediaPlayerEvents.js, line 160 METRICS_CHANGED Triggered anytime there is a change to the overall metrics. Source: streaming/MediaPlayerEvents.js, line 142 PERIOD_SWITCH_COMPLETED Triggered at the stream end of a period. Source: streaming/MediaPlayerEvents.js, line 172 PERIOD_SWITCH_STARTED Triggered when a new stream (period) starts. Source: streaming/MediaPlayerEvents.js, line 166 PLAYBACK_ENDED Sent when playback completes. Source: streaming/MediaPlayerEvents.js, line 288 PLAYBACK_ERROR Sent when an error occurs. The element's error attribute contains more information. Source: streaming/MediaPlayerEvents.js, line 294 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 314 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 307 PLAYBACK_NOT_ALLOWED Sent when playback is not allowed (for example if user gesture is needed). Source: streaming/MediaPlayerEvents.js, line 301 PLAYBACK_PAUSED Sent when playback is paused. Source: streaming/MediaPlayerEvents.js, line 321 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 327 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 335 PLAYBACK_RATE_CHANGED Sent when the playback speed changes. Source: streaming/MediaPlayerEvents.js, line 343 PLAYBACK_SEEKED Sent when a seek operation completes. Source: streaming/MediaPlayerEvents.js, line 349 PLAYBACK_SEEKING Sent when a seek operation begins. Source: streaming/MediaPlayerEvents.js, line 355 PLAYBACK_STALLED Sent when the video element reports stalled Source: streaming/MediaPlayerEvents.js, line 361 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 367 PLAYBACK_TIME_UPDATED The time indicated by the element's currentTime attribute has changed. Source: streaming/MediaPlayerEvents.js, line 375 PLAYBACK_VOLUME_CHANGED Sent when the video element reports that the volume has changed Source: streaming/MediaPlayerEvents.js, line 381 PLAYBACK_WAITING Sent when the media playback has stopped because of a temporary lack of data. Source: streaming/MediaPlayerEvents.js, line 387 QUALITY_CHANGE_RENDERED Triggered when the new ABR quality is being rendered on-screen. Source: streaming/MediaPlayerEvents.js, line 184 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 178 REPRESENTATION_SWITCH Event that is dispatched whenever the player switches to a different representation Source: streaming/MediaPlayerEvents.js, line 418 STREAM_ACTIVATED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 208 STREAM_DEACTIVATED Triggered when a stream (period) is deactivated Source: streaming/MediaPlayerEvents.js, line 214 STREAM_INITIALIZED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 220 STREAM_INITIALIZING Triggered when a stream (period) is being loaded Source: streaming/MediaPlayerEvents.js, line 196 STREAM_TEARDOWN_COMPLETE Triggered when the player has been reset. Source: streaming/MediaPlayerEvents.js, line 226 STREAM_UPDATED Triggered when a stream (period) is loaded Source: streaming/MediaPlayerEvents.js, line 202 TEXT_TRACK_ADDED Triggered when a text track is added to the video element's TextTrackList Source: streaming/MediaPlayerEvents.js, line 238 TEXT_TRACKS_ADDED Triggered once all text tracks detected in the MPD are added to the video element. Source: streaming/MediaPlayerEvents.js, line 232 THROUGHPUT_MEASUREMENT_STORED Triggered when a throughput measurement based on the last segment request has been stored Source: streaming/MediaPlayerEvents.js, line 244 TRACK_CHANGE_RENDERED Triggered when the new track is being rendered. Source: streaming/MediaPlayerEvents.js, line 190 TTML_PARSED Triggered when a ttml chunk is parsed. Source: streaming/MediaPlayerEvents.js, line 250 TTML_TO_PARSE Triggered when a ttml chunk has to be parsed. Source: streaming/MediaPlayerEvents.js, line 256 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 59 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 69 KEY_MESSAGE Event ID for events delivered when the protection set receives a key message from the CDM Source: streaming/protection/ProtectionEvents.js, line 76 KEY_SESSION_CLOSED Event ID for events delivered when a key session close process has completed Source: streaming/protection/ProtectionEvents.js, line 83 KEY_SESSION_CREATED Event ID for events delivered when a new key sessions creation process has completed Source: streaming/protection/ProtectionEvents.js, line 90 KEY_SESSION_REMOVED Event ID for events delivered when a key session removal process has completed Source: streaming/protection/ProtectionEvents.js, line 97 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 104 KEY_SYSTEM_ACCESS_COMPLETE Event ID for events delivered when a key system access procedure has completed Source: streaming/protection/ProtectionEvents.js, line 111 KEY_SYSTEM_SELECTED Event ID for events delivered when a key system selection procedure completes Source: streaming/protection/ProtectionEvents.js, line 118 LICENSE_REQUEST_COMPLETE Event ID for events delivered when a license request procedure has completed Source: streaming/protection/ProtectionEvents.js, line 125 LICENSE_REQUEST_SENDING Sending a license rquest Source: streaming/protection/ProtectionEvents.js, line 132 PROTECTION_CREATED Event ID for events delivered when the Protection system is detected and created. Source: streaming/protection/ProtectionEvents.js, line 144 PROTECTION_DESTROYED Event ID for events delivered when the Protection system is destroyed. Source: streaming/protection/ProtectionEvents.js, line 150 × Search results Close "},"classes.list.html":{"id":"classes.list.html","title":"Classes","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ThroughputController ThroughputModel 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 424 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 BASE_URLS_UPDATED Triggered when the BaseURLs have been updated. Source: streaming/MediaPlayerEvents.js, line 52 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 58 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 72 BUFFER_LEVEL_UPDATED Triggered when the buffer level of a media type has been updated Source: streaming/MediaPlayerEvents.js, line 78 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 65 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 274 CAN_PLAY_THROUGH This corresponds to the CAN_PLAY_THROUGH readyState. Source: streaming/MediaPlayerEvents.js, line 282 CAPTION_CONTAINER_RESIZE Triggered when the caption container is resized. Source: streaming/MediaPlayerEvents.js, line 268 CAPTION_RENDERED Triggered when a caption is rendered. Source: streaming/MediaPlayerEvents.js, line 262 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 412 CONTENT_STEERING_REQUEST_COMPLETED Triggered when a content steering request has completed. Source: streaming/MediaPlayerEvents.js, line 430 DYNAMIC_TO_STATIC Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand). Source: streaming/MediaPlayerEvents.js, line 84 ERROR Triggered when there is an error from the element or MSE source buffer. Source: streaming/MediaPlayerEvents.js, line 90 EVENT_MODE_ON_RECEIVE Dash events are triggered as soon as they were parsed. Source: streaming/MediaPlayerEvents.js, line 406 EVENT_MODE_ON_START Dash events are triggered at their respective start points on the timeline. Source: streaming/MediaPlayerEvents.js, line 400 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 112 FRAGMENT_LOADING_COMPLETED Triggered when a fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 95 FRAGMENT_LOADING_PROGRESS Triggered when a partial fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 101 FRAGMENT_LOADING_STARTED Triggered when a fragment download has started. Source: streaming/MediaPlayerEvents.js, line 106 INBAND_PRFT Triggered when an inband prft (ProducerReferenceTime) boxes has been received. Source: streaming/MediaPlayerEvents.js, line 436 LOG Triggered when module:Debug logger methods are called. Source: streaming/MediaPlayerEvents.js, line 118 MANIFEST_LOADED Triggered when the manifest load is complete, providing the payload Source: streaming/MediaPlayerEvents.js, line 136 MANIFEST_LOADING_FINISHED Triggered when the manifest loading is finished, providing the request object information Source: streaming/MediaPlayerEvents.js, line 130 MANIFEST_LOADING_STARTED Triggered when the manifest load is started Source: streaming/MediaPlayerEvents.js, line 124 MANIFEST_VALIDITY_CHANGED Manifest validity changed - As a result of an MPD validity expiration event. Source: streaming/MediaPlayerEvents.js, line 394 METRIC_ADDED Triggered every time a new metric is added. Source: streaming/MediaPlayerEvents.js, line 154 METRIC_CHANGED Triggered when an individual metric is added, updated or cleared. Source: streaming/MediaPlayerEvents.js, line 148 METRIC_UPDATED Triggered every time a metric is updated. Source: streaming/MediaPlayerEvents.js, line 160 METRICS_CHANGED Triggered anytime there is a change to the overall metrics. Source: streaming/MediaPlayerEvents.js, line 142 PERIOD_SWITCH_COMPLETED Triggered at the stream end of a period. Source: streaming/MediaPlayerEvents.js, line 172 PERIOD_SWITCH_STARTED Triggered when a new stream (period) starts. Source: streaming/MediaPlayerEvents.js, line 166 PLAYBACK_ENDED Sent when playback completes. Source: streaming/MediaPlayerEvents.js, line 288 PLAYBACK_ERROR Sent when an error occurs. The element's error attribute contains more information. Source: streaming/MediaPlayerEvents.js, line 294 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 314 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 307 PLAYBACK_NOT_ALLOWED Sent when playback is not allowed (for example if user gesture is needed). Source: streaming/MediaPlayerEvents.js, line 301 PLAYBACK_PAUSED Sent when playback is paused. Source: streaming/MediaPlayerEvents.js, line 321 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 327 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 335 PLAYBACK_RATE_CHANGED Sent when the playback speed changes. Source: streaming/MediaPlayerEvents.js, line 343 PLAYBACK_SEEKED Sent when a seek operation completes. Source: streaming/MediaPlayerEvents.js, line 349 PLAYBACK_SEEKING Sent when a seek operation begins. Source: streaming/MediaPlayerEvents.js, line 355 PLAYBACK_STALLED Sent when the video element reports stalled Source: streaming/MediaPlayerEvents.js, line 361 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 367 PLAYBACK_TIME_UPDATED The time indicated by the element's currentTime attribute has changed. Source: streaming/MediaPlayerEvents.js, line 375 PLAYBACK_VOLUME_CHANGED Sent when the video element reports that the volume has changed Source: streaming/MediaPlayerEvents.js, line 381 PLAYBACK_WAITING Sent when the media playback has stopped because of a temporary lack of data. Source: streaming/MediaPlayerEvents.js, line 387 QUALITY_CHANGE_RENDERED Triggered when the new ABR quality is being rendered on-screen. Source: streaming/MediaPlayerEvents.js, line 184 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 178 REPRESENTATION_SWITCH Event that is dispatched whenever the player switches to a different representation Source: streaming/MediaPlayerEvents.js, line 418 STREAM_ACTIVATED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 208 STREAM_DEACTIVATED Triggered when a stream (period) is deactivated Source: streaming/MediaPlayerEvents.js, line 214 STREAM_INITIALIZED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 220 STREAM_INITIALIZING Triggered when a stream (period) is being loaded Source: streaming/MediaPlayerEvents.js, line 196 STREAM_TEARDOWN_COMPLETE Triggered when the player has been reset. Source: streaming/MediaPlayerEvents.js, line 226 STREAM_UPDATED Triggered when a stream (period) is loaded Source: streaming/MediaPlayerEvents.js, line 202 TEXT_TRACK_ADDED Triggered when a text track is added to the video element's TextTrackList Source: streaming/MediaPlayerEvents.js, line 238 TEXT_TRACKS_ADDED Triggered once all text tracks detected in the MPD are added to the video element. Source: streaming/MediaPlayerEvents.js, line 232 THROUGHPUT_MEASUREMENT_STORED Triggered when a throughput measurement based on the last segment request has been stored Source: streaming/MediaPlayerEvents.js, line 244 TRACK_CHANGE_RENDERED Triggered when the new track is being rendered. Source: streaming/MediaPlayerEvents.js, line 190 TTML_PARSED Triggered when a ttml chunk is parsed. Source: streaming/MediaPlayerEvents.js, line 250 TTML_TO_PARSE Triggered when a ttml chunk has to be parsed. Source: streaming/MediaPlayerEvents.js, line 256 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 59 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 69 KEY_MESSAGE Event ID for events delivered when the protection set receives a key message from the CDM Source: streaming/protection/ProtectionEvents.js, line 76 KEY_SESSION_CLOSED Event ID for events delivered when a key session close process has completed Source: streaming/protection/ProtectionEvents.js, line 83 KEY_SESSION_CREATED Event ID for events delivered when a new key sessions creation process has completed Source: streaming/protection/ProtectionEvents.js, line 90 KEY_SESSION_REMOVED Event ID for events delivered when a key session removal process has completed Source: streaming/protection/ProtectionEvents.js, line 97 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 104 KEY_SYSTEM_ACCESS_COMPLETE Event ID for events delivered when a key system access procedure has completed Source: streaming/protection/ProtectionEvents.js, line 111 KEY_SYSTEM_SELECTED Event ID for events delivered when a key system selection procedure completes Source: streaming/protection/ProtectionEvents.js, line 118 LICENSE_REQUEST_COMPLETE Event ID for events delivered when a license request procedure has completed Source: streaming/protection/ProtectionEvents.js, line 125 LICENSE_REQUEST_SENDING Sending a license rquest Source: streaming/protection/ProtectionEvents.js, line 132 PROTECTION_CREATED Event ID for events delivered when the Protection system is detected and created. Source: streaming/protection/ProtectionEvents.js, line 144 PROTECTION_DESTROYED Event ID for events delivered when the Protection system is destroyed. Source: streaming/protection/ProtectionEvents.js, line 150 × Search results Close "},"index.html":{"id":"index.html","title":"Index","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 37 Members APPEND_ERROR_CODE Error code returned when the append operation in the SourceBuffer failed Source: core/errors/Errors.js, line 84 CAPABILITY_MEDIAKEYS_ERROR_CODE Error code returned when Protected contents are not supported Source: core/errors/Errors.js, line 104 CAPABILITY_MEDIASOURCE_ERROR_CODE Error code returned when MediaSource is not supported by the browser Source: core/errors/Errors.js, line 99 DATA_UPDATE_FAILED_ERROR_CODE Error code returned when updating the internal objects after loading an MPD failed Source: core/errors/Errors.js, line 94 DOWNLOAD_ERROR_ID_CONTENT_CODE Error code returned when loading the media content failed Source: core/errors/Errors.js, line 119 DOWNLOAD_ERROR_ID_INITIALIZATION_CODE Error code returned when loading the init segment failed Source: core/errors/Errors.js, line 124 DOWNLOAD_ERROR_ID_MANIFEST_CODE Error code returned when loading the manifest failed Source: core/errors/Errors.js, line 109 DOWNLOAD_ERROR_ID_SIDX_CODE Error code returned when loading the sidx failed Source: core/errors/Errors.js, line 114 DOWNLOAD_ERROR_ID_XLINK_CODE Error code returned when loading the XLink content failed Source: core/errors/Errors.js, line 129 FRAGMENT_LOADER_LOADING_FAILURE_ERROR_CODE Error code returned when loading a fragment failed Source: core/errors/Errors.js, line 69 FRAGMENT_LOADER_NULL_REQUEST_ERROR_CODE Error code returned when the FragmentLoader did not receive a request object Source: core/errors/Errors.js, line 74 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 150 MANIFEST_ERROR_ID_NOSTREAMS_CODE Error code returned when no stream (period) has been detected in the manifest Source: core/errors/Errors.js, line 139 MANIFEST_ERROR_ID_PARSE_CODE Error code returned when parsing the MPD resulted in a logical error Source: core/errors/Errors.js, line 134 MANIFEST_LOADER_LOADING_FAILURE_ERROR_CODE Error code returned when a manifest loading error occurs Source: core/errors/Errors.js, line 49 MANIFEST_LOADER_PARSING_FAILURE_ERROR_CODE Error code returned when a manifest parsing error occurs Source: core/errors/Errors.js, line 44 MEDIASOURCE_TYPE_UNSUPPORTED_CODE Error code returned when a media source type is not supported Source: core/errors/Errors.js, line 155 REMOVE_ERROR_CODE Error code returned when the remove operation in the SourceBuffer failed Source: core/errors/Errors.js, line 89 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 59 TIME_SYNC_FAILED_ERROR_CODE Error code returned when the time synchronization failed Source: core/errors/Errors.js, line 64 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 144 URL_RESOLUTION_FAILED_GENERIC_ERROR_CODE Error code returned when the BaseUrl resolution failed Source: core/errors/Errors.js, line 79 XLINK_LOADER_LOADING_FAILURE_ERROR_CODE Error code returned when a xlink loading error occurs Source: core/errors/Errors.js, line 54 × Search results Close "},"MediaPlayerEvents.html":{"id":"MediaPlayerEvents.html","title":"Class: MediaPlayerEvents","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 424 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 BASE_URLS_UPDATED Triggered when the BaseURLs have been updated. Source: streaming/MediaPlayerEvents.js, line 52 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 58 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 72 BUFFER_LEVEL_UPDATED Triggered when the buffer level of a media type has been updated Source: streaming/MediaPlayerEvents.js, line 78 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 65 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 274 CAN_PLAY_THROUGH This corresponds to the CAN_PLAY_THROUGH readyState. Source: streaming/MediaPlayerEvents.js, line 282 CAPTION_CONTAINER_RESIZE Triggered when the caption container is resized. Source: streaming/MediaPlayerEvents.js, line 268 CAPTION_RENDERED Triggered when a caption is rendered. Source: streaming/MediaPlayerEvents.js, line 262 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 412 CONTENT_STEERING_REQUEST_COMPLETED Triggered when a content steering request has completed. Source: streaming/MediaPlayerEvents.js, line 430 DYNAMIC_TO_STATIC Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand). Source: streaming/MediaPlayerEvents.js, line 84 ERROR Triggered when there is an error from the element or MSE source buffer. Source: streaming/MediaPlayerEvents.js, line 90 EVENT_MODE_ON_RECEIVE Dash events are triggered as soon as they were parsed. Source: streaming/MediaPlayerEvents.js, line 406 EVENT_MODE_ON_START Dash events are triggered at their respective start points on the timeline. Source: streaming/MediaPlayerEvents.js, line 400 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 112 FRAGMENT_LOADING_COMPLETED Triggered when a fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 95 FRAGMENT_LOADING_PROGRESS Triggered when a partial fragment download has completed. Source: streaming/MediaPlayerEvents.js, line 101 FRAGMENT_LOADING_STARTED Triggered when a fragment download has started. Source: streaming/MediaPlayerEvents.js, line 106 INBAND_PRFT Triggered when an inband prft (ProducerReferenceTime) boxes has been received. Source: streaming/MediaPlayerEvents.js, line 436 LOG Triggered when module:Debug logger methods are called. Source: streaming/MediaPlayerEvents.js, line 118 MANIFEST_LOADED Triggered when the manifest load is complete, providing the payload Source: streaming/MediaPlayerEvents.js, line 136 MANIFEST_LOADING_FINISHED Triggered when the manifest loading is finished, providing the request object information Source: streaming/MediaPlayerEvents.js, line 130 MANIFEST_LOADING_STARTED Triggered when the manifest load is started Source: streaming/MediaPlayerEvents.js, line 124 MANIFEST_VALIDITY_CHANGED Manifest validity changed - As a result of an MPD validity expiration event. Source: streaming/MediaPlayerEvents.js, line 394 METRIC_ADDED Triggered every time a new metric is added. Source: streaming/MediaPlayerEvents.js, line 154 METRIC_CHANGED Triggered when an individual metric is added, updated or cleared. Source: streaming/MediaPlayerEvents.js, line 148 METRIC_UPDATED Triggered every time a metric is updated. Source: streaming/MediaPlayerEvents.js, line 160 METRICS_CHANGED Triggered anytime there is a change to the overall metrics. Source: streaming/MediaPlayerEvents.js, line 142 PERIOD_SWITCH_COMPLETED Triggered at the stream end of a period. Source: streaming/MediaPlayerEvents.js, line 172 PERIOD_SWITCH_STARTED Triggered when a new stream (period) starts. Source: streaming/MediaPlayerEvents.js, line 166 PLAYBACK_ENDED Sent when playback completes. Source: streaming/MediaPlayerEvents.js, line 288 PLAYBACK_ERROR Sent when an error occurs. The element's error attribute contains more information. Source: streaming/MediaPlayerEvents.js, line 294 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 314 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 307 PLAYBACK_NOT_ALLOWED Sent when playback is not allowed (for example if user gesture is needed). Source: streaming/MediaPlayerEvents.js, line 301 PLAYBACK_PAUSED Sent when playback is paused. Source: streaming/MediaPlayerEvents.js, line 321 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 327 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 335 PLAYBACK_RATE_CHANGED Sent when the playback speed changes. Source: streaming/MediaPlayerEvents.js, line 343 PLAYBACK_SEEKED Sent when a seek operation completes. Source: streaming/MediaPlayerEvents.js, line 349 PLAYBACK_SEEKING Sent when a seek operation begins. Source: streaming/MediaPlayerEvents.js, line 355 PLAYBACK_STALLED Sent when the video element reports stalled Source: streaming/MediaPlayerEvents.js, line 361 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 367 PLAYBACK_TIME_UPDATED The time indicated by the element's currentTime attribute has changed. Source: streaming/MediaPlayerEvents.js, line 375 PLAYBACK_VOLUME_CHANGED Sent when the video element reports that the volume has changed Source: streaming/MediaPlayerEvents.js, line 381 PLAYBACK_WAITING Sent when the media playback has stopped because of a temporary lack of data. Source: streaming/MediaPlayerEvents.js, line 387 QUALITY_CHANGE_RENDERED Triggered when the new ABR quality is being rendered on-screen. Source: streaming/MediaPlayerEvents.js, line 184 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 178 REPRESENTATION_SWITCH Event that is dispatched whenever the player switches to a different representation Source: streaming/MediaPlayerEvents.js, line 418 STREAM_ACTIVATED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 208 STREAM_DEACTIVATED Triggered when a stream (period) is deactivated Source: streaming/MediaPlayerEvents.js, line 214 STREAM_INITIALIZED Triggered when a stream (period) is activated Source: streaming/MediaPlayerEvents.js, line 220 STREAM_INITIALIZING Triggered when a stream (period) is being loaded Source: streaming/MediaPlayerEvents.js, line 196 STREAM_TEARDOWN_COMPLETE Triggered when the player has been reset. Source: streaming/MediaPlayerEvents.js, line 226 STREAM_UPDATED Triggered when a stream (period) is loaded Source: streaming/MediaPlayerEvents.js, line 202 TEXT_TRACK_ADDED Triggered when a text track is added to the video element's TextTrackList Source: streaming/MediaPlayerEvents.js, line 238 TEXT_TRACKS_ADDED Triggered once all text tracks detected in the MPD are added to the video element. Source: streaming/MediaPlayerEvents.js, line 232 THROUGHPUT_MEASUREMENT_STORED Triggered when a throughput measurement based on the last segment request has been stored Source: streaming/MediaPlayerEvents.js, line 244 TRACK_CHANGE_RENDERED Triggered when the new track is being rendered. Source: streaming/MediaPlayerEvents.js, line 190 TTML_PARSED Triggered when a ttml chunk is parsed. Source: streaming/MediaPlayerEvents.js, line 250 TTML_TO_PARSE Triggered when a ttml chunk has to be parsed. Source: streaming/MediaPlayerEvents.js, line 256 × Search results Close "},"MediaPlayerModel.html":{"id":"MediaPlayerModel.html","title":"Class: MediaPlayerModel","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 51 Methods &lt;inner&gt; _checkMaxPlaybackRate(rate, log) Checks the supplied max playback rate is a valid vlaue and within supported limits Parameters: Name Type Description rate number Supplied max playback rate log boolean wether to shown warning or not Source: streaming/models/MediaPlayerModel.js, line 103 Returns: corrected max playback rate Type number &lt;inner&gt; _checkMinPlaybackRate(rate, log) Checks the supplied min playback rate is a valid vlaue and within supported limits Parameters: Name Type Description rate number Supplied min playback rate log boolean wether to shown warning or not Source: streaming/models/MediaPlayerModel.js, line 80 Returns: corrected min playback rate Type number &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 184 &lt;inner&gt; getBufferTimeDefault() Returns the stable buffer time taking the live delay into account Source: streaming/models/MediaPlayerModel.js, line 220 Returns: Type number &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 124 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 171 Returns: Type boolean &lt;inner&gt; getCatchupPlaybackRates() Returns the minimum and maximum playback rates to be used when applying the catchup mechanism If only one of the min/max values has been set then the other will default to 0 (no playback rate change). Source: streaming/models/MediaPlayerModel.js, line 142 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 206 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 232 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 243 Returns: Type number × Search results Close "},"MetricsReportingEvents.html":{"id":"MetricsReportingEvents.html","title":"Class: MetricsReportingEvents","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 applyPatchToManifest(manifest, patch) Takes a given patch and applies it to the provided manifest, assumes patch is valid for manifest Parameters: Name Type Description manifest object patch object Source: dash/DashAdapter.js, line 827 areMediaInfosEqual(mInfoOne, mInfoTwo) Compares two mediaInfo objects Parameters: Name Type Description mInfoOne MediaInfo mInfoTwo MediaInfo Source: dash/DashAdapter.js, line 159 Returns: Type boolean 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 253 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 547 Returns: availabilityStartTime Type number 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 734 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 722 Returns: codec Type String getContentSteering(manifest) Returns the ContentSteering element of the MPD Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 607 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 571 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 751 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 559 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 119 Returns: Type boolean getIsPatch(manifest) Checks if the manifest is actually just a patch manifest Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 686 Returns: Type boolean getIsTypeOf(adaptation, type) Checks if the given AdaptationSet is from the given media type Parameters: Name Type Description adaptation object type string Source: dash/DashAdapter.js, line 787 Returns: Type boolean getLocation(manifest) Returns the location element of the MPD Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 618 Returns: location Type String getMainAdaptationForType(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 134 Returns: adaptation Type null | object 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 630 Returns: manifestUpdatePeriod Type NaN | 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 95 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 595 Returns: MPD Type object getPatchLocation(manifest) Returns the patch locations of the MPD if existing and if they are still valid Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 652 Returns: patch location Type Array.&lt;PatchLocation&gt; getPeriodById(id) Returns the voPeriod object for a given id Parameters: Name Type Description id String Source: dash/DashAdapter.js, line 764 Returns: Type object | 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 362 Returns: producerReferenceTimes Type object getPublishTime(manifest) Returns the publish time from the manifest Parameters: Name Type Description manifest object Source: dash/DashAdapter.js, line 641 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 339 Returns: realAdaptation Type object getRealPeriodByIndex(index) Returns the period as defined in the DashManifestModel for a given index Parameters: Name Type Description index number Source: dash/DashAdapter.js, line 396 Returns: 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 583 Returns: periods Type Array getSuggestedPresentationDelay() Returns the suggestedPresentationDelay as specified in the manifest Source: dash/DashAdapter.js, line 535 Returns: suggestedPresentationDelay Type String getUTCTimingSources() Returns the UTC Timing Sources specified in the manifest Source: dash/DashAdapter.js, line 524 Returns: utcTimingSources Type Array getVoRepresentations(mediaInfo) Returns all voRepresentations for a given mediaInfo Parameters: Name Type Description mediaInfo object Source: dash/DashAdapter.js, line 407 Returns: voReps Type Array isPatchValid(manifest, patch) Checks if the supplied manifest is compatible for application of the supplied patch Parameters: Name Type Description manifest object patch object Source: dash/DashAdapter.js, line 803 Returns: Type boolean × Search results Close "},"module-DashMetrics.html":{"id":"module-DashMetrics.html","title":"Module: DashMetrics","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 40 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 229 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 114 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 102 Returns: Type number getCurrentDroppedFrames() Returns the number of dropped frames Source: dash/DashMetrics.js, line 243 Returns: Type * getCurrentDVRInfo(mediaType) Returns the current DVR window Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 373 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 165 Returns: Type * getCurrentManifestUpdate() Returns the current manifest update information Source: dash/DashMetrics.js, line 296 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 76 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 265 Returns: Type * getHttpRequests(mediaType) Returns all HTTP requests for a given media type Parameters: Name Type Description mediaType MediaType Source: dash/DashMetrics.js, line 200 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 432 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 399 Returns: Type * × Search results Close "},"module-MediaPlayer.html":{"id":"module-MediaPlayer.html","title":"Module: MediaPlayer","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 89 Members &lt;inner, constant&gt; ARRAY_NOT_SUPPORTED_ERROR :string error string thrown when settings object was called using an array. Type: string Source: streaming/MediaPlayer.js, line 121 &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 106 &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 116 &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 101 &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 111 &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 96 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 1018 Throws: BAD_ARGUMENT_ERROR if called with invalid arguments. addRequestInterceptor(interceptor) Adds a request interceptor. This enables application to monitor, manipulate, overwrite any request parameter and/or request data. The provided callback function shall return a promise with updated request that shall be resolved once the process of the request is completed. The interceptors are applied in the order they are added. Parameters: Name Type Description interceptor function the request interceptor callback Source: streaming/MediaPlayer.js, line 1705 addResponseInterceptor(interceptor) Adds a response interceptor. This enables application to monitor, manipulate, overwrite the response data The provided callback function shall return a promise with updated response that shall be resolved once the process of the response is completed. The interceptors are applied in the order they are added. Parameters: Name Type Description interceptor function the response interceptor Source: streaming/MediaPlayer.js, line 1727 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 1079 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 1808 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 1948 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 1377 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 1335 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 1108 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 2049 Returns: A formatted time code string. Type string destroy() Completely destroys the media player and frees all memory. Source: streaming/MediaPlayer.js, line 478 duration() Duration of the media's playback, in seconds. Source: streaming/MediaPlayer.js, line 907 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 949 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 1241 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 1223 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 2083 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 2032 Returns: A formatted time and date string. Type string getActiveStream() This method returns the active stream Source: streaming/MediaPlayer.js, line 2094 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function getAutoPlay() Source: streaming/MediaPlayer.js, line 985 Returns: The current autoPlay state. Type boolean getAverageThroughput(type, calculationMode, sampleSize) Returns the average throughput computed in the ThroughputController in kbit/s Parameters: Name Type Default Description type MediaType calculationMode string null sampleSize number Source: streaming/MediaPlayer.js, line 1139 Returns: value Type number 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 791 Returns: The length of the buffer for the given media type, in seconds, or NaN Type number getCurrentLiveLatency() Source: streaming/MediaPlayer.js, line 995 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 getCurrentRepresentationForType(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 1411 See: getCurrentRepresentationForType() Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: the quality index, 0 corresponding to the lowest bitrate Type Representation | null getCurrentTrackFor(type) Parameters: Name Type Description type MediaType Source: streaming/MediaPlayer.js, line 1583 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 2110 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 1203 See: module:DashMetrics Returns: Type Object getDebug() Use this method to access the dash.js logging class. Source: streaming/MediaPlayer.js, line 540 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 838 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 818 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 1631 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 703 Returns: Type boolean getOfflineController() Detects if Offline is included and returns an instance of OfflineController.js Source: streaming/MediaPlayer.js, line 1183 getPlaybackRate() Returns the current playback rate. Source: streaming/MediaPlayer.js, line 726 Returns: Type number getProtectionController() Detects if Protection is included and returns an instance of ProtectionController.js Source: streaming/MediaPlayer.js, line 1798 getRepresentationsByType(type, streamId) Parameters: Name Type Default Description type MediaType streamId string null Source: streaming/MediaPlayer.js, line 1511 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: Type Array getSettings() Get the current settings object being used on the player. Source: streaming/MediaPlayer.js, line 1984 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 1914 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 1527 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 862 Returns: The target live delay Type number 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 1542 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 1565 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 1365 Returns: Type Object getVersion() Current version of Dash.js Source: streaming/MediaPlayer.js, line 529 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 1320 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 772 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 1166 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 280 See: attachSource() setAutoPlay() isDynamic() Returns a Boolean that indicates whether the media is in the process of dynamic. Source: streaming/MediaPlayer.js, line 690 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 748 Returns: Type boolean isPaused() Returns a Boolean that indicates whether the Video Element is paused. Source: streaming/MediaPlayer.js, line 613 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 492 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 676 Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function Returns: Type boolean isTextEnabled() Return if text is enabled Source: streaming/MediaPlayer.js, line 1258 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 519 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 506 pause() This method will call pause on the native Video Element. Source: streaming/MediaPlayer.js, line 599 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 583 See: attachSource() Throws: PLAYBACK_NOT_INITIALIZED_ERROR if called before initializePlayback function preload() Causes the player to begin streaming the media as set by the attachSource() method in preparation for playing. It specifically does not require a view to be attached with attachView() to begin preloading. When a view is attached after preloading, the buffered data is transferred to the attached mediaSource buffers. Source: streaming/MediaPlayer.js, line 563 See: attachSource() attachView() Throws: SOURCE_NOT_ATTACHED_ERROR if called before attachSource 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 1848 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 1667 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 1749 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 1761 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 1029 removeAllABRCustomRule() Remove all ABR custom rules Source: streaming/MediaPlayer.js, line 1038 removeRequestInterceptor(interceptor) Removes a request interceptor. Parameters: Name Type Description interceptor function the request interceptor callback Source: streaming/MediaPlayer.js, line 1715 removeResponseInterceptor(interceptor) Removes a response interceptor. Parameters: Name Type Description interceptor function the request interceptor Source: streaming/MediaPlayer.js, line 1737 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 1093 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 448 resetSettings() Resets the settings object back to the default. Source: streaming/MediaPlayer.js, line 2017 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 1125 See: addUTCTimingSource() retrieveManifest(url, callback) Allows application to retrieve a manifest. Manifest loading is asynchronous 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 1887 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 632 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 975 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 206 setCurrentTrack(track [, noSettingsSave]) Parameters: Name Type Argument Default Description track MediaInfo instance of MediaInfo noSettingsSave boolean &lt;optional&gt; false specify if settings from the track must not be saved for incoming track selection Source: streaming/MediaPlayer.js, line 1645 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 (object:{schemeIdUri,value} or value-primitive), audioChannelConfiguration: audioChannelConfigurationValue (object:{schemeIdUri,value} or value-primitive (assumes schemeIdUri='urn:mpeg:mpegB:cicp:ChannelConfiguration')), accessibility: accessibilityValue (object:{schemeIdUri,value} or value-primitive (assumes schemeIdUri='urn:mpeg:dash:role:2011')), role: roleValue (object:{schemeIdUri,value} or value-primitive (assumes schemeIdUri='urn:mpeg:dash:role:2011')) } Parameters: Name Type Description type MediaType value Object Source: streaming/MediaPlayer.js, line 1608 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 737 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 716 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 1823 See: initialize() dashjs.Protection.events.PROTECTION_CREATED setRepresentationForTypeById(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 Description type MediaType 'video', 'audio' or 'image' value number the quality index, 0 corresponding to the lowest bitrate forceReplace boolean true if segments have to be replaced by segments of the new quality Source: streaming/MediaPlayer.js, line 1444 Throws: STREAMING_NOT_INITIALIZED_ERROR if called before initializePlayback function setRepresentationForTypeByIndex(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 Description type MediaType 'video', 'audio' or 'image' value number the quality index, 0 corresponding to the lowest absolute index forceReplace boolean true if segments have to be replaced by segments of the new quality Source: streaming/MediaPlayer.js, line 1479 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 1277 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 759 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 1153 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 882 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 930 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 1677 unregisterLicenseRequestFilter(filter) Unregisters a license request filter. Parameters: Name Type Description filter function the license request filter callback Source: streaming/MediaPlayer.js, line 1771 unregisterLicenseResponseFilter(filter) Unregisters a license response filter. Parameters: Name Type Description filter function the license response filter callback Source: streaming/MediaPlayer.js, line 1781 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 2007 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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 AbandonRequestsRule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule parameters object &lt;optional&gt; {abandonDurationMultiplier=1.8, minSegmentDownloadTimeThresholdInMs=500, minThroughputSamplesThreshold=6} Configures the rule specific parameters. abandonDurationMultiplier: Factor to multiply with the segment duration to compare against the estimated remaining download time of the current segment. See code example above. minSegmentDownloadTimeThresholdInMs: The AbandonRequestRule only kicks if the download time of the current segment exceeds this value. minThroughputSamplesThreshold: Minimum throughput samples (equivalent to number of progress events) required before the AbandonRequestRule kicks in. Source: core/Settings.js, line 731 AbrRules Type: Object Properties: Name Type Argument Description throughputRule module:Settings~ThroughputRule &lt;optional&gt; Configuration of the Throughput rule bolaRule module:Settings~BolaRule &lt;optional&gt; Configuration of the BOLA rule insufficientBufferRule module:Settings~InsufficientBufferRule &lt;optional&gt; Configuration of the Insufficient Buffer rule switchHistoryRule module:Settings~SwitchHistoryRule &lt;optional&gt; Configuration of the Switch History rule droppedFramesRule module:Settings~DroppedFramesRule &lt;optional&gt; Configuration of the Dropped Frames rule abandonRequestsRule module:Settings~AbandonRequestsRule &lt;optional&gt; Configuration of the Abandon Requests rule l2ARule module:Settings~L2ARule &lt;optional&gt; Configuration of the L2A rule loLPRule module:Settings~LoLPRule &lt;optional&gt; Configuration of the LoLP rule Source: core/Settings.js, line 666 AbrSettings Type: Object Properties: Name Type Argument Default Description 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. rules module:Settings~AbrRules &lt;optional&gt; Enable/Disable individual ABR rules. Note that if the throughputRule and the bolaRule are activated at the same time we switch to a dynamic mode. In the dynamic mode either ThroughputRule or BolaRule are active but not both at the same time. l2ARule and loLPRule are ABR rules that are designed for low latency streams. They are tested as standalone rules meaning the other rules should be deactivated when choosing these rules. throughput module:Settings~ThroughputSettings &lt;optional&gt; Settings related to throughput calculation 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. 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. autoSwitchBitrate module:Settings~AudioVideoSettings &lt;optional&gt; {audio: true, video: true} Indicates whether the player should enable ABR algorithms to switch the bitrate. Source: core/Settings.js, line 635 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 405 BolaRule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule Source: core/Settings.js, line 692 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| bufferTimeDefault number &lt;optional&gt; 18 The time that the internal buffer target will be set to when not playing at the top quality. 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 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. useChangeTypeForTrackSwitch boolean &lt;optional&gt; true If this flag is set to true then dash.js will use the MSE v.2 API call \"changeType()\" before switching to a different track. Note that some platforms might not implement the changeType functio. dash.js is checking for the availability before trying to call it. Source: core/Settings.js, line 339 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 454 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 627 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; 5 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; \"query\" 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 796 CmsdAbrSettings Type: Object Properties: Name Type Argument Default Description applyMb boolean &lt;optional&gt; false Set to true if dash.js should apply CMSD maximum suggested bitrate in ABR logic. etpWeightRatio number &lt;optional&gt; 0 Sets the weight ratio (between 0 and 1) that shall be applied on CMSD estimated throuhgput compared to measured throughput when calculating throughput. Source: core/Settings.js, line 834 CmsdSettings Type: Object Properties: Name Type Argument Default Description enabled boolean &lt;optional&gt; false Enable or disable the CMSD response headers parsing. abr module:Settings~CmsdAbrSettings &lt;optional&gt; Sets additional ABR rules based on CMSD response headers. Source: core/Settings.js, line 826 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 413 DroppedFramesRule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule parameters object &lt;optional&gt; {minimumSampleSize=375, droppedFramesPercentageThreshold=0.15} Configures the rule specific parameters. minimumSampleSize: Sum of rendered and dropped frames required for each Representation before the rule kicks in. droppedFramesPercentageThreshold: Minimum percentage of dropped frames to trigger a quality down switch. Values are defined in the range of 0 - 1. Source: core/Settings.js, line 720 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 446 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 464 InsufficientBufferRule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule parameters object &lt;optional&gt; {throughputSafetyFactor=0.7, segmentIgnoreCount=2} Configures the rule specific parameters. throughputSafetyFactor: The safety factor that is applied to the derived throughput, see example in the Description. segmentIgnoreCount: This rule is not taken into account until the first segmentIgnoreCount media segments have been appended to the buffer. Source: core/Settings.js, line 698 L2ARule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule Source: core/Settings.js, line 743 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; {min: NaN, max: NaN} Use this parameter to set the minimum and maximum catch up rates, as percentages, 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 min catch up rate are in the range -0.5 to 0 (-50% to 0% playback rate decrease) Valid values for max catch up rate are in the range 0 to 1 (0% to 100% playback rate increase). Set min and max to NaN to turn off live catch up feature. These playback rate limits take precedence over any PlaybackRate values in ServiceDescription elements in an MPD. If only one of the min/max properties is given a value, the property without a value will not fall back to a ServiceDescription value. Its default value of NaN will be used. Note: Catch-up mechanism is only applied when playing low latency live streams. playbackBufferMin number &lt;optional&gt; 0.5 Use this parameter to specify the minimum buffer which is used for LoL+ based playback rate reduction. enabled boolean &lt;optional&gt; null 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 544 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; NaN 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 319 LoLPRule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule Source: core/Settings.js, line 749 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 842 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: false, applyServiceDescription: true, applyProducerReferenceTime: true, applyContentSteering: true, eventControllerRefreshDelay: 100, enableManifestDurationMismatchFix: true, parseInbandPrft: false, enableManifestTimescaleMismatchFix: false, 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, bufferTimeDefault: 18, longFormContentDurationThreshold: 600, stallThreshold: 0.3, useAppendWindow: true, setStallState: true, avoidCurrentTimeRangePruning: false, useChangeTypeForTrackSwitch: true }, 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: 500, lowLatencyTimeout: 0, scheduleWhilePaused: true }, text: { defaultEnabled: true, extendSegmentedCues: true, webvtt: { customRenderingEnabled: false } }, liveCatchup: { maxDrift: NaN, playbackRate: {min: NaN, max: NaN}, playbackBufferMin: 0.5, enabled: null, mode: Constants.LIVE_CATCHUP_MODE_DEFAULT }, lastBitrateCachingInfo: { enabled: true, ttl: 360000 }, lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 }, saveLastMediaSettingsForCurrentStreamingSession: true, 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, fragmentRequestProgressTimeout: -1, manifestRequestTimeout: 10000, 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: { limitBitrateByPortal: false, usePixelRatioInLimitBitrateByPortal: false, rules: { throughputRule: { active: true }, bolaRule: { active: true }, insufficientBufferRule: { active: true, parameters: { throughputSafetyFactor: 0.7, segmentIgnoreCount: 2 } }, switchHistoryRule: { active: true, parameters: { sampleSize: 8, switchPercentageThreshold: 0.075 } }, droppedFramesRule: { active: true, parameters: { minimumSampleSize: 375, droppedFramesPercentageThreshold: 0.15 } }, abandonRequestsRule: { active: true, parameters: { abandonDurationMultiplier: 1.8, minSegmentDownloadTimeThresholdInMs: 500, minThroughputSamplesThreshold: 6 } }, l2ARule: { active: false }, loLPRule: { active: false } }, throughput: { averageCalculationMode: Constants.THROUGHPUT_CALCULATION_MODES.EWMA, lowLatencyDownloadTimeCalculationMode: Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING, useResourceTimingApi: true, useNetworkInformationApi: { xhr: false, fetch: true }, useDeadTimeLatency: true, bandwidthSafetyFactor: 0.9, sampleSettings: { live: 3, vod: 4, enableSampleSizeAdjustment: true, decreaseScale: 0.7, increaseScale: 1.3, maxMeasurementsToKeep: 20, averageLatencySampleAmount: 4, }, ewma: { throughputSlowHalfLifeSeconds: 8, throughputFastHalfLifeSeconds: 3, latencySlowHalfLifeCount: 2, latencyFastHalfLifeCount: 1 } }, maxBitrate: { audio: -1, video: -1 }, minBitrate: { audio: -1, video: -1 }, initialBitrate: { audio: -1, video: -1 }, autoSwitchBitrate: { audio: true, video: true } }, 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'] }, cmsd: { enabled: false, abr: { applyMb: false, etpWeightRatio: 0 } }, defaultSchemeIdUri: { viewpoint: '', audioChannelConfiguration: 'urn:mpeg:mpegB:cicp:ChannelConfiguration', role: 'urn:mpeg:dash:role:2011', accessibility: 'urn:mpeg:dash:role:2011' } }, 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 &lt;optional&gt; false If set to true the player will ignore \"encrypted\" and \"needkey\" events thrown by the EME. detectPlayreadyMessageFormat boolean &lt;optional&gt; true If set to true the player will use the raw unwrapped message from the Playready CDM Source: core/Settings.js, line 614 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 585 Scheduling Type: Object Properties: Name Type Argument Default Description defaultTimeout number &lt;optional&gt; 500 Default timeout between two consecutive segment scheduling attempts lowLatencyTimeout number &lt;optional&gt; 0 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 523 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; 100 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; false 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 Overwrite the manifest segments base information timescale attributes with the timescale set in initialization segments enableManifestTimescaleMismatchFix boolean &lt;optional&gt; false Defines the delay in milliseconds between two consecutive checks for events to be fired. parseInbandPrft boolean &lt;optional&gt; false Set to true if dash.js should parse inband prft boxes (ProducerReferenceTime) and trigger events. 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. lastMediaSettingsCachingInfo module:Settings~CachingInfoSettings &lt;optional&gt; {enabled: true, ttl: 360000} Set to false if you would like to disable the last media settings from being stored to localStorage during playback and used to set the initial track for subsequent playback within the expiration window. The default expiration is one hour, defined in milliseconds. saveLastMediaSettingsForCurrentStreamingSession boolean &lt;optional&gt; true Set to true if dash.js should save media settings from last selected track for incoming track selection during current streaming 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; \"highestSelectionPriority\" 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; 20000 Time in milliseconds before timing out on loading a media fragment. fragmentRequestProgressTimeout number &lt;optional&gt; -1 Time in milliseconds before timing out on loading progress of a media fragment. manifestRequestTimeout number &lt;optional&gt; 10000 Time in milliseconds before timing out on loading a manifest. 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. cmsd module:Settings~CmsdSettings Settings related to Common Media Server Data parsing. defaultSchemeIdUri module:Settings~defaultSchemeIdUri Default schemeIdUri for descriptor type elements These strings are used when not provided with setInitialMediaSettingsFor() Source: core/Settings.js, line 848 SwitchHistoryRule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule parameters object &lt;optional&gt; {sampleSize=8, switchPercentageThreshold=0.075} Configures the rule specific parameters. sampleSize: Number of switch requests (\"no switch\", because of the selected Representation is already playing or \"actual switches\") required before the rule is applied switchPercentageThreshold: Ratio of actual quality drops compared to no drops before a quality down-switch is triggered Source: core/Settings.js, line 709 Text Type: Object Properties: Name Type Argument Default Description defaultEnabled boolean &lt;optional&gt; true Enable/disable subtitle rendering by default. extendSegmentedCues boolean &lt;optional&gt; true Enable/disable patching of segmented cues in order to merge as a single cue by extending cue end time. webvtt object &lt;optional&gt; {customRenderingEnabled=false} Enables the custom rendering for WebVTT captions. For details refer to the \"Subtitles and Captions\" sample section of dash.js. Custom WebVTT rendering requires the external library vtt.js that can be found in the contrib folder. Source: core/Settings.js, line 533 ThroughputRule Type: Object Properties: Name Type Argument Default Description active boolean &lt;optional&gt; true Enable or disable the rule Source: core/Settings.js, line 686 ThroughputSettings Type: Object Properties: Name Type Argument Default Description averageCalculationMode string &lt;optional&gt; Constants.THROUGHPUT_CALCULATION_MODES.EWMA Defines the default mode for calculating the throughput based on the samples collected during playback. For arithmetic and harmonic mean calculations we use a sliding window with the values defined in \"sampleSettings\" For exponential weighted moving average calculation the default values can be changed in \"ewma\" lowLatencyDownloadTimeCalculationMode string &lt;optional&gt; Constants.LOW_LATENCY_DOWNLOAD_TIME_CALCULATION_MODE.MOOF_PARSING Defines the effective download time estimation method we use for low latency streams that utilize the Fetch API and chunked transfer coding useResourceTimingApi boolean &lt;optional&gt; true If set to true the ResourceTimingApi is used to derive the download time and the number of downloaded bytes. This option has no effect for low latency streaming as the download time equals the segment duration in most of the cases and therefor does not provide reliable values useNetworkInformationApi object &lt;optional&gt; { xhr=false, fetch=true} If set to true the NetworkInformationApi is used to derive the current throughput. Browser support is limited, only available in Chrome and Edge. Applies to standard (XHR requests) and/or low latency streaming (Fetch API requests). 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. 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) sampleSettings object &lt;optional&gt; {live=3,vod=4,enableSampleSizeAdjustment=true,decreaseScale=0.7,increaseScale=1.3,maxMeasurementsToKeep=20,averageLatencySampleAmount=4} When deriving the throughput based on the arithmetic or harmonic mean these settings define: live: Number of throughput samples to use (sample size) for live streams vod: Number of throughput samples to use (sample size) for VoD streams enableSampleSizeAdjustment: Adjust the sample sizes if throughput samples vary a lot decreaseScale: Increase sample size by one if the ratio of current and previous sample is below or equal this value increaseScale: Increase sample size by one if the ratio of current and previous sample is higher or equal this value maxMeasurementsToKeep: Number of samples to keep before sliding samples out of the window averageLatencySampleAmount: Number of latency samples to use (sample size) ewma object &lt;optional&gt; {throughputSlowHalfLifeSeconds=8,throughputFastHalfLifeSeconds=3,latencySlowHalfLifeCount=2,latencyFastHalfLifeCount=1} When deriving the throughput based on the exponential weighted moving average these settings define: throughputSlowHalfLifeSeconds: Number by which the weight of the current throughput measurement is divided, see ThroughputModel._updateEwmaValues throughputFastHalfLifeSeconds: Number by which the weight of the current throughput measurement is divided, see ThroughputModel._updateEwmaValues latencySlowHalfLifeCount: Number by which the weight of the current latency is divided, see ThroughputModel._updateEwmaValues latencyFastHalfLifeCount: Number by which the weight of the current latency is divided, see ThroughputModel._updateEwmaValues Source: core/Settings.js, line 755 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 311 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 484 × Search results Close "},"MssErrors.html":{"id":"MssErrors.html","title":"Class: MssErrors","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#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 36 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 59 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 69 KEY_MESSAGE Event ID for events delivered when the protection set receives a key message from the CDM Source: streaming/protection/ProtectionEvents.js, line 76 KEY_SESSION_CLOSED Event ID for events delivered when a key session close process has completed Source: streaming/protection/ProtectionEvents.js, line 83 KEY_SESSION_CREATED Event ID for events delivered when a new key sessions creation process has completed Source: streaming/protection/ProtectionEvents.js, line 90 KEY_SESSION_REMOVED Event ID for events delivered when a key session removal process has completed Source: streaming/protection/ProtectionEvents.js, line 97 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 104 KEY_SYSTEM_ACCESS_COMPLETE Event ID for events delivered when a key system access procedure has completed Source: streaming/protection/ProtectionEvents.js, line 111 KEY_SYSTEM_SELECTED Event ID for events delivered when a key system selection procedure completes Source: streaming/protection/ProtectionEvents.js, line 118 LICENSE_REQUEST_COMPLETE Event ID for events delivered when a license request procedure has completed Source: streaming/protection/ProtectionEvents.js, line 125 LICENSE_REQUEST_SENDING Sending a license rquest Source: streaming/protection/ProtectionEvents.js, line 132 PROTECTION_CREATED Event ID for events delivered when the Protection system is detected and created. Source: streaming/protection/ProtectionEvents.js, line 144 PROTECTION_DESTROYED Event ID for events delivered when the Protection system is destroyed. Source: streaming/protection/ProtectionEvents.js, line 150 × Search results Close "},"ThroughputController.html":{"id":"ThroughputController.html","title":"Class: ThroughputController","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: ThroughputController ThroughputController new ThroughputController() Source: streaming/controllers/ThroughputController.js, line 43 Methods &lt;inner&gt; getAverageLatency(mediaType, calculationMode, sampleSize) Returns the average latency based on the provided calculation mode Parameters: Name Type Default Description mediaType string calculationMode string | null null sampleSize number | NaN Source: streaming/controllers/ThroughputController.js, line 445 Returns: Type number &lt;inner&gt; getAverageThroughput(mediaType, calculationMode, sampleSize) Returns the average throughput based on the provided calculation mode. The returned value is depicted in kbit/s Parameters: Name Type Default Description mediaType string calculationMode string | null null sampleSize number | NaN Source: streaming/controllers/ThroughputController.js, line 415 Returns: Type number &lt;inner&gt; getRawThroughputData(mediaType) Returns the raw throughput measurements without calculating the average Parameters: Name Type Description mediaType Source: streaming/controllers/ThroughputController.js, line 456 Returns: Type * &lt;inner&gt; getSafeAverageThroughput(mediaType, calculationMode, sampleSize) Returns the average throughout applying the bandwidth safety factor provided in the settings. The returned value is depicted in kbit/s Parameters: Name Type Default Description mediaType string calculationMode string | null null sampleSize number | NaN Source: streaming/controllers/ThroughputController.js, line 428 Returns: Type number &lt;inner&gt; getZlema(dict, sampleSize) Calculates the Zero-Lag Exponential Moving Average Parameters: Name Type Description dict array sampleSize number Source: streaming/controllers/ThroughputController.js, line 387 Returns: Type number × Search results Close "},"ThroughputModel.html":{"id":"ThroughputModel.html","title":"Class: ThroughputModel","body":" dash.js Modules DashAdapterDashMetricsMediaPlayerOfflineControllerProtectionControllerSettings Classes ErrorsMediaPlayerEventsMediaPlayerModelMetricsReportingEventsMssErrorsOfflineErrorsOfflineEventsProtectionErrorsProtectionEventsThroughputControllerThroughputModel Events MediaPlayerEvents#event:ADAPTATION_SET_REMOVED_NO_CAPABILITIESMediaPlayerEvents#event:AST_IN_FUTUREMediaPlayerEvents#event:BASE_URLS_UPDATEDMediaPlayerEvents#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:INBAND_PRFTMediaPlayerEvents#event:LOGMediaPlayerEvents#event:MANIFEST_LOADEDMediaPlayerEvents#event:MANIFEST_LOADING_FINISHEDMediaPlayerEvents#event:MANIFEST_LOADING_STARTEDMediaPlayerEvents#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:THROUGHPUT_MEASUREMENT_STOREDMediaPlayerEvents#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_ACCESS_COMPLETEProtectionEvents#event:KEY_SYSTEM_SELECTEDProtectionEvents#event:LICENSE_REQUEST_COMPLETEProtectionEvents#event:LICENSE_REQUEST_SENDINGProtectionEvents#event:PROTECTION_CREATEDProtectionEvents#event:PROTECTION_DESTROYED Global LICENSE_SERVER_MANIFEST_CONFIGURATIONS Class: ThroughputModel ThroughputModel new ThroughputModel(config) Throughput generally stored in kbit/s Latency generally stored in ms Parameters: Name Type Description config object Source: streaming/models/ThroughputModel.js, line 45 Methods &lt;inner&gt; addEntry(mediaType, httpRequest) Use the provided request to add new entries for throughput and latency. Update the EWMA state as well. Parameters: Name Type Description mediaType MediaType httpRequest object Source: streaming/models/ThroughputModel.js, line 80 &lt;inner&gt; reset() Reset all values Source: streaming/models/ThroughputModel.js, line 355 × 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>