mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Optionally forward status updates from bridge to extension
This commit is contained in:
@@ -46,7 +46,7 @@ Cast SDK API calls are translated into Chromecast protocol messages and sent via
|
|||||||
| No. | Subject | Origin | Destination | Description |
|
| No. | Subject | Origin | Destination | Description |
|
||||||
| --: | --------------------------------------------- | ---------- | ----------- | ----------- |
|
| --: | --------------------------------------------- | ---------- | ----------- | ----------- |
|
||||||
| 1 | `shim:/initialized` | background | shim | Sent once bridge has been created. |
|
| 1 | `shim:/initialized` | background | shim | Sent once bridge has been created. |
|
||||||
| 2 | `bridge:/startDiscovery` | shim | bridge | Starts network discovery. |
|
| 2 | `bridge:/initialize` | shim | bridge | Starts network discovery. |
|
||||||
| 3 | `shim:/serviceUp` | bridge | shim | Sent once a receiver device has been found. |
|
| 3 | `shim:/serviceUp` | bridge | shim | Sent once a receiver device has been found. |
|
||||||
| 4 | `shim:/serviceDown` | bridge | shim | Sent once a receiver device has been lost. |
|
| 4 | `shim:/serviceDown` | bridge | shim | Sent once a receiver device has been lost. |
|
||||||
| 5 | `main:/openPopup` | shim | background | Opens the receiver selection popup. |
|
| 5 | `main:/openPopup` | shim | background | Opens the receiver selection popup. |
|
||||||
|
|||||||
157
app/src/main.ts
157
app/src/main.ts
@@ -10,12 +10,19 @@ import Media from "./Media";
|
|||||||
import Session from "./Session";
|
import Session from "./Session";
|
||||||
import * as transforms from "./transforms";
|
import * as transforms from "./transforms";
|
||||||
|
|
||||||
|
import { Channel, Client } from "castv2";
|
||||||
|
|
||||||
import { Message } from "./types";
|
import { Message } from "./types";
|
||||||
|
|
||||||
import { __applicationName
|
import { __applicationName
|
||||||
, __applicationVersion } from "../package.json";
|
, __applicationVersion } from "../package.json";
|
||||||
|
|
||||||
|
|
||||||
|
const NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection";
|
||||||
|
const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat";
|
||||||
|
const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver";
|
||||||
|
|
||||||
|
|
||||||
// Increase listener limit
|
// Increase listener limit
|
||||||
events.EventEmitter.defaultMaxListeners = 50;
|
events.EventEmitter.defaultMaxListeners = 50;
|
||||||
|
|
||||||
@@ -50,6 +57,10 @@ function sendMessage (message: object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface InitializeOptions {
|
||||||
|
shouldWatchStatus?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
// Existing counterpart Media/Session objects
|
// Existing counterpart Media/Session objects
|
||||||
const existingSessions: Map<string, Session> = new Map();
|
const existingSessions: Map<string, Session> = new Map();
|
||||||
const existingMedia: Map<string, Media> = new Map();
|
const existingMedia: Map<string, Media> = new Map();
|
||||||
@@ -111,11 +122,14 @@ async function handleMessage (message: Message) {
|
|||||||
return __applicationVersion;
|
return __applicationVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "bridge:/startDiscovery": {
|
case "bridge:/initialize": {
|
||||||
browser.start();
|
const options: InitializeOptions = message.data;
|
||||||
|
initialize(options);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case "bridge:/startHttpServer": {
|
case "bridge:/startHttpServer": {
|
||||||
const { filePath, port } = message.data;
|
const { filePath, port } = message.data;
|
||||||
|
|
||||||
@@ -173,25 +187,128 @@ async function handleMessage (message: Message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initialize (options: InitializeOptions) {
|
||||||
|
browser.on("serviceUp", (service: dnssd.Service) => {
|
||||||
|
const address = service.addresses[0];
|
||||||
|
const port = service.port;
|
||||||
|
const id = service.txt.id;
|
||||||
|
|
||||||
browser.on("serviceUp", (service: dnssd.Service) => {
|
if (options.shouldWatchStatus) {
|
||||||
transforms.encode.write({
|
registerStatusListener(address, port, id);
|
||||||
subject: "shim:/serviceUp"
|
|
||||||
, data: {
|
|
||||||
address: service.addresses[0]
|
|
||||||
, port: service.port
|
|
||||||
, id: service.txt.id
|
|
||||||
, friendlyName: service.txt.fn
|
|
||||||
, currentApp: service.txt.rs
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
browser.on("serviceDown", (service: dnssd.Service) => {
|
transforms.encode.write({
|
||||||
transforms.encode.write({
|
subject: "shim:/serviceUp"
|
||||||
subject: "shim:/serviceDown"
|
, data: {
|
||||||
, data: {
|
address, port, id
|
||||||
id: service.txt.id
|
, friendlyName: service.txt.fn
|
||||||
}
|
, currentApp: service.txt.rs
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
browser.on("serviceDown", (service: dnssd.Service) => {
|
||||||
|
const id = service.txt.id;
|
||||||
|
|
||||||
|
if (options.shouldWatchStatus) {
|
||||||
|
deregisterStatusListener(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
transforms.encode.write({
|
||||||
|
subject: "shim:/serviceDown"
|
||||||
|
, data: { id }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface StatusListener {
|
||||||
|
client: Client;
|
||||||
|
clientReceiver: Channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of client connections
|
||||||
|
const statusListeners = new Map<string, StatusListener>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a connection to a receiver device and forwards
|
||||||
|
* RECEIVER_STATUS updates to the extension.
|
||||||
|
*/
|
||||||
|
function registerStatusListener (
|
||||||
|
host: string
|
||||||
|
, port: number
|
||||||
|
, id: string) {
|
||||||
|
|
||||||
|
const client = new Client();
|
||||||
|
|
||||||
|
const sourceId = "sender-0";
|
||||||
|
const destinationId = "receiver-0";
|
||||||
|
|
||||||
|
let heartbeatIntervalId: number;
|
||||||
|
|
||||||
|
client.connect({ host, port }, () => {
|
||||||
|
const clientConnection = client.createChannel(
|
||||||
|
sourceId, destinationId, NS_CONNECTION, "JSON");
|
||||||
|
const clientHeartbeat = client.createChannel(
|
||||||
|
sourceId, destinationId, NS_HEARTBEAT, "JSON");
|
||||||
|
const clientReceiver = client.createChannel(
|
||||||
|
sourceId, destinationId, NS_RECEIVER, "JSON");
|
||||||
|
|
||||||
|
|
||||||
|
clientReceiver.on("message", data => {
|
||||||
|
switch (data.type) {
|
||||||
|
case "CLOSE": {
|
||||||
|
client.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "RECEIVER_STATUS": {
|
||||||
|
// Send update message
|
||||||
|
transforms.encode.write({
|
||||||
|
subject: "main:/receiverStatusUpdate"
|
||||||
|
, data: {
|
||||||
|
id
|
||||||
|
, status: data.status
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
clientConnection.send({ type: "CONNECT" });
|
||||||
|
clientHeartbeat.send({ type: "PING" });
|
||||||
|
clientReceiver.send({ type: "GET_STATUS", requestId: 1 });
|
||||||
|
|
||||||
|
heartbeatIntervalId = setInterval(() => {
|
||||||
|
clientHeartbeat.send({ type: "PING" });
|
||||||
|
});
|
||||||
|
|
||||||
|
statusListeners.set(id, {
|
||||||
|
client
|
||||||
|
, clientReceiver
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("close", () => {
|
||||||
|
clearInterval(heartbeatIntervalId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes status listener connection for a given receiver
|
||||||
|
* device.
|
||||||
|
*/
|
||||||
|
function deregisterStatusListener (id: string) {
|
||||||
|
const { client, clientReceiver } = statusListeners.get(id);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
clientReceiver.send({ type: "CLOSE" });
|
||||||
|
client.close();
|
||||||
|
|
||||||
|
// Remove from map
|
||||||
|
statusListeners.delete(id);
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@@ -539,6 +539,28 @@ browser.runtime.onConnect.addListener(port => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const statusBridge = browser.runtime.connectNative(APPLICATION_NAME);
|
||||||
|
const receiverStatusMap = new Map<string, any>();
|
||||||
|
|
||||||
|
statusBridge.onMessage.addListener((message: Message) => {
|
||||||
|
switch (message.subject) {
|
||||||
|
case "main:/receiverStatusUpdate": {
|
||||||
|
const { id, status } = message.data;
|
||||||
|
receiverStatusMap.set(id, status);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
statusBridge.postMessage({
|
||||||
|
subject: "bridge:/initialize"
|
||||||
|
, data: {
|
||||||
|
shouldWatchStatus: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
messageRouter.register("mirrorCast", message => {
|
messageRouter.register("mirrorCast", message => {
|
||||||
browser.tabs.sendMessage(mirrorCastTabId, message
|
browser.tabs.sendMessage(mirrorCastTabId, message
|
||||||
, { frameId: mirrorCastFrameId });
|
, { frameId: mirrorCastFrameId });
|
||||||
|
|||||||
Reference in New Issue
Block a user