fix(pipewire): denoising through configPackages, desktop gets steam and bitwig

The RNNoise config was deployed to /etc/xdg/pipewire, which PipeWire
never reads: it resolves $PIPEWIRE_CONFIG_DIR, then the home config, then
its compiled-in /etc/pipewire, and knows nothing of XDG_CONFIG_DIRS. An
installed system therefore had no denoising while carrying the file.

It now goes through services.pipewire.configPackages, with the LADSPA
plugin substituted to its store path since LADSPA_PATH has no /usr here.

Alongside, on the desktop host only: steam via its module (which also
turns on 32-bit graphics), bitwig-studio, and rtkit so a DAW can ask for
realtime scheduling at all.
This commit is contained in:
2026-08-20 18:25:36 +02:00
parent b0e819d630
commit af101afd14
3 changed files with 100 additions and 2 deletions
+58
View File
@@ -1,5 +1,63 @@
# Decisions
## 2026-08-20 Input denoising was deployed to a path PipeWire never reads
- **Who**: Dominik, ClaudeCode
- **Why**: The Arch machine runs RNNoise input denoising, and the config for it
lives in the shared tree as
`defaults/xdg/pipewire/pipewire.conf.d/99-input-denoising.conf`. It was in
`modules/desktop.nix` too, in the generic sweep to `/etc/xdg/` — and inert
there. PipeWire resolves its config directory from `$PIPEWIRE_CONFIG_DIR`,
then `$XDG_CONFIG_HOME/pipewire` or `$HOME/.config/pipewire`, then the
compiled-in `/etc/pipewire`; `XDG_CONFIG_DIRS` appears nowhere in
`src/pipewire/conf.c`. On Arch the file works because `post-install.sh` seeds
it into the home directory. Same class as the swaylock config on 2026-08-18: a
file installed to a plausible path that the program does not read.
- **Tradeoffs**: (1) **Which option** — the module accepts both
`services.pipewire.extraConfig.pipewire.<name>` (Nix attributes, rendered to
JSON) and `services.pipewire.configPackages` (a package carrying
`share/pipewire/pipewire.conf.d/*.conf`); both end up in the same merged
directory (`pipewire.nix:59-75`). The NixOS wiki uses `extraConfig` for its
examples, which are written by hand and have no file behind them. Taking that
route here would mean translating the shared file into Nix and maintaining the
VAD values in two places, so `configPackages` was chosen — which is also what
the module's own option documentation shows for a conf.d file
(`pipewire.nix:258-279`). (2) **The plugin path** — the file names the plugin
as `librnnoise_ladspa`, resolved through `LADSPA_PATH`, which is
`/usr/lib/ladspa` on Arch and does not exist here. There is no LADSPA
counterpart to `services.pipewire.extraLv2Packages`, so the absolute store
path is substituted into the file, the same treatment the wallpaper paths get.
- **How**: `denoisingConfig` via `runCommand` + `substitute`, handed to
`services.pipewire.configPackages`. The `xdg/pipewire/` entry in
`environment.etc` is removed rather than kept for layout parity — after the
swaylock case, an inert copy is a liability. Verified by building the package:
the conf.d file is there, the plugin line points at
`rnnoise-plugin-1.10/lib/ladspa/librnnoise_ladspa.so`, and that file exists.
- **Note**: the filter chain shows up as a separate "Noise Canceling source"
input. It does not replace the raw microphone; applications have to select it.
## 2026-08-20 Steam, Bitwig and rtkit belong to the desktop alone
- **Who**: Dominik, ClaudeCode
- **Why**: Both programs are wanted on the desktop and on no other machine, so
they go into `hosts/desktop/default.nix` rather than the shared module every
host imports.
- **Tradeoffs**: (1) **Steam**`pkgs.steam` in `systemPackages` is the wrong
handle: the module wraps the binary in an FHS environment and turns on
`hardware.graphics.enable32Bit` itself (`nixos/modules/programs/steam.nix:215-218`),
which the bare package would leave off. (2) **Bitwig** — the `bitwig-studio`
attribute currently resolves to `bitwig-studio6-6.0.11`; `bitwig-studio5`
(5.3.13) exists as a separate attribute if a downgrade is ever needed.
Dominik chose 6. (3) **Realtime**`security.rtkit.enable` was off. The
rlimits the PipeWire module installs (`rtprio` 95, `nice` -19, `memlock`)
apply to members of the `pipewire` group, and the account is in
`networkmanager wheel video input plugdev docker` only, so a DAW had no path
to realtime scheduling at all. Enabled on this host, where the DAW is.
- **How**: `programs.steam.enable`, `security.rtkit.enable` and
`environment.systemPackages = [ pkgs.bitwig-studio ]` in the host file.
Verified by evaluating both hosts: on `desktop` all three are set and 32-bit
graphics came along; on `thinkpad` Steam and rtkit stay `false`.
## 2026-08-20 The browser is LibreWolf from nixpkgs, not a self-packaged Waterfox
- **Who**: Dominik, ClaudeCode
+14
View File
@@ -109,6 +109,20 @@
# the shared module sets it unconditionally.
services.fwupd.enable = lib.mkForce false;
# --- Applications, this machine only ---
#
# Steam comes as a module rather than a package: it wraps the binary in an FHS
# environment and turns on 32-bit graphics for the drivers, which the package
# alone would not do.
programs.steam.enable = true;
# Lets audio applications ask for realtime scheduling, which Bitwig does. The
# rlimits the PipeWire module sets (rtprio 95, memlock) apply to members of
# the pipewire group only, and this account is not one.
security.rtkit.enable = true;
environment.systemPackages = [ pkgs.bitwig-studio ];
nix.settings.experimental-features = [ "nix-command" "flakes" ];
nixpkgs.config.allowUnfree = true;
+28 -2
View File
@@ -36,6 +36,24 @@ let
--replace-fail /usr/share/moonarch/wallpaper-blur.jpg ${wallpaperBlur}
'';
# PipeWire searches $PIPEWIRE_CONFIG_DIR, then $XDG_CONFIG_HOME/pipewire, then
# its compiled-in /etc/pipewire — never /etc/xdg (verified in PipeWire's
# src/pipewire/conf.c). The shared file therefore cannot be deployed the way
# the other XDG configs are; it goes through the module's configPackages,
# which is what its own option documentation shows for a conf.d file.
#
# The file names the plugin as `librnnoise_ladspa`, resolved through
# LADSPA_PATH — /usr/lib/ladspa on Arch, nothing here. Substituted to the
# store path, like the wallpaper paths above. LADSPA has no counterpart to
# services.pipewire.extraLv2Packages, so the path belongs in the file.
denoisingConfig = pkgs.runCommand "moonarch-pipewire-denoising" { } ''
mkdir -p "$out/share/pipewire/pipewire.conf.d"
substitute ${xdg}/pipewire/pipewire.conf.d/99-input-denoising.conf \
"$out/share/pipewire/pipewire.conf.d/99-input-denoising.conf" \
--replace-fail "plugin = librnnoise_ladspa" \
"plugin = ${pkgs.rnnoise-plugin}/lib/ladspa/librnnoise_ladspa.so"
'';
# zsh/newuser runs its setup wizard on every interactive login for as long as
# the user has none of .zshenv, .zprofile, .zshrc or .zlogin — the whole
# configuration living in /etc/zshrc does not count. Seeded below to stop
@@ -74,8 +92,9 @@ in
"xdg/qt6ct/qt6ct.conf".source = "${xdg}/qt6ct/qt6ct.conf";
"xdg/gtk-3.0/settings.ini".source = "${xdg}/gtk-3.0/settings.ini";
"xdg/gtk-4.0/settings.ini".source = "${xdg}/gtk-4.0/settings.ini";
"xdg/pipewire/pipewire.conf.d/99-input-denoising.conf".source =
"${xdg}/pipewire/pipewire.conf.d/99-input-denoising.conf";
# No xdg/pipewire/ entry: PipeWire does not read /etc/xdg, so the file was
# deployed and inert. It goes through services.pipewire.configPackages
# below instead.
# Kept for layout parity with the Arch package; waypaper itself only reads
# the copy in the home directory, seeded below.
"xdg/waypaper/config.ini".source = waypaperConfig;
@@ -202,6 +221,13 @@ in
openmoji-color
];
# --- Audio ---
#
# RNNoise input denoising, from the shared config. The filter chain appears as
# a separate "Noise Canceling source" input; it does not replace the raw
# microphone, so applications have to select it.
services.pipewire.configPackages = [ denoisingConfig ];
# --- Printing ---
#
# Driverless only, and no printer is declared here. Asked over IPP, the