diff --git a/lib/media/playhead.js b/lib/media/playhead.js index ea60821602..03277b84ca 100644 --- a/lib/media/playhead.js +++ b/lib/media/playhead.js @@ -18,6 +18,7 @@ goog.require('shaka.media.VideoWrapper'); goog.require('shaka.util.EventManager'); goog.require('shaka.util.IReleasable'); goog.require('shaka.util.MediaReadyState'); +goog.require('shaka.util.Platform'); goog.require('shaka.util.Timer'); goog.requireType('shaka.media.PresentationTimeline'); @@ -420,12 +421,20 @@ shaka.media.MediaSourcePlayhead = class { const gapLimit = shaka.media.GapJumpingController.BROWSER_GAP_TOLERANCE; if (Math.abs(targetTime - currentTime) > gapLimit) { - // You can only seek like this every so often. This is to prevent an - // infinite loop on systems where changing currentTime takes a significant - // amount of time (e.g. Chromecast). - const time = Date.now() / 1000; - if (!this.lastCorrectiveSeek_ || this.lastCorrectiveSeek_ < time - 1) { - this.lastCorrectiveSeek_ = time; + let canCorrectiveSeek = false; + if (shaka.util.Platform.isSeekingSlow()) { + // You can only seek like this every so often. This is to prevent an + // infinite loop on systems where changing currentTime takes a + // significant amount of time (e.g. Chromecast). + const time = Date.now() / 1000; + if (!this.lastCorrectiveSeek_ || this.lastCorrectiveSeek_ < time - 1) { + this.lastCorrectiveSeek_ = time; + canCorrectiveSeek = true; + } + } else { + canCorrectiveSeek = true; + } + if (canCorrectiveSeek) { this.videoWrapper_.setTime(targetTime); return; } diff --git a/lib/util/platform.js b/lib/util/platform.js index c713dca56c..138d1d5d30 100644 --- a/lib/util/platform.js +++ b/lib/util/platform.js @@ -645,6 +645,25 @@ shaka.util.Platform = class { return true; } + /** + * On some platforms, such as v1 Chromecasts, the act of seeking can take a + * significant amount of time. + * + * @return {boolean} + */ + static isSeekingSlow() { + const Platform = shaka.util.Platform; + if (Platform.isChromecast()) { + if (Platform.isAndroidCastDevice()) { + // Android-based Chromecasts are new enough to not be a problem. + return false; + } else { + return true; + } + } + return false; + } + /** * Returns true if MediaKeys is polyfilled * diff --git a/test/media/playhead_unit.js b/test/media/playhead_unit.js index ff2beb2867..cb8dc26a6b 100644 --- a/test/media/playhead_unit.js +++ b/test/media/playhead_unit.js @@ -593,7 +593,10 @@ describe('Playhead', () => { expect(onSeek).toHaveBeenCalled(); }); // clamps playhead after seeking for VOD - it('doesn\'t repeatedly re-seek', () => { + it('doesn\'t repeatedly re-seek in seeking slow platforms', () => { + if (!shaka.util.Platform.isSeekingSlow()) { + pending('No seeking slow platform'); + } video.readyState = HTMLMediaElement.HAVE_METADATA; video.buffered = createFakeBuffered([{start: 25, end: 55}]);