UNPKG

@l5i/dashjs

Version:

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

185 lines (157 loc) 7.28 kB
/** * 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 MetricSerialiser from '../../utils/MetricSerialiser'; import RNG from '../../utils/RNG'; function DVBReporting(config) { config = config || {}; let instance; let context = this.context; let metricSerialiser = MetricSerialiser(context).getInstance(); let randomNumberGenerator = RNG(context).getInstance(); let USE_DRAFT_DVB_SPEC = true; let isReportingPlayer = false; let reportingPlayerStatusDecided = false; let reportingUrl = null; let rangeController = null; let allowPendingRequestsToCompleteOnReset = true; let pendingRequests = []; const metricsConstants = config.metricsConstants; function doGetRequest(url, successCB, failureCB) { let req = new XMLHttpRequest(); const oncomplete = function () { let reqIndex = pendingRequests.indexOf(req); if (reqIndex === -1) { return; } else { pendingRequests.splice(reqIndex, 1); } if ((req.status >= 200) && (req.status < 300)) { if (successCB) { successCB(); } } else { if (failureCB) { failureCB(); } } }; pendingRequests.push(req); try { req.open('GET', url); req.onloadend = oncomplete; req.onerror = oncomplete; req.send(); } catch (e) { req.onerror(); } } function report(type, vos) { if (!Array.isArray(vos)) { vos = [vos]; } // If the Player is not a reporting Player, then the Player shall // not report any errors. // ... In addition to any time restrictions specified by a Range // element within the Metrics element. if (isReportingPlayer && rangeController.isEnabled()) { // This reporting mechanism operates by creating one HTTP GET // request for every entry in the top level list of the metric. vos.forEach(function (vo) { let url = metricSerialiser.serialise(vo); // this has been proposed for errata if (USE_DRAFT_DVB_SPEC && (type !== metricsConstants.DVB_ERRORS)) { url = `metricname=${type}&${url}`; } // Take the value of the @reportingUrl attribute, append a // question mark ('?') character and then append the string // created in the previous step. url = `${reportingUrl}?${url}`; // Make an HTTP GET request to the URL contained within the // string created in the previous step. doGetRequest(url, null, function () { // If the Player is unable to make the report, for // example because the @reportingUrl is invalid, the // host cannot be reached, or an HTTP status code other // than one in the 200 series is received, the Player // shall cease being a reporting Player for the // duration of the MPD. isReportingPlayer = false; }); }); } } function initialize(entry, rc) { let probability; rangeController = rc; reportingUrl = entry['dvb:reportingUrl']; // If a required attribute is missing, the Reporting descriptor may // be ignored by the Player if (!reportingUrl) { throw new Error( 'required parameter missing (dvb:reportingUrl)' ); } // A Player's status, as a reporting Player or not, shall remain // static for the duration of the MPD, regardless of MPD updates. // (i.e. only calling reset (or failure) changes this state) if (!reportingPlayerStatusDecided) { // NOTE: DVB spec has a typo where it incorrectly references the // priority attribute, which should be probability probability = entry['dvb:probability'] || entry['dvb:priority'] || 0; // If the @priority attribute is set to 1000, it shall be a reporting Player. // If the @priority attribute is missing, the Player shall not be a reporting Player. // For any other value of the @probability attribute, it shall decide at random whether to be a // reporting Player, such that the probability of being one is @probability/1000. if (probability && (probability === 1000 || ((probability / 1000) >= randomNumberGenerator.random()))) { isReportingPlayer = true; } reportingPlayerStatusDecided = true; } } function reset() { if (!allowPendingRequestsToCompleteOnReset) { pendingRequests.forEach(req => req.abort()); pendingRequests = []; } reportingPlayerStatusDecided = false; isReportingPlayer = false; reportingUrl = null; rangeController = null; } instance = { report: report, initialize: initialize, reset: reset }; return instance; } DVBReporting.__dashjs_factory_name = 'DVBReporting'; export default dashjs.FactoryMaker.getClassFactory(DVBReporting); /* jshint ignore:line */