diff --git a/src/master-playlist-controller.js b/src/master-playlist-controller.js index a96c5d87..254623ac 100644 --- a/src/master-playlist-controller.js +++ b/src/master-playlist-controller.js @@ -1413,15 +1413,8 @@ export class MasterPlaylistController extends videojs.EventTarget { this.subtitleSegmentLoader_.abort(); } - if (!this.tech_.paused()) { - this.mainSegmentLoader_.load(); - if (this.audioPlaylistLoader_) { - this.audioSegmentLoader_.load(); - } - if (this.subtitlePlaylistLoader_) { - this.subtitleSegmentLoader_.load(); - } - } + // start segment loader loading in case they are paused + this.load(); } /** diff --git a/test/master-playlist-controller.test.js b/test/master-playlist-controller.test.js index c26eb978..9d26eea7 100644 --- a/test/master-playlist-controller.test.js +++ b/test/master-playlist-controller.test.js @@ -588,6 +588,52 @@ function(assert) { assert.equal(MPC.mediaSource.readyState, 'ended', 'Media Source ended'); }); +QUnit.test('Segment loaders are unpaused when seeking after player has ended', +function(assert) { + openMediaSource(this.player, this.clock); + + const videoMedia = '#EXTM3U\n' + + '#EXT-X-VERSION:3\n' + + '#EXT-X-PLAYLIST-TYPE:VOD\n' + + '#EXT-X-MEDIA-SEQUENCE:0\n' + + '#EXT-X-TARGETDURATION:10\n' + + '#EXTINF:10,\n' + + 'video-0.ts\n' + + '#EXT-X-ENDLIST\n'; + + let ended = 0; + + this.masterPlaylistController.mainSegmentLoader_.on('ended', () => ended++); + + this.player.tech_.trigger('play'); + + // master + this.standardXHRResponse(this.requests.shift()); + + // media + this.standardXHRResponse(this.requests.shift(), videoMedia); + + // segment + this.standardXHRResponse(this.requests.shift()); + + assert.notOk(this.masterPlaylistController.mainSegmentLoader_.paused(), + 'segment loader not yet paused'); + + this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend'); + + assert.ok(this.masterPlaylistController.mainSegmentLoader_.paused(), + 'segment loader is paused after ending'); + assert.equal(ended, 1, 'segment loader triggered ended event'); + + this.player.currentTime(5); + + this.clock.tick(1); + + assert.notOk(this.masterPlaylistController.mainSegmentLoader_.paused(), + 'segment loader unpaused after a seek'); + assert.equal(ended, 1, 'segment loader did not trigger ended event again yet'); +}); + QUnit.test('detects if the player is stuck at the playlist end', function(assert) { let playlistCopy = Hls.Playlist.playlistEnd; @@ -2096,7 +2142,7 @@ QUnit.test('subtitle segment loader resets on seeks', function(assert) { assert.equal(resetCount, 1, 'reset subtitle segment loader'); assert.equal(abortCount, 1, 'aborted subtitle segment loader'); - assert.equal(loadCount, 0, 'did not call load on subtitle segment loader'); + assert.equal(loadCount, 1, 'called load on subtitle segment loader'); this.player.play(); resetCount = 0; diff --git a/test/videojs-contrib-hls.test.js b/test/videojs-contrib-hls.test.js index 5610442d..9545bcec 100644 --- a/test/videojs-contrib-hls.test.js +++ b/test/videojs-contrib-hls.test.js @@ -2780,7 +2780,11 @@ QUnit.test('cleans up the buffer when loading VOD segments', function(assert) { this.clock.tick(1); this.player.currentTime(120); this.player.tech_.hls.mediaSource.sourceBuffers[0].trigger('updateend'); - this.clock.tick(1); + // This requires 2 clock ticks because after updateend monitorBuffer_ is called + // to setup fillBuffer on the next tick, but the seek also causes monitorBuffer_ to be + // called, which cancels the previously set timeout and sets a new one for the following + // tick. + this.clock.tick(2); this.standardXHRResponse(this.requests[3]); assert.strictEqual(this.requests[0].url, 'manifest/master.m3u8',