nixos/wireplumber: add extraConfig
/extraScripts
options
Follow-up to #282377. #282377 broke `environment.etc."wireplumber<...>"`, however WirePlumber did not yet have `extraConfig` style options for configuring it ergonomically outside of `environment.etc`. This has caused issues for people who had custom config files for WirePlumber, as having to create a config package just to edit some settings is not as ergonomic or discoverable as with a proper `extraConfig` style option. This commit fixes this issue by adding the `extraConfig` option for additional config file and the `extraScripts` option for additional scripts to be used by config files. With WirePlumber 0.5 it is possible to supply config files and scripts via the `XDG_DATA_DIRS` variable to the WirePlumber daemon. This is how the new options and with this change also the `configPackages` option expose their files to the daemon. This way `environment.etc."wireplumber"` works again for user configuration and breakage of old configs from 23.11 to 24.05 should be limited to those caused by the change in the config format from WirePlumber 0.4 to 0.5.
This commit is contained in:
parent
b2245daba6
commit
72ed33777c
|
@ -1,18 +1,40 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (builtins) attrNames concatMap length;
|
||||
inherit (builtins) concatMap;
|
||||
inherit (lib) maintainers;
|
||||
inherit (lib.attrsets) attrByPath filterAttrs;
|
||||
inherit (lib.attrsets) attrByPath mapAttrsToList;
|
||||
inherit (lib.lists) flatten optional;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.options) literalExpression mkOption;
|
||||
inherit (lib.strings) hasPrefix;
|
||||
inherit (lib.types) bool listOf package;
|
||||
inherit (lib.strings) concatStringsSep makeSearchPath;
|
||||
inherit (lib.types) bool listOf attrsOf package lines;
|
||||
inherit (lib.path) subpath;
|
||||
|
||||
pwCfg = config.services.pipewire;
|
||||
cfg = pwCfg.wireplumber;
|
||||
pwUsedForAudio = pwCfg.audio.enable;
|
||||
|
||||
json = pkgs.formats.json { };
|
||||
|
||||
configSectionsToConfFile = path: value:
|
||||
pkgs.writeTextDir
|
||||
path
|
||||
(concatStringsSep "\n" (
|
||||
mapAttrsToList
|
||||
(section: content: "${section} = " + (builtins.toJSON content))
|
||||
value
|
||||
));
|
||||
|
||||
mapConfigToFiles = config:
|
||||
mapAttrsToList
|
||||
(name: value: configSectionsToConfFile "share/wireplumber/wireplumber.conf.d/${name}.conf" value)
|
||||
config;
|
||||
|
||||
mapScriptsToFiles = scripts:
|
||||
mapAttrsToList
|
||||
(relativePath: value: pkgs.writeTextDir (subpath.join ["share/wireplumber/scripts" relativePath]) value)
|
||||
scripts;
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ maintainers.k900 ];
|
||||
|
@ -33,6 +55,114 @@ in
|
|||
description = "The WirePlumber derivation to use.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
# Two layer attrset is necessary before using JSON, because of the whole
|
||||
# config file not being a JSON object, but a concatenation of JSON objects
|
||||
# in sections.
|
||||
type = attrsOf (attrsOf json.type);
|
||||
default = { };
|
||||
example = literalExpression ''{
|
||||
"log-level-debug" = {
|
||||
"context.properties" = {
|
||||
# Output Debug log messages as opposed to only the default level (Notice)
|
||||
"log.level" = "D";
|
||||
};
|
||||
};
|
||||
"wh-1000xm3-ldac-hq" = {
|
||||
"monitor.bluez.rules" = [
|
||||
{
|
||||
matches = [
|
||||
{
|
||||
# Match any bluetooth device with ids equal to that of a WH-1000XM3
|
||||
"device.name" = "~bluez_card.*";
|
||||
"device.product.id" = "0x0cd3";
|
||||
"device.vendor.id" = "usb:054c";
|
||||
}
|
||||
];
|
||||
actions = {
|
||||
update-props = {
|
||||
# Set quality to high quality instead of the default of auto
|
||||
"bluez5.a2dp.ldac.quality" = "hq";
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}'';
|
||||
description = ''
|
||||
Additional configuration for the WirePlumber daemon when run in
|
||||
single-instance mode (the default in nixpkgs and currently the only
|
||||
supported way to run WirePlumber configured via `extraConfig`).
|
||||
|
||||
See also:
|
||||
- [The configuration file][docs-the-conf-file]
|
||||
- [Modifying configuration][docs-modifying-config]
|
||||
- [Locations of files][docs-file-locations]
|
||||
- and the [configuration section][docs-config-section] of the docs in general
|
||||
|
||||
Note that WirePlumber (and PipeWire) use dotted attribute names like
|
||||
`device.product.id`. These are not nested, but flat objects for WirePlumber/PipeWire,
|
||||
so to write these in nix expressions, remember to quote them like `"device.product.id"`.
|
||||
Have a look at the example for this.
|
||||
|
||||
[docs-the-conf-file]: https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/conf_file.html
|
||||
[docs-modifying-config]: https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/modifying_configuration.html
|
||||
[docs-file-locations]: https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/locations.html
|
||||
[docs-config-section]: https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration.html
|
||||
'';
|
||||
};
|
||||
|
||||
extraScripts = mkOption {
|
||||
type = attrsOf lines;
|
||||
default = { };
|
||||
example = {
|
||||
"test/hello-world.lua" = ''
|
||||
print("Hello, world!")
|
||||
'';
|
||||
};
|
||||
description = ''
|
||||
Additional scripts for WirePlumber to be used by configuration files.
|
||||
|
||||
Every item in this attrset becomes a separate lua file with the path
|
||||
relative to the `scripts` directory specified in the name of the item.
|
||||
The scripts get passed to the WirePlumber service via the `XDG_DATA_DIRS`
|
||||
variable. Scripts specified here are preferred over those shipped with
|
||||
WirePlumber if they occupy the same relative path.
|
||||
|
||||
For a script to be loaded, it needs to be specified as part of a component,
|
||||
and that component needs to be required by an active profile (e.g. `main`).
|
||||
Components can be defined in config files either via `extraConfig` or `configPackages`.
|
||||
|
||||
For the hello-world example, you'd have to add the following `extraConfig`:
|
||||
```nix
|
||||
services.pipewire.wireplumber.extraConfig."99-hello-world" = {
|
||||
"wireplumber.components" = [
|
||||
{
|
||||
name = "test/hello-world.lua";
|
||||
type = "script/lua";
|
||||
provides = "custom.hello-world";
|
||||
}
|
||||
];
|
||||
|
||||
"wireplumber.profiles" = {
|
||||
main = {
|
||||
"custom.hello-world" = "required";
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
See also:
|
||||
- [Location of scripts][docs-file-locations-scripts]
|
||||
- [Components & Profiles][docs-components-profiles]
|
||||
- [Migration - Loading custom scripts][docs-migration-loading-custom-scripts]
|
||||
|
||||
[docs-file-locations-scripts]: https://pipewire.pages.freedesktop.org/wireplumber/daemon/locations.html#location-of-scripts
|
||||
[docs-components-profiles]: https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/components_and_profiles.html
|
||||
[docs-migration-loading-custom-scripts]: https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/migration.html#loading-custom-scripts
|
||||
'';
|
||||
};
|
||||
|
||||
configPackages = mkOption {
|
||||
type = listOf package;
|
||||
default = [ ];
|
||||
|
@ -57,7 +187,7 @@ in
|
|||
|
||||
extraLv2Packages = mkOption {
|
||||
type = listOf package;
|
||||
default = [];
|
||||
default = [ ];
|
||||
example = literalExpression "[ pkgs.lsp-plugins ]";
|
||||
description = ''
|
||||
List of packages that provide LV2 plugins in `lib/lv2` that should
|
||||
|
@ -96,9 +226,22 @@ in
|
|||
}
|
||||
'';
|
||||
|
||||
extraConfigPkg = pkgs.buildEnv {
|
||||
name = "wireplumber-extra-config";
|
||||
paths = mapConfigToFiles cfg.extraConfig;
|
||||
pathsToLink = [ "/share/wireplumber/wireplumber.conf.d" ];
|
||||
};
|
||||
|
||||
extraScriptsPkg = pkgs.buildEnv {
|
||||
name = "wireplumber-extra-scrips";
|
||||
paths = mapScriptsToFiles cfg.extraScripts;
|
||||
pathsToLink = [ "/share/wireplumber/scripts" ];
|
||||
};
|
||||
|
||||
configPackages = cfg.configPackages
|
||||
++ optional (!pwUsedForAudio) pwNotForAudioConfigPkg
|
||||
++ optional pwCfg.systemWide systemwideConfigPkg;
|
||||
++ [ extraConfigPkg extraScriptsPkg ]
|
||||
++ optional (!pwUsedForAudio) pwNotForAudioConfigPkg
|
||||
++ optional pwCfg.systemWide systemwideConfigPkg;
|
||||
|
||||
configs = pkgs.buildEnv {
|
||||
name = "wireplumber-configs";
|
||||
|
@ -110,7 +253,7 @@ in
|
|||
(
|
||||
concatMap
|
||||
(p:
|
||||
attrByPath ["passthru" "requiredLv2Packages"] [] p
|
||||
attrByPath [ "passthru" "requiredLv2Packages" ] [ ] p
|
||||
)
|
||||
configPackages
|
||||
);
|
||||
|
@ -127,24 +270,10 @@ in
|
|||
assertion = !config.hardware.bluetooth.hsphfpd.enable;
|
||||
message = "Using WirePlumber conflicts with hsphfpd, as it provides the same functionality. `hardware.bluetooth.hsphfpd.enable` needs be set to false";
|
||||
}
|
||||
{
|
||||
assertion = length
|
||||
(attrNames
|
||||
(
|
||||
filterAttrs
|
||||
(name: value:
|
||||
hasPrefix "wireplumber/" name || name == "wireplumber"
|
||||
)
|
||||
config.environment.etc
|
||||
)) == 1;
|
||||
message = "Using `environment.etc.\"wireplumber<...>\"` directly is no longer supported in 24.05. Use `services.pipewire.wireplumber.configPackages` instead.";
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
environment.etc.wireplumber.source = "${configs}/share/wireplumber";
|
||||
|
||||
systemd.packages = [ cfg.package ];
|
||||
|
||||
systemd.services.wireplumber.enable = pwCfg.systemWide;
|
||||
|
@ -156,10 +285,16 @@ in
|
|||
systemd.services.wireplumber.environment = mkIf pwCfg.systemWide {
|
||||
# Force WirePlumber to use system dbus.
|
||||
DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/dbus/system_bus_socket";
|
||||
|
||||
# Make WirePlumber find our config/script files and lv2 plugins required by those
|
||||
# (but also the configs/scripts shipped with WirePlumber)
|
||||
XDG_DATA_DIRS = makeSearchPath "share" [ configs cfg.package ];
|
||||
LV2_PATH = "${lv2Plugins}/lib/lv2";
|
||||
};
|
||||
|
||||
systemd.user.services.wireplumber.environment.LV2_PATH =
|
||||
mkIf (!pwCfg.systemWide) "${lv2Plugins}/lib/lv2";
|
||||
systemd.user.services.wireplumber.environment = mkIf (!pwCfg.systemWide) {
|
||||
XDG_DATA_DIRS = makeSearchPath "share" [ configs cfg.package ];
|
||||
LV2_PATH = "${lv2Plugins}/lib/lv2";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user