diff --git a/src/js/tech/ChromecastTech.js b/src/js/tech/ChromecastTech.js index 663ea3e..935b4bf 100644 --- a/src/js/tech/ChromecastTech.js +++ b/src/js/tech/ChromecastTech.js @@ -1,5 +1,7 @@ var ChromecastSessionManager = require('../chromecast/ChromecastSessionManager'), - ChromecastTechUI = require('./ChromecastTechUI'); + ChromecastTechUI = require('./ChromecastTechUI'), + Throttler = require('../throttler'); + /** * Registers the ChromecastTech Tech with Video.js. Calls {@link @@ -80,6 +82,14 @@ module.exports = function(videojs) { }; // See `currentTime` function this._initialStartTime = options.startTime || 0; + this._isScrubbing = false; + this._isSeeking = false; + + this.seekThrottler = new Throttler((time) => { + this._remotePlayer.currentTime = time; + this._remotePlayerController.seek(); + this._triggerTimeUpdateEvent(); + }); this._playSource(options.source, this._initialStartTime); this.ready(function() { @@ -243,19 +253,58 @@ module.exports = function(videojs) { * @see {@link http://docs.videojs.com/Tech.html#setCurrentTime} */ setCurrentTime(time) { - var duration = this.duration(); + const duration = this.duration(); if (time > duration || !this._remotePlayer.canSeek) { return; } - // Seeking to any place within (approximately) 1 second of the end of the item - // causes the Video.js player to get stuck in a BUFFERING state. To work around - // this, we only allow seeking to within 1 second of the end of an item. - this._remotePlayer.currentTime = Math.min(duration - 1, time); - this._remotePlayerController.seek(); + + if (this.scrubbing()) { + this._isSeeking = true; + // We need to throttle the actual seeking, because when you + // scrub, videojs does pause() -> setCurrentTime() -> play() + // and that triggers a weird bug where the chromecast stops sending + // time_changed events. + this.seekThrottler.throttle(time); + return false; + } + + // We need to delay the actual seeking, because when you + // scrub, videojs does pause() -> setCurrentTime() -> play() + // and that triggers a weird bug where the chromecast stops sending + // time_changed events. + this.player().one('play', () => { + if (this.seeking()) { + this.seekThrottler.executeRemaining(); + } else { + this._remotePlayer.currentTime = time; + this._remotePlayerController.seek(); + } + this._isSeeking = false; + }); + this._triggerTimeUpdateEvent(); } + seeking() { + return this._isSeeking; + } + + scrubbing() { + return this._isScrubbing; + } + + setScrubbing(newValue) { + if (newValue === true) { + this._isScrubbing = true; + return; + } + + if (newValue === false) { + this._isScrubbing = false; + } + } + /** * Returns the current playback time position. * @@ -274,6 +323,7 @@ module.exports = function(videojs) { if (!this._hasPlayedAnyItem) { return this._initialStartTime; } + return this._remotePlayer.currentTime; } diff --git a/src/js/throttler.js b/src/js/throttler.js new file mode 100644 index 0000000..0a8a522 --- /dev/null +++ b/src/js/throttler.js @@ -0,0 +1,26 @@ +module.exports = class Throttler { + timerId = null; + latestArgs; + + constructor(mainFunction) { + this.mainFunction = mainFunction; + } + + throttle(...args) { + this.latestArgs = args; + + if (this.timerId === null) { + this.mainFunction(...this.latestArgs); + this.timerId = setTimeout(() => { + this.timerId = null; + }, 300); + } + } + + executeRemaining() { + if (this.timerId) { + this.mainFunction(...this.latestArgs); + clearTimeout(this.timerId); + } + } +};