Check bridge compat before initializing cast shim

This commit is contained in:
hensm
2018-12-13 19:50:47 +00:00
parent 169ece39fc
commit e42766097f
5 changed files with 307 additions and 284 deletions

View File

@@ -10,6 +10,7 @@ export default async function getBridgeInfo () {
applicationVersion = response.data; applicationVersion = response.data;
} catch (err) { } catch (err) {
console.error(err)
return null; return null;
} }

View File

@@ -2,6 +2,7 @@
import defaultOptions from "./options/defaultOptions"; import defaultOptions from "./options/defaultOptions";
import messageRouter from "./messageRouter"; import messageRouter from "./messageRouter";
import getBridgeInfo from "./lib/getBridgeInfo";
import semver from "semver"; import semver from "semver";
@@ -421,7 +422,16 @@ messageRouter.register("main", async (message, sender) => {
switch (message.subject) { switch (message.subject) {
case "main:initialize": { 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; break;
}; };

View File

@@ -244,7 +244,7 @@ function onMediaSeekError (err) {
window.__onGCastApiAvailable = async function (loaded, errorInfo) { window.__onGCastApiAvailable = async function (loaded, errorInfo) {
if (!loaded) { if (!loaded) {
logMessage("__onGCastApiAvailable error"); console.error("__onGCastApiAvailable error");
return; return;
} }

View File

@@ -1,264 +1,259 @@
"use strict"; "use strict";
import ApiConfig from "./classes/ApiConfig"; import ApiConfig from "./classes/ApiConfig";
import DialRequest from "./classes/DialRequest"; import DialRequest from "./classes/DialRequest";
import Error_ from "./classes/Error"; import Error_ from "./classes/Error";
import Image_ from "./classes/Image"; import Image_ from "./classes/Image";
import Receiver from "./classes/Receiver"; import Receiver from "./classes/Receiver";
import ReceiverDisplayStatus from "./classes/ReceiverDisplayStatus"; import ReceiverDisplayStatus from "./classes/ReceiverDisplayStatus";
import SenderApplication from "./classes/SenderApplication"; import SenderApplication from "./classes/SenderApplication";
import Session from "./classes/Session"; import Session from "./classes/Session";
import SessionRequest from "./classes/SessionRequest"; import SessionRequest from "./classes/SessionRequest";
import Timeout from "./classes/Timeout"; import Timeout from "./classes/Timeout";
import Volume from "./classes/Volume"; import Volume from "./classes/Volume";
import { AutoJoinPolicy import { AutoJoinPolicy
, Capability , Capability
, DefaultActionPolicy , DefaultActionPolicy
, DialAppState , DialAppState
, ErrorCode , ErrorCode
, ReceiverAction , ReceiverAction
, ReceiverAvailability , ReceiverAvailability
, ReceiverType , ReceiverType
, SenderPlatform , SenderPlatform
, SessionStatus , SessionStatus
, VolumeControlType } from "./enums"; , VolumeControlType } from "./enums";
import { requestSession as requestSessionTimeout } from "../timeout"; import { requestSession as requestSessionTimeout } from "../timeout";
import state from "../state"; import state from "../state";
import { onMessage, sendMessage } from "../messageBridge"; import { onMessage, sendMessage } from "../messageBridge";
const cast = { const cast = {
// Enums // Enums
AutoJoinPolicy AutoJoinPolicy
, Capability , Capability
, DefaultActionPolicy , DefaultActionPolicy
, DialAppState , DialAppState
, ErrorCode , ErrorCode
, ReceiverAction , ReceiverAction
, ReceiverAvailability , ReceiverAvailability
, ReceiverType , ReceiverType
, SenderPlatform , SenderPlatform
, SessionStatus , SessionStatus
, VolumeControlType , VolumeControlType
// Classes // Classes
, ApiConfig , ApiConfig
, DialRequest , DialRequest
, Error: Error_ , Error: Error_
, Image: Image_ , Image: Image_
, Receiver , Receiver
, ReceiverDisplayStatus , ReceiverDisplayStatus
, SenderApplication , SenderApplication
, Session , Session
, SessionRequest , SessionRequest
, Timeout , Timeout
, Volume , Volume
, timeout: new Timeout() , timeout: new Timeout()
, isAvailable: true , isAvailable: true
, VERSION: [ 1, 2 ] , VERSION: [ 1, 2 ]
}; };
const receiverListeners = new Set(); const receiverListeners = new Set();
let sessionSuccessCallback; let sessionSuccessCallback;
let sessionErrorCallback; let sessionErrorCallback;
cast.addReceiverActionListener = (listener) => { cast.addReceiverActionListener = (listener) => {
console.info("Caster (Debug): cast.addReceiverActionListener"); console.info("Caster (Debug): cast.addReceiverActionListener");
receiverListeners.add(listener); receiverListeners.add(listener);
}; };
cast.initialize = ( cast.initialize = (
apiConfig apiConfig
, successCallback , successCallback
, errorCallback) => { , errorCallback) => {
console.info("Caster (Debug): cast.initialize"); console.info("Caster (Debug): cast.initialize");
// Already initialized // Already initialized
if (state.apiConfig) { if (state.apiConfig) {
errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE)); errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE));
return; return;
} }
state.apiConfig = apiConfig; state.apiConfig = apiConfig;
sendMessage({ sendMessage({
subject: "bridge:discover" subject: "bridge:discover"
}); });
apiConfig.receiverListener(state.receiverList.length apiConfig.receiverListener(state.receiverList.length
? ReceiverAvailability.AVAILABLE ? ReceiverAvailability.AVAILABLE
: ReceiverAvailability.UNAVAILABLE); : ReceiverAvailability.UNAVAILABLE);
successCallback(); successCallback();
}; };
cast.logMessage = (message) => { cast.logMessage = (message) => {
console.log("CAST MSG:", message); console.log("CAST MSG:", message);
}; };
cast.precache = (data) => { cast.precache = (data) => {
console.info("STUB :: cast.precache"); console.info("STUB :: cast.precache");
}; };
cast.removeReceiverActionListener = (listener) => { cast.removeReceiverActionListener = (listener) => {
receiverListeners.delete(listener); receiverListeners.delete(listener);
} }
cast.requestSession = ( cast.requestSession = (
successCallback successCallback
, errorCallback , errorCallback
, opt_sessionRequest = state.apiConfig.sessionRequest) => { , opt_sessionRequest = state.apiConfig.sessionRequest) => {
console.info("Caster (Debug): cast.requestSession"); console.info("Caster (Debug): cast.requestSession");
// Called before initialization // Called before initialization
if (!state.apiConfig) { if (!state.apiConfig) {
errorCallback(new Error_(ErrorCode.API_NOT_INITIALIZED)); errorCallback(new Error_(ErrorCode.API_NOT_INITIALIZED));
return; return;
} }
// No available receivers // No available receivers
if (!state.receiverList.length) { if (!state.receiverList.length) {
errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE)); errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE));
return; return;
} }
sessionSuccessCallback = successCallback; sessionSuccessCallback = successCallback;
sessionErrorCallback = errorCallback; sessionErrorCallback = errorCallback;
// Open destination chooser // Open destination chooser
sendMessage({ sendMessage({
subject: "main:openPopup" subject: "main:openPopup"
}); });
}; };
cast.requestSessionById = (sessionId) => { cast.requestSessionById = (sessionId) => {
console.info("STUB :: cast.requestSessionById"); console.info("STUB :: cast.requestSessionById");
}; };
cast.setCustomReceivers = (receivers, successCallback, errorCallback) => { cast.setCustomReceivers = (receivers, successCallback, errorCallback) => {
console.info("STUB :: cast.setCustomReceivers"); console.info("STUB :: cast.setCustomReceivers");
}; };
cast.setPageContext = (win) => { cast.setPageContext = (win) => {
console.info("STUB :: cast.setPageContext"); console.info("STUB :: cast.setPageContext");
}; };
cast.setReceiverDisplayStatus = (sessionId) => { cast.setReceiverDisplayStatus = (sessionId) => {
console.info("STUB :: cast.setReceiverDisplayStatus"); console.info("STUB :: cast.setReceiverDisplayStatus");
}; };
cast.unescape = (escaped) => unescape(escaped); cast.unescape = (escaped) => unescape(escaped);
onMessage(message => { onMessage(message => {
switch (message.subject) { switch (message.subject) {
/** /**
* Cast destination found (serviceUp). Set the API availability * Cast destination found (serviceUp). Set the API availability
* property and call the page event function (__onGCastApiAvailable). * property and call the page event function (__onGCastApiAvailable).
*/ */
case "shim:serviceUp": case "shim:serviceUp":
const receiver = new Receiver( const receiver = new Receiver(
message.data.id message.data.id
, message.data.friendlyName); , message.data.friendlyName);
receiver._address = message.data.address; receiver._address = message.data.address;
receiver._port = message.data.port; receiver._port = message.data.port;
if (state.receiverList.find(r => r.label === receiver.label)) { if (state.receiverList.find(r => r.label === receiver.label)) {
break; break;
} }
state.receiverList.push(receiver); state.receiverList.push(receiver);
// Notify listeners of new cast destination // Notify listeners of new cast destination
state.apiConfig.receiverListener(ReceiverAvailability.AVAILABLE); state.apiConfig.receiverListener(ReceiverAvailability.AVAILABLE);
receiverListeners.forEach( receiverListeners.forEach(
listener => listener(ReceiverAvailability.AVAILABLE)); listener => listener(ReceiverAvailability.AVAILABLE));
break; break;
/** /**
* Cast destination lost (serviceDown). Remove from the receiver list * Cast destination lost (serviceDown). Remove from the receiver list
* and update availability state. * and update availability state.
*/ */
case "shim:serviceDown": case "shim:serviceDown":
state.receiverList = state.receiverList.filter( state.receiverList = state.receiverList.filter(
receiver => receiver.label !== message.data.id); receiver => receiver.label !== message.data.id);
if (state.receiverList.length === 0) { if (state.receiverList.length === 0) {
state.apiConfig.receiverListener( state.apiConfig.receiverListener(
ReceiverAvailability.UNAVAILABLE); ReceiverAvailability.UNAVAILABLE);
} }
break; break;
case "shim:selectReceiver": case "shim:selectReceiver":
console.info("Caster (Debug): Selected receiver"); console.info("Caster (Debug): Selected receiver");
const selectedReceiver = message.data.receiver; const selectedReceiver = message.data.receiver;
const sessionConstructorArgs = [ const sessionConstructorArgs = [
state.sessionList.length // sessionId state.sessionList.length // sessionId
, state.apiConfig.sessionRequest.appId // appId , state.apiConfig.sessionRequest.appId // appId
, selectedReceiver.friendlyName // displayName , selectedReceiver.friendlyName // displayName
, [] // appImages , [] // appImages
, selectedReceiver // receiver , selectedReceiver // receiver
, (session) => { , (session) => {
sendMessage({ sendMessage({
subject: "popup:close" subject: "popup:close"
}); });
state.apiConfig.sessionListener(session); state.apiConfig.sessionListener(session);
sessionSuccessCallback(session, message.data.selectedMedia); sessionSuccessCallback(session, message.data.selectedMedia);
} }
]; ];
// If existing session active, stop it and start new one // If existing session active, stop it and start new one
if (state.sessionList.length) { if (state.sessionList.length) {
const lastSession const lastSession
= state.sessionList[state.sessionList.length - 1]; = state.sessionList[state.sessionList.length - 1];
if (lastSession.status !== SessionStatus.STOPPED) { if (lastSession.status !== SessionStatus.STOPPED) {
lastSession.stop(() => { lastSession.stop(() => {
state.sessionList.push(new Session( state.sessionList.push(new Session(
...sessionConstructorArgs)); ...sessionConstructorArgs));
}); });
break; break;
} }
} }
state.sessionList.push(new Session(...sessionConstructorArgs)); state.sessionList.push(new Session(...sessionConstructorArgs));
break; break;
/** /**
* Popup is ready to receive data to populate the cast destination * Popup is ready to receive data to populate the cast destination
* chooser. * chooser.
*/ */
case "shim:popupReady": case "shim:popupReady":
sendMessage({ sendMessage({
subject: "popup:populate" subject: "popup:populate"
, data: { , data: {
receivers: state.receiverList receivers: state.receiverList
, selectedMedia: state.apiConfig._selectedMedia , selectedMedia: state.apiConfig._selectedMedia
} }
}); });
break; break;
} }
}); });
// Trigger bridge mDNS discovery export default cast;
sendMessage({
subject: "main:initialize"
});
export default cast;

View File

@@ -1,18 +1,35 @@
"use strict"; "use strict";
import cast from "./cast"; import cast from "./cast";
import media from "./media"; import media from "./media";
if (!window.chrome) { import { onMessage, sendMessage } from "./messageBridge";
window.chrome = {};
}
if (!window.chrome) {
window.chrome.cast = cast; window.chrome = {};
window.chrome.cast.media = media; }
// Call page's API loaded function if defined window.chrome.cast = cast;
const readyFunction = window.__onGCastApiAvailable; window.chrome.cast.media = media;
console.log(readyFunction);
if (readyFunction && typeof readyFunction === "function") {
readyFunction(true); 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"
});