diff --git a/docs-site/content/docs/configuration.md b/docs-site/content/docs/configuration.md index 84dc0952..f811e8f2 100644 --- a/docs-site/content/docs/configuration.md +++ b/docs-site/content/docs/configuration.md @@ -36,6 +36,7 @@ redundant or stale. |---|---|---| | `PUNKTFUNK_COMPOSITOR` | `kwin` · `mutter` · `gamescope` · `wlroots` · `hyprland` (aliases: `kde`/`plasma`, `gnome`, `sway`/`wlr`) | Which backend creates the virtual display. `wlroots` is sway/River; `hyprland` is its own backend. **Leave unset.** Setting it **pins** the backend and turns session-following **off** — per connect *and* mid-stream, so a Desktop ↔ Gaming switch kills the stream instead of being followed. For CI/tests and dedicated single-session appliances only. | | `PUNKTFUNK_VIDEO_SOURCE` | `virtual` · `portal` | `virtual` creates a per-client display at the client's exact mode (the normal choice). `portal` captures an existing monitor instead. | +| `PUNKTFUNK_CAPTURE_MONITOR` | a connector name (`HDMI-A-1`, `DP-2`, …) | Stream a **physical** monitor this host already has instead of creating a virtual display — see [Streamed screen](/docs/virtual-displays#stream-a-real-monitor-instead). List the names with `punktfunk-host list-monitors`. Setting it here **outranks the web console's** choice, so an appliance stays aimed where its operator pointed it; leave it unset to steer from the console. A name that matches no monitor fails the session loudly rather than streaming a different screen. Linux only. | | `PUNKTFUNK_ZEROCOPY` | `1` · `0` *(default on)* | GPU zero-copy capture→encode (dmabuf → CUDA → NVENC, or D3D11 on Windows). **On by default** — no need to set it; it falls back to a CPU path automatically. Set `0` to force the CPU path. One exception: Windows **Intel/QSV** keeps the CPU path by default until zero-copy is validated on Intel hardware — set `1` to try it there. | | `PUNKTFUNK_INPUT_BACKEND` | `libei` · `gamescope` · `wlr` · `uinput` | How input is injected. `libei` for GNOME/KDE, `gamescope` for Bazzite/gamescope, `wlr` for Sway/wlroots **and Hyprland**. Auto-detected with the compositor. | | `PUNKTFUNK_ENCODER` | `auto` · `nvenc` · `vaapi` (Linux) · `amf` · `qsv` (Windows) · `software` | Encoder backend. `auto` (default) detects the GPU vendor: NVIDIA→NVENC, AMD→VAAPI/AMF, Intel→VAAPI/QSV. `software` (aliases `sw`/`openh264`) is the GPU-less H.264 path on both platforms — on Windows `auto` falls back to it when no GPU is found; on Linux it is **explicit-only** (`auto` never picks it). On a multi-GPU Windows box a forced hardware backend whose vendor contradicts the selected GPU (web-console preference) is **overridden** — the adapter wins and the host logs a warning; remove the stale pin. | diff --git a/docs-site/content/docs/host-cli.md b/docs-site/content/docs/host-cli.md index d6863cc5..36f7edd8 100644 --- a/docs-site/content/docs/host-cli.md +++ b/docs-site/content/docs/host-cli.md @@ -86,6 +86,33 @@ hosts from another machine with `punktfunk-probe --discover`. Where multicast do Docker/VLAN setups), pass `--no-mdns` (or set `PUNKTFUNK_MDNS=0`) and add the host in the client by address instead. +## `list-monitors` + +`punktfunk-host list-monitors` prints the **physical** monitors this host's compositor has, by +connector name — which is how you name one for [Streamed +screen](/docs/virtual-displays#stream-a-real-monitor-instead) (in the console, or as +`PUNKTFUNK_CAPTURE_MONITOR`). + +```sh +punktfunk-host list-monitors +``` + +``` +Kwin: + HDMI-A-1 1920x1080@60 at +0,+0 scale 1 Dell U2412M [primary] + DP-2 2560x1440@144 at +1920,+0 scale 1 ACME 27 [PINNED] +``` + +Tags flag what's worth knowing before you pick: `primary`, `disabled` (nothing to stream), `punktfunk +virtual display` (one of ours, not a real head), and `PINNED` for the one currently selected. Linux +only — it reads the live compositor, so run it in (or with the environment of) the session you want +to stream. + +`punktfunk-host mirror-test --monitor [--seconds N] [--cpu]` then proves the whole path — +mirror, capture, frames — with no client involved. It reports the first frame, the frame count and +the negotiated size. Screen recording is damage-driven, so move the mouse on the host while it runs; +an idle desktop legitimately yields almost nothing. + ## `detect-conflicts` `punktfunk-host detect-conflicts` reports other Moonlight-compatible hosts (Sunshine, Apollo, and diff --git a/docs-site/content/docs/running-as-a-service.md b/docs-site/content/docs/running-as-a-service.md index bb06b16b..38521ae3 100644 --- a/docs-site/content/docs/running-as-a-service.md +++ b/docs-site/content/docs/running-as-a-service.md @@ -26,6 +26,35 @@ systemctl --user enable --now punktfunk-host The host now starts whenever you log in. Check it with `systemctl --user status punktfunk-host`. +**You don't need to export anything for it.** The host finds the live compositor session itself on +every connect and works out where to reach it (`WAYLAND_DISPLAY`, `XDG_RUNTIME_DIR`, the session bus, +sway's `SWAYSOCK`, Hyprland's instance signature) from the running compositor — so `host.env` is for +policy, not session plumbing, and `systemctl --user import-environment` is not a prerequisite. + +### Restart the host with your desktop + +Add one drop-in so the host follows your session's lifetime: + +```sh +mkdir -p ~/.config/systemd/user/punktfunk-host.service.d +# /usr/share/punktfunk/ on Fedora/Arch, /usr/share/punktfunk-host/ on Debian/Ubuntu, +# scripts/ in a source checkout +cp /usr/share/punktfunk/punktfunk-host-desktop-session.conf \ + ~/.config/systemd/user/punktfunk-host.service.d/desktop-session.conf +systemctl --user daemon-reload +systemctl --user reenable punktfunk-host +systemctl --user restart punktfunk-host +``` + +Without it, restarting Plasma or GNOME — a crash, a log out and back in, "restart the shell" — leaves +the host running against a compositor that no longer exists. It keeps listening and answering, and +every session after that fails at capture, which is a confusing way to find out. The drop-in makes a +compositor restart a host restart. + +Skip it on the headless/appliance route below (which has its own session unit), and on Sway or +Hyprland, which don't hand their session to systemd — start the host from the compositor's config +there instead, so it comes and goes with the session. + ## B. A headless, always-on host To run with **no monitor and no login** — a machine in a closet that's always ready — you need two diff --git a/docs-site/content/docs/virtual-displays.md b/docs-site/content/docs/virtual-displays.md index 00f312a5..ae70ec09 100644 --- a/docs-site/content/docs/virtual-displays.md +++ b/docs-site/content/docs/virtual-displays.md @@ -18,6 +18,10 @@ opened on. > Reach for a preset when you want a specific experience — a dedicated box you only stream from, a > desktop you also use in person, or a multi-monitor workstation. +If you'd rather stream a monitor the host **already has** than have punktfunk make one, that's a +different setting and it turns most of this page off — see +[Stream a real monitor instead](#stream-a-real-monitor-instead) right below. + > **What's live today:** **keep-alive** (linger, or **forever**), **topology** (extend / primary / > exclusive), **conflict handling**, **per-client identity + persistent scaling** (Windows, KDE/KWin > *and* GNOME/Mutter), and **multi-monitor layout** (several clients as monitors of one desktop) are @@ -25,6 +29,71 @@ opened on. > second. The remaining gaps are noted inline: the Linux `primary` physical-keep *effect*, Sway > `exclusive`, and multi-display for a *single* client (that last is the next stage). +## Stream a real monitor instead + +Sometimes you don't want a new screen — you want *that* screen. A shop-floor PC on a wall mount, a +lab bench machine, a media box whose TV output you'd like to watch from the couch: what matters is +seeing the monitor that's already there, exactly as the person in front of it sees it. + +Set **Host → *Virtual displays* → Streamed screen** to one of the listed monitors and punktfunk stops +creating a virtual display altogether. It streams that physical monitor instead, and every client +sees it at *its* resolution — you're a viewer of a screen, not the owner of your own. + +- The monitor is **never touched**. punktfunk doesn't resize it, move it, disable it or restore it — + it only watches. Keep-alive, topology and the multi-monitor layout options above simply don't + apply, because there's no display of ours to apply them to. +- **The resolution is the monitor's**, not yours. A client asking for a different one is politely + told no and scales its own picture — reconfiguring the display someone is sitting at would be + rude, and the mid-stream resize machinery is switched off for this reason. +- **Every client sees the same screen.** Two clients means two viewers of one monitor, not two + desktops. +- Naming a monitor that isn't there is a **hard error**, not a fallback: the session fails with + `no monitor named "DP-9" — this host has: HDMI-1`. Showing you the wrong screen would be worse + than showing you none. +- Choosing **Virtual screen (default)** in the same card puts you back on the normal path. + +Supported on **KDE/KWin**, **GNOME/Mutter**, **Sway/wlroots** and **Hyprland** — each through the +compositor's own screen-recording API, so there is **no chooser dialog** and nothing to click. That +matters most for a host running unattended as a [service](/docs/running-as-a-service): a background +`systemd --user` daemon has nobody to answer a permission prompt, so the monitor has to be +configuration rather than a question. (A nested gamescope session has no physical monitors of its +own, so the setting doesn't appear there.) + +### Naming the monitor from the host + +Monitors are named by **connector** — `HDMI-A-1`, `DP-2`, `eDP-1`. List what this host has: + +```sh +punktfunk-host list-monitors +``` + +``` +Kwin: + HDMI-A-1 1920x1080@60 at +0,+0 scale 1 Dell U2412M [primary] + DP-2 2560x1440@144 at +1920,+0 scale 1 ACME 27 +``` + +To pin it **from the host's configuration** instead of the console — the appliance route — set it in +[`host.env`](/docs/configuration): + +```sh +PUNKTFUNK_CAPTURE_MONITOR=HDMI-A-1 +``` + +The environment variable **wins over the console setting**, deliberately: an operator who declared +the answer in the unit's environment shouldn't have it re-aimed by a click. The console shows the +Streamed screen card as locked while it's set. Leave it unset on a machine you want to steer from the +console. + +Check the whole path — mirror, capture, frames — without a client involved: + +```sh +punktfunk-host mirror-test --monitor HDMI-A-1 --seconds 20 +``` + +Compositor screen recording is **damage-driven**: an idle desktop legitimately produces almost no +frames, so move the mouse on the host while it runs or a working mirror reads as a stall. + ## Pick a preset A preset is the easy way in — select one in the console and you're done. Each expands to a bundle of @@ -252,6 +321,20 @@ landing on a dead stream — and switching between game mode and the KDE / GNOME follows the switch. If a launched game **exits**, a dedicated session ends and returns you to your library; a game mode / desktop session keeps streaming. +**My keep-alive / topology / layout settings do nothing.** Check whether **Streamed screen** is set +to a real monitor. Those options are all about a display punktfunk created; when it's mirroring one +of yours there is nothing of ours to keep alive or rearrange. Switch the card back to *Virtual screen +(default)* to get them back. + +**The console won't let me change Streamed screen.** `PUNKTFUNK_CAPTURE_MONITOR` is set in this +host's [`host.env`](/docs/configuration) and deliberately outranks the console. Unset it (and restart +the host) to choose from the console instead. + +**My session fails with "no monitor named …".** The pinned connector isn't among this host's +monitors — it was renamed, unplugged, or the host is now in a different session. Run +`punktfunk-host list-monitors` on the host to see the real names. punktfunk will not quietly stream a +different screen instead. + **My couch box's TV stayed on the streamed session after I disconnected.** With the **Headless box** preset (keep alive = *forever*), a managed Steam session is held indefinitely so a reconnect resumes instantly — return to game mode on the box (or restart the host) to hand the TV back.