UNPKG

@l5i/dashjs

Version:

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

133 lines (118 loc) 6.15 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 Constants from '../../constants/Constants'; import Debug from '../../../core/Debug'; import FactoryMaker from '../../../core/FactoryMaker'; import FragmentRequest from '../../../streaming/vo/FragmentRequest'; function NextFragmentRequestRule(config) { config = config || {}; const context = this.context; const adapter = config.adapter; const textController = config.textController; let instance, logger; function setup() { logger = Debug(context).getInstance().getLogger(instance); } function execute(streamProcessor, requestToReplace) { if (!streamProcessor) { return null; } const representationInfo = streamProcessor.getRepresentationInfo(); const mediaInfo = representationInfo.mediaInfo; const mediaType = mediaInfo.type; const scheduleController = streamProcessor.getScheduleController(); const seekTarget = scheduleController.getSeekTarget(); const hasSeekTarget = !isNaN(seekTarget); const bufferController = streamProcessor.getBufferController(); const currentTime = streamProcessor.getPlaybackController().getTime(); let time = hasSeekTarget ? seekTarget : adapter.getIndexHandlerTime(streamProcessor); let bufferIsDivided = false; let request; if (hasSeekTarget) { scheduleController.setSeekTarget(NaN); } if (isNaN(time) || (mediaType === Constants.FRAGMENTED_TEXT && !textController.isTextEnabled())) { return null; } /** * This is critical for IE/Safari/EDGE * */ if (bufferController) { let range = bufferController.getRangeAt(time); const playingRange = bufferController.getRangeAt(currentTime); const bufferRanges = bufferController.getBuffer().getAllBufferRanges(); const numberOfBuffers = bufferRanges ? bufferRanges.length : 0; if ((range !== null || playingRange !== null) && !hasSeekTarget) { if ( !range || (playingRange && playingRange.start != range.start && playingRange.end != range.end) ) { if (numberOfBuffers > 1 && mediaType !== Constants.FRAGMENTED_TEXT) { streamProcessor.getFragmentModel().removeExecutedRequestsAfterTime(playingRange.end); bufferIsDivided = true; } range = playingRange; } logger.debug('Prior to making a request for time, NextFragmentRequestRule is aligning index handler\'s currentTime with bufferedRange.end for', mediaType, '.', time, 'was changed to', range.end); time = range.end; } } if (requestToReplace) { time = requestToReplace.startTime + (requestToReplace.duration / 2); request = adapter.getFragmentRequest(streamProcessor, representationInfo, time, { timeThreshold: 0, ignoreIsFinished: true }); } else { request = adapter.getFragmentRequest(streamProcessor, representationInfo, time, { keepIdx: !hasSeekTarget && !bufferIsDivided }); // Then, check if this request was downloaded or not while (request && request.action !== FragmentRequest.ACTION_COMPLETE && streamProcessor.getFragmentModel().isFragmentLoaded(request)) { // loop until we found not loaded fragment, or no fragment request = adapter.getFragmentRequest(streamProcessor, representationInfo); } if (request) { if (!isNaN(request.startTime + request.duration)) { adapter.setIndexHandlerTime(streamProcessor, request.startTime + request.duration); } request.delayLoadingTime = new Date().getTime() + scheduleController.getTimeToLoadDelay(); scheduleController.setTimeToLoadDelay(0); } } return request; } instance = { execute: execute }; setup(); return instance; } NextFragmentRequestRule.__dashjs_factory_name = 'NextFragmentRequestRule'; export default FactoryMaker.getClassFactory(NextFragmentRequestRule);