Repository navigation
feat(discovery): capture virtual-meeting audio alongside the mic - #43
Merged
Merged
Conversation
Adds a `meeting` audio source for virtual calls (Zoom / Meet / Teams): the recorder opens the screen-share picker first (it needs the click's transient activation), keeps the shared surface's audio with voice processing off, stops the unused video track and then takes the mic. Both sources feed one mono GainNode mixer (explicit 1 channel, speakers down-mix) that drives the level meter and the PCM worklet, so `/ws/stt` still gets 16 kHz Int16 mono. - Sharing without "Share tab audio" stops the tracks and sets a notice; a dismissed picker stays idle without messages. - "Stop sharing" (audio track `ended`) disconnects the meeting audio and keeps streaming the mic with a notice; `shareMeetingAudio()` re-shares. - `pauseStreaming()` keeps the shared surface so a resume never re-opens the picker; `stopStreaming()` releases everything. - Socket handlers are detached before closing so a late close event can't tear down the next socket, and a session that fails to start releases the capture.
…ecorder Mocks navigator.mediaDevices to cover the picker-before-mic ordering (no await before getDisplayMedia), the display constraints, the dropped video track, the no-audio-track warning, silent picker dismissal, real capture failures, a missing getDisplayMedia, mic denial releasing the shared tab, the "Stop sharing" mic-only fallback and re-share, and pause vs. stop release. A real Web Audio graph with a fake socket checks that both sources feed the mono mixer, which drives the meter and the worklet. Also covers the desktop-Chromium support check and dismissal detection.
A compact segmented control next to the record button picks where the next recording takes its audio from: "In person (microphone)" or "Virtual meeting (microphone + meeting audio)". The choice is remembered per user in localStorage (try/catch) and locked while starting or once a session is live; the record click passes it to the recorder before any await so the screen-share picker keeps the click's activation, and a second click can't stack another picker. The virtual option stays visible but inert outside desktop Chromium, with the reason as tooltip and, on tap, as the composer hint. With the virtual source selected the hint explains to tick "Share tab audio" and to wear headphones; recorder notices (amber) render in the same line.
Covers the pressed state, switching to the virtual source, the inert virtual option (tooltip + unavailable event) where meeting audio is unsupported, the lock during a live session, the per-user storage key and the fallback to the microphone when a stored virtual choice can't be honoured.
…e session bar Virtual-meeting recordings show a meeting-audio badge next to the timer while the shared audio is mixed in. Once the user clicks "Stop sharing" (the recording carries on with the mic), the bar shows an amber "Share again" action that re-opens the picker straight from the click and mixes the new surface into the live (or paused) recording.
…hare Covers that in-person recordings show no meeting controls, that the badge shows while the meeting audio is captured, and that after "Stop sharing" the bar offers an accessible "Share again" button that calls the recorder.
14 of 18 tasks
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Lets the analyst run a live discovery session during a Zoom, Google Meet or Teams call, not only in a face-to-face meeting. A small audio-source picker next to the record button chooses In person (microphone) or Virtual meeting (microphone + meeting audio), remembered per user.
The virtual source opens the browser's screen-share picker straight from the record click (
getDisplayMediawith tab/window/system audio, voice processing off), drops the unused video track and mixes the shared audio with the mic in one mono Web Audio mixer. The backend keeps receiving the same 16 kHz Int16 PCM on/ws/stt, so no API change is needed, and the level meter shows the mix.Edge cases handled with translated messages (es/en):
Also fixes small issues in the recorder: the mic was requested twice on start, a session that failed to start kept the mic open, and a late close event from an old socket could kill the next one.
Feature module / area: discovery / core
Related issue / US: US56 — capture virtual-meeting audio (usability finding: the product only worked in person)
Type of Change
feat— new feature or UI componentfix— bug fixrefactor— code change without behavior changetest— tests onlydocs— documentation onlybuild/ci— build, dependencies, or CI/CDchore— maintenanceChecklist
develop(notmain)feature/*,bugfix/*, orhotfix/*bun run lintpasses locally (ESLint + angular-eslint)bun run testpasses locally (Vitest) — 305 passedbun run buildpasses locally (no type errors, no budget exceeded)ChangeDetectionStrategy.OnPushand Angular signalslocalStorage/sessionStorageaccess for JWT tokens (use the auth store)bypassSecurityTrust*calls without explicit review.envcontent committedCHANGELOG.mdupdated under[Unreleased]How to Test
Desktop Chrome or Edge, with headphones:
Notes (optional)