/**
* 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';
import Settings from '../../core/Settings';
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 = 0.5;
/**
* 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,
playbackController,
serviceDescriptionController;
const context = this.context;
const settings = Settings(context).getInstance();
function setup() {
}
function setConfig(config) {
if (config.playbackController) {
playbackController = config.playbackController;
}
if (config.serviceDescriptionController) {
serviceDescriptionController = config.serviceDescriptionController;
}
}
/**
* 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) && settings.get().streaming.liveCatchup.maxDrift > 0) {
return settings.get().streaming.liveCatchup.maxDrift;
}
const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings();
if (serviceDescriptionSettings && serviceDescriptionSettings.liveCatchup && !isNaN(serviceDescriptionSettings.liveCatchup.maxDrift) && serviceDescriptionSettings.liveCatchup.maxDrift > 0) {
return serviceDescriptionSettings.liveCatchup.maxDrift;
}
return DEFAULT_CATCHUP_MAX_DRIFT;
}
/**
* Returns the maximum playback rate to be used when applying the catchup mechanism
* @return {number}
*/
function getCatchupPlaybackRate() {
if (!isNaN(settings.get().streaming.liveCatchup.playbackRate) && settings.get().streaming.liveCatchup.playbackRate > 0) {
return settings.get().streaming.liveCatchup.playbackRate;
}
const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings();
if (serviceDescriptionSettings && serviceDescriptionSettings.liveCatchup && !isNaN(serviceDescriptionSettings.liveCatchup.playbackRate) && serviceDescriptionSettings.liveCatchup.playbackRate > 0) {
return serviceDescriptionSettings.liveCatchup.playbackRate;
}
return DEFAULT_CATCHUP_PLAYBACK_RATE;
}
/**
* 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) && setting !== -1) {
return setting;
}
const serviceDescriptionSettings = serviceDescriptionController.getServiceDescriptionSettings();
if(serviceDescriptionSettings && serviceDescriptionSettings[field] && !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 < 0) {
return 0;
}
return Math.min(getStableBufferTime(), initialBufferLevel);
}
/**
* Returns the stable buffer time taking the live delay into account
* @return {number}
*/
function getStableBufferTime() {
let stableBufferTime = settings.get().streaming.buffer.stableBufferTime > 0 ? settings.get().streaming.buffer.stableBufferTime : settings.get().streaming.buffer.fastSwitchEnabled ? DEFAULT_MIN_BUFFER_TIME_FAST_SWITCH : DEFAULT_MIN_BUFFER_TIME;
const liveDelay = playbackController.getLiveDelay();
return !isNaN(liveDelay) && liveDelay > 0 ? Math.min(stableBufferTime, liveDelay) : stableBufferTime;
}
/**
* 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,
getStableBufferTime,
getInitialBufferLevel,
getRetryAttemptsForType,
getRetryIntervalsForType,
getCatchupPlaybackRate,
getAbrBitrateParameter,
setConfig,
reset
};
setup();
return instance;
}
MediaPlayerModel.__dashjs_factory_name = 'MediaPlayerModel';
export default FactoryMaker.getSingletonFactory(MediaPlayerModel);