Performance

Fast is a pipeline, not a setting.

Screen Ferry delivers 60 fps desktop video and less than 30 ms interactive audio latency by removing delay at every stage and refusing to accumulate stale work.

60 fpsCapture cadence
10.67 msAAC-ELD frame
<30 msInteractive audio
LocalCursor presentation

Freshness is the latency budget.

Real-time capture and encode

ScreenCaptureKit captures at a configured 60 fps cap. VideoToolbox uses real-time mode, zero maximum frame delay, and no frame reordering.

Newest complete frame

The Client presents the newest useful complete frame. Old queued frames and incomplete assemblies expire instead of playing late.

Direct Metal presentation

Decoded NV12 buffers remain GPU-friendly through BT.709 conversion in the Metal fragment shader, avoiding an extra CPU conversion and copy.

Viewport-aware sharpness

The Client communicates its viewport and the Host selects an appropriate display mode so macOS lays out a legible desktop before it is captured.

The cursor gets its own path

Pointer motion is too important to bake into video.

The Host sends cursor position, visibility, and shape independently. The Client draws the pointer locally and predicts movement immediately, then reconciles against authoritative Host state.

This avoids waiting for capture, encode, transport, decode, and presentation just to move a pointer across the screen.

flowchart LR
  INPUT["Local pointer movement"] --> PREDICT["Client predicts and draws"]
  PREDICT --> NOW["Immediate visible motion"]
  INPUT --> HOST["Input sent to Host"]
  HOST --> AUTH["Authoritative macOS cursor state"]
  AUTH --> RECON["Client reconciliation"]
  RECON --> NOW
Cursor motion reaches the screen locally while Host authority keeps position, visibility, and shape correct.

Less than 30 ms interactive audio

Small frames. Bounded queues. A real-time-safe callback.

Screen Ferry uses AAC-ELD at 48 kHz. Its 512-sample frames represent roughly 10.67 ms of audio. An adaptive jitter buffer reacts quickly to arrival variation and returns conservatively to its low-latency operating point.

In-band redundancy can carry up to two previous audio blocks for burst-loss recovery. The Core Audio render callback reads a prefilled ring buffer without decoding, allocating, logging, actor calls, or locks.

flowchart LR
  CAP["ScreenCaptureKit audio"] --> AAC["AAC-ELD · 512 samples · 10.67 ms"]
  AAC --> QUEUE["Bounded real-time queue"]
  QUEUE --> NET["Prioritized sealed datagrams"]
  NET --> JITTER["Adaptive jitter + redundancy"]
  JITTER --> RING["Prefilled lock-free ring"]
  RING --> OUTPUT["Core Audio output"]
The audio path is engineered to deliver less than 30 ms interactive latency without allowing queues to grow unchecked.

Adapt without interruption

The stream changes in place.

Receiver reports carry RTT, loss, decode time, render-queue depth, freezes, and delivered bitrate. The Host combines them with measured relay egress and congestion feedback.

The running VideoToolbox session adjusts bitrate and its hard one-second cap without restarting. Audio quality follows a tiered link budget rather than simply disappearing under pressure.

Turn on P2P mode to let Screen Ferry qualify a shorter direct route when it is faster.