diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 3389f696c8..57e49f396b 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -9,6 +9,7 @@ goog.provide('shaka.hls.HlsParser'); goog.require('goog.Uri'); goog.require('goog.asserts'); +goog.require('shaka.abr.Ewma'); goog.require('shaka.hls.ManifestTextParser'); goog.require('shaka.hls.Playlist'); goog.require('shaka.hls.PlaylistType'); @@ -215,6 +216,13 @@ shaka.hls.HlsParser = class { /** @private {boolean} */ this.lowLatencyByterangeOptimization_ = false; + + /** + * An ewma that tracks how long updates take. + * This is to mitigate issues caused by slow parsing on embedded devices. + * @private {!shaka.abr.Ewma} + */ + this.averageUpdateDuration_ = new shaka.abr.Ewma(5); } @@ -3679,12 +3687,20 @@ shaka.hls.HlsParser = class { } try { + const startTime = Date.now(); await this.update(); + // Keep track of how long the longest manifest update took. + const endTime = Date.now(); + // This may have converted to VOD, in which case we stop updating. if (this.isLive_()) { + const updateDuration = (endTime - startTime) / 1000.0; + this.averageUpdateDuration_.sample(1, updateDuration); const delay = this.getUpdatePlaylistDelay_(); - this.updatePlaylistTimer_.tickAfter(/* seconds= */ delay); + const finalDelay = Math.max(0, + delay - this.averageUpdateDuration_.getEstimate()); + this.updatePlaylistTimer_.tickAfter(/* seconds= */ finalDelay); } } catch (error) { // Detect a call to stop() during this.update()