Commit Graph

11 Commits

Author SHA1 Message Date
lebaudantoine d723c14d84 🐛(frontend) handle device-in-use errors on Chrome / Windows 10
On Chrome and Windows 10, when the camera or microphone is already
in use by another application, the browser rejects
`getUserMedia`. Without dedicated handling, users just saw their
camera or microphone not turning on, without any explanation.

Detect this specific failure and surface a clear message to the
user, so they understand another application is holding the device
and know what to do about it.
2026-08-23 17:40:01 +02:00
lebaudantoine 8d000fc6d9 📈(frontend) stop double-reporting media device failures
Only report `Other` `MediaDeviceFailure` cases as they genuinely
need investigation.

Make sure we do not report the same situation both as a media event
and as a media exception when it is already handled.
2026-08-14 14:04:35 +02:00
lebaudantoine 40e4f17c65 🐛(frontend) stop reporting screen-share denials as errors
Add a small helper that classifies a `getDisplayMedia` failure as a
user, browser, or OS permission denial, or returns null when it is
a genuine error.

Chromium reports denials with explicit, non-localized messages:

* "Permission denied by user" when the user cancels or dismisses
  the source picker.
* "Permission denied by system" when the OS blocks capture (e.g.
  the macOS Screen Recording privacy setting).
* Plain "Permission denied" for browser-level blocks (site
  settings, enterprise policy, permissions-policy).

Firefox and Safari use generic `NotAllowedError` messages, which
fall into the "browser" bucket.

Firefox additionally does not map macOS Screen Recording (TCC)
blocks to `NotAllowedError`: the OS silently returns no capturable
sources, so `getDisplayMedia` rejects with `NotFoundError` ("The
object can not be found here."). Same quirk as the mic/cam OS blocks
handled in `useWatchMediaDeviceErrors` via `isLikelySystemNotFound`.

Behavior on a denied screen-share permission:

* Denials are expected outcomes (picker cancelled by the user, OS
  privacy settings, enterprise policy…) and no longer surface as
  exceptions in error tracking; capture an analytics event instead.
* Only OS-level blocks get the modal, since it explains how to
  unblock them.
2026-08-14 11:22:40 +02:00
lebaudantoine ff7a1a4f33 🐛(telemetry) tag in-room permission failures with their own path
Since `ToggleDevice` renders on both the join screen and in the
room, `requestDevicePermission` was reporting in-room denials
through the join-preview handler, inflating the `join_preview_failure`
funnel.

Rename `onJoinPreviewError` to `onMediaPermissionError` and thread
a `path` parameter through, derived from `ToggleDevice`'s existing
`context` prop. In-room failures are now reported under a new
`room_media_failure` code, keeping `join_preview_failure` intact
for existing dashboards.
2026-08-12 14:52:09 +02:00
lebaudantoine 22ab89994b (frontend) add a silent-microphone watcher on join and room screens
Introduce a watcher that listens to the microphone stream and detects
when it stays silent, which is often a sign of an underlying issue:
missing OS permissions, a faulty device, or a hardware lock (e.g. a
physical mute switch).

Wire the watcher on both the join and room screens, so users get a
signal that something is off before it turns into an actual meeting
problem.
2026-08-12 14:52:09 +02:00
lebaudantoine c838229ec9 📈(frontend) snapshot media devices on the happy path
Also snapshot the state of media devices when the user successfully
joins a meeting, not only when something goes wrong. This gives us
the baseline needed to compute meaningful ratios — for example, the
share of users who join a meeting without granting permissions, or
without a microphone or camera available.

Without a happy-path measurement, the current error-only data has no
denominator to compare against.
2026-08-12 14:52:09 +02:00
lebaudantoine ab40ec365d ♻️(frontend) prefer captureMediaEvent over reportError when no-op
Switch calls to `reportError` over to `captureMediaEvent` when the
underlying situation is not an engineering issue to investigate but
rather a media-related event worth tracking (e.g. no camera or
microphone available on the user's device).

`reportError` stays reserved for actual errors that warrant an
engineer's attention.
2026-08-12 14:52:09 +02:00
lebaudantoine 199c0297d4 🐛(frontend) handle missing device errors gracefully
Handle the "requested device not found" error surfaced in production
when users arrive without a microphone or camera available on their
computer. Some devices also have a hardware button that physically
locks the microphone and makes it invisible to the browser.

Instead of failing loudly, surface a clearer state to the user so
they can still proceed with whatever device is actually available.
2026-08-12 14:52:09 +02:00
lebaudantoine 8615bf879c 📈(frontend) capture media diagnostics on media errors
Attach a media diagnostics snapshot to the room event handler for
media exceptions. The snapshot captures the state of the user's
setup at the moment of the error (available devices, permission
state, active tracks, etc.), so support has enough context to
troubleshoot user issues without asking them to reproduce.
2026-08-12 14:52:09 +02:00
lebaudantoine fb3ee56702 ♻️(frontend) encapsulate PostHog capture calls in the telemetry module
Move the remaining direct `posthog.capture` calls behind the
telemetry module, so PostHog is only referenced from a single place.

Call sites now use the telemetry API instead of touching PostHog
directly, making it easier to swap the backend later without
changing every call site.
2026-08-12 14:52:09 +02:00
lebaudantoine 48c0cb320e ♻️(frontend) encapsulate error tracking behind a telemetry module
Introduce a telemetry module that exposes a `reportError` helper.
Under the hood it forwards errors to PostHog, but the module is the
only place that knows about PostHog.

Replace `console.error` calls used for error reporting with
`reportError`, so the codebase now goes through a single, consistent
API for telemetry.

This normalizes how errors are reported and makes it straightforward
to swap PostHog for another backend later on, without touching every
call site.
2026-08-12 14:52:09 +02:00