Repository navigation
Tags
Tags
chore(release): prepare 1.10.3 (OpenWhispr#2597) * chore(release): prepare 1.10.3 Bump the app version to 1.10.3 and move the Unreleased changelog entries into a dated 1.10.3 section covering everything merged since 1.10.2: agent connectors (email, Gmail, Slack, Linear, GitHub), note templates and actions with the docked note chat, tables in the note editor, idle resource release, friendly provider errors, Orukeet streaming for OpenWhispr Cloud, and transcription, meeting and platform fixes. * ci(release): write the Gmail OAuth client into the packaged .env The GMAIL_CLIENT_ID/GMAIL_CLIENT_SECRET repository secrets were never written to the release build's .env, so Gmail send fell back to the calendar's Google client. Write the pair next to the calendar credentials in the Linux, Windows and macOS jobs. * docs(changelog): tighten the 1.10.3 summary and cover OpenWhispr#2598
fix(meetings): keep the Windows silent-capture check armed for the wh… …ole call (OpenWhispr#2233) * fix(meetings): keep the Windows silent-capture check armed for the whole call Windows hides Microsoft Teams call audio from WASAPI process loopback: the helper receives digital silence for it no matter which process it targets or which format it asks for, while the same audio is plainly present on the render endpoint. The capture_silent watchdog added in OpenWhispr#1935 is the way out of that, but it disarmed permanently on the first audible sample from any application, so a notification sound, a browser tab or Teams' own join chime left the rest of the meeting recorded without the other participants and without a warning. The helper now compares its own capture against the render endpoints once a second for the whole session, resetting the confirmation count on any captured audio, and main no longer refuses the handover once some audio has been heard. Fixes OpenWhispr#1265 * fix(meetings): review follow-ups for the Windows silent-capture handover - File the changelog entry under Meetings, and stop claiming the check survives audio that plays continuously alongside the meeting: the streak resets on any captured second, so only a gap of five seconds trips it. - Drop the watchdog's restart hook when the renderer takes over, so it can never respawn the helper behind a session the renderer already owns. - Surface a takeover failure to the user. The one-shot silence notice is suppressed once a call has been audible, so a late failure was silent. * fix(meetings): ship the rebuilt helper, and report a failed takeover properly - Bump the helper workflow's default version to 1.2.0. The push trigger publishes the default tag, and the download script picks the newest published release with the prefix, so a rebuild published as 1.0.0 would have lost to the existing 1.1.0 and the fix would never have shipped. - Report a failed renderer takeover as a translated system-audio interruption instead of a raw English string, and tell auto-end the system channel is gone, so a quiet microphone cannot end the recording behind it. - Detach the watchdog's restart hook before stopping the helper, not after. - Trim the wiring pins the behavioral test now covers, and soften two doc claims: a generic "gone quiet" notice does arrive three minutes later, and the Teams finding is measured across configurations, not every machine. * fix(review): iteration 1 — 4 issues (takeover-failure guards) * fix(review): iteration 2 — 1 issue (takeover attach failure handling) * fix(meetings): keep the Windows helper until renderer loopback proves it hears more capture_silent can fire while the helper is capturing the call fine, for example when a stream hidden from process loopback plays through a lull. Stopping the helper then dropped a working capture for the rest of the meeting, and renderer loopback only hears the default output device. Renderer loopback now starts beside the helper and takes the system channel only after hearing audio the helper misses for a second (meetingSystemAudioHandover.js). Until then its chunks are dropped; after it, the helper's are, and the helper is stopped. A takeover whose capture graph fails to build now releases the loopback stream and its AudioContext instead of holding them until the recording stops. Also trims comments and updates the docs for the new log lines. --------- Co-authored-by: boseq <307062491+boseq@users.noreply.github.com> Co-authored-by: Chadpiha <chadpiha23@gmail.com>
fix(meetings): fall back to renderer loopback when WASAPI capture is … …silent (OpenWhispr#1935) * fix(meetings): fall back to renderer loopback when WASAPI capture is silent The Windows helper's probe only proves the OS exposes VAD\Process_Loopback and accepts our format; it never starts capture or reads a frame. On some machines activation then succeeds and every delivered sample is zero, and because strategy selection reads the probe verdict and start() resolves on the helper's {"type":"start"} event, nothing downstream ever reconsiders it. The silence filler keeps the timeline aligned with the wall clock, so a dead capture emits a well-formed, correctly paced stream of nothing and the Chromium fallback stays unreachable for the whole session. Silence on its own is ambiguous — an idle machine looks identical — so the helper now only calls its capture broken while a render endpoint is metering real output, confirmed over five consecutive one-second checks and disarmed for good the moment any real audio arrives. It reports that once as a capture_silent warning on the existing stderr channel. Main treats that warning as proof the native path cannot work, stops the helper, and hands the live session to Chromium loopback; the renderer builds the capture graph mid-call through the same code the initial start uses. The 45s silence toast stays armed as the backstop for when the fallback fails too. Fixes OpenWhispr#1891 * docs(changelog): note the silent Windows system-audio fallback
feat(meetings): Auto-end forgotten meeting recordings (OpenWhispr#1494) * feat(meetings): Auto-end forgotten meeting recordings Track reliable external microphone activity and show a protected 60-second countdown after meeting activity ends. Preserve recording during reconnects, unreliable detection, and Keep recording actions. * fix(meetings): Harden auto-end against stale binaries and races * fix(meetings): Keep auto-end alive through coverage loss and CI races Code review found that every major failure path killed the feature silently. All fixes preserve the fail-safe property: degradation can only delay or disable auto-end, never stop a live recording. - Windows: a single unattributable session or flaky endpoint made the helper exit, with no respawn and a polling fallback that also lost meeting prompts. It now announces CAPABILITY AGGREGATE once and keeps emitting best-effort events; unattributable sessions refcount under pid 0, which the JS side can never exclude as its own, so they count as external capture and park the countdown. - macOS: a process vanishing between enumeration and its property query permanently downgraded PID mode to aggregate, and the 5s heartbeat re-rolled that race for the whole session. Skip the vanished object and let the next reconcile retry it instead. - Linux: one pactl source-output without application.process.id (echo-cancel, loopbacks) dropped PID reliability entirely. Skip module streams; client streams always carry the pid. - CI: the notarize build raced the listener-publishing workflow and could cache a stale binary under a fresh source hash. The release tag is now pinned to MIC_LISTENER_VERSION in the C source on both ends, and CI downloads fail hard instead of silently falling back. - Renderer: a rejected auto-end stop was swallowed; it is now reported through a required onError hook wired to the meeting logger. * style(notes): Revert drive-by Prettier reflows Restore ShareNoteDialog, OverviewNoteList, and useNoteDragAndDrop to their merge-base content. The reflows were format-only, and the ShareNoteDialog hunk conflicts with the policy-enforcement merge on main for no benefit. * fix(meetings): Exclude own audio helpers and persist auto-end stops Auto-end never fired when system audio was captured: the capture helpers (macOS audio tap, Linux portal, Windows loopback) are plain child processes absent from app.getAppMetrics(), so the OS attributed their capture to non-excluded pids and externalMicActive never went false for the whole recording — verified empirically on macOS via the mic listener reporting the tap helper's pid. Feed the helpers' live pids into the detector's exclusion provider. Transcript persistence was keyed to mounted views, and an auto-end stop is the first stop that can fire while the notes view is closed: the final tail since the last 30s flush was lost and diarization results were dropped. Persist the final transcript in the store's stop path after the main result arrives, move the periodic saver to the always-mounted MeetingRecordingMount, and persist diarization results session-scoped to the note that was recorded. NoteEditor's handler is now display-only and gated to the recording note, so enrichment can no longer land on whichever note happens to be open. Toast when an auto-end request ends the live session — including when a Keep click loses the race with the countdown — so the user learns the recording ended instead of assuming it was kept. New notes.meeting.autoEnded key in all 10 locales. * feat(meetings): Confirm auto-end with audio silence and add a fallback Mic ownership alone had two blind spots: an app that releases the mic on mute could stop a live call while remote voices still played, and the feature was inert wherever ownership is unreliable (older macOS, coverage loss) or never armed (in-person meetings). Combine the two signals in a tick-driven controller. In ownership mode the countdown runs only while the system-audio channel is also quiet, so remote speech defers it; the mic channel is deliberately ignored there so room noise, typing, or talking to a colleague after the call can't mask the end. When ownership is unreliable or no app ever held the mic, both channels quiet for 60s prompts instead, tightened to 10s when the last tracked meeting app exits. Every raw meeting PCM chunk of both channels feeds a pure energy monitor via a single hook in sendMeetingAudio, sharing the echo-leak detector's thresholds through an alignment-safe RMS helper. Chunks are ignored until the controller session exists, since system audio starts streaming before the session is registered. Sleep gaps discard accumulated silence instead of stopping on wake, and a mic hold shorter than 30s no longer arms the mic-ignoring path on an in-person recording. Keep recording is now per episode with a 5-minute cooldown, the card explains which signal fired, and Settings → Meetings gains an "Auto-end forgotten recordings" toggle that takes effect immediately. * fix(meetings): Make auto-end recording fail safe * fix(meetings): Queue detections while a meeting recording session is live The engine's user-recording flag is shared with dictation, so a dictation that ends mid-meeting (or a cancel-hotkey press) clears it while the meeting recording is still live. From then on a detection — most plausibly the calendar reminder for a back-to-back meeting, which fires one minute before its start, right inside the auto-end countdown — bypassed the queue, and its prompt replaced the visible countdown card. The replacement path never notifies the controller, so the countdown ran on unseen and stopped the recording without any chance to keep it. Gate detections on the engine's own recording session as well, which nothing outside the recording lifecycle can reset: new detections are queued behind it like the user-recording gate, and a post-dictation cooldown flush holds the queue until the recording ends. This also stops the pre-existing "Take notes?" prompt that could appear during the user's own manual recording after a dictation. * fix(meetings): Persist the final transcript before awaiting the main-side stop Moving the final transcript save into the store's stop path (so auto-end and owner-loss stops persist without the notes view mounted) also moved it after `cleanup()` and the `meetingTranscriptionStop` round trip. The note editor swaps from live segments to the stored transcript the moment `isRecording` flips, so for the duration of that stop — up to a few seconds with a local Parakeet flush — the tail since the last 30s periodic save disappeared from the note and reappeared once the stop returned. On main the notes-view effect wrote it in the same commit as the state flip. Persist the captured segments before awaiting the stop; they are final once the session is released. Only a segment-less recording still waits for main's final transcript, as before. `persistFinalTranscriptAroundStop` replaces `buildFinalMeetingTranscript`, whose only caller was this path. * fix: clear meeting flag after recording session ends
PreviousNext