Aethersea Develop

Internal Architecture

A detailed tour of Leviathan streaming, capture, encoding, and control internals.

A detailed look at Leviathan's internal pipeline and platform-level implementation.

Streaming Pipeline

gRPC (TLS) Session stream
    └─► signaling.Server
            └─► streaming.SessionManager.CreateSession()
                    └─► WebRTC PeerConnection (media) + PeerConnection (control)
                            ├─ darwinPipeline / windowsPipeline
                            │   ├─ capture.CaptureHub → shared capture instance
                            │   │   └─ Subscriber (per session) → raw frames
                            │   ├─ encoder.VideoEncoder → H.265/AV1 RTP
                            │   ├─ audio.OpusEncoder → Opus RTP
                            │   ├─ FecEncoder → Reed-Solomon parity packets (dynamic %)
                            │   └─ WebRTC VideoTrack/AudioTrack injection
                            ├─ Control DataChannel
                            │   ├─ input.VirtualInput (keyboard/mouse/gamepad)
                            │   ├─ clipboard.ClipboardSync
                            │   ├─ cursor overlay (WebP over DataChannel)
                            │   └─ filetransfer.DataChannelTransfer
                            └─ Telemetry DataChannel
                                └─ RTT (from RTCP RR), heartbeat, server stats

Connection Flow

  1. A Shen client initiates a gRPC session stream to signaling.Server.
  2. SessionManager.CreateSession() creates a new WebRTC peer connection pair — one for media, one for control.
  3. The platform-specific pipeline (darwinPipeline or windowsPipeline) is started, which:
    • Subscribes to the shared CaptureHub instance (creates one if none exists).
    • Receives raw frames via per-subscriber channels and feeds them to the hardware encoder.
    • On Windows, if another session is already subscribed to the same hub, the encoder is automatically promoted to cross-device mode: it allocates its own D3D11 device instead of reusing the capture's shared device, preventing two encoders from contending on the same Video Processor immediate context.
    • Encodes video to H.265 or AV1 RTP packets using a long GOP strategy (no periodic IDR — keyframes are on-demand only).
    • Encodes system audio to Opus RTP packets.
    • Applies Reed-Solomon FEC with dynamic overhead (5–25%) based on measured RTT.
    • Injects encoded tracks into the WebRTC media connection.
  4. The control DataChannel handles input events, clipboard sync, cursor overlays, and file transfers.
  5. The telemetry DataChannel sends periodic heartbeats with RTT measurements derived from RTCP Receiver Reports.
  6. If the client did not set AudioConfig.play_on_host, the internal/hostaudio package mutes the host's default render endpoint for the duration of the session (Sunshine-compatible behaviour). A refcount ensures the host is unmuted only after the last "mute-requesting" session ends, and the endpoint's original mute state is restored rather than unconditionally cleared.

Platform Support Matrix

FeaturemacOSWindowsLinux
Screen captureScreenCaptureKit via CaptureHub (CGO)DXGI Desktop Duplication via CaptureHub (CGO)stub
Video encodeVideoToolbox + SVT-AV1 (CGO)Media Foundation + SVT-AV1 (CGO)stub
Audio encodelibopus (CGO)libopus (CGO)stub
Host audio muteCoreAudio (CGO)IAudioEndpointVolume (CGO)stub
Input injectionCGEvent / Objective-CSendInput + ViGEmstub
Cursor captureNSCursorGetCursorInfostub
ClipboardNSPasteboard + helper IPCWin32 Clipboard (base64 text encoding)stub

CGO Platform Backends

Leviathan uses CGO extensively for platform-specific functionality. Native code is organized under cgo/:

  • cgo/macos/ — Objective-C and C sources for macOS: screen capture via ScreenCaptureKit, video encoding via VideoToolbox, input injection via CGEvent, cursor capture via NSCursor, and audio encoding via libopus.
  • cgo/windows/ — C headers and prebuilt libraries for Windows: screen capture via DXGI Desktop Duplication, video encoding via Media Foundation, input injection via SendInput and ViGEm (virtual gamepad).

macOS Clipboard Helper

On macOS, clipboard sync requires a separate helper process (clipboard-helper) because NSPasteboard's declareTypes:owner: (lazy/delayed rendering) requires an active NSApplication run loop. Without one, Universal Clipboard / Handoff immediately steals pasteboard ownership and deferred data callbacks never fire.

The helper process communicates via Unix domain socket using 4-byte little-endian length-prefixed protobuf messages. See the Clipboard Helper documentation for details.

Clipboard Push Gating (Host → Client)

To avoid echoing the user's own actions back to the session that just produced them, the host's clipboardCaptureLoop suppresses image and file / folder announcements for 2 seconds after any keyboard, mouse, touch, or UTF-8 text-input event arrives on the control DataChannel. Plain text clipboard sync is never gated — text is small enough that immediate sync stays worthwhile even during active remote control.

Gamepad input deliberately does not trigger the gate: Shen clients keep sending GamepadState packets even when the controller is idle, so counting them would keep suppression permanently active for any session with a controller plugged in.

The window is defined by remoteControlInputWindow in internal/streaming/pipeline.go. Each darwinPipeline / windowsPipeline carries a lastInputAt atomic timestamp that the input handlers update on every received key / mouse / touch / text event; clipboardCaptureLoop consults it via isRemoteControlActive() before emitting a ClipboardAnnouncement for image or file content.

Proto File Reference

FilePurpose
signaling.protoSignalingService — bidirectional gRPC stream for SDP/ICE exchange; SessionConfig
control.protoDataChannel messages: KeyEvent, MouseEvent, GamepadState, TouchEvent, IDRRequest, RumbleFeedback, StatsReport, BitrateEstimate, ServerTelemetryEvent
pairing.protoClient pairing / authentication RPC
management.protoServer management RPC
clipboard.protoClipboard sync messages
clipboard_helper.protoIPC with macOS clipboard-helper helper process
overlay.protoCursor / overlay DataChannel messages

Regenerating Proto Files

When .proto files change, regenerate the Go code:

make proto

This requires protoc, protoc-gen-go, and protoc-gen-go-grpc to be installed. Run make deps to install the Go protoc plugins.

On this page