diff --git a/ext/src/background/receiverDevices.ts b/ext/src/background/receiverDevices.ts index 6182bde..5c19e1b 100644 --- a/ext/src/background/receiverDevices.ts +++ b/ext/src/background/receiverDevices.ts @@ -6,7 +6,7 @@ import { TypedEventTarget } from "../lib/TypedEventTarget"; import { Message, Port } from "../messaging"; import { ReceiverDevice, ReceiverDeviceCapabilities } from "../types"; -import { ReceiverStatus } from "../cast/api/types"; +import { ReceiverStatus } from "../cast/sdk/types"; interface EventMap { receiverDeviceUp: { deviceInfo: ReceiverDevice }; @@ -84,16 +84,6 @@ export default new (class extends TypedEventTarget { case "main:receiverDeviceUp": { const { deviceId, deviceInfo } = message.data; - // TODO: Add proper support for Chromecast Audio devices - if ( - !( - deviceInfo.capabilities & - ReceiverDeviceCapabilities.VIDEO_OUT - ) - ) { - break; - } - this.receiverDevices.set(deviceId, deviceInfo); this.dispatchEvent( new CustomEvent("receiverDeviceUp", { diff --git a/ext/src/background/receiverSelector/ReceiverSelector.ts b/ext/src/background/receiverSelector/ReceiverSelector.ts index 72540c0..189e396 100644 --- a/ext/src/background/receiverSelector/ReceiverSelector.ts +++ b/ext/src/background/receiverSelector/ReceiverSelector.ts @@ -6,6 +6,7 @@ import options from "../../lib/options"; import { TypedEventTarget } from "../../lib/TypedEventTarget"; import { ReceiverDevice } from "../../types"; +import { SessionRequest } from "../../cast/sdk/classes"; import { ReceiverSelectionCast, @@ -26,6 +27,7 @@ export interface PageInfo { url: string; tabId: number; frameId: number; + sessionRequest?: SessionRequest; } /** diff --git a/ext/src/background/receiverSelector/ReceiverSelectorManager.ts b/ext/src/background/receiverSelector/ReceiverSelectorManager.ts index 7564ac4..a7643bd 100644 --- a/ext/src/background/receiverSelector/ReceiverSelectorManager.ts +++ b/ext/src/background/receiverSelector/ReceiverSelectorManager.ts @@ -4,6 +4,7 @@ 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"; @@ -47,7 +48,10 @@ async function getSelector() { async function getSelection( contextTabId: number, contextFrameId = 0, - selectionOpts?: { withMediaSender?: boolean } + selectionOpts?: { + sessionRequest: SessionRequest; + withMediaSender?: boolean; + } ): Promise { return new Promise(async (resolve, reject) => { let castInstance = CastManager.getInstance( @@ -220,7 +224,8 @@ async function getSelection( ? { url: pageUrl, tabId: contextTabId, - frameId: contextFrameId + frameId: contextFrameId, + sessionRequest: selectionOpts?.sessionRequest } : undefined; diff --git a/ext/src/cast/CastManager.ts b/ext/src/cast/CastManager.ts index 24ee04a..db2b57d 100644 --- a/ext/src/cast/CastManager.ts +++ b/ext/src/cast/CastManager.ts @@ -227,7 +227,8 @@ export default new (class CastManager { const selection = await ReceiverSelectorManager.getSelection( instance.contentTabId, - instance.contentFrameId + instance.contentFrameId, + { sessionRequest: message.data.sessionRequest } ); // Handle cancellation diff --git a/ext/src/cast/sdk/index.ts b/ext/src/cast/sdk/index.ts index e48f840..237dd0c 100644 --- a/ext/src/cast/sdk/index.ts +++ b/ext/src/cast/sdk/index.ts @@ -466,7 +466,8 @@ export default class { } else { // Open receiver selector UI sendMessageResponse({ - subject: "main:selectReceiver" + subject: "main:selectReceiver", + data: { sessionRequest: this.#sessionRequest } }); } } diff --git a/ext/src/messaging.ts b/ext/src/messaging.ts index eebe292..c29ffb2 100644 --- a/ext/src/messaging.ts +++ b/ext/src/messaging.ts @@ -17,6 +17,7 @@ import { ReceiverStatus, SenderMessage } from "./cast/sdk/types"; +import { SessionRequest } from "./cast/sdk/classes"; import { ReceiverDevice } from "./types"; @@ -56,7 +57,9 @@ type ExtMessageDefinitions = { "receiverSelector:selected": ReceiverSelection; "receiverSelector:stop": ReceiverSelection; - "main:selectReceiver": {}; + "main:selectReceiver": { + sessionRequest: SessionRequest; + }; "cast:selectReceiver/selected": ReceiverSelectionCast; "cast:selectReceiver/stopped": ReceiverSelectionStop; "cast:selectReceiver/cancelled": {}; diff --git a/ext/src/ui/popup/index.tsx b/ext/src/ui/popup/index.tsx index f6efdb2..feb59e0 100755 --- a/ext/src/ui/popup/index.tsx +++ b/ext/src/ui/popup/index.tsx @@ -11,7 +11,7 @@ import messaging, { Message, Port } from "../../messaging"; import { getNextEllipsis } from "../../lib/utils"; import { RemoteMatchPattern } from "../../lib/matchPattern"; -import { ReceiverDevice } from "../../types"; +import { ReceiverDevice, ReceiverDeviceCapabilities } from "../../types"; import { Capability } from "../../cast/sdk/enums"; import { @@ -32,6 +32,38 @@ browser.runtime.getPlatformInfo().then(platformInfo => { } }); +/** + * Check receiver device capabilities bitflags against array of + * capability strings requested by the sender application. + */ +function hasRequiredCapabilities( + receiverDevice: ReceiverDevice, + capabilities: Capability[] = [] +) { + const { capabilities: deviceCapabilities } = receiverDevice; + return capabilities.every(capability => { + switch (capability) { + case Capability.AUDIO_IN: + return deviceCapabilities & ReceiverDeviceCapabilities.AUDIO_IN; + case Capability.AUDIO_OUT: + return ( + deviceCapabilities & ReceiverDeviceCapabilities.AUDIO_OUT + ); + case Capability.MULTIZONE_GROUP: + return ( + deviceCapabilities & + ReceiverDeviceCapabilities.MULTIZONE_GROUP + ); + case Capability.VIDEO_IN: + return deviceCapabilities & ReceiverDeviceCapabilities.VIDEO_IN; + case Capability.VIDEO_OUT: + return ( + deviceCapabilities & ReceiverDeviceCapabilities.VIDEO_OUT + ); + } + }); +} + interface PopupAppProps {} interface PopupAppState { receiverDevices: ReceiverDevice[]; @@ -114,12 +146,26 @@ class PopupApp extends Component { case "popup:update": { const { - receiverDevices: receivers, + receiverDevices, availableMediaTypes, defaultMediaType } = message.data; - this.setState({ receiverDevices: receivers }); + this.setState({ + /** + * Filter receiver devices without the required + * capabilities. + */ + receiverDevices: receiverDevices.filter( + receiverDevice => { + return hasRequiredCapabilities( + receiverDevice, + this.state.pageInfo?.sessionRequest + ?.capabilities + ); + } + ) + }); if ( availableMediaTypes !== undefined && @@ -543,9 +589,3 @@ class ReceiverEntry extends Component { window.addEventListener("load", () => { ReactDOM.render(, document.querySelector("#root")); }); - -window.addEventListener("contextmenu", () => { - browser.menus.overrideContext({ - showDefaults: false - }); -});