mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
WIP
This commit is contained in:
@@ -355,6 +355,15 @@
|
||||
"description": "Media stop on unload checkbox label."
|
||||
},
|
||||
|
||||
"optionsMediaMirroringEnabled": {
|
||||
"message": "Enable media mirroring",
|
||||
"description": "Media mirroring enabled checkbox label."
|
||||
},
|
||||
"optionsMediaMirroringEnabledDescription": {
|
||||
"message": "Use a screen mirroring connection as a fallback to cast certain kinds of video content.",
|
||||
"description": "Media mirroring enabled option description."
|
||||
},
|
||||
|
||||
"optionsLocalMediaCategoryName": {
|
||||
"message": "Local media casting",
|
||||
"description": "Options page local media category title."
|
||||
|
||||
@@ -398,6 +398,12 @@ const castManager = new (class {
|
||||
}
|
||||
|
||||
try {
|
||||
const mirroringAppId = await options.get("mirroringAppId");
|
||||
const requestedMediaType =
|
||||
sessionRequest.appId === mirroringAppId
|
||||
? ReceiverSelectorMediaType.Screen
|
||||
: ReceiverSelectorMediaType.App;
|
||||
|
||||
const selection = await getReceiverSelection({
|
||||
castInstance: instance
|
||||
});
|
||||
@@ -416,7 +422,7 @@ const castManager = new (class {
|
||||
* been changed, we need to cancel the current
|
||||
* sender and switch it out for the right one.
|
||||
*/
|
||||
if (selection.mediaType !== ReceiverSelectorMediaType.App) {
|
||||
if (selection.mediaType !== requestedMediaType) {
|
||||
instance.contentPort.postMessage({
|
||||
subject: "cast:sessionRequestCancelled"
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ const whitelistChildMenuPatterns = new Map<MenuId, string>();
|
||||
export async function initMenus() {
|
||||
logger.info("init (menus)");
|
||||
|
||||
const opts = await options.getAll();
|
||||
let opts = await options.getAll();
|
||||
|
||||
// Global "Cast..." menu item
|
||||
menuIdCast = browser.menus.create({
|
||||
@@ -39,15 +39,25 @@ export async function initMenus() {
|
||||
icons: { "16": "icons/icon.svg" } // browser_action context
|
||||
});
|
||||
|
||||
function createCastMediaMenu() {
|
||||
let targetUrlPatterns: Optional<string[]>;
|
||||
if (!opts.mediaMirroringEnabled) {
|
||||
targetUrlPatterns = opts.localMediaEnabled
|
||||
? URL_PATTERNS_ALL
|
||||
: URL_PATTERNS_REMOTE;
|
||||
}
|
||||
|
||||
return browser.menus.create({
|
||||
id: "media",
|
||||
contexts: ["audio", "video", "image"],
|
||||
title: _("contextCast"),
|
||||
visible: opts.mediaEnabled,
|
||||
targetUrlPatterns: targetUrlPatterns
|
||||
});
|
||||
}
|
||||
|
||||
// <video>/<audio> "Cast..." context menu item
|
||||
menuIdCastMedia = browser.menus.create({
|
||||
contexts: ["audio", "video", "image"],
|
||||
title: _("contextCast"),
|
||||
visible: opts.mediaEnabled,
|
||||
targetUrlPatterns: opts.localMediaEnabled
|
||||
? URL_PATTERNS_ALL
|
||||
: URL_PATTERNS_REMOTE
|
||||
});
|
||||
menuIdCastMedia = createCastMediaMenu();
|
||||
|
||||
menuIdWhitelist = browser.menus.create({
|
||||
contexts: ["browser_action"],
|
||||
@@ -118,20 +128,21 @@ export async function initMenus() {
|
||||
|
||||
options.addEventListener("changed", async ev => {
|
||||
const alteredOpts = ev.detail;
|
||||
const newOpts = await options.getAll();
|
||||
opts = await options.getAll();
|
||||
|
||||
if (menuIdCastMedia && alteredOpts.includes("mediaEnabled")) {
|
||||
browser.menus.update(menuIdCastMedia, {
|
||||
visible: newOpts.mediaEnabled
|
||||
visible: opts.mediaEnabled
|
||||
});
|
||||
}
|
||||
|
||||
if (menuIdCastMedia && alteredOpts.includes("localMediaEnabled")) {
|
||||
browser.menus.update(menuIdCastMedia, {
|
||||
targetUrlPatterns: newOpts.localMediaEnabled
|
||||
? URL_PATTERNS_ALL
|
||||
: URL_PATTERNS_REMOTE
|
||||
});
|
||||
if (
|
||||
menuIdCastMedia &&
|
||||
(alteredOpts.includes("localMediaEnabled") ||
|
||||
alteredOpts.includes("mediaMirroringEnabled"))
|
||||
) {
|
||||
browser.menus.remove(menuIdCastMedia);
|
||||
menuIdCastMedia = createCastMediaMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -183,20 +194,18 @@ async function onMenuClicked(
|
||||
}
|
||||
|
||||
case menuIdCastMedia:
|
||||
if (info.srcUrl) {
|
||||
await browser.tabs.executeScript(tab.id, {
|
||||
code: stringify`
|
||||
window.mediaUrl = ${info.srcUrl};
|
||||
window.targetElementId = ${info.targetElementId};
|
||||
`,
|
||||
frameId: info.frameId
|
||||
});
|
||||
await browser.tabs.executeScript(tab.id, {
|
||||
code: stringify`
|
||||
window.mediaUrl = ${info.srcUrl};
|
||||
window.targetElementId = ${info.targetElementId};
|
||||
`,
|
||||
frameId: info.frameId
|
||||
});
|
||||
|
||||
await browser.tabs.executeScript(tab.id, {
|
||||
file: "cast/senders/media.js",
|
||||
frameId: info.frameId
|
||||
});
|
||||
}
|
||||
await browser.tabs.executeScript(tab.id, {
|
||||
file: "cast/senders/media.js",
|
||||
frameId: info.frameId
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import type Session from "../sdk/Session";
|
||||
import type Media from "../sdk/media/Media";
|
||||
|
||||
import cast, { ensureInit, CastPort } from "../export";
|
||||
import MirroringSender from "./mirroring";
|
||||
|
||||
const logger = new Logger("fx_cast [media sender]");
|
||||
|
||||
@@ -359,8 +360,18 @@ if (window.location.protocol !== "moz-extension:") {
|
||||
) as HTMLMediaElement;
|
||||
}
|
||||
|
||||
new MediaSender({
|
||||
mediaUrl: window_.mediaUrl,
|
||||
mediaElement
|
||||
});
|
||||
if (window_.mediaUrl) {
|
||||
new MediaSender({
|
||||
mediaUrl: window_.mediaUrl,
|
||||
mediaElement
|
||||
});
|
||||
} else {
|
||||
const mirroringSender = new MirroringSender({
|
||||
onSessionCreated() {
|
||||
mirroringSender.createMirroringConnection(
|
||||
(mediaElement as any).mozCaptureStream() as MediaStream
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,17 +19,17 @@ type MirroringAppMessage =
|
||||
| { subject: "close" };
|
||||
|
||||
interface MirroringSenderOpts {
|
||||
receiverDevice: ReceiverDevice;
|
||||
onSessionCreated: () => void;
|
||||
onMirroringConnected: () => void;
|
||||
onMirroringStopped: () => void;
|
||||
receiverDevice?: ReceiverDevice;
|
||||
onSessionCreated?: () => void;
|
||||
onMirroringConnected?: () => void;
|
||||
onMirroringStopped?: () => void;
|
||||
}
|
||||
|
||||
export default class MirroringSender {
|
||||
private receiverDevice: ReceiverDevice;
|
||||
private sessionCreatedCallback: () => void;
|
||||
private mirroringConnectedCallback: () => void;
|
||||
private mirroringStoppedCallback: () => void;
|
||||
private receiverDevice?: ReceiverDevice;
|
||||
private sessionCreatedCallback?: () => void;
|
||||
private mirroringConnectedCallback?: () => void;
|
||||
private mirroringStoppedCallback?: () => void;
|
||||
|
||||
private session?: Session;
|
||||
private wasSessionRequested = false;
|
||||
@@ -96,7 +96,7 @@ export default class MirroringSender {
|
||||
cast.requestSession(
|
||||
session => {
|
||||
this.session = session;
|
||||
this.sessionCreatedCallback();
|
||||
this.sessionCreatedCallback?.();
|
||||
},
|
||||
err => {
|
||||
logger.error("Session request failed", err);
|
||||
@@ -114,7 +114,7 @@ export default class MirroringSender {
|
||||
this.peerConnection?.close();
|
||||
this.session?.stop();
|
||||
|
||||
this.mirroringStoppedCallback();
|
||||
this.mirroringStoppedCallback?.();
|
||||
}
|
||||
|
||||
async createMirroringConnection(stream: MediaStream) {
|
||||
@@ -157,7 +157,7 @@ export default class MirroringSender {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mirroringConnectedCallback();
|
||||
this.mirroringConnectedCallback?.();
|
||||
applyParameters();
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ export interface Options {
|
||||
localMediaEnabled: boolean;
|
||||
/** HTTP server port for local media. */
|
||||
localMediaServerPort: number;
|
||||
/** Media stream mirroring for when flinging not possible. */
|
||||
mediaMirroringEnabled: boolean;
|
||||
|
||||
/** Screen mirroring casting. */
|
||||
mirroringEnabled: boolean;
|
||||
@@ -85,6 +87,7 @@ export default {
|
||||
mediaStopOnUnload: false,
|
||||
localMediaEnabled: true,
|
||||
localMediaServerPort: 9555,
|
||||
mediaMirroringEnabled: true,
|
||||
|
||||
mirroringEnabled: false,
|
||||
mirroringAppId: MIRRORING_APP_ID,
|
||||
|
||||
@@ -139,6 +139,22 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="option option--inline">
|
||||
<div class="option__control">
|
||||
<input
|
||||
id="mediaMirroringEnabled"
|
||||
type="checkbox"
|
||||
bind:checked={opts.mediaMirroringEnabled}
|
||||
/>
|
||||
</div>
|
||||
<label class="option__label" for="mediaMirroringEnabled">
|
||||
{_("optionsMediaMirroringEnabled")}
|
||||
</label>
|
||||
<div class="option__description">
|
||||
{_("optionsMediaMirroringEnabledDescription")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="option option--inline">
|
||||
|
||||
Reference in New Issue
Block a user