Skip to content

Migration to dash.js 4.0

dsilhavy edited this page Jun 25, 2021 · 5 revisions

dash.js migration guide - 3.x to 4.0

With the release of 4.0 we also made changes to some of the core functionality in dash.js. In case you encounter any issue with the new version please create an issue or start a new discussion on Github. Moreover, if you are missing something in this migration guide let us know.

npm release

Due to a configuration error we had to republish version 4.0.0 to npm.js. Since the 4.0.0 tag could not be reused for this purpose we had to rename the release on npm.js to 4.0.0-npm

When installing dash.js 4.0.0 via npm please make sure to use

npm install dashjs@4.0.0-npm

This will be fixed with the next release.

dash.js samples

In order to make it easy for developers to understand the core functionality of dash.js we reworked the sample section of the player. Various samples on features like player setup, live playback, buffer management, ABR configuration, subtitle management can be found here. The sample section is a very good place to start looking for a specific feature in dash.js.

A good place to test 4.0 is also the reference client. It can be used as a template for the integration of dash.js in your own application.

dash.js settings

In order to structure the various settings in dash.js and make it easier for developers to understand the meaning and the scope of a specific setting we restructured the settings object. The complete settings object is depicted below.

As an example, the live delay settings are now grouped in a separate object called delay.

Before migrating from dash.js version 3.x to version 4.0 please make sure that your current player settings reflect the new structure of the settings object.

const defaultSettings = {
        debug: {
            logLevel: Debug.LOG_LEVEL_WARNING,
            dispatchEvent: false
        },
        streaming: {
            abandonLoadTimeout: 10000,
            wallclockTimeUpdateInterval: 100,
            lowLatencyEnabled: false,
            manifestUpdateRetryInterval: 100,
            cacheInitSegments: false,
            eventControllerRefreshDelay: 150,
            capabilities: {
                filterUnsupportedEssentialProperties: true,
                useMediaCapabilitiesApi: false
            },
            timeShiftBuffer: {
                calcFromSegmentTimeline: false,
                fallbackToSegmentTimeline: true
            },
            metrics: {
                maxListDepth: 100
            },
            delay: {
                liveDelayFragmentCount: NaN,
                liveDelay: NaN,
                useSuggestedPresentationDelay: true,
                applyServiceDescription: true
            },
            protection: {
                keepProtectionMediaKeys: false
            },
            buffer: {
                fastSwitchEnabled: true,
                flushBufferAtTrackSwitch: false,
                reuseExistingSourceBuffers: true,
                bufferPruningInterval: 10,
                bufferToKeep: 20,
                bufferTimeAtTopQuality: 30,
                bufferTimeAtTopQualityLongForm: 60,
                initialBufferLevel: NaN,
                stableBufferTime: 12,
                longFormContentDurationThreshold: 600,
                stallThreshold: 0.3,
                useAppendWindow: true,
                setStallState: true
            },
            gaps: {
                jumpGaps: true,
                jumpLargeGaps: true,
                smallGapLimit: 1.5,
                threshold: 0.3
            },
            utcSynchronization: {
                useManifestDateHeaderTimeSource: true,
                backgroundAttempts: 2,
                timeBetweenSyncAttempts: 30,
                maximumTimeBetweenSyncAttempts: 600,
                minimumTimeBetweenSyncAttempts: 2,
                timeBetweenSyncAttemptsAdjustmentFactor: 2,
                maximumAllowedDrift: 100,
                enableBackgroundSyncAfterSegmentDownloadError: true,
                defaultTimingSource: {
                    scheme: 'urn:mpeg:dash:utc:http-xsdate:2014',
                    value: 'https://time.akamai.com/?iso&ms'
                }
            },
            scheduling: {
                defaultTimeout: 500,
                lowLatencyTimeout: 0,
                scheduleWhilePaused: true
            },
            text: {
                defaultEnabled: true
            },
            liveCatchup: {
                minDrift: 0.02,
                maxDrift: 0,
                playbackRate: 0.5,
                latencyThreshold: 60,
                playbackBufferMin: 0.5,
                enabled: false,
                mode: Constants.LIVE_CATCHUP_MODE_DEFAULT
            },
            lastBitrateCachingInfo: {
                enabled: true,
                ttl: 360000
            },
            lastMediaSettingsCachingInfo: {
                enabled: true,
                ttl: 360000
            },
            cacheLoadThresholds: {
                video: 50,
                audio: 5
            },
            trackSwitchMode: {
                audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE,
                video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE
            },
            selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE,
            fragmentRequestTimeout: 0,
            retryIntervals: {
                [HTTPRequest.MPD_TYPE]: 500,
                [HTTPRequest.XLINK_EXPANSION_TYPE]: 500,
                [HTTPRequest.MEDIA_SEGMENT_TYPE]: 1000,
                [HTTPRequest.INIT_SEGMENT_TYPE]: 1000,
                [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 1000,
                [HTTPRequest.INDEX_SEGMENT_TYPE]: 1000,
                [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 1000,
                [HTTPRequest.LICENSE]: 1000,
                [HTTPRequest.OTHER_TYPE]: 1000,
                lowLatencyReductionFactor: 10
            },
            retryAttempts: {
                [HTTPRequest.MPD_TYPE]: 3,
                [HTTPRequest.XLINK_EXPANSION_TYPE]: 1,
                [HTTPRequest.MEDIA_SEGMENT_TYPE]: 3,
                [HTTPRequest.INIT_SEGMENT_TYPE]: 3,
                [HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE]: 3,
                [HTTPRequest.INDEX_SEGMENT_TYPE]: 3,
                [HTTPRequest.MSS_FRAGMENT_INFO_SEGMENT_TYPE]: 3,
                [HTTPRequest.LICENSE]: 3,
                [HTTPRequest.OTHER_TYPE]: 3,
                lowLatencyMultiplyFactor: 5
            },
            abr: {
                movingAverageMethod: Constants.MOVING_AVERAGE_SLIDING_WINDOW,
                ABRStrategy: Constants.ABR_STRATEGY_DYNAMIC,
                additionalAbrRules: {
                    insufficientBufferRule: true,
                    switchHistoryRule: true,
                    droppedFramesRule: true,
                    abandonRequestsRule: false
                },
                bandwidthSafetyFactor: 0.9,
                useDefaultABRRules: true,
                useDeadTimeLatency: true,
                limitBitrateByPortal: false,
                usePixelRatioInLimitBitrateByPortal: false,
                maxBitrate: {
                    audio: -1,
                    video: -1
                },
                minBitrate: {
                    audio: -1,
                    video: -1
                },
                maxRepresentationRatio: {
                    audio: 1,
                    video: 1
                },
                initialBitrate: {
                    audio: -1,
                    video: -1
                },
                initialRepresentationRatio: {
                    audio: -1,
                    video: -1
                },
                autoSwitchBitrate: {
                    audio: true,
                    video: true
                },
                fetchThroughputCalculationMode: Constants.ABR_FETCH_THROUGHPUT_CALCULATION_MOOF_PARSING
            },
            cmcd: {
                enabled: false,
                sid: null,
                cid: null,
                rtp: null,
                rtpSafetyFactor: 5,
                mode: Constants.CMCD_MODE_QUERY
            }
        }

Mediaplayer Events

All Mediaplayer events are now documented (JSDoc). Please check carefully for the required type of event needed by your application. Make sure that the events you are using in your application are included in the list of available events depicted below:

        /**
         * Triggered when playback will not start yet
         * as the MPD's availabilityStartTime is in the future.
         * Check delay property in payload to determine time before playback will start.
         * @event MediaPlayerEvents#AST_IN_FUTURE
         */
        this.AST_IN_FUTURE = 'astInFuture';

        /**
         * Triggered when the video element's buffer state changes to stalled.
         * Check mediaType in payload to determine type (Video, Audio, FragmentedText).
         * @event MediaPlayerEvents#BUFFER_EMPTY
         */
        this.BUFFER_EMPTY = 'bufferStalled';

        /**
         * Triggered when the video element's buffer state changes to loaded.
         * Check mediaType in payload to determine type (Video, Audio, FragmentedText).
         * @event MediaPlayerEvents#BUFFER_LOADED
         */
        this.BUFFER_LOADED = 'bufferLoaded';

        /**
         * Triggered when the video element's buffer state changes, either stalled or loaded. Check payload for state.
         * @event MediaPlayerEvents#BUFFER_LEVEL_STATE_CHANGED
         */
        this.BUFFER_LEVEL_STATE_CHANGED = 'bufferStateChanged';

        /**
         * Triggered when the buffer level of a media type has been updated
         * @event MediaPlayerEvents#BUFFER_LEVEL_UPDATED
         */
        this.BUFFER_LEVEL_UPDATED = 'bufferLevelUpdated';

        /**
         * Triggered when a dynamic stream changed to static (transition phase between Live and On-Demand).
         * @event MediaPlayerEvents#DYNAMIC_TO_STATIC
         */
        this.DYNAMIC_TO_STATIC = 'dynamicToStatic';

        /**
         * Triggered when there is an error from the element or MSE source buffer.
         * @event MediaPlayerEvents#ERROR
         */
        this.ERROR = 'error';
        /**
         * Triggered when a fragment download has completed.
         * @event MediaPlayerEvents#FRAGMENT_LOADING_COMPLETED
         */
        this.FRAGMENT_LOADING_COMPLETED = 'fragmentLoadingCompleted';

        /**
         * Triggered when a partial fragment download has completed.
         * @event MediaPlayerEvents#FRAGMENT_LOADING_PROGRESS
         */
        this.FRAGMENT_LOADING_PROGRESS = 'fragmentLoadingProgress';
        /**
         * Triggered when a fragment download has started.
         * @event MediaPlayerEvents#FRAGMENT_LOADING_STARTED
         */
        this.FRAGMENT_LOADING_STARTED = 'fragmentLoadingStarted';

        /**
         * Triggered when a fragment download is abandoned due to detection of slow download base on the ABR abandon rule..
         * @event MediaPlayerEvents#FRAGMENT_LOADING_ABANDONED
         */
        this.FRAGMENT_LOADING_ABANDONED = 'fragmentLoadingAbandoned';

        /**
         * Triggered when {@link module:Debug} logger methods are called.
         * @event MediaPlayerEvents#LOG
         */
        this.LOG = 'log';

        /**
         * Triggered when the manifest load is complete
         * @event MediaPlayerEvents#MANIFEST_LOADED
         */
        this.MANIFEST_LOADED = 'manifestLoaded';

        /**
         * Triggered anytime there is a change to the overall metrics.
         * @event MediaPlayerEvents#METRICS_CHANGED
         */
        this.METRICS_CHANGED = 'metricsChanged';

        /**
         * Triggered when an individual metric is added, updated or cleared.
         * @event MediaPlayerEvents#METRIC_CHANGED
         */
        this.METRIC_CHANGED = 'metricChanged';

        /**
         * Triggered every time a new metric is added.
         * @event MediaPlayerEvents#METRIC_ADDED
         */
        this.METRIC_ADDED = 'metricAdded';

        /**
         * Triggered every time a metric is updated.
         * @event MediaPlayerEvents#METRIC_UPDATED
         */
        this.METRIC_UPDATED = 'metricUpdated';

        /**
         * Triggered at the stream end of a period.
         * @event MediaPlayerEvents#PERIOD_SWITCH_COMPLETED
         */
        this.PERIOD_SWITCH_COMPLETED = 'periodSwitchCompleted';

        /**
         * Triggered when a new stream (period) starts.
         * @event MediaPlayerEvents#STREAM_SWITCH_STARTED
         */
        this.STREAM_SWITCH_STARTED = 'streamSwitchStarted';

        /**
         * Triggered when an ABR up /down switch is initiated; either by user in manual mode or auto mode via ABR rules.
         * @event MediaPlayerEvents#QUALITY_CHANGE_REQUESTED
         */
        this.QUALITY_CHANGE_REQUESTED = 'qualityChangeRequested';

        /**
         * Triggered when the new ABR quality is being rendered on-screen.
         * @event MediaPlayerEvents#QUALITY_CHANGE_RENDERED
         */
        this.QUALITY_CHANGE_RENDERED = 'qualityChangeRendered';

        /**
         * Triggered when the new track is being rendered.
         * @event MediaPlayerEvents#TRACK_CHANGE_RENDERED
         */
        this.TRACK_CHANGE_RENDERED = 'trackChangeRendered';

        /**
         * Triggered when a stream (period) is being loaded
         * @event MediaPlayerEvents#STREAM_INITIALIZING
         */
        this.STREAM_INITIALIZING = 'streamInitializing';

        /**
         * Triggered when a stream (period) is loaded
         * @event MediaPlayerEvents#STREAM_UPDATED
         */
        this.STREAM_UPDATED = 'streamUpdated';

        /**
         * Triggered when a stream (period) is activated
         * @event MediaPlayerEvents#STREAM_ACTIVATED
         */
        this.STREAM_ACTIVATED = 'streamActivated';

        /**
         * Triggered when a stream (period) is deactivated
         * @event MediaPlayerEvents#STREAM_DEACTIVATED
         */
        this.STREAM_DEACTIVATED = 'streamDeactivated';

        /**
         * Triggered when a stream (period) is activated
         * @event MediaPlayerEvents#STREAM_INITIALIZED
         */
        this.STREAM_INITIALIZED = 'streamInitialized';

        /**
         * Triggered when the player has been reset.
         * @event MediaPlayerEvents#STREAM_TEARDOWN_COMPLETE
         */
        this.STREAM_TEARDOWN_COMPLETE = 'streamTeardownComplete';

        /**
         * Triggered once all text tracks detected in the MPD are added to the video element.
         * @event MediaPlayerEvents#TEXT_TRACKS_ADDED
         */
        this.TEXT_TRACKS_ADDED = 'allTextTracksAdded';

        /**
         * Triggered when a text track is added to the video element's TextTrackList
         * @event MediaPlayerEvents#TEXT_TRACK_ADDED
         */
        this.TEXT_TRACK_ADDED = 'textTrackAdded';

        /**
         * Triggered when a ttml chunk is parsed.
         * @event MediaPlayerEvents#TTML_PARSED
         */
        this.TTML_PARSED = 'ttmlParsed';

        /**
         * Triggered when a ttml chunk has to be parsed.
         * @event MediaPlayerEvents#TTML_TO_PARSE
         */
        this.TTML_TO_PARSE = 'ttmlToParse';

        /**
         * Triggered when a caption is rendered.
         * @event MediaPlayerEvents#CAPTION_RENDERED
         */
        this.CAPTION_RENDERED = 'captionRendered';

        /**
         * Triggered when the caption container is resized.
         * @event MediaPlayerEvents#CAPTION_CONTAINER_RESIZE
         */
        this.CAPTION_CONTAINER_RESIZE = 'captionContainerResize';

        /**
         * Sent when enough data is available that the media can be played,
         * at least for a couple of frames.  This corresponds to the
         * HAVE_ENOUGH_DATA readyState.
         * @event MediaPlayerEvents#CAN_PLAY
         */
        this.CAN_PLAY = 'canPlay';

        /**
         * This corresponds to the CAN_PLAY_THROUGH readyState.
         * @event MediaPlayerEvents#CAN_PLAY_THROUGH
         */
        this.CAN_PLAY_THROUGH = 'canPlayThrough';

        /**
         * Sent when playback completes.
         * @event MediaPlayerEvents#PLAYBACK_ENDED
         */
        this.PLAYBACK_ENDED = 'playbackEnded';

        /**
         * Sent when an error occurs.  The element's error
         * attribute contains more information.
         * @event MediaPlayerEvents#PLAYBACK_ERROR
         */
        this.PLAYBACK_ERROR = 'playbackError';

        /**
         * Sent when playback is not allowed (for example if user gesture is needed).
         * @event MediaPlayerEvents#PLAYBACK_NOT_ALLOWED
         */
        this.PLAYBACK_NOT_ALLOWED = 'playbackNotAllowed';

        /**
         * The media's metadata has finished loading; all attributes now
         * contain as much useful information as they're going to.
         * @event MediaPlayerEvents#PLAYBACK_METADATA_LOADED
         */
        this.PLAYBACK_METADATA_LOADED = 'playbackMetaDataLoaded';

        /**
         * The media's metadata has finished loading; all attributes now
         * contain as much useful information as they're going to.
         * @event MediaPlayerEvents#PLAYBACK_METADATA_LOADED
         */
        this.PLAYBACK_LOADED_DATA = 'playbackLoadedData';

        /**
         * Sent when playback is paused.
         * @event MediaPlayerEvents#PLAYBACK_PAUSED
         */
        this.PLAYBACK_PAUSED = 'playbackPaused';

        /**
         * Sent when the media begins to play (either for the first time, after having been paused,
         * or after ending and then restarting).
         *
         * @event MediaPlayerEvents#PLAYBACK_PLAYING
         */
        this.PLAYBACK_PLAYING = 'playbackPlaying';

        /**
         * Sent periodically to inform interested parties of progress downloading
         * the media. Information about the current amount of the media that has
         * been downloaded is available in the media element's buffered attribute.
         * @event MediaPlayerEvents#PLAYBACK_PROGRESS
         */
        this.PLAYBACK_PROGRESS = 'playbackProgress';

        /**
         * Sent when the playback speed changes.
         * @event MediaPlayerEvents#PLAYBACK_RATE_CHANGED
         */
        this.PLAYBACK_RATE_CHANGED = 'playbackRateChanged';

        /**
         * Sent when a seek operation completes.
         * @event MediaPlayerEvents#PLAYBACK_SEEKED
         */
        this.PLAYBACK_SEEKED = 'playbackSeeked';

        /**
         * Sent when a seek operation begins.
         * @event MediaPlayerEvents#PLAYBACK_SEEKING
         */
        this.PLAYBACK_SEEKING = 'playbackSeeking';

        /**
         * Sent when a seek operation has been asked.
         * @event MediaPlayerEvents#PLAYBACK_SEEK_ASKED
         */
        this.PLAYBACK_SEEK_ASKED = 'playbackSeekAsked';

        /**
         * Sent when the video element reports stalled
         * @event MediaPlayerEvents#PLAYBACK_STALLED
         */
        this.PLAYBACK_STALLED = 'playbackStalled';

        /**
         * Sent when playback of the media starts after having been paused;
         * that is, when playback is resumed after a prior pause event.
         *
         * @event MediaPlayerEvents#PLAYBACK_STARTED
         */
        this.PLAYBACK_STARTED = 'playbackStarted';

        /**
         * The time indicated by the element's currentTime attribute has changed.
         * @event MediaPlayerEvents#PLAYBACK_TIME_UPDATED
         */
        this.PLAYBACK_TIME_UPDATED = 'playbackTimeUpdated';

        /**
         * Sent when the media playback has stopped because of a temporary lack of data.
         *
         * @event MediaPlayerEvents#PLAYBACK_WAITING
         */
        this.PLAYBACK_WAITING = 'playbackWaiting';

        /**
         * Manifest validity changed - As a result of an MPD validity expiration event.
         * @event MediaPlayerEvents#MANIFEST_VALIDITY_CHANGED
         */
        this.MANIFEST_VALIDITY_CHANGED = 'manifestValidityChanged';

        /**
         * Dash events are triggered at their respective start points on the timeline.
         * @event MediaPlayerEvents#EVENT_MODE_ON_START
         */
        this.EVENT_MODE_ON_START = 'eventModeOnStart';

        /**
         * Dash events are triggered as soon as they were parsed.
         * @event MediaPlayerEvents#EVENT_MODE_ON_RECEIVE
         */
        this.EVENT_MODE_ON_RECEIVE = 'eventModeOnReceive';

        /**
         * Event that is dispatched whenever the player encounters a potential conformance validation that might lead to unexpected/not optimal behavior
         * @event MediaPlayerEvents#CONFORMANCE_VIOLATION
         */
        this.CONFORMANCE_VIOLATION = 'conformanceViolation';

        /**
         * Event that is dispatched whenever the player switches to a different representation
         * @event MediaPlayerEvents#REPRESENTATION_SWITCH
         */
        this.REPRESENTATION_SWITCH = 'representationSwitch';

API changes

Mediaplayer.js

Only minor changes were applied to the MediaPlayer API.

  • There is only one type for all textracks now. For instance:
player.setInitialMediaSettingsFor('text', {
  lang: 'eng,
  role: 'caption
});

Details can be found in the sample section in the category "subtitles and captions": Samples

  • setTextDefaultLanguage , getTextDefaultLanguage have been removed. Use setInitialMediaSettingsFor and getInitialMediaSettingsFor instead.
  • Enable text by default using the settings:
streaming: 
    {
      text: {
        defaultEnabled: true
       }   
    }
  • setTrackSwitchModeFor and getTrackSwitchModeFor have been removed. Use the settings instead:
streaming: 
    { 
       trackSwitchMode: 
         {
           video: mode,
           audio: mode
         }
     } 

Clone this wiki locally