#687

[Feature Request]: 1 Gbps host microbursts cause UDP packet loss on USB 2.0 / 100M clients (Need sub-millisecond packet pacing)

Openfilgueirasfernandoopened 9d ago

User Story

Problem Description

When the host network adapter operates at 1 Gbps (1000BASE-T) and streams to a client with a downstream bottleneck—such as:

  1. Physical 100 Mbps links / shallow switch buffers, OR
  2. Gigabit USB Ethernet adapters plugged into USB 2.0 host ports (e.g., Xiaomi Mi TV Stick 4K, Chromecast, Fire TV),

Moonlight experiences severe stuttering, packet loss, and frequent session disconnects.

Even if the Ethernet link negotiates at 1 Gbps end-to-end, the host flushes video frames at the full 1 Gbps wire rate in sub-millisecond microbursts. When these 1 Gbps bursts hit the dongle, its internal FIFO buffer overflows trying to serialize data over the slower USB 2.0 bus (~250 Mbps practical limit), causing immediate UDP tail drops and high jitter.

Empirical Evidence & Proof

  1. Physical Link Rate Test (The definitive proof):

    • When forcing the host's physical network adapter to 100 Mbps Full Duplex via Windows device properties (*SpeedDuplex):
      • The streaming becomes 100% smooth and stable, even at high bitrates (up to 80 Mbps).
      • Because the host PHY physically clocks bits at 100 MHz, the burst rate never exceeds 100 Mbps, comfortably fitting within the client's USB 2.0 bus bandwidth.
    • When switching the host back to 1 Gbps, the exact same stream immediately drops packets and lags due to 1 Gbps microbursts.
  2. Current video_max_batch_size_kb Limitation:

    • Setting video_max_batch_size_kb = 16 flushes smaller chunks, but each chunk is still emitted at 1 Gbps line speed (~120 µs) because standard Windows sleep/yield timers lack sub-millisecond precision to space packets evenly across the frame interval.
  3. Host Logs during 1 Gbps Bursts:

    Info: AMF: creating native encoder session 2560x1440@60 codec=2 bitrate=78988kbps (active=1)
    Warning: Skipping FEC for abnormally large encoded frame (needed 5 FEC blocks)
    Info: CLIENT DISCONNECTED

Proposed Feature / Solution

Implement a sub-millisecond UDP packet pacing / token-bucket traffic shaper in the video transport send loop:

  1. Packet Spacing across Frame Budget:

    • Space packets evenly over the frame budget (e.g., across 16.6 ms for 60 FPS) based on a target pacing rate: $$\text{Inter-Packet Interval} = \frac{\text{Packet Size (bits)}}{\text{Pacing Rate (bps)}}$$
  2. High-Resolution Timing on Windows:

    • Use CreateWaitableTimerExW with CREATE_WAITABLE_TIMER_HIGH_RESOLUTION (available since Windows 10 build 1803) or a hybrid QueryPerformanceCounter spin-wait for sub-millisecond intervals.
  3. Exposed Config Options (sunshine.conf):

    • pacing_enabled = true / false
    • pacing_max_rate_mbps = <integer> (e.g., 80, 90, 100 to emulate 100M line-rate pacing on a 1 Gbps NIC without crippling the host's download speeds for other apps).

Environment Details

  • Host OS: Windows 11 / 10 x64
  • Host GPU: AMD Radeon RX 7700 XT (AMF native pipeline)
  • Host NIC: Realtek PCIe GbE Family Controller (1 Gbps)
  • Vibepollo Version: v2.0.0 / v2.0.1
  • Client: Moonlight Android TV (Xiaomi Mi TV Stick 4K with USB 3.0 Gigabit dongle on USB 2.0 OTG port)

Acceptance Criteria

Acceptance Criteria

  • Frame Packet Distribution (Pacing):

    • Outgoing video UDP packets are evenly distributed across the frame interval (~16.6 ms for 60 FPS) rather than being flushed simultaneously onto the socket in an unmetered 1 ms burst.
    • The instantaneous transmission rate does not exceed the configured/negotiated pacing ceiling (e.g., 80–100 Mbps).
  • Host Link Speed Independence:

    • The host network adapter can remain permanently set to 1 Gbps (1000BASE-T) with full bandwidth available for non-streaming host workloads (downloads, web browsing, local transfers).
  • Zero Packet Loss on 100M / USB 2.0 Bottlenecks:

    • When streaming to a client connected via a 100 Mbps port or a Gigabit adapter over USB 2.0, Moonlight reports 0% network frame loss / tail drops during steady-state gameplay.
    • Host logs no longer trigger Warning: Skipping FEC for abnormally large encoded frame due to sudden socket buffer overruns.
  • Minimal Host Latency Overhead:

    • The high-resolution pacing timer adds negligible host-side delay (< 1 ms extra pipeline latency).
  • Configurability & Safety:

    • Pacing can be configured or toggled in sunshine.conf (e.g., pacing_enabled, pacing_max_rate_mbps).
    • Users on full Gigabit/10G end-to-end setups can disable or increase the pacing limit to maintain unconstrained throughput.

Story Points

3

Priority

Medium

Notes / Additional Context

No response

Activity

0

No activity yet.