Three streaming scenarios exist depending on where the Head is relative to the Body. Each uses different components and network paths.
The Head and Body are at the same venue, on the same or bridged VLANs.
sequenceDiagram
participant EL as Experience Library
participant H as Head (HydraHead Flatscreen)
participant API as HydraHead API
participant B as Body (Sunshine)
H->>EL: Fetch available experiences
EL-->>H: Experience list
Note over H: User selects experience
H->>API: Query eligible Bodies in district
API-->>H: Eligible Bodies (LAN IP + WireGuard IP)
H->>B: TCP probe LAN IP :47990 (1s timeout)
B-->>H: Reachable
Note over H: discoverBody() selects LAN IP
H->>B: Moonlight pairing (PIN exchange)
H->>B: Moonlight stream (LAN direct, 1080p60, 150 Mbps)
Flow:
discoverBody() which queries the HydraHead API for eligible Bodies in the districtKey code: hydrahead/pkg/client/discovery.go -- discoverBody()
Partner relevance: At partner-managed locations, the partner configures the firewall rule allowing Head VLAN to Body VLAN traffic. This local path is the preferred path for co-located Heads and Bodies.
The Head is at a different location: another venue, home WiFi, or public 4G/5G. Not on the same LAN as the Body.
sequenceDiagram
participant H as Head (HydraHead Flatscreen)
participant API as HydraHead API
participant HUB as District Server (HydraGuard Hub)
participant B as Body (Sunshine)
H->>API: Query eligible Bodies in district
API-->>H: Eligible Bodies (LAN IP + WireGuard IP)
H->>B: TCP probe LAN IP :47990 (1s timeout)
B--xH: Unreachable
Note over H: discoverBody() falls back to WireGuard IP
H->>HUB: WireGuard tunnel
HUB->>B: WireGuard tunnel
H->>B: Moonlight stream (via WireGuard mesh)
Flow:
discoverBody() probes each Body's LAN IP -- fails (1s timeout, not on same network)Key code: hydrahead/pkg/client/discovery.go -- discoverBody() WireGuard fallback path
Partner relevance: Remote Heads on HYDRA-managed locations or public internet use their own WireGuard tunnel to the district server. The network partner does not manage these connections.
The Head is a web browser. No native client installed. Uses WebRTC for streaming.
sequenceDiagram
participant BR as Browser
participant WS as HydraHead WebStream
participant CTL as HydraNeck Controller
participant WK as HydraNeck Worker
participant B as Body (Sunshine)
BR->>WS: WebSocket (district, experience, round-trip time)
WS->>WS: FindBodyForDistrict()
WS->>CTL: POST /api/v1/sessions (body_ip, profile)
CTL->>CTL: Pick least-loaded worker
CTL->>WK: Route session
WK->>B: Spawn moonlight-web-stream (via WireGuard)
WK->>B: Sunshine pairing + app launch
WK-->>BR: stream_url
BR--)WK: WebRTC stream (STUN/TURN)
Flow:
FindBodyForDistrict() to find an eligible Body in the requested districtmoonlight-web-stream which connects to the Body's Sunshine via WireGuardQuality tiers:
| Profile | Resolution | FPS | Bitrate |
|---|---|---|---|
| Excellent (desktop, <50ms round-trip) | 1080p | 60 | 15 Mbps |
| Good (desktop, 50-100ms) | 1080p | 60 | 10 Mbps |
| Mobile Good (<75ms) | 720p | 60 | 7 Mbps |
| Poor (>200ms) | 720p | 30 | 5 Mbps |
Key code:
hydraheadwebstream/internal/client/hydracluster.go -- FindBodyForDistrict()hydraneckwebrtc/internal/api/controller.go -- session routinghydraneckwebrtc/internal/streaming/manager.go -- session lifecyclePartner relevance: Browser-based Heads do not need any partner infrastructure. They connect to HydraNeck WebRTC workers directly over the public internet. The workers reach Bodies via the WireGuard mesh.
| Head Location | Head Type | Path | Latency | Managed By |
|---|---|---|---|---|
| Same venue | Native | Direct LAN (VLAN) | Lowest | Partner (firewall) |
| Same venue | Browser | WebRTC via district | Medium | HYDRA |
| Different venue | Native | WireGuard via district | Medium | HYDRA |
| Home / public | Native | WireGuard via district | Higher | HYDRA |
| Home / public | Browser | WebRTC via district | Higher | HYDRA |