summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorSilvan Mosberger <infinisil@icloud.com>2019-03-07 00:00:48 +0100
committerGitHub <noreply@github.com>2019-03-07 00:00:48 +0100
commit502a4263a34a2a2e870c04b9e34ee23d05fa66cd (patch)
tree9ed618b197e290f3e41dc3c1a27707c0de99fe6f /nixos
parent01ad1729214c4bb3ef77551c3744dd0aa3f79181 (diff)
parent085751b63b4a393f6a35c40a94e6ef05d5ac36bc (diff)
downloadnixpkgs-502a4263a34a2a2e870c04b9e34ee23d05fa66cd.tar
nixpkgs-502a4263a34a2a2e870c04b9e34ee23d05fa66cd.tar.gz
nixpkgs-502a4263a34a2a2e870c04b9e34ee23d05fa66cd.tar.bz2
nixpkgs-502a4263a34a2a2e870c04b9e34ee23d05fa66cd.tar.lz
nixpkgs-502a4263a34a2a2e870c04b9e34ee23d05fa66cd.tar.xz
nixpkgs-502a4263a34a2a2e870c04b9e34ee23d05fa66cd.tar.zst
nixpkgs-502a4263a34a2a2e870c04b9e34ee23d05fa66cd.zip
Merge pull request #55936 from tobim/modules/snapserver
nixos/snapserver: init
Diffstat (limited to 'nixos')
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/audio/snapserver.nix217
2 files changed, 218 insertions, 0 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 5b95fc8ecc3..6bccd253500 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -182,6 +182,7 @@
   ./services/audio/mpd.nix
   ./services/audio/mopidy.nix
   ./services/audio/slimserver.nix
+  ./services/audio/snapserver.nix
   ./services/audio/squeezelite.nix
   ./services/audio/ympd.nix
   ./services/backup/bacula.nix
diff --git a/nixos/modules/services/audio/snapserver.nix b/nixos/modules/services/audio/snapserver.nix
new file mode 100644
index 00000000000..f709dd7fe16
--- /dev/null
+++ b/nixos/modules/services/audio/snapserver.nix
@@ -0,0 +1,217 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  package = "snapcast";
+  name = "snapserver";
+
+  cfg = config.services.snapserver;
+
+  # Using types.nullOr to inherit upstream defaults.
+  sampleFormat = mkOption {
+    type = with types; nullOr str;
+    default = null;
+    description = ''
+      Default sample format.
+    '';
+    example = "48000:16:2";
+  };
+
+  codec = mkOption {
+    type = with types; nullOr str;
+    default = null;
+    description = ''
+      Default audio compression method.
+    '';
+    example = "flac";
+  };
+
+  streamToOption = name: opt:
+    let
+      os = val:
+        optionalString (val != null) "${val}";
+      os' = prefixx: val:
+        optionalString (val != null) (prefixx + "${val}");
+      flatten = key: value:
+        "&${key}=${value}";
+    in
+      "-s ${opt.type}://" + os opt.location + "?" + os' "name=" name
+        + concatStrings (mapAttrsToList flatten opt.query);
+
+  optionalNull = val: ret:
+    optional (val != null) ret;
+
+  optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams
+             ++ ["-p ${toString cfg.port}"]
+             ++ ["--controlPort ${toString cfg.controlPort}"]
+             ++ optionalNull cfg.sampleFormat "--sampleFormat ${cfg.sampleFormat}"
+             ++ optionalNull cfg.codec "-c ${cfg.codec}"
+             ++ optionalNull cfg.streamBuffer "--streamBuffer ${cfg.streamBuffer}"
+             ++ optionalNull cfg.buffer "-b ${cfg.buffer}"
+             ++ optional cfg.sendToMuted "--sendToMuted");
+
+in {
+
+  ###### interface
+
+  options = {
+
+    services.snapserver = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable snapserver.
+        '';
+      };
+
+      port = mkOption {
+        type = types.port;
+        default = 1704;
+        description = ''
+          The port that snapclients can connect to.
+        '';
+      };
+
+      controlPort = mkOption {
+        type = types.port;
+        default = 1705;
+        description = ''
+          The port for control connections (JSON-RPC).
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to automatically open the specified ports in the firewall.
+        '';
+      };
+
+      inherit sampleFormat;
+      inherit codec;
+
+      streams = mkOption {
+        type = with types; attrsOf (submodule {
+          options = {
+            location = mkOption {
+              type = types.path;
+              description = ''
+                The location of the pipe.
+              '';
+            };
+            type = mkOption {
+              type = types.enum [ "pipe" "file" "process" "spotify" "airplay" ];
+              default = "pipe";
+              description = ''
+                The type of input stream.
+              '';
+            };
+            query = mkOption {
+              type = attrsOf str;
+              default = {};
+              description = ''
+                Key-value pairs that convey additional parameters about a stream.
+              '';
+              example = literalExample ''
+                # for type == "pipe":
+                {
+                  mode = "listen";
+                };
+                # for type == "process":
+                {
+                  params = "--param1 --param2";
+                  logStderr = "true";
+                };
+              '';
+            };
+            inherit sampleFormat;
+            inherit codec;
+          };
+        });
+        default = { default = {}; };
+        description = ''
+          The definition for an input source.
+        '';
+        example = literalExample ''
+          {
+            mpd = {
+              type = "pipe";
+              location = "/run/snapserver/mpd";
+              sampleFormat = "48000:16:2";
+              codec = "pcm";
+            };
+          };
+        '';
+      };
+
+      streamBuffer = mkOption {
+        type = with types; nullOr int;
+        default = null;
+        description = ''
+          Stream read (input) buffer in ms.
+        '';
+        example = 20;
+      };
+
+      buffer = mkOption {
+        type = with types; nullOr int;
+        default = null;
+        description = ''
+          Network buffer in ms.
+        '';
+        example = 1000;
+      };
+
+      sendToMuted = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Send audio to muted clients.
+        '';
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.snapserver = {
+      after = [ "network.target" ];
+      description = "Snapserver";
+      wantedBy = [ "multi-user.target" ];
+      before = [ "mpd.service" "mopidy.service" ];
+
+      serviceConfig = {
+        DynamicUser = true;
+        ExecStart = "${pkgs.snapcast}/bin/snapserver --daemon ${optionString}";
+        Type = "forking";
+        LimitRTPRIO = 50;
+        LimitRTTIME = "infinity";
+        NoNewPrivileges = true;
+        PIDFile = "/run/${name}/pid";
+        ProtectKernelTunables = true;
+        ProtectControlGroups = true;
+        ProtectKernelModules = true;
+        RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX";
+        RestrictNamespaces = true;
+        RuntimeDirectory = name;
+        StateDirectory = name;
+      };
+    };
+
+    networking.firewall.allowedTCPPorts = optionals cfg.openFirewall [ cfg.port cfg.controlPort ];
+  };
+
+  meta = {
+    maintainers = with maintainers; [ tobim ];
+  };
+
+}