cmux-next iOS: WireGuard by default, WebRTC media session for browser video

Draft
AZ
17d ago
+4258-133

Summary

cmux-next iOS: WireGuard becomes the default link, and browser video rides a WebRTC media session beside it.

  • Default transport. New installs dial WireGuard. A saved choice stays. Settings → Transport lists "WireGuard (recommended)" and "WebRTC only". "WebRTC only" behaves as before.
  • Media session. When the link is WireGuard, the phone opens a WebRTC peer connection to the same Mac's cnx-hostd. It carries only the browser video track. It uses the same TeamHub signaling (webrtc-offer with a new mediaFor) and the same Cloudflare TURN credentials. It is negotiated with a new webrtc-media lane in wg-init/wg-resp.
  • Routes and fallback. The Mac's media lane has two routes: the media session's track (preferred) and RTP in the tunnel (the floor). Video changes route only at a keyframe. A dead session (ICE failed/closed) or a silent one (500 ms without TWCC feedback) falls back to the tunnel, then to the browser channel as before. Video moves back when the session is up again. The phone gates sources by keyframe and capture time, so a late frame from the old route never reaches the decoder.
  • Lifecycle. The session opens lazily: on a shown browser tab, or on a warm-up when the workspace has browser tabs. It closes 30 s after no tab is visible, or when the app goes to the background. It never delays the link or the terminal.
  • Mac. hostd answers a media offer only for a live WireGuard link of the same phone device and owner that passed pairing. There is no new trust path.
  • Input. Input stays on the WireGuard input lane (see verify/hybrid-link.md "Input path").
  • Labels.
    • Phone: "Connected · WireGuard direct · video WebRTC (TURN) · 14 ms".
    • Mac: phone_media event; the iPhone card shows "Video over WebRTC (TURN)".

The contract is in PROTOCOL.md under "Media session". Design, tests, review and live measurements are in cnx-ios/verify/hybrid-link.md.

Tests

  • Rust (rbx): cargo test --workspace green; clippy -D warnings and fmt clean. New:
    • cnx-link/tests/hybrid.rs (4 tests: switch, fallback and return, silent stall, Block UDP, older peers);
    • media::routes (7);
    • the gate tests in media;
    • cnx-ffi browser_video_rides_the_media_session_beside_wireguard;
    • hostd media_session refusal test.
  • The floor-stall fix has a red commit, then a green one.
  • Swift on mini-cmux11s: CnxKit, 411 tests in 109 suites, including the new TransportDefaultTests and LinkStatusMediaTests. CmuxNext CnxHostTests passed as a fleet step.

Review

A fresh correctness-first subagent found 2 must-fix and 2 should-fix issues. All are fixed. The table is in verify/hybrid-link.md.

Live check (real link, mini-cmuxs-mac-mini-3, fleet Mac cnx-e2e-ce1d3585 + Demo simulator)

  • Hybrid vs WireGuard-only. Every frame rode the requested carrier. Glass-to-glass p50 was 40 and 83 ms for hybrid and 56 and 51 ms for WireGuard-only, at 24 to 35 fps. The mini's load was 500 to 900, so the comparison is noisy, and on a direct path the two carriers are within noise.
  • Killed media session. Video moved to tunnel RTP in 0.23 s and back to WebRTC 1.0 s later. Each switch happened at a keyframe.
  • Silent black hole. The stall was detected in 595 ms and video fell back. It returned within 0.4 s after the black hole was removed. The longest frame gap was 650 ms, and the tab never went black.
  • Block UDP. The link ran over TURN over TLS. The media session failed and retried with backoff, and video stayed on tunnel RTP.
  • Phone label. Settings → Devices shows "Connected · WireGuard direct · video WebRTC (direct) · 0 ms". The picker shows "WireGuard (recommended)" and "WebRTC only".
  • Not checked live. The Mac's iPhone card was not looked at in the GUI because that would need focus. It is unit-tested.

Changelog

none (cmux-next iOS, unreleased)

🤖 Generated with Claude Code