From 3e3e940e3486b867101c200de7e1bef4a4c760e3 Mon Sep 17 00:00:00 2001 From: Sandra Lokshina Date: Wed, 29 May 2019 10:15:01 -0700 Subject: [PATCH] Add a temporary fix to enable casting. Issue #1948 Change-Id: Id3953cdc32f1cdd02729c1a3f08c522b2ee376f1 --- lib/cast/cast_proxy.js | 115 +++++++++++++++++++++++++++++++++-------- lib/util/error.js | 6 +++ ui/controls.js | 2 + 3 files changed, 101 insertions(+), 22 deletions(-) diff --git a/lib/cast/cast_proxy.js b/lib/cast/cast_proxy.js index 8e7ae85c26..b9e17c7f51 100644 --- a/lib/cast/cast_proxy.js +++ b/lib/cast/cast_proxy.js @@ -79,14 +79,28 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { /** @private {shaka.util.EventManager} */ this.eventManager_ = null; - /** @private {shaka.cast.CastSender} */ - this.sender_ = new shaka.cast.CastSender( - receiverAppId, - () => this.onCastStatusChanged_(), - () => this.onFirstCastStateUpdate_(), - (targetName, event) => this.onRemoteEvent_(targetName, event), - () => this.onResumeLocal_(), - () => this.getInitState_()); + /** @private {string} */ + this.receiverAppId_ = receiverAppId; + + if (this.receiverAppId_) { + // TODO: This is temporary fix to get casting working. + // It masks the fact that we're at the moment unable to + // change the receiver id sucessfully. + // It relies on the assumption that changing one actual + // id to another is a very edgy use case (usually apps have + // only one receiver app). + // It unblocks casting in the world where UI can be configured, + // but it's hacky and must be changed to a permanent solution + // allowing to change Receiver App ID for reals. + /** @private {shaka.cast.CastSender} */ + this.sender_ = new shaka.cast.CastSender( + receiverAppId, + () => this.onCastStatusChanged_(), + () => this.onFirstCastStateUpdate_(), + (targetName, event) => this.onRemoteEvent_(targetName, event), + () => this.onResumeLocal_(), + () => this.getInitState_()); + } this.init_(); } @@ -184,6 +198,13 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @export */ async cast() { + if (!this.sender_) { + throw new shaka.util.Error( + shaka.util.Error.Severity.RECOVERABLE, + shaka.util.Error.Category.CAST, + shaka.util.Error.Code.CAST_RECEIVER_APP_ID_MISSING); + } + const initState = this.getInitState_(); // TODO: transfer manually-selected tracks? @@ -206,7 +227,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @export */ setAppData(appData) { - this.sender_.setAppData(appData); + if (this.sender_) { + this.sender_.setAppData(appData); + } } /** @@ -214,7 +237,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @export */ suggestDisconnect() { - this.sender_.showDisconnectDialog(); + if (this.sender_) { + this.sender_.showDisconnectDialog(); + } } /** @@ -222,7 +247,44 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @export */ forceDisconnect() { - this.sender_.forceDisconnect(); + if (this.sender_) { + this.sender_.forceDisconnect(); + } + } + + + /** + * @param {string} newAppId + * @export + */ + async changeReceiverId(newAppId) { + if (newAppId == this.receiverAppId_) { + // Nothing to change + return; + } + + this.receiverAppId_ = newAppId; + + // TODO: This code doesn't work correctly at the moment. Changing + // one working receiver id to another needs to be figured out. + // Destroy the old sender + if (this.sender_) { + this.sender_.forceDisconnect(); + await this.sender_.destroy(); + this.sender_ = null; + } + + + // Create the new one + this.sender_ = new shaka.cast.CastSender( + newAppId, + () => this.onCastStatusChanged_(), + () => this.onFirstCastStateUpdate_(), + (targetName, event) => this.onRemoteEvent_(targetName, event), + () => this.onResumeLocal_(), + () => this.getInitState_()); + + this.sender_.init(); } /** @@ -230,7 +292,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @private */ init_() { - this.sender_.init(); + if (this.sender_) { + this.sender_.init(); + } this.eventManager_ = new shaka.util.EventManager(); @@ -395,6 +459,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @private */ onResumeLocal_() { + goog.asserts.assert(this.sender_, + 'Cast sender should not be null!'); + // Transfer back the player state. for (const pair of shaka.cast.CastUtils.PlayerInitState) { const getter = pair[0]; @@ -484,7 +551,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { // If we are casting, but the first update has not come in yet, use local // values, but not local methods. - if (this.sender_.isCasting() && !this.sender_.hasRemoteProperties()) { + if (this.sender_ && this.sender_.isCasting() && + !this.sender_.hasRemoteProperties()) { const value = this.localVideo_[name]; if (typeof value != 'function') { return value; @@ -492,7 +560,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { } // Use local values and methods if we are not casting. - if (!this.sender_.isCasting()) { + if (!this.sender_ || !this.sender_.isCasting()) { let value = this.localVideo_[name]; if (typeof value == 'function') { value = value.bind(this.localVideo_); @@ -509,7 +577,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @private */ videoProxySet_(name, value) { - if (!this.sender_.isCasting()) { + if (!this.sender_ || !this.sender_.isCasting()) { this.localVideo_[name] = value; return; } @@ -522,7 +590,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @private */ videoProxyLocalEvent_(event) { - if (this.sender_.isCasting()) { + if (this.sender_ && this.sender_.isCasting()) { // Ignore any unexpected local events while casting. Events can still be // fired by the local video and Player when we unload() after the Cast // connection is complete. @@ -561,7 +629,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { if (name == 'getSharedConfiguration') { shaka.log.warning( 'Can\'t share configuration across a network. Returning copy.'); - return this.sender_.get('player', 'getConfiguration'); + return this.sender_ ? + this.sender_.get('player', 'getConfiguration') : + this.localPlayer_.getConfiguration(); } if (name == 'getNetworkingEngine') { @@ -574,7 +644,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { return () => this.localPlayer_.getNetworkingEngine(); } - if (this.sender_.isCasting()) { + if (this.sender_ && this.sender_.isCasting()) { // These methods are unavailable or otherwise stubbed during casting. if (name == 'getManifest' || name == 'drmInfo') { return () => { @@ -602,7 +672,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { // If we are casting, but the first update has not come in yet, use local // getters, but not local methods. - if (this.sender_.isCasting() && !this.sender_.hasRemoteProperties()) { + if (this.sender_ && this.sender_.isCasting() && + !this.sender_.hasRemoteProperties()) { if (shaka.cast.CastUtils.PlayerGetterMethods[name]) { const value = /** @type {Object} */(this.localPlayer_)[name]; goog.asserts.assert(typeof value == 'function', @@ -612,7 +683,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { } // Use local getters and methods if we are not casting. - if (!this.sender_.isCasting()) { + if (!this.sender_ || !this.sender_.isCasting()) { const value = /** @type {Object} */(this.localPlayer_)[name]; goog.asserts.assert(typeof value == 'function', 'only methods on Player'); @@ -627,7 +698,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @private */ playerProxyLocalEvent_(event) { - if (this.sender_.isCasting()) { + if (this.sender_ && this.sender_.isCasting()) { // Ignore any unexpected local events while casting. return; } @@ -641,7 +712,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget { * @private */ onRemoteEvent_(targetName, event) { - goog.asserts.assert(this.sender_.isCasting(), + goog.asserts.assert(this.sender_ && this.sender_.isCasting(), 'Should only receive remote events while casting'); if (!this.sender_.isCasting()) { // Ignore any unexpected remote events. diff --git a/lib/util/error.js b/lib/util/error.js index 2dc289d90b..c771f0a584 100644 --- a/lib/util/error.js +++ b/lib/util/error.js @@ -804,6 +804,12 @@ shaka.util.Error.Code = { 'CAST_RECEIVER_APP_UNAVAILABLE': 8006, + /** + * No receiver app id has been provided, making casting impossible. + */ + 'CAST_RECEIVER_APP_ID_MISSING': 8007, + + /** * Offline storage is not supported on this browser; it is required for * offline support. diff --git a/ui/controls.js b/ui/controls.js index a9f3721c98..14c1973c02 100644 --- a/ui/controls.js +++ b/ui/controls.js @@ -353,6 +353,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget { configure(config) { this.config_ = config; + this.castProxy_.changeReceiverId(config.castReceiverAppId); + if (this.controlsContainer_) { // Deconstruct the old layout if applicable shaka.util.Dom.removeAllChildren(this.controlsContainer_);