Files
home-manager/modules/services/easyeffects.nix
Sandro Marques 4067ca1ffb easyeffects: Fix race condition on Wayland session startup
Add systemd service ordering dependencies to prevent EasyEffects from
starting before the Wayland compositor is ready.

**Problem:** EasyEffects would crash during login with "Failed to create
wl_display (No such file or directory)" if started before the Wayland
display server was fully initialized.

**Solution:** Declaring the "After" property ensures EasyEffects waits
for the graphical session to be fully ready. The "PartOf" properly stops
EasyEffects when logging out. Got the tip from
https://github.com/wwmm/easyeffects/issues/1310.

Tested on NixOS 25.11 (Xantusia, 20251223.76701a1) and Home Manager 25.11
(0999ed8) with GNOME 49 on Wayland.
2025-12-27 12:56:02 -06:00

150 lines
3.9 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
inherit (lib) literalExpression mkOption types;
cfg = config.services.easyeffects;
presetOpts = lib.optionalString (cfg.preset != "") "--load-preset ${cfg.preset}";
olderThan8 = lib.versionOlder cfg.package.version "8.0.0"; # This version introduces breaking changes and this check is used to stay backwards compatible
jsonFormat = pkgs.formats.json { };
presetType =
let
baseType = types.attrsOf jsonFormat.type;
in
types.addCheck baseType (
v:
baseType.check v
&& lib.elem (lib.head (lib.attrNames v)) [
"input"
"output"
]
);
presetOptionType = mkOption {
type = types.nullOr (types.attrsOf presetType);
default = { };
description = ''
List of presets to import to easyeffects.
Presets are written to input and output folder in `$XDG_DATA_HOME/easyeffects`.
Top level block (input/output) determines the folder the file is written to.
See community presets at:
https://github.com/wwmm/easyeffects/wiki/Community-Presets
'';
example = literalExpression ''
{
my-preset = {
input = {
blocklist = [
];
"plugins_order" = [
"rnnoise#0"
];
"rnnoise#0" = {
bypass = false;
"enable-vad" = false;
"input-gain" = 0.0;
"model-path" = "";
"output-gain" = 0.0;
release = 20.0;
"vad-thres" = 50.0;
wet = 0.0;
};
};
};
};
'';
};
in
{
meta.maintainers = with lib.maintainers; [
fufexan
hausken
];
options.services.easyeffects = {
enable = lib.mkEnableOption ''
Easyeffects daemon.
Note, it is necessary to add
```nix
programs.dconf.enable = true;
```
to your system configuration for the daemon to work correctly'';
package = lib.mkPackageOption pkgs "easyeffects" { };
preset = mkOption {
type = types.str;
default = "";
description = ''
Which preset to use when starting easyeffects.
Will likely need to launch easyeffects to initially create preset.
'';
};
extraPresets = presetOptionType;
};
config = lib.mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "services.easyeffects" pkgs lib.platforms.linux)
];
home.packages = with pkgs; lib.optional olderThan8 at-spi2-core ++ [ cfg.package ]; # Only include if easyeffects version is below 8.0.0
xdg.dataFile = lib.mkIf (cfg.extraPresets != { }) (
lib.mapAttrs' (
k: v:
# Assuming only one of either input or output block is defined, having both in same file not seem to be supported by the application since it separates it by folder
let
folder = builtins.head (builtins.attrNames v);
in
lib.nameValuePair "easyeffects/${folder}/${k}.json" {
source = jsonFormat.generate "${folder}-${k}.json" v;
}
) cfg.extraPresets
);
systemd.user.services.easyeffects = {
Unit = {
Description = "Easyeffects daemon";
After = [ "graphical-session.target" ];
PartOf = [ "graphical-session.target" ];
};
Install.WantedBy = [ "graphical-session.target" ];
Service = {
ExecStart =
if olderThan8 then
"${cfg.package}/bin/easyeffects --gapplication-service ${presetOpts}"
else
"${cfg.package}/bin/easyeffects --hide-window --service-mode ${presetOpts}";
ExecStop = "${cfg.package}/bin/easyeffects --quit";
KillMode = "mixed";
Restart = "on-failure";
RestartSec = 5;
TimeoutStopSec = 10;
}
// (
if olderThan8 then
{
Type = "dbus";
BusName = "com.github.wwmm.easyeffects";
}
else
{ }
);
};
};
}