1{
2 pkgs,
3 lib,
4 config,
5 utils,
6 ...
7}:
8let
9 cfg = config.services.gmediarender;
10in
11{
12 options.services.gmediarender = {
13 enable = lib.mkEnableOption "the gmediarender DLNA renderer";
14
15 audioDevice = lib.mkOption {
16 type = lib.types.nullOr lib.types.str;
17 default = null;
18 description = ''
19 The audio device to use.
20 '';
21 };
22
23 audioSink = lib.mkOption {
24 type = lib.types.nullOr lib.types.str;
25 default = null;
26 description = ''
27 The audio sink to use.
28 '';
29 };
30
31 friendlyName = lib.mkOption {
32 type = lib.types.nullOr lib.types.str;
33 default = null;
34 description = ''
35 A "friendly name" for identifying the endpoint.
36 '';
37 };
38
39 initialVolume = lib.mkOption {
40 type = lib.types.nullOr lib.types.int;
41 default = 0;
42 description = ''
43 A default volume attenuation (in dB) for the endpoint.
44 '';
45 };
46
47 package = lib.mkPackageOption pkgs "gmediarender" {
48 default = "gmrender-resurrect";
49 };
50
51 port = lib.mkOption {
52 type = lib.types.nullOr lib.types.port;
53 default = null;
54 description = "Port that will be used to accept client connections.";
55 };
56
57 uuid = lib.mkOption {
58 type = lib.types.nullOr lib.types.str;
59 default = null;
60 description = ''
61 A UUID for uniquely identifying the endpoint. If you have
62 multiple renderers on your network, you MUST set this.
63 '';
64 };
65 };
66
67 config = lib.mkIf cfg.enable {
68 systemd = {
69 services.gmediarender = {
70 wants = [ "network-online.target" ];
71 after = [ "network-online.target" ];
72 wantedBy = [ "multi-user.target" ];
73 description = "gmediarender server daemon";
74 environment = {
75 XDG_CACHE_HOME = "%t/gmediarender";
76 };
77 serviceConfig = {
78 DynamicUser = true;
79 User = "gmediarender";
80 Group = "gmediarender";
81 SupplementaryGroups = [ "audio" ];
82 ExecStart =
83 "${cfg.package}/bin/gmediarender "
84 + lib.optionalString (cfg.audioDevice != null) (
85 "--gstout-audiodevice=${utils.escapeSystemdExecArg cfg.audioDevice} "
86 )
87 + lib.optionalString (cfg.audioSink != null) (
88 "--gstout-audiosink=${utils.escapeSystemdExecArg cfg.audioSink} "
89 )
90 + lib.optionalString (cfg.friendlyName != null) (
91 "--friendly-name=${utils.escapeSystemdExecArg cfg.friendlyName} "
92 )
93 + lib.optionalString (cfg.initialVolume != 0) ("--initial-volume=${toString cfg.initialVolume} ")
94 + lib.optionalString (cfg.port != null) ("--port=${toString cfg.port} ")
95 + lib.optionalString (cfg.uuid != null) ("--uuid=${utils.escapeSystemdExecArg cfg.uuid} ");
96 Restart = "always";
97 RuntimeDirectory = "gmediarender";
98
99 # Security options:
100 CapabilityBoundingSet = "";
101 LockPersonality = true;
102 MemoryDenyWriteExecute = true;
103 NoNewPrivileges = true;
104 # PrivateDevices = true;
105 PrivateTmp = true;
106 PrivateUsers = true;
107 ProcSubset = "pid";
108 ProtectClock = true;
109 ProtectControlGroups = true;
110 ProtectHome = true;
111 ProtectHostname = true;
112 ProtectKernelLogs = true;
113 ProtectKernelModules = true;
114 ProtectKernelTunables = true;
115 ProtectProc = "invisible";
116 RestrictNamespaces = true;
117 RestrictRealtime = true;
118 RestrictSUIDSGID = true;
119 SystemCallArchitectures = "native";
120 SystemCallFilter = [
121 "@system-service"
122 "~@privileged"
123 ];
124 UMask = 66;
125 };
126 };
127 };
128 };
129}