Commit Graph

7 Commits

Author SHA1 Message Date
Siavash Sameni
086a74782f feat(codec): Phase 0 — swap audiopus → opusic-c + opusic-sys (libopus 1.5.2)
Phase 0 of the DRED integration (docs/PRD-dred-integration.md). No behavior
change: inband FEC stays ON, no DRED, same bitrate, same quality. This
commit unblocks Phase 1+ by getting us onto libopus 1.5.2 where DRED lives.

Rationale for going straight to a custom DecoderHandle: opusic-c::Decoder's
inner *mut OpusDecoder pointer is pub(crate), so we cannot reach it for the
Phase 3 DRED reconstruction path. Running two parallel decoders (one for
audio, one for DRED) would drift because the DRED decoder wouldn't see
normal decode calls. Single unified DecoderHandle over raw opusic-sys is
the only correct architecture, so we build it in Phase 0 rather than
rewriting opus_dec.rs twice.

Changes:
- Cargo.toml (workspace + wzp-codec): remove audiopus 0.3.0-rc.0, add
  opusic-c 1.5.5 (bundled + dred features), opusic-sys 0.6.0 (bundled),
  bytemuck 1. Pinned exactly for reproducible libopus 1.5.2.
- opus_enc.rs: rewritten against opusic_c::Encoder. Argument order for
  Encoder::new swapped (Channels first). set_inband_fec(bool) now maps
  to InbandFec::Mode1 (the libopus 1.5 equivalent of 1.3's LBRR). encode
  uses bytemuck::cast_slice<i16,u16> at the &[u16] boundary.
- dred_ffi.rs (new): DecoderHandle wrapping *mut OpusDecoder directly via
  opusic-sys. Owns the allocation, frees on Drop. Exposes decode,
  decode_lost, and a pub(crate) as_raw_ptr() for the future Phase 3 DRED
  reconstruction. Send+Sync justified via &mut self access discipline.
- opus_dec.rs: rewritten as a thin AudioDecoder impl over DecoderHandle.
  Behavior identical to pre-swap.

Verification (Phase 0 acceptance gates):
- cargo check --workspace: clean (30 pre-existing warnings in jni_bridge.rs
  unrelated to this work; zero in changed files).
- cargo test -p wzp-codec: 53 tests pass (50 pre-swap + 6 new: 3 in
  dred_ffi.rs for DecoderHandle lifecycle, 3 in opus_enc.rs for version
  check and roundtrip).
- linked_libopus_is_1_5 test asserts opusic_c::version() contains "1.5" —
  hard signal that the swap landed correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:15:55 +04:00
Siavash Sameni
087bfd2335 feat: deterministic TLS certificate from relay identity seed
The relay's TLS certificate is now derived from the persisted
Ed25519 seed via HKDF, so the same seed produces the same cert
and the same TLS fingerprint across restarts. This fixes the
"Server Key Changed" warnings on every relay restart.

Implementation: HKDF-SHA256(seed, "wzp-tls-ed25519") → Ed25519
signing key → PKCS8 DER → rcgen KeyPair → self-signed cert.

Also adds tls_fingerprint() helper (SHA-256 of DER cert, hex with
colons) and prints it on startup. This is the prerequisite for
relay federation (peers verify each other by TLS fingerprint).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 22:10:08 +04:00
Claude
26e9c55f1f feat: Android VoIP client — Phase 1 (audio quality, network adaptation, crate skeleton)
- New wzp-android crate with Oboe C++ backend, lock-free SPSC ring buffers,
  engine orchestrator, codec pipeline, and Android Gradle project structure
- AEC (NLMS adaptive filter), AGC (two-stage with fast attack/slow release),
  windowed-sinc FIR resampler replacing linear interpolation (wzp-codec)
- Opus encoder tuning: complexity 7 default, set_expected_loss support
- Mobile jitter buffer: asymmetric EMA (fast up/slow down), handoff spike
  detection with 2s cooldown, configurable safety margin
- Network-aware quality control: cellular-specific thresholds, faster
  downgrade on cellular, proactive tier drop on WiFi→cellular handoff,
  FEC ratio boost during network transitions
- Handoff detection in PathMonitor via RTT jitter spike analysis

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 18:07:55 +00:00
Siavash Sameni
bf56d84ef0 test: 17 new tests for S-4/5/6/7/9 integration tasks
S-4 Room hashing + ACL (8 tests in featherchat_compat.rs):
- hash_room_name: deterministic, 32 hex chars, different inputs differ
- hash_room_name_matches_fc_convention: manual SHA-256 verification
- room_acl: open mode, enforced mode, allow-listed, deny-unlisted

S-5 Handshake integration (4 tests in handshake_integration.rs):
- handshake_succeeds: real QUIC, encrypt/decrypt cross-verified
- handshake_verifies_identity: different seeds, session still works
- auth_then_handshake: AuthToken + CallOffer/Answer in sequence
- handshake_rejects_bad_signature: tampered sig → error

S-6/7/9 Web+Proto+TLS (5 tests in featherchat_compat.rs):
- auth_response_with_eth_address: FC's extra field handled
- wzp_proto_has_auth_token_variant: serialize/deserialize roundtrip
- all_fc_call_signal_types_representable: all 7 types verified
- hash_room_name_used_as_sni_is_valid: unicode/special chars → valid hex
- wzp_proto_cargo_toml_is_standalone: no workspace inheritance

196 total tests passing across all crates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 10:09:34 +04:00
Siavash Sameni
3f128936c4 feat: web bridge — browser-based voice calls via WebSocket
New wzp-web crate serves a web page with:
- Browser mic capture via Web Audio API (48kHz mono)
- WebSocket transport for raw PCM audio
- Server-side Opus encode/decode + FEC through wzp relay
- Real-time audio playback in browser
- Level meter and connection stats

Usage:
  wzp-relay --listen 0.0.0.0:4433    # start relay
  wzp-web --port 8080 --relay 127.0.0.1:4433  # start web bridge
  Open http://localhost:8080 in browser

Two browsers connected to the same relay get bridged for a call.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:23:39 +04:00
Siavash Sameni
79f9ff1596 feat: Phase 3 — crypto handshake, codec2, benchmarks, audio I/O, relay forwarding
E2E crypto handshake:
- Client/relay handshake via SignalMessage (CallOffer/CallAnswer)
- X25519 ephemeral key exchange with Ed25519 identity signatures
- Integration tests proving bidirectional encrypt/decrypt

Codec2 integration:
- Pure Rust codec2 crate (v0.3) — no C bindings needed
- MODE_3200 (160 samples/20ms, 8 bytes) and MODE_1200 (320 samples/40ms, 6 bytes)
- 11 new tests including encode/decode roundtrip and adaptive switching

Relay forwarding:
- Bidirectional client → remote forwarding with pipeline processing
- CLI args: --listen, --remote
- Periodic stats logging, clean shutdown via tokio::select!

Benchmark tool (wzp-bench):
- Codec roundtrip, FEC recovery, crypto throughput, full pipeline benchmarks
- Sine wave PCM generator for realistic testing

Audio I/O (cpal):
- AudioCapture (microphone) and AudioPlayback (speakers) at 48kHz mono
- CLI --live mode: mic → encode → send / recv → decode → speakers

120 tests passing, 0 failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:43:22 +04:00
Siavash Sameni
51e893590c feat: WarzonePhone lossy VoIP protocol — Phase 1 complete
Rust workspace with 7 crates implementing a custom VoIP protocol
designed for extremely lossy connections (5-70% loss, 100-500kbps,
300-800ms RTT). 89 tests passing across all crates.

Crates:
- wzp-proto: Wire format, traits, adaptive quality controller, jitter buffer, session FSM
- wzp-codec: Opus encoder/decoder (audiopus), Codec2 stubs, adaptive switching, resampling
- wzp-fec: RaptorQ fountain codes, interleaving, block management (proven 30-70% loss recovery)
- wzp-crypto: X25519+ChaCha20-Poly1305, Warzone identity compatible, anti-replay, rekeying
- wzp-transport: QUIC via quinn with DATAGRAM frames, path monitoring, signaling streams
- wzp-relay: Integration stub (Phase 2)
- wzp-client: Integration stub (Phase 2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:45:07 +04:00