Skip to content

feat: capture tab audio in an offscreen document - #17

Merged
Maitrog merged 27 commits into
mainfrom
feature/offscreen-tab-capture-v2
Sep 27, 2026
Merged

Maitrog merged 27 commits into
mainfrom
feature/offscreen-tab-capture-v2

Conversation

@Maitrog

@Maitrog Maitrog commented Sep 23, 2026

Copy link
Copy Markdown
Owner

Summary

This PR replaces the legacy Window Mode capture path with a dedicated offscreen document that captures tab audio, moves capture lifecycle coordination into the background, starts capture directly from the popup, and hardens recovery and cleanup when captures end unexpectedly.

User-facing improvements

  • Replaced Window Mode with tab capture that starts directly from the popup.
  • Added a per-tab ON/OFF badge on the extension icon showing where capture is active.
  • Spectrum visualization is now enabled by default; volume compensation is disabled by default.
  • Improved capture reliability when:
    • the offscreen document is lost or killed (page mode is restored);
    • captures end while the popup is open (popup target is restored);
    • the offscreen document sits idle (closed after reconciliation);
    • captured tabs close or change quickly.
  • Capture errors are owned by the background and shown as a clear error state in the popup; the ordinary equalizer state is shown when no capture runs.
  • Kept toolkit-window tabs out of page-mode autostart.
  • Updated localization files for 19 locales.

Architecture and build

  • Added an offscreen document capture engine (offscreen.html, src/app/offscreen/) with the offscreen manifest permission and a dedicated build entry.
  • Added background capture coordination:
    • capture coordinator owning start/stop, reconciliation, and idle offscreen cleanup;
    • a dedicated capture error controller;
    • tab mute and per-tab badge modules.
  • Routed capture settings, keyboard shortcuts, and spectrum demand through the background; spectrum is relayed from the offscreen document through an explicit capture source and gated on the enabled setting.
  • Removed the legacy Window Mode capture path (windowModeCoordinator, toolkit window controller).
  • Separated persisted gain from transient equalizer state (persistedGain.ts).
  • Expanded unit coverage for the capture coordinator, offscreen engine, popup capture controller, badge, mute, and messaging.

Verification

  • npm test - 67 test files and 356 tests passed.
  • npm run typecheck - passed.
  • npm run lint - passed.
  • Prettier verification against committed LF content - passed.
  • npm run lint:locales - passed for 19 locales.
  • npm run build - production build completed successfully.

Scope

  • 19 commits.
  • 98 changed files.
  • 5,164 additions and 3,182 deletions.

Replace the window-mode popup flow with an in-popup tab capture controller:
start targets the current browser tab, stop/settings target the explicitly
selected captured tab, and closing the popup no longer stops audio. Rename
the window-mode button to tab-capture, drop the already-open screen, and
update localized copy across all locales.
The legacy window controller reconciles on captureActiveTabId, but
windowModeCoordinator still wrote toolkitWindowActiveTabId, so a window
opened during coexistence lost its selected tab and focus reconciliation.
Write and read captureActiveTabId, the same key captureCoordinator uses.
Restore the page equalizer when a capture session is dropped while the
service worker or offscreen document restarts. reconcileInternal now
restores interrupted "starting" snapshots and notifies every dropped tab's
content script; clearStaleStateIfNoDocument also restores vanished "active"
sessions. Drop the coordinator's blanket mode-change catch so only the
specific non-fatal send failures are swallowed.

Also from the final review: hoist the duplicated isTabId helper into
runtimeMessages, reject TOGGLE_CAPTURE_ENABLED from content scripts, gate
storage-change forwarding on capture-relevant keys, guard the popup enable
button against late tabEnabled writes, remove the dead
refreshToolkitCaptureFilters/onMuteStateApplied plumbing and the unused
captureSession.sync, pin captureEngine.dispose's terminal contract, and add
a dedicated localized stop-error prefix across all locales.
@Maitrog
Maitrog merged commit 2cf7850 into main Sep 27, 2026
3 checks passed
@Maitrog
Maitrog deleted the feature/offscreen-tab-capture-v2 branch September 28, 2026 07:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant