123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716 |
- import videojs from 'video.js';
- import QUnit from 'qunit';
- import {
- useFakeEnvironment,
- useFakeMediaSource,
- createPlayer,
- openMediaSource,
- standardXHRResponse
- } from './test-helpers.js';
- import PlaybackWatcher from '../src/playback-watcher';
- let monitorCurrentTime_;
- QUnit.module('PlaybackWatcher', {
- beforeEach(assert) {
- this.env = useFakeEnvironment(assert);
- this.requests = this.env.requests;
- this.mse = useFakeMediaSource();
- this.clock = this.env.clock;
- this.old = {};
- // setup a player
- this.player = createPlayer();
- this.player.autoplay(true);
- },
- afterEach() {
- this.env.restore();
- this.mse.restore();
- this.player.dispose();
- }
- });
- QUnit.test('skips over gap in firefox with waiting event', function(assert) {
- let hlsGapSkipEvents = 0;
- this.player.autoplay(true);
- this.player.tech_.on('usage', (event) => {
- if (event.name === 'hls-gap-skip') {
- hlsGapSkipEvents++;
- }
- });
- // create a buffer with a gap between 10 & 20 seconds
- this.player.tech_.buffered = function() {
- return videojs.createTimeRanges([[0, 10], [20, 30]]);
- };
- // set an arbitrary source
- this.player.src({
- src: 'master.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('canplay');
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- assert.equal(hlsGapSkipEvents, 0, 'there is no skipped gap');
- // seek to 10 seconds and wait 12 seconds
- this.player.currentTime(10);
- this.player.tech_.trigger('waiting');
- this.clock.tick(12000);
- // check that player jumped the gap
- assert.equal(Math.round(this.player.currentTime()),
- 20, 'Player seeked over gap after timer');
- assert.equal(hlsGapSkipEvents, 1, 'there is one skipped gap');
- });
- QUnit.test('skips over gap in chrome without waiting event', function(assert) {
- let hlsGapSkipEvents = 0;
- this.player.autoplay(true);
- this.player.tech_.on('usage', (event) => {
- if (event.name === 'hls-gap-skip') {
- hlsGapSkipEvents++;
- }
- });
- // create a buffer with a gap between 10 & 20 seconds
- this.player.tech_.buffered = function() {
- return videojs.createTimeRanges([[0, 10], [20, 30]]);
- };
- // set an arbitrary source
- this.player.src({
- src: 'master.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('canplay');
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- assert.equal(hlsGapSkipEvents, 0, 'there is no skipped gap');
- // seek to 10 seconds & simulate chrome waiting event
- this.player.currentTime(10);
- this.clock.tick(4000);
- // checks that player doesn't seek before timer expires
- assert.equal(this.player.currentTime(), 10, 'Player doesnt seek over gap pre-timer');
- this.clock.tick(10000);
- // check that player jumped the gap
- assert.equal(Math.round(this.player.currentTime()),
- 20, 'Player seeked over gap after timer');
- assert.equal(hlsGapSkipEvents, 1, 'there is one skipped gap');
- });
- QUnit.test('skips over gap in Chrome due to video underflow', function(assert) {
- let hlsVideoUnderflowEvents = 0;
- this.player.autoplay(true);
- this.player.tech_.on('usage', (event) => {
- if (event.name === 'hls-video-underflow') {
- hlsVideoUnderflowEvents++;
- }
- });
- this.player.tech_.buffered = () => {
- return videojs.createTimeRanges([[0, 10], [10.1, 20]]);
- };
- // set an arbitrary source
- this.player.src({
- src: 'master.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- assert.equal(hlsVideoUnderflowEvents, 0, 'no video underflow event got triggered');
- this.player.currentTime(13);
- let seeks = [];
- this.player.tech_.setCurrentTime = (time) => {
- seeks.push(time);
- };
- this.player.tech_.trigger('waiting');
- assert.equal(seeks.length, 1, 'one seek');
- assert.equal(seeks[0], 13, 'player seeked to current time');
- assert.equal(hlsVideoUnderflowEvents, 1, 'triggered a video underflow event');
- });
- QUnit.test('seek to live point if we fall off the end of a live playlist',
- function(assert) {
- // set an arbitrary live source
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- this.player.currentTime(0);
- let seeks = [];
- this.player.tech_.setCurrentTime = (time) => {
- seeks.push(time);
- };
- this.player.tech_.hls.playbackWatcher_.seekable = () => {
- return videojs.createTimeRanges([[1, 45]]);
- };
- this.player.tech_.trigger('waiting');
- assert.equal(seeks.length, 1, 'one seek');
- assert.equal(seeks[0], 45, 'player seeked to live point');
- });
- QUnit.test('seeks to current time when stuck inside buffered region', function(assert) {
- // set an arbitrary live source
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('canplay');
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- this.player.currentTime(10);
- let seeks = [];
- this.player.tech_.setCurrentTime = (time) => {
- seeks.push(time);
- };
- this.player.tech_.seeking = () => false;
- this.player.tech_.buffered = () => videojs.createTimeRanges([[0, 30]]);
- this.player.tech_.seekable = () => videojs.createTimeRanges([[0, 30]]);
- this.player.tech_.paused = () => false;
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop has run through once, `lastRecordedTime` should have been recorded
- // and `consecutiveUpdates` set to 0 to begin count
- assert.equal(this.player.tech_.hls.playbackWatcher_.lastRecordedTime, 10,
- 'Playback Watcher stored current time');
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 0,
- 'consecutiveUpdates set to 0');
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop should increment consecutive updates until it is >= 5
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 1,
- 'consecutiveUpdates incremented');
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop should increment consecutive updates until it is >= 5
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 2,
- 'consecutiveUpdates incremented');
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop should increment consecutive updates until it is >= 5
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 3,
- 'consecutiveUpdates incremented');
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop should increment consecutive updates until it is >= 5
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 4,
- 'consecutiveUpdates incremented');
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop should increment consecutive updates until it is >= 5
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 5,
- 'consecutiveUpdates incremented');
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop should see consecutive updates >= 5, call `waiting_`
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 0,
- 'consecutiveUpdates reset');
- // Playback watcher seeked to currentTime in `waiting_` to correct the `unknownwaiting`
- assert.equal(seeks.length, 1, 'one seek');
- assert.equal(seeks[0], 10, 'player seeked to currentTime');
- });
- QUnit.test('does not seek to current time when stuck near edge of buffered region',
- function(assert) {
- // set an arbitrary live source
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('canplay');
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- this.player.currentTime(29.98);
- let seeks = [];
- this.player.tech_.setCurrentTime = (time) => {
- seeks.push(time);
- };
- this.player.tech_.seeking = () => false;
- this.player.tech_.buffered = () => videojs.createTimeRanges([[0, 30]]);
- this.player.tech_.seekable = () => videojs.createTimeRanges([[0, 30]]);
- this.player.tech_.paused = () => false;
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop has run through once, `lastRecordedTime` should have been recorded
- // and `consecutiveUpdates` set to 0 to begin count
- assert.equal(this.player.tech_.hls.playbackWatcher_.lastRecordedTime, 29.98,
- 'Playback Watcher stored current time');
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 0,
- 'consecutiveUpdates set to 0');
- // Playback watcher loop runs on a 250ms clock
- this.clock.tick(250);
- // Loop has run through a second time, should detect that currentTime hasn't made
- // progress while at the end of the buffer. Since the currentTime is at the end of the
- // buffer, `consecutiveUpdates` should not be incremented
- assert.equal(this.player.tech_.hls.playbackWatcher_.lastRecordedTime, 29.98,
- 'Playback Watcher stored current time');
- assert.equal(this.player.tech_.hls.playbackWatcher_.consecutiveUpdates, 0,
- 'consecutiveUpdates should still be 0');
- // no corrective seek
- assert.equal(seeks.length, 0, 'no seek');
- });
- QUnit.test('fires notifications when activated', function(assert) {
- let buffered = [[]];
- let seekable = [[]];
- let currentTime = 0;
- let hlsLiveResyncEvents = 0;
- let hlsVideoUnderflowEvents = 0;
- let playbackWatcher;
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- this.player.tech_.currentTime = function() {
- return currentTime;
- };
- this.player.tech_.buffered = function() {
- return {
- length: buffered.length,
- start(i) {
- return buffered[i][0];
- },
- end(i) {
- return buffered[i][1];
- }
- };
- };
- playbackWatcher = this.player.tech_.hls.playbackWatcher_;
- playbackWatcher.seekable = function() {
- return {
- length: seekable.length,
- start(i) {
- return seekable[i][0];
- },
- end(i) {
- return seekable[i][1];
- }
- };
- };
- this.player.tech_.on('usage', (event) => {
- if (event.name === 'hls-live-resync') {
- hlsLiveResyncEvents++;
- }
- if (event.name === 'hls-video-underflow') {
- hlsVideoUnderflowEvents++;
- }
- });
- currentTime = 19;
- seekable[0] = [20, 30];
- playbackWatcher.waiting_();
- assert.equal(hlsLiveResyncEvents, 1, 'triggered a liveresync event');
- currentTime = 12;
- seekable[0] = [0, 100];
- buffered = [[0, 9], [10, 20]];
- playbackWatcher.waiting_();
- assert.equal(hlsVideoUnderflowEvents, 1, 'triggered a videounderflow event');
- assert.equal(hlsLiveResyncEvents, 1, 'did not trigger an additional liveresync event');
- });
- QUnit.test('fixes bad seeks', function(assert) {
- // set an arbitrary live source
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- let playbackWatcher = this.player.tech_.hls.playbackWatcher_;
- let seeks = [];
- let seekable;
- let seeking;
- let currentTime;
- playbackWatcher.seekable = () => seekable;
- playbackWatcher.tech_ = {
- off: () => {},
- seeking: () => seeking,
- setCurrentTime: (time) => {
- seeks.push(time);
- },
- currentTime: () => currentTime
- };
- currentTime = 50;
- seekable = videojs.createTimeRanges([[1, 45]]);
- seeking = false;
- assert.ok(!playbackWatcher.fixesBadSeeks_(), 'does nothing when not seeking');
- assert.equal(seeks.length, 0, 'did not seek');
- seeking = true;
- assert.ok(playbackWatcher.fixesBadSeeks_(), 'acts when seek past seekable range');
- assert.equal(seeks.length, 1, 'seeked');
- assert.equal(seeks[0], 45, 'player seeked to live point');
- currentTime = 0;
- assert.ok(playbackWatcher.fixesBadSeeks_(), 'acts when seek before seekable range');
- assert.equal(seeks.length, 2, 'seeked');
- assert.equal(seeks[1], 1.1, 'player seeked to start of the live window');
- currentTime = 30;
- assert.ok(!playbackWatcher.fixesBadSeeks_(), 'does nothing when time within range');
- assert.equal(seeks.length, 2, 'did not seek');
- });
- QUnit.test('corrects seek outside of seekable', function(assert) {
- // set an arbitrary live source
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- let playbackWatcher = this.player.tech_.hls.playbackWatcher_;
- let seeks = [];
- let seekable;
- let seeking;
- let currentTime;
- playbackWatcher.seekable = () => seekable;
- playbackWatcher.tech_ = {
- off: () => {},
- seeking: () => seeking,
- setCurrentTime: (time) => {
- seeks.push(time);
- },
- currentTime: () => currentTime,
- // mocked out
- paused: () => false,
- buffered: () => videojs.createTimeRanges()
- };
- // waiting
- currentTime = 50;
- seekable = videojs.createTimeRanges([[1, 45]]);
- seeking = true;
- this.player.tech_.trigger('waiting');
- assert.equal(seeks.length, 1, 'seeked');
- assert.equal(seeks[0], 45, 'player seeked to live point');
- currentTime = 0;
- this.player.tech_.trigger('waiting');
- assert.equal(seeks.length, 2, 'seeked');
- assert.equal(seeks[1], 1.1, 'player seeked to start of the live window');
- // inside of seekable range
- currentTime = 10;
- this.player.tech_.trigger('waiting');
- assert.equal(seeks.length, 2, 'did not seek');
- currentTime = 50;
- // if we're not seeking, the case shouldn't be handled here
- seeking = false;
- this.player.tech_.trigger('waiting');
- assert.equal(seeks.length, 2, 'did not seek');
- // no check for 0 with seeking false because that should be handled by live falloff
- // checkCurrentTime
- seeking = true;
- currentTime = 50;
- playbackWatcher.checkCurrentTime_();
- assert.equal(seeks.length, 3, 'seeked');
- assert.equal(seeks[2], 45, 'player seeked to live point');
- currentTime = 0;
- playbackWatcher.checkCurrentTime_();
- assert.equal(seeks.length, 4, 'seeked');
- assert.equal(seeks[3], 1.1, 'player seeked to live point');
- currentTime = 10;
- playbackWatcher.checkCurrentTime_();
- assert.equal(seeks.length, 4, 'did not seek');
- seeking = false;
- currentTime = 50;
- playbackWatcher.checkCurrentTime_();
- assert.equal(seeks.length, 4, 'did not seek');
- currentTime = 0;
- playbackWatcher.checkCurrentTime_();
- assert.equal(seeks.length, 4, 'did not seek');
- });
- QUnit.test('calls fixesBadSeeks_ on seekablechanged', function(assert) {
- // set an arbitrary live source
- this.player.src({
- src: 'liveStart30sBefore.m3u8',
- type: 'application/vnd.apple.mpegurl'
- });
- // start playback normally
- this.player.tech_.triggerReady();
- this.clock.tick(1);
- standardXHRResponse(this.requests.shift());
- openMediaSource(this.player, this.clock);
- this.player.tech_.trigger('play');
- this.player.tech_.trigger('playing');
- this.clock.tick(1);
- let playbackWatcher = this.player.tech_.hls.playbackWatcher_;
- let fixesBadSeeks_ = 0;
- playbackWatcher.fixesBadSeeks_ = () => fixesBadSeeks_++;
- this.player.tech_.trigger('seekablechanged');
- assert.equal(fixesBadSeeks_, 1, 'fixesBadSeeks_ was called');
- });
- QUnit.module('PlaybackWatcher isolated functions', {
- beforeEach() {
- monitorCurrentTime_ = PlaybackWatcher.prototype.monitorCurrentTime_;
- PlaybackWatcher.prototype.monitorCurrentTime_ = () => {};
- this.playbackWatcher = new PlaybackWatcher({
- tech: {
- on: () => {},
- off: () => {}
- }
- });
- },
- afterEach() {
- this.playbackWatcher.dispose();
- PlaybackWatcher.prototype.monitorCurrentTime_ = monitorCurrentTime_;
- }
- });
- QUnit.test('skips gap from video underflow', function(assert) {
- assert.equal(
- this.playbackWatcher.gapFromVideoUnderflow_(videojs.createTimeRanges(), 0),
- null,
- 'returns null when buffer is empty');
- assert.equal(
- this.playbackWatcher.gapFromVideoUnderflow_(videojs.createTimeRanges([[0, 10]]), 13),
- null,
- 'returns null when there is only a previous buffer');
- assert.equal(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10], [10.1, 20]]), 15),
- null,
- 'returns null when gap is too far from current time');
- assert.equal(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10], [10.1, 20]]), 9.9),
- null,
- 'returns null when gap is after current time');
- assert.equal(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10.1], [10.2, 20]]), 12.1),
- null,
- 'returns null when time is less than or equal to 2 seconds ahead');
- assert.equal(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10], [10.1, 20]]), 14.1),
- null,
- 'returns null when time is greater than or equal to 4 seconds ahead');
- assert.deepEqual(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10], [10.1, 20]]), 12.2),
- {start: 10, end: 10.1},
- 'returns gap when gap is small and time is greater than 2 seconds ahead in a buffer');
- assert.deepEqual(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10], [10.1, 20]]), 13),
- {start: 10, end: 10.1},
- 'returns gap when gap is small and time is 3 seconds ahead in a buffer');
- assert.deepEqual(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10], [10.1, 20]]), 13.9),
- {start: 10, end: 10.1},
- 'returns gap when gap is small and time is less than 4 seconds ahead in a buffer');
- // In a case where current time is outside of the buffered range, something odd must've
- // happened, but we should still allow the player to try to continue from that spot.
- assert.deepEqual(
- this.playbackWatcher.gapFromVideoUnderflow_(
- videojs.createTimeRanges([[0, 10], [10.1, 12.9]]), 13),
- {start: 10, end: 10.1},
- 'returns gap even when current time is not in buffered range');
- });
- QUnit.test('detects live window falloff', function(assert) {
- let beforeSeekableWindow_ =
- this.playbackWatcher.beforeSeekableWindow_.bind(this.playbackWatcher);
- assert.ok(
- beforeSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 10),
- 'true if playlist live and current time before seekable');
- assert.ok(
- !beforeSeekableWindow_(videojs.createTimeRanges([]), 10),
- 'false if no seekable range');
- assert.ok(
- !beforeSeekableWindow_(videojs.createTimeRanges([[0, 10]]), -1),
- 'false if seekable range starts at 0');
- assert.ok(
- !beforeSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 11),
- 'false if current time at seekable start');
- assert.ok(
- !beforeSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 20),
- 'false if current time at seekable end');
- assert.ok(
- !beforeSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 15),
- 'false if current time within seekable range');
- assert.ok(
- !beforeSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 21),
- 'false if current time past seekable range');
- assert.ok(
- beforeSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 0),
- 'true if current time is 0 and earlier than seekable range');
- });
- QUnit.test('detects beyond seekable window', function(assert) {
- let afterSeekableWindow_ =
- this.playbackWatcher.afterSeekableWindow_.bind(this.playbackWatcher);
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 10.8),
- 'false if before seekable range');
- assert.ok(
- afterSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 20.2),
- 'true if after seekable range');
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 10.9),
- 'false if within starting seekable range buffer');
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges([[11, 20]]), 20.1),
- 'false if within ending seekable range buffer');
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges(), 10),
- 'false if no seekable range');
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges([[0, 10]]), -0.2),
- 'false if current time is negative');
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges([[0, 10]]), 5),
- 'false if within seekable range');
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges([[0, 10]]), 0),
- 'false if within seekable range');
- assert.ok(
- !afterSeekableWindow_(videojs.createTimeRanges([[0, 10]]), 10),
- 'false if within seekable range');
- });
|