diff --git a/README.md b/README.md index 8aa7229f2..66742f91d 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ Video.js Compatibility: 6.0, 7.0 - [customTagMappers](#customtagmappers) - [cacheEncryptionKeys](#cacheencryptionkeys) - [handlePartialData](#handlepartialdata) + - [liveRangeSafeTimeDelta](#liverangesafetimedelta) - [Runtime Properties](#runtime-properties) - [vhs.playlists.master](#vhsplaylistsmaster) - [vhs.playlists.media](#vhsplaylistsmedia) @@ -451,6 +452,11 @@ This option defaults to `false`. * Default: `false` * Use partial appends in the transmuxer and segment loader +##### liveRangeSafeTimeDelta +* Type: `number`, +* Default: [`SAFE_TIME_DELTA`](https://github.com/videojs/http-streaming/blob/e7cb63af010779108336eddb5c8fd138d6390e95/src/ranges.js#L17) +* Allow to re-define length (in seconds) of time delta when you compare current time and the end of the buffered range. + ### Runtime Properties Runtime properties are attached to the tech object when HLS is in use. You can get a reference to the VHS source handler like this: diff --git a/src/playback-watcher.js b/src/playback-watcher.js index 6ebb7ed55..33cac2552 100644 --- a/src/playback-watcher.js +++ b/src/playback-watcher.js @@ -75,6 +75,7 @@ export default class PlaybackWatcher { this.tech_ = options.tech; this.seekable = options.seekable; this.allowSeeksWithinUnsafeLiveWindow = options.allowSeeksWithinUnsafeLiveWindow; + this.liveRangeSafeTimeDelta = options.liveRangeSafeTimeDelta; this.media = options.media; this.consecutiveUpdates = 0; @@ -502,7 +503,7 @@ export default class PlaybackWatcher { if (seekable.length && // can't fall before 0 and 0 seekable start identifies VOD stream seekable.start(0) > 0 && - currentTime < seekable.start(0) - Ranges.SAFE_TIME_DELTA) { + currentTime < seekable.start(0) - this.liveRangeSafeTimeDelta) { return true; } diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index e05d6e351..9ec9b12ec 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -32,6 +32,7 @@ import { } from './playlist-selectors.js'; import {isAudioCodec, isVideoCodec, browserSupportsCodec} from '@videojs/vhs-utils/dist/codecs.js'; import logger from './util/logger'; +import {SAFE_TIME_DELTA} from './ranges'; // IMPORTANT: // keep these at the bottom they are replaced at build time @@ -673,7 +674,8 @@ class VhsHandler extends Component { 'handlePartialData', 'playlistSelector', 'initialPlaylistSelector', - 'experimentalBufferBasedABR' + 'experimentalBufferBasedABR', + 'liveRangeSafeTimeDelta' ].forEach((option) => { if (typeof this.source_[option] !== 'undefined') { this.options_[option] = this.source_[option]; @@ -706,11 +708,20 @@ class VhsHandler extends Component { }; this.masterPlaylistController_ = new MasterPlaylistController(this.options_); - this.playbackWatcher_ = new PlaybackWatcher(videojs.mergeOptions(this.options_, { - seekable: () => this.seekable(), - media: () => this.masterPlaylistController_.media(), - masterPlaylistController: this.masterPlaylistController_ - })); + + const playbackWatcherOptions = videojs.mergeOptions( + { + liveRangeSafeTimeDelta: SAFE_TIME_DELTA + }, + this.options_, + { + seekable: () => this.seekable(), + media: () => this.masterPlaylistController_.media(), + masterPlaylistController: this.masterPlaylistController_ + } + ); + + this.playbackWatcher_ = new PlaybackWatcher(playbackWatcherOptions); this.masterPlaylistController_.on('error', () => { const player = videojs.players[this.tech_.options_.playerId]; diff --git a/test/playback-watcher.test.js b/test/playback-watcher.test.js index ab127f359..2cd511419 100644 --- a/test/playback-watcher.test.js +++ b/test/playback-watcher.test.js @@ -13,6 +13,7 @@ import { } from '../src/playback-watcher'; // needed for plugin registration import '../src/videojs-http-streaming'; +import { SAFE_TIME_DELTA } from '../src/ranges'; let monitorCurrentTime_; @@ -1184,6 +1185,8 @@ QUnit.test('skips gap from muxed video underflow', function(assert) { }); QUnit.test('detects live window falloff', function(assert) { + this.playbackWatcher.liveRangeSafeTimeDelta = SAFE_TIME_DELTA; + const beforeSeekableWindow_ = this.playbackWatcher.beforeSeekableWindow_.bind(this.playbackWatcher); @@ -1222,6 +1225,23 @@ QUnit.test('detects live window falloff', function(assert) { ); }); +QUnit.test('respects liveRangeSafeTimeDelta flag', function(assert) { + this.playbackWatcher.liveRangeSafeTimeDelta = 1; + + const beforeSeekableWindow_ = + this.playbackWatcher.beforeSeekableWindow_.bind(this.playbackWatcher); + + assert.ok( + beforeSeekableWindow_(videojs.createTimeRanges([[12, 20]]), 10), + 'true if playlist live and current time before seekable' + ); + + assert.ok( + !beforeSeekableWindow_(videojs.createTimeRanges([]), 10), + 'false if no seekable range' + ); +}); + QUnit.test('detects beyond seekable window for VOD', function(assert) { const playlist = { endList: true,