fix(audio+net): revert dual-stack [::]:0, add Oboe playout stall auto-restart
Two fixes: ## Revert [::]:0 dual-stack sockets → back to 0.0.0.0:0 Android's IPV6_V6ONLY=1 default on some kernels (confirmed on Nothing Phone) makes [::]:0 IPv6-only, silently killing ALL IPv4 traffic. This broke P2P direct calls: IPv4 LAN candidates (172.16.81.x) couldn't complete QUIC handshakes through the IPv6-only socket, causing local_direct_ok=false and relay fallback on every call after the first. Reverted all bind sites to 0.0.0.0:0 (reliable IPv4). IPv6 host candidates are disabled in local_host_candidates() until a proper dual-socket approach (one IPv4 + one IPv6 endpoint, Phase 7) is implemented. ## Fix A (task #35): Oboe playout callback stall auto-restart The Nothing Phone's Oboe playout callback fires once (cb#0) and then stops draining the ring on ~50% of cold-launch calls. Fix D+C (stop+prime from previous commit) didn't help because audio_stop is a no-op on cold launch. New approach: self-healing watchdog in audio_write_playout. Tracks the playout ring's read_idx across writes. If read_idx hasn't advanced in 50 consecutive writes (~1 second), the Oboe playout callback has stopped: 1. Log "playout STALL detected" 2. Call wzp_oboe_stop() to tear down the stuck streams 3. Clear both ring buffers (prevent stale data reads) 4. Call wzp_oboe_start() to rebuild fresh streams 5. Log success/failure 6. Return 0 (caller retries on next frame) This is the same teardown+rebuild that "rejoin" does — but triggered automatically from the first stalled call instead of requiring the user to hang up and redial. The watchdog runs on every write so it fires within 1s of the stall starting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -914,13 +914,10 @@ fn do_register_signal(
|
||||
// endpoints, which made MikroTik look symmetric and broke direct
|
||||
// P2P because the advertised reflex port was not the listening
|
||||
// port.
|
||||
// [::]:0 = dual-stack socket — handles IPv4 (via ::ffff:x.x.x.x
|
||||
// mapped addresses) AND native IPv6 on one socket. Critical for
|
||||
// Phase 5.5 ICE host candidates: without dual-stack, the IPv6
|
||||
// candidates advertised in DirectCallOffer/Answer are dead on
|
||||
// arrival — the Dialer can't send to them and the Acceptor can't
|
||||
// receive from them.
|
||||
let bind: std::net::SocketAddr = "[::]:0".parse().unwrap();
|
||||
// 0.0.0.0:0 = IPv4. [::]:0 dual-stack was tried but breaks on
|
||||
// Android (IPV6_V6ONLY=1 on some kernels kills IPv4). IPv6
|
||||
// host candidates need a separate dedicated socket (future).
|
||||
let bind: std::net::SocketAddr = "0.0.0.0:0".parse().unwrap();
|
||||
let (server_cfg, _cert_der) = wzp_transport::server_config();
|
||||
let endpoint = wzp_transport::create_endpoint(bind, Some(server_cfg))
|
||||
.map_err(|e| format!("{e}"))?;
|
||||
|
||||
Reference in New Issue
Block a user