Browse Source

fix: stutter after fast quality change in IE/Edge (#213)

pull/237/merge
Alex Barstow 7 years ago
committed by Joe Forbes
parent
commit
2c0d9b2455
  1. 20
      src/master-playlist-controller.js
  2. 115
      test/master-playlist-controller.test.js

20
src/master-playlist-controller.js

@ -530,14 +530,20 @@ export class MasterPlaylistController extends videojs.EventTarget {
this.masterPlaylistLoader_.media(media);
// delete all buffered data to allow an immediate quality switch, then seek
// in place to give the browser a kick to remove any cached frames from the
// previous rendition
// Delete all buffered data to allow an immediate quality switch, then seek to give
// the browser a kick to remove any cached frames from the previous rendtion (.04 seconds
// ahead is roughly the minimum that will accomplish this across a variety of content
// in IE and Edge, but seeking in place is sufficient on all other browsers)
// Edge/IE bug: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14600375/
// Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=651904
this.mainSegmentLoader_.resetEverything(() => {
// Since this is not a typical seek, we avoid the seekTo method which can cause
// segments from the previously enabled rendition to load before the new playlist
// has finished loading
this.tech_.setCurrentTime(this.tech_.currentTime());
// Since this is not a typical seek, we avoid the seekTo method which can cause segments
// from the previously enabled rendition to load before the new playlist has finished loading
if (videojs.browser.IE_VERSION || videojs.browser.IS_EDGE) {
this.tech_.setCurrentTime(this.tech_.currentTime() + 0.04);
} else {
this.tech_.setCurrentTime(this.tech_.currentTime());
}
});
// don't need to reset audio as it is reset when media changes

115
test/master-playlist-controller.test.js

@ -375,6 +375,121 @@ QUnit.test('resets everything for a fast quality change', function(assert) {
assert.deepEqual(removeFuncArgs, {start: 0, end: 60}, 'remove() called with correct arguments if media is changed');
});
QUnit.test('seeks in place for fast quality switch on non-IE/Edge browsers', function(assert) {
let seeks = 0;
this.masterPlaylistController.mediaSource.trigger('sourceopen');
// master
this.standardXHRResponse(this.requests.shift());
// media
this.standardXHRResponse(this.requests.shift());
// segment
this.standardXHRResponse(this.requests.shift());
// trigger updateend to indicate the end of the append operation
this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend');
// media is changed
this.masterPlaylistController.selectPlaylist = () => {
return this.masterPlaylistController.master().playlists[0];
};
this.player.tech_.on('seeking', function() {
seeks++;
});
const timeBeforeSwitch = this.player.currentTime();
this.masterPlaylistController.fastQualityChange_();
// trigger updateend to indicate the end of the remove operation
this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend');
this.clock.tick(1);
assert.equal(this.player.currentTime(), timeBeforeSwitch, 'current time remains the same on fast quality switch');
assert.equal(seeks, 1, 'seek event occurs on fast quality switch');
});
QUnit.test('seeks forward 0.04 sec for fast quality switch on Edge', function(assert) {
let oldIEVersion = videojs.browser.IE_VERSION;
let oldIsEdge = videojs.browser.IS_EDGE;
let seeks = 0;
this.masterPlaylistController.mediaSource.trigger('sourceopen');
// master
this.standardXHRResponse(this.requests.shift());
// media
this.standardXHRResponse(this.requests.shift());
// segment
this.standardXHRResponse(this.requests.shift());
// trigger updateend to indicate the end of the append operation
this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend');
// media is changed
this.masterPlaylistController.selectPlaylist = () => {
return this.masterPlaylistController.master().playlists[0];
};
this.player.tech_.on('seeking', function() {
seeks++;
});
const timeBeforeSwitch = this.player.currentTime();
videojs.browser.IE_VERSION = null;
videojs.browser.IS_EDGE = true;
this.masterPlaylistController.fastQualityChange_();
// trigger updateend to indicate the end of the remove operation
this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend');
this.clock.tick(1);
assert.equal(this.player.currentTime(), timeBeforeSwitch + 0.04, 'seeks forward on fast quality switch');
assert.equal(seeks, 1, 'seek event occurs on fast quality switch');
videojs.browser.IE_VERSION = oldIEVersion;
videojs.browser.IS_EDGE = oldIsEdge;
});
QUnit.test('seeks forward 0.04 sec for fast quality switch on IE', function(assert) {
let oldIEVersion = videojs.browser.IE_VERSION;
let oldIsEdge = videojs.browser.IS_EDGE;
let seeks = 0;
this.masterPlaylistController.mediaSource.trigger('sourceopen');
// master
this.standardXHRResponse(this.requests.shift());
// media
this.standardXHRResponse(this.requests.shift());
// segment
this.standardXHRResponse(this.requests.shift());
// trigger updateend to indicate the end of the append operation
this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend');
// media is changed
this.masterPlaylistController.selectPlaylist = () => {
return this.masterPlaylistController.master().playlists[0];
};
this.player.tech_.on('seeking', function() {
seeks++;
});
const timeBeforeSwitch = this.player.currentTime();
videojs.browser.IE_VERSION = 11;
videojs.browser.IS_EDGE = false;
this.masterPlaylistController.fastQualityChange_();
// trigger updateend to indicate the end of the remove operation
this.masterPlaylistController.mediaSource.sourceBuffers[0].trigger('updateend');
this.clock.tick(1);
assert.equal(this.player.currentTime(), timeBeforeSwitch + 0.04, 'seeks forward on fast quality switch');
assert.equal(seeks, 1, 'seek event occurs on fast quality switch');
videojs.browser.IE_VERSION = oldIEVersion;
videojs.browser.IS_EDGE = oldIsEdge;
});
QUnit.test('audio segment loader is reset on audio track change', function(assert) {
this.requests.length = 0;
this.player = createPlayer();

Loading…
Cancel
Save