RoomParticipant now has optional relay_label field. Desktop client
groups participants by relay: "This Relay" (green dot) for local,
peer label (blue dot) for federated. Shows all relays in the chain
including intermediate ones.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds three new codec IDs (Opus32k=6, Opus48k=7, Opus64k=8) and
corresponding STUDIO_32K, STUDIO_48K, STUDIO_64K quality profiles.
All use 20ms frames with minimal FEC (10%) for maximum quality on
good networks.
Updated across: wire protocol (codec_id.rs), encoder/decoder
(opus_enc/dec.rs), adaptive codec switch (call.rs), CLI
(--profile studio-64k), desktop engine + UI slider (8 quality
levels from Studio 64k green to Codec2 1.2k red).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a Quality dropdown (Auto / Opus 24k / Opus 6k / Codec2 3.2k /
Codec2 1.2k) to both the connect screen and settings panel. The
selected profile is passed through to the engine which configures
the encoder and decoder accordingly.
The desktop engine recv path now auto-switches the decoder codec
when incoming packets use a different codec than expected, enabling
cross-codec interop between clients on different quality settings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Identicon generator:
- Deterministic 5x5 symmetric pattern from fingerprint hash
- HSL-derived colors, rendered as inline SVG
- Click any identicon to copy its fingerprint to clipboard
- Used for participants, user identity, and relay servers
Server identity (TOFU — Trust On First Use):
- Ping returns server fingerprint (QUIC peer certificate hash)
- First contact: auto-saved as known fingerprint
- Subsequent pings: compared against known fingerprint
- Lock icons: locked (verified), unlocked (new), warning (changed), red (offline)
- Fingerprint mismatch shows confirmation dialog before connecting
UI updates:
- Participants show identicons instead of letter avatars
- User identity shows identicon + fingerprint on connect screen
- Manage Relays shows identicon per server with lock status
- Relay button shows lock icon instead of colored dot
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New ping_relay Tauri command: QUIC connect with 3s timeout, returns RTT ms
- Relay status shown next to input field: "42ms" (green) or "offline" (red)
- Auto-pings on app startup and debounced on relay input change
- Fix SyncWrapper dead_code warning with #[allow(dead_code)]
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#7 Fingerprint shown before connecting — new get_identity command reads
~/.wzp/identity at startup (generates if missing). Click to copy.
#8 Recent rooms store (relay, room) pairs — clicking a chip fills both
fields. Settings panel shows relay alongside room name. Migrates
old string[] format automatically.
#9 Auto-reconnect on unexpected disconnect — exponential backoff
(1s, 2s, 4s... max 10s), up to 5 attempts. Yellow blinking dot
shows reconnecting state. Stops if user clicks hangup.
#10 Audio handle cleanup — CPAL handles stored in SyncWrapper (no more
mem::forget), dropped properly on CallEngine::stop().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The VPIO/CPAL audio handles were dropped at the end of start(),
killing the audio unit immediately. Audio I/O stopped working
after the first frame.
- Store audio handle in CallEngine via SyncWrapper
- Drop MutexGuard before returning from status() (Send future)
- Audio streams now live for the entire call duration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change status() from blocking_lock to async lock().await —
fixes "Cannot block the current thread from within a runtime" panic
that froze the call timer and broke audio
- Click fingerprint to copy to clipboard (both connect and settings screens)
- Show "Copied!" feedback on click
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
send_datagram() returns Err(Blocked) when the QUIC congestion window
is full. This is transient — the window reopens once ACKs arrive.
Previously, all send paths treated this as fatal (break/return),
which killed the send task and cascaded via tokio::select! to kill
the entire call.
Now: log warning, drop the packet, continue. Brief audio glitch
(20-100ms) instead of complete call death. FEC on the receiver
side recovers most dropped packets.
Fixed in:
- CLI run_live send task (continue + error counter)
- CLI run_file_mode send paths (2 locations)
- Desktop engine send task
Also hardened recv tasks: transient errors (non-closed/reset)
are survived instead of causing exit.
Matches the fix applied to Android client (engine.rs).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Audio level meter with log-scale RMS visualization
- Call duration timer
- VPIO (OS AEC) wired through to engine with fallback to CPAL
- "You" badge on own participant entry
- Recent rooms list (click to reuse)
- Enter key to connect from form fields
- Improved dark theme with pulse animation on status dot
- Settings persistence via localStorage (relay, room, alias, AEC, recent rooms)
- Fingerprint display on connect screen
- Keyboard shortcuts skip input fields
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New desktop/ directory with Tauri v2 + Vite + TypeScript
- Rust backend: CallEngine wrapping wzp-client audio + transport
- Web frontend: connect screen, in-call screen with participants,
mic/speaker mute, keyboard shortcuts (m/s/q)
- Dark theme UI, settings persistence via localStorage
- Platform-aware --os-aec: warns on Windows/Linux (not yet implemented)
- Workspace updated to include desktop/src-tauri
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>