Add availableMediaTypes bitmask to receiver selector open method

This commit is contained in:
hensm
2019-07-09 10:56:55 +01:00
parent 43fcd5b351
commit 70e05566fa
14 changed files with 100 additions and 29 deletions

View File

@@ -66,14 +66,43 @@ class ViewController : NSViewController {
self.mediaTypePopUpButton = NSPopUpButton() self.mediaTypePopUpButton = NSPopUpButton()
self.mediaTypePopUpButton.autoenablesItems = false
self.mediaTypePopUpButton.addItems(withTitles: [ self.mediaTypePopUpButton.addItems(withTitles: [
initData.i18n_mediaTypeApp initData.i18n_mediaTypeApp
, initData.i18n_mediaTypeTab , initData.i18n_mediaTypeTab
, initData.i18n_mediaTypeScreen , initData.i18n_mediaTypeScreen
]) ])
let appItem = self.mediaTypePopUpButton
.item(withTitle: initData.i18n_mediaTypeApp)!
let tabItem = self.mediaTypePopUpButton
.item(withTitle: initData.i18n_mediaTypeTab)!
let screenItem = self.mediaTypePopUpButton
.item(withTitle: initData.i18n_mediaTypeScreen)!
// Set tags to enum value
appItem.tag = MediaType.app.rawValue
tabItem.tag = MediaType.tab.rawValue
screenItem.tag = MediaType.screen.rawValue
if (initData.availableMediaTypes & appItem.tag) == 0 {
self.mediaTypePopUpButton
.item(withTitle: initData.i18n_mediaTypeApp)?
.isEnabled = false
}
if (initData.availableMediaTypes & tabItem.tag) == 0 {
self.mediaTypePopUpButton
.item(withTitle: initData.i18n_mediaTypeTab)?
.isEnabled = false
}
if (initData.availableMediaTypes & screenItem.tag) == 0 {
self.mediaTypePopUpButton
.item(withTitle: initData.i18n_mediaTypeScreen)?
.isEnabled = false
}
self.mediaTypePopUpButton.selectItem( self.mediaTypePopUpButton.selectItem(
at: initData.defaultMediaType.rawValue) withTag: initData.defaultMediaType.rawValue)
let mediaTypeStackView = NSStackView(views: [ let mediaTypeStackView = NSStackView(views: [
@@ -140,7 +169,7 @@ extension ViewController : ReceiverViewDelegate {
do { do {
let mediaType = MediaType( let mediaType = MediaType(
rawValue: self.mediaTypePopUpButton.indexOfSelectedItem)! rawValue: self.mediaTypePopUpButton.selectedItem!.tag)!
let selection = ReceiverSelection( let selection = ReceiverSelection(
receiver: receiver receiver: receiver

View File

@@ -1,6 +1,7 @@
struct InitData : Codable { struct InitData : Codable {
let receivers: [Receiver] let receivers: [Receiver]
let defaultMediaType: MediaType let defaultMediaType: MediaType
let availableMediaTypes: Int
let i18n_extensionName: String let i18n_extensionName: String
let i18n_castButtonTitle: String let i18n_castButtonTitle: String

View File

@@ -1,3 +1,8 @@
enum MediaType : Int, Codable { import Foundation
case app, tab, screen
enum MediaType: Int, Codable {
case app = 1
case tab = 2
case screen = 4
} }

3
ext/src/global.d.ts vendored
View File

@@ -37,7 +37,8 @@ declare interface RTCPeerConnection {
} }
declare interface MediaDevices { declare interface MediaDevices {
getDisplayMedia(constraints: MediaStreamConstraints): Promise<MediaStream>; getDisplayMedia (constraints: MediaStreamConstraints)
: Promise<MediaStream>;
} }

View File

@@ -541,7 +541,7 @@ async function initCreateStatusBridge (opts: Options) {
*/ */
function onStatusBridgeDisconnect () { function onStatusBridgeDisconnect () {
// Notify shims for receiver availability // Notify shims for receiver availability
for (const [ , receiver ] of statusBridgeReceivers) { for (const [, receiver ] of statusBridgeReceivers) {
for (const [, shim ] of shimMap) { for (const [, shim ] of shimMap) {
shim.port.postMessage({ shim.port.postMessage({
subject: "shim:/serviceDown" subject: "shim:/serviceDown"
@@ -752,7 +752,8 @@ async function onConnectShim (port: browser.runtime.Port) {
case "main:/selectReceiverBegin": { case "main:/selectReceiverBegin": {
receiverSelector.open( receiverSelector.open(
Array.from(statusBridgeReceivers.values()) Array.from(statusBridgeReceivers.values())
, message.data.defaultMediaType); , message.data.defaultMediaType
, message.data.availableMediaTypes);
break; break;
} }

View File

@@ -28,7 +28,8 @@ export default class NativeMacReceiverSelector
public async open ( public async open (
receivers: Receiver[] receivers: Receiver[]
, defaultMediaType: ReceiverSelectorMediaType): Promise<void> { , defaultMediaType: ReceiverSelectorMediaType
, availableMediaTypes: ReceiverSelectorMediaType): Promise<void> {
const applicationName = await options.get("bridgeApplicationName"); const applicationName = await options.get("bridgeApplicationName");
this.bridgePort = nativeMessaging.connectNative(applicationName); this.bridgePort = nativeMessaging.connectNative(applicationName);
@@ -62,6 +63,7 @@ export default class NativeMacReceiverSelector
, data: JSON.stringify({ , data: JSON.stringify({
receivers receivers
, defaultMediaType , defaultMediaType
, availableMediaTypes
, i18n_extensionName: _("extensionName") , i18n_extensionName: _("extensionName")
, i18n_castButtonTitle: _("popupCastButtonTitle") , i18n_castButtonTitle: _("popupCastButtonTitle")

View File

@@ -17,6 +17,7 @@ export default class PopupReceiverSelector
private receivers: Receiver[]; private receivers: Receiver[];
private defaultMediaType: ReceiverSelectorMediaType; private defaultMediaType: ReceiverSelectorMediaType;
private availableMediaTypes: ReceiverSelectorMediaType;
private wasReceiverSelected: boolean = false; private wasReceiverSelected: boolean = false;
@@ -53,6 +54,7 @@ export default class PopupReceiverSelector
, data: { , data: {
receivers: this.receivers receivers: this.receivers
, defaultMediaType: this.defaultMediaType , defaultMediaType: this.defaultMediaType
, availableMediaTypes: this.availableMediaTypes
} }
}); });
}); });
@@ -61,7 +63,8 @@ export default class PopupReceiverSelector
public async open ( public async open (
receivers: Receiver[] receivers: Receiver[]
, defaultMediaType: ReceiverSelectorMediaType): Promise<void> { , defaultMediaType: ReceiverSelectorMediaType
, availableMediaTypes: ReceiverSelectorMediaType): Promise<void> {
// If popup already exists, close it // If popup already exists, close it
if (this.windowId) { if (this.windowId) {
@@ -70,6 +73,7 @@ export default class PopupReceiverSelector
this.receivers = receivers; this.receivers = receivers;
this.defaultMediaType = defaultMediaType; this.defaultMediaType = defaultMediaType;
this.availableMediaTypes = availableMediaTypes;
// Current window to base centered position on // Current window to base centered position on
const openerWindow = await browser.windows.getCurrent(); const openerWindow = await browser.windows.getCurrent();

View File

@@ -4,9 +4,9 @@ import { Receiver } from "../types";
export enum ReceiverSelectorMediaType { export enum ReceiverSelectorMediaType {
App App = 1
, Tab , Tab = 2
, Screen , Screen = 4
} }
export interface ReceiverSelection { export interface ReceiverSelection {
@@ -21,7 +21,8 @@ export type ReceiverSelectorCancelledEvent = CustomEvent;
export default interface ReceiverSelector extends EventTarget { export default interface ReceiverSelector extends EventTarget {
open (receivers: Receiver[] open (receivers: Receiver[]
, defaultMediaType: ReceiverSelectorMediaType): void; , defaultMediaType: ReceiverSelectorMediaType
, availableMediaTypes: ReceiverSelectorMediaType): void;
close (): void; close (): void;
} }

View File

@@ -22,6 +22,21 @@ let peerConnection: RTCPeerConnection;
let drawWindowIntervalId: number; let drawWindowIntervalId: number;
let availableMediaTypes =
ReceiverSelectorMediaType.Screen
| ReceiverSelectorMediaType.Tab;
/**
* Remove "Screen" option when on an insecure origin as
* MediaDevices.getDisplayMedia will not exist (and legacy
* MediaDevices.getUserMedia mediaSource constraint will
* fail).
*/
if (typeof navigator.mediaDevices.getDisplayMedia === "undefined") {
availableMediaTypes &= ~ReceiverSelectorMediaType.Screen;
}
/** /**
* Sends a message to the fx_cast app running on the * Sends a message to the fx_cast app running on the
* receiver device. * receiver device.
@@ -70,7 +85,6 @@ async function onRequestSessionSuccess (
switch (newSelectedMedia) { switch (newSelectedMedia) {
case ReceiverSelectorMediaType.Tab: { case ReceiverSelectorMediaType.Tab: {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
@@ -118,7 +132,6 @@ async function onRequestSessionSuccess (
} }
case ReceiverSelectorMediaType.Screen: { case ReceiverSelectorMediaType.Screen: {
const stream = await navigator.mediaDevices.getDisplayMedia({ const stream = await navigator.mediaDevices.getDisplayMedia({
video: { cursor: "motion" } video: { cursor: "motion" }
, audio: false , audio: false
@@ -142,8 +155,11 @@ async function onRequestSessionSuccess (
function receiverListener (availability: string) { function receiverListener (availability: string) {
cast.logMessage("receiverListener"); cast.logMessage("receiverListener");
if (!wasSessionRequested if (wasSessionRequested) {
&& availability === cast.ReceiverAvailability.AVAILABLE) { return;
}
if (availability === cast.ReceiverAvailability.AVAILABLE) {
wasSessionRequested = true; wasSessionRequested = true;
cast.requestSession( cast.requestSession(
onRequestSessionSuccess onRequestSessionSuccess
@@ -181,7 +197,8 @@ init().then(async bridgeInfo => {
, sessionListener , sessionListener
, receiverListener , receiverListener
, undefined, undefined , undefined, undefined
, selectedMedia); , selectedMedia
, availableMediaTypes);
cast.initialize(apiConfig cast.initialize(apiConfig
, onInitializeSuccess , onInitializeSuccess

View File

@@ -26,7 +26,11 @@ export default class ApiConfig {
= DefaultActionPolicy.CREATE_SESSION = DefaultActionPolicy.CREATE_SESSION
// TODO: Remove awful hack for mirror casting // TODO: Remove awful hack for mirror casting
, public _selectedMedia: ReceiverSelectorMediaType , public _defaultMediaType: ReceiverSelectorMediaType
= ReceiverSelectorMediaType.App) { = ReceiverSelectorMediaType.App
, public _availableMediaTypes: ReceiverSelectorMediaType
= ReceiverSelectorMediaType.App
| ReceiverSelectorMediaType.Tab
| ReceiverSelectorMediaType.Screen) {
} }
} }

View File

@@ -160,7 +160,8 @@ export function requestSession (
sendMessageResponse({ sendMessageResponse({
subject: "main:/selectReceiverBegin" subject: "main:/selectReceiverBegin"
, data: { , data: {
defaultMediaType: apiConfig._selectedMedia defaultMediaType: apiConfig._defaultMediaType
, availableMediaTypes: apiConfig._availableMediaTypes
} }
}); });
} }

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
import { onMessageResponse, sendMessage } from "./eventMessageChannel";
import { loadScript } from "../lib/utils"; import { loadScript } from "../lib/utils";
import { onMessageResponse, sendMessage } from "./eventMessageChannel";
const { isFramework } const { isFramework }

View File

@@ -28,6 +28,7 @@ browser.runtime.getPlatformInfo()
interface PopupAppState { interface PopupAppState {
receivers: Receiver[]; receivers: Receiver[];
mediaType: ReceiverSelectorMediaType; mediaType: ReceiverSelectorMediaType;
availableMediaTypes: ReceiverSelectorMediaType;
isLoading: boolean; isLoading: boolean;
} }
@@ -41,6 +42,7 @@ class PopupApp extends Component<{}, PopupAppState> {
this.state = { this.state = {
receivers: [] receivers: []
, mediaType: ReceiverSelectorMediaType.App , mediaType: ReceiverSelectorMediaType.App
, availableMediaTypes: ReceiverSelectorMediaType.App
, isLoading: false , isLoading: false
}; };
@@ -64,6 +66,7 @@ class PopupApp extends Component<{}, PopupAppState> {
this.setState({ this.setState({
receivers: message.data.receivers receivers: message.data.receivers
, mediaType: message.data.defaultMediaType , mediaType: message.data.defaultMediaType
, availableMediaTypes: message.data.availableMediaTypes
}); });
break; break;
@@ -90,10 +93,6 @@ class PopupApp extends Component<{}, PopupAppState> {
} }
public render () { public render () {
const shareMedia =
this.state.mediaType === ReceiverSelectorMediaType.Tab
|| this.state.mediaType === ReceiverSelectorMediaType.Screen;
return ( return (
<div> <div>
<div className="media-select"> <div className="media-select">
@@ -102,15 +101,18 @@ class PopupApp extends Component<{}, PopupAppState> {
onChange={ this.onSelectChange } onChange={ this.onSelectChange }
className="media-select-dropdown"> className="media-select-dropdown">
<option value={ ReceiverSelectorMediaType.App } <option value={ ReceiverSelectorMediaType.App }
disabled={ shareMedia }> disabled={ !(this.state.availableMediaTypes
& ReceiverSelectorMediaType.App) }>
{ _("popupMediaTypeApp") } { _("popupMediaTypeApp") }
</option> </option>
<option value={ ReceiverSelectorMediaType.Tab } <option value={ ReceiverSelectorMediaType.Tab }
disabled={ !shareMedia }> disabled={ !(this.state.availableMediaTypes
& ReceiverSelectorMediaType.Tab) }>
{ _("popupMediaTypeTab") } { _("popupMediaTypeTab") }
</option> </option>
<option value={ ReceiverSelectorMediaType.Screen } <option value={ ReceiverSelectorMediaType.Screen }
disabled={ !shareMedia }> disabled={ !(this.state.availableMediaTypes
& ReceiverSelectorMediaType.Screen) }>
{ _("popupMediaTypeScreen") } { _("popupMediaTypeScreen") }
</option> </option>
</select> </select>

View File

@@ -2,4 +2,7 @@
"extends": [ "extends": [
"../common/tslint.json" "../common/tslint.json"
] ]
, "rules": {
"no-bitwise": false
}
} }