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_();