Filter receiver list depending on capabilities in session request

This commit is contained in:
hensm
2022-04-25 16:01:10 +01:00
parent 4bccdecaa3
commit 234280f5ec
7 changed files with 67 additions and 25 deletions

View File

@@ -6,7 +6,7 @@ import { TypedEventTarget } from "../lib/TypedEventTarget";
import { Message, Port } from "../messaging"; import { Message, Port } from "../messaging";
import { ReceiverDevice, ReceiverDeviceCapabilities } from "../types"; import { ReceiverDevice, ReceiverDeviceCapabilities } from "../types";
import { ReceiverStatus } from "../cast/api/types"; import { ReceiverStatus } from "../cast/sdk/types";
interface EventMap { interface EventMap {
receiverDeviceUp: { deviceInfo: ReceiverDevice }; receiverDeviceUp: { deviceInfo: ReceiverDevice };
@@ -84,16 +84,6 @@ export default new (class extends TypedEventTarget<EventMap> {
case "main:receiverDeviceUp": { case "main:receiverDeviceUp": {
const { deviceId, deviceInfo } = message.data; 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.receiverDevices.set(deviceId, deviceInfo);
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("receiverDeviceUp", { new CustomEvent("receiverDeviceUp", {

View File

@@ -6,6 +6,7 @@ import options from "../../lib/options";
import { TypedEventTarget } from "../../lib/TypedEventTarget"; import { TypedEventTarget } from "../../lib/TypedEventTarget";
import { ReceiverDevice } from "../../types"; import { ReceiverDevice } from "../../types";
import { SessionRequest } from "../../cast/sdk/classes";
import { import {
ReceiverSelectionCast, ReceiverSelectionCast,
@@ -26,6 +27,7 @@ export interface PageInfo {
url: string; url: string;
tabId: number; tabId: number;
frameId: number; frameId: number;
sessionRequest?: SessionRequest;
} }
/** /**

View File

@@ -4,6 +4,7 @@ import options from "../../lib/options";
import logger from "../../lib/logger"; import logger from "../../lib/logger";
import CastManager from "../../cast/CastManager"; import CastManager from "../../cast/CastManager";
import { SessionRequest } from "../../cast/sdk/classes";
import receiverDevices from "../receiverDevices"; import receiverDevices from "../receiverDevices";
import { getMediaTypesForPageUrl } from "../../lib/utils"; import { getMediaTypesForPageUrl } from "../../lib/utils";
@@ -47,7 +48,10 @@ async function getSelector() {
async function getSelection( async function getSelection(
contextTabId: number, contextTabId: number,
contextFrameId = 0, contextFrameId = 0,
selectionOpts?: { withMediaSender?: boolean } selectionOpts?: {
sessionRequest: SessionRequest;
withMediaSender?: boolean;
}
): Promise<ReceiverSelection | null> { ): Promise<ReceiverSelection | null> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let castInstance = CastManager.getInstance( let castInstance = CastManager.getInstance(
@@ -220,7 +224,8 @@ async function getSelection(
? { ? {
url: pageUrl, url: pageUrl,
tabId: contextTabId, tabId: contextTabId,
frameId: contextFrameId frameId: contextFrameId,
sessionRequest: selectionOpts?.sessionRequest
} }
: undefined; : undefined;

View File

@@ -227,7 +227,8 @@ export default new (class CastManager {
const selection = const selection =
await ReceiverSelectorManager.getSelection( await ReceiverSelectorManager.getSelection(
instance.contentTabId, instance.contentTabId,
instance.contentFrameId instance.contentFrameId,
{ sessionRequest: message.data.sessionRequest }
); );
// Handle cancellation // Handle cancellation

View File

@@ -466,7 +466,8 @@ export default class {
} else { } else {
// Open receiver selector UI // Open receiver selector UI
sendMessageResponse({ sendMessageResponse({
subject: "main:selectReceiver" subject: "main:selectReceiver",
data: { sessionRequest: this.#sessionRequest }
}); });
} }
} }

View File

@@ -17,6 +17,7 @@ import {
ReceiverStatus, ReceiverStatus,
SenderMessage SenderMessage
} from "./cast/sdk/types"; } from "./cast/sdk/types";
import { SessionRequest } from "./cast/sdk/classes";
import { ReceiverDevice } from "./types"; import { ReceiverDevice } from "./types";
@@ -56,7 +57,9 @@ type ExtMessageDefinitions = {
"receiverSelector:selected": ReceiverSelection; "receiverSelector:selected": ReceiverSelection;
"receiverSelector:stop": ReceiverSelection; "receiverSelector:stop": ReceiverSelection;
"main:selectReceiver": {}; "main:selectReceiver": {
sessionRequest: SessionRequest;
};
"cast:selectReceiver/selected": ReceiverSelectionCast; "cast:selectReceiver/selected": ReceiverSelectionCast;
"cast:selectReceiver/stopped": ReceiverSelectionStop; "cast:selectReceiver/stopped": ReceiverSelectionStop;
"cast:selectReceiver/cancelled": {}; "cast:selectReceiver/cancelled": {};

View File

@@ -11,7 +11,7 @@ import messaging, { Message, Port } from "../../messaging";
import { getNextEllipsis } from "../../lib/utils"; import { getNextEllipsis } from "../../lib/utils";
import { RemoteMatchPattern } from "../../lib/matchPattern"; import { RemoteMatchPattern } from "../../lib/matchPattern";
import { ReceiverDevice } from "../../types"; import { ReceiverDevice, ReceiverDeviceCapabilities } from "../../types";
import { Capability } from "../../cast/sdk/enums"; import { Capability } from "../../cast/sdk/enums";
import { 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 PopupAppProps {}
interface PopupAppState { interface PopupAppState {
receiverDevices: ReceiverDevice[]; receiverDevices: ReceiverDevice[];
@@ -114,12 +146,26 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
case "popup:update": { case "popup:update": {
const { const {
receiverDevices: receivers, receiverDevices,
availableMediaTypes, availableMediaTypes,
defaultMediaType defaultMediaType
} = message.data; } = 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 ( if (
availableMediaTypes !== undefined && availableMediaTypes !== undefined &&
@@ -543,9 +589,3 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
window.addEventListener("load", () => { window.addEventListener("load", () => {
ReactDOM.render(<PopupApp />, document.querySelector("#root")); ReactDOM.render(<PopupApp />, document.querySelector("#root"));
}); });
window.addEventListener("contextmenu", () => {
browser.menus.overrideContext({
showDefaults: false
});
});