Environment
- Self-hosted stack from
deploy/self-hosting (v1 images pulled 2026-07-03, digest-pinned) - Web client on desktop Chrome (macOS) and iOS Safari — both affected
Symptoms
- Join a voice channel. The mic button shows muted (expected initial state).
- Click the mic toggle to unmute → the button stays visually muted and no audio is published.
- Workaround discovered by a tester: click mute again (while it already looks muted), then unmute → from then on the mic works normally.
On iOS Safari the same behavior presents as "can't open the mic at all" until the double-toggle workaround is used, so first-time mobile users assume voice is broken.
Console evidence (desktop Chrome)
On join:
[LocalVoiceState] [Info] Microphone permission granted, restoring persisted mute preference
publishing track
[VoiceEngineV2AppMediaExecutionAdapter] [Info] Successfully enabled microphone
Each subsequent click only logs:
[VoiceStateCommands] [Info] toggleSelfMute
…with no visible state change and no track unmute, until the double-toggle workaround is applied.
Suspected cause
The persisted mute preference restored at join appears to get out of sync with the actual toggle state — the first
toggleSelfMute seems to be consumed reconciling the restored preference rather than changing the effective state.
Impact
First-join UX: users (especially on mobile) believe the microphone is broken. Once the double-toggle is done, voice works reliably (tested UDP end-to-end, desktop + iOS over 5G).