From 7c9cba3253d291dcc20f17cb67d219094401bec0 Mon Sep 17 00:00:00 2001 From: Alvaro Escarcha Date: Thu, 7 Jun 2018 09:29:35 +0200 Subject: [PATCH 1/2] Catching up with the edge in live streams --- index.d.ts | 2 + src/streaming/MediaPlayer.js | 26 ++++++++ src/streaming/MediaPlayerEvents.js | 13 ++++ .../controllers/PlaybackController.js | 64 +++++++++++++++++++ .../rules/scheduling/BufferLevelRule.js | 1 - test/unit/mocks/PlaybackControllerMock.js | 9 +++ test/unit/streaming.MediaPlayerSpec.js | 21 +++++- 7 files changed, 134 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 7726651cc9..0146d2705a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -269,6 +269,8 @@ declare namespace dashjs { METRIC_UPDATED: 'metricUpdated'; PERIOD_SWITCH_COMPLETED: 'periodSwitchCompleted'; PERIOD_SWITCH_STARTED: 'periodSwitchStarted'; + PLAYBACK_CATCHUP_END: 'playbackCatchupEnd'; + PLAYBACK_CATCHUP_START: 'playbackCatchupStart'; PLAYBACK_ENDED: 'playbackEnded'; PLAYBACK_ERROR: 'playbackError'; PLAYBACK_METADATA_LOADED: 'playbackMetaDataLoaded'; diff --git a/src/streaming/MediaPlayer.js b/src/streaming/MediaPlayer.js index 26da644330..20dfc9e716 100644 --- a/src/streaming/MediaPlayer.js +++ b/src/streaming/MediaPlayer.js @@ -82,6 +82,7 @@ function MediaPlayer() { const SOURCE_NOT_ATTACHED_ERROR = 'You must first call attachSource() with a valid source before calling this method'; const MEDIA_PLAYER_NOT_INITIALIZED_ERROR = 'MediaPlayer not initialized!'; const MEDIA_PLAYER_BAD_ARGUMENT_ERROR = 'MediaPlayer Invalid Arguments!'; + const PLAYBACK_CATCHUP_RATE_BAD_ARGUMENT_ERROR = 'Playback catchup rate invalid argument! Use a number from 1 to 1.2'; const context = this.context; const eventBus = EventBus(context).getInstance(); @@ -482,6 +483,29 @@ function MediaPlayer() { return getVideoElement().playbackRate; } + /** + * Use this method to set the playback rate that will be used when catching up with live stream. Set 1 to disable the feature. + * @param {number} value + * @memberof module:MediaPlayer + * @instance + */ + function setCatchUpPlaybackRate(value) { + if (isNaN(value) || value < 1 || value > 1.20) { + throw PLAYBACK_CATCHUP_RATE_BAD_ARGUMENT_ERROR; + } + playbackController.setCatchUpPlaybackRate(value); + } + + /** + * Returns the current catchup playback rate. + * @returns {number} + * @memberof module:MediaPlayer + * @instance + */ + function getCatchUpPlaybackRate() { + return playbackController.getCatchUpPlaybackRate(); + } + /** * Use this method to set the native Video Element's muted state. Takes a Boolean that determines whether audio is muted. true if the audio is muted and false otherwise. * @param {boolean} value @@ -2831,6 +2855,8 @@ function MediaPlayer() { seek: seek, setPlaybackRate: setPlaybackRate, getPlaybackRate: getPlaybackRate, + setCatchUpPlaybackRate: setCatchUpPlaybackRate, + getCatchUpPlaybackRate: getCatchUpPlaybackRate, setMute: setMute, isMuted: isMuted, setVolume: setVolume, diff --git a/src/streaming/MediaPlayerEvents.js b/src/streaming/MediaPlayerEvents.js index 46fa749130..0738f4c122 100644 --- a/src/streaming/MediaPlayerEvents.js +++ b/src/streaming/MediaPlayerEvents.js @@ -214,6 +214,19 @@ class MediaPlayerEvents extends EventsBase { */ this.CAN_PLAY = 'canPlay'; + + /** + * Sent live catch up stops and playback rate goes back to normal + * @event MediaPlayerEvents#PLAYBACK_CATCHUP_END + */ + this.PLAYBACK_CATCHUP_END = 'playbackCatchupEnd'; + + /** + * Sent when playing live and buffer is too long, the player starts catching up by accelerating. + * @event MediaPlayerEvents#PLAYBACK_CATCHUP_START + */ + this.PLAYBACK_CATCHUP_START = 'playbackCatchupStart'; + /** * Sent when playback completes. * @event MediaPlayerEvents#PLAYBACK_ENDED diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index a15eb97e3b..7bbfe8d455 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -37,6 +37,8 @@ import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; const LIVE_UPDATE_PLAYBACK_TIME_INTERVAL_MS = 500; +const DEFAULT_CATCHUP_PLAYBACK_RATE = 1.05; +const LIVE_CATCHUP_THRESHOLD = 0.5; function PlaybackController() { @@ -63,8 +65,12 @@ function PlaybackController() { mediaPlayerModel, playOnceInitialized, lastLivePlaybackTime, + originalPlaybackRate, + catchingUp, availabilityStartTime; + let catchUpPlaybackRate = DEFAULT_CATCHUP_PLAYBACK_RATE; + function setup() { logger = Debug(context).getInstance().getLogger(instance); reset(); @@ -79,6 +85,10 @@ function PlaybackController() { eventBus.on(Events.BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this); eventBus.on(Events.BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this); eventBus.on(Events.PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, this); + eventBus.on(Events.PLAYBACK_CATCHUP_END, onPlaybackCatchUpEnd, this); + eventBus.on(Events.PLAYBACK_CATCHUP_START, onPlaybackCatchUpStart, this); + eventBus.on(Events.PLAYBACK_PROGRESS, onPlaybackProgression, this); + eventBus.on(Events.PLAYBACK_TIME_UPDATED, onPlaybackProgression, this); if (playOnceInitialized) { playOnceInitialized = false; @@ -161,6 +171,14 @@ function PlaybackController() { return liveStartTime; } + function setCatchUpPlaybackRate(value) { + catchUpPlaybackRate = value; + } + + function getCatchUpPlaybackRate() { + return catchUpPlaybackRate; + } + /** * Computes the desirable delay for the live edge to avoid a risk of getting 404 when playing at the bleeding edge * @param {number} fragmentDuration - seconds? @@ -220,6 +238,21 @@ function PlaybackController() { return ((Math.round(new Date().getTime() - (currentTime * 1000 + availabilityStartTime))) / 1000).toFixed(3); } + function onPlaybackCatchUpStart() { + if (videoModel) { + logger.info('onPlaybackCatchUpStart setting playback rate to', getCatchUpPlaybackRate()); + originalPlaybackRate = originalPlaybackRate || getPlaybackRate(); + videoModel.getElement().playbackRate = getCatchUpPlaybackRate(); + } + } + + function onPlaybackCatchUpEnd() { + if (videoModel) { + logger.info('onPlaybackCatchUpEnd setting playback rate to', originalPlaybackRate || 1); + videoModel.getElement().playbackRate = originalPlaybackRate || 1; + } + } + function reset() { currentTime = 0; liveStartTime = NaN; @@ -227,12 +260,17 @@ function PlaybackController() { commonEarliestTime = {}; liveDelay = 0; availabilityStartTime = 0; + catchUpPlaybackRate = DEFAULT_CATCHUP_PLAYBACK_RATE; bufferedRange = {}; if (videoModel) { eventBus.off(Events.DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this); eventBus.off(Events.BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this); eventBus.off(Events.BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this); eventBus.off(Events.PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, this); + eventBus.off(Events.PLAYBACK_CATCHUP_END, onPlaybackCatchUpEnd, this); + eventBus.off(Events.PLAYBACK_CATCHUP_START, onPlaybackCatchUpStart, this); + eventBus.off(Events.PLAYBACK_PROGRESS, onPlaybackProgression, this); + eventBus.off(Events.PLAYBACK_TIME_UPDATED, onPlaybackProgression, this); stopUpdatingWallclockTime(); removeAllListeners(); } @@ -510,6 +548,31 @@ function PlaybackController() { return false; } + function onPlaybackProgression() { + if (needToCatchUp() && !catchingUp) { + catchingUp = true; + eventBus.trigger(Events.PLAYBACK_CATCHUP_START, { sender: instance }); + } else if (stopCatchingUp()) { + catchingUp = false; + eventBus.trigger(Events.PLAYBACK_CATCHUP_END, { sender: instance }); + } + } + + function needToCatchUp() { + if (getIsDynamic() && getCatchUpPlaybackRate() !== 1) { + return getCurrentLiveLatency() > (mediaPlayerModel.getLiveDelay() * (1 + LIVE_CATCHUP_THRESHOLD)); + } + return false; + } + + function stopCatchingUp() { + if (catchingUp && getIsDynamic()) { + return getCurrentLiveLatency() <= (mediaPlayerModel.getLiveDelay() + LIVE_CATCHUP_THRESHOLD ); + } + + return false; + } + function onBytesAppended(e) { let earliestTime, initialStartTime; @@ -625,6 +688,7 @@ function PlaybackController() { getEnded: getEnded, getIsDynamic: getIsDynamic, getStreamController: getStreamController, + setCatchUpPlaybackRate: setCatchUpPlaybackRate, setLiveStartTime: setLiveStartTime, getLiveStartTime: getLiveStartTime, computeLiveDelay: computeLiveDelay, diff --git a/src/streaming/rules/scheduling/BufferLevelRule.js b/src/streaming/rules/scheduling/BufferLevelRule.js index b3da43ba94..dad3e5ed5d 100644 --- a/src/streaming/rules/scheduling/BufferLevelRule.js +++ b/src/streaming/rules/scheduling/BufferLevelRule.js @@ -69,7 +69,6 @@ function BufferLevelRule(config) { bufferTarget = mediaPlayerModel.getStableBufferTime(); } } - return bufferTarget; } diff --git a/test/unit/mocks/PlaybackControllerMock.js b/test/unit/mocks/PlaybackControllerMock.js index 3e579b71ff..60393c343e 100644 --- a/test/unit/mocks/PlaybackControllerMock.js +++ b/test/unit/mocks/PlaybackControllerMock.js @@ -9,6 +9,7 @@ class PlaybackControllerMock { this.playing = false; this.seeking = false; this.isDynamic = false; + this.catchUpPlaybackRate = 1.05; } initialize() {} @@ -97,6 +98,14 @@ class PlaybackControllerMock { getStreamStartTime() { return 0; } + + setCatchUpPlaybackRate(value) { + this.catchUpPlaybackRate = value; + } + + getCatchUpPlaybackRate() { + return this.catchUpPlaybackRate; + } } export default PlaybackControllerMock; diff --git a/test/unit/streaming.MediaPlayerSpec.js b/test/unit/streaming.MediaPlayerSpec.js index c463a05bce..94e3c846f9 100644 --- a/test/unit/streaming.MediaPlayerSpec.js +++ b/test/unit/streaming.MediaPlayerSpec.js @@ -247,7 +247,7 @@ describe('MediaPlayer', function () { expect(playbackRate).to.equal(newPlaybackRate); }); - it('Method setPlaybackRate should return video element playback rate', function () { + it('Method getPlaybackRate should return video element playback rate', function () { const elementPlayBackRate = videoElementMock.playbackRate; const playerPlayBackRate = player.getPlaybackRate(); expect(playerPlayBackRate).to.equal(elementPlayBackRate); @@ -330,6 +330,25 @@ describe('MediaPlayer', function () { duration = player.duration(); expect(duration).to.equal(4); }); + + it('Method setCatchUpPlaybackRate should change catchUpPlaybackRate', function () { + let rate = player.getCatchUpPlaybackRate(); + expect(rate).to.equal(1.05); + + player.setCatchUpPlaybackRate(1.2); + rate = player.getCatchUpPlaybackRate(); + expect(rate).to.equal(1.2); + + player.setCatchUpPlaybackRate(1); + rate = player.getCatchUpPlaybackRate(); + expect(rate).to.equal(1); + }); + + it('Method setCatchUpPlaybackRate should throw an exception if given bad values', function () { + expect(() => {player.setCatchUpPlaybackRate(0.9);}).to.throw(MediaPlayer.PLAYBACK_CATCHUP_RATE_BAD_ARGUMENT_ERROR); + expect(() => {player.setCatchUpPlaybackRate(13);}).to.throw(MediaPlayer.PLAYBACK_CATCHUP_RATE_BAD_ARGUMENT_ERROR); + expect(() => {player.setCatchUpPlaybackRate('string');}).to.throw(MediaPlayer.PLAYBACK_CATCHUP_RATE_BAD_ARGUMENT_ERROR); + }); }); }); From f14e6ff057f3b9c785ba0b2abad4fec55bf5c39d Mon Sep 17 00:00:00 2001 From: "J. Oliva" Date: Thu, 7 Jun 2018 16:45:53 +0200 Subject: [PATCH 2/2] Minor fixes and documentation update --- build/typings/index.d.ts | 2 +- index.d.ts | 2 +- .../dash-if-reference-player/app/sources.json | 4 +- src/streaming/MediaPlayer.js | 16 ++++- src/streaming/MediaPlayerEvents.js | 18 +++-- .../controllers/PlaybackController.js | 68 +++++++++++-------- test/unit/mocks/PlaybackControllerMock.js | 2 +- test/unit/streaming.MediaPlayerSpec.js | 10 +-- 8 files changed, 74 insertions(+), 48 deletions(-) diff --git a/build/typings/index.d.ts b/build/typings/index.d.ts index 7726651cc9..9989befd48 100644 --- a/build/typings/index.d.ts +++ b/build/typings/index.d.ts @@ -123,7 +123,7 @@ declare namespace dashjs { isMuted(): boolean; setVolume(value: number): void; getVolume(): number; - time(streamId: string | undefined): number; + time(streamId?: string): number; duration(): number; timeAsUTC(): number; durationAsUTC(): number; diff --git a/index.d.ts b/index.d.ts index 0146d2705a..007beeeae8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -123,7 +123,7 @@ declare namespace dashjs { isMuted(): boolean; setVolume(value: number): void; getVolume(): number; - time(streamId: string | undefined): number; + time(streamId?: string): number; duration(): number; timeAsUTC(): number; durationAsUTC(): number; diff --git a/samples/dash-if-reference-player/app/sources.json b/samples/dash-if-reference-player/app/sources.json index 9aa699f7ac..d6be8afae2 100644 --- a/samples/dash-if-reference-player/app/sources.json +++ b/samples/dash-if-reference-player/app/sources.json @@ -74,7 +74,7 @@ "name": "Low Latency (Single-Rate)", "bufferConfig" : { "lowLatencyMode": true, - "liveDelay": 3 + "liveDelay": 3.5 } }, { @@ -82,7 +82,7 @@ "name": "Low Latency (Multi-Rate)", "bufferConfig" : { "lowLatencyMode": true, - "liveDelay": 3 + "liveDelay": 3.5 } }, { diff --git a/src/streaming/MediaPlayer.js b/src/streaming/MediaPlayer.js index 20dfc9e716..12133febf8 100644 --- a/src/streaming/MediaPlayer.js +++ b/src/streaming/MediaPlayer.js @@ -484,13 +484,22 @@ function MediaPlayer() { } /** - * Use this method to set the playback rate that will be used when catching up with live stream. Set 1 to disable the feature. - * @param {number} value + * Use this method to set the catch up rate, as a percentage, for low latency live streams. In low latency mode, + * when measured latency is higher than the target one ({@link module:MediaPlayer#setLiveDelay setLiveDelay()}), + * dash.js increases playback rate the percentage defined with this method until target is reached. + * + * Valid values for catch up rate are in range 0-20%. Set it to 0% to turn off live catch up feature. + * + * Note: Catch-up mechanism is only applied when playing low latency live streams. + * + * @param {number} value Percentage in which playback rate is increased when live catch up mechanism is activated. * @memberof module:MediaPlayer + * @see {@link module:MediaPlayer#setLiveDelay setLiveDelay()} + * @default {number} 0.05 * @instance */ function setCatchUpPlaybackRate(value) { - if (isNaN(value) || value < 1 || value > 1.20) { + if (isNaN(value) || value < 0.0 || value > 0.20) { throw PLAYBACK_CATCHUP_RATE_BAD_ARGUMENT_ERROR; } playbackController.setCatchUpPlaybackRate(value); @@ -499,6 +508,7 @@ function MediaPlayer() { /** * Returns the current catchup playback rate. * @returns {number} + * @see {@link module:MediaPlayer#setCatchUpPlaybackRate setCatchUpPlaybackRate()} * @memberof module:MediaPlayer * @instance */ diff --git a/src/streaming/MediaPlayerEvents.js b/src/streaming/MediaPlayerEvents.js index 0738f4c122..31a58984cc 100644 --- a/src/streaming/MediaPlayerEvents.js +++ b/src/streaming/MediaPlayerEvents.js @@ -214,18 +214,22 @@ class MediaPlayerEvents extends EventsBase { */ this.CAN_PLAY = 'canPlay'; - /** - * Sent live catch up stops and playback rate goes back to normal - * @event MediaPlayerEvents#PLAYBACK_CATCHUP_END + * Sent when live catch mechanism has been activated, which implies the measured latency of the low latency + * stream that is been played has gone beyond the target one. + * @see {@link module:MediaPlayer#setCatchUpPlaybackRate setCatchUpPlaybackRate()} + * @see {@link module:MediaPlayer#setLiveDelay setLiveDelay()} + * @event MediaPlayerEvents#PLAYBACK_CATCHUP_START */ - this.PLAYBACK_CATCHUP_END = 'playbackCatchupEnd'; + this.PLAYBACK_CATCHUP_START = 'playbackCatchupStart'; /** - * Sent when playing live and buffer is too long, the player starts catching up by accelerating. - * @event MediaPlayerEvents#PLAYBACK_CATCHUP_START + * Sent live catch up mechanism has been deactivated. + * @see {@link module:MediaPlayer#setCatchUpPlaybackRate setCatchUpPlaybackRate()} + * @see {@link module:MediaPlayer#setLiveDelay setLiveDelay()} + * @event MediaPlayerEvents#PLAYBACK_CATCHUP_END */ - this.PLAYBACK_CATCHUP_START = 'playbackCatchupStart'; + this.PLAYBACK_CATCHUP_END = 'playbackCatchupEnd'; /** * Sent when playback completes. diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js index 7bbfe8d455..df0e880652 100644 --- a/src/streaming/controllers/PlaybackController.js +++ b/src/streaming/controllers/PlaybackController.js @@ -37,8 +37,11 @@ import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; const LIVE_UPDATE_PLAYBACK_TIME_INTERVAL_MS = 500; -const DEFAULT_CATCHUP_PLAYBACK_RATE = 1.05; -const LIVE_CATCHUP_THRESHOLD = 0.5; +const DEFAULT_CATCHUP_PLAYBACK_RATE = 0.05; + +// Start catching up mechanism for low latency live streaming +// when latency goes beyong targetDelay * (1 + LIVE_CATCHUP_START_THRESHOLD) +const LIVE_CATCHUP_START_THRESHOLD = 0.35; function PlaybackController() { @@ -85,8 +88,6 @@ function PlaybackController() { eventBus.on(Events.BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this); eventBus.on(Events.BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this); eventBus.on(Events.PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, this); - eventBus.on(Events.PLAYBACK_CATCHUP_END, onPlaybackCatchUpEnd, this); - eventBus.on(Events.PLAYBACK_CATCHUP_START, onPlaybackCatchUpStart, this); eventBus.on(Events.PLAYBACK_PROGRESS, onPlaybackProgression, this); eventBus.on(Events.PLAYBACK_TIME_UPDATED, onPlaybackProgression, this); @@ -173,6 +174,11 @@ function PlaybackController() { function setCatchUpPlaybackRate(value) { catchUpPlaybackRate = value; + + // If value == 0.0, deactivate catchup mechanism + if (value === 0.0 && getPlaybackRate() > 1.0) { + stopPlaybackCatchUp(); + } } function getCatchUpPlaybackRate() { @@ -238,18 +244,33 @@ function PlaybackController() { return ((Math.round(new Date().getTime() - (currentTime * 1000 + availabilityStartTime))) / 1000).toFixed(3); } - function onPlaybackCatchUpStart() { + function startPlaybackCatchUp() { if (videoModel) { - logger.info('onPlaybackCatchUpStart setting playback rate to', getCatchUpPlaybackRate()); - originalPlaybackRate = originalPlaybackRate || getPlaybackRate(); - videoModel.getElement().playbackRate = getCatchUpPlaybackRate(); + const playbackRate = 1 + getCatchUpPlaybackRate(); + const currentRate = getPlaybackRate(); + if (playbackRate !== currentRate) { + catchingUp = true; + + logger.info('Starting live catchup mechanism. Setting playback rate to', playbackRate); + originalPlaybackRate = currentRate; + videoModel.getElement().playbackRate = playbackRate; + + eventBus.trigger(Events.PLAYBACK_CATCHUP_START, { sender: instance }); + } } } - function onPlaybackCatchUpEnd() { + function stopPlaybackCatchUp() { if (videoModel) { - logger.info('onPlaybackCatchUpEnd setting playback rate to', originalPlaybackRate || 1); - videoModel.getElement().playbackRate = originalPlaybackRate || 1; + const playbackRate = originalPlaybackRate || 1; + if (playbackRate !== getPlaybackRate()) { + catchingUp = false; + + logger.info('Stopping live catchup mechanism. Setting playback rate to', playbackRate); + videoModel.getElement().playbackRate = playbackRate; + + eventBus.trigger(Events.PLAYBACK_CATCHUP_END, { sender: instance }); + } } } @@ -267,8 +288,6 @@ function PlaybackController() { eventBus.off(Events.BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this); eventBus.off(Events.BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this); eventBus.off(Events.PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, this); - eventBus.off(Events.PLAYBACK_CATCHUP_END, onPlaybackCatchUpEnd, this); - eventBus.off(Events.PLAYBACK_CATCHUP_START, onPlaybackCatchUpStart, this); eventBus.off(Events.PLAYBACK_PROGRESS, onPlaybackProgression, this); eventBus.off(Events.PLAYBACK_TIME_UPDATED, onPlaybackProgression, this); stopUpdatingWallclockTime(); @@ -549,28 +568,21 @@ function PlaybackController() { } function onPlaybackProgression() { - if (needToCatchUp() && !catchingUp) { - catchingUp = true; - eventBus.trigger(Events.PLAYBACK_CATCHUP_START, { sender: instance }); - } else if (stopCatchingUp()) { - catchingUp = false; - eventBus.trigger(Events.PLAYBACK_CATCHUP_END, { sender: instance }); + if (isDynamic && mediaPlayerModel.getLowLatencyEnabled() && getCatchUpPlaybackRate() > 0.0) { + if (!catchingUp && needToCatchUp()) { + startPlaybackCatchUp(); + } else if (stopCatchingUp()) { + stopPlaybackCatchUp(); + } } } function needToCatchUp() { - if (getIsDynamic() && getCatchUpPlaybackRate() !== 1) { - return getCurrentLiveLatency() > (mediaPlayerModel.getLiveDelay() * (1 + LIVE_CATCHUP_THRESHOLD)); - } - return false; + return getCurrentLiveLatency() > (mediaPlayerModel.getLiveDelay() * (1 + LIVE_CATCHUP_START_THRESHOLD)); } function stopCatchingUp() { - if (catchingUp && getIsDynamic()) { - return getCurrentLiveLatency() <= (mediaPlayerModel.getLiveDelay() + LIVE_CATCHUP_THRESHOLD ); - } - - return false; + return getCurrentLiveLatency() <= (mediaPlayerModel.getLiveDelay() ); } function onBytesAppended(e) { diff --git a/test/unit/mocks/PlaybackControllerMock.js b/test/unit/mocks/PlaybackControllerMock.js index 60393c343e..7d521f3064 100644 --- a/test/unit/mocks/PlaybackControllerMock.js +++ b/test/unit/mocks/PlaybackControllerMock.js @@ -9,7 +9,7 @@ class PlaybackControllerMock { this.playing = false; this.seeking = false; this.isDynamic = false; - this.catchUpPlaybackRate = 1.05; + this.catchUpPlaybackRate = 0.05; } initialize() {} diff --git a/test/unit/streaming.MediaPlayerSpec.js b/test/unit/streaming.MediaPlayerSpec.js index 94e3c846f9..b4616c3b98 100644 --- a/test/unit/streaming.MediaPlayerSpec.js +++ b/test/unit/streaming.MediaPlayerSpec.js @@ -333,15 +333,15 @@ describe('MediaPlayer', function () { it('Method setCatchUpPlaybackRate should change catchUpPlaybackRate', function () { let rate = player.getCatchUpPlaybackRate(); - expect(rate).to.equal(1.05); + expect(rate).to.equal(0.05); - player.setCatchUpPlaybackRate(1.2); + player.setCatchUpPlaybackRate(0.2); rate = player.getCatchUpPlaybackRate(); - expect(rate).to.equal(1.2); + expect(rate).to.equal(0.2); - player.setCatchUpPlaybackRate(1); + player.setCatchUpPlaybackRate(0.0); rate = player.getCatchUpPlaybackRate(); - expect(rate).to.equal(1); + expect(rate).to.equal(0.0); }); it('Method setCatchUpPlaybackRate should throw an exception if given bad values', function () {