diff --git a/nixos/modules/services/audio/squeezelite.nix b/nixos/modules/services/audio/squeezelite.nix index 05a5323f4ebe..5f7ce4fa5a4f 100644 --- a/nixos/modules/services/audio/squeezelite.nix +++ b/nixos/modules/services/audio/squeezelite.nix @@ -6,53 +6,142 @@ }: let - inherit (lib) - mkEnableOption - mkIf - mkOption - optionalString - types - ; - - dataDir = "/var/lib/squeezelite"; cfg = config.services.squeezelite; - pkg = if cfg.pulseAudio then pkgs.squeezelite-pulse else pkgs.squeezelite; - bin = "${pkg}/bin/${pkg.pname}"; + + serviceDeps = [ + "network.target" + "sound.target" + ] + ++ lib.optionals cfg.pulseaudio.enable ( + if config.services.pulseaudio.systemWide then + [ "pulseaudio.service" ] + else + [ + "pipewire.service" + "pipewire-pulse.socket" + ] + ); in { - - ###### interface + imports = [ + (lib.mkRenamedOptionModule + [ "services" "squeezelite" "pulseAudio" ] + [ "services" "squeezelite" "pulseaudio" "enable" ] + ) + (lib.mkRenamedOptionModule + [ "services" "squeezelite" "extraArguments" ] + [ "services" "squeezelite" "extraArgs" ] + ) + ]; options.services.squeezelite = { - enable = mkEnableOption "Squeezelite, a software Squeezebox emulator"; + enable = lib.mkEnableOption "Squeezelite, a software Squeezebox emulator"; - pulseAudio = mkEnableOption "pulseaudio support"; + package = lib.mkPackageOption pkgs "squeezelite" { } // { + default = if cfg.pulseaudio.enable then pkgs.squeezelite-pulse else pkgs.squeezelite; + defaultText = lib.literalExpression "if config.services.squeezelite.pulseaudio.enable then pkgs.squeezelite-pulse else pkgs.squeezelite"; + }; - extraArguments = mkOption { + name = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = "name to report to server"; + default = null; + }; + + mutableName = lib.mkOption { + type = lib.types.bool; + description = "store name in file, controllable by server"; + default = cfg.name == null; + defaultText = lib.literalExpression "config.services.squeezelite.name == null"; + }; + + pulseaudio = { + enable = lib.mkEnableOption "pulseaudio support"; + group = lib.mkOption { + type = lib.types.str; + description = "group for accessing to pulseaudio socket"; + default = if config.services.pulseaudio.systemWide then "pulse-access" else "pipewire"; + defaultText = lib.literalExpression ''if config.services.pulseaudio.systemWide then "pulse-access" else "pipewire"''; + }; + }; + + extraArgs = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Additional command line arguments to pass to Squeezelite. ''; }; }; - ###### implementation + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.name == null || !cfg.mutableName; + message = "'services.squeezelite.name' and 'services.squeezelite.mutableName' are mutually exclusive"; + } + { + assertion = + !cfg.pulseaudio.enable + || ( + (config.services.pulseaudio.enable && config.services.pulseaudio.systemWide) + || ( + config.services.pipewire.enable + && config.services.pipewire.pulse.enable + && config.services.pipewire.systemWide + ) + ); + message = '' + `services.squeezelite.pulseaudio.enable = true' requires a system-wide Pulseaudio server. Either: + - `services.pulseaudio.enable = true' and `services.pulseaudio.systemWide = true' + or + - `services.pipewire.enable = true', `services.pipewire.pulse.enable = true', and `services.pipewire.systemWide = true' + should be set. + ''; + } + ]; - config = mkIf cfg.enable { systemd.services.squeezelite = { - wantedBy = [ "multi-user.target" ]; - after = [ - "network.target" + wantedBy = [ + "multi-user.target" + # try and start squeezelite if it isn't already, e.g. a sound card plugged in "sound.target" ]; + after = serviceDeps; + requires = serviceDeps; description = "Software Squeezebox emulator"; + + environment = { + XDG_CONFIG_HOME = "%S/squeezelite/.config"; + XDG_RUNTIME_DIR = "%t/squeezelite"; + }; + serviceConfig = { + ExecStartPre = [ + # print available interfaces + "${lib.getExe cfg.package} -l" + ] + ++ lib.optionals (!cfg.pulseaudio.enable) [ + # print available alsa controls + "${lib.getExe cfg.package} -L" + ]; + ExecStart = "${lib.getExe cfg.package} ${ + lib.optionalString (cfg.name != null) "-n ${cfg.name} " + }${lib.optionalString cfg.mutableName "-N %S/squeezelite/player-name "}${cfg.extraArgs}"; + DynamicUser = true; - ExecStart = "${bin} -N ${dataDir}/player-name ${cfg.extraArguments}"; - StateDirectory = baseNameOf dataDir; - SupplementaryGroups = "audio"; + RuntimeDirectory = "squeezelite"; + RuntimeDirectoryMode = "0700"; + StateDirectory = "squeezelite"; + StateDirectoryMode = "0700"; + SupplementaryGroups = [ + "audio" + ] + ++ lib.optionals cfg.pulseaudio.enable [ + cfg.pulseaudio.group + ]; + TimeoutStopSec = "5"; }; }; };