mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-11 01:59:58 +00:00
Implement receiver action listeners
This commit is contained in:
@@ -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({
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ export enum ReceiverSelectorType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { ReceiverSelection
|
export { ReceiverSelection
|
||||||
|
, ReceiverSelectionActionType
|
||||||
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user