Remove n0emis as direct maintainer (#365023)
[NixPkgs.git] / nixos / modules / services / audio / marytts.nix
blob8409b64bd3711aea96cc30ae36617f43efff5c9e
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
8   cfg = config.services.marytts;
9   format = pkgs.formats.javaProperties { };
12   options.services.marytts = {
13     enable = lib.mkEnableOption "MaryTTS";
15     settings = lib.mkOption {
16       type = lib.types.submodule {
17         freeformType = format.type;
18       };
19       default = { };
20       description = ''
21         Settings for MaryTTS.
23         See the [default settings](https://github.com/marytts/marytts/blob/master/marytts-runtime/conf/marybase.config)
24         for a list of possible keys.
25       '';
26     };
28     package = lib.mkPackageOption pkgs "marytts" { };
30     basePath = lib.mkOption {
31       type = lib.types.path;
32       default = "/var/lib/marytts";
33       description = ''
34         The base path in which MaryTTS runs.
35       '';
36     };
38     port = lib.mkOption {
39       type = lib.types.port;
40       default = 59125;
41       description = ''
42         Port to bind the MaryTTS server to.
43       '';
44     };
46     openFirewall = lib.mkOption {
47       type = lib.types.bool;
48       default = false;
49       example = true;
50       description = ''
51         Whether to open the port in the firewall for MaryTTS.
52       '';
53     };
55     voices = lib.mkOption {
56       type = lib.types.listOf lib.types.path;
57       default = [ ];
58       example = lib.literalExpression ''
59         [
60           (pkgs.fetchzip {
61             url = "https://github.com/marytts/voice-bits1-hsmm/releases/download/v5.2/voice-bits1-hsmm-5.2.zip";
62             hash = "sha256-1nK+qZxjumMev7z5lgKr660NCKH5FDwvZ9sw/YYYeaA=";
63           })
64         ]
65       '';
66       description = ''
67         Paths to the JAR files that contain additional voices for MaryTTS.
69         Voices are automatically detected by MaryTTS, so there is no need to alter
70         your config to make use of new voices.
71       '';
72     };
74     userDictionaries = lib.mkOption {
75       type = lib.types.listOf lib.types.path;
76       default = [ ];
77       example = lib.literalExpression ''
78         [
79           (pkgs.writeTextFile {
80             name = "userdict-en_US";
81             destination = "/userdict-en_US.txt";
82             text = '''
83               Nixpkgs | n I k s - ' p { - k @ - dZ @ s
84             ''';
85           })
86         ]
87       '';
88       description = ''
89         Paths to the user dictionary files for MaryTTS.
90       '';
91     };
92   };
94   config = lib.mkIf cfg.enable {
95     services.marytts.settings = {
96       "mary.base" = lib.mkDefault cfg.basePath;
97       "socket.port" = lib.mkDefault cfg.port;
98     };
100     environment.systemPackages = [ cfg.package ];
102     systemd.services.marytts = {
103       description = "MaryTTS server instance";
104       after = [ "network.target" ];
105       wantedBy = [ "multi-user.target" ];
107       # FIXME: MaryTTS's config loading mechanism appears to be horrendously broken
108       # and it doesn't seem to actually read config files outside of precompiled JAR files.
109       # Using system properties directly works for now, but this is really ugly.
110       script = ''
111         ${lib.getExe pkgs.marytts} -classpath "${cfg.basePath}/lib/*:${cfg.package}/lib/*" ${
112           lib.concatStringsSep " " (lib.mapAttrsToList (n: v: ''-D${n}="${v}"'') cfg.settings)
113         }
114       '';
116       restartTriggers = cfg.voices ++ cfg.userDictionaries;
118       serviceConfig = {
119         DynamicUser = true;
120         User = "marytts";
121         RuntimeDirectory = "marytts";
122         StateDirectory = "marytts";
123         Restart = "on-failure";
124         RestartSec = 5;
125         TimeoutSec = 20;
127         # Hardening
128         ProtectClock = true;
129         ProtectKernelLogs = true;
130         ProtectControlGroups = true;
131         ProtectKernelModules = true;
132         ProtectHostname = true;
133         ProtectKernelTunables = true;
134         ProtectProc = "invisible";
135         ProtectHome = true;
136         ProcSubset = "pid";
138         PrivateTmp = true;
139         PrivateNetwork = false;
140         PrivateUsers = cfg.port >= 1024;
141         PrivateDevices = true;
143         RestrictRealtime = true;
144         RestrictNamespaces = true;
145         RestrictAddressFamilies = [
146           "AF_INET"
147           "AF_INET6"
148         ];
150         MemoryDenyWriteExecute = false; # Java does not like w^x :(
151         LockPersonality = true;
152         AmbientCapabilities = lib.optional (cfg.port < 1024) "CAP_NET_BIND_SERVICE";
153         CapabilityBoundingSet = "";
154         SystemCallArchitectures = "native";
155         SystemCallFilter = [
156           "@system-service"
157           "~@resources"
158           "~@privileged"
159         ];
160         UMask = "0027";
161       };
162     };
164     systemd.tmpfiles.settings."10-marytts" = {
165       "${cfg.basePath}/lib"."L+".argument = "${pkgs.symlinkJoin {
166         name = "marytts-lib";
168         # Put user paths before default ones so that user ones have priority
169         paths = cfg.voices ++ [ "${cfg.package}/lib" ];
170       }}";
172       "${cfg.basePath}/user-dictionaries"."L+".argument = "${pkgs.symlinkJoin {
173         name = "marytts-user-dictionaries";
175         # Put user paths before default ones so that user ones have priority
176         paths = cfg.userDictionaries ++ [ "${cfg.package}/user-dictionaries" ];
177       }}";
178     };
180     networking.firewall = lib.mkIf cfg.openFirewall {
181       allowedTCPPorts = [ cfg.port ];
182     };
183   };