diff --git a/ext/src/background/castManager.ts b/ext/src/background/castManager.ts index 14599a6..c2980a2 100644 --- a/ext/src/background/castManager.ts +++ b/ext/src/background/castManager.ts @@ -20,6 +20,7 @@ import { import type { ApiConfig } from "../cast/sdk/classes"; import { ReceiverAction } from "../cast/sdk/enums"; +import { DEFAULT_MEDIA_RECEIVER_APP_ID } from "../cast/sdk/media"; import { createReceiver } from "../cast/utils"; import deviceManager from "./deviceManager"; @@ -301,10 +302,10 @@ const castManager = new (class { if ( receiverSelector?.isOpen && // If selector context is the same as the instance context - receiverSelector.pageInfo?.tabId === - instance.contentContext?.tabId && - receiverSelector.pageInfo?.frameId === - instance.contentContext?.frameId && + isSameContext( + receiverSelector.pageInfo, + instance.contentContext + ) && // If selector is supposed to close (await options.get("receiverSelectorWaitForConnection")) ) { @@ -566,17 +567,48 @@ async function getReceiverSelection(selectionOpts: { let availableMediaTypes = ReceiverSelectorMediaType.None; // Default frame ID - if (!selectionOpts.frameId) selectionOpts.frameId = 0; + if (selectionOpts.frameId === undefined) selectionOpts.frameId = 0; // Fallback to instance context - if (!selectionOpts.tabId && selectionOpts.castInstance?.contentContext) { + if ( + selectionOpts.tabId === undefined && + selectionOpts.castInstance?.contentContext + ) { selectionOpts.tabId = selectionOpts.castInstance.contentContext.tabId; selectionOpts.frameId = selectionOpts.castInstance.contentContext.frameId; } + const opts = await options.getAll(); + + /** + * If context supplied, but no instance, check for an instance at + * that context. + */ + if ( + !selectionOpts.castInstance && + selectionOpts.tabId !== undefined && + selectionOpts.frameId !== undefined + ) { + const contextInstance = castManager.getInstanceAt( + selectionOpts.tabId, + selectionOpts.frameId + ); + /** + * If the app in that context is the extension mirroring app or + * the default receiver, just ignore it. + */ + const contextAppId = contextInstance?.apiConfig?.sessionRequest.appId; + if ( + contextAppId !== opts.mirroringAppId && + contextAppId !== DEFAULT_MEDIA_RECEIVER_APP_ID + ) { + selectionOpts.castInstance = contextInstance; + } + } + let pageInfo: Optional; - if (selectionOpts.tabId) { + if (selectionOpts.tabId !== undefined) { try { pageInfo = { tabId: selectionOpts.tabId, @@ -603,8 +635,6 @@ async function getReceiverSelection(selectionOpts: { availableMediaTypes |= ReceiverSelectorMediaType.App; } - const opts = await options.getAll(); - // Disable mirroring media types if mirroring is not enabled if (!opts.mirroringEnabled) { availableMediaTypes &= ~( diff --git a/ext/src/cast/senders/media.ts b/ext/src/cast/senders/media.ts index 12265ad..01d4efd 100644 --- a/ext/src/cast/senders/media.ts +++ b/ext/src/cast/senders/media.ts @@ -5,10 +5,10 @@ import type { Message } from "../../messaging"; // Cast types import { Capability, ReceiverAvailability } from "../sdk/enums"; +import { Media, PlayerState } from "../sdk/media"; import type Session from "../sdk/Session"; import cast, { ensureInit, CastPort } from "../export"; -import { Media, PlayerState } from "../sdk/media"; const logger = new Logger("fx_cast [media sender]"); diff --git a/ext/src/cast/senders/mirroring.ts b/ext/src/cast/senders/mirroring.ts index b2237b8..9e3be18 100644 --- a/ext/src/cast/senders/mirroring.ts +++ b/ext/src/cast/senders/mirroring.ts @@ -5,9 +5,10 @@ import { Logger } from "../../lib/logger"; import { ReceiverDevice, ReceiverSelectorMediaType } from "../../types"; -import type Session from "../sdk/Session"; -import cast, { ensureInit } from "../export"; import type { ReceiverAvailability } from "../sdk/enums"; +import type Session from "../sdk/Session"; + +import cast, { ensureInit } from "../export"; const logger = new Logger("fx_cast [mirroring sender]"); @@ -49,7 +50,7 @@ class MirroringSender { private async init() { try { - ensureInit({ + await ensureInit({ contextTabId: this.contextTabId, receiverDevice: this.receiverDevice }); diff --git a/ext/src/ui/popup/Popup.svelte b/ext/src/ui/popup/Popup.svelte index adb473a..a54e6ce 100644 --- a/ext/src/ui/popup/Popup.svelte +++ b/ext/src/ui/popup/Popup.svelte @@ -67,19 +67,37 @@ * Checks if device is compatible with the requested app and * capabilities. */ - function isDeviceCompatible(device: ReceiverDevice) { - // If device is audio-only, check app's audio support flag - if ( - !(device.capabilities & ReceiverDeviceCapabilities.VIDEO_OUT) && - appInfo?.isRequestAppAudioCompatible === false - ) { - return false; + function isDeviceCompatible( + mediaType: ReceiverSelectorMediaType, + device: ReceiverDevice + ) { + switch (mediaType) { + case ReceiverSelectorMediaType.App: + // If device is audio-only, check app's audio support flag + if ( + !( + device.capabilities & + ReceiverDeviceCapabilities.VIDEO_OUT + ) && + appInfo?.isRequestAppAudioCompatible === false + ) { + return false; + } + + return hasRequiredCapabilities( + device, + appInfo?.sessionRequest?.capabilities + ); + + /** Mirroring requires video output capability. */ + case ReceiverSelectorMediaType.Tab: + case ReceiverSelectorMediaType.Screen: + return !!( + device.capabilities & ReceiverDeviceCapabilities.VIDEO_OUT + ); } - return hasRequiredCapabilities( - device, - appInfo?.sessionRequest?.capabilities - ); + return false; } let port: Nullable = null; @@ -365,7 +383,7 @@ {isMediaTypeAvailable} isAnyMediaTypeAvailable={availableMediaTypes !== ReceiverSelectorMediaType.None && - isDeviceCompatible(device)} + isDeviceCompatible(mediaType, device)} isAnyConnecting={isConnecting} bind:lastMenuShownDeviceId on:cast={ev => onReceiverCast(ev.detail.device)}