mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-10 17:49:58 +00:00
More receiver selector refactoring
This commit is contained in:
@@ -1,35 +1,45 @@
|
||||
"use strict";
|
||||
|
||||
import logger from "../../lib/logger";
|
||||
import messaging, { Port, Message } from "../../messaging";
|
||||
import options from "../../lib/options";
|
||||
|
||||
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
||||
import { ReceiverDevice } from "../../types";
|
||||
import { SessionRequest } from "../../cast/sdk/classes";
|
||||
import logger from "../lib/logger";
|
||||
import messaging, { Port, Message } from "../messaging";
|
||||
import options from "../lib/options";
|
||||
|
||||
import { TypedEventTarget } from "../lib/TypedEventTarget";
|
||||
import { SessionRequest } from "../cast/sdk/classes";
|
||||
import {
|
||||
ReceiverSelectionCast,
|
||||
ReceiverSelectionStop,
|
||||
ReceiverDevice,
|
||||
ReceiverSelectionActionType,
|
||||
ReceiverSelectorMediaType
|
||||
} from "./index";
|
||||
} from "../types";
|
||||
|
||||
const POPUP_URL = browser.runtime.getURL("ui/popup/index.html");
|
||||
|
||||
export interface PageInfo {
|
||||
/** Info about sender page context. */
|
||||
export interface ReceiverSelectorPageInfo {
|
||||
url: string;
|
||||
tabId: number;
|
||||
frameId: number;
|
||||
sessionRequest?: SessionRequest;
|
||||
}
|
||||
|
||||
export interface ReceiverSelectionCast {
|
||||
actionType: ReceiverSelectionActionType.Cast;
|
||||
receiverDevice: ReceiverDevice;
|
||||
mediaType: ReceiverSelectorMediaType;
|
||||
filePath?: string;
|
||||
}
|
||||
export interface ReceiverSelectionStop {
|
||||
actionType: ReceiverSelectionActionType.Stop;
|
||||
receiverDevice: ReceiverDevice;
|
||||
}
|
||||
export type ReceiverSelection = ReceiverSelectionCast | ReceiverSelectionStop;
|
||||
|
||||
interface ReceiverSelectorEvents {
|
||||
selected: ReceiverSelectionCast;
|
||||
error: string;
|
||||
cancelled: void;
|
||||
stop: ReceiverSelectionStop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the receiver selector popup window and communication with the
|
||||
* extension page hosted within.
|
||||
@@ -38,7 +48,7 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
/** Popup window ID. */
|
||||
private windowId?: number;
|
||||
|
||||
/** Message port to extension page within popup window. */
|
||||
/** Message port to extension page. */
|
||||
private messagePort?: Port;
|
||||
private messagePortDisconnected?: boolean;
|
||||
|
||||
@@ -50,9 +60,7 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
private wasReceiverSelected = false;
|
||||
|
||||
private appId?: string;
|
||||
private pageInfo?: PageInfo;
|
||||
|
||||
#isOpen = false;
|
||||
private pageInfo?: ReceiverSelectorPageInfo;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -63,6 +71,7 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
this.onWindowsFocusChanged = this.onWindowsFocusChanged.bind(this);
|
||||
|
||||
browser.windows.onRemoved.addListener(this.onWindowsRemoved);
|
||||
browser.windows.onFocusChanged.addListener(this.onWindowsFocusChanged);
|
||||
|
||||
/**
|
||||
* Handle incoming message channel connection from popup
|
||||
@@ -73,7 +82,7 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
|
||||
/** Is receiver selector window currently open. */
|
||||
get isOpen() {
|
||||
return this.#isOpen;
|
||||
return this.windowId !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +93,7 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
defaultMediaType: ReceiverSelectorMediaType;
|
||||
availableMediaTypes: ReceiverSelectorMediaType;
|
||||
appId?: string;
|
||||
pageInfo?: PageInfo;
|
||||
pageInfo?: ReceiverSelectorPageInfo;
|
||||
}) {
|
||||
this.appId = opts.appId;
|
||||
this.pageInfo = opts.pageInfo;
|
||||
@@ -139,15 +148,7 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
...popupSizePosition
|
||||
});
|
||||
|
||||
this.#isOpen = true;
|
||||
this.windowId = popup.id;
|
||||
|
||||
// Add focus listener
|
||||
if (await options.get("receiverSelectorCloseIfFocusLost")) {
|
||||
browser.windows.onFocusChanged.addListener(
|
||||
this.onWindowsFocusChanged
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates receiver devices displayed in the receiver selector. */
|
||||
@@ -258,8 +259,6 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
return;
|
||||
}
|
||||
|
||||
this.#isOpen = false;
|
||||
|
||||
browser.windows.onRemoved.removeListener(this.onWindowsRemoved);
|
||||
browser.windows.onFocusChanged.removeListener(
|
||||
this.onWindowsFocusChanged
|
||||
@@ -279,21 +278,18 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes popup window if another browser window is brought
|
||||
* into focus. Doesn't apply if no window is focused
|
||||
* `WINDOW_ID_NONE` or if the popup window is re-focused.
|
||||
* Closes popup window if another browser window is brought into
|
||||
* focus. Doesn't apply if no window is focused `WINDOW_ID_NONE`
|
||||
* or if the popup window is re-focused.
|
||||
*/
|
||||
private onWindowsFocusChanged(windowId: number) {
|
||||
private async onWindowsFocusChanged(windowId: number) {
|
||||
if (!this.windowId) return;
|
||||
|
||||
if (
|
||||
windowId !== browser.windows.WINDOW_ID_NONE &&
|
||||
windowId !== this.windowId
|
||||
) {
|
||||
// Only run once
|
||||
browser.windows.onFocusChanged.removeListener(
|
||||
this.onWindowsFocusChanged
|
||||
);
|
||||
|
||||
if (this.windowId) {
|
||||
if (await options.get("receiverSelectorCloseIfFocusLost")) {
|
||||
browser.windows.remove(this.windowId);
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import logger from "../lib/logger";
|
||||
import options from "../lib/options";
|
||||
import bridge, { BridgeInfo } from "../lib/bridge";
|
||||
|
||||
import CastManager from "../cast/CastManager";
|
||||
import receiverDevices from "./receiverDevices";
|
||||
import ReceiverSelectorManager from "./receiverSelector/ReceiverSelectorManager";
|
||||
import castManager from "./castManager";
|
||||
import deviceManager from "./deviceManager";
|
||||
import selectorManager from "./selectorManager";
|
||||
|
||||
import { initMenus } from "./menus";
|
||||
import { initWhitelist } from "./whitelist";
|
||||
@@ -101,8 +101,8 @@ async function init() {
|
||||
|
||||
await notifyBridgeCompat();
|
||||
|
||||
await receiverDevices.init();
|
||||
await CastManager.init();
|
||||
await deviceManager.init();
|
||||
await castManager.init();
|
||||
|
||||
await initMenus();
|
||||
await initWhitelist();
|
||||
@@ -119,9 +119,9 @@ async function init() {
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = await ReceiverSelectorManager.getSelection(tab.id);
|
||||
const selection = await selectorManager.getSelection(tab.id);
|
||||
if (selection) {
|
||||
CastManager.loadSender({
|
||||
castManager.loadSender({
|
||||
tabId: tab.id,
|
||||
frameId: 0,
|
||||
selection
|
||||
|
||||
380
ext/src/background/castManager.ts
Normal file
380
ext/src/background/castManager.ts
Normal file
@@ -0,0 +1,380 @@
|
||||
"use strict";
|
||||
|
||||
import bridge from "../lib/bridge";
|
||||
import logger from "../lib/logger";
|
||||
import messaging, { Message, Port } from "../messaging";
|
||||
import options from "../lib/options";
|
||||
import { stringify } from "../lib/utils";
|
||||
|
||||
import {
|
||||
ReceiverSelectionActionType,
|
||||
ReceiverSelectorMediaType
|
||||
} from "../types";
|
||||
|
||||
import { ReceiverSelection } from "./ReceiverSelector";
|
||||
|
||||
import deviceManager from "./deviceManager";
|
||||
import selectorManager from "./selectorManager";
|
||||
|
||||
type AnyPort = Port | MessagePort;
|
||||
|
||||
export interface CastInstance {
|
||||
bridgePort: Port;
|
||||
contentPort: AnyPort;
|
||||
contentTabId?: number;
|
||||
contentFrameId?: number;
|
||||
appId?: string;
|
||||
}
|
||||
|
||||
/** Keeps track of cast API instances and provides bridge messaging. */
|
||||
export default new (class {
|
||||
private activeInstances = new Set<CastInstance>();
|
||||
|
||||
public async init() {
|
||||
// Handle incoming instance connections
|
||||
messaging.onConnect.addListener(async port => {
|
||||
if (port.name === "cast") {
|
||||
this.createInstance(port);
|
||||
}
|
||||
});
|
||||
|
||||
// Forward receiver eventes to cast instances
|
||||
deviceManager.addEventListener("receiverDeviceUp", ev => {
|
||||
for (const instance of this.activeInstances) {
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:receiverDeviceUp",
|
||||
data: { receiverDevice: ev.detail.deviceInfo }
|
||||
});
|
||||
}
|
||||
});
|
||||
deviceManager.addEventListener("receiverDeviceDown", ev => {
|
||||
for (const instance of this.activeInstances) {
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:receiverDeviceDown",
|
||||
data: { receiverDeviceId: ev.detail.deviceId }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a cast instance at the given tab (and optionally frame) ID.
|
||||
*/
|
||||
public getInstance(tabId: number, frameId?: number) {
|
||||
for (const instance of this.activeInstances) {
|
||||
if (instance.contentTabId === tabId) {
|
||||
// If frame ID doesn't match go to next instance
|
||||
if (frameId && instance.contentFrameId !== frameId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cast instance with a given port and connects messaging
|
||||
* correctly depending on the type of port.
|
||||
*/
|
||||
public async createInstance(port: AnyPort) {
|
||||
const instance = await (port instanceof MessagePort
|
||||
? this.createInstanceFromBackground(port)
|
||||
: this.createInstanceFromContent(port));
|
||||
|
||||
this.activeInstances.add(instance);
|
||||
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:initialized",
|
||||
data: await bridge.getInfo()
|
||||
});
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Creates a cast instance with a `MessagePort` content port. */
|
||||
private async createInstanceFromBackground(
|
||||
contentPort: MessagePort
|
||||
): Promise<CastInstance> {
|
||||
const instance: CastInstance = {
|
||||
bridgePort: await bridge.connect(),
|
||||
contentPort
|
||||
};
|
||||
|
||||
instance.bridgePort.onDisconnect.addListener(() => {
|
||||
contentPort.close();
|
||||
this.activeInstances.delete(instance);
|
||||
});
|
||||
|
||||
// bridge -> content
|
||||
instance.bridgePort.onMessage.addListener(message => {
|
||||
contentPort.postMessage(message);
|
||||
});
|
||||
|
||||
// content -> (any)
|
||||
contentPort.addEventListener("message", ev => {
|
||||
this.handleContentMessage(instance, ev.data);
|
||||
});
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cast instance with a WebExtension `Port` content port.
|
||||
*/
|
||||
private async createInstanceFromContent(
|
||||
contentPort: Port
|
||||
): Promise<CastInstance> {
|
||||
if (
|
||||
contentPort.sender?.tab?.id === undefined ||
|
||||
contentPort.sender?.frameId === undefined
|
||||
) {
|
||||
throw logger.error(
|
||||
"Cast instance created from content with an invalid port context."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If there's already an active instance for the sender
|
||||
* tab/frame ID, disconnect it.
|
||||
*
|
||||
* TODO: Fix this behaviour!
|
||||
*/
|
||||
for (const instance of this.activeInstances) {
|
||||
if (
|
||||
instance.contentTabId === contentPort.sender.tab.id &&
|
||||
instance.contentFrameId === contentPort.sender.frameId
|
||||
) {
|
||||
instance.bridgePort.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
const instance: CastInstance = {
|
||||
bridgePort: await bridge.connect(),
|
||||
contentPort,
|
||||
contentTabId: contentPort.sender.tab.id,
|
||||
contentFrameId: contentPort.sender.frameId
|
||||
};
|
||||
|
||||
// content -> (any)
|
||||
const onContentPortMessage = (message: Message) => {
|
||||
this.handleContentMessage(instance, message);
|
||||
};
|
||||
// bridge -> content
|
||||
const onBridgePortMessage = (message: Message) => {
|
||||
contentPort.postMessage(message);
|
||||
};
|
||||
|
||||
const onDisconnect = () => {
|
||||
instance.bridgePort.onMessage.removeListener(onBridgePortMessage);
|
||||
contentPort.onMessage.removeListener(onContentPortMessage);
|
||||
|
||||
instance.bridgePort.disconnect();
|
||||
contentPort.disconnect();
|
||||
|
||||
this.activeInstances.delete(instance);
|
||||
};
|
||||
|
||||
instance.bridgePort.onDisconnect.addListener(onDisconnect);
|
||||
instance.bridgePort.onMessage.addListener(onBridgePortMessage);
|
||||
|
||||
contentPort.onDisconnect.addListener(onDisconnect);
|
||||
contentPort.onMessage.addListener(onContentPortMessage);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle content messages from the cast instance. These will either
|
||||
* be handled here in the background script or forwarded to the
|
||||
* bridge associated with the cast instance.
|
||||
*/
|
||||
private async handleContentMessage(
|
||||
instance: CastInstance,
|
||||
message: Message
|
||||
) {
|
||||
const [destination] = message.subject.split(":");
|
||||
if (destination === "bridge") {
|
||||
instance.bridgePort.postMessage(message);
|
||||
}
|
||||
|
||||
switch (message.subject) {
|
||||
// Cast API has been initialized
|
||||
case "main:initializeCast": {
|
||||
instance.appId = message.data.appId;
|
||||
|
||||
for (const receiverDevice of deviceManager.getDevices()) {
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:receiverDeviceUp",
|
||||
data: { receiverDevice }
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// User has triggered receiver selection via the cast API
|
||||
case "main:selectReceiver": {
|
||||
if (
|
||||
instance.contentTabId === undefined ||
|
||||
instance.contentFrameId === undefined
|
||||
) {
|
||||
throw logger.error(
|
||||
"Cast instance associated with content sender missing tab/frame ID"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const selection = await selectorManager.getSelection(
|
||||
instance.contentTabId,
|
||||
instance.contentFrameId,
|
||||
{ sessionRequest: message.data.sessionRequest }
|
||||
);
|
||||
|
||||
// Handle cancellation
|
||||
if (!selection) {
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:selectReceiver/cancelled"
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
switch (selection.actionType) {
|
||||
case ReceiverSelectionActionType.Cast: {
|
||||
/**
|
||||
* If the media type returned from the
|
||||
* selector has been changed, we need to
|
||||
* cancel the current sender and switch it
|
||||
* out for the right one.
|
||||
*/
|
||||
if (
|
||||
selection.mediaType !==
|
||||
ReceiverSelectorMediaType.App
|
||||
) {
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:selectReceiver/cancelled"
|
||||
});
|
||||
|
||||
this.loadSender({
|
||||
tabId: instance.contentTabId,
|
||||
frameId: instance.contentFrameId,
|
||||
selection
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:selectReceiver/selected",
|
||||
data: selection
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ReceiverSelectionActionType.Stop: {
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:selectReceiver/stopped",
|
||||
data: selection
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// TODO: Report errors properly
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:selectReceiver/cancelled"
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: If we're closing a selector, make sure it's the
|
||||
* same one that caused the session creation.
|
||||
*/
|
||||
case "main:closeReceiverSelector": {
|
||||
const selector = await selectorManager.getSelector();
|
||||
const shouldClose = await options.get(
|
||||
"receiverSelectorWaitForConnection"
|
||||
);
|
||||
|
||||
if (selector.isOpen && shouldClose) {
|
||||
selector.close();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the appropriate sender for a given receiver selector
|
||||
* response.
|
||||
*/
|
||||
public async loadSender(opts: {
|
||||
tabId: number;
|
||||
frameId?: number;
|
||||
selection: ReceiverSelection;
|
||||
}) {
|
||||
// Cancelled
|
||||
if (!opts.selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.selection.actionType !== ReceiverSelectionActionType.Cast) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (opts.selection.mediaType) {
|
||||
case ReceiverSelectorMediaType.App: {
|
||||
const instance = this.getInstance(opts.tabId, opts.frameId);
|
||||
if (!instance) {
|
||||
throw logger.error(
|
||||
`Cast instance not found at tabId ${opts.tabId} / frameId ${opts.frameId}`
|
||||
);
|
||||
}
|
||||
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:launchApp",
|
||||
data: { receiverDevice: opts.selection.receiverDevice }
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ReceiverSelectorMediaType.Tab:
|
||||
case ReceiverSelectorMediaType.Screen: {
|
||||
await browser.tabs.executeScript(opts.tabId, {
|
||||
code: stringify`
|
||||
window.selectedMedia = ${opts.selection.mediaType};
|
||||
window.selectedReceiver = ${opts.selection.receiverDevice};
|
||||
`,
|
||||
frameId: opts.frameId
|
||||
});
|
||||
|
||||
await browser.tabs.executeScript(opts.tabId, {
|
||||
file: "cast/senders/mirroring.js",
|
||||
frameId: opts.frameId
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ReceiverSelectorMediaType.File: {
|
||||
const fileUrl = new URL(`file://${opts.selection.filePath}`);
|
||||
const { init } = await import("../cast/senders/media");
|
||||
|
||||
init({
|
||||
mediaUrl: fileUrl.href,
|
||||
receiver: opts.selection.receiverDevice
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
import logger from "../lib/logger";
|
||||
import options from "../lib/options";
|
||||
|
||||
import { stringify } from "../lib/utils";
|
||||
|
||||
import {
|
||||
ReceiverSelection,
|
||||
ReceiverSelectionActionType,
|
||||
ReceiverSelectorMediaType
|
||||
} from "./receiverSelector";
|
||||
} from "../types";
|
||||
|
||||
import ReceiverSelectorManager from "./receiverSelector/ReceiverSelectorManager";
|
||||
import CastManager from "../cast/CastManager";
|
||||
import { ReceiverSelection } from "./ReceiverSelector";
|
||||
|
||||
import selectorManager from "./selectorManager";
|
||||
import castManager from "./castManager";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
@@ -142,7 +142,7 @@ async function onMenuClicked(
|
||||
|
||||
let selection: Nullable<ReceiverSelection> = null;
|
||||
try {
|
||||
selection = await ReceiverSelectorManager.getSelection(
|
||||
selection = await selectorManager.getSelection(
|
||||
tab.id,
|
||||
info.frameId,
|
||||
{ withMediaSender: castMediaMenuClicked }
|
||||
@@ -160,7 +160,7 @@ async function onMenuClicked(
|
||||
}
|
||||
|
||||
if (castMenuClicked) {
|
||||
CastManager.loadSender({
|
||||
castManager.loadSender({
|
||||
tabId: tab.id,
|
||||
frameId: info.frameId,
|
||||
selection
|
||||
@@ -187,7 +187,7 @@ async function onMenuClicked(
|
||||
});
|
||||
} else {
|
||||
// Handle other responses
|
||||
CastManager.loadSender({
|
||||
castManager.loadSender({
|
||||
tabId: tab.id,
|
||||
frameId: info.frameId,
|
||||
selection
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { ReceiverDevice } from "../../types";
|
||||
|
||||
export enum ReceiverSelectorMediaType {
|
||||
None = 0,
|
||||
App = 1,
|
||||
Tab = 2,
|
||||
Screen = 4,
|
||||
File = 8
|
||||
}
|
||||
|
||||
export enum ReceiverSelectionActionType {
|
||||
Cast = 1,
|
||||
Stop = 2
|
||||
}
|
||||
|
||||
export interface ReceiverSelectionCast {
|
||||
actionType: ReceiverSelectionActionType.Cast;
|
||||
receiverDevice: ReceiverDevice;
|
||||
mediaType: ReceiverSelectorMediaType;
|
||||
filePath?: string;
|
||||
}
|
||||
export interface ReceiverSelectionStop {
|
||||
actionType: ReceiverSelectionActionType.Stop;
|
||||
receiverDevice: ReceiverDevice;
|
||||
}
|
||||
|
||||
export type ReceiverSelection = ReceiverSelectionCast | ReceiverSelectionStop;
|
||||
@@ -1,23 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
import options from "../../lib/options";
|
||||
import logger from "../../lib/logger";
|
||||
import options from "../lib/options";
|
||||
import logger from "../lib/logger";
|
||||
|
||||
import CastManager from "../../cast/CastManager";
|
||||
import { SessionRequest } from "../../cast/sdk/classes";
|
||||
import receiverDevices from "../receiverDevices";
|
||||
import { getMediaTypesForPageUrl } from "../lib/utils";
|
||||
import { SessionRequest } from "../cast/sdk/classes";
|
||||
|
||||
import { getMediaTypesForPageUrl } from "../../lib/utils";
|
||||
import castManager from "./castManager";
|
||||
import deviceManager from "./deviceManager";
|
||||
|
||||
import ReceiverSelector, {
|
||||
ReceiverSelection,
|
||||
ReceiverSelectionCast,
|
||||
ReceiverSelectionStop
|
||||
} from "./ReceiverSelector";
|
||||
|
||||
import {
|
||||
ReceiverSelection,
|
||||
ReceiverSelectionActionType,
|
||||
ReceiverSelectionCast,
|
||||
ReceiverSelectionStop,
|
||||
ReceiverSelectorMediaType
|
||||
} from "./index";
|
||||
|
||||
import ReceiverSelector from "./ReceiverSelector";
|
||||
} from "../types";
|
||||
|
||||
let sharedSelector: ReceiverSelector;
|
||||
async function getSelector() {
|
||||
@@ -46,12 +47,12 @@ async function getSelection(
|
||||
contextTabId: number,
|
||||
contextFrameId = 0,
|
||||
selectionOpts?: {
|
||||
sessionRequest: SessionRequest;
|
||||
sessionRequest?: SessionRequest;
|
||||
withMediaSender?: boolean;
|
||||
}
|
||||
): Promise<ReceiverSelection | null> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let castInstance = CastManager.getInstance(
|
||||
let castInstance = castManager.getInstance(
|
||||
contextTabId,
|
||||
contextFrameId
|
||||
);
|
||||
@@ -112,15 +113,12 @@ async function getSelection(
|
||||
sharedSelector = new ReceiverSelector();
|
||||
|
||||
function onReceiverChange() {
|
||||
sharedSelector.update(receiverDevices.getDevices());
|
||||
sharedSelector.update(deviceManager.getDevices());
|
||||
}
|
||||
|
||||
receiverDevices.addEventListener("receiverDeviceUp", onReceiverChange);
|
||||
receiverDevices.addEventListener(
|
||||
"receiverDeviceDown",
|
||||
onReceiverChange
|
||||
);
|
||||
receiverDevices.addEventListener(
|
||||
deviceManager.addEventListener("receiverDeviceUp", onReceiverChange);
|
||||
deviceManager.addEventListener("receiverDeviceDown", onReceiverChange);
|
||||
deviceManager.addEventListener(
|
||||
"receiverDeviceUpdated",
|
||||
onReceiverChange
|
||||
);
|
||||
@@ -139,7 +137,7 @@ async function getSelection(
|
||||
function onSelectorStop(ev: CustomEvent<ReceiverSelectionStop>) {
|
||||
logger.info("Stopping receiver app...", ev.detail);
|
||||
|
||||
receiverDevices.stopReceiverApp(ev.detail.receiverDevice.id);
|
||||
deviceManager.stopReceiverApp(ev.detail.receiverDevice.id);
|
||||
|
||||
removeListeners();
|
||||
resolve({
|
||||
@@ -172,25 +170,25 @@ async function getSelection(
|
||||
);
|
||||
sharedSelector.removeEventListener("error", onSelectorError);
|
||||
|
||||
receiverDevices.removeEventListener(
|
||||
deviceManager.removeEventListener(
|
||||
"receiverDeviceUp",
|
||||
onReceiverChange
|
||||
);
|
||||
receiverDevices.removeEventListener(
|
||||
deviceManager.removeEventListener(
|
||||
"receiverDeviceDown",
|
||||
onReceiverChange
|
||||
);
|
||||
receiverDevices.removeEventListener(
|
||||
deviceManager.removeEventListener(
|
||||
"receiverDeviceUpdated",
|
||||
onReceiverChange
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure status manager is initialized
|
||||
await receiverDevices.init();
|
||||
await deviceManager.init();
|
||||
|
||||
sharedSelector.open({
|
||||
receiverDevices: receiverDevices.getDevices(),
|
||||
receiverDevices: deviceManager.getDevices(),
|
||||
defaultMediaType,
|
||||
availableMediaTypes,
|
||||
appId: castInstance?.appId,
|
||||
Reference in New Issue
Block a user