Sfoglia il codice sorgente

Restart on collection ID mismatches

Manav Rathi 1 anno fa
parent
commit
ddb19e2333
1 ha cambiato i file con 56 aggiunte e 11 eliminazioni
  1. 56 11
      web/apps/cast/src/services/pair.ts

+ 56 - 11
web/apps/cast/src/services/pair.ts

@@ -116,25 +116,68 @@ export const advertiseCode = (
     const namespace = "urn:x-cast:pair-request";
 
     const options = new cast.framework.CastReceiverOptions();
-    // options.skipPlayersLoad = true;
-    // Do not automatically close the connection when the sender disconnects.
-    options.maxInactivity = 3600; /* 1 hour */
+    // We don't use the media features of the Cast SDK.
+    options.skipPlayersLoad = true;
     // TODO:Is this required? The docs say "(The default type of a message bus
     // is JSON; if not provided here)."
     options.customNamespaces = Object.assign({});
     options.customNamespaces[namespace] =
         cast.framework.system.MessageType.JSON;
-    // TODO: This looks like the only one needed, but a comment with the reason
-    // might be good.
+    // Do not stop the casting if the receiver is unreachable. A user should be
+    // able to start a cast on their phone and then put it away, leaving the
+    // cast running on their big screen.
     options.disableIdleTimeout = true;
 
+    // The collection ID with which we paired. If we get another connection
+    // request for a different collection ID, restart the app to allow them to
+    // reconnect using a freshly generated pairing code.
+    //
+    // If the request does not have a collectionID, just keep a boolean flag.
+    let pairedCollectionID: string | boolean | undefined;
+
+    type ListenerProps = {
+        senderId: string;
+        data: unknown;
+    };
+
     // Reply with the code that we have if anyone asks over Chromecast.
-    const incomingMessageListener = ({ senderId }: { senderId: string }) => {
+    const incomingMessageListener = ({ senderId, data }: ListenerProps) => {
+        const restart = (reason: string) => {
+            log.error(`Restarting app because ${reason}`);
+            // context.stop will close the tab but it'll get reopened again
+            // immediately since the client app will reconnect in the scenarios
+            // where we're calling this function.
+            context.stop();
+        };
+
+        const cid =
+            data &&
+            typeof data == "object" &&
+            typeof data["collectionID"] == "string"
+                ? data["collectionID"]
+                : undefined;
+
+        if (pairedCollectionID !== undefined && pairedCollectionID != cid) {
+            restart(`incoming request for a new collection ${cid}`);
+            return;
+        }
+
+        pairedCollectionID = cid ?? true;
+
         const code = pairingCode();
         if (!code) {
-            log.warn(
-                "Ignoring incoming Chromecast message because we do not yet have a pairing code",
-            );
+            // Our caller waits until it has a pairing code before it calls
+            // `advertiseCode`, but there is still an edge case where we can
+            // find ourselves without a pairing code:
+            //
+            // 1. The current pairing code expires. We start the process to get
+            //    a new one.
+            //
+            // 2. But before that happens, someone connects.
+            //
+            // The window where this can happen is short, so if we do find
+            // ourselves in this scenario,
+            restart("we got a pairing request when refreshing pairing codes");
             return;
         }
 
@@ -148,8 +191,10 @@ export const advertiseCode = (
         incomingMessageListener as unknown as SystemEventHandler,
     );
 
-    // Shutdown ourselves if the sender disconnects.
-    // TODO(MR): I assume the page reloads on shutdown. Is that correct?
+    // Close the (chromecast) tab if the sender disconnects.
+    //
+    // Chromecast does a "shutdown" of our cast app when we call `context.stop`.
+    // This translates into it closing the tab where it is showing our app.
     context.addEventListener(
         cast.framework.system.EventType.SENDER_DISCONNECTED,
         () => context.stop(),