@dmlap quicker quality switches when bandwidth changes. Closes #285.
Showing
3 changed files
with
54 additions
and
0 deletions
... | @@ -10,6 +10,7 @@ CHANGELOG | ... | @@ -10,6 +10,7 @@ CHANGELOG |
10 | * @mikrohard: Trim whitespace in playlist. ([view](https://github.com/videojs/videojs-contrib-hls/pull/282)) | 10 | * @mikrohard: Trim whitespace in playlist. ([view](https://github.com/videojs/videojs-contrib-hls/pull/282)) |
11 | * @dmlap add a contrib option to merge PRs without squashing ([view](https://github.com/videojs/videojs-contrib-hls/pull/287)) | 11 | * @dmlap add a contrib option to merge PRs without squashing ([view](https://github.com/videojs/videojs-contrib-hls/pull/287)) |
12 | * @mikrohard allow playback of TS files with NITs. Don't warn about PCR PIDs. ([view](https://github.com/videojs/videojs-contrib-hls/pull/284)) | 12 | * @mikrohard allow playback of TS files with NITs. Don't warn about PCR PIDs. ([view](https://github.com/videojs/videojs-contrib-hls/pull/284)) |
13 | * @dmlap quicker quality switches when bandwidth changes. ([view](https://github.com/videojs/videojs-contrib-hls/pull/285)) | ||
13 | 14 | ||
14 | -------------------- | 15 | -------------------- |
15 | 16 | ... | ... |
... | @@ -315,6 +315,12 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { | ... | @@ -315,6 +315,12 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { |
315 | return 0; | 315 | return 0; |
316 | } | 316 | } |
317 | 317 | ||
318 | // it's clearly an edge-case but don't thrown an error if asked to | ||
319 | // seek within an empty playlist | ||
320 | if (!this.playlists.media().segments) { | ||
321 | return 0; | ||
322 | } | ||
323 | |||
318 | // save the seek target so currentTime can report it correctly | 324 | // save the seek target so currentTime can report it correctly |
319 | // while the seek is pending | 325 | // while the seek is pending |
320 | this.lastSeekedTime_ = currentTime; | 326 | this.lastSeekedTime_ = currentTime; |
... | @@ -578,6 +584,11 @@ videojs.Hls.prototype.fillBuffer = function(offset) { | ... | @@ -578,6 +584,11 @@ videojs.Hls.prototype.fillBuffer = function(offset) { |
578 | return; | 584 | return; |
579 | } | 585 | } |
580 | 586 | ||
587 | // if a playlist switch is in progress, wait for it to finish | ||
588 | if (this.playlists.state === 'SWITCHING_MEDIA') { | ||
589 | return; | ||
590 | } | ||
591 | |||
581 | // if the video has finished downloading, stop trying to buffer | 592 | // if the video has finished downloading, stop trying to buffer |
582 | segment = this.playlists.media().segments[this.mediaIndex]; | 593 | segment = this.playlists.media().segments[this.mediaIndex]; |
583 | if (!segment) { | 594 | if (!segment) { | ... | ... |
... | @@ -976,6 +976,35 @@ test('only appends one segment at a time', function() { | ... | @@ -976,6 +976,35 @@ test('only appends one segment at a time', function() { |
976 | equal(appends, 0, 'did not append while updating'); | 976 | equal(appends, 0, 'did not append while updating'); |
977 | }); | 977 | }); |
978 | 978 | ||
979 | test('waits to download new segments until the media playlist is stable', function() { | ||
980 | var media; | ||
981 | player.src({ | ||
982 | src: 'manifest/master.m3u8', | ||
983 | type: 'application/vnd.apple.mpegurl' | ||
984 | }); | ||
985 | openMediaSource(player); | ||
986 | standardXHRResponse(requests.shift()); // master | ||
987 | player.hls.bandwidth = 1; // make sure we stay on the lowest variant | ||
988 | standardXHRResponse(requests.shift()); // media | ||
989 | |||
990 | // mock a playlist switch | ||
991 | media = player.hls.playlists.media(); | ||
992 | player.hls.playlists.media = function() { | ||
993 | return media; | ||
994 | }; | ||
995 | player.hls.playlists.state = 'SWITCHING_MEDIA'; | ||
996 | |||
997 | standardXHRResponse(requests.shift()); // segment 0 | ||
998 | |||
999 | equal(requests.length, 0, 'no requests outstanding'); | ||
1000 | player.hls.checkBuffer_(); | ||
1001 | equal(requests.length, 0, 'delays segment fetching'); | ||
1002 | |||
1003 | player.hls.playlists.state = 'LOADED_METADATA'; | ||
1004 | player.hls.checkBuffer_(); | ||
1005 | equal(requests.length, 1, 'resumes segment fetching'); | ||
1006 | }); | ||
1007 | |||
979 | test('cancels outstanding XHRs when seeking', function() { | 1008 | test('cancels outstanding XHRs when seeking', function() { |
980 | player.src({ | 1009 | player.src({ |
981 | src: 'manifest/media.m3u8', | 1010 | src: 'manifest/media.m3u8', |
... | @@ -1321,6 +1350,19 @@ test('segment 500 should trigger MEDIA_ERR_ABORTED', function () { | ... | @@ -1321,6 +1350,19 @@ test('segment 500 should trigger MEDIA_ERR_ABORTED', function () { |
1321 | equal(4, player.hls.error.code, 'Player error code should be set to MediaError.MEDIA_ERR_ABORTED'); | 1350 | equal(4, player.hls.error.code, 'Player error code should be set to MediaError.MEDIA_ERR_ABORTED'); |
1322 | }); | 1351 | }); |
1323 | 1352 | ||
1353 | test('seeking in an empty playlist is a non-erroring noop', function() { | ||
1354 | player.src({ | ||
1355 | src: 'manifest/empty-live.m3u8', | ||
1356 | type: 'application/vnd.apple.mpegurl' | ||
1357 | }); | ||
1358 | openMediaSource(player); | ||
1359 | |||
1360 | requests.shift().respond(200, null, '#EXTM3U\n'); | ||
1361 | |||
1362 | player.currentTime(183); | ||
1363 | equal(player.currentTime(), 0, 'remains at time zero'); | ||
1364 | }); | ||
1365 | |||
1324 | test('duration is Infinity for live playlists', function() { | 1366 | test('duration is Infinity for live playlists', function() { |
1325 | player.src({ | 1367 | player.src({ |
1326 | src: 'http://example.com/manifest/missingEndlist.m3u8', | 1368 | src: 'http://example.com/manifest/missingEndlist.m3u8', | ... | ... |
-
Please register or sign in to post a comment