From 603fae969550c69ea38a61249da905857c67b9f1 Mon Sep 17 00:00:00 2001 From: Jacob Trimble Date: Mon, 24 Aug 2015 12:56:19 -0700 Subject: [PATCH] Added disable live build option. A new build option --disable-live added to disable the ability to play live content. Issue #116 Change-Id: I35876f51bddc3689d60ff6dc1b736d74c8ed4f80 --- build/build.sh | 8 +- lib/dash/container_segment_index_source.js | 19 +- lib/dash/duration_segment_index_source.js | 4 +- lib/dash/list_segment_index_source.js | 18 +- lib/dash/timeline_segment_index_source.js | 18 +- lib/player/dash_video_source.js | 35 ++-- lib/player/stream_video_source.js | 227 +++++++++++---------- lib/util/features.js | 5 + 8 files changed, 189 insertions(+), 145 deletions(-) diff --git a/build/build.sh b/build/build.sh index edd035485d..466e3acb4c 100755 --- a/build/build.sh +++ b/build/build.sh @@ -23,6 +23,7 @@ name= arguments= function argsHelper() { local arg=$1 + local choices= shift while [[ $# -ne 0 ]]; do @@ -30,13 +31,15 @@ function argsHelper() { arguments="$arguments -D shaka.features.$2=false" return 0 fi + choices="$choices [$1]" shift 2 done if [[ -z $name ]] && [[ $arg != -* ]]; then name=$arg else - echo "Usage: build.sh [--disable-dash] [--disable-offline] [--disable-http] [name]" + # There is an extra space at the beginning of $choices + echo "Usage: build.sh$choices [name]" exit 1 # Exit here fi } @@ -44,7 +47,8 @@ function argsHelper() { while [[ $# -ne 0 ]]; do argsHelper "$1" --disable-dash "Dash" \ --disable-offline "Offline" \ - --disable-http "Http" + --disable-http "Http" \ + --disable-live "Live" shift done diff --git a/lib/dash/container_segment_index_source.js b/lib/dash/container_segment_index_source.js index 2f17c6cd8b..223873bb9d 100644 --- a/lib/dash/container_segment_index_source.js +++ b/lib/dash/container_segment_index_source.js @@ -21,6 +21,7 @@ goog.provide('shaka.dash.ContainerSegmentIndexSource'); goog.require('shaka.asserts'); goog.require('shaka.dash.LiveSegmentIndex'); +goog.require('shaka.features'); goog.require('shaka.log'); goog.require('shaka.media.ISegmentIndexSource'); goog.require('shaka.media.Mp4SegmentIndexParser'); @@ -154,13 +155,17 @@ shaka.dash.ContainerSegmentIndexSource.prototype.create = function() { return Promise.reject(error); } - var segmentIndex = this.mpd_.type == 'dynamic' ? - new shaka.dash.LiveSegmentIndex( - references, - this.mpd_, - this.period_, - this.manifestCreationTime_) : - new shaka.media.SegmentIndex(references); + var segmentIndex; + if (shaka.features.Live && this.mpd_.type == 'dynamic') { + segmentIndex = new shaka.dash.LiveSegmentIndex( + references, + this.mpd_, + this.period_, + this.manifestCreationTime_); + } else { + shaka.asserts.assert(this.mpd_.type == 'static'); + segmentIndex = new shaka.media.SegmentIndex(references); + } return Promise.resolve(segmentIndex); })); diff --git a/lib/dash/duration_segment_index_source.js b/lib/dash/duration_segment_index_source.js index fef0a4dbe0..627adc936a 100644 --- a/lib/dash/duration_segment_index_source.js +++ b/lib/dash/duration_segment_index_source.js @@ -21,6 +21,7 @@ goog.provide('shaka.dash.DurationSegmentIndexSource'); goog.require('shaka.asserts'); goog.require('shaka.dash.DynamicLiveSegmentIndex'); +goog.require('shaka.features'); goog.require('shaka.log'); goog.require('shaka.media.ISegmentIndexSource'); goog.require('shaka.media.SegmentIndex'); @@ -94,7 +95,7 @@ shaka.dash.DurationSegmentIndexSource.prototype.create = function() { return Promise.resolve(this.segmentIndex_); } - if (this.mpd_.type == 'dynamic') { + if (shaka.features.Live && this.mpd_.type == 'dynamic') { try { this.segmentIndex_ = new shaka.dash.DynamicLiveSegmentIndex( this.mpd_, this.period_, this.representation_, @@ -103,6 +104,7 @@ shaka.dash.DurationSegmentIndexSource.prototype.create = function() { return Promise.reject(exception); } } else { + shaka.asserts.assert(this.mpd_.type == 'static'); var segmentTemplate = this.representation_.segmentTemplate; var scaledSegmentDuration = segmentTemplate.segmentDuration / segmentTemplate.timescale; diff --git a/lib/dash/list_segment_index_source.js b/lib/dash/list_segment_index_source.js index 8499a5558e..7868e4ea4f 100644 --- a/lib/dash/list_segment_index_source.js +++ b/lib/dash/list_segment_index_source.js @@ -21,6 +21,7 @@ goog.provide('shaka.dash.ListSegmentIndexSource'); goog.require('shaka.asserts'); goog.require('shaka.dash.LiveSegmentIndex'); +goog.require('shaka.features'); goog.require('shaka.log'); goog.require('shaka.media.ISegmentIndexSource'); goog.require('shaka.media.SegmentIndex'); @@ -174,13 +175,16 @@ shaka.dash.ListSegmentIndexSource.prototype.create = function() { startByte, endByte))); } - this.segmentIndex_ = this.mpd_.type == 'dynamic' ? - new shaka.dash.LiveSegmentIndex( - references, - this.mpd_, - this.period_, - this.manifestCreationTime_) : - new shaka.media.SegmentIndex(references); + if (shaka.features.Live && this.mpd_.type == 'dynamic') { + this.segmentIndex_ = new shaka.dash.LiveSegmentIndex( + references, + this.mpd_, + this.period_, + this.manifestCreationTime_); + } else { + shaka.asserts.assert(this.mpd_.type == 'static'); + this.segmentIndex_ = new shaka.media.SegmentIndex(references); + } return Promise.resolve(this.segmentIndex_); }; diff --git a/lib/dash/timeline_segment_index_source.js b/lib/dash/timeline_segment_index_source.js index daa6fa0436..897a6cd556 100644 --- a/lib/dash/timeline_segment_index_source.js +++ b/lib/dash/timeline_segment_index_source.js @@ -21,6 +21,7 @@ goog.provide('shaka.dash.TimelineSegmentIndexSource'); goog.require('shaka.asserts'); goog.require('shaka.dash.LiveSegmentIndex'); +goog.require('shaka.features'); goog.require('shaka.log'); goog.require('shaka.media.ISegmentIndexSource'); goog.require('shaka.media.SegmentIndex'); @@ -137,13 +138,16 @@ shaka.dash.TimelineSegmentIndexSource.prototype.create = function() { mediaUrl)); } - this.segmentIndex_ = this.mpd_.type == 'dynamic' ? - new shaka.dash.LiveSegmentIndex( - references, - this.mpd_, - this.period_, - this.manifestCreationTime_) : - new shaka.media.SegmentIndex(references); + if (shaka.features.Live && this.mpd_.type == 'dynamic') { + this.segmentIndex_ = new shaka.dash.LiveSegmentIndex( + references, + this.mpd_, + this.period_, + this.manifestCreationTime_); + } else { + shaka.asserts.assert(this.mpd_.type == 'static'); + this.segmentIndex_ = new shaka.media.SegmentIndex(references); + } return Promise.resolve(this.segmentIndex_); }; diff --git a/lib/player/dash_video_source.js b/lib/player/dash_video_source.js index 11a73eecf4..1a6c29f700 100644 --- a/lib/player/dash_video_source.js +++ b/lib/player/dash_video_source.js @@ -181,6 +181,12 @@ shaka.player.DashVideoSource.prototype.load = function() { this.captionsLang_[i], this.captionsMime_[i]); } + if (!shaka.features.Live && mpd.type == 'dynamic') { + var error = new Error('Live manifest support not enabled.'); + error.type = 'stream'; + return Promise.reject(error); + } + var mpdProcessor = new shaka.dash.MpdProcessor(this.interpretContentProtection_); this.manifestInfo = mpdProcessor.process(mpd, this.networkCallback_); @@ -194,17 +200,20 @@ shaka.player.DashVideoSource.prototype.load = function() { }; -/** @override */ -shaka.player.DashVideoSource.prototype.onUpdateManifest = function(url) { - var mpdRequest = new shaka.dash.MpdRequest(url, this.mpdRequestTimeout); - return mpdRequest.send().then(shaka.util.TypedBind(this, - /** @param {!shaka.dash.mpd.Mpd} mpd */ - function(mpd) { - var mpdProcessor = - new shaka.dash.MpdProcessor(this.interpretContentProtection_); - var newManifestInfo = mpdProcessor.process(mpd, this.networkCallback_); - return Promise.resolve(newManifestInfo); - }) - ); -}; +if (shaka.features.Live) { + /** @override */ + shaka.player.DashVideoSource.prototype.onUpdateManifest = function(url) { + var mpdRequest = new shaka.dash.MpdRequest(url, this.mpdRequestTimeout); + return mpdRequest.send().then(shaka.util.TypedBind(this, + /** @param {!shaka.dash.mpd.Mpd} mpd */ + function(mpd) { + var mpdProcessor = + new shaka.dash.MpdProcessor(this.interpretContentProtection_); + var newManifestInfo = + mpdProcessor.process(mpd, this.networkCallback_); + return Promise.resolve(newManifestInfo); + }) + ); + }; +} diff --git a/lib/player/stream_video_source.js b/lib/player/stream_video_source.js index 85228f619d..a8ccede360 100644 --- a/lib/player/stream_video_source.js +++ b/lib/player/stream_video_source.js @@ -19,6 +19,7 @@ goog.provide('shaka.player.StreamVideoSource'); goog.require('shaka.asserts'); +goog.require('shaka.features'); goog.require('shaka.log'); goog.require('shaka.media.IAbrManager'); goog.require('shaka.media.IStream'); @@ -341,6 +342,12 @@ shaka.player.StreamVideoSource.prototype.load = function() { return Promise.reject(error); } + if (!shaka.features.Live && this.manifestInfo.live) { + var error = new Error('Live manifest support not enabled.'); + error.type = 'stream'; + return Promise.reject(error); + } + var periodInfos = this.manifestInfo.periodInfos; (new shaka.media.StreamInfoProcessor()).process(periodInfos); @@ -366,103 +373,105 @@ shaka.player.StreamVideoSource.prototype.load = function() { }; -/** - * Updates the manifest. - * - * @private - */ -shaka.player.StreamVideoSource.prototype.onUpdateManifest_ = function() { - shaka.asserts.assert(this.loaded_); - shaka.asserts.assert(this.manifestInfo.updatePeriod != null); - shaka.asserts.assert(this.manifestInfo.updateUrl != null); - - shaka.log.info('Updating manifest...'); - - var startTime = Date.now(); - this.updateTimer_ = null; +if (shaka.features.Live) { + /** + * Updates the manifest. + * + * @private + */ + shaka.player.StreamVideoSource.prototype.onUpdateManifest_ = function() { + shaka.asserts.assert(this.loaded_); + shaka.asserts.assert(this.manifestInfo.updatePeriod != null); + shaka.asserts.assert(this.manifestInfo.updateUrl != null); - /** @type {shaka.media.ManifestUpdater} */ - var updater = null; - - var url = /** @type {!shaka.util.FailoverUri} */ - (this.manifestInfo.updateUrl); - this.onUpdateManifest(url).then(shaka.util.TypedBind(this, - /** @param {!shaka.media.ManifestInfo} newManifestInfo */ - function(newManifestInfo) { - updater = new shaka.media.ManifestUpdater(newManifestInfo); - return updater.update( - /** @type {!shaka.media.ManifestInfo} */ (this.manifestInfo)); - }) - ).then(shaka.util.TypedBind(this, - /** @param {!Array.} removedStreamInfos */ - function(removedStreamInfos) { - shaka.log.info('Manifest updated!'); - - updater.destroy(); - updater = null; - - for (var i = 0; i < removedStreamInfos.length; ++i) { - // ManifestUpdater will have already removed the StreamInfo from the - // manifest, but if the StreamInfo is currently being used then we - // need to switch to another StreamInfo. - this.removeStream_(removedStreamInfos[i]); - } + shaka.log.info('Updating manifest...'); - // Reconfigure the Streams because |minBufferTime| may have changed. - this.streamConfig_['initialStreamBufferSize'] = - this.manifestInfo.minBufferTime; - this.configureStreams_(); + var startTime = Date.now(); + this.updateTimer_ = null; - this.applyRestrictions_(); + /** @type {shaka.media.ManifestUpdater} */ + var updater = null; + + var url = /** @type {!shaka.util.FailoverUri} */ + (this.manifestInfo.updateUrl); + this.onUpdateManifest(url).then(shaka.util.TypedBind(this, + /** @param {!shaka.media.ManifestInfo} newManifestInfo */ + function(newManifestInfo) { + updater = new shaka.media.ManifestUpdater(newManifestInfo); + return updater.update( + /** @type {!shaka.media.ManifestInfo} */ (this.manifestInfo)); + }) + ).then(shaka.util.TypedBind(this, + /** @param {!Array.} removedStreamInfos */ + function(removedStreamInfos) { + shaka.log.info('Manifest updated!'); - if (shaka.util.MapUtils.empty(this.streamsByType_)) { - // createAndStartStreams_() failed the first time it was called. - // When createAndStartStreams_() succeeds then beginPlayback_() - // will call onUpdateManifest_(). - this.createAndStartStreams_(); - } else { - // Ensure the next update occurs within |manifestInfo.updatePeriod| - // seconds by taking into account the time it took to update the - // manifest. - var endTime = Date.now(); - this.setUpdateTimer_((endTime - startTime) / 1000.0); - } - }) - ).catch(shaka.util.TypedBind(this, - /** @param {*} error */ - function(error) { - if (updater) { updater.destroy(); updater = null; - } - if (error.type != 'aborted') { - var event = shaka.util.FakeEvent.createErrorEvent(error); - this.dispatchEvent(event); + for (var i = 0; i < removedStreamInfos.length; ++i) { + // ManifestUpdater will have already removed the StreamInfo from the + // manifest, but if the StreamInfo is currently being used then we + // need to switch to another StreamInfo. + this.removeStream_(removedStreamInfos[i]); + } - // Try updating again, but ensure we haven't been destroyed. - if (this.manifestInfo) { - this.setUpdateTimer_(0); + // Reconfigure the Streams because |minBufferTime| may have changed. + this.streamConfig_['initialStreamBufferSize'] = + this.manifestInfo.minBufferTime; + this.configureStreams_(); + + this.applyRestrictions_(); + + if (shaka.util.MapUtils.empty(this.streamsByType_)) { + // createAndStartStreams_() failed the first time it was called. + // When createAndStartStreams_() succeeds then beginPlayback_() + // will call onUpdateManifest_(). + this.createAndStartStreams_(); + } else { + // Ensure the next update occurs within |manifestInfo.updatePeriod| + // seconds by taking into account the time it took to update the + // manifest. + var endTime = Date.now(); + this.setUpdateTimer_((endTime - startTime) / 1000.0); + } + }) + ).catch(shaka.util.TypedBind(this, + /** @param {*} error */ + function(error) { + if (updater) { + updater.destroy(); + updater = null; } - } - }) - ); -}; + if (error.type != 'aborted') { + var event = shaka.util.FakeEvent.createErrorEvent(error); + this.dispatchEvent(event); -/** - * Update manifest hook. The caller takes ownership of the returned manifest. - * - * @param {!shaka.util.FailoverUri} url - * @return {!Promise.} - * @protected - */ -shaka.player.StreamVideoSource.prototype.onUpdateManifest = function(url) { - shaka.asserts.notImplemented(); - var error = 'Cannot update manifest with this VideoSource implementation.'; - error.type = 'stream'; - return Promise.reject(error); -}; + // Try updating again, but ensure we haven't been destroyed. + if (this.manifestInfo) { + this.setUpdateTimer_(0); + } + } + }) + ); + }; + + + /** + * Update manifest hook. The caller takes ownership of the returned manifest. + * + * @param {!shaka.util.FailoverUri} url + * @return {!Promise.} + * @protected + */ + shaka.player.StreamVideoSource.prototype.onUpdateManifest = function(url) { + shaka.asserts.notImplemented(); + var error = 'Cannot update manifest with this VideoSource implementation.'; + error.type = 'stream'; + return Promise.reject(error); + }; +} /** @@ -1493,7 +1502,7 @@ shaka.player.StreamVideoSource.prototype.beginPlayback_ = function( // or after playback begins. this.video.playbackRate = this.originalPlaybackRate_; - if (this.manifestInfo.updatePeriod != null) { + if (this.manifestInfo.live && this.manifestInfo.updatePeriod != null) { // Ensure the next update occurs within |manifestInfo.updatePeriod| seconds // by taking into account the time it took to start the streams. shaka.asserts.assert(this.updateTimer_ == null); @@ -1882,29 +1891,31 @@ shaka.player.StreamVideoSource.prototype.computeStreamLimits_ = function( }; -/** - * Sets the update timer. Does nothing if the manifest does not specify - * an update period. - * - * @param {number} offset An offset, in seconds, to apply to the manifest's - * update period. - * @private - */ -shaka.player.StreamVideoSource.prototype.setUpdateTimer_ = function(offset) { - if (this.manifestInfo.updatePeriod == null) { - return; - } - shaka.asserts.assert(this.updateTimer_ == null); +if (shaka.features.Live) { + /** + * Sets the update timer. Does nothing if the manifest does not specify + * an update period. + * + * @param {number} offset An offset, in seconds, to apply to the manifest's + * update period. + * @private + */ + shaka.player.StreamVideoSource.prototype.setUpdateTimer_ = function(offset) { + if (this.manifestInfo.updatePeriod == null) { + return; + } + shaka.asserts.assert(this.updateTimer_ == null); - var updatePeriod = - Math.max(this.manifestInfo.updatePeriod, - shaka.player.StreamVideoSource.MIN_UPDATE_PERIOD_); - var updateInterval = Math.max(updatePeriod - offset, 0); - shaka.log.debug('updateInterval', updateInterval); + var updatePeriod = + Math.max(this.manifestInfo.updatePeriod, + shaka.player.StreamVideoSource.MIN_UPDATE_PERIOD_); + var updateInterval = Math.max(updatePeriod - offset, 0); + shaka.log.debug('updateInterval', updateInterval); - var callback = this.onUpdateManifest_.bind(this); - this.updateTimer_ = window.setTimeout(callback, 1000 * updateInterval); -}; + var callback = this.onUpdateManifest_.bind(this); + this.updateTimer_ = window.setTimeout(callback, 1000 * updateInterval); + }; +} /** diff --git a/lib/util/features.js b/lib/util/features.js index 4d48ab0a02..6fba008f27 100644 --- a/lib/util/features.js +++ b/lib/util/features.js @@ -42,3 +42,8 @@ goog.define('shaka.features.Offline', true); */ goog.define('shaka.features.Http', true); + +/** + * @define {boolean} true to enable Live sources, false otherwise. + */ +goog.define('shaka.features.Live', true);