Audit: - docs/AUDIT-2026-05-25.md: full protocol audit covering 8 findings (4 critical, 2 high, 5 medium, 4 low) with code references and fix effort estimates - vault/Audit/Tasks.md: Obsidian Tasks plugin file tracking all audit items with priorities, due dates, and per-step checklists Architecture docs updated for Wire format v2 and Wave 5/6 features: - ARCHITECTURE.md: adds wzp-video to dependency graph and project structure; wire format updated to v2 (16B header, 5B MiniHeader); relay concurrency section corrected (DashMap+RwLock is current, not a future optimization); test count 571→702; Android note - PROGRESS.md: Wave 5 and Wave 6 sections appended; test count 372→702; current status and open blockers as of 2026-05-25 - ROAD-TO-VIDEO.md: implementation status table inserted (✅/🟡/🔴/🔲 per phase); 6-step critical path to first video call - WZP-SPEC.md: MediaHeader updated to v2 (16B byte-aligned); MiniHeader updated to 5B with seq_delta; codec IDs 9-12 added (H.264/H.265/AV1); version negotiation section added Obsidian vault (vault/): - 114 files across Architecture/, PRDs/, Reports/, Android/, Reference/, Audit/ with YAML frontmatter - 00 - Home.md index note with wiki links - .obsidian/app.json config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.4 KiB
tags, type
| tags | type | ||
|---|---|---|---|
|
prd |
PRD: Network Awareness
Phase: Implemented (core path)
Status: Ready for testing
Platform: Android native Kotlin app (com.wzp)
Problem
WarzonePhone's quality controller (AdaptiveQualityController) had a signal_network_change() API for proactive adaptation to WiFi↔cellular transitions, but nothing called it. Network handoffs during calls were only detected reactively via jitter spikes — by which time the user had already experienced degraded audio.
Solution
Integrate Android's ConnectivityManager.NetworkCallback to detect network transport changes in real-time and feed them to the quality controller. This enables:
- Preemptive quality downgrade when switching from WiFi to cellular
- FEC boost (10-second window with +0.2 ratio) after any network change
- Faster downgrade thresholds on cellular (2 consecutive reports vs 3 on WiFi)
Architecture
┌──────────────────────────────────────────────────────────────┐
│ Android │
│ │
│ ConnectivityManager │
│ │ NetworkCallback │
│ ▼ │
│ NetworkMonitor.kt │
│ │ onNetworkChanged(type, bandwidthKbps) │
│ ▼ │
│ CallViewModel.kt ──► WzpEngine.onNetworkChanged() │
│ │ JNI │
│ ▼ │
│ jni_bridge.rs: nativeOnNetworkChanged(handle, type, bw) │
│ │ │
│ ▼ │
│ engine.rs: state.pending_network_type.store(type) │
│ │ AtomicU8 (lock-free) │
│ ▼ │
│ recv task: quality_ctrl.signal_network_change(ctx) │
│ │ │
│ ├─ Preemptive downgrade (WiFi → cellular) │
│ ├─ FEC boost 10s │
│ └─ Faster cellular thresholds │
└──────────────────────────────────────────────────────────────┘
Network Classification
NetworkMonitor classifies the active transport without requiring READ_PHONE_STATE permission by using bandwidth heuristics:
| Downstream Bandwidth | Classification | Rust NetworkContext |
|---|---|---|
| N/A (WiFi transport) | WiFi | WiFi |
| >= 100 Mbps | 5G NR | Cellular5g |
| >= 10 Mbps | LTE | CellularLte |
| < 10 Mbps | 3G or worse | Cellular3g |
| Ethernet | WiFi (equivalent) | WiFi |
| Network lost | None | Unknown |
Cross-Task Signaling
The network type is communicated from the JNI thread to the recv task via AtomicU8 — the same pattern used for pending_profile (adaptive quality profile switches):
JNI thread recv task (tokio)
│ │
│ store(type, Release) │
│──────────────────────────────►│
│ │ swap(0xFF, Acquire)
│ │ if != 0xFF:
│ │ quality_ctrl.signal_network_change(ctx)
│ │
Sentinel value 0xFF means "no change pending". The recv task polls on every received packet (~20-40ms), so latency is bounded by the inter-packet interval.
Components
New File
| File | Purpose |
|---|---|
android/.../net/NetworkMonitor.kt |
ConnectivityManager callback, transport classification, deduplication |
Modified Files
| File | Change |
|---|---|
android/.../engine/WzpEngine.kt |
Added onNetworkChanged() method + nativeOnNetworkChanged external |
android/.../ui/call/CallViewModel.kt |
Instantiates NetworkMonitor, wires callback, register/unregister lifecycle |
crates/wzp-android/src/jni_bridge.rs |
Added Java_com_wzp_engine_WzpEngine_nativeOnNetworkChanged JNI entry |
crates/wzp-android/src/engine.rs |
Added pending_network_type: AtomicU8 to EngineState, recv task polls it |
Unchanged (already implemented)
| File | API |
|---|---|
crates/wzp-proto/src/quality.rs |
AdaptiveQualityController::signal_network_change(NetworkContext) |
crates/wzp-transport/src/path_monitor.rs |
PathMonitor::detect_handoff() (available for future use) |
Deferred Work
Tauri Desktop App (com.wzp.desktop)
The Tauri engine doesn't use Update (2026-04-13): Desktop now has AdaptiveQualityController — quality is resolved once at call start.AdaptiveQualityController wired into the recv task with pending_profile AtomicU8 bridge. Network monitoring on desktop is now feasible — the blocker was adaptive quality, which is done. Remaining work: platform-specific network change detection (macOS: SCNetworkReachability or NWPathMonitor; Linux: netlink socket).
Mid-Call ICE Re-gathering — PARTIALLY IMPLEMENTED (2026-04-14)
When the device's IP address changes, the system now:
- Re-gather local host candidates (
local_host_candidates()) ✅ - Re-probe STUN (
stun::discover_reflexive()+portmap::acquire_port_mapping()) ✅ - Send updated candidates to the peer (
CandidateUpdatesignal message) ✅ - Relay forwards
CandidateUpdateto peer (same pattern asMediaPathReport) ✅ - Peer receives and can parse via
IceAgent::apply_peer_update()✅ - Attempt new dual-path race for path upgrade — NOT YET WIRED (transport hot-swap)
NetworkMonitor.onIpChanged fires on onLinkPropertiesChanged — the hook is ready.
The signaling plane is fully implemented via IceAgent + CandidateUpdate.
Remaining: wire onIpChanged → JNI → pending_ice_regather AtomicBool → recv task → ice_agent.re_gather() → transport swap.
New modules added in Phase 8 (Tailscale-inspired):
crates/wzp-client/src/ice_agent.rs— candidate lifecycle managementcrates/wzp-client/src/stun.rs— public STUN server probing (independent of relay)crates/wzp-client/src/portmap.rs— NAT-PMP/PCP/UPnP port mappingcrates/wzp-client/src/netcheck.rs— comprehensive network diagnostic
Testing
- Build native APK
- Start a call on WiFi
- Verify logcat:
quality controller: network context updatedwithctx=WiFi - Disable WiFi → device falls to cellular
- Verify logcat:
ctx=CellularLte(orCellular5g/Cellular3g) - Verify FEC boost activates (check quality_ctrl logs)
- Verify preemptive quality downgrade (tier drops one level on WiFi→cellular)
- Re-enable WiFi → verify transition back
- Rapid WiFi toggle (5x in 10s) → verify no crashes, deduplication works
- Airplane mode → verify
onLostfires withTYPE_NONE