Browse Source
Immediately reload the source when an error is emitted by the player (#902)
Immediately reload the source when an error is emitted by the player (#902)
* Immediately reload the source when an error is emitted by the player * Fixed linting opinions * Updated pluging to use the Tech for currentSourcepull/6/head

committed by
David LaPalomento

4 changed files with 142 additions and 1 deletions
-
34src/reload-source-on-error.js
-
2src/videojs-contrib-hls.js
-
105test/reload-source-on-error.test.js
-
2test/test-helpers.js
@ -0,0 +1,34 @@ |
|||||
|
/** |
||||
|
* Reload the source when an error is detected as long as there |
||||
|
* wasn't an error previously within the last 30 seconds |
||||
|
*/ |
||||
|
const reloadSourceOnError = function() { |
||||
|
const player = this; |
||||
|
let lastCalled = 0; |
||||
|
const reloadSource = function() { |
||||
|
let tech = player.tech({ IWillNotUseThisInPlugins: true }); |
||||
|
let sourceObj = tech.currentSource_; |
||||
|
let seekTo = (player.duration() !== Infinity && player.currentTime()) || 0; |
||||
|
|
||||
|
if (Date.now() - lastCalled < 30 * 1000) { |
||||
|
return; |
||||
|
} |
||||
|
lastCalled = Date.now(); |
||||
|
|
||||
|
if (seekTo) { |
||||
|
player.one('loadedmetadata', () => { |
||||
|
player.currentTime(seekTo); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
player.src(sourceObj); |
||||
|
player.play(); |
||||
|
}; |
||||
|
|
||||
|
player.on('error', reloadSource); |
||||
|
player.on('dispose', () => { |
||||
|
player.off('error', reloadSource); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
export default reloadSourceOnError; |
@ -0,0 +1,105 @@ |
|||||
|
import QUnit from 'qunit'; |
||||
|
import videojs from 'video.js'; |
||||
|
import sinon from 'sinon'; |
||||
|
import reloadSourceOnError from '../src/reload-source-on-error'; |
||||
|
|
||||
|
QUnit.module('ReloadSourceOnError', { |
||||
|
beforeEach() { |
||||
|
this.clock = sinon.useFakeTimers(); |
||||
|
|
||||
|
// setup a player
|
||||
|
this.player = new videojs.EventTarget(); |
||||
|
this.player.currentValues = { |
||||
|
currentTime: 10, |
||||
|
duration: 12 |
||||
|
}; |
||||
|
|
||||
|
this.tech = { |
||||
|
currentSource_: { |
||||
|
src: 'thisisasource.m3u8', |
||||
|
type: 'doesn\'t/matter' |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
this.player.tech = () => { |
||||
|
return this.tech; |
||||
|
}; |
||||
|
|
||||
|
this.player.duration = () => { |
||||
|
return this.player.currentValues.duration; |
||||
|
}; |
||||
|
|
||||
|
this.player.src = (source) => { |
||||
|
this.player.currentValues.currentTime = 0; |
||||
|
this.player.src.calledWith.push(source); |
||||
|
}; |
||||
|
this.player.src.calledWith = []; |
||||
|
|
||||
|
this.player.currentTime = (time) => { |
||||
|
if (time) { |
||||
|
this.player.currentTime.calledWith.push(time); |
||||
|
this.player.currentValues.currentTime = time; |
||||
|
} |
||||
|
return this.player.currentValues.currentTime; |
||||
|
}; |
||||
|
this.player.currentTime.calledWith = []; |
||||
|
|
||||
|
this.player.play = () => { |
||||
|
this.player.play.called++; |
||||
|
}; |
||||
|
this.player.play.called = 0; |
||||
|
|
||||
|
reloadSourceOnError.call(this.player); |
||||
|
this.clock.tick(60 * 1000); |
||||
|
}, |
||||
|
|
||||
|
afterEach() { |
||||
|
this.clock.restore(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
QUnit.test('triggers on player error', function() { |
||||
|
this.player.trigger('error', -2); |
||||
|
|
||||
|
QUnit.equal(this.player.src.calledWith.length, 1, 'player.src was called'); |
||||
|
QUnit.deepEqual(this.player.src.calledWith[0], this.tech.currentSource_, 'player.src was called with player.currentSource'); |
||||
|
}); |
||||
|
|
||||
|
QUnit.test('seeks to currentTime in VOD', function() { |
||||
|
this.player.trigger('error', -2); |
||||
|
this.player.trigger('loadedmetadata'); |
||||
|
|
||||
|
QUnit.equal(this.player.currentTime.calledWith.length, 1, 'player.currentTime was called'); |
||||
|
QUnit.deepEqual(this.player.currentTime.calledWith[0], 10, 'player.currentTime was called with the right value'); |
||||
|
}); |
||||
|
|
||||
|
QUnit.test('doesn\'t seek to currentTime in live', function() { |
||||
|
this.player.currentValues.duration = Infinity; |
||||
|
|
||||
|
this.player.trigger('error', -2); |
||||
|
this.player.trigger('loadedmetadata'); |
||||
|
|
||||
|
QUnit.equal(this.player.currentTime.calledWith.length, 0, 'player.currentTime was not called'); |
||||
|
QUnit.deepEqual(this.player.currentTime(), 0, 'player.currentTime is still zero'); |
||||
|
}); |
||||
|
|
||||
|
QUnit.test('only allows a retry once every 30 seconds', function() { |
||||
|
this.player.trigger('error', -2); |
||||
|
this.player.trigger('loadedmetadata'); |
||||
|
|
||||
|
QUnit.equal(this.player.src.calledWith.length, 1, 'player.src was called once'); |
||||
|
|
||||
|
// Advance 60 seconds
|
||||
|
this.clock.tick(60 * 1000); |
||||
|
this.player.trigger('error', -2); |
||||
|
this.player.trigger('loadedmetadata'); |
||||
|
|
||||
|
QUnit.equal(this.player.src.calledWith.length, 2, 'player.src was called twice'); |
||||
|
|
||||
|
// Advance 29 seconds
|
||||
|
this.clock.tick(29 * 1000); |
||||
|
this.player.trigger('error', -2); |
||||
|
this.player.trigger('loadedmetadata'); |
||||
|
|
||||
|
QUnit.equal(this.player.src.calledWith.length, 2, 'player.src was called twice'); |
||||
|
}); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue