From c19f4ca99ec5963a2c44626c0b37967d913e8665 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Wed, 8 Jul 2026 14:00:26 -0700 Subject: [PATCH] [eric] browser: never suspend an audible card (Chrome parity, music keeps playing off-screen) --- .../hooks/interaction/useWebviewSuspend.ts | 16 ++++++++++++++-- frontend/src/shared/browserRegistry.ts | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/Dashboard/hooks/interaction/useWebviewSuspend.ts b/frontend/src/app/pages/Dashboard/hooks/interaction/useWebviewSuspend.ts index ebeba010..4b67c46b 100644 --- a/frontend/src/app/pages/Dashboard/hooks/interaction/useWebviewSuspend.ts +++ b/frontend/src/app/pages/Dashboard/hooks/interaction/useWebviewSuspend.ts @@ -71,9 +71,21 @@ function agentNeedsLive(browserId: string, card: BrowserCardPosition): boolean { return false; } -// A card we must never snapshot-swap: an agent is driving it, OR it's in the keep-alive set (recently used). Suspending a keep-alive card would destroy its webContents and wipe its sessionStorage (logged-in sites drop their session), the whole thing we're preventing. +// Chrome never discards an audible tab: a card playing music off-screen keeps playing instead of going silent mid-song. +function cardIsAudible(browserId: string, card: BrowserCardPosition): boolean { + for (const tab of card.tabs ?? []) { + try { + if (getWebview(browserId, tab.id)?.isCurrentlyAudible?.()) return true; + } catch { + // A detached/dying webview reads as silent. + } + } + return false; +} + +// A card we must never snapshot-swap: an agent is driving it, it's in the keep-alive set (recently used), or it's playing audio. Suspending destroys the webContents (sessionStorage, playback), the things we're preserving. function mustStayLive(browserId: string, card: BrowserCardPosition): boolean { - return agentNeedsLive(browserId, card) || isKeepAliveBrowser(browserId); + return agentNeedsLive(browserId, card) || isKeepAliveBrowser(browserId) || cardIsAudible(browserId, card); } /** diff --git a/frontend/src/shared/browserRegistry.ts b/frontend/src/shared/browserRegistry.ts index 1c620c06..1828da69 100644 --- a/frontend/src/shared/browserRegistry.ts +++ b/frontend/src/shared/browserRegistry.ts @@ -23,6 +23,8 @@ export interface BrowserWebview extends HTMLElement { getURL: () => string; getTitle: () => string; isLoading: () => boolean; + // Optional: present on real Electron webviews; the iframe fallback lacks it, callers must ?.() it. + isCurrentlyAudible?: () => boolean; capturePage: (rect?: { x: number; y: number; width: number; height: number }) => Promise; executeJavaScript: (code: string) => Promise; sendInputEvent: (event: any) => void;