Cast your screen, YouTube and media to Chromecast & LG webOS TVs on Linux, with native screen mirroring.
Schwupp is a self-contained casting app for Linux desktops and Linux phones
(Phosh, e.g. FuriPhone FLX1). It streams your screen, YouTube and local media to the TV
and supports both Chromecast / Google TV and LG webOS from a single adaptive
GTK4/libadwaita interface — without depending on external CLI tools like catt.
The interface follows your system language (English and German included; English is the fallback for unsupported locales).
| Feature | Chromecast / Google TV | LG webOS (2024+) | AirPlay 2 (Hisense, Samsung …) |
|---|---|---|---|
| Automatic discovery | ✅ | ✅ | ✅ |
| Music files | ✅ | ✅ | ✅ |
| Video files | ✅ | ✅ | † |
| YouTube | ✅ (TV's own app) | ✅ (TV's own app) | † (as a video stream) |
| Web videos | ✅ | ✅ | † |
| Play / pause / stop, volume | ✅ | ✅ | — |
| Screen mirroring (native, < 1 s) | ✅ | ✅ | — |
| Screen mirroring (AirPlay, with sound) | — | — | ✅ |
| Screen mirroring (HLS) | ✅ | ✅ | † |
| Sound while mirroring | ✅ | ✅ | ✅ |
† depends on the individual TV. Many AirPlay sets take only audio and refuse every video request — including YouTube and HLS mirroring, which both arrive as a video URL. Schwupp finds this out on the first attempt and then stops offering what that device won't do, so you are not left guessing. Playback controls are not offered at all on AirPlay: these TVs acknowledge the commands and ignore them.
Most TVs are found and connected automatically. Newer LG webOS TVs (≈2024 and later) work just like a Chromecast, including screen mirroring.
AirPlay 2 TVs (Hisense/VIDAA, Samsung Tizen, Sony, older non-Cast models …) pair with the code shown on the TV the first time you connect; the pairing is stored, so this happens only once. Screen mirroring uses a separate protocol and therefore asks for its own code once — see Screen mirroring below.
Do not trust what these TVs advertise: the tested Hisense claims AirPlay video and refuses every playback request — yet mirroring to it works, with sound. On such a set, mirroring is how you get any moving picture there, YouTube included.
Samsung, Sony, Panasonic, Philips and many Hisense TVs without AirPlay are also detected via DLNA and can play your media, web videos and YouTube, with playback and volume control. (Screen mirroring on these needs a Chromecast.)
Mirror your desktop to the TV. (Curious how it works? See docs/MIRRORING.md.)
On AirPlay TVs this uses the AirPlay mirroring protocol by way of doubletake, which the Flatpak bundles. Two things are worth knowing: the TV shows a one-time code the first time, and the receiver probes a UDP timing port on your machine during setup. If a firewall drops that, the session comes up but no picture ever appears — so allow the range Schwupp uses:
sudo ufw allow from <TV-IP> proto udp to any port 60000:60010 comment 'AirPlay Mirroring'Not every AirPlay TV accepts video at all: some only take audio. Schwupp says so plainly instead of leaving you guessing — and on such a TV, mirroring is the way to get a picture there, including for YouTube (there is no startable YouTube app over AirPlay, unlike on LG webOS or Chromecast).
app/
discovery.py unified discovery (Cast, webOS, AirPlay, DLNA)
receivers/ device backends behind one interface:
base.py Receiver interface + feature gating
chromecast.py pychromecast
webos.py pywebostv (control/YouTube) + DLNA (media)
airplay.py pyatv (AirPlay 2: PIN pairing + play_url)
dlna.py generic UPnP media renderers
dlna.py minimal UPnP-AVTransport client
server/ local HTTP server (files w/ Range, HLS, live stream)
sources/ YouTube / web video (yt-dlp)
mirror/ pluggable mirror engines (native, hls, dlnats)
paths.py locates VERSION/lang (git checkout, prefix, Flatpak)
updater.py self-update (git pull or verified ZIP staging)
ui/ GTK4/libadwaita interface (adaptive desktop/phone)
tests/ protocol, server and config tests — no TV required
The GUI only talks to the Receiver interface; which actions appear is driven by
receiver.supports(...). Mirror engines share one base class that handles screen
capture selection, the worker thread and error reporting back into the window.
Pre-built, GPG-signed bundle for x86_64 and aarch64 — ideal for the phone, no build tools needed:
flatpak remote-add --if-not-exists schwupp https://misc-de.github.io/Schwupp/de.cais.Schwupp.flatpakrepo
flatpak install schwupp de.cais.Schwupp
flatpak run de.cais.SchwuppUpdate later with flatpak update de.cais.Schwupp. The signing key is already
embedded in the .flatpakrepo file — nothing needs to be imported separately.
The Flatpak brings everything along, including the X11 screen capture element
and wf-recorder for wlroots compositors without a screen-cast portal.
Prefer to run it from a Git checkout, or compile it yourself? See Building from source & project layout.
git clone https://github.com/misc-de/Schwupp.git
cd Schwupp
make venv # Python environment (uses the system GTK4/GStreamer)
make runThe system libraries needed for this route are listed in
BUILDING.md. To get an app icon and menu entry,
run make install PREFIX=$HOME/.local (no root needed).
Open Schwupp from your app menu. The computer and TV must be on the same network and the TV must be on. The first time you connect to an LG TV, a pairing dialog appears on the TV — confirm it with the remote (the key is then stored). On AirPlay TVs (e.g. Hisense) the TV shows a code instead — type it into the dialog in Schwupp (also stored, one-time).
On startup Schwupp checks that everything it needs is installed: if something required is missing it tells you and stops; if only optional parts are missing it lists them and lets you continue anyway.
Installed as a Flatpak: flatpak update de.cais.Schwupp (the settings page says
so as well).
Running from a Git checkout: go to Settings → App → "Check for updates". Schwupp checks for a newer version and updates itself in place — your settings are kept — and then offers to restart.
Schwupp stands on the shoulders of these projects:
| Project | Used for | License |
|---|---|---|
| pychromecast | Google Cast protocol (incl. bundled casttube for YouTube) |
LGPL-2.1 |
| pywebostv | LG webOS SSAP control | MIT |
| pyatv | AirPlay 2 pairing & playback (Hisense, Samsung …) | MIT |
| yt-dlp | web video extraction (fallback) | Unlicense |
| python-zeroconf | mDNS service discovery | LGPL-2.1 |
| cryptography | AES-128-CTR for the native mirror | Apache-2.0 / BSD |
| requests | HTTP for the updater | Apache-2.0 |
| PyGObject · GTK4 · libadwaita | the user interface | LGPL |
| GStreamer | screen capture & H.264 encoding | LGPL |
| doubletake | AirPlay screen mirroring (the protocol pyatv does not speak) | LGPL-3.0 |
| wf-recorder | Wayland capture where no screen-cast portal exists | MIT |
The native Cast-streaming wire format was derived from the public
Chromium Open Screen Library /
media/cast sources (no code copied). The self-update flow is modeled on the author's
DrivePulse app.
doubletake and wf-recorder are invoked as separate programs — Schwupp does not
link against them — and the Flatpak ships them as standalone binaries alongside the
app. They keep their own licenses, as do all dependencies; the table above is
informational.
A word of thanks is due for the AirPlay work in particular: mirroring from Linux
was long considered impossible without FairPlay, Apple's DRM. That it works here
rests on years of reverse engineering by the
UxPlay and
RPiPlay projects, which doubletake builds on.
Released under the MIT License © 2026 misc-de.
