Implement receiver action listeners

This commit is contained in:
hensm
2020-01-26 16:05:27 +00:00
parent 741379ca72
commit c676184898
7 changed files with 187 additions and 79 deletions

View File

@@ -8,7 +8,8 @@ import options from "../lib/options";
import { Message } from "../types"; import { Message } from "../types";
import { getMediaTypesForPageUrl } from "../lib/utils"; import { getMediaTypesForPageUrl } from "../lib/utils";
import { ReceiverSelectorMediaType } from "./receiverSelector"; import { ReceiverSelectionActionType
, ReceiverSelectorMediaType } from "./receiverSelector";
import ReceiverSelectorManager import ReceiverSelectorManager
from "./receiverSelector/ReceiverSelectorManager"; from "./receiverSelector/ReceiverSelectorManager";
@@ -182,31 +183,46 @@ export default new class ShimManager {
break; break;
} }
/** switch (selection.actionType) {
* If the media type returned from the selector has been case ReceiverSelectionActionType.Cast: {
* changed, we need to cancel the current sender and switch /**
* it out for the right one. * If the media type returned from the selector has
*/ * been changed, we need to cancel the current
if (selection.mediaType !== ReceiverSelectorMediaType.App) { * sender and switch it out for the right one.
shim.contentPort.postMessage({ */
subject: "shim:/selectReceiverCancelled" if (selection.mediaType !==
}); ReceiverSelectorMediaType.App) {
loadSender({ shim.contentPort.postMessage({
tabId: shim.contentTabId subject: "shim:/selectReceiverCancelled"
, frameId: shim.contentFrameId });
, selection
});
break; loadSender({
tabId: shim.contentTabId
, frameId: shim.contentFrameId
, selection
});
break;
}
shim.contentPort.postMessage({
subject: "shim:/selectReceiverEnd"
, data: selection
});
break;
}
case ReceiverSelectionActionType.Stop: {
shim.contentPort.postMessage({
subject: "shim:/selectReceiverStop"
, data: selection
});
break;
}
} }
// Pass selection back to shim
shim.contentPort.postMessage({
subject: "shim:/selectReceiverEnd"
, data: selection
});
} catch (err) { } catch (err) {
// TODO: Report errors properly // TODO: Report errors properly
shim.contentPort.postMessage({ shim.contentPort.postMessage({

View File

@@ -11,7 +11,8 @@ import { getMediaTypesForPageUrl, stringify } from "../lib/utils";
import { CAST_FRAMEWORK_LOADER_SCRIPT_URL import { CAST_FRAMEWORK_LOADER_SCRIPT_URL
, CAST_LOADER_SCRIPT_URL } from "../lib/endpoints"; , CAST_LOADER_SCRIPT_URL } from "../lib/endpoints";
import { ReceiverSelectorMediaType } from "./receiverSelector"; import { ReceiverSelectionActionType
, ReceiverSelectorMediaType } from "./receiverSelector";
import ReceiverSelectorManager import ReceiverSelectorManager
from "./receiverSelector/ReceiverSelectorManager"; from "./receiverSelector/ReceiverSelectorManager";
@@ -200,32 +201,41 @@ async function initMenus () {
break; break;
} }
/** switch (selection.actionType) {
* If the selected media type is App, that refers to the case ReceiverSelectionActionType.Cast: {
* media sender in this context, so load media sender. /**
*/ * If the selected media type is App, that refers to the
if (selection.mediaType === ReceiverSelectorMediaType.App) { * media sender in this context, so load media sender.
await browser.tabs.executeScript(tab.id, { */
code: stringify` if (selection.mediaType ===
window.receiver = ${selection.receiver}; ReceiverSelectorMediaType.App) {
window.mediaUrl = ${info.srcUrl};
window.targetElementId = ${info.targetElementId};
`
, frameId: info.frameId
});
await browser.tabs.executeScript(tab.id, { await browser.tabs.executeScript(tab.id, {
file: "senders/media/bundle.js" code: stringify`
, frameId: info.frameId window.receiver = ${selection.receiver};
}); window.mediaUrl = ${info.srcUrl};
} else { window.targetElementId = ${
info.targetElementId};
`
, frameId: info.frameId
});
// Handle other responses await browser.tabs.executeScript(tab.id, {
loadSender({ file: "senders/media/bundle.js"
tabId: tab.id , frameId: info.frameId
, frameId: info.frameId });
, selection } else {
});
// Handle other responses
loadSender({
tabId: tab.id
, frameId: info.frameId
, selection
});
}
break;
}
} }
break; break;

View File

@@ -11,18 +11,30 @@ export enum ReceiverSelectorMediaType {
, File = 8 , File = 8
} }
export interface ReceiverSelection { export enum ReceiverSelectionActionType {
Cast = 1
, Stop = 2
}
export interface ReceiverSelectionCast {
actionType: ReceiverSelectionActionType.Cast;
receiver: Receiver; receiver: Receiver;
mediaType: ReceiverSelectorMediaType; mediaType: ReceiverSelectorMediaType;
filePath?: string; filePath?: string;
} }
export interface ReceiverSelectionStop {
actionType: ReceiverSelectionActionType.Stop;
receiver: Receiver;
}
export type ReceiverSelection = ReceiverSelectionCast | ReceiverSelectionStop;
export interface ReceiverSelectorEvents { export interface ReceiverSelectorEvents {
"selected": ReceiverSelection; "selected": ReceiverSelectionCast;
"error": string; "error": string;
"cancelled": void; "cancelled": void;
"stop": { receiver: Receiver }; "stop": ReceiverSelectionStop;
} }
export default interface ReceiverSelector export default interface ReceiverSelector

View File

@@ -13,6 +13,7 @@ import { DEFAULT_MEDIA_RECEIVER_APP_ID } from "../../shim/cast/media/";
import { ReceiverSelector import { ReceiverSelector
, ReceiverSelectorType } from "./"; , ReceiverSelectorType } from "./";
import { ReceiverSelection import { ReceiverSelection
, ReceiverSelectionActionType
, ReceiverSelectorMediaType } from "./ReceiverSelector"; , ReceiverSelectorMediaType } from "./ReceiverSelector";
import NativeReceiverSelector from "./NativeReceiverSelector"; import NativeReceiverSelector from "./NativeReceiverSelector";
@@ -122,10 +123,28 @@ async function getSelection (
// Get a new selector for each selection // Get a new selector for each selection
sharedSelector = await createSelector(); sharedSelector = await createSelector();
sharedSelector.addEventListener("selected", onSelected);
sharedSelector.addEventListener("cancelled", onCancelled); let onSelected: any;
sharedSelector.addEventListener("error", onError); let onCancelled: any;
sharedSelector.addEventListener("stop", onStop); let onError: any;
let onStop: any;
type EvParamsType =
Parameters<typeof sharedSelector.addEventListener>[0];
function storeListener<T> (type: EvParamsType, fn: T) {
if (type === "selected") {
onSelected = fn;
} else if (type === "cancelled") {
onCancelled = fn;
} else if (type === "error") {
onError = fn;
} else if (type === "stop") {
onStop = fn;
}
return fn;
}
function removeListeners () { function removeListeners () {
sharedSelector.removeEventListener("selected", onSelected); sharedSelector.removeEventListener("selected", onSelected);
@@ -134,31 +153,48 @@ async function getSelection (
sharedSelector.removeEventListener("stop", onStop); sharedSelector.removeEventListener("stop", onStop);
} }
function onSelected (ev: any) { sharedSelector.addEventListener("selected"
logger.info("Selected receiver", ev.detail); , storeListener("selected", ev => {
resolve(ev.detail);
removeListeners(); logger.info("Selected receiver", ev.detail);
} resolve({
actionType: ReceiverSelectionActionType.Cast
, receiver: ev.detail.receiver
, mediaType: ev.detail.mediaType
, filePath: ev.detail.filePath
});
removeListeners();
}));
sharedSelector.addEventListener("cancelled"
, storeListener("cancelled", () => {
function onCancelled () {
logger.info("Cancelled receiver selection"); logger.info("Cancelled receiver selection");
resolve(null); resolve(null);
removeListeners(); removeListeners();
} }));
function onError () { sharedSelector.addEventListener("error"
logger.error("Failed to select receiver"); , storeListener("error", () => {
reject(); reject();
removeListeners(); removeListeners();
} }));
sharedSelector.addEventListener("stop"
, storeListener("stop", ev => {
function onStop (ev: any) {
logger.info("Stopped receiver app", ev.detail); logger.info("Stopped receiver app", ev.detail);
StatusManager.init().then(() => { StatusManager.init()
StatusManager.stopReceiverApp(ev.detail.receiver); .then(() => StatusManager.stopReceiverApp(ev.detail.receiver))
}); .then(() => {
} resolve({
actionType: ReceiverSelectionActionType.Stop
, receiver: ev.detail.receiver
});
removeListeners();
});
}));
// Ensure status manager is initialized // Ensure status manager is initialized

View File

@@ -14,4 +14,5 @@ export enum ReceiverSelectorType {
} }
export { ReceiverSelection export { ReceiverSelection
, ReceiverSelectionActionType
, ReceiverSelectorMediaType } from "./ReceiverSelector"; , ReceiverSelectorMediaType } from "./ReceiverSelector";

View File

@@ -4,6 +4,7 @@ import logger from "./logger";
import { stringify } from "./utils"; import { stringify } from "./utils";
import { ReceiverSelection import { ReceiverSelection
, ReceiverSelectionActionType
, ReceiverSelectorMediaType } from "../background/receiverSelector"; , ReceiverSelectorMediaType } from "../background/receiverSelector";
import ShimManager from "../background/ShimManager"; import ShimManager from "../background/ShimManager";
@@ -25,6 +26,10 @@ export default async function loadSender (opts: LoadSenderOptions) {
return; return;
} }
if (opts.selection.actionType !== ReceiverSelectionActionType.Cast) {
return;
}
switch (opts.selection.mediaType) { switch (opts.selection.mediaType) {
case ReceiverSelectorMediaType.App: { case ReceiverSelectorMediaType.App: {
const shim = ShimManager.getShim(opts.tabId, opts.frameId); const shim = ShimManager.getShim(opts.tabId, opts.frameId);

View File

@@ -41,12 +41,13 @@ type ErrorCallback = (err: Error_) => void;
let apiConfig: ApiConfig; let apiConfig: ApiConfig;
let receiverList: any[] = [];
const receiverList: Receiver[] = [];
const sessionList: Session[] = []; const sessionList: Session[] = [];
const receiverActionListeners = new Set<ReceiverActionListener>();
let sessionRequestInProgress = false; let sessionRequestInProgress = false;
const receiverListeners = new Set<ReceiverActionListener>();
let sessionSuccessCallback: RequestSessionSuccessCallback; let sessionSuccessCallback: RequestSessionSuccessCallback;
let sessionErrorCallback: ErrorCallback; let sessionErrorCallback: ErrorCallback;
@@ -76,8 +77,7 @@ export const VERSION = [1, 2];
export function addReceiverActionListener ( export function addReceiverActionListener (
listener: ReceiverActionListener): void { listener: ReceiverActionListener): void {
console.info("fx_cast (Debug): cast.addReceiverActionListener"); receiverActionListeners.add(listener);
receiverListeners.add(listener);
} }
export function initialize ( export function initialize (
@@ -125,7 +125,7 @@ export function precache (_data: string): void {
export function removeReceiverActionListener ( export function removeReceiverActionListener (
listener: ReceiverActionListener): void { listener: ReceiverActionListener): void {
receiverListeners.delete(listener); receiverActionListeners.delete(listener);
} }
export function requestSession ( export function requestSession (
@@ -306,8 +306,10 @@ onMessage(async message => {
* and update availability state. * and update availability state.
*/ */
case "shim:/serviceDown": { case "shim:/serviceDown": {
receiverList = receiverList.filter( const receiverIndex = receiverList.findIndex(
receiver => receiver.id !== message.data.id); receiver => receiver.id === message.data.id);
receiverList.splice(receiverIndex, 1);
if (receiverList.length === 0) { if (receiverList.length === 0) {
if (apiConfig) { if (apiConfig) {
@@ -322,10 +324,19 @@ onMessage(async message => {
case "shim:/selectReceiverEnd": { case "shim:/selectReceiverEnd": {
console.info("fx_cast (Debug): Selected receiver"); console.info("fx_cast (Debug): Selected receiver");
if (!sessionRequestInProgress) {
break;
}
const selectedReceiver = new Receiver_( const selectedReceiver = new Receiver_(
message.data.receiver.id message.data.receiver.id
, message.data.receiver.friendlyName); , message.data.receiver.friendlyName);
for (const listener of receiverActionListeners) {
console.info("fx_cast (Debug): Calling receiver action listener (CAST)", message.data.receiver);
listener(selectedReceiver, ReceiverAction.CAST);
}
(selectedReceiver as any)._address = message.data.receiver.host; (selectedReceiver as any)._address = message.data.receiver.host;
(selectedReceiver as any)._port = message.data.receiver.port; (selectedReceiver as any)._port = message.data.receiver.port;
@@ -363,6 +374,23 @@ onMessage(async message => {
break; break;
} }
case "shim:/selectReceiverStop": {
console.info("fx_cast (Debug): Stopped receiver");
if (sessionRequestInProgress) {
for (const listener of receiverActionListeners) {
const castReceiver = new Receiver_(
message.data.receiver.id
, message.data.receiver.friendlyName);
console.info("fx_cast (Debug): Calling receiver action listener (STOP)", message.data.receiver);
listener(castReceiver, ReceiverAction.STOP);
}
}
break;
}
/** /**
* Popup closed before session established. * Popup closed before session established.
*/ */