Siavash Sameni 8c4d640f89
Some checks failed
Mirror to GitHub / mirror (push) Failing after 40s
Build Release Binaries / build-amd64 (push) Failing after 3m43s
fix(android): playout Usage::Media + relay CallSetup advertises real IP
Three real bugs, one smoke-test session's worth of progress.

1. RELAY: wrong advertised addr in CallSetup
   The direct-call CallSetup computed `relay_addr = addr.ip()` where
   `addr = connection.remote_address()` — i.e. the CLIENT'S IP, not the
   relay's. So the relay was telling both parties "the call room is at
   the answerer's IP:4433", which meant each client dialed either the
   other client (no server listening) or themselves. Both endpoint.connect
   calls hung forever and the call never happened.
   Fix: compute the relay's own advertised IP once at startup. If the
   listen addr is 0.0.0.0, probe the primary outbound interface via the
   classic UDP-bind-and-connect(8.8.8.8:80) trick to discover the LAN
   IP the OS would use to reach external hosts. Thread the resulting
   advertised_addr_str into the CallSetup sender for both parties.

2. RELAY: accept loop serialized QUIC handshakes
   Previously the main accept loop called `wzp_transport::accept` which
   did both `endpoint.accept().await` AND `incoming.await` (the server-
   side QUIC handshake). A single slow handshake therefore blocked every
   subsequent client from being accepted. Unroll the helper here and
   move `incoming.await` into the per-connection spawned task, so every
   handshake runs in parallel. Also log "accept queue: new Incoming",
   "QUIC handshake complete", and "QUIC handshake failed" so we can tell
   immediately whether a client's packets are reaching the relay at all.

3. ANDROID: playout was routed to the silent in-call stream
   The Oboe playout stream was configured with Usage::VoiceCommunication,
   which routes to the Android in-call earpiece stream. That stream is
   silent unless the Activity has called AudioManager.setMode(
   IN_COMMUNICATION) and, even then, only the earpiece/BT headset get
   audio (not the loud speaker). Result: android→mac calls worked
   because mac had a normal media output, but mac→android calls were
   silent even though packets flowed through the relay just fine.
   Switch to Usage::Media + ContentType::Speech so Oboe routes to the
   loud speaker and uses the media volume slider. A later polish step
   will wire setMode + setSpeakerphoneOn from MainActivity.kt so we can
   go back to VoiceCommunication for AEC and proximity-sensor routing.

Plus: heartbeat tracing every 2s in the send/recv tasks — frames_sent,
last_rms, last_pkt_bytes, short_reads on the send side; decoded_frames,
last_decode_n, last_written, decode_errs on the recv side. Will make the
next "no sound" regression trivial to localize.
2026-04-09 20:55:10 +04:00

WarzonePhone

Custom lossy VoIP protocol built in Rust. E2E encrypted, FEC-protected, adaptive quality, designed for hostile network conditions.

Quick Start

# Build
cargo build --release

# Run relay
./target/release/wzp-relay --listen 0.0.0.0:4433

# Send a test tone
./target/release/wzp-client --send-tone 5 relay-addr:4433

# Web bridge (browser calls)
./target/release/wzp-web --port 8080 --relay 127.0.0.1:4433 --tls
# Open https://localhost:8080/room-name in two browser tabs

Architecture

See docs/ARCHITECTURE.md for the full system architecture with Mermaid diagrams covering:

  • System overview and data flow
  • Crate dependency graph (8 crates)
  • Wire formats (MediaHeader, MiniHeader, TrunkFrame, SignalMessage)
  • Cryptographic handshake (X25519 + Ed25519 + ChaCha20-Poly1305)
  • Identity model (BIP39 seed, featherChat compatible)
  • Quality profiles (GOOD/DEGRADED/CATASTROPHIC)
  • FEC protection (RaptorQ with interleaving)
  • Adaptive jitter buffer (NetEq-inspired)
  • Telemetry stack (Prometheus + Grafana)
  • Deployment topology

Features

  • 3 quality tiers: Opus 24k (28.8 kbps) / Opus 6k (9 kbps) / Codec2 1200 (2.4 kbps)
  • RaptorQ FEC: Recovers from 20-100% packet loss depending on tier
  • E2E encryption: ChaCha20-Poly1305 with X25519 key exchange
  • Adaptive jitter buffer: EMA-based playout delay tracking
  • Silence suppression: VAD + comfort noise (~50% bandwidth savings)
  • ML noise removal: RNNoise (nnnoiseless pure Rust port)
  • Mini-frames: 67% header compression for steady-state packets
  • Trunking: Multiplex sessions into batched datagrams
  • featherChat integration: Shared BIP39 identity, token auth, call signaling
  • Prometheus metrics: Relay, web bridge, inter-relay probes
  • Grafana dashboard: Pre-built JSON with 18 panels

Documentation

Document Description
ARCHITECTURE.md Full system architecture with diagrams
TELEMETRY.md Prometheus metrics specification
INTEGRATION_TASKS.md featherChat integration tracker
WZP-FC-SHARED-CRATES.md Shared crate strategy
grafana-dashboard.json Importable Grafana dashboard

Binaries

Binary Description
wzp-relay Relay daemon (SFU room mode, forward mode, probes)
wzp-client CLI client (send-tone, record, live mic, echo-test, drift-test, sweep)
wzp-web Browser bridge (HTTPS + WebSocket + AudioWorklet)
wzp-bench Component benchmarks

Linux Build

./scripts/build-linux.sh --prepare   # Create Hetzner VM + install deps
./scripts/build-linux.sh --build     # Build release binaries
./scripts/build-linux.sh --transfer  # Download to target/linux-x86_64/
./scripts/build-linux.sh --destroy   # Delete VM

Tests

cargo test --workspace   # 272 tests

License

MIT OR Apache-2.0

Description
No description provided
Readme 147 MiB
Languages
Rust 78%
Kotlin 7.9%
Shell 6.7%
TypeScript 3.2%
C++ 1.5%
Other 2.6%