From e42766097f9a046965df2fe623d29aaf06e2ba77 Mon Sep 17 00:00:00 2001 From: hensm Date: Thu, 13 Dec 2018 19:50:47 +0000 Subject: [PATCH] Check bridge compat before initializing cast shim --- ext/src/lib/getBridgeInfo.js | 1 + ext/src/main.js | 12 +- ext/src/mediaCast.js | 2 +- ext/src/shim/cast/index.js | 523 +++++++++++++++++------------------ ext/src/shim/index.js | 53 ++-- 5 files changed, 307 insertions(+), 284 deletions(-) diff --git a/ext/src/lib/getBridgeInfo.js b/ext/src/lib/getBridgeInfo.js index a7434c3..942ad3c 100644 --- a/ext/src/lib/getBridgeInfo.js +++ b/ext/src/lib/getBridgeInfo.js @@ -10,6 +10,7 @@ export default async function getBridgeInfo () { applicationVersion = response.data; } catch (err) { + console.error(err) return null; } diff --git a/ext/src/main.js b/ext/src/main.js index 603de3d..3f44533 100755 --- a/ext/src/main.js +++ b/ext/src/main.js @@ -2,6 +2,7 @@ import defaultOptions from "./options/defaultOptions"; import messageRouter from "./messageRouter"; +import getBridgeInfo from "./lib/getBridgeInfo"; import semver from "semver"; @@ -421,7 +422,16 @@ messageRouter.register("main", async (message, sender) => { switch (message.subject) { case "main:initialize": { - initBridge(tabId, sender.tab.frameId); + const bridgeInfo = await getBridgeInfo(); + if (bridgeInfo && bridgeInfo.isVersionCompatible) { + initBridge(tabId, sender.tab.frameId); + } + + browser.tabs.sendMessage(sender.tab.id, { + subject: "shim:initialized" + , data: bridgeInfo + }, { frameId: sender.tab.frameId }); + break; }; diff --git a/ext/src/mediaCast.js b/ext/src/mediaCast.js index 028cc15..acb1648 100644 --- a/ext/src/mediaCast.js +++ b/ext/src/mediaCast.js @@ -244,7 +244,7 @@ function onMediaSeekError (err) { window.__onGCastApiAvailable = async function (loaded, errorInfo) { if (!loaded) { - logMessage("__onGCastApiAvailable error"); + console.error("__onGCastApiAvailable error"); return; } diff --git a/ext/src/shim/cast/index.js b/ext/src/shim/cast/index.js index 4839fbc..5bddfa6 100755 --- a/ext/src/shim/cast/index.js +++ b/ext/src/shim/cast/index.js @@ -1,264 +1,259 @@ -"use strict"; - -import ApiConfig from "./classes/ApiConfig"; -import DialRequest from "./classes/DialRequest"; -import Error_ from "./classes/Error"; -import Image_ from "./classes/Image"; -import Receiver from "./classes/Receiver"; -import ReceiverDisplayStatus from "./classes/ReceiverDisplayStatus"; -import SenderApplication from "./classes/SenderApplication"; -import Session from "./classes/Session"; -import SessionRequest from "./classes/SessionRequest"; -import Timeout from "./classes/Timeout"; -import Volume from "./classes/Volume"; - -import { AutoJoinPolicy - , Capability - , DefaultActionPolicy - , DialAppState - , ErrorCode - , ReceiverAction - , ReceiverAvailability - , ReceiverType - , SenderPlatform - , SessionStatus - , VolumeControlType } from "./enums"; - -import { requestSession as requestSessionTimeout } from "../timeout"; - -import state from "../state"; - -import { onMessage, sendMessage } from "../messageBridge"; - - -const cast = { - // Enums - AutoJoinPolicy - , Capability - , DefaultActionPolicy - , DialAppState - , ErrorCode - , ReceiverAction - , ReceiverAvailability - , ReceiverType - , SenderPlatform - , SessionStatus - , VolumeControlType - - // Classes - , ApiConfig - , DialRequest - , Error: Error_ - , Image: Image_ - , Receiver - , ReceiverDisplayStatus - , SenderApplication - , Session - , SessionRequest - , Timeout - , Volume - - , timeout: new Timeout() - , isAvailable: true - , VERSION: [ 1, 2 ] -}; - - -const receiverListeners = new Set(); - -let sessionSuccessCallback; -let sessionErrorCallback; - - -cast.addReceiverActionListener = (listener) => { - console.info("Caster (Debug): cast.addReceiverActionListener"); - receiverListeners.add(listener); -}; - -cast.initialize = ( - apiConfig - , successCallback - , errorCallback) => { - - console.info("Caster (Debug): cast.initialize"); - - // Already initialized - if (state.apiConfig) { - errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE)); - return; - } - - state.apiConfig = apiConfig; - - sendMessage({ - subject: "bridge:discover" - }); - - apiConfig.receiverListener(state.receiverList.length - ? ReceiverAvailability.AVAILABLE - : ReceiverAvailability.UNAVAILABLE); - - successCallback(); -}; - -cast.logMessage = (message) => { - console.log("CAST MSG:", message); -}; - -cast.precache = (data) => { - console.info("STUB :: cast.precache"); -}; - -cast.removeReceiverActionListener = (listener) => { - receiverListeners.delete(listener); -} - -cast.requestSession = ( - successCallback - , errorCallback - , opt_sessionRequest = state.apiConfig.sessionRequest) => { - - console.info("Caster (Debug): cast.requestSession"); - - // Called before initialization - if (!state.apiConfig) { - errorCallback(new Error_(ErrorCode.API_NOT_INITIALIZED)); - return; - } - - // No available receivers - if (!state.receiverList.length) { - errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE)); - return; - } - - sessionSuccessCallback = successCallback; - sessionErrorCallback = errorCallback; - - // Open destination chooser - sendMessage({ - subject: "main:openPopup" - }); -}; - -cast.requestSessionById = (sessionId) => { - console.info("STUB :: cast.requestSessionById"); -}; - -cast.setCustomReceivers = (receivers, successCallback, errorCallback) => { - console.info("STUB :: cast.setCustomReceivers"); -}; - -cast.setPageContext = (win) => { - console.info("STUB :: cast.setPageContext"); -}; - -cast.setReceiverDisplayStatus = (sessionId) => { - console.info("STUB :: cast.setReceiverDisplayStatus"); -}; - -cast.unescape = (escaped) => unescape(escaped); - - -onMessage(message => { - switch (message.subject) { - /** - * Cast destination found (serviceUp). Set the API availability - * property and call the page event function (__onGCastApiAvailable). - */ - case "shim:serviceUp": - const receiver = new Receiver( - message.data.id - , message.data.friendlyName); - - receiver._address = message.data.address; - receiver._port = message.data.port; - - if (state.receiverList.find(r => r.label === receiver.label)) { - break; - } - - state.receiverList.push(receiver); - - // Notify listeners of new cast destination - state.apiConfig.receiverListener(ReceiverAvailability.AVAILABLE); - receiverListeners.forEach( - listener => listener(ReceiverAvailability.AVAILABLE)); - - break; - - /** - * Cast destination lost (serviceDown). Remove from the receiver list - * and update availability state. - */ - case "shim:serviceDown": - state.receiverList = state.receiverList.filter( - receiver => receiver.label !== message.data.id); - - if (state.receiverList.length === 0) { - state.apiConfig.receiverListener( - ReceiverAvailability.UNAVAILABLE); - } - - break; - - case "shim:selectReceiver": - console.info("Caster (Debug): Selected receiver"); - const selectedReceiver = message.data.receiver; - - const sessionConstructorArgs = [ - state.sessionList.length // sessionId - , state.apiConfig.sessionRequest.appId // appId - , selectedReceiver.friendlyName // displayName - , [] // appImages - , selectedReceiver // receiver - , (session) => { - sendMessage({ - subject: "popup:close" - }); - - state.apiConfig.sessionListener(session); - sessionSuccessCallback(session, message.data.selectedMedia); - } - ]; - - // If existing session active, stop it and start new one - if (state.sessionList.length) { - const lastSession - = state.sessionList[state.sessionList.length - 1]; - - if (lastSession.status !== SessionStatus.STOPPED) { - lastSession.stop(() => { - state.sessionList.push(new Session( - ...sessionConstructorArgs)); - }); - break; - } - } - - state.sessionList.push(new Session(...sessionConstructorArgs)); - - break; - - /** - * Popup is ready to receive data to populate the cast destination - * chooser. - */ - case "shim:popupReady": - sendMessage({ - subject: "popup:populate" - , data: { - receivers: state.receiverList - , selectedMedia: state.apiConfig._selectedMedia - } - }); - break; - } -}); - -// Trigger bridge mDNS discovery -sendMessage({ - subject: "main:initialize" -}); - -export default cast; +"use strict"; + +import ApiConfig from "./classes/ApiConfig"; +import DialRequest from "./classes/DialRequest"; +import Error_ from "./classes/Error"; +import Image_ from "./classes/Image"; +import Receiver from "./classes/Receiver"; +import ReceiverDisplayStatus from "./classes/ReceiverDisplayStatus"; +import SenderApplication from "./classes/SenderApplication"; +import Session from "./classes/Session"; +import SessionRequest from "./classes/SessionRequest"; +import Timeout from "./classes/Timeout"; +import Volume from "./classes/Volume"; + +import { AutoJoinPolicy + , Capability + , DefaultActionPolicy + , DialAppState + , ErrorCode + , ReceiverAction + , ReceiverAvailability + , ReceiverType + , SenderPlatform + , SessionStatus + , VolumeControlType } from "./enums"; + +import { requestSession as requestSessionTimeout } from "../timeout"; + +import state from "../state"; + +import { onMessage, sendMessage } from "../messageBridge"; + + +const cast = { + // Enums + AutoJoinPolicy + , Capability + , DefaultActionPolicy + , DialAppState + , ErrorCode + , ReceiverAction + , ReceiverAvailability + , ReceiverType + , SenderPlatform + , SessionStatus + , VolumeControlType + + // Classes + , ApiConfig + , DialRequest + , Error: Error_ + , Image: Image_ + , Receiver + , ReceiverDisplayStatus + , SenderApplication + , Session + , SessionRequest + , Timeout + , Volume + + , timeout: new Timeout() + , isAvailable: true + , VERSION: [ 1, 2 ] +}; + + +const receiverListeners = new Set(); + +let sessionSuccessCallback; +let sessionErrorCallback; + + +cast.addReceiverActionListener = (listener) => { + console.info("Caster (Debug): cast.addReceiverActionListener"); + receiverListeners.add(listener); +}; + +cast.initialize = ( + apiConfig + , successCallback + , errorCallback) => { + + console.info("Caster (Debug): cast.initialize"); + + // Already initialized + if (state.apiConfig) { + errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE)); + return; + } + + state.apiConfig = apiConfig; + + sendMessage({ + subject: "bridge:discover" + }); + + apiConfig.receiverListener(state.receiverList.length + ? ReceiverAvailability.AVAILABLE + : ReceiverAvailability.UNAVAILABLE); + + successCallback(); +}; + +cast.logMessage = (message) => { + console.log("CAST MSG:", message); +}; + +cast.precache = (data) => { + console.info("STUB :: cast.precache"); +}; + +cast.removeReceiverActionListener = (listener) => { + receiverListeners.delete(listener); +} + +cast.requestSession = ( + successCallback + , errorCallback + , opt_sessionRequest = state.apiConfig.sessionRequest) => { + + console.info("Caster (Debug): cast.requestSession"); + + // Called before initialization + if (!state.apiConfig) { + errorCallback(new Error_(ErrorCode.API_NOT_INITIALIZED)); + return; + } + + // No available receivers + if (!state.receiverList.length) { + errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE)); + return; + } + + sessionSuccessCallback = successCallback; + sessionErrorCallback = errorCallback; + + // Open destination chooser + sendMessage({ + subject: "main:openPopup" + }); +}; + +cast.requestSessionById = (sessionId) => { + console.info("STUB :: cast.requestSessionById"); +}; + +cast.setCustomReceivers = (receivers, successCallback, errorCallback) => { + console.info("STUB :: cast.setCustomReceivers"); +}; + +cast.setPageContext = (win) => { + console.info("STUB :: cast.setPageContext"); +}; + +cast.setReceiverDisplayStatus = (sessionId) => { + console.info("STUB :: cast.setReceiverDisplayStatus"); +}; + +cast.unescape = (escaped) => unescape(escaped); + + +onMessage(message => { + switch (message.subject) { + /** + * Cast destination found (serviceUp). Set the API availability + * property and call the page event function (__onGCastApiAvailable). + */ + case "shim:serviceUp": + const receiver = new Receiver( + message.data.id + , message.data.friendlyName); + + receiver._address = message.data.address; + receiver._port = message.data.port; + + if (state.receiverList.find(r => r.label === receiver.label)) { + break; + } + + state.receiverList.push(receiver); + + // Notify listeners of new cast destination + state.apiConfig.receiverListener(ReceiverAvailability.AVAILABLE); + receiverListeners.forEach( + listener => listener(ReceiverAvailability.AVAILABLE)); + + break; + + /** + * Cast destination lost (serviceDown). Remove from the receiver list + * and update availability state. + */ + case "shim:serviceDown": + state.receiverList = state.receiverList.filter( + receiver => receiver.label !== message.data.id); + + if (state.receiverList.length === 0) { + state.apiConfig.receiverListener( + ReceiverAvailability.UNAVAILABLE); + } + + break; + + case "shim:selectReceiver": + console.info("Caster (Debug): Selected receiver"); + const selectedReceiver = message.data.receiver; + + const sessionConstructorArgs = [ + state.sessionList.length // sessionId + , state.apiConfig.sessionRequest.appId // appId + , selectedReceiver.friendlyName // displayName + , [] // appImages + , selectedReceiver // receiver + , (session) => { + sendMessage({ + subject: "popup:close" + }); + + state.apiConfig.sessionListener(session); + sessionSuccessCallback(session, message.data.selectedMedia); + } + ]; + + // If existing session active, stop it and start new one + if (state.sessionList.length) { + const lastSession + = state.sessionList[state.sessionList.length - 1]; + + if (lastSession.status !== SessionStatus.STOPPED) { + lastSession.stop(() => { + state.sessionList.push(new Session( + ...sessionConstructorArgs)); + }); + break; + } + } + + state.sessionList.push(new Session(...sessionConstructorArgs)); + + break; + + /** + * Popup is ready to receive data to populate the cast destination + * chooser. + */ + case "shim:popupReady": + sendMessage({ + subject: "popup:populate" + , data: { + receivers: state.receiverList + , selectedMedia: state.apiConfig._selectedMedia + } + }); + break; + } +}); + +export default cast; diff --git a/ext/src/shim/index.js b/ext/src/shim/index.js index 33cea77..cd3a35a 100755 --- a/ext/src/shim/index.js +++ b/ext/src/shim/index.js @@ -1,18 +1,35 @@ -"use strict"; - -import cast from "./cast"; -import media from "./media"; - -if (!window.chrome) { - window.chrome = {}; -} - -window.chrome.cast = cast; -window.chrome.cast.media = media; - -// Call page's API loaded function if defined -const readyFunction = window.__onGCastApiAvailable; -console.log(readyFunction); -if (readyFunction && typeof readyFunction === "function") { - readyFunction(true); -} +"use strict"; + +import cast from "./cast"; +import media from "./media"; + +import { onMessage, sendMessage } from "./messageBridge"; + + +if (!window.chrome) { + window.chrome = {}; +} + +window.chrome.cast = cast; +window.chrome.cast.media = media; + + +onMessage(message => { + switch (message.subject) { + case "shim:initialized": { + const bridgeInfo = message.data; + + // Call page's API loaded function if defined + const readyFunction = window.__onGCastApiAvailable; + if (readyFunction && typeof readyFunction === "function") { + readyFunction(bridgeInfo && bridgeInfo.isVersionCompatible); + } + break; + }; + } +}); + +// Trigger bridge mDNS discovery +sendMessage({ + subject: "main:initialize" +});