Files
punktfunk/packaging/flatpak/io.unom.Punktfunk.yml
T
enricobuehler b2451e6aea fix(flatpak): ship punktfunk-session so Decky streaming survives the two-binary split
The re-architected Linux client is now two binaries: the punktfunk-client shell
execs its sibling punktfunk-session (ash/Vulkan presenter + Skia console UI) for
--connect/--browse. The Decky plugin's stream and browse paths launch the shell
with exactly those flags, but the flatpak built and installed only the shell, so
streaming and the gamepad library from the Deck failed at exec with
"punktfunk-session: No such file" (pair/wake/library still worked — the shell
handles them in-process).

Build and install both binaries. The session binary pulls in Skia (skia-safe),
whose build script downloads a prebuilt libskia — dead in the offline sandbox —
so point skia-bindings at a pinned, vendored archive via SKIA_BINARIES_URL=file://
(read directly, no curl); the tarball rides along as a sha256-pinned flatpak
source. Widen the flatpak CI path filters to the session binary's crates
(linux-session, pf-presenter, pf-console-ui, pf-client-core) and fix the moved
library.rs path in the Decky error-classifier comment.

All other plugin↔client contracts (flags, pairing/library output, config files,
env vars, exit codes, the 47990 mgmt port) already match — no changes needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:14:08 +02:00

201 lines
12 KiB
YAML

# Flatpak manifest for the native punktfunk Linux client: the shell (crate
# punktfunk-client-linux, binary `punktfunk-client`) PLUS the Vulkan session binary (crate
# punktfunk-client-session, binary `punktfunk-session`) that the shell execs for
# `--connect`/`--browse` — both must ship or streaming from the Deck breaks (the Decky
# wrapper launches the shell with those flags and the shell resolves its sibling
# `punktfunk-session`, see clients/linux/src/spawn.rs). Built into a single-file `.flatpak`
# bundle and published to Gitea's generic package registry (see .gitea/workflows/flatpak.yml
# + packaging/flatpak/README.md).
#
# Why flatpak for the CLIENT (the host stays an RPM/deb — see packaging/README.md "Why not
# Flatpak"): on SteamOS the Steam Deck's /usr is read-only and image-based, so a bare
# `punktfunk-client` binary in ~/.local/bin can't bring its own libadwaita / SDL3 (both
# MISSING from the SteamOS system) — but flatpak is the Deck's native, update-survivable app
# path (the user already runs Moonlight + chiaki-ng as flatpaks). Unlike the host, the client
# is sandbox-friendly: it only needs the GPU render node, the host PipeWire socket, the
# network, Wayland, hidraw for DualSense, and its config dir — all expressible as finish-args.
#
# Runtime: GNOME 50 ships GTK 4.20 and libadwaita 1.8 — both far exceed the crate floors
# (gtk4 0.11 "v4_16", libadwaita 0.9 "v1_5"). GNOME 50 is built on freedesktop-sdk 25.08, so
# `org.freedesktop.Sdk.Extension.rust-stable` resolves to //25.08 (rustc 1.96 — the GTK4 dep
# chain, e.g. pango-sys 0.22, needs >= 1.92, which the older GNOME-48/24.08 rust-stable at 1.89
# could NOT satisfy). GNOME 50 is also a *supported* runtime (GNOME 48 went EOL in March 2026).
# libopus and the PipeWire client lib are in the freedesktop base; SDL3 is NOT, so it is built
# from source as a bundled module.
#
# HEVC decode: the base runtime's libavcodec is a stripped build (no encumbered codecs). The
# freedesktop runtime declares `org.freedesktop.Platform.codecs-extra` as a built-in extension
# point (directory lib/x86_64-linux-gnu/codecs-extra, add-ld-path lib, auto-downloaded with the
# runtime), whose full libavcodec.so.61 transparently shadows the base one at runtime. So HEVC
# (software + VAAPI) works with NO app-side codec extension to declare — we just build against
# the SDK's linkable libavcodec.so.61 and let the runtime swap in the capable build.
app-id: io.unom.Punktfunk
runtime: org.gnome.Platform
runtime-version: '50'
sdk: org.gnome.Sdk
# Build-time SDK extensions:
# - rust-stable: cargo/rustc 1.96 + the bundled mold linker (/usr/lib/sdk/rust-stable/bin).
# - llvm20: provides libclang (/usr/lib/sdk/llvm20/lib), which bindgen needs — ffmpeg-sys-next
# and sdl3-sys generate their FFI bindings via bindgen at build time. The base SDK ships no
# clang/libclang, so without this the build panics ("Unable to find libclang").
# Both are added to PATH / LIBCLANG_PATH in build-options below.
sdk-extensions:
- org.freedesktop.Sdk.Extension.rust-stable
- org.freedesktop.Sdk.Extension.llvm20
command: punktfunk-client
cleanup:
- /include
- /lib/pkgconfig
- /lib/cmake
- /share/aclocal
- /man
- /share/man
- '*.a'
- '*.la'
finish-args:
# --- display ---
- --socket=wayland # GTK4 native Wayland window (the client is Wayland-first)
- --socket=fallback-x11 # Xwayland fallback when no Wayland socket is exposed
- --share=ipc # required alongside X11 for shared-memory surfaces
# --- GPU + all input devices ---
# --device=all (not just --device=dri): covers the GPU render node (VAAPI HEVC decode + GL),
# evdev joysticks, AND the hidraw CHAR devices SDL3's HIDAPI needs for DualSense touchpad/
# motion/adaptive-triggers/lightbar. flatpak cannot bind individual /dev/hidrawN via
# --filesystem (they are char devices — "unsupported type 0o20000"), and there is no granular
# --device=hidraw; --device=all is what game/emulator flatpaks (RetroArch, Dolphin) use. We
# self-host via the Gitea generic registry — NOT Flathub — so its --device=all review rule
# does not apply.
- --device=all
- --filesystem=/run/udev:ro # SDL/HIDAPI enumerates devices via udev
# --- audio: the client speaks the NATIVE PipeWire protocol (audio.rs `pw connect`), NOT the
# PulseAudio shim — so it needs the real `pipewire-0` socket in the sandbox. With only
# --socket=pulseaudio the sandbox has just `pulse/native`, no `pipewire-0`, and playback +
# mic both die with "pw connect (is PipeWire running in this session?)" (observed live on the
# Deck in Gaming Mode). We bind the native socket via --filesystem=xdg-run/pipewire-0 (NOT
# --socket=pipewire: this flatpak-builder toolchain rejects it as an "Unknown socket type",
# and the Deck's flatpak 1.16 override CLI does too — the filesystem bind is the portable
# form, validated on-Deck to make pipewire-0 appear + the client register its audio node).
# --socket=pulseaudio stays as a fallback for any pulse-only path. ---
- --filesystem=xdg-run/pipewire-0
- --socket=pulseaudio
# --- network: QUIC control + UDP data plane + mDNS discovery (_punktfunk._udp) ---
- --share=network
# --- persistent client identity / pairing store (shared with punktfunk-probe) ---
- --filesystem=~/.config/punktfunk:create # client-{cert,key}.pem, known-hosts, settings
build-options:
append-path: /usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm20/bin
# The rust build resolves everything via pkg-config: gtk4/libadwaita/pipewire/opus AND a
# linkable libavcodec.so.61 from org.gnome.Sdk//50 (the multiarch /usr dir), plus the bundled
# SDL3's .pc from /app. (At runtime the codecs-extra extension swaps in the HEVC-capable
# libavcodec — see the header.)
env:
PKG_CONFIG_PATH: /app/lib/pkgconfig:/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/lib/pkgconfig
# bindgen (ffmpeg-sys-next / sdl3-sys) loads libclang from the llvm20 extension.
LIBCLANG_PATH: /usr/lib/sdk/llvm20/lib
# mold (shipped in rust-stable) speeds the ~450-crate link on the Deck APU.
RUSTFLAGS: -C link-arg=-fuse-ld=mold
modules:
# ---------------------------------------------------------------------------------------
# SDL3 — NOT provided as a linkable libSDL3.so.0 by org.gnome.Platform/freedesktop-sdk
# 25.08, and there is no SDL3 recipe in flathub/shared-modules. Build it from source.
# Pinned to 3.4.10 to match the crate exactly: sdl3-sys is `0.6.6+SDL-3.4.10`, i.e. its
# bindings target SDL 3.4.10 — building an older SDL risks missing symbols at link time.
# HIDAPI is enabled (DualSense touchpad/motion/triggers/lightbar over hidraw).
# ---------------------------------------------------------------------------------------
- name: sdl3
buildsystem: cmake-ninja
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DSDL_SHARED=ON
- -DSDL_STATIC=OFF
- -DSDL_HIDAPI=ON # DualSense full fidelity over hidraw
- -DSDL_TEST_LIBRARY=OFF
- -DSDL_EXAMPLES=OFF
sources:
- type: archive
url: https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz
# `sha256sum SDL3-3.4.10.tar.gz` (verified 2026-06-15). Bump url + sha together.
sha256: 12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785
x-checker-data:
type: anitya
project-id: 4974
stable-only: true
url-template: https://github.com/libsdl-org/SDL/releases/download/release-$version/SDL3-$version.tar.gz
cleanup:
- /bin
- /include
- /lib/cmake
- /lib/pkgconfig
# ---------------------------------------------------------------------------------------
# The client. cargo-sources.json is the GENERATED offline crate cache:
# python3 flatpak-cargo-generator.py Cargo.lock -o packaging/flatpak/cargo-sources.json
# (run from the repo root; the CI step does exactly this). With it present the build is fully
# offline (CARGO_NET_OFFLINE). For quick LOCAL iteration WITHOUT regenerating it, drop the
# cargo-sources.json source and pass --build-args=--share=network to flatpak-builder
# (non-reproducible; cargo fetches from crates.io during the build).
# ---------------------------------------------------------------------------------------
- name: punktfunk-client
buildsystem: simple
build-options:
env:
CARGO_HOME: /run/build/punktfunk-client/cargo
CARGO_NET_OFFLINE: 'true'
# The session binary's Skia (pf-console-ui → skia-safe) fetches prebuilt libskia in
# its build script — dead in the offline sandbox. skia-bindings accepts a file://
# override (read directly, no curl), so we point it at the archive that
# flatpak-builder pre-downloaded as a pinned source below. No {tag}/{key}
# placeholders needed: a template without them is used verbatim.
SKIA_BINARIES_URL: file:///run/build/punktfunk-client/skia-binaries.tar.gz
build-commands:
# Drop the Windows client from the workspace before building. It pins windows-rs as a
# git dependency (cfg(windows)-gated, but cargo resolves it for the whole workspace
# regardless of target), and that git source is deliberately NOT vendored into
# cargo-sources.json — see packaging/flatpak/prune-windows-lock.py, which strips it so
# flatpak-builder doesn't full-clone the multi-GB windows-rs repo. Without removing the
# member, `cargo --offline` would try to load the un-vendored windows-rs source and fail
# ("can't checkout ... you are in the offline mode"). The flatpak never compiles the
# Windows client; this edits only the sandbox copy of Cargo.toml. (No --locked: the lock
# no longer matches the reduced member set; --offline still pins every crate to the
# vendored cargo-sources.json, so the build stays reproducible.)
- sed -i '\#"clients/windows",#d' Cargo.toml
# One cargo invocation for both binaries: the shell and the Vulkan session binary it
# execs for --connect/--browse. Building them together keeps skia-bindings' feature
# unification identical to a workspace build (the pinned skia-binaries archive's
# `pdf-textlayout-vulkan` key must match the resolved feature set).
- cargo --offline build --release -p punktfunk-client-linux -p punktfunk-client-session
- install -Dm0755 target/release/punktfunk-client ${FLATPAK_DEST}/bin/punktfunk-client
- install -Dm0755 target/release/punktfunk-session ${FLATPAK_DEST}/bin/punktfunk-session
# Desktop entry (renamed to the app id; Exec is the in-sandbox binary).
- install -Dm0644 packaging/flatpak/io.unom.Punktfunk.desktop
${FLATPAK_DEST}/share/applications/io.unom.Punktfunk.desktop
# AppStream metainfo (required for a well-formed flatpak / Software listings).
- install -Dm0644 packaging/flatpak/io.unom.Punktfunk.metainfo.xml
${FLATPAK_DEST}/share/metainfo/io.unom.Punktfunk.metainfo.xml
# Scalable icon named for the app id (GNOME runtime renders SVG via librsvg).
- install -Dm0644 packaging/flatpak/io.unom.Punktfunk.svg
${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/io.unom.Punktfunk.svg
sources:
# The repo checkout. For a Flathub/published build, replace with a pinned git source:
# - type: git
# url: https://git.unom.io/unom/punktfunk
# tag: vX.Y.Z
# commit: <sha>
# For ON-DECK / CI builds we build the checked-out working tree in place:
- type: dir
path: ../..
# Generated offline crate cache (see the comment block above). Remove for --share=network.
- cargo-sources.json
# Prebuilt Skia for skia-bindings 0.87.0 (SKIA_BINARIES_URL above). The key encodes the
# crate's pinned skia commit + target + resolved features — when bumping skia-safe, build
# the workspace once locally and take the new name from
# target/release/build/skia-bindings-*/out/.cache/, then update url + sha256 together.
- type: file
url: https://github.com/rust-skia/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-x86_64-unknown-linux-gnu-pdf-textlayout-vulkan.tar.gz
sha256: b46e7061e6b9df792025acaf9b8b90180224c7cec63f4c3ce09af7ddddb8abfa
dest-filename: skia-binaries.tar.gz