aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/services/audio/snapserver.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services/audio/snapserver.nix')
-rw-r--r--nixpkgs/nixos/modules/services/audio/snapserver.nix216
1 files changed, 216 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/audio/snapserver.nix b/nixpkgs/nixos/modules/services/audio/snapserver.nix
new file mode 100644
index 00000000000..b0b9264e816
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/audio/snapserver.nix
@@ -0,0 +1,216 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ 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 ];
+ };
+
+}