From fa931883f72ef35d93d8655432b38f3fc2a9d366 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 8 Apr 2015 15:51:42 -0700 Subject: [PATCH] Minor clean-up in Stream. Use Stream.BUFFER_SIZE_SECONDS_ on startup. Improved the way adaptation latency is measured. Avoid calling abort() twice during adaptation. Reduce the size of the Promise chain slightly. Merge the SPLICING state into SWITCHING. Change-Id: Ie06e6c56df4df17e7acb379d0e19f639f791c99b --- lib/debug/timer.js | 20 ++++++++++++--- lib/media/stream.js | 62 ++++++++++++++++++--------------------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/debug/timer.js b/lib/debug/timer.js index 6c222efe1..12cc85914 100644 --- a/lib/debug/timer.js +++ b/lib/debug/timer.js @@ -60,15 +60,16 @@ shaka.timer.end = function(name) { /** - * Log (debug) the diff between two completed timers and return it. - * Does nothing if either timer has not begun. + * Log (debug) the diff between two or more completed timers and return it. + * Does nothing if not all of the timers have begun. * * @param {string} name1 * @param {string} name2 - * @return {number} The diff between the two, or NaN if they are not both + * @param {...string} var_args + * @return {number} The diff between the timers, or NaN if they have not all * completed. */ -shaka.timer.diff = function(name1, name2) { +shaka.timer.diff = function(name1, name2, var_args) { var t1 = shaka.timer.get(name1); var t2 = shaka.timer.get(name2); if (!t1 || !t2) { @@ -76,6 +77,17 @@ shaka.timer.diff = function(name1, name2) { } var diff = t1 - t2; var name = name1 + ' - ' + name2; + + for (var i = 2; i < arguments.length; ++i) { + var name3 = arguments[i]; + var t3 = shaka.timer.get(name3); + if (!t3) { + return NaN; + } + diff -= t3; + name += ' - ' + name3; + } + shaka.log.debug(name + ': ' + diff.toFixed(3) + 'ms'); return diff; }; diff --git a/lib/media/stream.js b/lib/media/stream.js index 9f8ed235a..0e99e26b4 100644 --- a/lib/media/stream.js +++ b/lib/media/stream.js @@ -149,20 +149,16 @@ shaka.media.Stream.State_ = { // The stream is starting. INITIALIZING: 1, - // The stream is fetching metadata for the new StreamInfo and is still + // The stream is fetching metadata for the new StreamInfo and has stopped // updating using the old StreamInfo. SWITCHING: 2, - // The stream has stopped updating using the old StreamInfo and is - // splicing in segments into the source buffer from the new StreamInfo. - SPLICING: 3, - // The stream is updating by periodically appending segments into the // source buffer. - UPDATING: 4, + UPDATING: 3, // The stream has ended. - ENDED: 5 + ENDED: 4 }; @@ -235,8 +231,11 @@ shaka.media.Stream.prototype.hasEnded = function() { /** @override */ shaka.media.Stream.prototype.start = function(streamInfo) { - shaka.asserts.assert(this.state_ == shaka.media.Stream.State_.IDLE); - if (this.state_ != shaka.media.Stream.State_.IDLE) { + // Alias. + var Stream = shaka.media.Stream; + + shaka.asserts.assert(this.state_ == Stream.State_.IDLE); + if (this.state_ != Stream.State_.IDLE) { shaka.log.error('Cannot start stream: stream has already been started.'); return; } @@ -245,7 +244,7 @@ shaka.media.Stream.prototype.start = function(streamInfo) { this.streamInfo_ = streamInfo; this.type_ = streamInfo.mimeType.split('/')[0]; - this.state_ = shaka.media.Stream.State_.INITIALIZING; + this.state_ = Stream.State_.INITIALIZING; var expectedFirstTimestamp; @@ -258,9 +257,10 @@ shaka.media.Stream.prototype.start = function(streamInfo) { function() { shaka.asserts.assert(streamInfo.segmentIndex); - var initialBufferTime = streamInfo.minBufferTime; + var bufferTime = Math.max(streamInfo.minBufferTime, + Stream.BUFFER_SIZE_SECONDS_); var segmentRange = streamInfo.segmentIndex.getRangeForInterval( - this.video_.currentTime, initialBufferTime); + this.video_.currentTime, bufferTime); if (!segmentRange) { return Promise.reject(new Error('No segments available.')); } @@ -278,7 +278,7 @@ shaka.media.Stream.prototype.start = function(streamInfo) { shaka.asserts.assert(actualFirstTimestamp != null); var timestampCorrection = actualFirstTimestamp - expectedFirstTimestamp; - this.state_ = shaka.media.Stream.State_.UPDATING; + this.state_ = Stream.State_.UPDATING; // Dispatch StartedEvent. var event = shaka.util.FakeEvent.create({ @@ -294,7 +294,7 @@ shaka.media.Stream.prototype.start = function(streamInfo) { /** @param {!Error} error */ function(error) { if (error.type != 'aborted') { - this.state_ = shaka.media.Stream.State_.IDLE; + this.state_ = Stream.State_.IDLE; var event = shaka.util.FakeEvent.createErrorEvent(error); this.dispatchEvent(event); } @@ -321,8 +321,7 @@ shaka.media.Stream.prototype.switch = function(streamInfo, immediate) { // We cannot switch streams if we are initializing or already switching // streams. if (this.state_ == Stream.State_.INITIALIZING || - this.state_ == Stream.State_.SWITCHING || - this.state_ == Stream.State_.SPLICING) { + this.state_ == Stream.State_.SWITCHING) { shaka.log.info('Waiting to switch streams...'); this.nextSwitch_ = this.switch.bind(this, streamInfo, immediate); return; @@ -343,7 +342,7 @@ shaka.media.Stream.prototype.switch = function(streamInfo, immediate) { var check = (function(video) { if (video.videoHeight == streamInfo.height) { shaka.timer.end('switch'); - shaka.timer.diff('switch', 'switch logic'); + shaka.timer.diff('switch', 'switch logic', 'switch fetch'); } else { window.setTimeout(check, 50); } @@ -353,18 +352,17 @@ shaka.media.Stream.prototype.switch = function(streamInfo, immediate) { this.state_ = Stream.State_.SWITCHING; + this.cancelUpdateTimer_(); var async = [ streamInfo.getSegmentIndex(), - streamInfo.getSegmentInitializationData() + streamInfo.getSegmentInitializationData(), + this.sbm_.abort() ]; - // If it's an immediate switch, pause the video and cancel updates until the - // switch is complete. + // If it's an immediate switch, pause the video until the switch is complete. var previouslyPaused = this.video_.paused; if (immediate) { this.video_.pause(); - this.cancelUpdateTimer_(); - async.push(this.sbm_.abort()); } Promise.all(async).then(shaka.util.TypedBind(this, @@ -373,17 +371,8 @@ shaka.media.Stream.prototype.switch = function(streamInfo, immediate) { this.streamInfo_ = streamInfo; this.type_ = streamInfo.mimeType.split('/')[0]; - this.state_ = Stream.State_.SPLICING; - this.sbm_.reset(); - // Stop updating and abort |sbm_|'s current operation. This will reject - // |sbm_|'s current promise. - this.cancelUpdateTimer_(); - return this.sbm_.abort(); - }) - ).then(shaka.util.TypedBind(this, - function() { var bufferTime = Math.max(streamInfo.minBufferTime, Stream.BUFFER_SIZE_SECONDS_); // Fetch new segments to meet the buffering requirement and replace @@ -395,11 +384,14 @@ shaka.media.Stream.prototype.switch = function(streamInfo, immediate) { } shaka.log.v1('Fetching segment range', this.type_, segmentRange.references); + shaka.timer.end('switch logic'); + shaka.timer.begin('switch fetch'); return this.sbm_.fetch(segmentRange, streamInfo.segmentInitializationData); }) ).then(shaka.util.TypedBind(this, function() { + shaka.timer.end('switch fetch'); if (immediate) { // Force the video to start presenting the new segment(s). this.video_.currentTime -= Stream.NUDGE_; @@ -408,8 +400,6 @@ shaka.media.Stream.prototype.switch = function(streamInfo, immediate) { } } - shaka.timer.end('switch logic'); - this.fireAdaptationEvent_(streamInfo); this.state_ = Stream.State_.UPDATING; @@ -482,8 +472,7 @@ shaka.media.Stream.prototype.resync = function() { } if (this.state_ == Stream.State_.INITIALIZING || - this.state_ == Stream.State_.SWITCHING || - this.state_ == Stream.State_.SPLICING) { + this.state_ == Stream.State_.SWITCHING) { // Since the stream is initializing or switching it will be resynchronized // after the first call to onUpdate_(). return; @@ -541,8 +530,7 @@ shaka.media.Stream.prototype.onUpdate_ = function() { shaka.asserts.assert(this.streamInfo_); shaka.asserts.assert(this.streamInfo_.segmentIndex); - shaka.asserts.assert(this.state_ == Stream.State_.SWITCHING || - this.state_ == Stream.State_.UPDATING); + shaka.asserts.assert(this.state_ == Stream.State_.UPDATING); // Avoid stacking timeouts. this.cancelUpdateTimer_();