Fix speech-to-text microphone on Linux AppImage #72

Merged
jknapp merged 1 commits from fix/linux-microphone into main 2026-11-05 14:42:33 +00:00
Owner

Speech-to-text mic (bottom-right button) did not work in the Linux AppImage. It was a chain of separate problems, each hidden behind the previous one. The surfaced error, OverconstrainedError: Invalid constraint, was only a symptom of WebKitGTK seeing 0 capture devices.

Changes

  • GStreamer plugins: the AppImage bundled GStreamer libs but no plugins (appsink not found, 0 devices). Enable bundle.linux.appimage.bundleMediaFramework and install the gst plugin packages on the CI runners (both app workflows).
  • libpipewire: the bundled copy has the builder's SPA plugin paths compiled in and failed on other layouts (pw_loop_new: can't make support.system handle). finalize-appimage.sh now removes it so the host's is used, as already done for libwayland-client, and asserts it is gone.
  • WebKitGTK permission (new linux_media.rs, Linux only): wry neither enables media streams nor answers permission-request, giving NotAllowedError. The main window now enables media streams and grants audio-only requests; camera, mixed, and all other permission types are denied. Other windows get nothing.
  • getUserMedia ladder (get-microphone.ts): saved device, then default device, then bare audio: true on OverconstrainedError/NotFoundError. Permission errors still surface. STT error now includes the DOMException name.

Testing

  • Frontend: tsc clean, 1173 vitest tests pass. Rust: unit tests for the grant rule pass.
  • Manually verified on CachyOS with a built AppImage: media permission request allowed, recording and transcription work.
  • CI changes are unverified until this PR's preview build runs.

Notes

  • AppImage grows from ~89 MB to ~100 MB.
  • GStreamer-CRITICAL ... GstIntRange lines still print from WebKit; mic works regardless.
  • The Microphone settings picker remains hidden (c023d80).

🤖 Generated with Claude Code

Speech-to-text mic (bottom-right button) did not work in the Linux AppImage. It was a chain of separate problems, each hidden behind the previous one. The surfaced error, `OverconstrainedError: Invalid constraint`, was only a symptom of WebKitGTK seeing 0 capture devices. ## Changes - **GStreamer plugins**: the AppImage bundled GStreamer libs but no plugins (`appsink not found`, `0 devices`). Enable `bundle.linux.appimage.bundleMediaFramework` and install the gst plugin packages on the CI runners (both app workflows). - **libpipewire**: the bundled copy has the builder's SPA plugin paths compiled in and failed on other layouts (`pw_loop_new: can't make support.system handle`). `finalize-appimage.sh` now removes it so the host's is used, as already done for libwayland-client, and asserts it is gone. - **WebKitGTK permission** (new `linux_media.rs`, Linux only): wry neither enables media streams nor answers `permission-request`, giving `NotAllowedError`. The main window now enables media streams and grants audio-only requests; camera, mixed, and all other permission types are denied. Other windows get nothing. - **getUserMedia ladder** (`get-microphone.ts`): saved device, then default device, then bare `audio: true` on `OverconstrainedError`/`NotFoundError`. Permission errors still surface. STT error now includes the DOMException name. ## Testing - Frontend: tsc clean, 1173 vitest tests pass. Rust: unit tests for the grant rule pass. - Manually verified on CachyOS with a built AppImage: `media permission request allowed`, recording and transcription work. - **CI changes are unverified until this PR's preview build runs.** ## Notes - AppImage grows from ~89 MB to ~100 MB. - `GStreamer-CRITICAL ... GstIntRange` lines still print from WebKit; mic works regardless. - The Microphone settings picker remains hidden (c023d80). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jknapp added 1 commit 2026-11-05 14:25:44 +00:00
Fix speech-to-text microphone on Linux AppImage
Secret Scan / scan (push) Successful in 6s
Secret Scan / scan (pull_request) Successful in 6s
Build App (Preview) / compute-version (pull_request) Successful in 5s
Build App (Preview) / create-release (pull_request) Successful in 6s
Build App (Preview) / test (pull_request) Successful in 4m8s
Build App (Preview) / build-macos (pull_request) Successful in 3m18s
Build App (Preview) / build-windows (pull_request) Successful in 8m8s
Build App (Preview) / build-linux (pull_request) Successful in 6m48s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
c4cb04f011
The mic button failed on Linux with a chain of distinct problems, each
hidden behind the previous one:

- The AppImage bundled GStreamer libraries but no plugins, so WebKitGTK
  found 0 capture devices. Enable bundleMediaFramework and install the
  GStreamer plugin packages on the CI runners.
- The bundled libpipewire had the builder's SPA plugin paths compiled in
  and failed on hosts with a different layout. finalize-appimage.sh now
  drops it so the host's is used (host-coupled, like libwayland-client).
- WebKitGTK denies getUserMedia until the embedder enables media streams
  and answers the permission request; wry does neither. Add a Linux-only
  handler for the main window that grants audio-only requests and denies
  everything else.
- getUserMedia now steps down from the saved device to the default device
  to bare audio:true on OverconstrainedError/NotFoundError, and the STT
  error shows the DOMException name.

Verified on CachyOS: permission request allowed, recording works.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
jknapp merged commit d4a14d2ded into main 2026-11-05 14:42:33 +00:00
jknapp deleted branch fix/linux-microphone 2026-11-05 14:42:33 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: CyberCoveLLC/Triple-C#72