The open-source, ultra-low-latency remote desktop and game streaming stack for Linux; built with FFmpeg, UDP, and Qt.
- Codecs: H.264 / H.265 (HEVC) via NVENC, QSV, VAAPI, AMF, or CPU.
- Transport: Video over MPEG-TS/UDP, audio over UDP, control (mouse, keyboard, gamepad), and clipboard over UDP; handshake & file upload over TCP.
- Controller Support: Forwards gamepad input from client→host using UDP and a
uinputvirtual device on the host; compatible with Xbox, DualSense, 8BitDo, and others. - Multi-monitor: Stream one or multiple monitors.
- Clipboard & Drag-and-Drop: Bi-directional clipboard; client→host file upload (TCP).
- Link-aware: Client auto-detects Wi-Fi vs LAN and the host adapts buffers accordingly.
- Resilience: Heartbeat (PING/PONG); host auto-stops and returns to Waiting for connection if the client drops.
- Stats Overlay (Client): FPS / CPU / RAM overlay via OpenGL (triple-buffered PBO uploads).
LinuxPlay exists for people who like their tools fast, open, and understandable.
No accounts, no mystery daemons, no “trust us” black boxes, just a lean pipeline built on FFmpeg and UDP that runs entirely on your machines.
It’s tuned for low latency and high control: you choose the codec, the bitrate, the buffers, and how aggressive you want to be.
Stream your desktop, your game, or your workflow with knobs that actually do something, because you can see (and tweak) every step.
Ideal for developers, tinkerers, and power users who enjoy shaping their stack rather than being shaped by it.
Light warning with a smile: LinuxPlay gives you real horsepower. If you floor it and the network skids... that’s on purpose.
Client Network Host
------ ------- ----
TCP handshake (7001) <--------------------> Handshake
UDP control (7000) --------------------> xdotool/pynput
UDP clipboard (7002) <--------------------> pyperclip
UDP heartbeat (7004) <--------------------> PING/PONG
UDP gamepad (7005) --------------------> uinput virtual controller
UDP video (5000+idx) <-------------------- FFmpeg capture+encode
UDP audio (6001) <-------------------- FFmpeg Opus (optional)
TCP upload (7003) ---------------------> ~/LinuxPlayDrop
sudo apt update && sudo apt install -y ffmpeg xdotool xclip pulseaudio-utils libcap2-bin wireguard-tools qrencode python3 python3-venv python3-pip libgl1 python3-evdevIf
pip install avfails, install FFmpeg dev headers:
sudo apt install -y pkg-config python3-dev libavdevice-dev libavfilter-dev libavformat-dev libavcodec-dev libswscale-dev libswresample-dev libavutil-dev
python3 -m venv .venv
source .venv/bin/activate # (on Linux/macOS)
# .venv\Scripts\activate # (on Windows PowerShell)python3 -m pip install -U pip wheel setuptools
python3 -m pip install PyQt5 PyOpenGL PyOpenGL_accelerate av numpy pynput pyperclip psutil evdev
evdevis required on Linux clients for controller capture. Hosting already requires Linux; controller forwarding currently supports Linux→Linux.
LinuxPlay can forward a physical controller connected to the client to a virtual controller on the host.
Requirements
- Client: Linux, a gamepad exposed via
/dev/input/event*(e.g. Xbox, DualSense, 8BitDo), andpython-evdev. - Host: Linux with
/dev/uinputavailable (most distros provide this).
Quick start
python3 client.py --host_ip 192.168.1.20 --decoder h.264 --hwaccel auto --gamepad enablepython3 start.py- On Host tab: pick a preset (Lowest Latency / Balanced / High Quality), then Start Host.
- On Client tab: enter the host's LAN IP (or WireGuard tunnel IP).
# Host
python3 host.py --gui --encoder h.264 --hwenc auto --framerate 60 --bitrate 8M --audio enable --gop 15 --pix_fmt yuv420p
# Client
python3 client.py --host_ip 192.168.1.20 --decoder h.264 --hwaccel auto --audio enable --monitor 0 --gamepad enable --debug- Client auto-detects the route to host (Wi-Fi or Ethernet) and announces
NET WIFI/NET LAN. - Host retunes sender buffers accordingly.
- Manual override:
client.py --net wifi|lan(defaultauto).
- Host sends PING every 1 s; expects PONG within 10 s.
- On timeout, host stops streams and waits for reconnection.
- Reconnecting the client restarts video/audio automatically.
| Purpose | Proto | Port |
|---|---|---|
| Handshake | TCP | 7001 |
| Video (per monitor) | UDP | 5000 + index |
| Audio | UDP | 6001 |
| Control (mouse/keyboard) | UDP | 7000 |
| Clipboard | UDP | 7002 |
| File upload | TCP | 7003 |
| Heartbeat (ping/pong) | UDP | 7004 |
| Gamepad (controller) | UDP | 7005 |
- kmsgrab (lowest overhead, no cursor). Grant capability:
sudo setcap cap_sys_admin+ep "$(command -v ffmpeg)" - x11grab is the fallback if kmsgrab isn't viable or you require cursor capture.
- VAAPI encode requires access to
/dev/dri/renderD128(add your user to thevideogroup).
- Lowest Latency: H.264 @ 60–120 fps, GOP 8–15, low-latency tune.
- Balanced: H.264 @ 45–75 fps, 4–10 Mbit/s, GOP 15.
- High Quality: H.265 @ 30–60 fps, 12–20 Mbit/s,
yuv444pif supported.
- For WAN use, tunnel over WireGuard and point the client to the tunnel IP.
A new experimental client (experimental-client.py) is included for advanced users.
This version is a complete rework of the LinuxPlay frontend, faster, smarter, and closer to a true game-streaming platform.
-
Multi-Renderer Backend:
Automatically picks the best available GPU path in this order:
→KMSDRM(direct /dev/dri) →Vulkan→OpenGL
with automatic CPU fallback if no renderer is available. -
Real-Time Stats & Control:
Shows FPS, CPU, RAM, GPU usage, and renderer info in the title bar.
- Requires PyAV built with FFmpeg hardware-accel support.
- GPU decode/encode requires
/dev/dri/renderD128access. - Experimental, expect instability and occasional performance quirks.
- LinuxPlay is licensed under GNU GPL v2.0 only. See LICENSE.
- External tools (FFmpeg, xdotool, xclip, ffplay, etc.) are executed as separate processes and retain their own licenses.
Developed and maintained by Techlm77 :)