UNPKG

@l5i/dashjs

Version:

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

44 lines (43 loc) 7.94 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. */'use strict';Object.defineProperty(exports,'__esModule',{value:true});function _interopRequireDefault(obj){return obj && obj.__esModule?obj:{'default':obj};}var _MssEvents=require('./MssEvents');var _MssEvents2=_interopRequireDefault(_MssEvents);var _MssFragmentMoofProcessor=require('./MssFragmentMoofProcessor');var _MssFragmentMoofProcessor2=_interopRequireDefault(_MssFragmentMoofProcessor);var _streamingVoFragmentRequest=require('../streaming/vo/FragmentRequest');var _streamingVoFragmentRequest2=_interopRequireDefault(_streamingVoFragmentRequest);function MssFragmentInfoController(config){config = config || {};var context=this.context;var instance=undefined;var logger=undefined;var fragmentModel=undefined;var started=undefined;var type=undefined;var bufferTimeout=undefined;var startTime=undefined;var startFragmentTime=undefined;var index=undefined;var streamProcessor=config.streamProcessor;var eventBus=config.eventBus;var metricsModel=config.metricsModel;var playbackController=config.playbackController;var ISOBoxer=config.ISOBoxer;var baseURLController=config.baseURLController;var debug=config.debug;var controllerType='MssFragmentInfoController';function setup(){logger = debug.getLogger(instance);}function initialize(){started = false;startTime = null;startFragmentTime = null; // Register to StreamProcessor as external controller streamProcessor.registerExternalController(instance);type = streamProcessor.getType();fragmentModel = streamProcessor.getFragmentModel();}function doStart(){if(started === true){return;}logger.debug('Do start');eventBus.on(_MssEvents2['default'].FRAGMENT_INFO_LOADING_COMPLETED,onFragmentInfoLoadedCompleted,instance);started = true;startTime = new Date().getTime();index = 0;loadNextFragmentInfo();}function doStop(){if(!started){return;}logger.debug('Do stop');eventBus.off(_MssEvents2['default'].FRAGMENT_INFO_LOADING_COMPLETED,onFragmentInfoLoadedCompleted,instance); // Stop buffering process clearTimeout(bufferTimeout);started = false;startTime = null;startFragmentTime = null;}function reset(){doStop();streamProcessor.unregisterExternalController(instance);}function loadNextFragmentInfo(){ // Check if running state if(!started){return;} // Get last segment from SegmentTimeline var representation=getCurrentRepresentation();var manifest=representation.adaptation.period.mpd.manifest;var adaptation=manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index];var segments=adaptation.SegmentTemplate.SegmentTimeline.S_asArray;var segment=segments[segments.length - 1];logger.debug('Last fragment time: ' + segment.t / adaptation.SegmentTemplate.timescale); // Generate segment request var request=getRequestForSegment(adaptation,representation,segment); // Send segment request requestFragment.call(this,request);}function delayLoadNextFragmentInfo(delay){clearTimeout(bufferTimeout);bufferTimeout = setTimeout(function(){bufferTimeout = null;loadNextFragmentInfo();},delay * 1000);}function getRequestForSegment(adaptation,representation,segment){var timescale=adaptation.SegmentTemplate.timescale;var request=new _streamingVoFragmentRequest2['default']();request.mediaType = type;request.type = 'FragmentInfoSegment'; // request.range = segment.mediaRange; request.startTime = segment.t / timescale;request.duration = segment.d / timescale;request.timescale = timescale; // request.availabilityStartTime = segment.availabilityStartTime; // request.availabilityEndTime = segment.availabilityEndTime; // request.wallStartTime = segment.wallStartTime; request.quality = representation.index;request.index = index++;request.mediaInfo = streamProcessor.getMediaInfo();request.adaptationIndex = representation.adaptation.index;request.representationId = representation.id;request.url = baseURLController.resolve(representation.path).url + adaptation.SegmentTemplate.media;request.url = request.url.replace('$Bandwidth$',representation.bandwidth);request.url = request.url.replace('$Time$',segment.tManifest?segment.tManifest:segment.t);request.url = request.url.replace('/Fragments(','/FragmentInfo(');return request;}function getCurrentRepresentation(){var representationController=streamProcessor.getRepresentationController();var representation=representationController.getCurrentRepresentation();return representation;}function requestFragment(request){logger.debug('Load fragment for time: ' + request.startTime);if(streamProcessor.getFragmentModel().isFragmentLoadedOrPending(request)){ // We may have reached end of timeline in case of start-over streams logger.debug('No more fragments');return;}fragmentModel.executeRequest(request);}function onFragmentInfoLoadedCompleted(e){if(e.streamProcessor !== streamProcessor){return;}var request=e.fragmentInfo.request;if(!e.fragmentInfo.response){logger.error('Load error',request.url);return;}var deltaFragmentTime=undefined,deltaTime=undefined;logger.debug('FragmentInfo loaded: ',request.url);if(!startFragmentTime){startFragmentTime = request.startTime;}try{ // Process FramgentInfo in order to update segment timeline (DVR window) var mssFragmentMoofProcessor=(0,_MssFragmentMoofProcessor2['default'])(context).create({metricsModel:metricsModel,playbackController:playbackController,ISOBoxer:ISOBoxer,eventBus:eventBus,debug:debug});mssFragmentMoofProcessor.updateSegmentList(e.fragmentInfo,streamProcessor);deltaTime = (new Date().getTime() - startTime) / 1000;deltaFragmentTime = request.startTime + request.duration - startFragmentTime;delayLoadNextFragmentInfo(Math.max(0,deltaFragmentTime - deltaTime));}catch(e) {logger.fatal('Internal error while processing fragment info segment ');}}function getType(){return type;}instance = {initialize:initialize,controllerType:controllerType,start:doStart,getType:getType,reset:reset};setup();return instance;}MssFragmentInfoController.__dashjs_factory_name = 'MssFragmentInfoController';exports['default'] = dashjs.FactoryMaker.getClassFactory(MssFragmentInfoController); /* jshint ignore:line */module.exports = exports['default']; //# sourceMappingURL=MssFragmentInfoController.js.map