streaming_MediaPlayer.js

/**
 * 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 Debug from './../core/Debug.js';
import Errors from './../core/errors/Errors.js';
import FactoryMaker from '../core/FactoryMaker.js';
import MediaPlayerEvents from './MediaPlayerEvents.js';
import Settings from '../core/Settings.js';
import CoreApi from './mediaplayer/CoreApi.js';
import CustomParametersApi from './mediaplayer/CustomParametersApi.js';
import LifecycleApi from './mediaplayer/LifecycleApi.js';
import ManifestApi from './mediaplayer/ManifestApi.js';
import MediaPlayerWiring from './mediaplayer/MediaPlayerWiring.js';
import PlaybackApi from './mediaplayer/PlaybackApi.js';
import TextApi from './mediaplayer/TextApi.js';
import TrackApi from './mediaplayer/TrackApi.js';

/**
 * The media types
 * @typedef {('video' | 'audio' | 'text' | 'image')} MediaType
 */

/**
 * @module MediaPlayer
 * @description The MediaPlayer is the primary dash.js Module and a Facade to build your player around.
 * It will allow you access to all the important dash.js properties/methods via the public API and all the
 * events to build a robust DASH media player.
 */
function MediaPlayer() {
    // Public API groups split out of this file. Each is a FactoryMaker class factory (so player.extend() works on them)
    // and gets the shared `state` object plus a back-reference to the composed player instance.
    const API_FACTORIES = [CoreApi, LifecycleApi, PlaybackApi, TrackApi, TextApi, ManifestApi, CustomParametersApi];

    const context = this.context;
    let instance;

    // Shared with the API sub-modules (see _composeApis). Single source of truth for player state.
    const state = {
        abrController: null,
        adapter: null,
        autoPlay: true,
        baseURLController: null,
        contentSteeringController: null,
        customParametersModel: null,
        dashMetrics: null,
        logger: null,
        manifestModel: null,
        mediaController: null,
        mediaPlayerInitialized: false,
        offlineController: null,
        playbackController: null,
        playbackInitialized: false,
        protectionController: null,
        protectionData: null,
        providedStartTime: NaN,
        retrieveManifestRequest: null,
        settings: Settings(context).getInstance(),
        source: null,
        streamController: null,
        streamingInitialized: false,
        textController: null,
        throughputController: null,
        uriFragmentModel: null,
        videoModel: null,
    };
    const debug = Debug(context).getInstance({ settings: state.settings });
    const wiring = MediaPlayerWiring(context).getInstance();
    wiring.setConfig({ state, debug });

    function setup() {
        state.logger = debug.getLogger(instance);
        wiring.setup();
    }

    /**
     * Configure media player with customs controllers. Helpful for tests
     *
     * @param {object=} config controllers configuration
     * @memberof module:MediaPlayer
     * @instance
     */
    function setConfig(config) {
        wiring.setConfig(config);
    }

    /**
     * This method should be used to extend or replace internal dash.js objects.
     * There are two ways to extend dash.js (determined by the override argument):
     * <ol>
     * <li>If you set override to true any public method or property in your custom object will
     * override the dash.js parent object's property(ies) and will be used instead but the
     * dash.js parent module will still be created.</li>
     *
     * <li>If you set override to false your object will completely replace the dash.js object.
     * (Note: This is how it was in 1.x of Dash.js with Dijon).</li>
     * </ol>
     * <b>When you extend you get access to this.context, this.factory and this.parent to operate with in your custom object.</b>
     * <ul>
     * <li><b>this.context</b> - can be used to pass context for singleton access.</li>
     * <li><b>this.factory</b> - can be used to call factory.getSingletonInstance().</li>
     * <li><b>this.parent</b> - is the reference of the parent object to call other public methods. (this.parent is excluded if you extend with override set to false or option 2)</li>
     * </ul>
     * <b>You must call extend before you call initialize</b>
     * @see {@link module:MediaPlayer#initialize initialize()}
     * @param {string} parentNameString - name of parent module
     * @param {Object} childInstance - overriding object
     * @param {boolean} override - replace only some methods (true) or the whole object (false)
     * @memberof module:MediaPlayer
     * @instance
     */
    function extend(parentNameString, childInstance, override) {
        FactoryMaker.extend(parentNameString, childInstance, override, context);
        _composeApis();
    }

    /**
     *
     * @private
     */
    function _composeApis() {
        API_FACTORIES.forEach((Factory) => {
            const api = Factory(context).create();
            if (typeof api.setConfig === 'function') { // a full replacement via extend(name, obj, false) may omit it
                api.setConfig({ state, mediaPlayer: instance, wiring, debug });
            }
            const { setConfig, getClassName, ...methods } = api; // strip factory plumbing
            Object.assign(instance, methods);
        });
    }

    instance = {
        extend,
        setConfig,
    };

    _composeApis();
    setup();

    return instance;
}

MediaPlayer.__dashjs_factory_name = 'MediaPlayer';
const factory = FactoryMaker.getClassFactory(MediaPlayer);
factory.events = MediaPlayerEvents;
factory.errors = Errors;
FactoryMaker.updateClassFactory(MediaPlayer.__dashjs_factory_name, factory);

export default factory;