The endpoint previously used presets::N0, which both relays through n0's
servers and publishes a signed EndpointId->addresses record to n0's public
DNS every time you go online. Since PeerSpeak already exchanges full peer
addresses via the join ticket and gossip, that DNS presence beacon is
redundant here.
Adds a NetworkMode config option (persisted, switchable from Settings):
- RelayNoDiscovery (new default): presets::Minimal + RelayMode::Default +
the in-memory address lookup. Keeps n0 relay for NAT traversal but drops
the DNS publish/resolve, so n0 only ever sees relayed-call metadata, never
a standing online beacon.
- N0Full: previous behavior (relay + DNS) for maximum reliability.
- DirectOnly: RelayMode::Disabled, fully serverless.
The mode is applied when the endpoint is built on room join. Existing
config.json files load unchanged via #[serde(default)].
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the fire-and-forget datagram path with sequenced packets, a
per-peer jitter buffer, and persistent per-peer send tasks. Together these
fix three intertwined weaknesses that only showed up off localhost.
Packet format: every audio frame now carries a 4-byte little-endian
sequence number header ([seq][opus payload]), the basis for reordering and
loss detection.
Jitter buffer (core/jitter.rs): incoming packets are reordered by sequence
behind a fixed ~60ms playout delay. Missing sequences with later packets
already buffered are concealed via Opus PLC (decode(None)) -- a path the
decoder supported but nothing ever invoked. Underruns go idle and re-buffer
rather than concealing indefinitely. Covered by unit tests using real
encoded frames (reorder, gap-conceal, prime, late-drop).
Transport (network/iroh_impl.rs): each peer gets one long-lived send task
fed by a shallow bounded channel (drop-oldest on backpressure), instead of
spawning a throwaway task per peer per 20ms frame. Connections are now
established reactively on peer-join and torn down on peer-leave; the
lexicographically-lower EndpointId dials so a full-mesh pair forms exactly
one shared bidirectional connection instead of two racing ones. This also
removes the previous lock-held-across-connect().await serialization.
Opus decoder: PLC output is now sized to one 20ms frame, so concealment
synthesizes 20ms instead of a 120ms burst from the oversized max buffer.
Known follow-up (Tier 2): no reconnect on transient connection loss; a
send error currently retires the peer until they rejoin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove Gemini's committed update_*.py regex-surgery scripts
- Drop unused iroh-tickets dependency (hand-rolled ticket is used instead)
- Replace ToString antipattern with Display impl on PeerSpeakTicket
- Route debug log to XDG state/cache dir instead of hardcoded /home path
- Clear all compiler + clippy warnings (unused imports, collapsible ifs,
redundant pattern matching, missing Default)
Builds clean with zero warnings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fix tokio runtime panic by spawning a dedicated Tokio runtime thread in CoreController.
- Add central log_msg utility in src/lib.rs for debugging.
- Add instrumentation/logs to join, leave, and gossip events in src/network/gossip.rs.
- Add test_net.rs bin for testing gossip loopback sync.
- Use std::sync::Mutex in IrohGossipState to resolve Tokio block-in-async panics.