summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Baines <mail@cbaines.net>2026-08-09 10:20:02 +0100
committerChristopher Baines <mail@cbaines.net>2026-08-22 20:03:01 +0100
commit9ceab34e9bd42c878bfeab15c71687ab754e4cf4 (patch)
tree5eb50180c5a7b577f461b2c89d777213308d2c2e
parent239327961888f109b0a66bda099a5ac23ce9f9ef (diff)
gnu: services: audio: Add snapcast snapserver service.
This is just the server component, another service definition is needed for the snapclient. * gnu/services/audio.scm: (snapserver-stream, snapserver-stream?, snapserver-stream-name, snapserver-stream-type, snapserver-stream-location, snapserver-stream-codec, snapserver-stream-sampleformat, snapserver-stream-chunk-ms, snapserver-stream-parameters, snapserver-configuration, snapserver-configuration?, snapserver-configuration-package, snapserver-configuration-user, snapserver-configuration-group, snapserver-configuration-shepherd-requirement, snapserver-configuration-log-file, snapserver-configuration-log-filter, snapserver-configuration-data-directory, snapserver-configuration-mdns?, snapserver-configuration-http?, snapserver-configuration-http-port, snapserver-configuration-http-bind-address, snapserver-configuration-doc-root, snapserver-configuration-tcp-control?, snapserver-configuration-tcp-control-port, snapserver-configuration-tcp-streaming?, snapserver-configuration-tcp-streaming-port, snapserver-configuration-streams, snapserver-configuration-codec, snapserver-configuration-sampleformat, snapserver-configuration-buffer-ms, snapserver-configuration-chunk-ms, snapserver-configuration-send-to-muted?, snapserver-configuration-extra-content): New procedures. (snapserver-service-type): New variable. * doc/guix.texi (Audio Services): Document it. Change-Id: I5dd2c15ff8c1b560abd481147312a8d6fc844776
-rw-r--r--doc/guix.texi174
-rw-r--r--gnu/services/audio.scm361
2 files changed, 530 insertions, 5 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 555fd082471..39544d9acff 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -456,7 +456,7 @@ Services
456* Samba Services:: Samba services. 456* Samba Services:: Samba services.
457* Continuous Integration:: Cuirass and Laminar services. 457* Continuous Integration:: Cuirass and Laminar services.
458* Power Management Services:: Extending battery life, etc. 458* Power Management Services:: Extending battery life, etc.
459* Audio Services:: The MPD. 459* Audio Services:: The MPD and Snapcast.
460* Virtualization Services:: Virtualization services. 460* Virtualization Services:: Virtualization services.
461* Version Control Services:: Software version control servers. 461* Version Control Services:: Software version control servers.
462* Game Services:: Game servers. 462* Game Services:: Game servers.
@@ -20622,7 +20622,7 @@ declaration.
20622* Samba Services:: Samba services. 20622* Samba Services:: Samba services.
20623* Continuous Integration:: Cuirass and Laminar services. 20623* Continuous Integration:: Cuirass and Laminar services.
20624* Power Management Services:: Extending battery life, etc. 20624* Power Management Services:: Extending battery life, etc.
20625* Audio Services:: The MPD. 20625* Audio Services:: The MPD and Snapcast.
20626* Virtualization Services:: Virtualization services. 20626* Virtualization Services:: Virtualization services.
20627* Version Control Services:: Software version control servers. 20627* Version Control Services:: Software version control servers.
20628* Game Services:: Game servers. 20628* Game Services:: Game servers.
@@ -41763,8 +41763,9 @@ The handler for the battattach event.
41763@node Audio Services 41763@node Audio Services
41764@subsection Audio Services 41764@subsection Audio Services
41765 41765
41766The @code{(gnu services audio)} module provides a service to start MPD 41766The @code{(gnu services audio)} module provides services to start MPD
41767(the Music Player Daemon). 41767(the Music Player Daemon) and Snapcast, a multi-room audio streaming
41768system.
41768 41769
41769@cindex mpd 41770@cindex mpd
41770@subsubheading Music Player Daemon 41771@subsubheading Music Player Daemon
@@ -42167,6 +42168,171 @@ Disallowed IP addresses.
42167@end deftp 42168@end deftp
42168@c %end of fragment 42169@c %end of fragment
42169 42170
42171@subsubheading Snapcast
42172
42173@cindex Snapcast
42174@cindex multi-room audio
42175
42176@uref{https://github.com/badaix/snapcast, Snapcast} is a multi-room
42177audio streaming system: @command{snapserver} receives audio from one or
42178more sources and streams it to @command{snapclient} instances, which
42179play it back in sync.
42180
42181The following example runs @command{snapserver} with a single named pipe
42182as its audio source, in addition to the default HTTP interface on port
421831780 and the client-facing streaming interface on port 1704.
42184
42185@lisp
42186(service snapserver-service-type
42187 (snapserver-configuration
42188 (streams (list (snapserver-stream
42189 (name "mpd")
42190 (location "/run/snapserver/mpd"))))))
42191@end lisp
42192
42193@command{snapserver} creates the named pipes of its @code{pipe} sources
42194when it starts, as the @samp{snapserver} user; make sure the program
42195feeding such a pipe---the @code{fifo} output of MPD, for instance---is
42196allowed to write to it.
42197
42198@defvar snapserver-service-type
42199The service type for @command{snapserver}.
42200@end defvar
42201
42202@c %start of fragment
42203@deftp {Data Type} snapserver-configuration
42204Available @code{snapserver-configuration} fields are:
42205
42206@table @asis
42207@item @code{package} (default: @code{snapcast}) (type: file-like)
42208The Snapcast package to use.
42209
42210@item @code{user} (default: @code{%snapserver-user}) (type: user-account)
42211Owner of the @command{snapserver} process.
42212
42213@item @code{group} (default: @code{%snapserver-group}) (type: user-group)
42214Owner group of the @command{snapserver} process.
42215
42216@item @code{shepherd-requirement} (default: @code{'()}) (type: list-of-symbols)
42217This is a list of symbols naming Shepherd services that this service
42218will depend on.
42219
42220@item @code{log-file} (default: @code{"/var/log/snapserver.log"}) (type: string)
42221File where @command{snapserver} writes its log.
42222
42223@item @code{log-filter} (default: @code{"*:info"}) (type: string)
42224Log filter, given as @code{@var{tag}:@var{level}} pairs separated by
42225commas, where @var{tag} is @code{*} or a log tag and @var{level} is one
42226of @code{trace}, @code{debug}, @code{info}, @code{notice},
42227@code{warning}, @code{error} or @code{fatal}.
42228
42229@item @code{data-directory} (default: @code{"/var/lib/snapserver"}) (type: string)
42230Directory where @command{snapserver} stores persistent data, such as
42231client settings.
42232
42233@item @code{mdns?} (default: @code{#t}) (type: boolean)
42234Whether to publish the Snapcast services over mDNS. This requires
42235@code{avahi-service-type} (@pxref{Networking Services}).
42236
42237@item @code{http?} (default: @code{#t}) (type: boolean)
42238Whether to enable the HTTP JSON-RPC interface, which also serves the
42239Snapweb web interface.
42240
42241@item @code{http-port} (default: @code{1780}) (type: integer)
42242Port the HTTP server listens on.
42243
42244@item @code{http-bind-address} (default: @code{"::"}) (type: string)
42245Address the HTTP server listens on.
42246
42247@item @code{doc-root} (type: maybe-file-like)
42248Directory served by the HTTP server. It defaults to the Snapweb web
42249interface bundled with the @code{package} field.
42250
42251@item @code{tcp-control?} (default: @code{#t}) (type: boolean)
42252Whether to enable the TCP JSON-RPC control interface.
42253
42254@item @code{tcp-control-port} (default: @code{1705}) (type: integer)
42255Port the TCP control interface listens on.
42256
42257@item @code{tcp-streaming?} (default: @code{#t}) (type: boolean)
42258Whether to enable TCP streaming, which is what Snapcast clients connect
42259to.
42260
42261@item @code{tcp-streaming-port} (default: @code{1704}) (type: integer)
42262Port the TCP streaming interface listens on.
42263
42264@item @code{streams} (type: list-of-snapserver-stream)
42265List of @code{snapserver-stream} records describing the audio sources
42266@command{snapserver} reads from.
42267
42268@item @code{codec} (default: @code{"flac"}) (type: string)
42269Default codec used to send audio to clients, given as
42270@code{@var{codec}[:@var{options}]} where @var{codec} is one of
42271@code{flac}, @code{ogg}, @code{opus} or @code{pcm}.
42272
42273@item @code{sampleformat} (default: @code{"48000:16:2"}) (type: string)
42274Default sample format of the streams, given as
42275@code{@var{rate}:@var{bits}:@var{channels}}.
42276
42277@item @code{buffer-ms} (default: @code{1000}) (type: integer)
42278End-to-end latency, in milliseconds.
42279
42280@item @code{chunk-ms} (default: @code{20}) (type: integer)
42281Default duration, in milliseconds, of the audio chunks read from the
42282sources.
42283
42284@item @code{send-to-muted?} (default: @code{#f}) (type: boolean)
42285Whether to send audio to muted clients.
42286
42287@item @code{extra-content} (type: maybe-string)
42288Content appended verbatim to @file{snapserver.conf}, for options that
42289are not covered by the fields above, such as the @code{[ssl]} and
42290@code{[authorization]} sections.
42291
42292@end table
42293@end deftp
42294@c %end of fragment
42295
42296@c %start of fragment
42297@deftp {Data Type} snapserver-stream
42298Available @code{snapserver-stream} fields are:
42299
42300@table @asis
42301@item @code{name} (default: @code{"default"}) (type: string)
42302Name of the stream, as shown by Snapcast clients.
42303
42304@item @code{type} (default: @code{pipe}) (type: snapserver-stream-type)
42305Type of the stream source: one of @code{pipe}, @code{file},
42306@code{process}, @code{librespot}, @code{airplay}, @code{tcp},
42307@code{alsa} or @code{meta}.
42308
42309@item @code{location} (default: @code{"/run/snapserver/snapfifo"}) (type: string)
42310Location of the stream source: a file name for @code{pipe}, @code{file}
42311and @code{process} streams, a host name for @code{tcp} streams, a device
42312name for @code{alsa} streams, and a slash-separated list of stream names
42313for @code{meta} streams.
42314
42315@item @code{codec} (type: maybe-string)
42316Codec to use for this stream, overriding the @code{codec} field of
42317@code{snapserver-configuration}.
42318
42319@item @code{sampleformat} (type: maybe-string)
42320Sample format of this stream, given as
42321@code{@var{rate}:@var{bits}:@var{channels}}, overriding the
42322@code{sampleformat} field of @code{snapserver-configuration}.
42323
42324@item @code{chunk-ms} (type: maybe-integer)
42325Duration, in milliseconds, of the audio chunks read from this source,
42326overriding the @code{chunk-ms} field of @code{snapserver-configuration}.
42327
42328@item @code{parameters} (default: @code{'()}) (type: alist)
42329Additional source parameters, given as an association list, for example
42330@code{'(("controlscript" . "meta_mpd.py"))}.
42331
42332@end table
42333@end deftp
42334@c %end of fragment
42335
42170@node Virtualization Services 42336@node Virtualization Services
42171@subsection Virtualization Services 42337@subsection Virtualization Services
42172 42338
diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm
index 518f8f2c0fa..2981b89ed8c 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -32,6 +32,7 @@
32 #:use-module (gnu services admin) 32 #:use-module (gnu services admin)
33 #:use-module (gnu system shadow) 33 #:use-module (gnu system shadow)
34 #:use-module (gnu packages admin) 34 #:use-module (gnu packages admin)
35 #:use-module ((gnu packages audio) #:select (snapcast))
35 #:use-module (gnu packages mpd) 36 #:use-module (gnu packages mpd)
36 #:use-module (guix records) 37 #:use-module (guix records)
37 #:use-module (ice-9 format) 38 #:use-module (ice-9 format)
@@ -123,7 +124,44 @@
123 mympd-ip-acl 124 mympd-ip-acl
124 mympd-ip-acl? 125 mympd-ip-acl?
125 mympd-ip-acl-allow 126 mympd-ip-acl-allow
126 mympd-ip-acl-deny)) 127 mympd-ip-acl-deny
128
129 snapserver-stream
130 snapserver-stream?
131 snapserver-stream-name
132 snapserver-stream-type
133 snapserver-stream-location
134 snapserver-stream-codec
135 snapserver-stream-sampleformat
136 snapserver-stream-chunk-ms
137 snapserver-stream-parameters
138
139 snapserver-configuration
140 snapserver-configuration?
141 snapserver-configuration-package
142 snapserver-configuration-user
143 snapserver-configuration-group
144 snapserver-configuration-shepherd-requirement
145 snapserver-configuration-log-file
146 snapserver-configuration-log-filter
147 snapserver-configuration-data-directory
148 snapserver-configuration-mdns?
149 snapserver-configuration-http?
150 snapserver-configuration-http-port
151 snapserver-configuration-http-bind-address
152 snapserver-configuration-doc-root
153 snapserver-configuration-tcp-control?
154 snapserver-configuration-tcp-control-port
155 snapserver-configuration-tcp-streaming?
156 snapserver-configuration-tcp-streaming-port
157 snapserver-configuration-streams
158 snapserver-configuration-codec
159 snapserver-configuration-sampleformat
160 snapserver-configuration-buffer-ms
161 snapserver-configuration-chunk-ms
162 snapserver-configuration-send-to-muted?
163 snapserver-configuration-extra-content
164 snapserver-service-type))
127 165
128;;; Commentary: 166;;; Commentary:
129;;; 167;;;
@@ -945,3 +983,324 @@ prompting a pin from the user.")
945 mympd-serialize-configuration))) 983 mympd-serialize-configuration)))
946 (description "Run myMPD, a frontend for MPD (Music Player Daemon).") 984 (description "Run myMPD, a frontend for MPD (Music Player Daemon).")
947 (default-value (mympd-configuration)))) 985 (default-value (mympd-configuration))))
986
987
988;;;
989;;; Snapcast
990;;;
991
992(define %snapserver-user
993 (user-account
994 (name "snapserver")
995 (group %lazy-group)
996 (system? #t)
997 (comment "Snapcast server user")
998 (home-directory "/var/lib/snapserver")
999 (shell (file-append shadow "/sbin/nologin"))))
1000
1001(define %snapserver-group
1002 (user-group
1003 (name "snapserver")
1004 (system? #t)))
1005
1006(define (snapserver-stream-type? value)
1007 (memq value '(pipe file process librespot airplay tcp alsa meta)))
1008
1009(define-maybe/no-serialization file-like)
1010
1011(define-configuration/no-serialization snapserver-stream
1012 (name
1013 (string "default")
1014 "Name of the stream, as shown by Snapcast clients.")
1015
1016 (type
1017 (snapserver-stream-type 'pipe)
1018 "Type of the stream source: one of @code{pipe}, @code{file},
1019@code{process}, @code{librespot}, @code{airplay}, @code{tcp}, @code{alsa} or
1020@code{meta}.")
1021
1022 (location
1023 (string "/run/snapserver/snapfifo")
1024 "Location of the stream source: a file name for @code{pipe}, @code{file}
1025and @code{process} streams, a host name for @code{tcp} streams, a device name
1026for @code{alsa} streams, and a slash-separated list of stream names for
1027@code{meta} streams.")
1028
1029 (codec
1030 maybe-string
1031 "Codec to use for this stream, overriding the @code{codec} field of
1032@code{snapserver-configuration}.")
1033
1034 (sampleformat
1035 maybe-string
1036 "Sample format of this stream, given as
1037@code{@var{rate}:@var{bits}:@var{channels}}, overriding the
1038@code{sampleformat} field of @code{snapserver-configuration}.")
1039
1040 (chunk-ms
1041 maybe-integer
1042 "Duration, in milliseconds, of the audio chunks read from this source,
1043overriding the @code{chunk-ms} field of @code{snapserver-configuration}.")
1044
1045 (parameters
1046 (alist '())
1047 "Additional source parameters, given as an association list, for example
1048@code{'((\"controlscript\" . \"meta_mpd.py\"))}."))
1049
1050(define (snapserver-stream->uri stream)
1051 (match-record stream <snapserver-stream>
1052 (name type location codec sampleformat chunk-ms parameters)
1053 (let ((query `(("name" . ,name)
1054 ,@(if (maybe-value-set? codec)
1055 `(("codec" . ,codec))
1056 '())
1057 ,@(if (maybe-value-set? sampleformat)
1058 `(("sampleformat" . ,sampleformat))
1059 '())
1060 ,@(if (maybe-value-set? chunk-ms)
1061 `(("chunk_ms" . ,chunk-ms))
1062 '())
1063 ,@parameters)))
1064 (simple-format #f "~A://~A?~A" type location
1065 (string-join
1066 (map (match-lambda
1067 ((key . value)
1068 (simple-format #f "~A=~A" key value)))
1069 query)
1070 "&")))))
1071
1072(define list-of-snapserver-stream?
1073 (list-of snapserver-stream?))
1074
1075(define-configuration/no-serialization snapserver-configuration
1076 (package
1077 (file-like snapcast)
1078 "The Snapcast package to use.")
1079
1080 (user
1081 (user-account %snapserver-user)
1082 "Owner of the @command{snapserver} process.")
1083
1084 (group
1085 (user-group %snapserver-group)
1086 "Owner group of the @command{snapserver} process.")
1087
1088 (shepherd-requirement
1089 (list-of-symbols '())
1090 "This is a list of symbols naming Shepherd services that this service
1091will depend on.")
1092
1093 (log-file
1094 (string "/var/log/snapserver.log")
1095 "File where @command{snapserver} writes its log.")
1096
1097 (log-filter
1098 (string "*:info")
1099 "Log filter, given as @code{@var{tag}:@var{level}} pairs separated by
1100commas, where @var{tag} is @code{*} or a log tag and @var{level} is one of
1101@code{trace}, @code{debug}, @code{info}, @code{notice}, @code{warning},
1102@code{error} or @code{fatal}.")
1103
1104 (data-directory
1105 (string "/var/lib/snapserver")
1106 "Directory where @command{snapserver} stores persistent data, such as
1107client settings.")
1108
1109 (mdns?
1110 (boolean #t)
1111 "Whether to publish the Snapcast services over mDNS. This requires
1112@code{avahi-service-type} (@pxref{Networking Services}).")
1113
1114 (http?
1115 (boolean #t)
1116 "Whether to enable the HTTP JSON-RPC interface, which also serves the
1117Snapweb web interface.")
1118
1119 (http-port
1120 (integer 1780)
1121 "Port the HTTP server listens on.")
1122
1123 (http-bind-address
1124 (string "::")
1125 "Address the HTTP server listens on.")
1126
1127 (doc-root
1128 maybe-file-like
1129 "Directory served by the HTTP server. It defaults to the Snapweb web
1130interface bundled with the @code{package} field.")
1131
1132 (tcp-control?
1133 (boolean #t)
1134 "Whether to enable the TCP JSON-RPC control interface.")
1135
1136 (tcp-control-port
1137 (integer 1705)
1138 "Port the TCP control interface listens on.")
1139
1140 (tcp-streaming?
1141 (boolean #t)
1142 "Whether to enable TCP streaming, which is what Snapcast clients connect
1143to.")
1144
1145 (tcp-streaming-port
1146 (integer 1704)
1147 "Port the TCP streaming interface listens on.")
1148
1149 (streams
1150 (list-of-snapserver-stream (list (snapserver-stream)))
1151 "List of @code{snapserver-stream} records describing the audio sources
1152@command{snapserver} reads from.")
1153
1154 (codec
1155 (string "flac")
1156 "Default codec used to send audio to clients, given as
1157@code{@var{codec}[:@var{options}]} where @var{codec} is one of @code{flac},
1158@code{ogg}, @code{opus} or @code{pcm}.")
1159
1160 (sampleformat
1161 (string "48000:16:2")
1162 "Default sample format of the streams, given as
1163@code{@var{rate}:@var{bits}:@var{channels}}.")
1164
1165 (buffer-ms
1166 (integer 1000)
1167 "End-to-end latency, in milliseconds.")
1168
1169 (chunk-ms
1170 (integer 20)
1171 "Default duration, in milliseconds, of the audio chunks read from the
1172sources.")
1173
1174 (send-to-muted?
1175 (boolean #f)
1176 "Whether to send audio to muted clients.")
1177
1178 (extra-content
1179 maybe-string
1180 "Content appended verbatim to @file{snapserver.conf}, for options that are
1181not covered by the fields above, such as the @code{[ssl]} and
1182@code{[authorization]} sections."))
1183
1184(define (snapserver-config-file config)
1185 (define (boolean->string value)
1186 (if value "1" "0"))
1187
1188 (match-record config <snapserver-configuration>
1189 (package log-filter data-directory mdns?
1190 http? http-port http-bind-address doc-root
1191 tcp-control? tcp-control-port tcp-streaming? tcp-streaming-port
1192 streams codec sampleformat buffer-ms chunk-ms send-to-muted?
1193 extra-content)
1194 (apply mixed-text-file "snapserver.conf"
1195 `("[server]\n"
1196 "datadir = " ,data-directory "\n"
1197 "mdns_enabled = " ,(boolean->string mdns?) "\n"
1198
1199 "\n[http]\n"
1200 "enabled = " ,(boolean->string http?) "\n"
1201 "port = " ,(number->string http-port) "\n"
1202 "bind_to_address = " ,http-bind-address "\n"
1203 "doc_root = " ,(if (maybe-value-set? doc-root)
1204 doc-root
1205 (file-append package
1206 "/share/snapserver/snapweb"))
1207 "\n"
1208
1209 "\n[tcp-control]\n"
1210 "enabled = " ,(boolean->string tcp-control?) "\n"
1211 "port = " ,(number->string tcp-control-port) "\n"
1212
1213 "\n[tcp-streaming]\n"
1214 "enabled = " ,(boolean->string tcp-streaming?) "\n"
1215 "port = " ,(number->string tcp-streaming-port) "\n"
1216
1217 "\n[stream]\n"
1218 ;; The upstream defaults for these two point into /usr/share.
1219 "plugin_dir = " ,(file-append package
1220 "/share/snapserver/plug-ins") "\n"
1221 "sandbox_dir = " ,(file-append package
1222 "/share/snapserver/sandbox") "\n"
1223 ,@(map (lambda (stream)
1224 (string-append "source = "
1225 (snapserver-stream->uri stream) "\n"))
1226 streams)
1227 "codec = " ,codec "\n"
1228 "sampleformat = " ,sampleformat "\n"
1229 "buffer = " ,(number->string buffer-ms) "\n"
1230 "chunk_ms = " ,(number->string chunk-ms) "\n"
1231 "send_to_muted = " ,(boolean->string send-to-muted?) "\n"
1232
1233 "\n[logging]\n"
1234 ;; Log to standard error, which the Shepherd redirects to the
1235 ;; 'log-file' of the service.
1236 "sink = stderr\n"
1237 "filter = " ,log-filter "\n"
1238 ,@(if (maybe-value-set? extra-content)
1239 `("\n" ,extra-content "\n")
1240 '())))))
1241
1242(define (snapserver-shepherd-service config)
1243 (match-record config <snapserver-configuration>
1244 (package user group shepherd-requirement log-file data-directory
1245 mdns? streams)
1246 (let ((config-file (snapserver-config-file config))
1247 (username (user-account-name user))
1248 (groupname (user-group-name group))
1249 ;; 'snapserver' creates the named pipes of its 'pipe' sources, but
1250 ;; not the directories holding them.
1251 (directories
1252 (delete-duplicates
1253 (cons* data-directory (dirname log-file)
1254 (filter-map (lambda (stream)
1255 (and (eq? 'pipe
1256 (snapserver-stream-type
1257 stream))
1258 (dirname
1259 (snapserver-stream-location
1260 stream))))
1261 streams)))))
1262 (shepherd-service
1263 (documentation "Run the Snapcast server.")
1264 (requirement `(user-processes loopback
1265 ,@(if mdns? '(avahi-daemon) '())
1266 ,@shepherd-requirement))
1267 (provision '(snapserver))
1268 (start
1269 (with-imported-modules (source-module-closure
1270 '((gnu build activation)))
1271 #~(begin
1272 (use-modules (gnu build activation))
1273
1274 (let ((user (getpw #$username)))
1275 (for-each (lambda (directory)
1276 (unless (file-exists? directory)
1277 (mkdir-p/perms directory user #o755)))
1278 '#$directories))
1279
1280 (make-forkexec-constructor
1281 (list #$(file-append package "/bin/snapserver")
1282 "--config" #$config-file)
1283 #:user #$username
1284 #:group #$groupname
1285 #:log-file #$log-file))))
1286 (stop #~(make-kill-destructor))
1287 (actions (list (shepherd-configuration-action config-file)))))))
1288
1289(define (snapserver-accounts config)
1290 (match-record config <snapserver-configuration> (user group)
1291 (list (if (eq? (user-account-group user) %lazy-group)
1292 (set-user-group user group)
1293 user)
1294 group)))
1295
1296(define snapserver-service-type
1297 (service-type
1298 (name 'snapserver)
1299 (extensions
1300 (list (service-extension shepherd-root-service-type
1301 (compose list snapserver-shepherd-service))
1302 (service-extension account-service-type
1303 snapserver-accounts)))
1304 (description "Run the Snapcast server, @command{snapserver}, which streams
1305audio to Snapcast clients.")
1306 (default-value (snapserver-configuration))))