summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorTobias Mayer <tobim@fastmail.fm>2019-02-17 11:08:48 +0100
committerTobias Mayer <tobim@fastmail.fm>2019-03-06 23:40:05 +0100
commit085751b63b4a393f6a35c40a94e6ef05d5ac36bc (patch)
tree2fac97e2fc6113f5389847fbd807de91d30076c9 /nixos
parent4b2336ea283707686c3a1f674e03add420720dd4 (diff)
downloadnixpkgs-085751b63b4a393f6a35c40a94e6ef05d5ac36bc.tar
nixpkgs-085751b63b4a393f6a35c40a94e6ef05d5ac36bc.tar.gz
nixpkgs-085751b63b4a393f6a35c40a94e6ef05d5ac36bc.tar.bz2
nixpkgs-085751b63b4a393f6a35c40a94e6ef05d5ac36bc.tar.lz
nixpkgs-085751b63b4a393f6a35c40a94e6ef05d5ac36bc.tar.xz
nixpkgs-085751b63b4a393f6a35c40a94e6ef05d5ac36bc.tar.zst
nixpkgs-085751b63b4a393f6a35c40a94e6ef05d5ac36bc.zip
nixos/snapserver: init
A nixos module for configuring the server side of pkgs.snapcast.
The module is named "snapserver" following upstream convention.
This commit does not provide module for the corresponding client.

Fix handling of port and controlPort

Fix stream uri generation & address review

Remove unused streams options & add description

Add missing description & Remove default fs path

Use types.port for ports & formatting improvements

Force mpd and mopidy to wait for snapserver
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 04bcb41cd07..0aec89ff635 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -180,6 +180,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 ];
+  };
+
+}