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 { 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<EventMap> {
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", {

View File

@@ -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;
}
/**

View File

@@ -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<ReceiverSelection | null> {
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;

View File

@@ -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

View File

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

View File

@@ -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": {};

View File

@@ -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<PopupAppProps, PopupAppState> {
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<ReceiverEntryProps, ReceiverEntryState> {
window.addEventListener("load", () => {
ReactDOM.render(<PopupApp />, document.querySelector("#root"));
});
window.addEventListener("contextmenu", () => {
browser.menus.overrideContext({
showDefaults: false
});
});