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 |
|
||||
| --: | --------------------------------------------- | ---------- | ----------- | ----------- |
|
||||
| 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. |
|
||||
| 4 | `shim:/serviceDown` | bridge | shim | Sent once a receiver device has been lost. |
|
||||
| 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 * as transforms from "./transforms";
|
||||
|
||||
import { Channel, Client } from "castv2";
|
||||
|
||||
import { Message } from "./types";
|
||||
|
||||
import { __applicationName
|
||||
, __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
|
||||
events.EventEmitter.defaultMaxListeners = 50;
|
||||
|
||||
@@ -50,6 +57,10 @@ function sendMessage (message: object) {
|
||||
}
|
||||
|
||||
|
||||
interface InitializeOptions {
|
||||
shouldWatchStatus?: boolean;
|
||||
}
|
||||
|
||||
// Existing counterpart Media/Session objects
|
||||
const existingSessions: Map<string, Session> = new Map();
|
||||
const existingMedia: Map<string, Media> = new Map();
|
||||
@@ -111,11 +122,14 @@ async function handleMessage (message: Message) {
|
||||
return __applicationVersion;
|
||||
}
|
||||
|
||||
case "bridge:/startDiscovery": {
|
||||
browser.start();
|
||||
case "bridge:/initialize": {
|
||||
const options: InitializeOptions = message.data;
|
||||
initialize(options);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case "bridge:/startHttpServer": {
|
||||
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) => {
|
||||
transforms.encode.write({
|
||||
subject: "shim:/serviceUp"
|
||||
, data: {
|
||||
address: service.addresses[0]
|
||||
, port: service.port
|
||||
, id: service.txt.id
|
||||
, friendlyName: service.txt.fn
|
||||
, currentApp: service.txt.rs
|
||||
if (options.shouldWatchStatus) {
|
||||
registerStatusListener(address, port, id);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
browser.on("serviceDown", (service: dnssd.Service) => {
|
||||
transforms.encode.write({
|
||||
subject: "shim:/serviceDown"
|
||||
, data: {
|
||||
id: service.txt.id
|
||||
}
|
||||
transforms.encode.write({
|
||||
subject: "shim:/serviceUp"
|
||||
, data: {
|
||||
address, port, 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 => {
|
||||
browser.tabs.sendMessage(mirrorCastTabId, message
|
||||
, { frameId: mirrorCastFrameId });
|
||||
|
||||
Reference in New Issue
Block a user