From f3e6003f9d9f2da6a9f99335e373584085271912 Mon Sep 17 00:00:00 2001 From: Natalie Harris Date: Mon, 11 May 2015 14:30:31 -0700 Subject: [PATCH] Allow injection of a custom IAbrManager implementation at runtime. Closes #48. Change-Id: I8f15adb9143076626bdc616e3f3ba4f3be90324e --- app.js | 16 ++++++++++++---- lib/media/i_abr_manager.js | 4 +++- lib/media/simple_abr_manager.js | 27 ++++++++++++++++++--------- lib/player/dash_video_source.js | 11 ++++++++--- lib/player/offline_video_source.js | 11 +++++++++-- lib/player/stream_video_source.js | 7 ++++--- 6 files changed, 54 insertions(+), 22 deletions(-) diff --git a/app.js b/app.js index 71639f37c3..3eaa1fe735 100644 --- a/app.js +++ b/app.js @@ -392,7 +392,9 @@ app.deleteStream = function() { console.assert(app.estimator_); var estimator = /** @type {!shaka.util.IBandwidthEstimator} */( app.estimator_); - var offlineSource = new shaka.player.OfflineVideoSource(groupId, estimator); + var abrManager = new shaka.media.SimpleAbrManager(); + var offlineSource = new shaka.player.OfflineVideoSource( + groupId, estimator, abrManager); offlineSource.deleteGroup().then( function() { var deleted = app.offlineStreams_.indexOf(text); @@ -430,7 +432,9 @@ app.storeStream = function() { console.assert(app.estimator_); var estimator = /** @type {!shaka.util.IBandwidthEstimator} */( app.estimator_); - var offlineSource = new shaka.player.OfflineVideoSource(null, estimator); + var abrManager = new shaka.media.SimpleAbrManager(); + var offlineSource = new shaka.player.OfflineVideoSource( + null, estimator, abrManager); offlineSource.addEventListener('progress', app.progressEventHandler_); offlineSource.store( mediaUrl, preferredLanguage, app.interpretContentProtection_, @@ -607,11 +611,13 @@ app.loadDashStream = function() { var estimator = /** @type {!shaka.util.IBandwidthEstimator} */( app.estimator_); + var abrManager = new shaka.media.SimpleAbrManager(); app.load_( new shaka.player.DashVideoSource( mediaUrl, app.interpretContentProtection_, - estimator)); + estimator, + abrManager)); }; @@ -628,7 +634,9 @@ app.loadOfflineStream = function() { console.assert(app.estimator_); var estimator = /** @type {!shaka.util.IBandwidthEstimator} */( app.estimator_); - app.load_(new shaka.player.OfflineVideoSource(groupId, estimator)); + var abrManager = new shaka.media.SimpleAbrManager(); + app.load_(new shaka.player.OfflineVideoSource( + groupId, estimator, abrManager)); }; diff --git a/lib/media/i_abr_manager.js b/lib/media/i_abr_manager.js index b0d7d52d61..fe1c4256bd 100755 --- a/lib/media/i_abr_manager.js +++ b/lib/media/i_abr_manager.js @@ -46,9 +46,11 @@ shaka.media.IAbrManager.prototype.destroy = function() {}; /** * Starts the AbrManager. * + * @param {!shaka.util.IBandwidthEstimator} estimator + * @param {!shaka.player.IVideoSource} videoSource * @expose */ -shaka.media.IAbrManager.prototype.start = function() {}; +shaka.media.IAbrManager.prototype.start = function(estimator, videoSource) {}; /** diff --git a/lib/media/simple_abr_manager.js b/lib/media/simple_abr_manager.js index 963862359a..6ada8426ba 100644 --- a/lib/media/simple_abr_manager.js +++ b/lib/media/simple_abr_manager.js @@ -18,6 +18,7 @@ goog.provide('shaka.media.SimpleAbrManager'); +goog.require('shaka.asserts'); goog.require('shaka.log'); goog.require('shaka.media.IAbrManager'); goog.require('shaka.player.AudioTrack'); @@ -32,19 +33,17 @@ goog.require('shaka.util.IBandwidthEstimator'); * Creates a SimpleAbrManager, which selects video tracks using a basic set of * heuristics. * - * @param {!shaka.util.IBandwidthEstimator} estimator - * @param {!shaka.player.IVideoSource} videoSource - * * @struct * @constructor * @implements {shaka.media.IAbrManager} + * @export */ -shaka.media.SimpleAbrManager = function(estimator, videoSource) { - /** @private {!shaka.util.IBandwidthEstimator} */ - this.estimator_ = estimator; +shaka.media.SimpleAbrManager = function() { + /** @private {shaka.util.IBandwidthEstimator} */ + this.estimator_ = null; - /** @private {!shaka.player.IVideoSource} */ - this.videoSource_ = videoSource; + /** @private {shaka.player.IVideoSource} */ + this.videoSource_ = null; /** @private {!shaka.util.EventManager} */ this.eventManager_ = new shaka.util.EventManager(); @@ -126,7 +125,13 @@ shaka.media.SimpleAbrManager.prototype.destroy = function() { /** @override */ -shaka.media.SimpleAbrManager.prototype.start = function() { +shaka.media.SimpleAbrManager.prototype.start = function(estimator, + videoSource) { + if (this.estimator_ && this.videoSource_) return; + + this.estimator_ = estimator; + this.videoSource_ = videoSource; + this.nextAdaptationTime_ = Date.now() + shaka.media.SimpleAbrManager.FIRST_SWITCH_INTERVAL_; this.eventManager_.listen(this.estimator_, 'bandwidth', @@ -144,6 +149,10 @@ shaka.media.SimpleAbrManager.prototype.enable = function(enabled) { /** @override */ shaka.media.SimpleAbrManager.prototype.getInitialVideoTrackId = function() { + shaka.asserts.assert(this.videoSource_); + shaka.asserts.assert(this.estimator_); + if (!this.videoSource_ || !this.estimator_) return null; + var chosen = this.chooseVideoTrack_(); return chosen ? chosen.id : null; }; diff --git a/lib/player/dash_video_source.js b/lib/player/dash_video_source.js index 3a510243cb..9e7fecd810 100644 --- a/lib/player/dash_video_source.js +++ b/lib/player/dash_video_source.js @@ -21,6 +21,8 @@ goog.provide('shaka.player.DashVideoSource'); goog.require('shaka.dash.MpdProcessor'); goog.require('shaka.dash.MpdRequest'); goog.require('shaka.dash.mpd'); +goog.require('shaka.media.IAbrManager'); +goog.require('shaka.media.SimpleAbrManager'); goog.require('shaka.player.DrmSchemeInfo'); goog.require('shaka.player.StreamVideoSource'); goog.require('shaka.util.EWMA'); @@ -48,6 +50,7 @@ goog.require('shaka.util.TypedBind'); * interpretContentProtection A callback to interpret the ContentProtection * elements in the MPD. * @param {shaka.util.IBandwidthEstimator} estimator + * @param {shaka.media.IAbrManager} abrManager * * @fires shaka.player.DashVideoSource.SeekRangeChanged * @@ -57,14 +60,16 @@ goog.require('shaka.util.TypedBind'); * @export */ shaka.player.DashVideoSource = - function(mpdUrl, interpretContentProtection, estimator) { + function(mpdUrl, interpretContentProtection, estimator, abrManager) { if (!estimator) { // For backward compatibility, provide an instance of the default // implementation if none is provided. estimator = new shaka.util.EWMABandwidthEstimator(); } - - shaka.player.StreamVideoSource.call(this, null, estimator); + if (!abrManager) { + abrManager = new shaka.media.SimpleAbrManager(); + } + shaka.player.StreamVideoSource.call(this, null, estimator, abrManager); /** @private {string} */ this.mpdUrl_ = mpdUrl; diff --git a/lib/player/offline_video_source.js b/lib/player/offline_video_source.js index 0717133868..c95d54503b 100644 --- a/lib/player/offline_video_source.js +++ b/lib/player/offline_video_source.js @@ -25,6 +25,8 @@ goog.require('shaka.dash.MpdRequest'); goog.require('shaka.dash.mpd'); goog.require('shaka.log'); goog.require('shaka.media.EmeManager'); +goog.require('shaka.media.IAbrManager'); +goog.require('shaka.media.SimpleAbrManager'); goog.require('shaka.media.StreamInfo'); goog.require('shaka.player.StreamVideoSource'); goog.require('shaka.util.ContentDatabase'); @@ -39,19 +41,24 @@ goog.require('shaka.util.TypedBind'); * @param {?number} groupId The unique ID of the group of streams * in this source. * @param {shaka.util.IBandwidthEstimator} estimator + * @param {shaka.media.IAbrManager} abrManager + * * @struct * @constructor * @extends {shaka.player.StreamVideoSource} * @export */ -shaka.player.OfflineVideoSource = function(groupId, estimator) { +shaka.player.OfflineVideoSource = function(groupId, estimator, abrManager) { if (!estimator) { // For backward compatibility, provide an instance of the default // implementation if none is provided. estimator = new shaka.util.EWMABandwidthEstimator(); } + if (!abrManager) { + abrManager = new shaka.media.SimpleAbrManager(); + } - shaka.player.StreamVideoSource.call(this, null, estimator); + shaka.player.StreamVideoSource.call(this, null, estimator, abrManager); /** @private {?number} */ this.groupId_ = groupId; diff --git a/lib/player/stream_video_source.js b/lib/player/stream_video_source.js index e4c77e8af7..651f7378f5 100644 --- a/lib/player/stream_video_source.js +++ b/lib/player/stream_video_source.js @@ -49,6 +49,7 @@ goog.require('shaka.util.Task'); * @param {shaka.media.ManifestInfo} manifestInfo The ManifestInfo, which may * be modified by this VideoSource. * @param {!shaka.util.IBandwidthEstimator} estimator + * @param {!shaka.media.IAbrManager} abrManager * * @listens shaka.media.Stream.EndedEvent * @listens shaka.media.Stream.PleaseBufferEvent @@ -61,7 +62,7 @@ goog.require('shaka.util.Task'); * @extends {shaka.util.FakeEventTarget} * @export */ -shaka.player.StreamVideoSource = function(manifestInfo, estimator) { +shaka.player.StreamVideoSource = function(manifestInfo, estimator, abrManager) { shaka.util.FakeEventTarget.call(this, null); /** @protected {shaka.media.ManifestInfo} */ @@ -130,7 +131,7 @@ shaka.player.StreamVideoSource = function(manifestInfo, estimator) { this.stats_ = null; /** @private {!shaka.media.IAbrManager} */ - this.abrManager_ = new shaka.media.SimpleAbrManager(this.estimator, this); + this.abrManager_ = abrManager; }; goog.inherits(shaka.player.StreamVideoSource, shaka.util.FakeEventTarget); @@ -1010,6 +1011,7 @@ shaka.player.StreamVideoSource.prototype.createAndStartStreams_ = function() { // would cause a seek. this.originalPlaybackRate_ = this.video.playbackRate; this.video.playbackRate = 0; + this.abrManager_.start(this.estimator, this); /** @type {!Object.} */ var selectedStreamInfosByType = @@ -1038,7 +1040,6 @@ shaka.player.StreamVideoSource.prototype.createAndStartStreams_ = function() { this.startTask_.append( function() { this.startStreams_(selectedStreamInfosByType); - this.abrManager_.start(); return [Promise.resolve()]; }.bind(this));