@l5i/dashjs
Version:
A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.
51 lines (50 loc) • 11.7 kB
JavaScript
/**
* 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.
*/'use strict';Object.defineProperty(exports,'__esModule',{value:true});function _interopRequireDefault(obj){return obj && obj.__esModule?obj:{'default':obj};}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else {obj[key] = value;}return obj;}var _XHRLoader=require('./XHRLoader');var _XHRLoader2=_interopRequireDefault(_XHRLoader);var _FetchLoader=require('./FetchLoader');var _FetchLoader2=_interopRequireDefault(_FetchLoader);var _voMetricsHTTPRequest=require('../vo/metrics/HTTPRequest');var _coreFactoryMaker=require('../../core/FactoryMaker');var _coreFactoryMaker2=_interopRequireDefault(_coreFactoryMaker);var _coreErrorsErrors=require('../../core/errors/Errors');var _coreErrorsErrors2=_interopRequireDefault(_coreErrorsErrors);var _voDashJSError=require('../vo/DashJSError');var _voDashJSError2=_interopRequireDefault(_voDashJSError); /**
* @module HTTPLoader
* @description Manages download of resources via HTTP.
* @param {Object} cfg - dependancies from parent
*/function HTTPLoader(cfg){cfg = cfg || {};var context=this.context;var errHandler=cfg.errHandler;var metricsModel=cfg.metricsModel;var mediaPlayerModel=cfg.mediaPlayerModel;var requestModifier=cfg.requestModifier;var useFetch=cfg.useFetch || false;var instance=undefined;var requests=undefined;var delayedRequests=undefined;var retryTimers=undefined;var downloadErrorToRequestTypeMap=undefined;var newDownloadErrorToRequestTypeMap=undefined;function setup(){var _downloadErrorToRequestTypeMap,_newDownloadErrorToRequestTypeMap;requests = [];delayedRequests = [];retryTimers = [];downloadErrorToRequestTypeMap = (_downloadErrorToRequestTypeMap = {},_defineProperty(_downloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.MPD_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_MANIFEST),_defineProperty(_downloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.XLINK_EXPANSION_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_XLINK),_defineProperty(_downloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_INITIALIZATION),_defineProperty(_downloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT),_defineProperty(_downloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.INDEX_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT),_defineProperty(_downloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT),_defineProperty(_downloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.OTHER_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT),_downloadErrorToRequestTypeMap);newDownloadErrorToRequestTypeMap = (_newDownloadErrorToRequestTypeMap = {},_defineProperty(_newDownloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.MPD_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_MANIFEST_CODE),_defineProperty(_newDownloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.XLINK_EXPANSION_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_XLINK_CODE),_defineProperty(_newDownloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_INITIALIZATION_CODE),_defineProperty(_newDownloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT_CODE),_defineProperty(_newDownloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.INDEX_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT_CODE),_defineProperty(_newDownloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT_CODE),_defineProperty(_newDownloadErrorToRequestTypeMap,_voMetricsHTTPRequest.HTTPRequest.OTHER_TYPE,_coreErrorsErrors2['default'].DOWNLOAD_ERROR_ID_CONTENT_CODE),_newDownloadErrorToRequestTypeMap);}function internalLoad(config,remainingAttempts){var request=config.request;var traces=[];var firstProgress=true;var needFailureReport=true;var requestStartTime=new Date();var lastTraceTime=requestStartTime;var lastTraceReceivedCount=0;var httpRequest=undefined;if(!requestModifier || !metricsModel || !errHandler){throw new Error('config object is not correct or missing');}var handleLoaded=function handleLoaded(success){needFailureReport = false;request.requestStartDate = requestStartTime;request.requestEndDate = new Date();request.firstByteDate = request.firstByteDate || requestStartTime;if(!request.checkExistenceOnly){metricsModel.addHttpRequest(request.mediaType,null,request.type,request.url,httpRequest.response?httpRequest.response.responseURL:null,request.serviceLocation || null,request.range || null,request.requestStartDate,request.firstByteDate,request.requestEndDate,httpRequest.response?httpRequest.response.status:null,request.duration,httpRequest.response && httpRequest.response.getAllResponseHeaders?httpRequest.response.getAllResponseHeaders():httpRequest.response?httpRequest.response.responseHeaders:[],success?traces:null);}};var onloadend=function onloadend(){if(requests.indexOf(httpRequest) === -1){return;}else {requests.splice(requests.indexOf(httpRequest),1);}if(needFailureReport){handleLoaded(false);if(remainingAttempts > 0){remainingAttempts--;retryTimers.push(setTimeout(function(){internalLoad(config,remainingAttempts);},mediaPlayerModel.getRetryIntervalForType(request.type)));}else {errHandler.downloadError(downloadErrorToRequestTypeMap[request.type],request.url,request);errHandler.error(new _voDashJSError2['default'](newDownloadErrorToRequestTypeMap[request.type],request.url + ' is not available',{request:request,response:httpRequest.response}));if(config.error){config.error(request,'error',httpRequest.response.statusText);}if(config.complete){config.complete(request,httpRequest.response.statusText);}}}};var progress=function progress(event){var currentTime=new Date();if(firstProgress){firstProgress = false;if(!event.lengthComputable || event.lengthComputable && event.total !== event.loaded){request.firstByteDate = currentTime;}}if(event.lengthComputable){request.bytesLoaded = event.loaded;request.bytesTotal = event.total;}if(!event.noTrace){traces.push({s:lastTraceTime,d:event.time?event.time:currentTime.getTime() - lastTraceTime.getTime(),b:[event.loaded?event.loaded - lastTraceReceivedCount:0]});lastTraceTime = currentTime;lastTraceReceivedCount = event.loaded;}if(config.progress && event){config.progress(event);}};var onload=function onload(){if(httpRequest.response.status >= 200 && httpRequest.response.status <= 299){handleLoaded(true);if(config.success){config.success(httpRequest.response.response,httpRequest.response.statusText,httpRequest.response.responseURL);}if(config.complete){config.complete(request,httpRequest.response.statusText);}}};var onabort=function onabort(){if(config.abort){config.abort(request);}};var loader=undefined;if(useFetch && window.fetch && request.responseType === 'arraybuffer'){loader = (0,_FetchLoader2['default'])(context).create({requestModifier:requestModifier});}else {loader = (0,_XHRLoader2['default'])(context).create({requestModifier:requestModifier});}var modifiedUrl=requestModifier.modifyRequestURL(request.url);var verb=request.checkExistenceOnly?_voMetricsHTTPRequest.HTTPRequest.HEAD:_voMetricsHTTPRequest.HTTPRequest.GET;var withCredentials=mediaPlayerModel.getXHRWithCredentialsForType(request.type);httpRequest = {url:modifiedUrl,method:verb,withCredentials:withCredentials,request:request,onload:onload,onend:onloadend,onerror:onloadend,progress:progress,onabort:onabort,loader:loader}; // Adds the ability to delay single fragment loading time to control buffer.
var now=new Date().getTime();if(isNaN(request.delayLoadingTime) || now >= request.delayLoadingTime){ // no delay - just send
requests.push(httpRequest);loader.load(httpRequest);}else {(function(){ // delay
var delayedRequest={httpRequest:httpRequest};delayedRequests.push(delayedRequest);delayedRequest.delayTimeout = setTimeout(function(){if(delayedRequests.indexOf(delayedRequest) === -1){return;}else {delayedRequests.splice(delayedRequests.indexOf(delayedRequest),1);}try{requestStartTime = new Date();lastTraceTime = requestStartTime;requests.push(delayedRequest.httpRequest);loader.load(delayedRequest.httpRequest);}catch(e) {delayedRequest.httpRequest.onerror();}},request.delayLoadingTime - now);})();}} /**
* Initiates a download of the resource described by config.request
* @param {Object} config - contains request (FragmentRequest or derived type), and callbacks
* @memberof module:HTTPLoader
* @instance
*/function load(config){if(config.request){internalLoad(config,mediaPlayerModel.getRetryAttemptsForType(config.request.type));}} /**
* Aborts any inflight downloads
* @memberof module:HTTPLoader
* @instance
*/function abort(){retryTimers.forEach(function(t){return clearTimeout(t);});retryTimers = [];delayedRequests.forEach(function(x){return clearTimeout(x.delayTimeout);});delayedRequests = [];requests.forEach(function(x){ // abort will trigger onloadend which we don't want
// when deliberately aborting inflight requests -
// set them to undefined so they are not called
x.onloadend = x.onerror = x.onprogress = undefined;x.loader.abort(x);x.onabort();});requests = [];}instance = {load:load,abort:abort};setup();return instance;}HTTPLoader.__dashjs_factory_name = 'HTTPLoader';var factory=_coreFactoryMaker2['default'].getClassFactory(HTTPLoader);exports['default'] = factory;module.exports = exports['default'];
//# sourceMappingURL=HTTPLoader.js.map