diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index 7acf050a9a40..2939e67566c8 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -9,11 +9,36 @@ let systemWide = cfg.enable && cfg.systemWide; nonSystemWide = cfg.enable && !cfg.systemWide; + hasZeroconf = let z = cfg.zeroconf; in z.publish.enable || z.discovery.enable; + + overriddenPackage = cfg.package.override + (optionalAttrs hasZeroconf { zeroconfSupport = true; }); + binary = "${getBin overriddenPackage}/bin/pulseaudio"; + binaryNoDaemon = "${binary} --daemonize=no"; # Forces 32bit pulseaudio and alsaPlugins to be built/supported for apps # using 32bit alsa on 64bit linux. enable32BitAlsaPlugins = cfg.support32Bit && stdenv.isx86_64 && (pkgs_i686.alsaLib != null && pkgs_i686.libpulseaudio != null); + + myConfigFile = + let + addModuleIf = cond: mod: optionalString cond "load-module ${mod}"; + allAnon = optional cfg.tcp.anonymousClients.allowAll "auth-anonymous=1"; + ipAnon = let a = cfg.tcp.anonymousClients.allowedIpRanges; + in optional (a != []) ''auth-ip-acl=${concatStringsSep ";" a}''; + in writeTextFile { + name = "default.pa"; + text = '' + .include ${cfg.configFile} + ${addModuleIf cfg.zeroconf.publish.enable "module-zeroconf-publish"} + ${addModuleIf cfg.zeroconf.discovery.enable "module-zeroconf-discover"} + ${addModuleIf cfg.tcp.enable (concatStringsSep " " + ([ "load-module module-native-protocol-tcp" ] ++ allAnon ++ ipAnon))} + ${cfg.extraConfig} + ''; + }; + ids = config.ids; uid = ids.uids.pulseaudio; @@ -26,7 +51,7 @@ let # are built with PulseAudio support (like KDE). clientConf = writeText "client.conf" '' autospawn=${if nonSystemWide then "yes" else "no"} - ${optionalString nonSystemWide "daemon-binary=${cfg.package.out}/bin/pulseaudio"} + ${optionalString nonSystemWide "daemon-binary=${binary}"} ${cfg.extraClientConf} ''; @@ -44,7 +69,7 @@ let hint.description "Default Audio Device (via PulseAudio)" } ctl_type.pulse { - libs.native = ${alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ; + libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ; ${lib.optionalString enable32BitAlsaPlugins "libs.32Bit = ${pkgs_i686.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ;"} } @@ -89,16 +114,25 @@ in { }; configFile = mkOption { - type = types.path; + type = types.nullOr types.path; description = '' - The path to the configuration the PulseAudio server + The path to the default configuration options the PulseAudio server should use. By default, the "default.pa" configuration from the PulseAudio distribution is used. ''; }; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Literal string to append to configFile + and the config file generated by the pulseaudio module. + ''; + }; + extraClientConf = mkOption { - type = types.str; + type = types.lines; default = ""; description = '' Extra configuration appended to pulse/client.conf file. @@ -127,6 +161,31 @@ in { ''; }; }; + + zeroconf = { + discovery.enable = + mkEnableOption "discovery of pulseaudio sinks in the local network"; + publish.enable = + mkEnableOption "publishing the pulseaudio sink in the local network"; + }; + + # TODO: enable by default? + tcp = { + enable = mkEnableOption "tcp streaming support"; + + anonymousClients = { + allowAll = mkEnableOption "all anonymous clients to stream to the server"; + allowedIpRanges = mkOption { + type = types.listOf types.str; + default = []; + example = literalExample ''[ "127.0.0.1" "192.168.1.0/24" ]''; + description = '' + A list of IP subnets that are allowed to stream to the server. + ''; + }; + }; + }; + }; }; @@ -139,11 +198,11 @@ in { source = clientConf; }; - hardware.pulseaudio.configFile = mkDefault "${getBin cfg.package}/etc/pulse/default.pa"; + hardware.pulseaudio.configFile = mkDefault "${getBin overriddenPackage}/etc/pulse/default.pa"; } (mkIf cfg.enable { - environment.systemPackages = [ cfg.package ]; + environment.systemPackages = [ overriddenPackage ]; environment.etc = singleton { target = "asound.conf"; @@ -152,12 +211,21 @@ in { # Allow PulseAudio to get realtime priority using rtkit. security.rtkit.enable = true; + + }) + + (mkIf hasZeroconf { + services.avahi.enable = true; + }) + (mkIf cfg.zeroconf.publish.enable { + services.avahi.publish.enable = true; + services.avahi.publish.userServices = true; }) (mkIf nonSystemWide { environment.etc = singleton { target = "pulse/default.pa"; - source = cfg.configFile; + source = myConfigFile; }; systemd.user = { @@ -167,10 +235,11 @@ in { wantedBy = [ "default.target" ]; serviceConfig = { Type = "notify"; - ExecStart = "${getBin cfg.package}/bin/pulseaudio --daemonize=no"; + ExecStart = binaryNoDaemon; Restart = "on-failure"; }; environment = { DISPLAY = ":${toString config.services.xserver.display}"; }; + restartIfChanged = true; }; sockets.pulseaudio = { @@ -205,7 +274,7 @@ in { environment.PULSE_RUNTIME_PATH = stateDir; serviceConfig = { Type = "notify"; - ExecStart = "${getBin cfg.package}/bin/pulseaudio --daemonize=no --log-level=${cfg.daemon.logLevel} --system -n --file=${cfg.configFile}"; + ExecStart = "${binaryNoDaemon} --log-level=${cfg.daemon.logLevel} --system -n --file=${myConfigFile}"; Restart = "on-failure"; }; };