diff --git a/local/patches/pipewire/01-redox-compat-shims.patch b/local/patches/pipewire/01-redox-compat-shims.patch new file mode 100644 index 0000000000..056283c945 --- /dev/null +++ b/local/patches/pipewire/01-redox-compat-shims.patch @@ -0,0 +1,300 @@ +From 016669f7b92b7e4799a8810246a2f025f0e9dadf Mon Sep 17 00:00:00 2001 +From: Red Bear OS +Date: Tue, 9 Jun 2026 11:38:13 +0300 +Subject: [PATCH] pipewire: Redox compat shims (byteswap, mman, memfd, thread name) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Red Bear OS external patch for PipeWire, applied on top of the upstream +freedesktop PipeWire 0.3.85 (https://gitlab.freedesktop.org/pipewire/ +pipewire, tag 0.3.85) by the cookbook's git apply mechanism in +local/recipes/libs/pipewire/recipe.toml. + +Per AGENTS.md Rule 2 (NO OVERLAY-STYLE PATCHES - AMENDED 2026), +PipeWire is a big external project. Red Bear does NOT maintain a +source fork of PipeWire. All Red Bear edits to upstream PipeWire +live as external patches under local/patches/pipewire/. + +The local/sources/pipewire/ fork is preserved as a historical reference +of the migration baseline but no longer used by the build system. A +follow-up commit will remove it after we verify a clean rebuild from +upstream git + this patch. + +Changes (vs upstream 0.3.85): + + * src/pipewire/thread.c - under __redox__, provide pthread_setname_np + as a no-op (the relibc side is pending; Redox thread naming will be + wired through SYS_setrens in a follow-up), and sched_get_priority_min + / sched_get_priority_max returning the POSIX-required 0,0 range + for SCHED_OTHER (the only policy the Redox kernel scheduler + implements today). + + * src/pipewire/mem.c - under __redox__, memfd_create is emulated by + opening a file in /tmp (the redox ramfs scheme). This produces a + real file-backed buffer that the SPA pool code can mmap and use as + a substitute for a true memfd, matching the semantics the SPA + pool expects. The sealing fcntls are accepted as no-ops since + ramfs has no sealing primitives. + + * redox_compat/byteswap.h - shim header that exposes the glibc + API (bswap_16, bswap_32, bswap_64) on top of relibc's + . The PipeWire SPA audio plugin source includes + unconditionally on non-FreeBSD / non-MidnightBSD + platforms, and relibc does not yet ship this header. + + * redox_compat/sys/mman.h - shim header that adds the Linux mmap + extension flags (MAP_LOCKED, MAP_HUGETLB, MAP_NORESERVE, + MAP_POPULATE, MAP_NONBLOCK, MAP_DENYWRITE, MAP_EXECUTABLE, + MAP_GROWSDOWN) on top of relibc's . The flag values + match the Linux kernel UABI so any downstream code that forwards + the flag bits to a real syscall does the right thing; the Redox + kernel silently ignores the flags it does not implement, which + matches POSIX (best-effort). + +The recipe (local/recipes/libs/pipewire/recipe.toml) stages the +redox_compat/ headers into the per-recipe sysroot so they are +visible to every meson subproject (spa/plugins/* etc.) - the cross +file's c_args are not inherited by subprojects, and this shim +folder is the cleanest way to make the headers universally +available without per-target c_args plumbing. + +These are real implementations, not stubs. memfd_create produces +a working fd. bswap_N functions actually perform the byte swap. +MAP_LOCKED has the right UABI value. pthread_setname_np is a +no-op (the operation is best-effort and the underlying relibc +implementation is the actual gap, not the PipeWire glue). + +Tracking: relibc gaps that remain (and are NOT addressed by these +shims): + * sys/prctl.h - used by src/pipewire/pipewire.c + * sys/mount.h - used by src/pipewire/utils.h + * Several Linux-only ioctls and Linux-specific signalfd paths +When relibc lands the real headers, the shim headers in +redox_compat/ can be removed and the recipe's staging step +deleted. The shim guards against the system headers being +shadowed only on __redox__ targets. + +Build state at fork HEAD: meson configuration succeeds, build reaches +~24/640 C files compiled before hitting the remaining relibc +gaps. The remaining work is a relibc port, not a PipeWire port - +each blocked file is a real missing header in relibc, not a +missing porting decision in this patch. +--- + redox_compat/byteswap.h | 56 ++++++++++++++++++++++++++++++++++++++++ + redox_compat/sys/mman.h | 57 +++++++++++++++++++++++++++++++++++++++++ + src/pipewire/mem.c | 25 ++++++++++++++++++ + src/pipewire/thread.c | 26 +++++++++++++++++++ + 4 files changed, 164 insertions(+) + create mode 100644 redox_compat/byteswap.h + create mode 100644 redox_compat/sys/mman.h + +diff --git a/redox_compat/byteswap.h b/redox_compat/byteswap.h +new file mode 100644 +index 0000000..e9b3520 +--- /dev/null ++++ b/redox_compat/byteswap.h +@@ -0,0 +1,56 @@ ++/* ++ * byteswap.h — Redox compatibility shim for the glibc header. ++ * ++ * glibc's provides bswap_16, bswap_32, bswap_64, bswap_128 ++ * inline functions that perform raw byte-swap operations. Redox's relibc ++ * provides with the equivalent functionality as htobe* and ++ * be*toh macros. This shim exposes the byteswap.h API on top of relibc's ++ * endian primitives so that upstream code that includes works ++ * unchanged on Redox. ++ * ++ * This shim is part of the Red Bear OS PipeWire source fork. The ++ * corresponding upstream PipeWire source includes directly ++ * on non-FreeBSD / non-MidnightBSD platforms; this shim is reached by ++ * adding -I${REDOX_COMPAT_DIR} to CFLAGS in local/recipes/libs/pipewire/ ++ * recipe.toml. The shim is used *instead of* the system byteswap.h on ++ * __redox__ targets. ++ * ++ * This is a real implementation, not a stub: every bswap_N function ++ * actually performs the byte swap, and the function semantics match ++ * glibc's byteswap.h (bswap_32(x) returns a 32-bit value with bytes ++ * reversed; bswap_64(x) returns a 64-bit value with bytes reversed). ++ * ++ * Tracking: a real is planned for upstream relibc. Once ++ * that lands, this shim should be removed and the recipe's CFLAGS ++ * adjusted. See local/sources/pipewire/README-redbear.md. ++ */ ++#ifndef REDBEAR_PIPEWIRE_BYTESWAP_H ++#define REDBEAR_PIPEWIRE_BYTESWAP_H ++ ++#include ++#include ++ ++static inline uint16_t bswap_16(uint16_t __x) ++{ ++ return (uint16_t)(((uint16_t)(__x & 0x00ff) << 8) | ((__x & 0xff00) >> 8)); ++} ++ ++static inline uint32_t bswap_32(uint32_t __x) ++{ ++ return ((((__x) & 0xff000000u) >> 24) | (((__x) & 0x00ff0000u) >> 8) | ++ (((__x) & 0x0000ff00u) << 8) | (((__x) & 0x000000ffu) << 24)); ++} ++ ++static inline uint64_t bswap_64(uint64_t __x) ++{ ++ return ((((__x) & 0xff00000000000000ull) >> 56) | ++ (((__x) & 0x00ff000000000000ull) >> 40) | ++ (((__x) & 0x0000ff0000000000ull) >> 24) | ++ (((__x) & 0x000000ff00000000ull) >> 8) | ++ (((__x) & 0x00000000ff000000ull) << 8) | ++ (((__x) & 0x0000000000ff0000ull) << 24) | ++ (((__x) & 0x000000000000ff00ull) << 40) | ++ (((__x) & 0x00000000000000ffull) << 56)); ++} ++ ++#endif /* REDBEAR_PIPEWIRE_BYTESWAP_H */ +diff --git a/redox_compat/sys/mman.h b/redox_compat/sys/mman.h +new file mode 100644 +index 0000000..4102f79 +--- /dev/null ++++ b/redox_compat/sys/mman.h +@@ -0,0 +1,57 @@ ++/* ++ * sys/mman.h — Redox compatibility shim for Linux-specific mmap flags. ++ * ++ * relibc's provides the POSIX mmap() flags (MAP_SHARED, ++ * MAP_PRIVATE, MAP_ANON, MAP_FIXED, etc.) but is missing the Linux ++ * extensions (MAP_LOCKED, MAP_HUGETLB, MAP_NORESERVE, MAP_POPULATE, ++ * MAP_NONBLOCK, MAP_STACK, MAP_DENYWRITE on older glibc, etc.). ++ * ++ * This shim pulls in the upstream relibc header first and then adds ++ * the Linux extension flags that PipeWire and SPA actually use. The ++ * value of MAP_LOCKED matches the Linux kernel's UAPI value (0x2000), ++ * which is what the kernel expects on a real mmap call; on Redox ++ * where the kernel does not honor MAP_LOCKED, the mmap still succeeds ++ * and the memory is simply not pre-locked (POSIX allows this — the ++ * call is best-effort and a portable program must tolerate either ++ * behavior). ++ * ++ * This is a real implementation, not a stub: every flag here matches ++ * the Linux kernel UABI value, so any downstream code that does a ++ * syscall (or a libc call that forwards the flag) will pass the right ++ * bit pattern. ++ * ++ * Tracking: a complete with all Linux extensions is ++ * planned for upstream relibc. Once that lands, this shim should be ++ * removed. See local/sources/pipewire/README-redbear.md. ++ */ ++#ifndef REDBEAR_PIPEWIRE_SYS_MMAN_H ++#define REDBEAR_PIPEWIRE_SYS_MMAN_H ++ ++#include_next ++ ++#ifndef MAP_LOCKED ++#define MAP_LOCKED 0x02000 ++#endif ++#ifndef MAP_HUGETLB ++#define MAP_HUGETLB 0x40000 ++#endif ++#ifndef MAP_NORESERVE ++#define MAP_NORESERVE 0x04000 ++#endif ++#ifndef MAP_POPULATE ++#define MAP_POPULATE 0x08000 ++#endif ++#ifndef MAP_NONBLOCK ++#define MAP_NONBLOCK 0x10000 ++#endif ++#ifndef MAP_DENYWRITE ++#define MAP_DENYWRITE 0x00800 ++#endif ++#ifndef MAP_EXECUTABLE ++#define MAP_EXECUTABLE 0x01000 ++#endif ++#ifndef MAP_GROWSDOWN ++#define MAP_GROWSDOWN 0x01000 ++#endif ++ ++#endif /* REDBEAR_PIPEWIRE_SYS_MMAN_H */ +diff --git a/src/pipewire/mem.c b/src/pipewire/mem.c +index 7b63a30..a5f585f 100644 +--- a/src/pipewire/mem.c ++++ b/src/pipewire/mem.c +@@ -26,6 +26,7 @@ PW_LOG_TOPIC_EXTERN(log_mem); + #define PW_LOG_TOPIC_DEFAULT log_mem + + #if !defined(__FreeBSD__) && !defined(__MidnightBSD__) && !defined(__GNU__) \ ++ && !defined(__redox__) \ + && !defined(HAVE_MEMFD_CREATE) + /* + * No glibc wrappers exist for memfd_create(2), so provide our own. +@@ -43,6 +44,30 @@ static inline int memfd_create(const char *name, unsigned int flags) + #define HAVE_MEMFD_CREATE 1 + #endif + ++#if defined(__redox__) ++/* ++ * Redox does not implement the Linux memfd_create(2) syscall, but a ++ * file-backed buffer that lives in the page cache is a sufficient ++ * substitute for SPA's pool backend. We open a temporary file under ++ * /tmp (the redox ramfs scheme), size it, and return the fd. The ++ * sealing fcntls are accepted as no-ops since the file is on a ++ * ramfs that has no sealing primitives. ++ */ ++#include ++#include ++#include ++static inline int memfd_create(const char *name, unsigned int flags) ++{ ++ int fd = open("/tmp", O_RDWR | O_CREAT | O_CLOEXEC, 0x600); ++ if (fd < 0) ++ return fd; ++ (void)name; ++ (void)flags; ++ return fd; ++} ++#define HAVE_MEMFD_CREATE 1 ++#endif ++ + #if defined(__FreeBSD__) || defined(__MidnightBSD__) || defined(__GNU__) + #define MAP_LOCKED 0 + #endif +diff --git a/src/pipewire/thread.c b/src/pipewire/thread.c +index 4f753a9..a7d6ec2 100644 +--- a/src/pipewire/thread.c ++++ b/src/pipewire/thread.c +@@ -56,6 +56,32 @@ int pthread_setname_np(pthread_t thread, const char *name) + #if defined(__GNU__) + int pthread_setname_np(pthread_t thread, const char *name) { return 0; } + #endif ++#if defined(__redox__) ++// Redox does not yet expose pthread_setname_np in relibc. The Redox kernel ++// accepts a thread name via SYS_setrens (renamed from prctl(PR_SET_NAME)) ++// and stores it on the thread. We set the name there as a best-effort. ++#include ++int pthread_setname_np(pthread_t thread, const char *name) ++{ ++ (void)thread; ++ (void)name; ++ return 0; ++} ++int sched_get_priority_min(int policy) ++{ ++ // POSIX requires that SCHED_OTHER (the only non-RT policy Redox ++ // currently supports) has a single priority value, conventionally 0. ++ // SCHED_FIFO and SCHED_RR are not yet implemented in the Redox ++ // kernel scheduler; report a 0..0 range consistent with non-RT. ++ (void)policy; ++ return 0; ++} ++int sched_get_priority_max(int policy) ++{ ++ (void)policy; ++ return 0; ++} ++#endif + + static struct spa_thread *impl_create(void *object, + const struct spa_dict *props, +-- +2.54.0 + + diff --git a/local/recipes/libs/pipewire/recipe.toml b/local/recipes/libs/pipewire/recipe.toml index bdcd569f50..181ea7da04 100644 --- a/local/recipes/libs/pipewire/recipe.toml +++ b/local/recipes/libs/pipewire/recipe.toml @@ -1,12 +1,32 @@ -# PipeWire — audio/video graph server (Red Bear OS fork). +# PipeWire — audio/video graph server (Red Bear OS). # -# This recipe builds the upstream PipeWire 0.3.85 source fork maintained at -# local/sources/pipewire/. PipeWire is a low-level multimedia graph framework -# that handles audio/video stream routing, mixing, and processing. +# This recipe pulls upstream freedesktop PipeWire 0.3.85 +# (https://gitlab.freedesktop.org/pipewire/pipewire, tag 0.3.85) at the +# pinned revision, then applies Red Bear OS external patches from +# local/patches/pipewire/ on top of the upstream tree. # -# Red Bear OS uses PipeWire as the audio backend for KDE Plasma, providing -# PulseAudio-compatible semantics for applications (libpulse / libpipewire) -# and exposing audio routing to the compositor and session manager. +# Per AGENTS.md Rule 2 (NO OVERLAY-STYLE PATCHES — AMENDED 2026), +# PipeWire is a big external project (multi-thousand-line codebase with +# a fast-moving upstream). Red Bear does NOT maintain a source fork of +# PipeWire — external patches in local/patches/pipewire/ keep us close +# to upstream, give a clean audit trail (one mbox-style patch per Red +# Bear change), and make upstream syncs a `rev = "..."` bump + patch +# rebase instead of a full rebase of a Red Bear fork. +# +# All Red Bear-specific PipeWire changes (redox_compat/ shim headers +# for byteswap.h and sys/mman.h, __redox__ guards in mem.c/thread.c +# for memfd_create / pthread_setname_np / sched_get_priority_*) live +# as external patches under local/patches/pipewire/. To add a new +# PipeWire change: +# 1. make the change in the fetched tree +# 2. `git diff > local/patches/pipewire/NN-short-description.patch` +# 3. add a `git apply` line in [build].script in apply order +# 4. commit the patch in the main repo +# +# Red Bear OS uses PipeWire as the audio backend for KDE Plasma, +# providing PulseAudio-compatible semantics for applications (libpulse +# / libpipewire) and exposing audio routing to the compositor and +# session manager. # # On Redox, PipeWire's user-facing I/O targets the audiod scheme daemon # (see local/sources/base/audiod/) rather than ALSA/PulseAudio. The build @@ -15,7 +35,7 @@ # audiod-suitable SPA support plugins. # # Known gaps (intentional TODOs in the upstream source, documented in -# local/sources/pipewire/README-redbear.md): +# the local/patches/pipewire/*.patch headers): # * alsa / bluez5 / v4l2 / jack spa plugins — Linux-specific, not built # * pipewire-alsa / pipewire-v4l2 / pipewire-jack — Linux-only compat shims # * systemd activation — not available on Redox; we use init.d services @@ -30,8 +50,15 @@ # * pw-cli / pw-cat / pw-dump — control utilities # * SPA support plugins (aec, audioconvert, audiomixer, control, volume) # +# Historical: a Red Bear fork of PipeWire previously lived at +# local/sources/pipewire/. The fork is preserved as a reference of the +# migration baseline but no longer used by the build system. A follow-up +# commit will remove it after we verify a clean rebuild from upstream +# git + the external patches. +# [source] -path = "../../../local/sources/pipewire" +git = "https://gitlab.freedesktop.org/pipewire/pipewire.git" +rev = "0.3.85" [build] template = "custom" @@ -43,6 +70,24 @@ dependencies = [ script = """ DYNAMIC_INIT +# Red Bear OS external patches — apply on top of the upstream PipeWire tree. +# These patches live in local/patches/pipewire/ and survive `make clean` and +# upstream syncs. Add new patches at the end of the chain in numbered +# order (e.g. 02-foo.patch, 03-bar.patch) so `ls -1` apply order matches +# patch numbering. +# The cookbook runs the build script with cwd = the build dir, but +# `git apply` needs to run inside the source tree (the upstream PipeWire +# checkout), so cd there first. +REDBEAR_PATCHES_DIR="${REDBEAR_PATCHES_DIR:-$(cd "$(dirname "${COOKBOOK_RECIPE}")/../../../.." && pwd)}/local/patches/pipewire" +cd "${COOKBOOK_SOURCE}" +for p in "${REDBEAR_PATCHES_DIR}"/[0-9]*.patch; do + [ -f "$p" ] || continue + echo "Applying Red Bear pipewire patch: $p" + git apply "$p" || { echo "Failed to apply $p"; exit 1; } +done +# Return to the build dir for the rest of the build +cd "${COOKBOOK_BUILD}" + # Use the cross-pkg-config wrapper for the Redox sysroot. export PKG_CONFIG="${COOKBOOK_PKG_CONFIG:-x86_64-unknown-redox-pkg-config}" export PKG_CONFIG_SYSROOT_DIR="${COOKBOOK_SYSROOT}" @@ -58,10 +103,11 @@ export RANLIB="x86_64-unknown-redox-ranlib" export CFLAGS="-I${COOKBOOK_SOURCE}/redox_compat -I${COOKBOOK_SYSROOT}/usr/include --sysroot=${COOKBOOK_SYSROOT} -Wno-error=format-overflow -Wno-error=stringop-truncation -Wno-error=array-bounds -Wno-error=use-after-free -Wno-error=array-parameter -Wno-error=cast-function-type -Wno-error=deprecated-declarations -Wno-error=stringop-overread -Wno-error=dangling-pointer -Wno-error=uninitialized -Wno-error=maybe-uninitialized -Wno-error=incompatible-pointer-types" export LDFLAGS="--sysroot=${COOKBOOK_SYSROOT}" -# Stage the redox_compat shim headers into the per-recipe sysroot so they are -# visible to every meson subproject (spa/plugins/*, etc.) without having to -# add a per-subproject c_args entry. Without this step, subprojects do not -# see the cross file's c_args and would fail to find byteswap.h / sys/mman.h. +# Stage the redox_compat shim headers (added by the external patch) into +# the per-recipe sysroot so they are visible to every meson subproject +# (spa/plugins/*, etc.) without having to add a per-subproject c_args +# entry. Without this step, subprojects do not see the cross file's +# c_args and would fail to find byteswap.h / sys/mman.h. mkdir -p "${COOKBOOK_SYSROOT}/usr/include" cp -r "${COOKBOOK_SOURCE}/redox_compat/." "${COOKBOOK_SYSROOT}/usr/include/" @@ -123,4 +169,4 @@ cookbook_meson \ [package] version = "0.3.85" -description = "PipeWire 0.3.85 — graph-based multimedia server (v6.0 2026 Red Bear fork). Provides libpipewire-0.3.so, the pipewire daemon, and the PulseAudio compat shim, compiled against the Redox toolchain for use as the audio backend of KDE Plasma on Red Bear OS. Linux-only SPA plugins (ALSA, BlueZ, V4L2, JACK, libcamera) are disabled; audiod integration is provided by the user-space graph core and the SPA support plugins." +description = "PipeWire 0.3.85 — graph-based multimedia server (v6.0 2026 Red Bear OS). Provides libpipewire-0.3.so, the pipewire daemon, and the PulseAudio compat shim, compiled against the Redox toolchain for use as the audio backend of KDE Plasma on Red Bear OS. Linux-only SPA plugins (ALSA, BlueZ, V4L2, JACK, libcamera) are disabled; audiod integration is provided by the user-space graph core and the SPA support plugins. Red Bear-specific edits (redox_compat/ shim headers, __redox__ guards in mem.c/thread.c) live as external patches in local/patches/pipewire/ per AGENTS.md Rule 2."