From unknown Wed Jun 18 00:21:10 2025 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.509 (Entity 5.509) Content-Type: text/plain; charset=utf-8 From: bug#59866 <59866@debbugs.gnu.org> To: bug#59866 <59866@debbugs.gnu.org> Subject: Status: [PATCH 0/2] services: mpd: Refactor MPD service. Reply-To: bug#59866 <59866@debbugs.gnu.org> Date: Wed, 18 Jun 2025 07:21:10 +0000 retitle 59866 [PATCH 0/2] services: mpd: Refactor MPD service. reassign 59866 guix-patches submitter 59866 mirai@makinata.eu severity 59866 normal tag 59866 patch thanks From debbugs-submit-bounces@debbugs.gnu.org Tue Dec 06 18:23:23 2022 Received: (at submit) by debbugs.gnu.org; 6 Dec 2022 23:23:24 +0000 Received: from localhost ([127.0.0.1]:45740 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2hHX-0000of-NB for submit@debbugs.gnu.org; Tue, 06 Dec 2022 18:23:23 -0500 Received: from lists.gnu.org ([209.51.188.17]:58510) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2hHV-0000oZ-9e for submit@debbugs.gnu.org; Tue, 06 Dec 2022 18:23:22 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p2hHV-000742-22 for guix-patches@gnu.org; Tue, 06 Dec 2022 18:23:21 -0500 Received: from smtpm2.myservices.hosting ([185.26.105.233]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p2hHT-00043l-2n for guix-patches@gnu.org; Tue, 06 Dec 2022 18:23:20 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm2.myservices.hosting (Postfix) with ESMTP id 771A920D63 for ; Wed, 7 Dec 2022 00:23:15 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 213F480097; Wed, 7 Dec 2022 00:23:15 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id gnzJf-MHdcfJ; Wed, 7 Dec 2022 00:23:14 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id B91CE80093; Wed, 7 Dec 2022 00:23:13 +0100 (CET) From: mirai@makinata.eu To: guix-patches@gnu.org Subject: [PATCH 0/2] services: mpd: Refactor MPD service Date: Tue, 6 Dec 2022 23:22:16 +0000 Message-Id: X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=185.26.105.233; envelope-from=mirai@makinata.eu; helo=smtpm2.myservices.hosting X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.3 (-) X-Debbugs-Envelope-To: submit Cc: mirai@makinata.eu X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.3 (--) Modernizes and expands 'mpd-service-type'. Performs "pretty-formatting" to the generated configuration file at the cost of a few extra procedures. It also deprecates some of the fields (abbreviated forms). Bruno Victal (2): services: mpd: use 'define-configuration'. services: mpd: Refactor MPD service. doc/guix.texi | 172 +++++++++++-- gnu/services/audio.scm | 549 ++++++++++++++++++++++++++++++----------- 2 files changed, 556 insertions(+), 165 deletions(-) base-commit: b94724e8b2102be0fe9d19e9dfe44d6f7101bd4b -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Tue Dec 06 18:25:35 2022 Received: (at 59866) by debbugs.gnu.org; 6 Dec 2022 23:25:35 +0000 Received: from localhost ([127.0.0.1]:45755 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2hJf-0000q7-5U for submit@debbugs.gnu.org; Tue, 06 Dec 2022 18:25:35 -0500 Received: from smtpm4.myservices.hosting ([185.26.105.235]:59584) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2hJd-0000q1-HR for 59866@debbugs.gnu.org; Tue, 06 Dec 2022 18:25:34 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm4.myservices.hosting (Postfix) with ESMTP id ACB4220555 for <59866@debbugs.gnu.org>; Wed, 7 Dec 2022 00:25:32 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 60E0380097; Wed, 7 Dec 2022 00:25:32 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 7IKKuLBZjI1B; Wed, 7 Dec 2022 00:25:31 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 9C2DA80096; Wed, 7 Dec 2022 00:25:31 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH 1/2] services: mpd: use 'define-configuration'. Date: Tue, 6 Dec 2022 23:25:16 +0000 Message-Id: X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal --- gnu/services/audio.scm | 217 ++++++++++++++++++++++++----------------- 1 file changed, 129 insertions(+), 88 deletions(-) diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index c60053f33c..2351db8a4a 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -21,6 +21,7 @@ (define-module (gnu services audio) #:use-module (guix gexp) #:use-module (gnu services) + #:use-module (gnu services configuration) #:use-module (gnu services shepherd) #:use-module (gnu system shadow) #:use-module (gnu packages admin) @@ -28,6 +29,8 @@ (define-module (gnu services audio) #:use-module (guix records) #:use-module (ice-9 match) #:use-module (ice-9 format) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? mpd-configuration @@ -40,93 +43,131 @@ (define-module (gnu services audio) ;;; ;;; Code: -(define-record-type* - mpd-output make-mpd-output - mpd-output? - (type mpd-output-type - (default "pulse")) - (name mpd-output-name - (default "MPD")) - (enabled? mpd-output-enabled? - (default #t)) - (tags? mpd-output-tags? - (default #t)) - (always-on? mpd-output-always-on? - (default #f)) - (mixer-type mpd-output-mixer-type - ;; valid: hardware, software, null, none - (default #f)) - (extra-options mpd-output-extra-options - (default '()))) - -(define-record-type* - mpd-configuration make-mpd-configuration - mpd-configuration? - (user mpd-configuration-user - (default "mpd")) - (music-dir mpd-configuration-music-dir - (default "~/Music")) - (playlist-dir mpd-configuration-playlist-dir - (default "~/.mpd/playlists")) - (db-file mpd-configuration-db-file - (default "~/.mpd/tag_cache")) - (state-file mpd-configuration-state-file - (default "~/.mpd/state")) - (sticker-file mpd-configuration-sticker-file - (default "~/.mpd/sticker.sql")) - (port mpd-configuration-port - (default "6600")) - (address mpd-configuration-address - (default "any")) - (outputs mpd-configuration-outputs - (default (list (mpd-output))))) - -(define (mpd-output->string output) - "Convert the OUTPUT of type to a configuration file snippet." - (let ((extra (string-join - (map (match-lambda - ((key . value) - (format #f " ~a \"~a\"" - (string-map - (lambda (c) (if (char=? c #\-) #\_ c)) - (symbol->string key)) - value))) - (mpd-output-extra-options output)) - "\n"))) - (format #f "\ -audio_output { - type \"~a\" - name \"~a\" -~:[ enabled \"no\"~%~;~]\ -~:[ tags \"no\"~%~;~]\ -~:[~; always_on \"yes\"~%~]\ -~@[ mixer_type \"~a\"~%~]\ -~a~%}~%" - (mpd-output-type output) - (mpd-output-name output) - (mpd-output-enabled? output) - (mpd-output-tags? output) - (mpd-output-always-on? output) - (mpd-output-mixer-type output) - extra))) - -(define (mpd-config->file config) - (apply - mixed-text-file "mpd.conf" - "pid_file \"" (mpd-file-name config "pid") "\"\n" - (append (map mpd-output->string - (mpd-configuration-outputs config)) - (map (match-lambda - ((config-name config-val) - (string-append config-name " \"" (config-val config) "\"\n"))) - `(("user" ,mpd-configuration-user) - ("music_directory" ,mpd-configuration-music-dir) - ("playlist_directory" ,mpd-configuration-playlist-dir) - ("db_file" ,mpd-configuration-db-file) - ("state_file" ,mpd-configuration-state-file) - ("sticker_file" ,mpd-configuration-sticker-file) - ("port" ,mpd-configuration-port) - ("bind_to_address" ,mpd-configuration-address)))))) +(define (uglify-field-name field-name) + (let ((str (symbol->string field-name))) + (string-join (string-split (if (string-suffix? "?" str) + (string-drop-right str 1) + str) + #\-) + "_"))) + +(define (free-form-args? val) + (match val + (() #t) + ((((? symbol?) . (? string?)) . val) (free-form-args? val)) + (_ #f))) + +(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) + #~(begin + (use-modules ((ice-9 format))) + (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) + field-name + (uglify-field-name field-name)) #$value))) + +(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) + (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) + +(define mpd-serialize-number mpd-serialize-field) + +(define mpd-serialize-string mpd-serialize-field) + +(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) + (mpd-serialize-field field-name (if value "yes" "no") indent-level)) + +(define (mpd-serialize-list-of-mpd-output field-name value) + #~(string-append "\naudio_output {\n" + #$@(map (cut serialize-configuration <> + mpd-output-fields) + value) + "}\n")) + +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) +(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) +(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) +(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) +(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) + +(define-configuration mpd-output + (name + (string "MPD") + "The name of the audio output.") + (type + (string "pulse") + "The type of audio output.") + (enabled? + (boolean #t) + "Specifies whether this audio output is enabled when MPD is started. By +default, all audio outputs are enabled. This is just the default +setting when there is no state file; with a state file, the previous +state is restored.") + (tags? + (boolean #t) + "If set to @code{#f}, then MPD will not send tags to this output. This +is only useful for output plugins that can receive tags, for example the +@code{httpd} output plugin.") + (always-on? + (boolean #f) + "If set to @code{#t}, then MPD attempts to keep this audio output always +open. This may be useful for streaming servers, when you don’t want to +disconnect all listeners even when playback is accidentally stopped.") + (mixer-type + (string "none") + "This field accepts a symbol that specifies which mixer should be used +for this audio output: the @code{hardware} mixer, the @code{software} +mixer, the @code{null} mixer (allows setting the volume, but with no +effect; this can be used as a trick to implement an external mixer +External Mixer) or no mixer (@code{none}).") + (extra-options + (free-form-args '()) + "An association list of option symbols to string values to be appended to +the audio output configuration.") + (prefix mpd-subsystem-)) + +(define list-of-mpd-output? + (list-of mpd-output?)) + +(define-configuration mpd-configuration + (user + (string "mpd") + "The user to run mpd as.") + (music-dir + (string "~/Music") + "The directory to scan for music files." + (lambda (_ x) + (mpd-serialize-field "music_directory" x))) + (playlist-dir + (string "~/.mpd/playlists") + "The directory to store playlists." + (lambda (_ x) + (mpd-serialize-field "playlist_directory" x))) + (db-file + (string "~/.mpd/tag_cache") + "The location of the music database.") + (state-file + (string "~/.mpd/state") + "The location of the file that stores current MPD's state.") + (sticker-file + (string "~/.mpd/sticker.sql") + "The location of the sticker database.") + (port + (string "6600") + "The port to run mpd on.") + (address + (string "any") + "The address that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (mpd-serialize-field "bind_to_address" x))) + (outputs + (list-of-mpd-output (list (mpd-output))) + "The audio outputs that MPD can use. +By default this is a single output using pulseaudio.") + (prefix mpd-)) (define (mpd-file-name config file) "Return a path in /var/run/mpd/ that is writable @@ -143,7 +184,7 @@ (define (mpd-shepherd-service config) (start #~(make-forkexec-constructor (list #$(file-append mpd "/bin/mpd") "--no-daemon" - #$(mpd-config->file config)) + #$(mpd-serialize-configuration config)) #:environment-variables ;; Required to detect PulseAudio when run under a user account. (list (string-append -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Tue Dec 06 18:25:42 2022 Received: (at 59866) by debbugs.gnu.org; 6 Dec 2022 23:25:42 +0000 Received: from localhost ([127.0.0.1]:45759 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2hJk-0000qK-QQ for submit@debbugs.gnu.org; Tue, 06 Dec 2022 18:25:42 -0500 Received: from smtpm5.myservices.hosting ([185.26.105.236]:44784) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2hJh-0000qE-Bi for 59866@debbugs.gnu.org; Tue, 06 Dec 2022 18:25:39 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm5.myservices.hosting (Postfix) with ESMTP id B4BD720CFC for <59866@debbugs.gnu.org>; Wed, 7 Dec 2022 00:25:36 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 6064280096; Wed, 7 Dec 2022 00:25:36 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 8Yz3X4RiMOQf; Wed, 7 Dec 2022 00:25:35 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id A621980093; Wed, 7 Dec 2022 00:25:34 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH 2/2] services: mpd: Refactor MPD service. Date: Tue, 6 Dec 2022 23:25:17 +0000 Message-Id: X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal Introduces 'mpd-plugin' and 'mpd-partition' records. Expands 'mpd-output' and 'mpd-configuration' records. Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids serializing unused fields that may introduce undesired behavior. Implement log-rotation via rottlog. Implements Shepherd actions: 'reload' and 'configuration'. --- doc/guix.texi | 172 ++++++++++++++--- gnu/services/audio.scm | 422 +++++++++++++++++++++++++++++++---------- 2 files changed, 472 insertions(+), 122 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index a79b777826..0408cab1cb 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -32823,79 +32824,184 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (type: maybe-string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) +@item @code{port} (default: @code{6600}) (type: maybe-integer) The port to run mpd on. -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{addresses} (type: maybe-list-of-string) +The addresses that mpd will bind to. To use a Unix domain socket, an +absolute path can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". + +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -32907,7 +33013,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 2351db8a4a..b0587e0d3c 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Peter Mikkelsen ;;; Copyright © 2019 Ricardo Wurmus ;;; Copyright © 2020 Ludovic Courtès +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -20,15 +21,18 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) #:export (mpd-output @@ -51,180 +55,406 @@ (define (uglify-field-name field-name) #\-) "_"))) -(define (free-form-args? val) - (match val - (() #t) - ((((? symbol?) . (? string?)) . val) (free-form-args? val)) - (_ #f))) +(define list-of-string? + (list-of string?)) -(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) - #~(begin - (use-modules ((ice-9 format))) - (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) - field-name - (uglify-field-name field-name)) #$value))) +(define list-of-symbol? + (list-of symbol?)) -(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) - (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) +(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (if (boolean? value) (if value "yes" "no") value))) + #~(begin + (use-modules (ice-9 format)) + (format #f "~v/~a \"~a\"~%" #$indent-level #$field #$value)))) (define mpd-serialize-number mpd-serialize-field) (define mpd-serialize-string mpd-serialize-field) -(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) - (mpd-serialize-field field-name (if value "yes" "no") indent-level)) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define* (mpd-serialize-alist field-name value #:optional (indent-level 0)) + #~(string-append #$@(generic-serialize-alist list (cut mpd-serialize-field <> <> indent-level) value))) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) (define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) (define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) (define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) (define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) +(define mpd-subsystem-serialize-alist (cut mpd-serialize-alist <> <> 1)) + +(define-maybe string (prefix mpd-subsystem-)) +(define-maybe boolean (prefix mpd-subsystem-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . addresses))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin (warn-about-deprecation field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning (G_ "string value for '~a' is deprecated, use integer instead~%") field-name)) + (mpd-serialize-field field-name value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-subsystem-)) + +;; Translate field name into block name for mpd.conf" +(define mpd-subsystem-name + (match-lambda + ('archive-plugins "archive_plugin") + ('playlist-plugins "playlist_plugin") + ('inputs "input") + ('decoders "decoder") + ('filters "filter") + (x (symbol->string x)))) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(string-append "\n" #$(mpd-subsystem-name field-name) " {\n" + #$(serialize-configuration value mpd-plugin-fields) + "}\n")) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) value))) + +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-subsystem-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(string-append "\npartition {\n" + #$(serialize-configuration value mpd-partition-fields) + "}\n")) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name (string "MPD") "The name of the audio output.") + (type (string "pulse") "The type of audio output.") + (enabled? (boolean #t) "Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin.") + (always-on? (boolean #f) "If set to @code{#t}, then MPD attempts to keep this audio output always open. This may be useful for streaming servers, when you don’t want to disconnect all listeners even when playback is accidentally stopped.") + (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} is +to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options - (free-form-args '()) - "An association list of option symbols to string values to be appended to + (alist '()) + "An association list of option symbols/strings to string values to be appended to the audio output configuration.") + (prefix mpd-subsystem-)) +(define (mpd-serialize-mpd-output field-name value) + #~(string-append "\naudio_output {\n" + #$(serialize-configuration value mpd-output-fields) + "}\n")) + +(define (mpd-serialize-list-of-mpd-output field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-output #f <>) value))) + (define list-of-mpd-output? (list-of mpd-output?)) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + + (group + maybe-string + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the local syslog daemon or +@code{%unset-value} to omit this directive from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. Available values: @code{notice}, +@code{info}, @code{verbose}, @code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) - (playlist-dir - (string "~/.mpd/playlists") + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") + + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) + (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") + (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") + (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") + (port - (string "6600") + (maybe-port 6600) ; TODO: switch to integer "The port to run mpd on.") - (address - (string "any") + + (addresses + maybe-list-of-string + "The addresses that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations.") + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations.") + + (input-cache-size + maybe-string + "MPD input cache size." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-subsystem-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations.") + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations.") + (outputs (list-of-mpd-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reload) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) + (match-record config (user package shepherd-requirement) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reload) + (documentation "Reopen log files and flush caches.") + (procedure #~(lambda (pid) + (if pid + (begin (kill pid SIGHUP) + (format #t "Issued SIGHUP to Service MPD (PID ~a)." pid)) + (format #t "Service MPD is not running."))))))))))) (define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) + (match-record config (user log-file) #~(begin (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") + (let* ((user (getpw #$user)) + (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd")) + (new-directory (string-append (passwd:dir user) "/.config/mpd"))) + ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd. + (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory))) + (rename-file deprecated-directory new-directory) + (chown new-directory (passwd:uid user) (passwd:gid user))) + (mkdir-p (dirname #$log-file)))))) - (shell (file-append shadow "/sbin/nologin"))))) +(define (mpd-accounts config) + (match-record config (user) + (list (user-account + (name user) + (group "nogroup") + (system? #t) + (comment "Music Player Daemon (MPD) user") + (home-directory "/var/lib/mpd") ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -234,7 +464,9 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) + mpd-accounts) (service-extension activation-service-type - mpd-service-activation))) + mpd-service-activation) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Wed Dec 07 03:59:35 2022 Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 08:59:35 +0000 Received: from localhost ([127.0.0.1]:48600 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2qH8-00016K-VL for submit@debbugs.gnu.org; Wed, 07 Dec 2022 03:59:35 -0500 Received: from knopi.disroot.org ([178.21.23.139]:36624) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2qH6-00016D-5J for 59866@debbugs.gnu.org; Wed, 07 Dec 2022 03:59:34 -0500 Received: from localhost (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 55C1641538; Wed, 7 Dec 2022 09:59:30 +0100 (CET) X-Virus-Scanned: SPAM Filter at disroot.org Received: from knopi.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9ckLy6OFx9ap; Wed, 7 Dec 2022 09:59:29 +0100 (CET) Content-Type: multipart/signed; boundary=ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e; micalg=pgp-sha512; protocol="application/pgp-signature" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1670403569; bh=7n0BmylC3oc8H39zfidTICQ/FQ07oTFmw65oEaZQ/ak=; h=Date:Subject:From:To:References:In-Reply-To; b=Uosy3vJ+YOcbmlGpGE5CYf+CwNuJh7VY1ZJEuI12g96TfM5fAWsLLAyGsKvILIuAf AYqW4HlaMl3Xg2HQ2xuzvN0QJaOQIejEYXfAVUQJ3szgb+4PmjO7w/FrIHgmyvkOSC el2zVJiCxz07D1i+Vs6EvNzVw2pTs4f/mc4tsdrWqCUdjEbAJqjsutnlHMUqRTGHjz sDwNGbM0bX25Pa3UgCGbWyd5wFTf7fCYEL1Pj4TNgMDAXyiX4qaChPQHNwUrsioJUP VjY10KkZTwreZCbRCfte1yv0uqyDFVMwEAKVtChOGiLVKhnEuhKlWFy8YCeZs+iU3e fwkiTDWGx1tSg== Date: Wed, 07 Dec 2022 08:59:23 +0000 Message-Id: Subject: Re: [bug#59866] [PATCH 0/2] services: mpd: Refactor MPD service From: "(" To: , <59866@debbugs.gnu.org> References: In-Reply-To: X-Spam-Score: 0.1 (/) X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.9 (/) --ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 On Tue Dec 6, 2022 at 11:22 PM GMT, wrote: > Modernizes and expands 'mpd-service-type'. > Performs "pretty-formatting" to the generated configuration file > at the cost of a few extra procedures. > It also deprecates some of the fields (abbreviated forms). > > Bruno Victal (2): > services: mpd: use 'define-configuration'. > services: mpd: Refactor MPD service. > > doc/guix.texi | 172 +++++++++++-- > gnu/services/audio.scm | 549 ++++++++++++++++++++++++++++++----------- > 2 files changed, 556 insertions(+), 165 deletions(-) > > > base-commit: b94724e8b2102be0fe9d19e9dfe44d6f7101bd4b > --=20 > 2.38.1 Could you also add support for ``herd configuration'' (added in #59197)? -- ( --ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6Vh10NblKE5doNlW7ImHg/nqI20FAmOQVewACgkQ7ImHg/nq I23FbQv/e6N7SbmFcjqJ7eAs3eNcwtP3FfMLxIqkFAKqi3IVJwQpyHY+J+OmQA4q TEE1FBmM+nPJ1J/XG/ahHh2ACOULT9YZPaEwsndZQEPyoUr/cbdFQ9k0J0GNG62+ hcwEmlGpHRCAR4T1gjFj7hqvlI6Gt/S/kjG8Mygnj7Q82qv4V4LJcjbRf4Q8F4Q5 15EYjvPQRfFdgT0rm9QYQU1YX/qOCX4aIiZGPkETV3i9J6bPSghtjcXQgbX4WzzS 6T0HEIIOOeJPNf4lJ+DH+N5m3iLxKe+PTZJ2owpihymyE5YeUhGRoGk664MzNSmG wuXaFMQdSJFQ8zDqywkTGMy834OA7ZXxNvScVtYBVJmuCh1Vj6k2KRJbsdpoDYws w3dQW1NF29ijChDsu7lO9RViMIf6gatb/xz/UitrR0EFe9i0UFAGM9hMgwG5s1yE yCFnogLZkxCStbEi599Jx2kwe8wnphqn3yZvm5L1jqmrOZgpwmLAASBbC68hZFug 8j/MIRxB =2UDc -----END PGP SIGNATURE----- --ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e-- From debbugs-submit-bounces@debbugs.gnu.org Wed Dec 07 08:43:02 2022 Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 13:43:02 +0000 Received: from localhost ([127.0.0.1]:50436 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2uhS-0000yb-1d for submit@debbugs.gnu.org; Wed, 07 Dec 2022 08:43:02 -0500 Received: from smtpm5.myservices.hosting ([185.26.105.236]:34812) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2uhQ-0000yP-SC for 59866@debbugs.gnu.org; Wed, 07 Dec 2022 08:43:01 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm5.myservices.hosting (Postfix) with ESMTP id 9A4EA20C90; Wed, 7 Dec 2022 14:42:57 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 34ED380099; Wed, 7 Dec 2022 14:42:57 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id EgFTmrhw9hV7; Wed, 7 Dec 2022 14:42:56 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 0BABF8009B; Wed, 7 Dec 2022 14:42:53 +0100 (CET) Message-ID: Date: Wed, 7 Dec 2022 13:42:53 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.5.1 Subject: Re: [bug#59866] [PATCH 0/2] services: mpd: Refactor MPD service Content-Language: en-US To: "(" , 59866@debbugs.gnu.org References: From: mirai In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) It already does! The second commit introduces the bulk of the changes :) On 2022-12-07 08:59, ( wrote: > On Tue Dec 6, 2022 at 11:22 PM GMT, wrote: >> Modernizes and expands 'mpd-service-type'. >> Performs "pretty-formatting" to the generated configuration file >> at the cost of a few extra procedures. >> It also deprecates some of the fields (abbreviated forms). >> >> Bruno Victal (2): >> services: mpd: use 'define-configuration'. >> services: mpd: Refactor MPD service. >> >> doc/guix.texi | 172 +++++++++++-- >> gnu/services/audio.scm | 549 ++++++++++++++++++++++++++++++----------- >> 2 files changed, 556 insertions(+), 165 deletions(-) >> >> >> base-commit: b94724e8b2102be0fe9d19e9dfe44d6f7101bd4b >> -- >> 2.38.1 > > Could you also add support for ``herd configuration'' (added in #59197)? > -- ( From debbugs-submit-bounces@debbugs.gnu.org Wed Dec 07 08:43:39 2022 Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 13:43:39 +0000 Received: from localhost ([127.0.0.1]:50439 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2ui3-0000z3-AU for submit@debbugs.gnu.org; Wed, 07 Dec 2022 08:43:39 -0500 Received: from knopi.disroot.org ([178.21.23.139]:36064) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2ui1-0000yx-QS for 59866@debbugs.gnu.org; Wed, 07 Dec 2022 08:43:38 -0500 Received: from localhost (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 7736D415D7; Wed, 7 Dec 2022 14:43:36 +0100 (CET) X-Virus-Scanned: SPAM Filter at disroot.org Received: from knopi.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id A5bp9Yf9XSa7; Wed, 7 Dec 2022 14:43:35 +0100 (CET) Content-Type: multipart/signed; boundary=e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325; micalg=pgp-sha512; protocol="application/pgp-signature" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1670420615; bh=Ssz1h51TTFIxyStFf76GwZFlrKD0R/Xa5xPY17TkN4M=; h=Date:Subject:From:To:References:In-Reply-To; b=HsF13kvuQggeU85cF0vawyU7xwMv4O8DB51XRitUH6Czm1uyjGn8IHw/8iJIQhaKZ xzjX6iIEQmaJecdTM4Ai96doNsQwig5wBvrGuxdNmiCFczRvPgCC3WI2SBipdKUf5L Wic6zfbCr9f34MnNfH4YLvjrHLml8TkS/R454X2bgYrXYgklykeqbyBfOCrqr6L7+K b3uxw4tasp1s/L3eKRmWRhBi86PGYLQYqNElTbW875siQZYK+dsDlzSdk2bhuSsjCR VFdZ312oN5Vgu9XEfDsdbqqKGSSx6Th4FxEY/5g3mMe1i55d0bN09nE0qw3KDprW3e 9KpPU3PXDkwSg== Date: Wed, 07 Dec 2022 13:43:31 +0000 Message-Id: Subject: Re: [bug#59866] [PATCH 0/2] services: mpd: Refactor MPD service From: "(" To: "mirai" , <59866@debbugs.gnu.org> References: In-Reply-To: X-Spam-Score: 0.1 (/) X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.9 (/) --e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325 Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 Heya, On Wed Dec 7, 2022 at 1:42 PM GMT, mirai wrote: > It already does! The second commit introduces the bulk of the changes :) Oops :) Reviewing now... -- ( --e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325 Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6Vh10NblKE5doNlW7ImHg/nqI20FAmOQmIQACgkQ7ImHg/nq I23rXQv+JkbnxdWrWh17sL1WfjnKBfw1dbwDR5EOcwt3gyH95DYX0L8EtxWv1kwH fnV+ZYIu1W1/gqrrkNWAWcXqIFliZjL7wmPIqxE4QdJ0eB9/QVLvp6Cx6nLsuYAK TDVZUBLbKHgKIQlKR9dIyPILEgKxHW7E1x0lnaOda86KeiPerUyG3BEx/KbIqm92 Txk9agDrNVc3+vS+cyhgtnf0LvIw4CgMg19UjhZwOGm/n+/iPjtTysmwEbU3ZobP Mv3LQR97LqOlc0UBjWy4wmKRSXigI8mR53D1nz0A8pcSElTIFCD/2nfcl3dRg7GH fDbPpUHW3qGwHiLKX7supcu8ge/LMcNJpdHbtxUFrroegI6ODGHyuKfo5wodc7mn wRuvTVWsXpunRl9V9/NyZO40ao43a54VYOXeKTSBXunGlqIh4uRhPjSTD+EWT4hv 7FBLcU8OXDj2j9mAAHzUEnWZMJgsDhcjcpixxRSb2Hvorpi5/nmXuAR6XM8dZ8+Y YcDJ81Qn =3VPs -----END PGP SIGNATURE----- --e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325-- From debbugs-submit-bounces@debbugs.gnu.org Wed Dec 07 13:28:06 2022 Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 18:28:06 +0000 Received: from localhost ([127.0.0.1]:51530 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2z9K-00086e-Eo for submit@debbugs.gnu.org; Wed, 07 Dec 2022 13:28:06 -0500 Received: from mail-ej1-f67.google.com ([209.85.218.67]:36631) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p2z9H-00086G-AO for 59866@debbugs.gnu.org; Wed, 07 Dec 2022 13:28:05 -0500 Received: by mail-ej1-f67.google.com with SMTP id qk9so16058459ejc.3 for <59866@debbugs.gnu.org>; Wed, 07 Dec 2022 10:28:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=MiTkz2PzmcVWDGiO+0q5zfX3Gt8gcRLJczq/PGlFZjw=; b=YYnJH90wn3wQ+VSKw8rdBFWjoItxC1MI60c+cMJioypE1Lh/66DIYTeY4JY+n6/tBI v30SS6JirGyClf0aJHAtrMNj9k2L0u9yldn+mQJEDGr2dScCtJUpDP3RstTX7gdOVAJD bdMkq5i0BSTX+h3JjXOUCCtWO6mU8dIQpcs/EoOoSE1vn2wyFxYmWpOnG6uTwVyO5wCI rXaUyHLfeRnC0fGKnNafql++s5orfk69Ax+Cga/wQxv2zYCGp5Foyko7wQNQIp9oyoA+ UkA8bLs5GXoWR/PJruOnb5jjy64gbV0eaQvm/R27no81OUHTtH8VWZpr4QLcJGOciery xKmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=MiTkz2PzmcVWDGiO+0q5zfX3Gt8gcRLJczq/PGlFZjw=; b=eVt5ov7PzwBkN1ktnjDFLQDztiX7U2ITqYWizH5BYbj3DF1TVjMCOY4DVbog5hWjIg F7T2V14+iZr/gOMd5Sr7wqnKJ8LZhyB/vbnZhrKwbRgKQfPW64H7WH95LrfZLUQzlyWt alHVNVyqNu2pM5WvLU8p4Mfy9ffS2Jj2c/r1E6C0czJZOf16oJEhTSd6v/w8+4j3z/Kl D7gQuLJCLJ+X+YLQMEcMN+TEqNel8Dtp8BhxVZmuoBGez1BmY2xNgaKz0uR2fsWXWTFX EtV2nHcPOaC9l2Gr9QqMZNV1wr2hNEV9ukjbRGc+owejlcvPbPrOtVaNiEzSS1ug7OLX Re0A== X-Gm-Message-State: ANoB5png6u2BSS0w2trq2pHQKFu96RqkZaRYFeUJH4U2KwpRO8JzXNvi UDxomToCf/qpxE7tAXE3KQM= X-Google-Smtp-Source: AA0mqf6zs7dmneuV5rmwhvwasLsmPRa91F8xlDAQ0jHnJv3OOSDQubCVr+yHhsU97YPbBuQ1NxDvVg== X-Received: by 2002:a17:906:60c4:b0:7a2:36c7:31ea with SMTP id f4-20020a17090660c400b007a236c731eamr62592596ejk.210.1670437677313; Wed, 07 Dec 2022 10:27:57 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id x16-20020a170906135000b007b2a58e31dasm4522552ejb.145.2022.12.07.10.27.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Dec 2022 10:27:56 -0800 (PST) Message-ID: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@gmail.com> Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service From: Liliana Marie Prikler To: mirai@makinata.eu, 59866@debbugs.gnu.org Date: Wed, 07 Dec 2022 19:27:55 +0100 In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Am Dienstag, dem 06.12.2022 um 23:22 +0000 schrieb mirai@makinata.eu: > Modernizes and expands 'mpd-service-type'. > Performs "pretty-formatting" to the generated configuration file > at the cost of a few extra procedures. > It also deprecates some of the fields (abbreviated forms). >=20 > Bruno Victal (2): > =C2=A0 services: mpd: use 'define-configuration'. > =C2=A0 services: mpd: Refactor MPD service. Note that there is [1], which attempts to make it so that shepherd endpoints can be specified in lieu of MPD endpoints. You don't need to implement this logic =E2=80=93 you are free to do so if you want to =E2=80= =93 but could you make it so that there is an explicit endpoint abstraction that would allow for extension later on? Cheers [1] https://issues.guix.gnu.org/54986 From debbugs-submit-bounces@debbugs.gnu.org Wed Dec 07 20:01:47 2022 Received: (at 59866) by debbugs.gnu.org; 8 Dec 2022 01:01:47 +0000 Received: from localhost ([127.0.0.1]:53276 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p35IH-0007h2-Kr for submit@debbugs.gnu.org; Wed, 07 Dec 2022 20:01:47 -0500 Received: from smtpm5.myservices.hosting ([185.26.105.236]:48210) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p35ID-0007gw-Pj for 59866@debbugs.gnu.org; Wed, 07 Dec 2022 20:01:44 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm5.myservices.hosting (Postfix) with ESMTP id A372E20CFC for <59866@debbugs.gnu.org>; Thu, 8 Dec 2022 02:01:39 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 3312F80096; Thu, 8 Dec 2022 02:01:39 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id Z6Nc9jOAjO2M; Thu, 8 Dec 2022 02:01:38 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id D320A80093; Thu, 8 Dec 2022 02:01:37 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v2] services: mpd: Refactor MPD service. Date: Thu, 8 Dec 2022 00:59:57 +0000 Message-Id: <358a67f1493b55505ec5907750722fd43656e4d4.1670461192.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal Introduces 'mpd-plugin' and 'mpd-partition' records. Expands 'mpd-output' and 'mpd-configuration' records. Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids serializing unused fields that may introduce undesired behavior. Implement log-rotation via rottlog. Implements Shepherd actions: 'reload' and 'configuration'. --- Slight oversight, mpd-plugin and mpd-partition record types weren't being exported. doc/guix.texi | 172 ++++++++++++++--- gnu/services/audio.scm | 426 ++++++++++++++++++++++++++++++++--------- 2 files changed, 476 insertions(+), 122 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 50487a5172..5a009df240 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -32823,79 +32824,184 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (type: maybe-string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) +@item @code{port} (default: @code{6600}) (type: maybe-integer) The port to run mpd on. -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{addresses} (type: maybe-list-of-string) +The addresses that mpd will bind to. To use a Unix domain socket, an +absolute path can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". + +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -32907,7 +33013,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 2351db8a4a..07baf8554c 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Peter Mikkelsen ;;; Copyright © 2019 Ricardo Wurmus ;;; Copyright © 2020 Ludovic Courtès +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -20,19 +21,26 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? + mpd-plugin + mpd-plugin? + mpd-partition + mpd-partition? mpd-configuration mpd-configuration? mpd-service-type)) @@ -51,180 +59,406 @@ (define (uglify-field-name field-name) #\-) "_"))) -(define (free-form-args? val) - (match val - (() #t) - ((((? symbol?) . (? string?)) . val) (free-form-args? val)) - (_ #f))) +(define list-of-string? + (list-of string?)) -(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) - #~(begin - (use-modules ((ice-9 format))) - (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) - field-name - (uglify-field-name field-name)) #$value))) +(define list-of-symbol? + (list-of symbol?)) -(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) - (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) +(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (if (boolean? value) (if value "yes" "no") value))) + #~(begin + (use-modules (ice-9 format)) + (format #f "~v/~a \"~a\"~%" #$indent-level #$field #$value)))) (define mpd-serialize-number mpd-serialize-field) (define mpd-serialize-string mpd-serialize-field) -(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) - (mpd-serialize-field field-name (if value "yes" "no") indent-level)) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define* (mpd-serialize-alist field-name value #:optional (indent-level 0)) + #~(string-append #$@(generic-serialize-alist list (cut mpd-serialize-field <> <> indent-level) value))) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) (define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) (define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) (define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) (define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) +(define mpd-subsystem-serialize-alist (cut mpd-serialize-alist <> <> 1)) + +(define-maybe string (prefix mpd-subsystem-)) +(define-maybe boolean (prefix mpd-subsystem-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . addresses))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin (warn-about-deprecation field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning (G_ "string value for '~a' is deprecated, use integer instead~%") field-name)) + (mpd-serialize-field field-name value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-subsystem-)) + +;; Translate field name into block name for mpd.conf" +(define mpd-subsystem-name + (match-lambda + ('archive-plugins "archive_plugin") + ('playlist-plugins "playlist_plugin") + ('inputs "input") + ('decoders "decoder") + ('filters "filter") + (x (symbol->string x)))) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(string-append "\n" #$(mpd-subsystem-name field-name) " {\n" + #$(serialize-configuration value mpd-plugin-fields) + "}\n")) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) value))) + +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-subsystem-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(string-append "\npartition {\n" + #$(serialize-configuration value mpd-partition-fields) + "}\n")) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name (string "MPD") "The name of the audio output.") + (type (string "pulse") "The type of audio output.") + (enabled? (boolean #t) "Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin.") + (always-on? (boolean #f) "If set to @code{#t}, then MPD attempts to keep this audio output always open. This may be useful for streaming servers, when you don’t want to disconnect all listeners even when playback is accidentally stopped.") + (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} is +to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options - (free-form-args '()) - "An association list of option symbols to string values to be appended to + (alist '()) + "An association list of option symbols/strings to string values to be appended to the audio output configuration.") + (prefix mpd-subsystem-)) +(define (mpd-serialize-mpd-output field-name value) + #~(string-append "\naudio_output {\n" + #$(serialize-configuration value mpd-output-fields) + "}\n")) + +(define (mpd-serialize-list-of-mpd-output field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-output #f <>) value))) + (define list-of-mpd-output? (list-of mpd-output?)) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + + (group + maybe-string + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the local syslog daemon or +@code{%unset-value} to omit this directive from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. Available values: @code{notice}, +@code{info}, @code{verbose}, @code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) - (playlist-dir - (string "~/.mpd/playlists") + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") + + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) + (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") + (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") + (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") + (port - (string "6600") + (maybe-port 6600) ; TODO: switch to integer "The port to run mpd on.") - (address - (string "any") + + (addresses + maybe-list-of-string + "The addresses that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations.") + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations.") + + (input-cache-size + maybe-string + "MPD input cache size." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-subsystem-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations.") + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations.") + (outputs (list-of-mpd-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reload) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) + (match-record config (user package shepherd-requirement) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reload) + (documentation "Reopen log files and flush caches.") + (procedure #~(lambda (pid) + (if pid + (begin (kill pid SIGHUP) + (format #t "Issued SIGHUP to Service MPD (PID ~a)." pid)) + (format #t "Service MPD is not running."))))))))))) (define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) + (match-record config (user log-file) #~(begin (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") + (let* ((user (getpw #$user)) + (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd")) + (new-directory (string-append (passwd:dir user) "/.config/mpd"))) + ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd. + (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory))) + (rename-file deprecated-directory new-directory) + (chown new-directory (passwd:uid user) (passwd:gid user))) + (mkdir-p (dirname #$log-file)))))) - (shell (file-append shadow "/sbin/nologin"))))) +(define (mpd-accounts config) + (match-record config (user) + (list (user-account + (name user) + (group "nogroup") + (system? #t) + (comment "Music Player Daemon (MPD) user") + (home-directory "/var/lib/mpd") ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -234,7 +468,9 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) + mpd-accounts) (service-extension activation-service-type - mpd-service-activation))) + mpd-service-activation) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) base-commit: 81191e3410cc00c6438f532599dd0b96d521982f prerequisite-patch-id: 3b756bb4d930897ce79b1e51cc25478cb73fd9d8 -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Thu Dec 08 08:11:37 2022 Received: (at 59866) by debbugs.gnu.org; 8 Dec 2022 13:11:37 +0000 Received: from localhost ([127.0.0.1]:56704 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3Ggb-0002o5-B5 for submit@debbugs.gnu.org; Thu, 08 Dec 2022 08:11:37 -0500 Received: from smtpmciv4.myservices.hosting ([185.26.107.240]:48080) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3GgZ-0002nu-9L; Thu, 08 Dec 2022 08:11:35 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpmciv4.myservices.hosting (Postfix) with ESMTP id A58AF20775; Thu, 8 Dec 2022 14:11:33 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 65C0E80096; Thu, 8 Dec 2022 14:11:33 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id Qm4M4if-MSeb; Thu, 8 Dec 2022 14:11:29 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 9CFC980093; Thu, 8 Dec 2022 14:11:29 +0100 (CET) Message-ID: <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@makinata.eu> Date: Thu, 8 Dec 2022 13:11:29 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.5.1 From: mirai Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service To: Liliana Marie Prikler , 59866@debbugs.gnu.org References: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@gmail.com> Content-Language: en-US In-Reply-To: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@gmail.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: 54986@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) On 2022-12-07 18:27, Liliana Marie Prikler wrote: > Note that there is [1], which attempts to make it so that shepherd > endpoints can be specified in lieu of MPD endpoints. You don't need to > implement this logic – you are free to do so if you want to – but could > you make it so that there is an explicit endpoint abstraction that > would allow for extension later on? > > Cheers > > [1] https://issues.guix.gnu.org/54986 Hi, After reading issue #54986, regarding mpd escaping shepherd management, my guess is that there could be two issues at play here: * mpd.conf was serialized with pid_file [1]. The safest is to actually not serialize any unused directives and let MPD decide based on what's actually present. pid_file should only be set if MPD is to be launched as a "daemon process". [2] * But the service definition for MPD is launched with '--no-daemon' option as seen in [3], which could be triggering a bug in MPD. It's probably worth testing the combinations of having pid_file set and invoking --no-daemon. > but could > you make it so that there is an explicit endpoint abstraction that > would allow for extension later on? If I'm understanding correctly what [1] is about, I think this can be implemented through the 'extend' interface. See how certbot adds a nginx-server-configuration to a nginx-service-type through the 'extend' interface. For MPD, this would amount to appending the 'adresses' field with "adequately formatted" values. [1]: https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/services/audio.scm?id=1b6172d5f6ca22f0fa02cd1335b1b90e9501b731#n116 [2]: https://mpd.readthedocs.io/en/latest/user.html#starting-and-stopping-mpd [3]: https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/services/audio.scm?id=1b6172d5f6ca22f0fa02cd1335b1b90e9501b731#n145 From debbugs-submit-bounces@debbugs.gnu.org Thu Dec 08 08:36:06 2022 Received: (at 59866) by debbugs.gnu.org; 8 Dec 2022 13:36:06 +0000 Received: from localhost ([127.0.0.1]:56811 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3H4I-00033K-7p for submit@debbugs.gnu.org; Thu, 08 Dec 2022 08:36:06 -0500 Received: from mail-ej1-f66.google.com ([209.85.218.66]:40764) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3H4G-00032r-32; Thu, 08 Dec 2022 08:36:04 -0500 Received: by mail-ej1-f66.google.com with SMTP id b2so3910445eja.7; Thu, 08 Dec 2022 05:36:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject :date:message-id:reply-to; bh=NLSGOOf2eRBAwiYW6X8+LYnqDTQCwpP7U+hL/+ZUHVQ=; b=nigV6vxdvqjvSTOBVGJyMbgXrlmDMcah6CMYU/lv5MW5wZT+kBSuknsHSss1CdDjUY 6wRpQtaQI5omo1xhgw+PKP1ob4YB4ZTGDInr8WeZSdG3Sii2Ah5VpzXwFCMkwmAmf1eN wRpFNNDLkR2jJ88h6EDYxYEM4wF3ouMvrVW70uZcAEsVdtfkgGLA3jnb3BLuNy8ATVWr tdamTH7ktq2IB1x82EsiLpWkEFerMn+tz0d1Vlsnz5aYHp7d35h+xI2AH5radpNkbYYi B3OlfNb4nhb9OhgbTSKFi+W4ssNJuCh1TqfOjI9l5CUUDffwiE4PrpQJMoism9pG/wG9 mHug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=NLSGOOf2eRBAwiYW6X8+LYnqDTQCwpP7U+hL/+ZUHVQ=; b=eWuofNeZrctnoL2UbNalrbcOaQ3WKlwJwIY8Ne6bh32NymI6g0h2Hd6jnLoJsChZIh eLOPCADI+aggBnVFyzP/so3Mx8JStyqkKK8cs0t4fvQVxiap+DIAc+czT3ai3iHNgiTE irUqN7KS3tCCJm4XZ6+Jkru2rRI//qeEMa8xGR4UxDq0rjPCcDaNWyxukO35wPtKZT27 KDlSAB8QeJ59NAFPBUnh7SELHFRKCN2/86DrRyXEAVCazAIphJylpfCYGUy/i2tHvBFP XH5bGpnTIjU2mKRKc3REXK8cFZ2e0TL+lwaJOhdJqV35VqFeGtg8wcjx68UrsUsgD0bs Sqag== X-Gm-Message-State: ANoB5pkQ2329GieiWpoRajUiVj0L2JUQEqOBszVd7KluM5r9VrzGSebw 8xwox0JAldLPqifJnBjHrZI= X-Google-Smtp-Source: AA0mqf5Ln50FtyONi6KSjrGOB+MJbHvtPfzUlpfihVKWxpPlvU/LquS4omNId7i5rnq+03w5Lt3aQQ== X-Received: by 2002:aa7:cd02:0:b0:46c:9536:8598 with SMTP id b2-20020aa7cd02000000b0046c95368598mr15835083edw.123.1670506557965; Thu, 08 Dec 2022 05:35:57 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id i26-20020aa7dd1a000000b0045c47b2a800sm3358568edv.67.2022.12.08.05.35.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 05:35:57 -0800 (PST) Message-ID: Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service From: Liliana Marie Prikler To: mirai , 59866@debbugs.gnu.org Date: Thu, 08 Dec 2022 14:35:55 +0100 In-Reply-To: <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@makinata.eu> References: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@gmail.com> <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@makinata.eu> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: 54986@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Am Donnerstag, dem 08.12.2022 um 13:11 +0000 schrieb mirai: > On 2022-12-07 18:27, Liliana Marie Prikler wrote: > > Note that there is [1], which attempts to make it so that shepherd > > endpoints can be specified in lieu of MPD endpoints.=C2=A0 You don't > > need to implement this logic =E2=80=93 you are free to do so if you wan= t to > > =E2=80=93 but could you make it so that there is an explicit endpoint > > abstraction that would allow for extension later on? > >=20 > > Cheers > >=20 > > [1] https://issues.guix.gnu.org/54986 >=20 > Hi, >=20 > After reading issue #54986, regarding mpd escaping shepherd > management, my guess is that there could be two issues at play here: >=20 > * mpd.conf was serialized with pid_file [1]. The safest is > to actually not serialize any unused directives and let MPD decide > based on what's actually present. pid_file should only be set if > MPD is to be launched as a "daemon process". [2] >=20 > * But the service definition for MPD is launched with '--no-daemon' > option as seen in [3], which could be triggering a bug in MPD. It's > probably worth testing the combinations of having pid_file set and > invoking --no-daemon. Nice catch, but completely unrelated to the issue. In neither case do we ever spawn MPD as a regular daemon, yet only in the systemd case does shepherd have a problem with it. That statement was concerning shepherd's (mis)management of sockets, not MPD. > > but could you make it so that there is an explicit endpoint > > abstraction that would allow for extension later on? >=20 > If I'm understanding correctly what [1] is about, I think this can be > implemented through the 'extend' interface. See how certbot adds a > nginx-server-configuration to a nginx-service-type through the > 'extend' interface. For MPD, this would amount to appending the > 'adresses' field with "adequately formatted" values. This doesn't work for #54986, which makes it so that in-file addresses are ignored in favour of handing over the sockets directly through shepherd. Looking at [4], it appears the meaning of "port" is closer to that of a default port, as addresses can have ports in them. But I would still prefer addresses to be "endpoints", which if they happen to be a list of strings are taken as MPD addresses and if they happen to be shepherd endpoints are passed on to the shepherd service. WDYT? [4] https://mpd.readthedocs.io/en/stable/user.html#client-connections From debbugs-submit-bounces@debbugs.gnu.org Fri Dec 09 08:45:05 2022 Received: (at 59866) by debbugs.gnu.org; 9 Dec 2022 13:45:06 +0000 Received: from localhost ([127.0.0.1]:36197 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3dgX-00024L-KZ for submit@debbugs.gnu.org; Fri, 09 Dec 2022 08:45:05 -0500 Received: from smtpmciv5.myservices.hosting ([185.26.107.241]:50898) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3dgV-00023u-DU; Fri, 09 Dec 2022 08:45:03 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpmciv5.myservices.hosting (Postfix) with ESMTP id E947520BE5; Fri, 9 Dec 2022 14:45:00 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 865A080098; Fri, 9 Dec 2022 14:45:00 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id qmuGHNF6oe9n; Fri, 9 Dec 2022 14:45:00 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id DD71480093; Fri, 9 Dec 2022 14:44:59 +0100 (CET) Message-ID: Date: Fri, 9 Dec 2022 13:44:58 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.5.1 Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service Content-Language: en-US To: Liliana Marie Prikler , 59866@debbugs.gnu.org References: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@gmail.com> <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@makinata.eu> From: mirai In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: 54986@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) On 2022-12-08 13:35, Liliana Marie Prikler wrote: > This doesn't work for #54986, which makes it so that in-file addresses > are ignored in favour of handing over the sockets directly through > shepherd. Looking at [4], it appears the meaning of "port" is closer > to that of a default port, as addresses can have ports in them. But I > would still prefer addresses to be "endpoints", which if they happen to > be a list of strings are taken as MPD addresses and if they happen to > be shepherd endpoints are passed on to the shepherd service. Are you proposing for the 'addresses' field to be a "maybe-list-of-string-or-shepherd-endpoint"? (more of a xor as they can't be used simultaneously) Example: --8<---------------cut here---------------start------------->8--- ;; should fire a error message during guix system reconfigure (mpd-configuration (addresses `("[::]:6645" ,(shepherd-endpoint (address "/var/run/mpd-shepherd-socket"))))) --8<---------------cut here---------------end--------------->8--- I don't think it breaks backward compatibility to introduce this after #59866 is merged. The type of field 'addresses' could be changed transparently to something like: --8<---------------cut here---------------start------------->8--- (define list-of-addresses (list-of (lambda (x) (or (string? x) (shepherd-endpoint? x))))) --8<---------------cut here---------------end--------------->8--- From debbugs-submit-bounces@debbugs.gnu.org Fri Dec 09 08:52:38 2022 Received: (at control) by debbugs.gnu.org; 9 Dec 2022 13:52:39 +0000 Received: from localhost ([127.0.0.1]:36230 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3dnq-0002GY-Gy for submit@debbugs.gnu.org; Fri, 09 Dec 2022 08:52:38 -0500 Received: from smtpm1.myservices.hosting ([185.26.105.232]:50696) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3dno-0002GM-CP for control@debbugs.gnu.org; Fri, 09 Dec 2022 08:52:36 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm1.myservices.hosting (Postfix) with ESMTP id 220EB20021 for ; Fri, 9 Dec 2022 14:52:33 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id D84DF80098 for ; Fri, 9 Dec 2022 14:52:33 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id i1AbGH-EipVh for ; Fri, 9 Dec 2022 14:52:33 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 9837F80093 for ; Fri, 9 Dec 2022 14:52:33 +0100 (CET) Message-ID: Date: Fri, 9 Dec 2022 13:52:33 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.5.1 Content-Language: en-US To: control From: mirai Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Score: 2.0 (++) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: # mpd-output represents a MPD plugin, so mpd-plugin type should also be accepted as a valid alternative to outputs field. # "Pretty-formatting" could be removed to reduce redundant code # Shepherd end [...] Content analysis details: (2.0 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 1.8 MISSING_SUBJECT Missing Subject: header 0.2 NO_SUBJECT Extra score for no subject X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 1.0 (+) # mpd-output represents a MPD plugin, so mpd-plugin type should also be accepted as a valid alternative to outputs field. # "Pretty-formatting" could be removed to reduce redundant code # Shepherd endpoints? retitle 59866 [WIP] [PATCH 0/2] services: mpd: Refactor MPD service quit From debbugs-submit-bounces@debbugs.gnu.org Fri Dec 09 14:22:16 2022 Received: (at 59866) by debbugs.gnu.org; 9 Dec 2022 19:22:16 +0000 Received: from localhost ([127.0.0.1]:37956 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3iwq-0002AX-Dw for submit@debbugs.gnu.org; Fri, 09 Dec 2022 14:22:16 -0500 Received: from mail-ed1-f66.google.com ([209.85.208.66]:43878) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p3iwo-0002AO-Lm; Fri, 09 Dec 2022 14:22:15 -0500 Received: by mail-ed1-f66.google.com with SMTP id r26so4406588edc.10; Fri, 09 Dec 2022 11:22:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject :date:message-id:reply-to; bh=UYDUuFv+QX94mxBglSp5PdFi+xLnIehulY1Kn2d4rPk=; b=KppNnK2Rwihk1crComLMhSa8UPjEjnxOrvoFpi9/o6czta1sVPgUzpeos/35nSDCli pHmpQxgC3fd/QWJxESu2bTxM2rPy6eBrP5e9IsjCkB+GYlw6bVeBdVEOCMD2B8WaF18/ jB9cjqwR4o3gNlfe9AH7uHDSqvH+QvBr6scud+GRCkt3+M8inETA2HIJbt/v3OnS/AET nQ7rTO4jWaha3P4ClWdk77xoPEeiwYJbxLAGtGpaaQAIrYgJ62kiFPYNHyYhkCM/tPIo 0e+WrAwC55phwpk0IVJeB8tOHg5wDUu1wPx1pIENEbg4PkP/WJCtnstPFkG4JI6M2q5q wunw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=UYDUuFv+QX94mxBglSp5PdFi+xLnIehulY1Kn2d4rPk=; b=j168HP51cwZcv5/eUpyBea305ud492017v4GSqRRy/w52QcHKlkf5IsuB0HtB9QNBg cWcyT0ii4eHU3o+Rl5R4Ffg6b56I0S+cRcsodJu08AEGiloWE7X2zE7LtgACpxhRJtHB puVyjUh8zF/PyUCgrWCcx3Q2smyzxRxsoQmXQJVQU3eLW+Cv8xM13IXwEZpI6IJzNvt7 OsFGaIfsY1S9m0qjz13B/HUzTQ4RDfiqTcgM6pEvJRcDjBC/NH3RhjTcORxLNif18rpD E9dD26QDvSD8k4eBXofFRM81x1qPGkTZOyl7wL5H1yRqZjQAirhMVdPscz000jPeFNzQ vjEQ== X-Gm-Message-State: ANoB5pk8jEFIDGwmewfrj/1vNjLkulrFmz2T9ugeJzA8YoaPV9aqtVnH 1Cspbbns33f2lkn9cbgW/oofCbE+hrs= X-Google-Smtp-Source: AA0mqf6QXuoUzjKeH5AwW76lueHl196u1Gr0R1HUOqdnAauMuHb10TlDjd+gON94I5xhAyStTRZ0cw== X-Received: by 2002:a05:6402:1047:b0:45c:835b:ac4d with SMTP id e7-20020a056402104700b0045c835bac4dmr5736202edu.8.1670613728618; Fri, 09 Dec 2022 11:22:08 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id m6-20020a056402050600b0046c5baa1f58sm952676edv.97.2022.12.09.11.22.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Dec 2022 11:22:08 -0800 (PST) Message-ID: <4e6249e0970fcd02ac4666ce1fd40203b4b09003.camel@gmail.com> Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service From: Liliana Marie Prikler To: mirai , 59866@debbugs.gnu.org Date: Fri, 09 Dec 2022 20:22:06 +0100 In-Reply-To: References: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@gmail.com> <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@makinata.eu> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: 54986@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Am Freitag, dem 09.12.2022 um 13:44 +0000 schrieb mirai: > On 2022-12-08 13:35, Liliana Marie Prikler wrote: > > This doesn't work for #54986, which makes it so that in-file > > addresses are ignored in favour of handing over the sockets > > directly through shepherd.=C2=A0 Looking at [4], it appears the meaning > > of "port" is closer to that of a default port, as addresses can > > have ports in them.=C2=A0 > > But I would still prefer addresses to be "endpoints", which if they > > happen to be a list of strings are taken as MPD addresses and if > > they happen to be shepherd endpoints are passed on to the shepherd > > service. >=20 > Are you proposing for the 'addresses' field to be a > "maybe-list-of-string-or-shepherd-endpoint"? (more of a xor as they > can't be used simultaneously) > Example: >=20 > --8<---------------cut here---------------start------------->8--- > ;; should fire a error message during guix system reconfigure > (mpd-configuration > =C2=A0 (addresses `("[::]:6645"=C2=A0=20 > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 ,(shepherd-endpoint > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (address "/var/run/mpd-shepherd-socket"))))) > --8<---------------cut here---------------end--------------->8--- >=20 > I don't think it breaks backward compatibility to introduce this > after #59866 is merged. > The type of field 'addresses' could be changed transparently to > something like: >=20 > --8<---------------cut here---------------start------------->8--- > (define list-of-addresses (list-of (lambda (x) (or (string? x) > (shepherd-endpoint? x))))) > --8<---------------cut here---------------end--------------->8--- Something like that, but I don't think the vocabulary matches 1:1. In my opinion, an address is an endpoint =E2=80=93 not a shepherd endpoint, bu= t an endpoint still =E2=80=93 while a shepherd endpoint is not an address. Thus= , I propose changing the vocabulary now to not break backwards compatibility later. IIUC, the change from the previous records to define-configuration is already an API change, so it'd be good to have both in the same series. Cheers From debbugs-submit-bounces@debbugs.gnu.org Sun Dec 11 07:05:47 2022 Received: (at 59866) by debbugs.gnu.org; 11 Dec 2022 12:05:47 +0000 Received: from localhost ([127.0.0.1]:46358 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p4L5X-0001GD-An for submit@debbugs.gnu.org; Sun, 11 Dec 2022 07:05:47 -0500 Received: from smtpm3.myservices.hosting ([185.26.105.234]:57936) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p4L5V-0001G1-9v; Sun, 11 Dec 2022 07:05:45 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm3.myservices.hosting (Postfix) with ESMTP id 5FEC420CD0; Sun, 11 Dec 2022 13:05:40 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 1BAA480097; Sun, 11 Dec 2022 13:05:40 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 7i8Dm-61ekDB; Sun, 11 Dec 2022 13:05:39 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id A48E680093; Sun, 11 Dec 2022 13:05:39 +0100 (CET) Message-ID: Date: Sun, 11 Dec 2022 12:05:38 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.5.1 Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service Content-Language: en-US To: Liliana Marie Prikler , 59866@debbugs.gnu.org References: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@gmail.com> <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@makinata.eu> <4e6249e0970fcd02ac4666ce1fd40203b4b09003.camel@gmail.com> From: mirai In-Reply-To: <4e6249e0970fcd02ac4666ce1fd40203b4b09003.camel@gmail.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: 54986@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) On 2022-12-09 19:22, Liliana Marie Prikler wrote: > Something like that, but I don't think the vocabulary matches 1:1. In > my opinion, an address is an endpoint – not a shepherd endpoint, but an > endpoint still – while a shepherd endpoint is not an address. Thus, I > propose changing the vocabulary now to not break backwards > compatibility later. You prefer the 'addresses' field to be renamed to 'endpoints', is that correct? IIUC, the change from the previous records to > define-configuration is already an API change, so it'd be good to have > both in the same series. The first patch in the series changes from define-record-type* to define-configuration but it does not add anything, I don't think there are actually any (exported) API changes visible to the user. Only the second patch starts to introduce visible API changes. Cheers From debbugs-submit-bounces@debbugs.gnu.org Fri Dec 16 09:25:12 2022 Received: (at 59866) by debbugs.gnu.org; 16 Dec 2022 14:25:12 +0000 Received: from localhost ([127.0.0.1]:49644 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p6BeA-0006Cu-K4 for submit@debbugs.gnu.org; Fri, 16 Dec 2022 09:25:12 -0500 Received: from smtpm2.myservices.hosting ([185.26.105.233]:36820) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p6Be5-0006Cm-Md for 59866@debbugs.gnu.org; Fri, 16 Dec 2022 09:25:09 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm2.myservices.hosting (Postfix) with ESMTP id 320A320D8E for <59866@debbugs.gnu.org>; Fri, 16 Dec 2022 15:25:03 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id D699A8009B; Fri, 16 Dec 2022 15:25:03 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id huDVcoAZ3AiS; Fri, 16 Dec 2022 15:25:01 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 808CF8009A; Fri, 16 Dec 2022 15:25:00 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v3] services: mpd: Refactor MPD service. Date: Fri, 16 Dec 2022 14:15:16 +0000 Message-Id: X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal Introduces 'mpd-plugin' and 'mpd-partition' records. Expands 'mpd-output' and 'mpd-configuration' records. Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids serializing unused fields that may introduce undesired behavior. Implement log-rotation via rottlog. Implements Shepherd actions: 'reopen' and 'configuration'. --- Changes from v2 to v3: * Removed "pretty-formatting" code to reduce overall code "weight". * Renamed shepherd action 'reload' to 'reopen' as reloading would suggest that it re-reads the config file. * Renamed 'addresses' field to 'endpoints'. * Allow mpd-plugin records to be used in 'outputs' field. Technically an audio output is a mpd-plugin but since there are numerous common audio output specific options it's worthwhile having a mpd-output record-type for it. * mpd-plugin serialization was simplified and the "subsystem block name" was integrated directly into mpd-configuration record-type to better track which field corresponds to which subsystem rather than keep an external dictionary that maps the fields to the subsystem names. doc/guix.texi | 172 +++++++++++++--- gnu/services/audio.scm | 434 +++++++++++++++++++++++++++++++---------- 2 files changed, 476 insertions(+), 130 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 5cb5ae1dfe..3f186aefa9 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -33007,79 +33008,184 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (type: maybe-string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) +@item @code{port} (default: @code{6600}) (type: maybe-integer) The port to run mpd on. -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{endpoints} (type: maybe-list-of-string) +The addresses that mpd will bind to. To use a Unix domain socket, an +absolute path can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". + +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-plugin-or-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -33091,7 +33197,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 2351db8a4a..aeb081380a 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Peter Mikkelsen ;;; Copyright © 2019 Ricardo Wurmus ;;; Copyright © 2020 Ludovic Courtès +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -20,19 +21,27 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-8) #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? + mpd-plugin + mpd-plugin? + mpd-partition + mpd-partition? mpd-configuration mpd-configuration? mpd-service-type)) @@ -51,180 +60,397 @@ (define (uglify-field-name field-name) #\-) "_"))) -(define (free-form-args? val) - (match val - (() #t) - ((((? symbol?) . (? string?)) . val) (free-form-args? val)) - (_ #f))) +(define list-of-string? + (list-of string?)) -(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) - #~(begin - (use-modules ((ice-9 format))) - (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) - field-name - (uglify-field-name field-name)) #$value))) +(define list-of-symbol? + (list-of symbol?)) -(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) - (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) +(define (mpd-serialize-field field-name value) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (if (boolean? value) (if value "yes" "no") value))) + #~(format #f "~a \"~a\"~%" #$field #$value))) (define mpd-serialize-number mpd-serialize-field) (define mpd-serialize-string mpd-serialize-field) -(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) - (mpd-serialize-field field-name (if value "yes" "no") indent-level)) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define* (mpd-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list mpd-serialize-field value))) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) +(define-maybe boolean (prefix mpd-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . addresses))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin (warn-about-deprecation field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning (G_ "string value for '~a' is deprecated, use integer instead~%") field-name)) + (mpd-serialize-field field-name value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(format #f "~a {~%~a}~%" + '#$field-name #$(serialize-configuration value mpd-plugin-fields))) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) value))) -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(format #f "partition {~%~a}~%" + #$(serialize-configuration value mpd-partition-fields))) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name (string "MPD") "The name of the audio output.") + (type (string "pulse") "The type of audio output.") + (enabled? (boolean #t) "Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin.") + (always-on? (boolean #f) "If set to @code{#t}, then MPD attempts to keep this audio output always open. This may be useful for streaming servers, when you don’t want to disconnect all listeners even when playback is accidentally stopped.") + (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} is +to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options - (free-form-args '()) - "An association list of option symbols to string values to be appended to + (alist '()) + "An association list of option symbols/strings to string values to be appended to the audio output configuration.") - (prefix mpd-subsystem-)) -(define list-of-mpd-output? - (list-of mpd-output?)) + (prefix mpd-)) + +(define (mpd-serialize-mpd-output field-name value) + #~(format #f "audio_output {~%~a}~%" + #$(serialize-configuration value mpd-output-fields))) + +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value) + (receive (plugins outputs) + (partition mpd-plugin? value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>) plugins) + #$@(map (cut mpd-serialize-mpd-output #f <>) outputs)))) + +(define list-of-mpd-plugin-or-output? + (list-of (lambda (x) + (or (mpd-output? x) (mpd-plugin? x))))) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + + (group + maybe-string + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the local syslog daemon or +@code{%unset-value} to omit this directive from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. Available values: @code{notice}, +@code{info}, @code{verbose}, @code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) - (playlist-dir - (string "~/.mpd/playlists") + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") + + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) + (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") + (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") + (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") + (port - (string "6600") + (maybe-port 6600) ; TODO: switch to integer "The port to run mpd on.") - (address - (string "any") + + (endpoints + maybe-list-of-string + "The addresses that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "input" x))) + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (mpd-serialize-list-of-mpd-plugin "archive_plugin" x))) + + (input-cache-size + maybe-string + "MPD input cache size." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "decoder" x))) + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "filter" x))) + (outputs - (list-of-mpd-output (list (mpd-output))) + (list-of-mpd-plugin-or-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "playlist_plugin" x))) + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reopen) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) + (match-record config (user package shepherd-requirement) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reopen) + (documentation "Re-open log files and flush caches.") + (procedure #~(lambda (pid) + (if pid + (begin (kill pid SIGHUP) + (format #t "Issued SIGHUP to Service MPD (PID ~a)." pid)) + (format #t "Service MPD is not running."))))))))))) (define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) + (match-record config (user log-file) #~(begin (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") + (let* ((user (getpw #$user)) + (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd")) + (new-directory (string-append (passwd:dir user) "/.config/mpd"))) + ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd. + (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory))) + (rename-file deprecated-directory new-directory) + (chown new-directory (passwd:uid user) (passwd:gid user))) + (mkdir-p (dirname #$log-file)))))) - (shell (file-append shadow "/sbin/nologin"))))) +(define (mpd-accounts config) + (match-record config (user) + (list (user-account + (name user) + (group "nogroup") + (system? #t) + (comment "Music Player Daemon (MPD) user") + (home-directory "/var/lib/mpd") ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -234,7 +460,9 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) + mpd-accounts) (service-extension activation-service-type - mpd-service-activation))) + mpd-service-activation) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) base-commit: 7ce9b7e7062eee406e269bc40a20247973732be2 prerequisite-patch-id: 3b756bb4d930897ce79b1e51cc25478cb73fd9d8 -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Wed Dec 21 09:15:51 2022 Received: (at 59866) by debbugs.gnu.org; 21 Dec 2022 14:15:51 +0000 Received: from localhost ([127.0.0.1]:52142 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p7zss-0006YO-Gf for submit@debbugs.gnu.org; Wed, 21 Dec 2022 09:15:51 -0500 Received: from smtpm2.myservices.hosting ([185.26.105.233]:55018) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p7zsp-0006YI-OX for 59866@debbugs.gnu.org; Wed, 21 Dec 2022 09:15:48 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm2.myservices.hosting (Postfix) with ESMTP id A7D8520DF1 for <59866@debbugs.gnu.org>; Wed, 21 Dec 2022 15:15:46 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 4CC558009A; Wed, 21 Dec 2022 15:15:46 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 3VLzJ0EnXfa2; Wed, 21 Dec 2022 15:15:45 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id F3F3380099; Wed, 21 Dec 2022 15:15:42 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v4 1/2] services: mpd: use 'define-configuration'. Date: Wed, 21 Dec 2022 14:15:12 +0000 Message-Id: <248f6adc7d434e3d8df791311744a38e0d965744.1671632111.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal --- gnu/services/audio.scm | 217 ++++++++++++++++++++++++----------------- 1 file changed, 129 insertions(+), 88 deletions(-) diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index c60053f33c..2351db8a4a 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -21,6 +21,7 @@ (define-module (gnu services audio) #:use-module (guix gexp) #:use-module (gnu services) + #:use-module (gnu services configuration) #:use-module (gnu services shepherd) #:use-module (gnu system shadow) #:use-module (gnu packages admin) @@ -28,6 +29,8 @@ (define-module (gnu services audio) #:use-module (guix records) #:use-module (ice-9 match) #:use-module (ice-9 format) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? mpd-configuration @@ -40,93 +43,131 @@ (define-module (gnu services audio) ;;; ;;; Code: -(define-record-type* - mpd-output make-mpd-output - mpd-output? - (type mpd-output-type - (default "pulse")) - (name mpd-output-name - (default "MPD")) - (enabled? mpd-output-enabled? - (default #t)) - (tags? mpd-output-tags? - (default #t)) - (always-on? mpd-output-always-on? - (default #f)) - (mixer-type mpd-output-mixer-type - ;; valid: hardware, software, null, none - (default #f)) - (extra-options mpd-output-extra-options - (default '()))) - -(define-record-type* - mpd-configuration make-mpd-configuration - mpd-configuration? - (user mpd-configuration-user - (default "mpd")) - (music-dir mpd-configuration-music-dir - (default "~/Music")) - (playlist-dir mpd-configuration-playlist-dir - (default "~/.mpd/playlists")) - (db-file mpd-configuration-db-file - (default "~/.mpd/tag_cache")) - (state-file mpd-configuration-state-file - (default "~/.mpd/state")) - (sticker-file mpd-configuration-sticker-file - (default "~/.mpd/sticker.sql")) - (port mpd-configuration-port - (default "6600")) - (address mpd-configuration-address - (default "any")) - (outputs mpd-configuration-outputs - (default (list (mpd-output))))) - -(define (mpd-output->string output) - "Convert the OUTPUT of type to a configuration file snippet." - (let ((extra (string-join - (map (match-lambda - ((key . value) - (format #f " ~a \"~a\"" - (string-map - (lambda (c) (if (char=? c #\-) #\_ c)) - (symbol->string key)) - value))) - (mpd-output-extra-options output)) - "\n"))) - (format #f "\ -audio_output { - type \"~a\" - name \"~a\" -~:[ enabled \"no\"~%~;~]\ -~:[ tags \"no\"~%~;~]\ -~:[~; always_on \"yes\"~%~]\ -~@[ mixer_type \"~a\"~%~]\ -~a~%}~%" - (mpd-output-type output) - (mpd-output-name output) - (mpd-output-enabled? output) - (mpd-output-tags? output) - (mpd-output-always-on? output) - (mpd-output-mixer-type output) - extra))) - -(define (mpd-config->file config) - (apply - mixed-text-file "mpd.conf" - "pid_file \"" (mpd-file-name config "pid") "\"\n" - (append (map mpd-output->string - (mpd-configuration-outputs config)) - (map (match-lambda - ((config-name config-val) - (string-append config-name " \"" (config-val config) "\"\n"))) - `(("user" ,mpd-configuration-user) - ("music_directory" ,mpd-configuration-music-dir) - ("playlist_directory" ,mpd-configuration-playlist-dir) - ("db_file" ,mpd-configuration-db-file) - ("state_file" ,mpd-configuration-state-file) - ("sticker_file" ,mpd-configuration-sticker-file) - ("port" ,mpd-configuration-port) - ("bind_to_address" ,mpd-configuration-address)))))) +(define (uglify-field-name field-name) + (let ((str (symbol->string field-name))) + (string-join (string-split (if (string-suffix? "?" str) + (string-drop-right str 1) + str) + #\-) + "_"))) + +(define (free-form-args? val) + (match val + (() #t) + ((((? symbol?) . (? string?)) . val) (free-form-args? val)) + (_ #f))) + +(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) + #~(begin + (use-modules ((ice-9 format))) + (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) + field-name + (uglify-field-name field-name)) #$value))) + +(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) + (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) + +(define mpd-serialize-number mpd-serialize-field) + +(define mpd-serialize-string mpd-serialize-field) + +(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) + (mpd-serialize-field field-name (if value "yes" "no") indent-level)) + +(define (mpd-serialize-list-of-mpd-output field-name value) + #~(string-append "\naudio_output {\n" + #$@(map (cut serialize-configuration <> + mpd-output-fields) + value) + "}\n")) + +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) +(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) +(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) +(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) +(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) + +(define-configuration mpd-output + (name + (string "MPD") + "The name of the audio output.") + (type + (string "pulse") + "The type of audio output.") + (enabled? + (boolean #t) + "Specifies whether this audio output is enabled when MPD is started. By +default, all audio outputs are enabled. This is just the default +setting when there is no state file; with a state file, the previous +state is restored.") + (tags? + (boolean #t) + "If set to @code{#f}, then MPD will not send tags to this output. This +is only useful for output plugins that can receive tags, for example the +@code{httpd} output plugin.") + (always-on? + (boolean #f) + "If set to @code{#t}, then MPD attempts to keep this audio output always +open. This may be useful for streaming servers, when you don’t want to +disconnect all listeners even when playback is accidentally stopped.") + (mixer-type + (string "none") + "This field accepts a symbol that specifies which mixer should be used +for this audio output: the @code{hardware} mixer, the @code{software} +mixer, the @code{null} mixer (allows setting the volume, but with no +effect; this can be used as a trick to implement an external mixer +External Mixer) or no mixer (@code{none}).") + (extra-options + (free-form-args '()) + "An association list of option symbols to string values to be appended to +the audio output configuration.") + (prefix mpd-subsystem-)) + +(define list-of-mpd-output? + (list-of mpd-output?)) + +(define-configuration mpd-configuration + (user + (string "mpd") + "The user to run mpd as.") + (music-dir + (string "~/Music") + "The directory to scan for music files." + (lambda (_ x) + (mpd-serialize-field "music_directory" x))) + (playlist-dir + (string "~/.mpd/playlists") + "The directory to store playlists." + (lambda (_ x) + (mpd-serialize-field "playlist_directory" x))) + (db-file + (string "~/.mpd/tag_cache") + "The location of the music database.") + (state-file + (string "~/.mpd/state") + "The location of the file that stores current MPD's state.") + (sticker-file + (string "~/.mpd/sticker.sql") + "The location of the sticker database.") + (port + (string "6600") + "The port to run mpd on.") + (address + (string "any") + "The address that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (mpd-serialize-field "bind_to_address" x))) + (outputs + (list-of-mpd-output (list (mpd-output))) + "The audio outputs that MPD can use. +By default this is a single output using pulseaudio.") + (prefix mpd-)) (define (mpd-file-name config file) "Return a path in /var/run/mpd/ that is writable @@ -143,7 +184,7 @@ (define (mpd-shepherd-service config) (start #~(make-forkexec-constructor (list #$(file-append mpd "/bin/mpd") "--no-daemon" - #$(mpd-config->file config)) + #$(mpd-serialize-configuration config)) #:environment-variables ;; Required to detect PulseAudio when run under a user account. (list (string-append base-commit: 7833acab0da02335941974608510c02e2d1d8069 -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Wed Dec 21 09:25:14 2022 Received: (at 59866) by debbugs.gnu.org; 21 Dec 2022 14:25:14 +0000 Received: from localhost ([127.0.0.1]:52183 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p801v-0006dW-Tl for submit@debbugs.gnu.org; Wed, 21 Dec 2022 09:25:14 -0500 Received: from smtpm4.myservices.hosting ([185.26.105.235]:60734) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p801r-0006dO-Kq for 59866@debbugs.gnu.org; Wed, 21 Dec 2022 09:25:10 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm4.myservices.hosting (Postfix) with ESMTP id 5CA0520BEC for <59866@debbugs.gnu.org>; Wed, 21 Dec 2022 15:25:06 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id D346680098; Wed, 21 Dec 2022 15:16:01 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id qwO8616BuW0h; Wed, 21 Dec 2022 15:15:58 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 3478580096; Wed, 21 Dec 2022 15:15:58 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v4 2/2] services: mpd: Refactor MPD service. Date: Wed, 21 Dec 2022 14:15:13 +0000 Message-Id: <22745f1abf008ad389638c984e51b12630a18307.1671632111.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 In-Reply-To: <248f6adc7d434e3d8df791311744a38e0d965744.1671632111.git.mirai@makinata.eu> References: <248f6adc7d434e3d8df791311744a38e0d965744.1671632111.git.mirai@makinata.eu> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal Introduces 'mpd-plugin' and 'mpd-partition' records. Expands 'mpd-output' and 'mpd-configuration' records. Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids serializing unused fields that may introduce undesired behavior. Implement log-rotation via rottlog. Implements Shepherd actions: 'reopen' and 'configuration'. --- doc/guix.texi | 172 +++++++++++++--- gnu/services/audio.scm | 434 +++++++++++++++++++++++++++++++---------- 2 files changed, 476 insertions(+), 130 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index fd03da8c97..3daec7dfaa 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -33012,79 +33013,184 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (type: maybe-string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) +@item @code{port} (default: @code{6600}) (type: maybe-integer) The port to run mpd on. -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{endpoints} (type: maybe-list-of-string) +The addresses that mpd will bind to. To use a Unix domain socket, an +absolute path can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". + +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-plugin-or-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -33096,7 +33202,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 2351db8a4a..2b0447fd09 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Peter Mikkelsen ;;; Copyright © 2019 Ricardo Wurmus ;;; Copyright © 2020 Ludovic Courtès +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -20,19 +21,27 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-8) #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? + mpd-plugin + mpd-plugin? + mpd-partition + mpd-partition? mpd-configuration mpd-configuration? mpd-service-type)) @@ -51,180 +60,397 @@ (define (uglify-field-name field-name) #\-) "_"))) -(define (free-form-args? val) - (match val - (() #t) - ((((? symbol?) . (? string?)) . val) (free-form-args? val)) - (_ #f))) +(define list-of-string? + (list-of string?)) -(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) - #~(begin - (use-modules ((ice-9 format))) - (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) - field-name - (uglify-field-name field-name)) #$value))) +(define list-of-symbol? + (list-of symbol?)) -(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) - (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) +(define (mpd-serialize-field field-name value) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (if (boolean? value) (if value "yes" "no") value))) + #~(format #f "~a \"~a\"~%" #$field #$value))) (define mpd-serialize-number mpd-serialize-field) (define mpd-serialize-string mpd-serialize-field) -(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) - (mpd-serialize-field field-name (if value "yes" "no") indent-level)) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define (mpd-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list mpd-serialize-field value))) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) +(define-maybe boolean (prefix mpd-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . addresses))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin (warn-about-deprecation field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning (G_ "string value for '~a' is deprecated, use integer instead~%") field-name)) + (mpd-serialize-field field-name value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(format #f "~a {~%~a}~%" + '#$field-name #$(serialize-configuration value mpd-plugin-fields))) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) value))) -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(format #f "partition {~%~a}~%" + #$(serialize-configuration value mpd-partition-fields))) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name (string "MPD") "The name of the audio output.") + (type (string "pulse") "The type of audio output.") + (enabled? (boolean #t) "Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin.") + (always-on? (boolean #f) "If set to @code{#t}, then MPD attempts to keep this audio output always open. This may be useful for streaming servers, when you don’t want to disconnect all listeners even when playback is accidentally stopped.") + (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} is +to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options - (free-form-args '()) - "An association list of option symbols to string values to be appended to + (alist '()) + "An association list of option symbols/strings to string values to be appended to the audio output configuration.") - (prefix mpd-subsystem-)) -(define list-of-mpd-output? - (list-of mpd-output?)) + (prefix mpd-)) + +(define (mpd-serialize-mpd-output field-name value) + #~(format #f "audio_output {~%~a}~%" + #$(serialize-configuration value mpd-output-fields))) + +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value) + (receive (plugins outputs) + (partition mpd-plugin? value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>) plugins) + #$@(map (cut mpd-serialize-mpd-output #f <>) outputs)))) + +(define list-of-mpd-plugin-or-output? + (list-of (lambda (x) + (or (mpd-output? x) (mpd-plugin? x))))) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + + (group + maybe-string + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the local syslog daemon or +@code{%unset-value} to omit this directive from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. Available values: @code{notice}, +@code{info}, @code{verbose}, @code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) - (playlist-dir - (string "~/.mpd/playlists") + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") + + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) + (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") + (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") + (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") + (port - (string "6600") + (maybe-port 6600) ; TODO: switch to integer "The port to run mpd on.") - (address - (string "any") + + (endpoints + maybe-list-of-string + "The addresses that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "input" x))) + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (mpd-serialize-list-of-mpd-plugin "archive_plugin" x))) + + (input-cache-size + maybe-string + "MPD input cache size." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "decoder" x))) + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "filter" x))) + (outputs - (list-of-mpd-output (list (mpd-output))) + (list-of-mpd-plugin-or-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "playlist_plugin" x))) + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be appended to +the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reopen) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) + (match-record config (user package shepherd-requirement) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reopen) + (documentation "Re-open log files and flush caches.") + (procedure #~(lambda (pid) + (if pid + (begin (kill pid SIGHUP) + (format #t "Issued SIGHUP to Service MPD (PID ~a)." pid)) + (format #t "Service MPD is not running."))))))))))) (define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) + (match-record config (user log-file) #~(begin (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") + (let* ((user (getpw #$user)) + (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd")) + (new-directory (string-append (passwd:dir user) "/.config/mpd"))) + ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd. + (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory))) + (rename-file deprecated-directory new-directory) + (chown new-directory (passwd:uid user) (passwd:gid user))) + (mkdir-p (dirname #$log-file)))))) - (shell (file-append shadow "/sbin/nologin"))))) +(define (mpd-accounts config) + (match-record config (user) + (list (user-account + (name user) + (group "nogroup") + (system? #t) + (comment "Music Player Daemon (MPD) user") + (home-directory "/var/lib/mpd") ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -234,7 +460,9 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) + mpd-accounts) (service-extension activation-service-type - mpd-service-activation))) + mpd-service-activation) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Sat Dec 24 08:55:18 2022 Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 13:55:19 +0000 Received: from localhost ([127.0.0.1]:43110 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p94ze-0001hz-2T for submit@debbugs.gnu.org; Sat, 24 Dec 2022 08:55:18 -0500 Received: from smtpm5.myservices.hosting ([185.26.105.236]:52658) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p94zc-0001hq-Dr for 59866@debbugs.gnu.org; Sat, 24 Dec 2022 08:55:17 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm5.myservices.hosting (Postfix) with ESMTP id 27ACB20C62 for <59866@debbugs.gnu.org>; Sat, 24 Dec 2022 14:55:14 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 4BCA08009F; Sat, 24 Dec 2022 14:55:14 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id PsQ3Rg-zBAAs; Sat, 24 Dec 2022 14:55:13 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id B2A448009D; Sat, 24 Dec 2022 14:55:12 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v5 1/2] services: mpd: rewrite using 'define-configuration'. Date: Sat, 24 Dec 2022 13:51:31 +0000 Message-Id: <8448291fc734b10d0dc9ce50d6a5131d477b537f.1671889887.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal * gnu/services/audio.scm (mpd-configuration, mpd-output): Rewrite using define-configuration. (uglify-field-name): New procedure. (free-form-args?, list-of-mpd-output?): New predicate. --- Changes since v4: * Copyright line moved to patch 1/2. * Retitled commit message and added ChangeLog formatted entries. gnu/services/audio.scm | 218 ++++++++++++++++++++++++----------------- 1 file changed, 130 insertions(+), 88 deletions(-) diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index c60053f33c..1a1026f342 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Peter Mikkelsen ;;; Copyright © 2019 Ricardo Wurmus ;;; Copyright © 2020 Ludovic Courtès +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -21,6 +22,7 @@ (define-module (gnu services audio) #:use-module (guix gexp) #:use-module (gnu services) + #:use-module (gnu services configuration) #:use-module (gnu services shepherd) #:use-module (gnu system shadow) #:use-module (gnu packages admin) @@ -28,6 +30,8 @@ (define-module (gnu services audio) #:use-module (guix records) #:use-module (ice-9 match) #:use-module (ice-9 format) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? mpd-configuration @@ -40,93 +44,131 @@ (define-module (gnu services audio) ;;; ;;; Code: -(define-record-type* - mpd-output make-mpd-output - mpd-output? - (type mpd-output-type - (default "pulse")) - (name mpd-output-name - (default "MPD")) - (enabled? mpd-output-enabled? - (default #t)) - (tags? mpd-output-tags? - (default #t)) - (always-on? mpd-output-always-on? - (default #f)) - (mixer-type mpd-output-mixer-type - ;; valid: hardware, software, null, none - (default #f)) - (extra-options mpd-output-extra-options - (default '()))) - -(define-record-type* - mpd-configuration make-mpd-configuration - mpd-configuration? - (user mpd-configuration-user - (default "mpd")) - (music-dir mpd-configuration-music-dir - (default "~/Music")) - (playlist-dir mpd-configuration-playlist-dir - (default "~/.mpd/playlists")) - (db-file mpd-configuration-db-file - (default "~/.mpd/tag_cache")) - (state-file mpd-configuration-state-file - (default "~/.mpd/state")) - (sticker-file mpd-configuration-sticker-file - (default "~/.mpd/sticker.sql")) - (port mpd-configuration-port - (default "6600")) - (address mpd-configuration-address - (default "any")) - (outputs mpd-configuration-outputs - (default (list (mpd-output))))) - -(define (mpd-output->string output) - "Convert the OUTPUT of type to a configuration file snippet." - (let ((extra (string-join - (map (match-lambda - ((key . value) - (format #f " ~a \"~a\"" - (string-map - (lambda (c) (if (char=? c #\-) #\_ c)) - (symbol->string key)) - value))) - (mpd-output-extra-options output)) - "\n"))) - (format #f "\ -audio_output { - type \"~a\" - name \"~a\" -~:[ enabled \"no\"~%~;~]\ -~:[ tags \"no\"~%~;~]\ -~:[~; always_on \"yes\"~%~]\ -~@[ mixer_type \"~a\"~%~]\ -~a~%}~%" - (mpd-output-type output) - (mpd-output-name output) - (mpd-output-enabled? output) - (mpd-output-tags? output) - (mpd-output-always-on? output) - (mpd-output-mixer-type output) - extra))) - -(define (mpd-config->file config) - (apply - mixed-text-file "mpd.conf" - "pid_file \"" (mpd-file-name config "pid") "\"\n" - (append (map mpd-output->string - (mpd-configuration-outputs config)) - (map (match-lambda - ((config-name config-val) - (string-append config-name " \"" (config-val config) "\"\n"))) - `(("user" ,mpd-configuration-user) - ("music_directory" ,mpd-configuration-music-dir) - ("playlist_directory" ,mpd-configuration-playlist-dir) - ("db_file" ,mpd-configuration-db-file) - ("state_file" ,mpd-configuration-state-file) - ("sticker_file" ,mpd-configuration-sticker-file) - ("port" ,mpd-configuration-port) - ("bind_to_address" ,mpd-configuration-address)))))) +(define (uglify-field-name field-name) + (let ((str (symbol->string field-name))) + (string-join (string-split (if (string-suffix? "?" str) + (string-drop-right str 1) + str) + #\-) + "_"))) + +(define (free-form-args? val) + (match val + (() #t) + ((((? symbol?) . (? string?)) . val) (free-form-args? val)) + (_ #f))) + +(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) + #~(begin + (use-modules ((ice-9 format))) + (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) + field-name + (uglify-field-name field-name)) #$value))) + +(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) + (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) + +(define mpd-serialize-number mpd-serialize-field) + +(define mpd-serialize-string mpd-serialize-field) + +(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) + (mpd-serialize-field field-name (if value "yes" "no") indent-level)) + +(define (mpd-serialize-list-of-mpd-output field-name value) + #~(string-append "\naudio_output {\n" + #$@(map (cut serialize-configuration <> + mpd-output-fields) + value) + "}\n")) + +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) +(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) +(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) +(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) +(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) + +(define-configuration mpd-output + (name + (string "MPD") + "The name of the audio output.") + (type + (string "pulse") + "The type of audio output.") + (enabled? + (boolean #t) + "Specifies whether this audio output is enabled when MPD is started. By +default, all audio outputs are enabled. This is just the default +setting when there is no state file; with a state file, the previous +state is restored.") + (tags? + (boolean #t) + "If set to @code{#f}, then MPD will not send tags to this output. This +is only useful for output plugins that can receive tags, for example the +@code{httpd} output plugin.") + (always-on? + (boolean #f) + "If set to @code{#t}, then MPD attempts to keep this audio output always +open. This may be useful for streaming servers, when you don’t want to +disconnect all listeners even when playback is accidentally stopped.") + (mixer-type + (string "none") + "This field accepts a symbol that specifies which mixer should be used +for this audio output: the @code{hardware} mixer, the @code{software} +mixer, the @code{null} mixer (allows setting the volume, but with no +effect; this can be used as a trick to implement an external mixer +External Mixer) or no mixer (@code{none}).") + (extra-options + (free-form-args '()) + "An association list of option symbols to string values to be appended to +the audio output configuration.") + (prefix mpd-subsystem-)) + +(define list-of-mpd-output? + (list-of mpd-output?)) + +(define-configuration mpd-configuration + (user + (string "mpd") + "The user to run mpd as.") + (music-dir + (string "~/Music") + "The directory to scan for music files." + (lambda (_ x) + (mpd-serialize-field "music_directory" x))) + (playlist-dir + (string "~/.mpd/playlists") + "The directory to store playlists." + (lambda (_ x) + (mpd-serialize-field "playlist_directory" x))) + (db-file + (string "~/.mpd/tag_cache") + "The location of the music database.") + (state-file + (string "~/.mpd/state") + "The location of the file that stores current MPD's state.") + (sticker-file + (string "~/.mpd/sticker.sql") + "The location of the sticker database.") + (port + (string "6600") + "The port to run mpd on.") + (address + (string "any") + "The address that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (mpd-serialize-field "bind_to_address" x))) + (outputs + (list-of-mpd-output (list (mpd-output))) + "The audio outputs that MPD can use. +By default this is a single output using pulseaudio.") + (prefix mpd-)) (define (mpd-file-name config file) "Return a path in /var/run/mpd/ that is writable @@ -143,7 +185,7 @@ (define (mpd-shepherd-service config) (start #~(make-forkexec-constructor (list #$(file-append mpd "/bin/mpd") "--no-daemon" - #$(mpd-config->file config)) + #$(mpd-serialize-configuration config)) #:environment-variables ;; Required to detect PulseAudio when run under a user account. (list (string-append base-commit: aae8371f72805cc35e31817e4120468eee4a4a80 -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Sat Dec 24 08:59:13 2022 Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 13:59:14 +0000 Received: from localhost ([127.0.0.1]:43128 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p953Q-0001ld-76 for submit@debbugs.gnu.org; Sat, 24 Dec 2022 08:59:13 -0500 Received: from smtpm5.myservices.hosting ([185.26.105.236]:53366) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p953N-0001lU-4S for 59866@debbugs.gnu.org; Sat, 24 Dec 2022 08:59:10 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm5.myservices.hosting (Postfix) with ESMTP id A886820C62 for <59866@debbugs.gnu.org>; Sat, 24 Dec 2022 14:59:08 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 4AC508009E; Sat, 24 Dec 2022 14:59:08 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id EOAl1alI_5_a; Sat, 24 Dec 2022 14:59:07 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 250178009D; Sat, 24 Dec 2022 14:59:07 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v5 2/2] services: mpd: Refactor MPD service. Date: Sat, 24 Dec 2022 13:51:33 +0000 Message-Id: X-Mailer: git-send-email 2.38.1 In-Reply-To: <8448291fc734b10d0dc9ce50d6a5131d477b537f.1671889887.git.mirai@makinata.eu> References: <8448291fc734b10d0dc9ce50d6a5131d477b537f.1671889887.git.mirai@makinata.eu> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal Introduces 'mpd-plugin' and 'mpd-partition' records. Expands 'mpd-output' and 'mpd-configuration' records. Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids serializing unused fields that may introduce undesired behavior. Replace free-form-args serialization by making 'mpd-serialize-field' handle multiple types and using it with 'generic-serialize-alist'. Reduce code weight by removing cosmetic indented serialization procedures. Offload logging from shepherd to MPD. Implement log-rotation via rottlog. Implement Shepherd actions: 'reopen' and 'configuration'. * gnu/services/audio.scm (mpd-plugin, mpd-partition): New record. (mpd-plugin?, mpd-partition?, list-of-string?, list-of-symbol?) (list-of-mpd-plugin?, list-of-mpd-partition?) (list-of-mpd-plugin-or-output?, port?): New predicate. (mpd-serialize-field): Handle multiple types. (mpd-configuration) [package, group, shepherd-requirement, log-file, log-level, music-directory] [playlist-directory, endpoints, database, partitions, neighbors, inputs] [archive-plugins, input-cache-size, decoders, resampler, filters] [playlist-plugins, extra-options]: New field. [music-dir, playlist-dir, address]: Deprecate shorthand field. [db-file, state-file, sticker-file, port, outputs]: Change admissible type. (mpd-log-rotation): New procedure. (mpd-shepherd-service) [actions]: New shepherd actions: 'reopen' and 'configuration'. [requirement]: Splice with 'shepherd-requirement' field. [start]: Use 'package' field. Remove #:log-file parameter. (mpd-service-activation): Create logging directory. Handle migration from old-style configuration. (mpd-accounts): Do not hardcode username, change primary group to "nogroup". (mpd-service-type): Extend rottlog-service-type for log-rotation. Update activation-service-type extension to reflect mpd-accounts procedure change. * doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc. --- Changes since v4: * Retitled commit message and added ChangeLog formatted entries. * Split long lines into shorter ones. * Fix leftover mentions of "addresses". * Document that endpoint addresses may contain ports in them. doc/guix.texi | 177 +++++++++++++--- gnu/services/audio.scm | 463 +++++++++++++++++++++++++++++++---------- 2 files changed, 506 insertions(+), 134 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index e25692fd27..5663d1913a 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -33014,79 +33015,187 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (type: maybe-string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) -The port to run mpd on. +@item @code{default-port} (default: @code{6600}) (type: maybe-integer) +The default port to run mpd on. + +@item @code{endpoints} (type: maybe-list-of-string) +The addresses that mpd will bind to. A different port may be +specified, e.g. @code{localhost:6602}. IPv6 addresses must be +enclosed in square brackets if a different port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-plugin-or-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -33098,7 +33207,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 1a1026f342..54b00157b0 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -21,19 +21,27 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-8) #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? + mpd-plugin + mpd-plugin? + mpd-partition + mpd-partition? mpd-configuration mpd-configuration? mpd-service-type)) @@ -52,180 +60,421 @@ (define (uglify-field-name field-name) #\-) "_"))) -(define (free-form-args? val) - (match val - (() #t) - ((((? symbol?) . (? string?)) . val) (free-form-args? val)) - (_ #f))) +(define list-of-string? + (list-of string?)) -(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) - #~(begin - (use-modules ((ice-9 format))) - (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) - field-name - (uglify-field-name field-name)) #$value))) +(define list-of-symbol? + (list-of symbol?)) -(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) - (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) +(define (mpd-serialize-field field-name value) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (if (boolean? value) (if value "yes" "no") value))) + #~(format #f "~a \"~a\"~%" #$field #$value))) (define mpd-serialize-number mpd-serialize-field) (define mpd-serialize-string mpd-serialize-field) -(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) - (mpd-serialize-field field-name (if value "yes" "no") indent-level)) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define (mpd-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list + mpd-serialize-field + value))) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) +(define-maybe boolean (prefix mpd-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . endpoints))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin + (warn-about-deprecation + field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning + (G_ "string value for '~a' is deprecated, use integer instead~%") + field-name)) + (mpd-serialize-field field-name value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(format #f "~a {~%~a}~%" + '#$field-name + #$(serialize-configuration value mpd-plugin-fields))) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) + value))) -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(format #f "partition {~%~a}~%" + #$(serialize-configuration value mpd-partition-fields))) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name (string "MPD") "The name of the audio output.") + (type (string "pulse") "The type of audio output.") + (enabled? (boolean #t) "Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin.") + (always-on? (boolean #f) "If set to @code{#t}, then MPD attempts to keep this audio output always open. This may be useful for streaming servers, when you don’t want to disconnect all listeners even when playback is accidentally stopped.") + (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} +is to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options - (free-form-args '()) - "An association list of option symbols to string values to be appended to -the audio output configuration.") - (prefix mpd-subsystem-)) + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the audio output configuration.") -(define list-of-mpd-output? - (list-of mpd-output?)) + (prefix mpd-)) + +(define (mpd-serialize-mpd-output field-name value) + #~(format #f "audio_output {~%~a}~%" + #$(serialize-configuration value mpd-output-fields))) + +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value) + (receive (plugins outputs) + (partition mpd-plugin? value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>) + plugins) + #$@(map (cut mpd-serialize-mpd-output #f <>) outputs)))) + +(define list-of-mpd-plugin-or-output? + (list-of (lambda (x) + (or (mpd-output? x) (mpd-plugin? x))))) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + + (group + maybe-string + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the +local syslog daemon or @code{%unset-value} to omit this directive +from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. +Available values: @code{notice}, @code{info}, @code{verbose}, +@code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) - (playlist-dir - (string "~/.mpd/playlists") + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") + + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) + (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") + (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") + (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") - (port - (string "6600") - "The port to run mpd on.") - (address - (string "any") + + (default-port + (maybe-port 6600) ; TODO: switch to integer + "The default port to run mpd on.") + + (endpoints + maybe-list-of-string + "The addresses that mpd will bind to. A different port may be +specified, e.g. @code{localhost:6602}. IPv6 addresses must be +enclosed in square brackets if a different port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "input" x))) + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (mpd-serialize-list-of-mpd-plugin "archive_plugin" x))) + + (input-cache-size + maybe-string + "MPD input cache size." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "decoder" x))) + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "filter" x))) + (outputs - (list-of-mpd-output (list (mpd-output))) + (list-of-mpd-plugin-or-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "playlist_plugin" x))) + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be +appended to the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reopen) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) + (match-record config (user package shepherd-requirement) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append + "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reopen) + (documentation "Re-open log files and flush caches.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGHUP) + (format #t + "Issued SIGHUP to Service MPD (PID ~a)." + pid)) + (format #t "Service MPD is not running."))))))))))) (define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) + (match-record config (user log-file) #~(begin (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") + ;; TODO: remove me, migrates from the old location at /var/run/mpd + ;; to the new one at /var/lib/mpd. + (let* ((user (getpw #$user)) + (deprecated-directory (string-append "/var/run/mpd/" + #$user "/.mpd")) + (new-directory (string-append (passwd:dir user) + "/.config/mpd"))) + (when (and (file-exists? deprecated-directory) + (not (file-exists? new-directory))) + (rename-file deprecated-directory new-directory) + (chown new-directory (passwd:uid user) (passwd:gid user)))) + (mkdir-p (dirname #$log-file))))) - (shell (file-append shadow "/sbin/nologin"))))) +(define (mpd-accounts config) + (match-record config (user) + (list (user-account + (name user) + (group "nogroup") + (system? #t) + (comment "Music Player Daemon (MPD) user") + ;; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (home-directory "/var/lib/mpd") + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -235,7 +484,9 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) + mpd-accounts) (service-extension activation-service-type - mpd-service-activation))) + mpd-service-activation) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Sat Dec 24 09:24:26 2022 Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 14:24:26 +0000 Received: from localhost ([127.0.0.1]:43233 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p95Ro-0004TP-PX for submit@debbugs.gnu.org; Sat, 24 Dec 2022 09:24:26 -0500 Received: from smtpm1.myservices.hosting ([185.26.105.232]:44804) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p95Rm-0004TD-3e for 59866@debbugs.gnu.org; Sat, 24 Dec 2022 09:24:24 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm1.myservices.hosting (Postfix) with ESMTP id 5F3A420334 for <59866@debbugs.gnu.org>; Sat, 24 Dec 2022 15:24:19 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id B95FA80096; Sat, 24 Dec 2022 15:24:18 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id xnv4DjSWzaTg; Sat, 24 Dec 2022 15:24:06 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 21EDB80093; Sat, 24 Dec 2022 15:24:06 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v5.1] services: mpd: Refactor MPD service. Date: Sat, 24 Dec 2022 14:11:01 +0000 Message-Id: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal Introduces 'mpd-plugin' and 'mpd-partition' records. Expands 'mpd-output' and 'mpd-configuration' records. Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids serializing unused fields that may introduce undesired behavior. Replace free-form-args serialization by making 'mpd-serialize-field' handle multiple types and using it with 'generic-serialize-alist'. Reduce code weight by removing cosmetic indented serialization procedures. Offload logging from shepherd to MPD. Implement log-rotation via rottlog. Implement Shepherd actions: 'reopen' and 'configuration'. * gnu/services/audio.scm (mpd-plugin, mpd-partition): New record. (mpd-plugin?, mpd-partition?, list-of-string?, list-of-symbol?) (list-of-mpd-plugin?, list-of-mpd-partition?) (list-of-mpd-plugin-or-output?, port?): New predicate. (mpd-serialize-field): Handle multiple types. (mpd-configuration) [package, group, shepherd-requirement, log-file, log-level, music-directory] [playlist-directory, endpoints, database, partitions, neighbors, inputs] [archive-plugins, input-cache-size, decoders, resampler, filters] [playlist-plugins, extra-options]: New field. [music-dir, playlist-dir, address]: Deprecate shorthand field. [db-file, state-file, sticker-file, port, outputs]: Change admissible type. (mpd-log-rotation): New procedure. (mpd-shepherd-service) [actions]: New shepherd actions: 'reopen' and 'configuration'. [requirement]: Splice with 'shepherd-requirement' field. [start]: Use 'package' field. Remove #:log-file parameter. (mpd-service-activation): Create logging directory. Handle migration from old-style configuration. (mpd-accounts): Do not hardcode username, change primary group to "nogroup". (mpd-service-type): Extend rottlog-service-type for log-rotation. Update activation-service-type extension to reflect mpd-accounts procedure change. * doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc. --- Changes since v5: * Serialize default_port field-name as "port". doc/guix.texi | 177 +++++++++++++--- gnu/services/audio.scm | 463 +++++++++++++++++++++++++++++++---------- 2 files changed, 506 insertions(+), 134 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index e25692fd27..5663d1913a 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -33014,79 +33015,187 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (type: maybe-string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) -The port to run mpd on. +@item @code{default-port} (default: @code{6600}) (type: maybe-integer) +The default port to run mpd on. + +@item @code{endpoints} (type: maybe-list-of-string) +The addresses that mpd will bind to. A different port may be +specified, e.g. @code{localhost:6602}. IPv6 addresses must be +enclosed in square brackets if a different port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-plugin-or-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -33098,7 +33207,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 1a1026f342..e456205e99 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -21,19 +21,27 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-8) #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? + mpd-plugin + mpd-plugin? + mpd-partition + mpd-partition? mpd-configuration mpd-configuration? mpd-service-type)) @@ -52,180 +60,421 @@ (define (uglify-field-name field-name) #\-) "_"))) -(define (free-form-args? val) - (match val - (() #t) - ((((? symbol?) . (? string?)) . val) (free-form-args? val)) - (_ #f))) +(define list-of-string? + (list-of string?)) -(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) - #~(begin - (use-modules ((ice-9 format))) - (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) - field-name - (uglify-field-name field-name)) #$value))) +(define list-of-symbol? + (list-of symbol?)) -(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) - (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) +(define (mpd-serialize-field field-name value) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (if (boolean? value) (if value "yes" "no") value))) + #~(format #f "~a \"~a\"~%" #$field #$value))) (define mpd-serialize-number mpd-serialize-field) (define mpd-serialize-string mpd-serialize-field) -(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) - (mpd-serialize-field field-name (if value "yes" "no") indent-level)) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define (mpd-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list + mpd-serialize-field + value))) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) +(define-maybe boolean (prefix mpd-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . endpoints))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin + (warn-about-deprecation + field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning + (G_ "string value for '~a' is deprecated, use integer instead~%") + field-name)) + (mpd-serialize-field "port" value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(format #f "~a {~%~a}~%" + '#$field-name + #$(serialize-configuration value mpd-plugin-fields))) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) + value))) -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(format #f "partition {~%~a}~%" + #$(serialize-configuration value mpd-partition-fields))) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name (string "MPD") "The name of the audio output.") + (type (string "pulse") "The type of audio output.") + (enabled? (boolean #t) "Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin.") + (always-on? (boolean #f) "If set to @code{#t}, then MPD attempts to keep this audio output always open. This may be useful for streaming servers, when you don’t want to disconnect all listeners even when playback is accidentally stopped.") + (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} +is to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options - (free-form-args '()) - "An association list of option symbols to string values to be appended to -the audio output configuration.") - (prefix mpd-subsystem-)) + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the audio output configuration.") -(define list-of-mpd-output? - (list-of mpd-output?)) + (prefix mpd-)) + +(define (mpd-serialize-mpd-output field-name value) + #~(format #f "audio_output {~%~a}~%" + #$(serialize-configuration value mpd-output-fields))) + +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value) + (receive (plugins outputs) + (partition mpd-plugin? value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>) + plugins) + #$@(map (cut mpd-serialize-mpd-output #f <>) outputs)))) + +(define list-of-mpd-plugin-or-output? + (list-of (lambda (x) + (or (mpd-output? x) (mpd-plugin? x))))) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + + (group + maybe-string + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the +local syslog daemon or @code{%unset-value} to omit this directive +from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. +Available values: @code{notice}, @code{info}, @code{verbose}, +@code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) - (playlist-dir - (string "~/.mpd/playlists") + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") + + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) + (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") + (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") + (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") - (port - (string "6600") - "The port to run mpd on.") - (address - (string "any") + + (default-port + (maybe-port 6600) ; TODO: switch to integer + "The default port to run mpd on.") + + (endpoints + maybe-list-of-string + "The addresses that mpd will bind to. A different port may be +specified, e.g. @code{localhost:6602}. IPv6 addresses must be +enclosed in square brackets if a different port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "input" x))) + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (mpd-serialize-list-of-mpd-plugin "archive_plugin" x))) + + (input-cache-size + maybe-string + "MPD input cache size." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "decoder" x))) + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "filter" x))) + (outputs - (list-of-mpd-output (list (mpd-output))) + (list-of-mpd-plugin-or-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "playlist_plugin" x))) + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be +appended to the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reopen) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) + (match-record config (user package shepherd-requirement) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append + "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reopen) + (documentation "Re-open log files and flush caches.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGHUP) + (format #t + "Issued SIGHUP to Service MPD (PID ~a)." + pid)) + (format #t "Service MPD is not running."))))))))))) (define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) + (match-record config (user log-file) #~(begin (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") + ;; TODO: remove me, migrates from the old location at /var/run/mpd + ;; to the new one at /var/lib/mpd. + (let* ((user (getpw #$user)) + (deprecated-directory (string-append "/var/run/mpd/" + #$user "/.mpd")) + (new-directory (string-append (passwd:dir user) + "/.config/mpd"))) + (when (and (file-exists? deprecated-directory) + (not (file-exists? new-directory))) + (rename-file deprecated-directory new-directory) + (chown new-directory (passwd:uid user) (passwd:gid user)))) + (mkdir-p (dirname #$log-file))))) - (shell (file-append shadow "/sbin/nologin"))))) +(define (mpd-accounts config) + (match-record config (user) + (list (user-account + (name user) + (group "nogroup") + (system? #t) + (comment "Music Player Daemon (MPD) user") + ;; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (home-directory "/var/lib/mpd") + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -235,7 +484,9 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) + mpd-accounts) (service-extension activation-service-type - mpd-service-activation))) + mpd-service-activation) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) base-commit: aae8371f72805cc35e31817e4120468eee4a4a80 prerequisite-patch-id: e47455c06e8e73edcc3f36ccd7b6b289cdfa1e16 -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Sat Dec 24 12:21:08 2022 Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 17:21:08 +0000 Received: from localhost ([127.0.0.1]:47060 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p98Co-0002A1-4Y for submit@debbugs.gnu.org; Sat, 24 Dec 2022 12:21:08 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:36855) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p98Cl-000293-1E for 59866@debbugs.gnu.org; Sat, 24 Dec 2022 12:21:05 -0500 Received: by mail-wm1-f66.google.com with SMTP id c65-20020a1c3544000000b003cfffd00fc0so8196499wma.1 for <59866@debbugs.gnu.org>; Sat, 24 Dec 2022 09:21:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=ciboyAGhoWIxNKcuoCKq/EpiuvbsahqbNAca0qttacI=; b=jm6axPxaDrG7hhrzcLIx2G5OsN5pLyV0RJVISaZ4H91nYU1DnaOlHHV7Q52HyGQQZu yCkWgflbmzs2JqwqPwVyJhF0A1Ahwn0zYtKTkQWH85es8REc0nG0TxPIQL5qvxlt6JgR BXs0hOhW6wg+RL6SPBoYdMEVXfFHwxSuQpeKmwuhyAiZ/+Wr8HwUZDz7RkYMNwc3NR50 RCSV4/bUZ1xzW9pVlklMGXToC6kMN4IAhnks+IUpkJR3zVEcYM/CaUnilaJyPaupWl7/ ui0nWu/IgJPE9sTMSEKvtEvvCdySmjxx9kLyKPKK0kasOrt3jF8Ou0GQBxwxmc34tNxN YdbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ciboyAGhoWIxNKcuoCKq/EpiuvbsahqbNAca0qttacI=; b=ns8+PRxAO7Dg4iB9UtdC9O+KbAw8T+784Ikt78Bgehj5Voykq2xJu0YUJeyd6nmbSL 1Qs13phigNXVbH5IFW5W94Ewiyxa78QeEzNvAJX3sMTq2Vn3ITGaX0lUq1oHFQfZLvEs 443iJ7+hfIWmZep5ZAhbzrGxeK47WcYYyvPVsvQ4qE8m9BPe096FJybsNQhF2P3Kgg7P 0SDtSK3cNS8FczRQfCdrJsMJOwTnTrfu6+rq+ZaKQAws4u+fm+HpCq6nxdKdQu6hL9ag rVJ5ehDBR4HHaMVsFJJFvuStDhmrfYSGkXah5uaMoRiGqJNA0WrNmuCb7OyVOY7RamIn xYFQ== X-Gm-Message-State: AFqh2krnzAeglcCw0ZEFSExZbGH30VjSCR6WVGFIkMPP3DavwMPH0tL9 qzAXfGiYEE0l/qaOlH2yqVQ= X-Google-Smtp-Source: AMrXdXt8/8GXl8d4to1GUILweXsVwfyM+P5ja6VY+Py8AhRn4lNwTrjfGa+v019T2qjMg2s4KijQmg== X-Received: by 2002:a05:600c:601e:b0:3c6:e61e:ae71 with SMTP id az30-20020a05600c601e00b003c6e61eae71mr11584043wmb.1.1671902456530; Sat, 24 Dec 2022 09:20:56 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id i2-20020a05600c354200b003d35acb0fd7sm14347049wmq.34.2022.12.24.09.20.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 24 Dec 2022 09:20:56 -0800 (PST) Message-ID: <4a93981e06259ffac47ecc6f988c37d1910593ee.camel@gmail.com> Subject: Re: [PATCH v5.1] services: mpd: Refactor MPD service. From: Liliana Marie Prikler To: mirai@makinata.eu, 59866@debbugs.gnu.org Date: Sat, 24 Dec 2022 18:20:54 +0100 In-Reply-To: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@makinata.eu> References: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@makinata.eu> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Am Samstag, dem 24.12.2022 um 14:11 +0000 schrieb mirai@makinata.eu: > From: Bruno Victal >=20 > Introduces 'mpd-plugin' and 'mpd-partition' records. > Expands 'mpd-output' and 'mpd-configuration' records. > Deprecates redundant abbreviated fields in 'mpd-configuration' and > avoids > serializing unused fields that may introduce undesired behavior. > Replace free-form-args serialization by making 'mpd-serialize-field' > handle > multiple types and using it with 'generic-serialize-alist'. > Reduce code weight by removing cosmetic indented serialization > procedures. > Offload logging from shepherd to MPD. > Implement log-rotation via rottlog. > Implement Shepherd actions: 'reopen' and 'configuration'. The things you wrote here read a like a less structured ChangeLog. The section between header and ChangeLog should instead be used to give some wider context if needed, imo. > * gnu/services/audio.scm > (mpd-plugin, mpd-partition): New record. >=20 > (mpd-plugin?, mpd-partition?, list-of-string?, list-of-symbol?) > (list-of-mpd-plugin?, list-of-mpd-partition?) > (list-of-mpd-plugin-or-output?, port?): New predicate. >=20 > (mpd-serialize-field): Handle multiple types. >=20 > (mpd-configuration) > [package, group, shepherd-requirement, log-file, log-level, music- > directory] > [playlist-directory, endpoints, database, partitions, neighbors, > inputs] > [archive-plugins, input-cache-size, decoders, resampler, filters] > [playlist-plugins, extra-options]: New field. > [music-dir, playlist-dir, address]: Deprecate shorthand field. > [db-file, state-file, sticker-file, port, outputs]: Change admissible > type. >=20 > (mpd-log-rotation): New procedure. >=20 > (mpd-shepherd-service) > [actions]: New shepherd actions: 'reopen' and 'configuration'. > [requirement]: Splice with 'shepherd-requirement' field. > [start]: Use 'package' field. Remove #:log-file parameter. >=20 > (mpd-service-activation): Create logging directory. Handle migration > from old-style configuration. >=20 > (mpd-accounts): Do not hardcode username, change primary group to > "nogroup". While I welcome the extensibility here, I think the default should still be mpd:mpd. I think you should make it so that you can pass a user-account and user-group to the mpd service so that they can be reused (with a sanitizer that creates a user/group from string). > (mpd-service-type): Extend rottlog-service-type for log-rotation. > Update activation-service-type extension to reflect mpd-accounts > procedure change. >=20 > * doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc. > --- >=20 > =C2=A0Changes since v5: > =C2=A0* Serialize default_port field-name as "port". >=20 > =C2=A0doc/guix.texi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= | 177 +++++++++++++--- > =C2=A0gnu/services/audio.scm | 463 +++++++++++++++++++++++++++++++-------= - > -- > =C2=A02 files changed, 506 insertions(+), 134 deletions(-) >=20 > diff --git a/doc/guix.texi b/doc/guix.texi > index e25692fd27..5663d1913a 100644 > --- a/doc/guix.texi > +++ b/doc/guix.texi > @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* > =C2=A0Copyright @copyright{} 2022 Simon Streit@* > =C2=A0Copyright @copyright{} 2022 (@* > =C2=A0Copyright @copyright{} 2022 John Kehayias@* > +Copyright @copyright{} 2022 Bruno Victal@* > =C2=A0 > =C2=A0Permission is granted to copy, distribute and/or modify this > document > =C2=A0under the terms of the GNU Free Documentation License, Version 1.3 > or > @@ -33014,79 +33015,187 @@ The service type for @command{mpd} > =C2=A0Data type representing the configuration of @command{mpd}. > =C2=A0 > =C2=A0@table @asis > -@item @code{user} (default: @code{"mpd"}) > +@item @code{package} (default: @code{mpd}) (type: file-like) > +The MPD package. > + > +@item @code{user} (default: @code{"mpd"}) (type: string) > =C2=A0The user to run mpd as. > =C2=A0 > -@item @code{music-dir} (default: @code{"~/Music"}) > +@item @code{group} (type: maybe-string) > +The group to run mpd as. > + > +@item @code{shepherd-requirement} (default: @code{()}) (type: list- > of-symbol) > +This is a list of symbols naming Shepherd services that this service > +will depend on. > + > +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: > maybe-string) > +The location of the log file.=C2=A0 Set to @code{syslog} to use the loca= l > +syslog daemon or @code{%unset-value} to omit this directive from the > +configuration file. > + > +@item @code{log-level} (type: maybe-string) > +Supress any messages below this threshold.=C2=A0 Available values: > +@code{notice}, @code{info}, @code{verbose}, @code{warning} and > +@code{error}. > + > +@item @code{music-directory} (type: maybe-string) > =C2=A0The directory to scan for music files. > =C2=A0 > -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) > +@item @code{playlist-directory} (type: maybe-string) > =C2=A0The directory to store playlists. > =C2=A0 > -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) > +@item @code{db-file} (type: maybe-string) > =C2=A0The location of the music database. > =C2=A0 > -@item @code{state-file} (default: @code{"~/.mpd/state"}) > +@item @code{state-file} (type: maybe-string) > =C2=A0The location of the file that stores current MPD's state. > =C2=A0 > -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) > +@item @code{sticker-file} (type: maybe-string) > =C2=A0The location of the sticker database. > =C2=A0 > -@item @code{port} (default: @code{"6600"}) > -The port to run mpd on. > +@item @code{default-port} (default: @code{6600}) (type: maybe- > integer) > +The default port to run mpd on. > + > +@item @code{endpoints} (type: maybe-list-of-string) > +The addresses that mpd will bind to.=C2=A0 A different port may be > +specified, e.g. @code{localhost:6602}.=C2=A0 IPv6 addresses must be > +enclosed in square brackets if a different port is used. > +To use a Unix domain socket, an absolute path or a path starting > with @code{~} > +can be specified here. LGTM, but "A different port" should probably be "A port different from @var{default-port}. > +@item @code{database} (type: maybe-mpd-plugin) > +MPD database plugin configuration. > + > +@item @code{partitions} (default: @code{()}) (type: list-of-mpd- > partition) > +List of MPD "partitions". > =C2=A0 > -@item @code{address} (default: @code{"any"}) > -The address that mpd will bind to.=C2=A0 To use a Unix domain socket, > -an absolute path can be specified here. > +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd- > plugin) > +List of MPD neighbor plugin configurations. > =C2=A0 > -@item @code{outputs} (default: @code{"(list (mpd-output))"}) > -The audio outputs that MPD can use.=C2=A0 By default this is a single > output using pulseaudio. > +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) > +List of MPD input plugin configurations. > + > +@item @code{archive-plugins} (default: @code{()}) (type: list-of- > mpd-plugin) > +List of MPD archive plugin configurations. > + > +@item @code{input-cache-size} (type: maybe-string) > +MPD input cache size. > + > +@item @code{decoders} (default: @code{()}) (type: list-of-mpd- > plugin) > +List of MPD decoder plugin configurations. > + > +@item @code{resampler} (type: maybe-mpd-plugin) > +MPD resampler plugin configuration. > + > +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) > +List of MPD filter plugin configurations. > + > +@item @code{outputs} (type: list-of-mpd-plugin-or-output) > +The audio outputs that MPD can use.=C2=A0 By default this is a single > output > +using pulseaudio. > + > +@item @code{playlist-plugins} (default: @code{()}) (type: list-of- > mpd-plugin) > +List of MPD playlist plugin configurations. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the configuration. > + > +@end table > +@end deftp > + > +@deftp {Data Type} mpd-plugin > +Data type representing a @command{mpd} plugin. > + > +@table @asis > +@item @code{plugin} (type: maybe-string) > +Plugin name. > + > +@item @code{name} (type: maybe-string) > +Name. > + > +@item @code{enabled?} (type: maybe-boolean) > +Whether the plugin is enabled/disabled. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the plugin configuration.=C2=A0 See > +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD=C2=A0plugin > +reference} for available options. > + > +@end table > +@end deftp > + > +@deftp {Data Type} mpd-partition > +Data type representing a @command{mpd} partition. > + > +@table @asis > +@item @code{name} (type: string) > +Partition name. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the partition configuration.=C2=A0 See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions > ,Configuring > +Partitions} for available options. > =C2=A0 > =C2=A0@end table > =C2=A0@end deftp > =C2=A0 > =C2=A0@deftp {Data Type} mpd-output > -Data type representing an @command{mpd} audio output. > +Data type representing a @command{mpd} audio output. > =C2=A0 > =C2=A0@table @asis > -@item @code{name} (default: @code{"MPD"}) > +@item @code{name} (default: @code{"MPD"}) (type: string) > =C2=A0The name of the audio output. > =C2=A0 > -@item @code{type} (default: @code{"pulse"}) > +@item @code{type} (default: @code{"pulse"}) (type: string) > =C2=A0The type of audio output. > =C2=A0 > -@item @code{enabled?} (default: @code{#t}) > +@item @code{enabled?} (default: @code{#t}) (type: boolean) > =C2=A0Specifies whether this audio output is enabled when MPD is started.= =C2=A0 > By > =C2=A0default, all audio outputs are enabled.=C2=A0 This is just the defa= ult > =C2=A0setting when there is no state file; with a state file, the previou= s > =C2=A0state is restored. > =C2=A0 > -@item @code{tags?} (default: @code{#t}) > +@item @code{format} (type: maybe-string) > +Force a specific audio format on output.=C2=A0 See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Gl > obal > +Audio Format} for a more detailed description. > + > +@item @code{tags?} (default: @code{#t}) (type: boolean) > =C2=A0If set to @code{#f}, then MPD will not send tags to this output.=C2= =A0 > This > =C2=A0is only useful for output plugins that can receive tags, for exampl= e > the > =C2=A0@code{httpd} output plugin. > =C2=A0 > -@item @code{always-on?} (default: @code{#f}) > +@item @code{always-on?} (default: @code{#f}) (type: boolean) > =C2=A0If set to @code{#t}, then MPD attempts to keep this audio output > always > -open.=C2=A0 This may be useful for streaming servers, when you don=E2=80= =99t want > to > +open.=C2=A0 This may be useful for streaming servers, when you don?t wan= t > to > =C2=A0disconnect all listeners even when playback is accidentally stopped= . > =C2=A0 > -@item @code{mixer-type} > -This field accepts a symbol that specifies which mixer should be > used > +@item @code{mixer-type} (default: @code{"none"}) (type: string) > +This field accepts a string that specifies which mixer should be > used > =C2=A0for this audio output: the @code{hardware} mixer, the > @code{software} > =C2=A0mixer, the @code{null} mixer (allows setting the volume, but with n= o > =C2=A0effect; this can be used as a trick to implement an external mixer > =C2=A0External Mixer) or no mixer (@code{none}). > =C2=A0 > -@item @code{extra-options} (default: @code{'()}) > -An association list of option symbols to string values to be > appended to > -the audio output configuration. > +@item @code{replay-gain-handler} (type: maybe-string) > +This field accepts a string that specifies how > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay > +Gain} is to be applied.=C2=A0 @code{software} uses an internal software > +volume control, @code{mixer} uses the configured (hardware) mixer > +control and @code{none} disables replay gain on this audio output. > + > +@item @code{extra-options} (default: @code{()}) (type: alist) > +An association list of option symbols/strings to string values to be > +appended to the audio output configuration. > =C2=A0 > =C2=A0@end table > =C2=A0@end deftp > =C2=A0 > -The following example shows a configuration of @code{mpd} that > provides > -an HTTP audio streaming output. > +The following example shows a configuration of @command{mpd} that > +configures some of its plugins and provides a HTTP audio streaming > output. > =C2=A0 > =C2=A0@lisp > =C2=A0(service mpd-service-type > @@ -33098,7 +33207,19 @@ an HTTP audio streaming output. > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mixer-type 'null) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-options > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 `((encoder . "= vorbis") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (port=C2= =A0=C2=A0=C2=A0 . "8080")))))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (port=C2= =A0=C2=A0=C2=A0 . "8080")))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (decoders > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (list (mpd-plugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin "mikmod") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (enabled? #f)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-plugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin "openmpt") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (enabled? #t) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-options `((repeat-c= ount . -1) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (interpolation-filter . > 1)))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (resampler = (mpd-plugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin = "libsamplerate") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-o= ptions `((type . 0))))))) > =C2=A0@end lisp > =C2=A0 > =C2=A0 > diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm > index 1a1026f342..e456205e99 100644 > --- a/gnu/services/audio.scm > +++ b/gnu/services/audio.scm > @@ -21,19 +21,27 @@ > =C2=A0 > =C2=A0(define-module (gnu services audio) > =C2=A0=C2=A0 #:use-module (guix gexp) > +=C2=A0 #:use-module (guix deprecation) > +=C2=A0 #:use-module (guix diagnostics) > +=C2=A0 #:use-module (guix i18n) > =C2=A0=C2=A0 #:use-module (gnu services) > =C2=A0=C2=A0 #:use-module (gnu services configuration) > =C2=A0=C2=A0 #:use-module (gnu services shepherd) > +=C2=A0 #:use-module (gnu services admin) > =C2=A0=C2=A0 #:use-module (gnu system shadow) > =C2=A0=C2=A0 #:use-module (gnu packages admin) > =C2=A0=C2=A0 #:use-module (gnu packages mpd) > =C2=A0=C2=A0 #:use-module (guix records) > =C2=A0=C2=A0 #:use-module (ice-9 match) > -=C2=A0 #:use-module (ice-9 format) > =C2=A0=C2=A0 #:use-module (srfi srfi-1) > +=C2=A0 #:use-module (srfi srfi-8) > =C2=A0=C2=A0 #:use-module (srfi srfi-26) > =C2=A0=C2=A0 #:export (mpd-output > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-output? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= lugin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= lugin? > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= artition > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p= artition? > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-configuration > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-configuration? > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = mpd-service-type)) > @@ -52,180 +60,421 @@ (define (uglify-field-name field-name) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #\-) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "_"))) > =C2=A0 > -(define (free-form-args? val) > -=C2=A0 (match val > -=C2=A0=C2=A0=C2=A0 (() #t) > -=C2=A0=C2=A0=C2=A0 ((((? symbol?) . (? string?)) . val) (free-form-args?= val)) > -=C2=A0=C2=A0=C2=A0 (_ #f))) > +(define list-of-string? > +=C2=A0 (list-of string?)) > =C2=A0 > -(define* (mpd-serialize-field field-name value #:optional (indent- > level 0)) > -=C2=A0 #~(begin > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules ((ice-9 format))) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (format #f "~v/~a \"~a\"~%" #$indent-leve= l #$(if (string? > field-name) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 field-name > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (uglify- > field-name field-name)) #$value))) > +(define list-of-symbol? > +=C2=A0 (list-of symbol?)) > =C2=A0 > -(define* (mpd-serialize-free-form-args field-name value #:optional > (indent-level 0)) > -=C2=A0 (generic-serialize-alist string-append (cut mpd-serialize-field <= > > <> indent-level) value)) > +(define (mpd-serialize-field field-name value) > +=C2=A0 (let ((field (if (string? field-name) field-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (uglify-field-name field-name))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (value (if (boolean? value) (= if value "yes" "no") value))) > +=C2=A0=C2=A0=C2=A0 #~(format #f "~a \"~a\"~%" #$field #$value))) > =C2=A0 > =C2=A0(define mpd-serialize-number mpd-serialize-field) > =C2=A0 > =C2=A0(define mpd-serialize-string mpd-serialize-field) > =C2=A0 > -(define* (mpd-serialize-boolean field-name value #:optional (indent- > level 0)) > -=C2=A0 (mpd-serialize-field field-name (if value "yes" "no") indent- > level)) > +(define mpd-serialize-boolean mpd-serialize-field) > =C2=A0 > -(define (mpd-serialize-list-of-mpd-output field-name value) > -=C2=A0 #~(string-append "\naudio_output {\n" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$@(map (cut serialize-configuration <= > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-output-fields) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 value) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "}\n")) > +(define (mpd-serialize-alist field-name value) > +=C2=A0 #~(string-append #$@(generic-serialize-alist list > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-serialize-field > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 value))) > =C2=A0 > -(define (mpd-serialize-configuration configuration) > -=C2=A0 (mixed-text-file > -=C2=A0=C2=A0 "mpd.conf" > -=C2=A0=C2=A0 (serialize-configuration configuration mpd-configuration- > fields))) > +(define-maybe string (prefix mpd-)) > +(define-maybe list-of-string (prefix mpd-)) > +(define-maybe boolean (prefix mpd-)) > + > +;;; TODO: Procedures for deprecated fields, to be removed. > + > +(define mpd-deprecated-fields '((music-dir . music-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (playlist-dir . playlist-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (address . endpoints))) > + > +(define (port? value) (or (string? value) (integer? value))) > + > +(define (mpd-serialize-deprecated-field field-name value) > +=C2=A0 (if (maybe-value-set? value) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (warn-about-deprecation > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 field-name #f > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #:replacement (assoc-re= f mpd-deprecated-fields field-name)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (match field-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('playlist-dir (m= pd-serialize-string "playlist_directory" > value)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('music-dir (mpd-= serialize-string "music_directory" > value)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('address (mpd-se= rialize-string "bind_to_address" > value)))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "")) > + > +(define (mpd-serialize-port field-name value) > +=C2=A0 (when (string? value) > +=C2=A0=C2=A0=C2=A0 (warning > +=C2=A0=C2=A0=C2=A0=C2=A0 (G_ "string value for '~a' is deprecated, use i= nteger > instead~%") > +=C2=A0=C2=A0=C2=A0=C2=A0 field-name)) > +=C2=A0 (mpd-serialize-field "port" value)) > + > +(define-maybe port (prefix mpd-)) > + > +;;; > + > +;; Generic MPD plugin record, lists only the most prevalent fields. > +(define-configuration mpd-plugin > +=C2=A0 (plugin > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Plugin name.") > + > +=C2=A0 (name > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Name.") > + > +=C2=A0 (enabled? > +=C2=A0=C2=A0 maybe-boolean > +=C2=A0=C2=A0 "Whether the plugin is enabled/disabled.") > + > +=C2=A0 (extra-options > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > +to be appended to the plugin configuration. See > +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD=C2=A0plugin > reference} > +for available options.") > + > +=C2=A0 (prefix mpd-)) > + > +(define (mpd-serialize-mpd-plugin field-name value) > +=C2=A0 #~(format #f "~a {~%~a}~%" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 '#$fi= eld-name > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se= rialize-configuration value mpd-plugin-fields))) > + > +(define (mpd-serialize-list-of-mpd-plugin field-name value) > +=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name > <>) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 value))) > =C2=A0 > -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> > 1)) > -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> > <> 1)) > -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> > <> 1)) > -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean > <> <> 1)) > -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize- > free-form-args <> <> 1)) > +(define list-of-mpd-plugin? (list-of mpd-plugin?)) > + > +(define-maybe mpd-plugin (prefix mpd-)) > + > +(define-configuration mpd-partition > +=C2=A0 (name > +=C2=A0=C2=A0 string > +=C2=A0=C2=A0 "Partition name.") > + > +=C2=A0 (extra-options > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > +to be appended to the partition configuration. See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions > ,Configuring=C2=A0Partitions} > +for available options.") > + > +=C2=A0 (prefix mpd-)) > + > +(define (mpd-serialize-mpd-partition field-name value) > +=C2=A0 #~(format #f "partition {~%~a}~%" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se= rialize-configuration value mpd-partition-fields))) > + > +(define (mpd-serialize-list-of-mpd-partition field-name value) > +=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) > value))) > + > +(define list-of-mpd-partition? > +=C2=A0 (list-of mpd-partition?)) > =C2=A0 > =C2=A0(define-configuration mpd-output > =C2=A0=C2=A0 (name > =C2=A0=C2=A0=C2=A0 (string "MPD") > =C2=A0=C2=A0=C2=A0 "The name of the audio output.") > + > =C2=A0=C2=A0 (type > =C2=A0=C2=A0=C2=A0 (string "pulse") > =C2=A0=C2=A0=C2=A0 "The type of audio output.") > + > =C2=A0=C2=A0 (enabled? > =C2=A0=C2=A0=C2=A0 (boolean #t) > =C2=A0=C2=A0=C2=A0 "Specifies whether this audio output is enabled when M= PD is > started. By > =C2=A0default, all audio outputs are enabled. This is just the default > =C2=A0setting when there is no state file; with a state file, the previou= s > =C2=A0state is restored.") > + > +=C2=A0 (format > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Force a specific audio format on output. See > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Gl > obal=C2=A0Audio Format} > +for a more detailed description.") > +=C2=A0=C2=A0=20 > =C2=A0=C2=A0 (tags? > =C2=A0=C2=A0=C2=A0 (boolean #t) > =C2=A0=C2=A0=C2=A0 "If set to @code{#f}, then MPD will not send tags to t= his output. > This > =C2=A0is only useful for output plugins that can receive tags, for exampl= e > the > =C2=A0@code{httpd} output plugin.") > + > =C2=A0=C2=A0 (always-on? > =C2=A0=C2=A0=C2=A0 (boolean #f) > =C2=A0=C2=A0=C2=A0 "If set to @code{#t}, then MPD attempts to keep this a= udio output > always > =C2=A0open. This may be useful for streaming servers, when you don=E2=80= =99t want > to > =C2=A0disconnect all listeners even when playback is accidentally > stopped.") > + > =C2=A0=C2=A0 (mixer-type > =C2=A0=C2=A0=C2=A0 (string "none") > -=C2=A0=C2=A0 "This field accepts a symbol that specifies which mixer sho= uld be > used > +=C2=A0=C2=A0 "This field accepts a string that specifies which mixer sho= uld be > used > =C2=A0for this audio output: the @code{hardware} mixer, the > @code{software} > =C2=A0mixer, the @code{null} mixer (allows setting the volume, but with n= o > =C2=A0effect; this can be used as a trick to implement an external mixer > =C2=A0External Mixer) or no mixer (@code{none}).") > + > +=C2=A0 (replay-gain-handler > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "This field accepts a string that specifies how > +@uref{ > https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay=C2=A0Ga= i > n} > +is to be applied. @code{software} uses an internal software volume > control, > +@code{mixer} uses the configured (hardware) mixer control and > @code{none} > +disables replay gain on this audio output.") > + > =C2=A0=C2=A0 (extra-options > -=C2=A0=C2=A0 (free-form-args '()) > -=C2=A0=C2=A0 "An association list of option symbols to string values to = be > appended to > -the audio output configuration.") > -=C2=A0 (prefix mpd-subsystem-)) > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > +to be appended to the audio output configuration.") > =C2=A0 > -(define list-of-mpd-output? > -=C2=A0 (list-of mpd-output?)) > +=C2=A0 (prefix mpd-)) > + > +(define (mpd-serialize-mpd-output field-name value) > +=C2=A0 #~(format #f "audio_output {~%~a}~%" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se= rialize-configuration value mpd-output-fields))) > + > +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name > value) > +=C2=A0 (receive (plugins outputs) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (partition mpd-plugin? value) > +=C2=A0=C2=A0=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-plugi= n > "audio_output" <>) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 plugins) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$@(map (cut mpd-serialize= -mpd-output #f <>) > outputs)))) > + > +(define list-of-mpd-plugin-or-output? > +=C2=A0 (list-of (lambda (x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (or (mpd-output? x) (mpd-plugin? x))))) > =C2=A0 > =C2=A0(define-configuration mpd-configuration > +=C2=A0 (package > +=C2=A0=C2=A0 (file-like mpd) > +=C2=A0=C2=A0 "The MPD package." > +=C2=A0=C2=A0 empty-serializer) > + > =C2=A0=C2=A0 (user > =C2=A0=C2=A0=C2=A0 (string "mpd") > =C2=A0=C2=A0=C2=A0 "The user to run mpd as.") > -=C2=A0 (music-dir > -=C2=A0=C2=A0 (string "~/Music") > + > +=C2=A0 (group > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "The group to run mpd as.") > + > +=C2=A0 (shepherd-requirement > +=C2=A0=C2=A0 (list-of-symbol '()) > +=C2=A0=C2=A0 "This is a list of symbols naming Shepherd services that th= is > service > +will depend on." > +=C2=A0=C2=A0 empty-serializer) > + > +=C2=A0 (log-file > +=C2=A0=C2=A0 (maybe-string "/var/log/mpd/log") > +=C2=A0=C2=A0 "The location of the log file. Set to @code{syslog} to use = the > +local syslog daemon or @code{%unset-value} to omit this directive > +from the configuration file.") > + > +=C2=A0 (log-level > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "Supress any messages below this threshold. > +Available values: @code{notice}, @code{info}, @code{verbose}, > +@code{warning} and @code{error}.") > + > +=C2=A0 (music-directory > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "The directory to scan for music files.") > + > +=C2=A0 (music-dir ; TODO: deprecated, remove later > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The directory to scan for music files." > -=C2=A0=C2=A0 (lambda (_ x) > -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "music_directory" x))) > -=C2=A0 (playlist-dir > -=C2=A0=C2=A0 (string "~/.mpd/playlists") > +=C2=A0=C2=A0 mpd-serialize-deprecated-field) > + > +=C2=A0 (playlist-directory > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "The directory to store playlists.") > + > +=C2=A0 (playlist-dir ; TODO: deprecated, remove later > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The directory to store playlists." > -=C2=A0=C2=A0 (lambda (_ x) > -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "playlist_directory" x))) > +=C2=A0=C2=A0 mpd-serialize-deprecated-field) > + > =C2=A0=C2=A0 (db-file > -=C2=A0=C2=A0 (string "~/.mpd/tag_cache") > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The location of the music database.") > + > =C2=A0=C2=A0 (state-file > -=C2=A0=C2=A0 (string "~/.mpd/state") > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The location of the file that stores current MPD's st= ate.") > + > =C2=A0=C2=A0 (sticker-file > -=C2=A0=C2=A0 (string "~/.mpd/sticker.sql") > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The location of the sticker database.") > -=C2=A0 (port > -=C2=A0=C2=A0 (string "6600") > -=C2=A0=C2=A0 "The port to run mpd on.") > -=C2=A0 (address > -=C2=A0=C2=A0 (string "any") > + > +=C2=A0 (default-port > +=C2=A0=C2=A0 (maybe-port 6600) ; TODO: switch to integer > +=C2=A0=C2=A0 "The default port to run mpd on.") > + > +=C2=A0 (endpoints > +=C2=A0=C2=A0 maybe-list-of-string > +=C2=A0=C2=A0 "The addresses that mpd will bind to. A different port may = be > +specified, e.g. @code{localhost:6602}. IPv6 addresses must be > +enclosed in square brackets if a different port is used. > +To use a Unix domain socket, an absolute path or a path starting > with @code{~} > +can be specified here." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (if (maybe-value-set? x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #~(string-append #$@(ma= p > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 (cut mpd-serialize-field > "bind_to_address" <>) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 x)) ""))) > + > +=C2=A0 (address ; TODO: deprecated, remove later > +=C2=A0=C2=A0 maybe-string > =C2=A0=C2=A0=C2=A0 "The address that mpd will bind to. > =C2=A0To use a Unix domain socket, an absolute path can be specified > here." > +=C2=A0=C2=A0 mpd-serialize-deprecated-field) > + > +=C2=A0 (database > +=C2=A0=C2=A0 maybe-mpd-plugin > +=C2=A0=C2=A0 "MPD database plugin configuration.") > + > +=C2=A0 (partitions > +=C2=A0=C2=A0 (list-of-mpd-partition '()) > +=C2=A0=C2=A0 "List of MPD \"partitions\".") > +=C2=A0=20 > +=C2=A0 (neighbors > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD neighbor plugin configurations.") > + > +=C2=A0 (inputs > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD input plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "input" x))) > + > +=C2=A0 (archive-plugins > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD archive plugin configurations." > =C2=A0=C2=A0=C2=A0 (lambda (_ x) > -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "bind_to_address" x))) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "archive_plug= in" x))) > + > +=C2=A0 (input-cache-size > +=C2=A0=C2=A0 maybe-string > +=C2=A0=C2=A0 "MPD input cache size." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (if (maybe-value-set? x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #~(string-append "\ninp= ut_cache {\n" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 #$(mpd-serialize-string "size" x) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 "}\n") ""))) > + > +=C2=A0 (decoders > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD decoder plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "decoder" x))= ) > + > +=C2=A0 (resampler > +=C2=A0=C2=A0 maybe-mpd-plugin > +=C2=A0=C2=A0 "MPD resampler plugin configuration.") > + > +=C2=A0 (filters > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD filter plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "filter" x))) > + > =C2=A0=C2=A0 (outputs > -=C2=A0=C2=A0 (list-of-mpd-output (list (mpd-output))) > +=C2=A0=C2=A0 (list-of-mpd-plugin-or-output (list (mpd-output))) > =C2=A0=C2=A0=C2=A0 "The audio outputs that MPD can use. > =C2=A0By default this is a single output using pulseaudio.") > + > +=C2=A0 (playlist-plugins > +=C2=A0=C2=A0 (list-of-mpd-plugin '()) > +=C2=A0=C2=A0 "List of MPD playlist plugin configurations." > +=C2=A0=C2=A0 (lambda (_ x) > +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "playlist_plu= gin" x))) > + > +=C2=A0 (extra-options > +=C2=A0=C2=A0 (alist '()) > +=C2=A0=C2=A0 "An association list of option symbols/strings to string va= lues > to be > +appended to the configuration.") > + > =C2=A0=C2=A0 (prefix mpd-)) > =C2=A0 > -(define (mpd-file-name config file) > -=C2=A0 "Return a path in /var/run/mpd/ that is writable > -=C2=A0=C2=A0 by @code{user} from @code{config}." > -=C2=A0 (string-append "/var/run/mpd/" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (mpd-configuration-user config) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 "/" file)) > +(define (mpd-serialize-configuration configuration) > +=C2=A0 (mixed-text-file > +=C2=A0=C2=A0 "mpd.conf" > +=C2=A0=C2=A0 (serialize-configuration configuration mpd-configuration- > fields))) > + > +(define (mpd-log-rotation config) > +=C2=A0 (match-record config (log-file) > +=C2=A0=C2=A0=C2=A0 (log-rotation > +=C2=A0=C2=A0=C2=A0=C2=A0 (files (list log-file)) > +=C2=A0=C2=A0=C2=A0=C2=A0 (post-rotate #~(begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules (gnu se= rvices herd)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (with-shepherd-actio= n 'mpd ('reopen) #f)))))) > =C2=A0 > =C2=A0(define (mpd-shepherd-service config) > -=C2=A0 (shepherd-service > -=C2=A0=C2=A0 (documentation "Run the MPD (Music Player Daemon)") > -=C2=A0=C2=A0 (requirement '(user-processes)) > -=C2=A0=C2=A0 (provision '(mpd)) > -=C2=A0=C2=A0 (start #~(make-forkexec-constructor > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (list #$(file-append mpd "/bin/mpd") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "--no-daemon" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(mpd-serialize-configuration config)= ) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= #:environment-variables > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= ;; Required to detect PulseAudio when run under a user > account. > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= (list (string-append > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "XDG_RUNTIME_DIR=3D/run/user/" > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (number->string > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (passwd:uid > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (getpwnam #$(mpd-con= figuration-user > config)))))) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= #:log-file #$(mpd-file-name config "log"))) > -=C2=A0=C2=A0 (stop=C2=A0 #~(make-kill-destructor)))) > +=C2=A0 (match-record config (user package shepherd- > requirement) > +=C2=A0=C2=A0=C2=A0 (let* ((config-file (mpd-serialize-configuration conf= ig))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (shepherd-service > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (documentation "Run the MPD (Music = Player Daemon)") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (requirement `(user-processes loopb= ack ,@shepherd- > requirement)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (provision '(mpd)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (start #~(make-forkexec-constructor > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (list #$(file-append package "/bin/mpd") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "--no-daemon" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$config-file) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 #:environment-variables > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 ;; Required to detect PulseAudio when run under a > user account. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (list (string-append > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "XDG_RUN= TIME_DIR=3D/run/user/" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (number-= >string (passwd:uid (getpwnam > #$user))))))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (stop=C2=A0 #~(make-kill-destructor= )) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (actions > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (list (shepherd-configuration= -action config-file) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 (shepherd-action > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (name 'reopen) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (documentation "Re-open log files and flush caches.") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (procedure > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 #~(lambda (pid) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if pid > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (kill pid SIGHUP) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 (format #t > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Issued SIGHUP to Servi= ce MPD (PID > ~a)." > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 pid)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (format = #t "Service MPD is not > running."))))))))))) > =C2=A0 > =C2=A0(define (mpd-service-activation config) > -=C2=A0 (with-imported-modules '((guix build utils)) > +=C2=A0 (match-record config (user log-file) > =C2=A0=C2=A0=C2=A0=C2=A0 #~(begin > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules (guix build= utils)) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (define %user > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (getpw #$(mpd-con= figuration-user config))) > - > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (let ((directory #$(mpd-file-= name config ".mpd"))) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mkdir-p director= y) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chown directory = (passwd:uid %user) (passwd:gid %user)) > - > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; Make /var/run/= mpd/USER user-owned as well. > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chown (dirname d= irectory) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 (passwd:uid %user) (passwd:gid %user)))))) > - > - > -(define %mpd-accounts > -=C2=A0 ;; Default account and group for MPD. > -=C2=A0 (list (user-group (name "mpd") (system? #t)) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (user-account > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "mpd") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (group "mpd") > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (system? #t) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (comment "Music Player = Daemon (MPD) user") > =C2=A0 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; Note: /var/run/mpd h= osts one sub-directory per user, of > which > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; /var/run/mpd/mpd cor= responds to the "mpd" user. > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (home-directory "/var/r= un/mpd/mpd") > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; TODO: remove me, migrates = from the old location at > /var/run/mpd > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;;=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 to the new one at /var/lib/mpd. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (let* ((user (getpw #$user)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (deprecated-directory (string-append "/var/run/mpd/" > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 #$user "/.mpd")) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 (new-directory (string-append (passwd:dir user) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "/.config/mpd"))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (when (and (file-= exists? deprecated-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (not (file-exists? new-dir= ectory))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (rena= me-file deprecated-directory new-directory) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chow= n new-directory (passwd:uid user) (passwd:gid > user)))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mkdir-p (dirname #$log-file)= )))) I'm not sure whether we should migrate the logs here. I do think the logs should be stored in /var/log rather than /var/run, but other than that I'm not even sure there's much value in changing the /var/run/mpd structure. What's your use case for doing so? Cheers From debbugs-submit-bounces@debbugs.gnu.org Sat Dec 24 13:55:20 2022 Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 18:55:20 +0000 Received: from localhost ([127.0.0.1]:47156 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p99fz-0007Se-1B for submit@debbugs.gnu.org; Sat, 24 Dec 2022 13:55:20 -0500 Received: from smtpm3.myservices.hosting ([185.26.105.234]:49794) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p99fv-0007SJ-Ci for 59866@debbugs.gnu.org; Sat, 24 Dec 2022 13:55:17 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm3.myservices.hosting (Postfix) with ESMTP id 8B9A420DB1 for <59866@debbugs.gnu.org>; Sat, 24 Dec 2022 19:55:11 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 1DAE380098; Sat, 24 Dec 2022 19:55:11 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id yFBDdU6qcc39; Sat, 24 Dec 2022 19:55:10 +0100 (CET) Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 4D9DA80097; Sat, 24 Dec 2022 19:55:09 +0100 (CET) From: mirai@makinata.eu To: 59866@debbugs.gnu.org Subject: [PATCH v5.2] services: mpd: Refactor MPD service. Date: Sat, 24 Dec 2022 18:53:00 +0000 Message-Id: X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) From: Bruno Victal Refactor mpd-service-type to support additional mpd.conf directives. * gnu/services/audio.scm (mpd-plugin, mpd-partition): New record. (mpd-plugin?, mpd-partition?, list-of-string?, list-of-symbol?) (list-of-mpd-plugin?, list-of-mpd-partition?) (list-of-mpd-plugin-or-output?, port?): New predicate. (mpd-serialize-field): Handle multiple types. (mpd-configuration) [package, group, shepherd-requirement, log-file, log-level, music-directory] [playlist-directory, endpoints, database, partitions, neighbors, inputs] [archive-plugins, input-cache-size, decoders, resampler, filters] [playlist-plugins, extra-options]: New field. [music-dir, playlist-dir, address]: Deprecate shorthand field. [db-file, state-file, sticker-file, port, outputs]: Change admissible type. (mpd-log-rotation): New procedure. (mpd-shepherd-service) [actions]: New shepherd actions: 'reopen' and 'configuration'. [requirement]: Splice with 'shepherd-requirement' field. [start]: Use 'package' field. Remove #:log-file parameter. (mpd-service-activation): Create logging directory. Handle migration from old-style configuration. (mpd-accounts): Do not hardcode user and group names. (mpd-service-type): Extend rottlog-service-type for log-rotation. Update activation-service-type extension to reflect mpd-accounts procedure change. * doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc. --- Changes since v5.1: * Rewrite commit message. * Create group and user, by default mpd:mpd. * Reword endpoints doc. doc/guix.texi | 177 +++++++++++++--- gnu/services/audio.scm | 467 +++++++++++++++++++++++++++++++---------- 2 files changed, 510 insertions(+), 134 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index e25692fd27..870efdbe2d 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -33014,79 +33015,187 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (default: @code{"mpd"}) (type: string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) -The port to run mpd on. +@item @code{default-port} (default: @code{6600}) (type: maybe-integer) +The default port to run mpd on. + +@item @code{endpoints} (type: maybe-list-of-string) +The addresses that mpd will bind to. A port different from @var{default-port} +may be specified, e.g. @code{localhost:6602} and IPv6 addresses must be +enclosed in square brackets when a different port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-plugin-or-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -33098,7 +33207,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 1a1026f342..6caacf8c68 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -21,19 +21,27 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-8) #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? + mpd-plugin + mpd-plugin? + mpd-partition + mpd-partition? mpd-configuration mpd-configuration? mpd-service-type)) @@ -52,180 +60,425 @@ (define (uglify-field-name field-name) #\-) "_"))) -(define (free-form-args? val) - (match val - (() #t) - ((((? symbol?) . (? string?)) . val) (free-form-args? val)) - (_ #f))) +(define list-of-string? + (list-of string?)) -(define* (mpd-serialize-field field-name value #:optional (indent-level 0)) - #~(begin - (use-modules ((ice-9 format))) - (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name) - field-name - (uglify-field-name field-name)) #$value))) +(define list-of-symbol? + (list-of symbol?)) -(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0)) - (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value)) +(define (mpd-serialize-field field-name value) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (if (boolean? value) (if value "yes" "no") value))) + #~(format #f "~a \"~a\"~%" #$field #$value))) (define mpd-serialize-number mpd-serialize-field) (define mpd-serialize-string mpd-serialize-field) -(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0)) - (mpd-serialize-field field-name (if value "yes" "no") indent-level)) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define (mpd-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list + mpd-serialize-field + value))) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) +(define-maybe boolean (prefix mpd-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . endpoints))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin + (warn-about-deprecation + field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning + (G_ "string value for '~a' is deprecated, use integer instead~%") + field-name)) + (mpd-serialize-field "port" value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(format #f "~a {~%~a}~%" + '#$field-name + #$(serialize-configuration value mpd-plugin-fields))) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) + value))) -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1)) -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1)) -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1)) -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1)) -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1)) +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(format #f "partition {~%~a}~%" + #$(serialize-configuration value mpd-partition-fields))) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name (string "MPD") "The name of the audio output.") + (type (string "pulse") "The type of audio output.") + (enabled? (boolean #t) "Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin.") + (always-on? (boolean #f) "If set to @code{#t}, then MPD attempts to keep this audio output always open. This may be useful for streaming servers, when you don’t want to disconnect all listeners even when playback is accidentally stopped.") + (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} +is to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options - (free-form-args '()) - "An association list of option symbols to string values to be appended to -the audio output configuration.") - (prefix mpd-subsystem-)) + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the audio output configuration.") -(define list-of-mpd-output? - (list-of mpd-output?)) + (prefix mpd-)) + +(define (mpd-serialize-mpd-output field-name value) + #~(format #f "audio_output {~%~a}~%" + #$(serialize-configuration value mpd-output-fields))) + +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value) + (receive (plugins outputs) + (partition mpd-plugin? value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>) + plugins) + #$@(map (cut mpd-serialize-mpd-output #f <>) outputs)))) + +(define list-of-mpd-plugin-or-output? + (list-of (lambda (x) + (or (mpd-output? x) (mpd-plugin? x))))) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + + (group + (string "mpd") + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the +local syslog daemon or @code{%unset-value} to omit this directive +from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. +Available values: @code{notice}, @code{info}, @code{verbose}, +@code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) - (playlist-dir - (string "~/.mpd/playlists") + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") + + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) + (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") + (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") + (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") - (port - (string "6600") - "The port to run mpd on.") - (address - (string "any") + + (default-port + (maybe-port 6600) ; TODO: switch to integer + "The default port to run mpd on.") + + (endpoints + maybe-list-of-string + "The addresses that mpd will bind to. A port different from +@var{default-port} may be specified, e.g. @code{localhost:6602} and +IPv6 addresses must be enclosed in square brackets when a different +port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "input" x))) + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (mpd-serialize-list-of-mpd-plugin "archive_plugin" x))) + + (input-cache-size + maybe-string + "MPD input cache size." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "decoder" x))) + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "filter" x))) + (outputs - (list-of-mpd-output (list (mpd-output))) + (list-of-mpd-plugin-or-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "playlist_plugin" x))) + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be +appended to the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reopen) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) + (match-record config (user package shepherd-requirement) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append + "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reopen) + (documentation "Re-open log files and flush caches.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGHUP) + (format #t + "Issued SIGHUP to Service MPD (PID ~a)." + pid)) + (format #t "Service MPD is not running."))))))))))) (define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) + (match-record config (user log-file) #~(begin (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") + ;; TODO: remove me, migrates from the old location at /var/run/mpd + ;; to the new one at /var/lib/mpd. + (let* ((user (getpw #$user)) + (deprecated-directory (string-append "/var/run/mpd/" + #$user "/.mpd")) + (new-directory (string-append (passwd:dir user) + "/.config/mpd"))) + (when (and (file-exists? deprecated-directory) + (not (file-exists? new-directory))) + (rename-file deprecated-directory new-directory) + (chown new-directory (passwd:uid user) (passwd:gid user)))) + (mkdir-p (dirname #$log-file))))) - (shell (file-append shadow "/sbin/nologin"))))) +(define (mpd-accounts config) + (match-record config (user group) + (list (user-group + (name group) + (system? #t)) + (user-account + (name user) + (group group) + (system? #t) + (comment "Music Player Daemon (MPD) user") + ;; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (home-directory "/var/lib/mpd") + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -235,7 +488,9 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) + mpd-accounts) (service-extension activation-service-type - mpd-service-activation))) + mpd-service-activation) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) base-commit: aae8371f72805cc35e31817e4120468eee4a4a80 prerequisite-patch-id: e47455c06e8e73edcc3f36ccd7b6b289cdfa1e16 -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Sat Dec 24 14:17:34 2022 Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 19:17:34 +0000 Received: from localhost ([127.0.0.1]:47165 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p9A1V-0008Br-W6 for submit@debbugs.gnu.org; Sat, 24 Dec 2022 14:17:34 -0500 Received: from smtpm5.myservices.hosting ([185.26.105.236]:55032) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p9A1T-0008Bg-RB for 59866@debbugs.gnu.org; Sat, 24 Dec 2022 14:17:32 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm5.myservices.hosting (Postfix) with ESMTP id 91F0F201BD; Sat, 24 Dec 2022 20:17:30 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 4E2B18009A; Sat, 24 Dec 2022 20:17:30 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id SW7pDfSv6QS9; Sat, 24 Dec 2022 20:17:30 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id D449480099; Sat, 24 Dec 2022 20:17:29 +0100 (CET) Message-ID: <9d585ea3-2cab-6aee-16ee-672e4cf1cf81@makinata.eu> Date: Sat, 24 Dec 2022 19:17:29 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.6.0 Subject: Re: [PATCH v5.1] services: mpd: Refactor MPD service. Content-Language: en-US To: Liliana Marie Prikler , 59866@debbugs.gnu.org References: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@makinata.eu> <4a93981e06259ffac47ecc6f988c37d1910593ee.camel@gmail.com> From: mirai In-Reply-To: <4a93981e06259ffac47ecc6f988c37d1910593ee.camel@gmail.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -1.1 (-) X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.1 (--) On 2022-12-24 17:20, Liliana Marie Prikler wrote: >> -(define %mpd-accounts >> -  ;; Default account and group for MPD. >> -  (list (user-group (name "mpd") (system? #t)) >> -        (user-account >> -         (name "mpd") >> -         (group "mpd") >> -         (system? #t) >> -         (comment "Music Player Daemon (MPD) user") >>   >> -         ;; Note: /var/run/mpd hosts one sub-directory per user, of >> which >> -         ;; /var/run/mpd/mpd corresponds to the "mpd" user. >> -         (home-directory "/var/run/mpd/mpd") >> +        ;; TODO: remove me, migrates from the old location at >> /var/run/mpd >> +        ;;       to the new one at /var/lib/mpd. >> +        (let* ((user (getpw #$user)) >> +               (deprecated-directory (string-append "/var/run/mpd/" >> +                                                    #$user "/.mpd")) >> +               (new-directory (string-append (passwd:dir user) >> +                                             "/.config/mpd"))) >> +          (when (and (file-exists? deprecated-directory) >> +                     (not (file-exists? new-directory))) >> +            (rename-file deprecated-directory new-directory) >> +            (chown new-directory (passwd:uid user) (passwd:gid >> user)))) >> +        (mkdir-p (dirname #$log-file))))) > I'm not sure whether we should migrate the logs here. I do think the > logs should be stored in /var/log rather than /var/run, but other than > that I'm not even sure there's much value in changing the /var/run/mpd > structure. What's your use case for doing so? I agree with you that they belong to /var/log, though I prefer leaving this to MPDs default behavior when the directives are not explicitly set. IIRC MPD will store them under $XDG_CONFIG_HOME/log if the "log_file" directive is absent. They were previously stored under /var/run because it was set by default to store under ~/.mpd and the user account had its $HOME set as "/var/run/mpd/mpd". (Looking closer to the old behavior, this also meant that the user field was actually ignored as the user-group/user-account was hardcoded). Since /var/run/mpd(/mpd) is the $HOME directory in the old style configuration, it also contains other files of interest, as most of the fields default values are directives relative to $HOME. Personally I've no use to this migration part and I'd prefer an outright breaking change to the new style, most of the MPD generated files can be regenerated without much hardship and this is introducing complexity and soon™ to be obsolete code. Cheers From debbugs-submit-bounces@debbugs.gnu.org Tue Dec 27 09:12:54 2022 Received: (at control) by debbugs.gnu.org; 27 Dec 2022 14:12:54 +0000 Received: from localhost ([127.0.0.1]:54935 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pAAhK-0008Ox-D9 for submit@debbugs.gnu.org; Tue, 27 Dec 2022 09:12:54 -0500 Received: from smtpm4.myservices.hosting ([185.26.105.235]:58372) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pAAhI-0008On-B5 for control@debbugs.gnu.org; Tue, 27 Dec 2022 09:12:52 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm4.myservices.hosting (Postfix) with ESMTP id 4DCFB20D3B for ; Tue, 27 Dec 2022 15:12:50 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 0C9D980096 for ; Tue, 27 Dec 2022 15:12:50 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id wd_xl_jvHuvx for ; Tue, 27 Dec 2022 15:12:49 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id BA1C980093 for ; Tue, 27 Dec 2022 15:12:49 +0100 (CET) Message-ID: <135bf584-4149-9da1-2188-1980f489e45d@makinata.eu> Date: Tue, 27 Dec 2022 14:12:47 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.6.0 Content-Language: en-US To: control From: mirai Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Score: 2.0 (++) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: # remove WIP tag. retitle 59866 [PATCH 0/2] services: mpd: Refactor MPD service. quit Content analysis details: (2.0 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 1.8 MISSING_SUBJECT Missing Subject: header 0.2 NO_SUBJECT Extra score for no subject X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 1.0 (+) # remove WIP tag. retitle 59866 [PATCH 0/2] services: mpd: Refactor MPD service. quit From debbugs-submit-bounces@debbugs.gnu.org Tue Jan 03 09:43:39 2023 Received: (at 59866) by debbugs.gnu.org; 3 Jan 2023 14:43:40 +0000 Received: from localhost ([127.0.0.1]:45032 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pCiVr-0007Vc-S5 for submit@debbugs.gnu.org; Tue, 03 Jan 2023 09:43:39 -0500 Received: from smtpmciv5.myservices.hosting ([185.26.107.241]:38368) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pCiVl-0007VP-Jd for 59866@debbugs.gnu.org; Tue, 03 Jan 2023 09:43:33 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpmciv5.myservices.hosting (Postfix) with ESMTP id ADFC620BE5; Tue, 3 Jan 2023 15:43:24 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 357CF80096; Tue, 3 Jan 2023 15:43:24 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id rmK9p6p4dvEO; Tue, 3 Jan 2023 15:43:23 +0100 (CET) Received: from [192.168.1.239] (unknown [10.192.1.83]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 7463280093; Tue, 3 Jan 2023 15:43:23 +0100 (CET) Message-ID: Date: Tue, 3 Jan 2023 14:43:23 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.6.0 Content-Language: en-US To: 59866 <59866@debbugs.gnu.org> From: mirai Subject: Pulseaudio woes Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Liliana Marie Prikler X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) I've found out that this service (even before this patch-set) is biased towards being used as a home service rather than a system service. The reason is that it sets the XDG_RUNTIME_DIR environment variable through shepherd to: --8<---------------cut here---------------start------------->8--- (list (string-append "XDG_RUNTIME_DIR=/run/user/" (number->string (passwd:uid (getpwnam #$user))))) --8<---------------cut here---------------end--------------->8--- This directory does not exist if this is launched as a system-wide service. I presume that this went unnoticed because most of the times you'd want to use this service system-wide you also configure this either as a MPD 'satellite instance' or the audio-outputs are always network-streaming ones. This falls apart if you configure a system-wide mpd-service with a pulseaudio output as it will try to access XDG_RUNTIME_DIR which is not created for the system? #t 'mpd' user. Now, pulseaudio is usually launched as a 'per-user' daemon although it can be used in a system-pulse configuration though this is strongly discouraged. Under most conditions (pulseaudio config mostly unchanged), a system-wide mpd-service-type is also able to launch its own pulse instance but due to the inherent assumptions present in the original service we have that: - The XDG_RUNTIME_DIR env var is set when it should only be set for 'system? #f' users. - PULSE_CLIENTCONFIG and PULSE_CONFIG are not set by shepherd. These usually correspond to: PULSE_CONFIG =/etc/pulse/client.conf PULSE_CONFIG=/etc/pulse/daemon.conf But if you use mpd-service-type as a home service, you could also have these set to a user-specific pulse config, which will be overridden by shepherd if these are set in mpd-service-type. But again, if you don't set these env vars and use it as a systemwide service with a pulseaudio output and you workaround the XDG_RUNTIME_DIR by unsetting it, your pulse daemon won't read its config and there will be no output. This is not just a theoretical issue, consider this snippet: --8<---------------cut here---------------start------------->8--- ;; Set a systemwide mpd service that streams with pulseaudio RTP output. (service pulseaudio-service-type (pulseaudio-configuration (extra-script-files (list (plain-file "rtp.pa" (string-join (list "load-module module-null-sink sink_name=rtp" "load-module module-rtp-send source=rtp.monitor" "set-default-sink rtp") "\n" 'suffix)))))) (service mpd-service-type (mpd-configuration (outputs (list (mpd-output (name "Pulseaudio over RTP") (type "pulse") (extra-options '((sink . "rtp"))))))) --8<---------------cut here---------------end--------------->8--- The problem here is how to conditionally select which environment variables should be set based on whether this is being launched as a system-wide or home-instance service. I'm all ears for suggestions. Regarding the current patch-set, I'm thinking that some of the non-public procedures could be defined with 'define-deprecated' instead which should (?) be cleaner than the current comments that are demarcating deprecated code. Regards, Bruno From debbugs-submit-bounces@debbugs.gnu.org Tue Jan 03 14:38:27 2023 Received: (at 59866) by debbugs.gnu.org; 3 Jan 2023 19:38:27 +0000 Received: from localhost ([127.0.0.1]:46722 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pCn7D-0007Rz-4y for submit@debbugs.gnu.org; Tue, 03 Jan 2023 14:38:27 -0500 Received: from mail-ej1-f65.google.com ([209.85.218.65]:41472) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pCn78-0007Ri-KW for 59866@debbugs.gnu.org; Tue, 03 Jan 2023 14:38:25 -0500 Received: by mail-ej1-f65.google.com with SMTP id u19so76546734ejm.8 for <59866@debbugs.gnu.org>; Tue, 03 Jan 2023 11:38:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=gBQ+iGtJZUysPIMAzTgsU8U5wao51urAM1Ht84CuD2E=; b=caSH6cNPftw60aRy7oT5dsS+7IMmiWkLHmTdCIVBPqIuVsr9U1WZDE3W1Wkkdo+mQX L8yvnfZd/IAJFwS+kNc171CpfIFHfW4GmBpmqzRmhr1IlMd7rBchKyrDiwz+WJ4265FK axkz7IZUlYJ9R7JB0xn5DNXd5fSyCSPcv89zK/OjG2aqXBlMSYZOPbYlSIGKmkPPJjCt Jjt3CshC+6kpZ8/A6zj6R7obDAjdMqP0jShaHiHKWR10ZNcrQ4fPdiYirkFMWElYe2E+ MXfKqEK3lEwwO7GjY8LqyDCeJmTyd4rRumwIdTLy9hgyi2PpzCQVkpumRvpmbHHi2/bP 2xyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=gBQ+iGtJZUysPIMAzTgsU8U5wao51urAM1Ht84CuD2E=; b=1ruUh3XBX46RZEoT0c6H4gnMC7Lh0JUAAKqypqg3jTB/bezs8fpLNpjjO1CzoNN2cr tCZ6xX+iaFLTyxKYWAFwYNelqrFLB6LlJxFDzw56TL1vvl+Uf6pBSGqRwbdWngat+EVW HkK3zXfrrgxSCF/mLBWMmSjynGZhxcWawA7o3hy1c28qgKEJfAs1adaIv0kxQiqJtN68 XhvTwajHfSpRWNTiXrQB67vT40iHybviT1iflBs4gM0uJc78HDz8h2wbzSeaNTxHQycW EInCNl8Upa1IdQqkSlEsH0SkR10Iv0KcIhq7Zm5aX16rnxo16PRNttaheUuLbsC1otDb 9sDA== X-Gm-Message-State: AFqh2kqASReE8Ms55su/YWEeFlymWEgCJjKrKVB56iymLgVHw9FMPfnV HsCTjvCgJw6ZgyYgp6FuCyw= X-Google-Smtp-Source: AMrXdXsGwoagZeFFO15Ttg0/r29/7PglguQAjf+Zvip1kTVKn+ERnkQ07sFBlD3CHmNAoclpbhB73w== X-Received: by 2002:a17:906:27d4:b0:7c1:337e:575b with SMTP id k20-20020a17090627d400b007c1337e575bmr38089450ejc.66.1672774696520; Tue, 03 Jan 2023 11:38:16 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id k13-20020a1709061c0d00b0082000f8d871sm14445252ejg.152.2023.01.03.11.38.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Jan 2023 11:38:16 -0800 (PST) Message-ID: <8af12f33afa0ef406711e8ed144d49b3e67935c3.camel@gmail.com> Subject: Re: Pulseaudio woes From: Liliana Marie Prikler To: mirai , 59866 <59866@debbugs.gnu.org> Date: Tue, 03 Jan 2023 20:38:14 +0100 In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: base64 User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-Spam-Score: 1.3 (+) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Am Dienstag, dem 03.01.2023 um 14:43 +0000 schrieb mirai: > I've found out that this service (even before this patch-set) > is biased towards being used as a home service rather than a system > servic [...] Content analysis details: (1.3 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (liliana.prikler[at]gmail.com) 1.3 RCVD_IN_VALIDITY_RPBL RBL: Relay in Validity RPBL, https://senderscore.org/blocklistlookup/ [209.85.218.65 listed in bl.score.senderscore.com] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [209.85.218.65 listed in wl.mailspike.net] 0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 0.3 (/) QW0gRGllbnN0YWcsIGRlbSAwMy4wMS4yMDIzIHVtIDE0OjQzICswMDAwIHNjaHJpZWIgbWlyYWk6 Cj4gSSd2ZSBmb3VuZCBvdXQgdGhhdCB0aGlzIHNlcnZpY2UgKGV2ZW4gYmVmb3JlIHRoaXMgcGF0 Y2gtc2V0KQo+IGlzIGJpYXNlZCB0b3dhcmRzIGJlaW5nIHVzZWQgYXMgYSBob21lIHNlcnZpY2Ug cmF0aGVyIHRoYW4gYSBzeXN0ZW0KPiBzZXJ2aWNlLgo+IAo+IFRoZSByZWFzb24gaXMgdGhhdCBp dCBzZXRzIHRoZSBYREdfUlVOVElNRV9ESVIgZW52aXJvbm1lbnQgdmFyaWFibGUKPiB0aHJvdWdo IHNoZXBoZXJkCj4gdG86Cj4gCj4gLS04PC0tLS0tLS0tLS0tLS0tLWN1dCBoZXJlLS0tLS0tLS0t LS0tLS0tc3RhcnQtLS0tLS0tLS0tLS0tPjgtLS0KPiAobGlzdCAoc3RyaW5nLWFwcGVuZAo+IMKg wqDCoMKgwqDCoMKgICJYREdfUlVOVElNRV9ESVI9L3J1bi91c2VyLyIKPiDCoMKgwqDCoMKgwqDC oCAobnVtYmVyLT5zdHJpbmcgKHBhc3N3ZDp1aWQgKGdldHB3bmFtICMkdXNlcikpKSkpCj4gLS04 PC0tLS0tLS0tLS0tLS0tLWN1dCBoZXJlLS0tLS0tLS0tLS0tLS0tZW5kLS0tLS0tLS0tLS0tLS0t PjgtLS0KPiAKPiBUaGlzIGRpcmVjdG9yeSBkb2VzIG5vdCBleGlzdCBpZiB0aGlzIGlzIGxhdW5j aGVkIGFzIGEgc3lzdGVtLXdpZGUKPiBzZXJ2aWNlLgo+IEkgcHJlc3VtZSB0aGF0IHRoaXMgd2Vu dCB1bm5vdGljZWQgYmVjYXVzZSBtb3N0IG9mIHRoZSB0aW1lcyB5b3UnZAo+IHdhbnQgdG8gdXNl IHRoaXMgc2VydmljZSBzeXN0ZW0td2lkZSB5b3UgYWxzbyBjb25maWd1cmUgdGhpcyBlaXRoZXIK PiBhcyBhIE1QRCAnc2F0ZWxsaXRlIGluc3RhbmNlJyBvciB0aGUgYXVkaW8tb3V0cHV0cyBhcmUg YWx3YXlzCj4gbmV0d29yay1zdHJlYW1pbmcgb25lcy4KPiAKPiBUaGlzIGZhbGxzIGFwYXJ0IGlm IHlvdSBjb25maWd1cmUgYSBzeXN0ZW0td2lkZSBtcGQtc2VydmljZSB3aXRoIGEKPiBwdWxzZWF1 ZGlvIG91dHB1dCBhcyBpdCB3aWxsIHRyeSB0byBhY2Nlc3MgWERHX1JVTlRJTUVfRElSIHdoaWNo IGlzCj4gbm90IGNyZWF0ZWQgZm9yIHRoZSBzeXN0ZW0/ICN0ICdtcGQnIHVzZXIuCkFzIGZhciBh cyBJJ20gYXdhcmUsIHlvdSBjYW4gaW5zdGFudGlhdGUgdGhlIE1QRCBzZXJ2aWNlIHN5c3RlbS13 aWRlCndoaWxlIGFsc28gcG9pbnRpbmcgaXQgdG8gYSBub24tc3lzdGVtIHVzZXIuICBBZG1pdHRl ZGx5LCB0aGlzIGlzIGEKc29tZXdoYXQgZGVnZW5lcmF0ZSB1c2UgY2FzZSwgYnV0IHRoYXQncyBo b3cgdGhpbmdzIHdlcmUgaGFuZGxlZCBiZWZvcmUKaG9tZSBzZXJ2aWNlcyB3ZXJlIGEgdGhpbmcs IGFuZCB0aGVyZSBtaWdodCBzdGlsbCBiZSB2YWxpZCByZWFzb25zIHRvCnN1cHBvcnQgaXQuCgo+ IE5vdywgcHVsc2VhdWRpbyBpcyB1c3VhbGx5IGxhdW5jaGVkIGFzIGEgJ3Blci11c2VyJyBkYWVt b24gYWx0aG91Z2gKPiBpdCBjYW4gYmUgdXNlZCBpbiBhIHN5c3RlbS1wdWxzZSBjb25maWd1cmF0 aW9uIHRob3VnaCB0aGlzIGlzCj4gc3Ryb25nbHkgZGlzY291cmFnZWQuCklmIGl0IGlzLCB0aGVu IFhER19SVU5USU1FX0RJUiBkb2Vzbid0IG1hdHRlci4KCj4gVW5kZXIgbW9zdCBjb25kaXRpb25z IChwdWxzZWF1ZGlvIGNvbmZpZyBtb3N0bHkgdW5jaGFuZ2VkKSwKPiBhIHN5c3RlbS13aWRlIG1w ZC1zZXJ2aWNlLXR5cGUgaXMgYWxzbyBhYmxlIHRvIGxhdW5jaCBpdHMgb3duIHB1bHNlCj4gaW5z dGFuY2UgYnV0IGR1ZSB0byB0aGUgaW5oZXJlbnQgYXNzdW1wdGlvbnMgcHJlc2VudCBpbiB0aGUg b3JpZ2luYWwKPiBzZXJ2aWNlIHdlIGhhdmUgdGhhdDoKPiDCoCAtIFRoZSBYREdfUlVOVElNRV9E SVIgZW52IHZhciBpcyBzZXQgd2hlbiBpdCBzaG91bGQgb25seSBiZSBzZXQgZm9yCj4gJ3N5c3Rl bT8gI2YnIHVzZXJzLgo+IMKgIC0gUFVMU0VfQ0xJRU5UQ09ORklHIGFuZCBQVUxTRV9DT05GSUcg YXJlIG5vdCBzZXQgYnkgc2hlcGhlcmQuCj4gwqDCoMKgwqDCoMKgwqDCoFRoZXNlIHVzdWFsbHkg Y29ycmVzcG9uZCB0bzoKPiDCoMKgwqDCoMKgwqDCoMKgwqAgUFVMU0VfQ09ORklHID0vZXRjL3B1 bHNlL2NsaWVudC5jb25mCj4gwqDCoMKgwqDCoMKgwqDCoMKgIFBVTFNFX0NPTkZJRz0vZXRjL3B1 bHNlL2RhZW1vbi5jb25mCj4gwqDCoMKgwqDCoMKgwqAgQnV0IGlmIHlvdSB1c2UgbXBkLXNlcnZp Y2UtdHlwZSBhcyBhIGhvbWUgc2VydmljZSwgeW91IGNvdWxkCj4gYWxzbyBoYXZlCj4gwqDCoMKg wqDCoCB0aGVzZSBzZXQgdG8gYSB1c2VyLXNwZWNpZmljIHB1bHNlIGNvbmZpZywgd2hpY2ggd2ls bCBiZQo+IG92ZXJyaWRkZW4gYnkgc2hlcGhlcmQKPiDCoMKgwqDCoMKgIGlmIHRoZXNlIGFyZSBz ZXQgaW4gbXBkLXNlcnZpY2UtdHlwZS4KPiDCoMKgwqDCoMKgwqDCoCBCdXQgYWdhaW4sIGlmIHlv dSBkb24ndCBzZXQgdGhlc2UgZW52IHZhcnMgYW5kIHVzZSBpdCBhcyBhCj4gc3lzdGVtd2lkZSBz ZXJ2aWNlCj4gwqDCoMKgwqDCoCB3aXRoIGEgcHVsc2VhdWRpbyBvdXRwdXQgYW5kIHlvdSB3b3Jr YXJvdW5kIHRoZSBYREdfUlVOVElNRV9ESVIKPiBieSB1bnNldHRpbmcgaXQsCj4gwqDCoMKgwqDC oCB5b3VyIHB1bHNlIGRhZW1vbiB3b24ndCByZWFkIGl0cyBjb25maWcgYW5kIHRoZXJlIHdpbGwg YmUgbm8KPiBvdXRwdXQuCuS9le+8nwoKPiBUaGlzIGlzIG5vdCBqdXN0IGEgdGhlb3JldGljYWwg aXNzdWUsIGNvbnNpZGVyIHRoaXMgc25pcHBldDoKPiAKPiAtLTg8LS0tLS0tLS0tLS0tLS0tY3V0 IGhlcmUtLS0tLS0tLS0tLS0tLS1zdGFydC0tLS0tLS0tLS0tLS0+OC0tLQo+IDs7IFNldCBhIHN5 c3RlbXdpZGUgbXBkIHNlcnZpY2UgdGhhdCBzdHJlYW1zIHdpdGggcHVsc2VhdWRpbyBSVFAKPiBv dXRwdXQuCj4gCj4gKHNlcnZpY2UgcHVsc2VhdWRpby1zZXJ2aWNlLXR5cGUgKHB1bHNlYXVkaW8t Y29uZmlndXJhdGlvbgo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGV4dHJhLXNjcmlwdC1maWxlcwo+IMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgKGxpc3QKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAocGxhaW4tZmls ZQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAicnRwLnBhIgo+IMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCAoc3RyaW5nLWpvaW4gKGxpc3QgImxvYWQtCj4gbW9kdWxlIG1vZHVsZS1u dWxsLXNpbmsgc2lua19uYW1lPXJ0cCIKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAibG9hZC0KPiBtb2R1bGUgbW9kdWxl LXJ0cC1zZW5kIHNvdXJjZT1ydHAubW9uaXRvciIKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAic2V0LQo+IGRlZmF1bHQt c2luayBydHAiKSAiXG4iICdzdWZmaXgpKSkpKSkKPiAoc2VydmljZSBtcGQtc2VydmljZS10eXBl Cj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChtcGQtY29uZmlndXJhdGlv bgo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChvdXRwdXRzIChsaXN0 IChtcGQtb3V0cHV0IChuYW1lICJQdWxzZWF1ZGlvIG92ZXIKPiBSVFAiKQo+IMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAodHlwZSAicHVsc2UiKQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoZXh0cmEtb3B0aW9ucyAnKChz aW5rIC4KPiAicnRwIikpKSkpKSkKPiAtLTg8LS0tLS0tLS0tLS0tLS0tY3V0IGhlcmUtLS0tLS0t LS0tLS0tLS1lbmQtLS0tLS0tLS0tLS0tLS0+OC0tLQo+IAo+IFRoZSBwcm9ibGVtIGhlcmUgaXMg aG93IHRvIGNvbmRpdGlvbmFsbHkgc2VsZWN0IHdoaWNoIGVudmlyb25tZW50Cj4gdmFyaWFibGVz IHNob3VsZCBiZSBzZXQgYmFzZWQgb24gd2hldGhlciB0aGlzIGlzIGJlaW5nIGxhdW5jaGVkIGFz IGEKPiBzeXN0ZW0td2lkZSBvciBob21lLWluc3RhbmNlIHNlcnZpY2UuIEknbSBhbGwgZWFycyBm b3IKPiBzdWdnZXN0aW9ucy4KSSBkb24ndCB0aGluayB5b3UgbmVlZCB0byB0aGluayBhYm91dCB0 aGUgaG9tZSBzZXJ2aWNlIHRvbyBoYXJkIGhlcmUuIApJZiB5b3UgY2FuJ3QgZ2V0IHRoZSB0d28g dXNlIGNhc2VzIHRvIHdvcmsgdG9nZXRoZXIsIHlvdSBjYW4gZGVmaW5lIGEKaG9tZS1tcGQtc2Vy dmljZS10eXBlIHdoaWNoIHRha2VzIGEgcmVndWxhciBtcGQtY29uZmlndXJhdGlvbiBvciBhCnBh cnRpY3VsYXJseSBjcmFmdGVkIGhvbWUtbXBkLWNvbmZpZ3VyYXRpb24sIHdoaWNoZXZlciBtYWtl cyBtb3JlCnNlbnNlLiAgTm90IHNheWluZyB0aGF0IHRoaXMgd291bGQgYmUgYSBnb29kIGRlc2ln biBpZGVhLCBqdXN0IHRoYXQgdGhlCm9wdGlvbiBleGlzdHMuCgpJIGRvIHRoaW5rIHRyeWluZyB0 byBmaWd1cmUgb3V0IHdoYXQgeW91J3JlIGdvaW5nIHRvIGRvIHdpdGggeW91cgplbnZpcm9ubWVu dCB2YXJpYWJsZXMgaXMgYSBtb3JlIHdvcnRod2hpbGUgZXhlcmNpc2UgYXQgdGhlIG1vbWVudC4K Cj4gUmVnYXJkaW5nIHRoZSBjdXJyZW50IHBhdGNoLXNldCwgSSdtIHRoaW5raW5nIHRoYXQgc29t ZSBvZiB0aGUgbm9uLQo+IHB1YmxpYyBwcm9jZWR1cmVzIGNvdWxkIGJlIGRlZmluZWQgd2l0aCAn ZGVmaW5lLWRlcHJlY2F0ZWQnIGluc3RlYWQKPiB3aGljaCBzaG91bGQgKD8pIGJlIGNsZWFuZXIg dGhhbiB0aGUgY3VycmVudAo+IGNvbW1lbnRzIHRoYXQgYXJlIGRlbWFyY2F0aW5nIGRlcHJlY2F0 ZWQgY29kZS4KSWYgdGhleSBhcmVuJ3QgcHVibGljLCB3aGF0IGlzIHRoZSBwb2ludCBvZiBkZWZp bmUtZGVwcmVjYXRlZD8gIFlvdQp3aWxsIG9ubHkgdHJpcCBvdmVyIHlvdXIgb3duIHVzZXMuCgpD aGVlcnMK From debbugs-submit-bounces@debbugs.gnu.org Thu Feb 02 15:07:49 2023 Received: (at 59866) by debbugs.gnu.org; 2 Feb 2023 20:07:49 +0000 Received: from localhost ([127.0.0.1]:35879 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNfs5-0007ZX-1Q for submit@debbugs.gnu.org; Thu, 02 Feb 2023 15:07:49 -0500 Received: from smtpmciv3.myservices.hosting ([185.26.107.239]:55878) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNfs3-0007ZN-FD for 59866@debbugs.gnu.org; Thu, 02 Feb 2023 15:07:48 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpmciv3.myservices.hosting (Postfix) with ESMTP id 549292079E; Thu, 2 Feb 2023 21:07:45 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 0E92E80096; Thu, 2 Feb 2023 21:07:45 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id s5UzeYsfdz2q; Thu, 2 Feb 2023 21:07:42 +0100 (CET) Received: from guix-nuc.home.arpa (bl9-118-236.dsl.telepac.pt [85.242.118.236]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id D489980093; Thu, 2 Feb 2023 21:07:41 +0100 (CET) From: Bruno Victal To: 59866@debbugs.gnu.org Subject: [PATCH v6 1/3] services: mpd: Rewrite using 'define-configuration'. Date: Thu, 2 Feb 2023 20:07:36 +0000 Message-Id: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal , liliana.prikler@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) * gnu/services/audio.scm (mpd-configuration, mpd-output): Rewrite using define-configuration. (uglify-field-name, mpd-serialize-field, mpd-serialize-alist) (mpd-serialize-number, mpd-serialize-boolean, mpd-serialize-list-of-mpd-output) (mpd-serialize-configuration): New procedure. (list-of-mpd-output?): New predicate. (mpd-config->file, mpd-output->string): Remove procedure. --- Notable changes since v5: * Completely eliminate indented procedures from patchset. gnu/services/audio.scm | 222 ++++++++++++++++++++++++----------------- 1 file changed, 133 insertions(+), 89 deletions(-) diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index c60053f33c..b7cb0ebe38 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Peter Mikkelsen ;;; Copyright © 2019 Ricardo Wurmus ;;; Copyright © 2020 Ludovic Courtès +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -21,13 +22,15 @@ (define-module (gnu services audio) #:use-module (guix gexp) #:use-module (gnu services) + #:use-module (gnu services configuration) #:use-module (gnu services shepherd) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? mpd-configuration @@ -40,93 +43,134 @@ (define-module (gnu services audio) ;;; ;;; Code: -(define-record-type* - mpd-output make-mpd-output - mpd-output? - (type mpd-output-type - (default "pulse")) - (name mpd-output-name - (default "MPD")) - (enabled? mpd-output-enabled? - (default #t)) - (tags? mpd-output-tags? - (default #t)) - (always-on? mpd-output-always-on? - (default #f)) - (mixer-type mpd-output-mixer-type - ;; valid: hardware, software, null, none - (default #f)) - (extra-options mpd-output-extra-options - (default '()))) - -(define-record-type* - mpd-configuration make-mpd-configuration - mpd-configuration? - (user mpd-configuration-user - (default "mpd")) - (music-dir mpd-configuration-music-dir - (default "~/Music")) - (playlist-dir mpd-configuration-playlist-dir - (default "~/.mpd/playlists")) - (db-file mpd-configuration-db-file - (default "~/.mpd/tag_cache")) - (state-file mpd-configuration-state-file - (default "~/.mpd/state")) - (sticker-file mpd-configuration-sticker-file - (default "~/.mpd/sticker.sql")) - (port mpd-configuration-port - (default "6600")) - (address mpd-configuration-address - (default "any")) - (outputs mpd-configuration-outputs - (default (list (mpd-output))))) - -(define (mpd-output->string output) - "Convert the OUTPUT of type to a configuration file snippet." - (let ((extra (string-join - (map (match-lambda - ((key . value) - (format #f " ~a \"~a\"" - (string-map - (lambda (c) (if (char=? c #\-) #\_ c)) - (symbol->string key)) - value))) - (mpd-output-extra-options output)) - "\n"))) - (format #f "\ -audio_output { - type \"~a\" - name \"~a\" -~:[ enabled \"no\"~%~;~]\ -~:[ tags \"no\"~%~;~]\ -~:[~; always_on \"yes\"~%~]\ -~@[ mixer_type \"~a\"~%~]\ -~a~%}~%" - (mpd-output-type output) - (mpd-output-name output) - (mpd-output-enabled? output) - (mpd-output-tags? output) - (mpd-output-always-on? output) - (mpd-output-mixer-type output) - extra))) - -(define (mpd-config->file config) - (apply - mixed-text-file "mpd.conf" - "pid_file \"" (mpd-file-name config "pid") "\"\n" - (append (map mpd-output->string - (mpd-configuration-outputs config)) - (map (match-lambda - ((config-name config-val) - (string-append config-name " \"" (config-val config) "\"\n"))) - `(("user" ,mpd-configuration-user) - ("music_directory" ,mpd-configuration-music-dir) - ("playlist_directory" ,mpd-configuration-playlist-dir) - ("db_file" ,mpd-configuration-db-file) - ("state_file" ,mpd-configuration-state-file) - ("sticker_file" ,mpd-configuration-sticker-file) - ("port" ,mpd-configuration-port) - ("bind_to_address" ,mpd-configuration-address)))))) +(define (uglify-field-name field-name) + (let ((str (symbol->string field-name))) + (string-join (string-split (if (string-suffix? "?" str) + (string-drop-right str 1) + str) + #\-) "_"))) + +(define (mpd-serialize-field field-name value) + #~(format #f "~a ~s~%" #$(if (string? field-name) + field-name + (uglify-field-name field-name)) + #$(if (string? value) + value + (object->string value)))) + +(define (mpd-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list mpd-serialize-field + value))) + +(define mpd-serialize-string mpd-serialize-field) + +(define (mpd-serialize-boolean field-name value) + (mpd-serialize-field field-name (if value "yes" "no"))) + +(define (mpd-serialize-list-of-mpd-output field-name value) + #~(string-append "\naudio_output {\n" + #$@(map (cut serialize-configuration <> + mpd-output-fields) + value) + "}\n")) + +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define-configuration mpd-output + (name + (string "MPD") + "The name of the audio output.") + + (type + (string "pulse") + "The type of audio output.") + + (enabled? + (boolean #t) + "Specifies whether this audio output is enabled when MPD is started. By +default, all audio outputs are enabled. This is just the default +setting when there is no state file; with a state file, the previous +state is restored.") + + (tags? + (boolean #t) + "If set to @code{#f}, then MPD will not send tags to this output. This +is only useful for output plugins that can receive tags, for example the +@code{httpd} output plugin.") + + (always-on? + (boolean #f) + "If set to @code{#t}, then MPD attempts to keep this audio output always +open. This may be useful for streaming servers, when you don’t want to +disconnect all listeners even when playback is accidentally stopped.") + + (mixer-type + (string "none") + "This field accepts a symbol that specifies which mixer should be used +for this audio output: the @code{hardware} mixer, the @code{software} +mixer, the @code{null} mixer (allows setting the volume, but with no +effect; this can be used as a trick to implement an external mixer +External Mixer) or no mixer (@code{none}).") + + (extra-options + (alist '()) + "An association list of option symbols to string values to be appended to +the audio output configuration.") + + (prefix mpd-)) + +(define list-of-mpd-output? + (list-of mpd-output?)) + +(define-configuration mpd-configuration + (user + (string "mpd") + "The user to run mpd as.") + + (music-dir + (string "~/Music") + "The directory to scan for music files." + (lambda (_ x) + (mpd-serialize-field "music_directory" x))) + + (playlist-dir + (string "~/.mpd/playlists") + "The directory to store playlists." + (lambda (_ x) + (mpd-serialize-field "playlist_directory" x))) + + (db-file + (string "~/.mpd/tag_cache") + "The location of the music database.") + + (state-file + (string "~/.mpd/state") + "The location of the file that stores current MPD's state.") + + (sticker-file + (string "~/.mpd/sticker.sql") + "The location of the sticker database.") + + (port + (string "6600") + "The port to run mpd on.") + + (address + (string "any") + "The address that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (mpd-serialize-field "bind_to_address" x))) + + (outputs + (list-of-mpd-output (list (mpd-output))) + "The audio outputs that MPD can use. +By default this is a single output using pulseaudio.") + + (prefix mpd-)) (define (mpd-file-name config file) "Return a path in /var/run/mpd/ that is writable @@ -143,7 +187,7 @@ (define (mpd-shepherd-service config) (start #~(make-forkexec-constructor (list #$(file-append mpd "/bin/mpd") "--no-daemon" - #$(mpd-config->file config)) + #$(mpd-serialize-configuration config)) #:environment-variables ;; Required to detect PulseAudio when run under a user account. (list (string-append -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Thu Feb 02 15:08:15 2023 Received: (at 59866) by debbugs.gnu.org; 2 Feb 2023 20:08:15 +0000 Received: from localhost ([127.0.0.1]:35883 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNfsT-0007ac-Sc for submit@debbugs.gnu.org; Thu, 02 Feb 2023 15:08:15 -0500 Received: from smtpm2.myservices.hosting ([185.26.105.233]:40388) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNfsQ-0007aR-Tq for 59866@debbugs.gnu.org; Thu, 02 Feb 2023 15:08:12 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpm2.myservices.hosting (Postfix) with ESMTP id EF1EE20E7C; Thu, 2 Feb 2023 21:08:09 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id B061480096; Thu, 2 Feb 2023 21:08:09 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id L-GJINCNunHY; Thu, 2 Feb 2023 21:08:08 +0100 (CET) Received: from guix-nuc.home.arpa (bl9-118-236.dsl.telepac.pt [85.242.118.236]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id 8E76380093; Thu, 2 Feb 2023 21:08:08 +0100 (CET) From: Bruno Victal To: 59866@debbugs.gnu.org Subject: [PATCH v6 2/3] services: mpd: Refactor MPD service. Date: Thu, 2 Feb 2023 20:07:37 +0000 Message-Id: X-Mailer: git-send-email 2.38.1 In-Reply-To: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@makinata.eu> References: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@makinata.eu> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal , liliana.prikler@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Refactor mpd-service-type to support additional mpd.conf directives and move activation-service-extension into service constructor. * gnu/services/audio.scm (mpd-plugin, mpd-partition): New record. (mpd-serialize-boolean, mpd-serialize-field): Integrate serializers into a single procedure for alist interop. (mpd-plugin?, mpd-partition?, list-of-string?, list-of-symbol?) (list-of-mpd-plugin?, list-of-mpd-partition?) (list-of-mpd-plugin-or-output?, port?): New predicate. (mpd-file-name, mpd-service-activation): Remove procedure. (mpd-configuration) [package, group, shepherd-requirement, log-file, log-level, music-directory] [playlist-directory, endpoints, database, partitions, neighbors, inputs] [archive-plugins, input-cache-size, decoders, resampler, filters] [playlist-plugins, extra-options]: New field. [music-dir, playlist-dir, address]: Deprecate shorthand field. [db-file, state-file, sticker-file, port, outputs]: Change admissible type. (mpd-shepherd-service) [actions]: New shepherd actions: 'reopen' and 'configuration'. [requirement]: Splice with 'shepherd-requirement' field. [start]: Use 'package' field. Remove #:log-file parameter. Move activation-service extension into constructor. (mpd-accounts): Honor user and group names from configuration. (mpd-log-rotation): New procedure. (mpd-service-type)[extensions]: Add rottlog-service-type extension. Remove activation-service-type extension. (mpd-output-name, mpd-output-type, mpd-output-enabled?, mpd-output-format) (mpd-output-tags?, mpd-output-always-on?, mpd-output-mixer-type) (mpd-output-replay-gain-handler, mpd-output-extra-options) (mpd-plugin-plugin, mpd-plugin-name, mpd-plugin-enabled?) (mpd-plugin-extra-options) (mpd-partition-name, mpd-partition-extra-options) (mpd-configuration-package, mpd-configuration-user) (mpd-configuration-group, mpd-configuration-shepherd-requirement) (mpd-configuration-log-file, mpd-configuration-log-level) (mpd-configuration-music-directory, mpd-configuration-music-dir) (mpd-configuration-playlist-directory, mpd-configuration-playlist-dir) (mpd-configuration-db-file, mpd-configuration-state-file) (mpd-configuration-sticker-file, mpd-configuration-default-port) (mpd-configuration-endpoints, mpd-configuration-address) (mpd-configuration-database, mpd-configuration-partitions) (mpd-configuration-neighbors, mpd-configuration-inputs) (mpd-configuration-archive-plugins, mpd-configuration-input-cache-size) (mpd-configuration-decoders, mpd-configuration-resampler) (mpd-configuration-filters, mpd-configuration-outputs) (mpd-configuration-playlist-plugins, mpd-configuration-extra-options): Export accessors. * doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc. --- Notable changes since v5: * Export accessors. * Integrate activation-service-type extension into service constructor. * Honor existing directories and permissions, only create when absent. doc/guix.texi | 177 ++++++++++++--- gnu/services/audio.scm | 492 +++++++++++++++++++++++++++++++++-------- 2 files changed, 543 insertions(+), 126 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 64873db00b..8e220e0631 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@* Copyright @copyright{} 2023 Giacomo Leidi@* Copyright @copyright{} 2022 Antero Mejr@* @@ -33185,79 +33186,187 @@ Audio Services Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (default: @code{"mpd"}) (type: string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) -The port to run mpd on. +@item @code{default-port} (default: @code{6600}) (type: maybe-integer) +The default port to run mpd on. + +@item @code{endpoints} (type: maybe-list-of-string) +The addresses that mpd will bind to. A port different from @var{default-port} +may be specified, e.g. @code{localhost:6602} and IPv6 addresses must be +enclosed in square brackets when a different port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-plugin-or-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -33269,7 +33378,19 @@ Audio Services (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index b7cb0ebe38..7168320635 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -21,20 +21,75 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-8) #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? + mpd-output-name + mpd-output-type + mpd-output-enabled? + mpd-output-format + mpd-output-tags? + mpd-output-always-on? + mpd-output-mixer-type + mpd-output-replay-gain-handler + mpd-output-extra-options + + mpd-plugin + mpd-plugin? + mpd-plugin-plugin + mpd-plugin-name + mpd-plugin-enabled? + mpd-plugin-extra-options + + mpd-partition + mpd-partition? + mpd-partition-name + mpd-partition-extra-options + mpd-configuration mpd-configuration? + mpd-configuration-package + mpd-configuration-user + mpd-configuration-group + mpd-configuration-shepherd-requirement + mpd-configuration-log-file + mpd-configuration-log-level + mpd-configuration-music-directory + mpd-configuration-music-dir + mpd-configuration-playlist-directory + mpd-configuration-playlist-dir + mpd-configuration-db-file + mpd-configuration-state-file + mpd-configuration-sticker-file + mpd-configuration-default-port + mpd-configuration-endpoints + mpd-configuration-address + mpd-configuration-database + mpd-configuration-partitions + mpd-configuration-neighbors + mpd-configuration-inputs + mpd-configuration-archive-plugins + mpd-configuration-input-cache-size + mpd-configuration-decoders + mpd-configuration-resampler + mpd-configuration-filters + mpd-configuration-outputs + mpd-configuration-playlist-plugins + mpd-configuration-extra-options mpd-service-type)) ;;; Commentary: @@ -50,13 +105,20 @@ (define (uglify-field-name field-name) str) #\-) "_"))) +(define list-of-string? + (list-of string?)) + +(define list-of-symbol? + (list-of symbol?)) + (define (mpd-serialize-field field-name value) - #~(format #f "~a ~s~%" #$(if (string? field-name) - field-name - (uglify-field-name field-name)) - #$(if (string? value) - value - (object->string value)))) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (cond + ((boolean? value) (if value "yes" "no")) + ((string? value) value) + (else (object->string value))))) + #~(format #f "~a ~s~%" #$field #$value))) (define (mpd-serialize-alist field-name value) #~(string-append #$@(generic-serialize-alist list mpd-serialize-field @@ -64,20 +126,103 @@ (define (mpd-serialize-alist field-name value) (define mpd-serialize-string mpd-serialize-field) -(define (mpd-serialize-boolean field-name value) - (mpd-serialize-field field-name (if value "yes" "no"))) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) +(define-maybe boolean (prefix mpd-)) + +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . endpoints))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin + (warn-about-deprecation + field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning + (G_ "string value for '~a' is deprecated, use integer instead~%") + field-name)) + (mpd-serialize-field "port" value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(format #f "~a {~%~a}~%" + '#$field-name + #$(serialize-configuration value mpd-plugin-fields))) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) + value))) + +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(format #f "partition {~%~a}~%" + #$(serialize-configuration value mpd-partition-fields))) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name @@ -95,6 +240,12 @@ (define-configuration mpd-output setting when there is no state file; with a state file, the previous state is restored.") + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This @@ -109,125 +260,270 @@ (define-configuration mpd-output (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} +is to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options (alist '()) - "An association list of option symbols to string values to be appended to -the audio output configuration.") + "An association list of option symbols/strings to string values +to be appended to the audio output configuration.") (prefix mpd-)) -(define list-of-mpd-output? - (list-of mpd-output?)) +(define (mpd-serialize-mpd-output field-name value) + #~(format #f "audio_output {~%~a}~%" + #$(serialize-configuration value mpd-output-fields))) + +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value) + (receive (plugins outputs) + (partition mpd-plugin? value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>) + plugins) + #$@(map (cut mpd-serialize-mpd-output #f <>) outputs)))) + +(define list-of-mpd-plugin-or-output? + (list-of (lambda (x) + (or (mpd-output? x) (mpd-plugin? x))))) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + (group + (string "mpd") + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the +local syslog daemon or @code{%unset-value} to omit this directive +from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. +Available values: @code{notice}, @code{info}, @code{verbose}, +@code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") - (playlist-dir - (string "~/.mpd/playlists") + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") - (port - (string "6600") - "The port to run mpd on.") + (default-port + (maybe-port 6600) + "The default port to run mpd on.") + + (endpoints + maybe-list-of-string + "The addresses that mpd will bind to. A port different from +@var{default-port} may be specified, e.g. @code{localhost:6602} and +IPv6 addresses must be enclosed in square brackets when a different +port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append #$@(map + (cut mpd-serialize-field "bind_to_address" <>) + x)) ""))) - (address - (string "any") + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (mpd-serialize-list-of-mpd-plugin "input" x))) + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "archive_plugin" x))) + + (input-cache-size + maybe-string + "MPD input cache size." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "decoder" x))) + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "filter" x))) (outputs - (list-of-mpd-output (list (mpd-output))) + (list-of-mpd-plugin-or-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "playlist_plugin" x))) + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be +appended to the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reopen) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) - -(define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) - #~(begin - (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") - - (shell (file-append shadow "/sbin/nologin"))))) + (match-record config (user package shepherd-requirement + log-file playlist-directory + db-file state-file sticker-file) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(begin + (and=> #$(maybe-value log-file) + (compose mkdir-p dirname)) + + (let ((user (getpw #$user))) + (for-each + (lambda (x) + (when (and x (not (file-exists? x))) + (mkdir-p x) + (chown x (passwd:uid user) (passwd:gid user)))) + (list #$(maybe-value playlist-directory) + (and=> #$(maybe-value db-file) dirname) + (and=> #$(maybe-value state-file) dirname) + (and=> #$(maybe-value sticker-file) dirname)))) + + (make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append + "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user)))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reopen) + (documentation "Re-open log files and flush caches.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGHUP) + (format #t + "Issued SIGHUP to Service MPD (PID ~a)." + pid)) + (format #t "Service MPD is not running."))))))))))) + +(define (mpd-accounts config) + (match-record config (user group) + (list (user-group + (name group) + (system? #t)) + (user-account + (name user) + (group group) + (system? #t) + (comment "Music Player Daemon (MPD) user") + ;; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (home-directory "/var/lib/mpd") + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -237,7 +533,7 @@ (define mpd-service-type (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) - (service-extension activation-service-type - mpd-service-activation))) + mpd-accounts) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Thu Feb 02 15:09:52 2023 Received: (at 59866) by debbugs.gnu.org; 2 Feb 2023 20:09:52 +0000 Received: from localhost ([127.0.0.1]:35887 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNfu3-0007cx-L2 for submit@debbugs.gnu.org; Thu, 02 Feb 2023 15:09:51 -0500 Received: from smtpmciv6.myservices.hosting ([185.26.106.201]:47066) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNfu1-0007cp-E3 for 59866@debbugs.gnu.org; Thu, 02 Feb 2023 15:09:50 -0500 Received: from mail1.netim.hosting (unknown [185.26.106.172]) by smtpmciv6.myservices.hosting (Postfix) with ESMTP id 7B85320DE9; Thu, 2 Feb 2023 21:09:48 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by mail1.netim.hosting (Postfix) with ESMTP id 2EFF680098; Thu, 2 Feb 2023 21:09:48 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting Received: from mail1.netim.hosting ([127.0.0.1]) by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id rtrGhNt4uFWV; Thu, 2 Feb 2023 21:09:47 +0100 (CET) Received: from guix-nuc.home.arpa (bl9-118-236.dsl.telepac.pt [85.242.118.236]) (Authenticated sender: lumen@makinata.eu) by mail1.netim.hosting (Postfix) with ESMTPSA id A5A7880097; Thu, 2 Feb 2023 21:09:47 +0100 (CET) From: Bruno Victal To: 59866@debbugs.gnu.org Subject: [PATCH v6 3/3] services: mpd: Do not hardcode environment variables. Date: Thu, 2 Feb 2023 20:07:38 +0000 Message-Id: <6b51304098d50a01c207abddb3b02ba863034e56.1675367583.git.mirai@makinata.eu> X-Mailer: git-send-email 2.38.1 In-Reply-To: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@makinata.eu> References: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@makinata.eu> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 Cc: Bruno Victal , liliana.prikler@gmail.com X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Services should not expect for XDG_RUNTIME_DIR to be set. Inferring from the past comment, this seemed to resolve an issue when the service was launched with an _interactive_ user-account, which tends to have this variable set by the login-manager. This is not the case for system accounts and setting this variable results in PulseAudio (launched by the same system user) failing to start since it attempts to use a nonexistent directory. Ideally, this service should have a home-service counterpart but the old behavior can be emulated by setting the environment-variables field to: (environment-variables (list (string-append "XDG_RUNTIME_DIR=/run/user/" (number->string (passwd:uid (getpwnam "myuser")))))) * gnu/services/audio.scm (mpd-configuration)[environment-variables]: New field. (mpd-shepherd-service)[start]: Use new field. * doc/guix.texi (Audio Services)[Music Player Daemon]: Document it. --- Notable changes since v5: * NEW. Fixes PulseAudio issues resulting from hardcoded environment variables. doc/guix.texi | 3 +++ gnu/services/audio.scm | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 8e220e0631..05c216bec4 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -33199,6 +33199,9 @@ Audio Services This is a list of symbols naming Shepherd services that this service will depend on. +@item @code{environment-variables} (default: @code{()}) (type: list-of-string) +A list of strings specifying environment variables. + @item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) The location of the log file. Set to @code{syslog} to use the local syslog daemon or @code{%unset-value} to omit this directive from the diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 7168320635..96b27660e5 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -316,6 +316,11 @@ (define-configuration mpd-configuration will depend on." empty-serializer) + (environment-variables + (list-of-string '()) + "A list of strings specifying environment variables." + empty-serializer) + (log-file (maybe-string "/var/log/mpd/log") "The location of the log file. Set to @code{syslog} to use the @@ -465,7 +470,8 @@ (define (mpd-log-rotation config) (define (mpd-shepherd-service config) (match-record config (user package shepherd-requirement log-file playlist-directory - db-file state-file sticker-file) + db-file state-file sticker-file + environment-variables) (let* ((config-file (mpd-serialize-configuration config))) (shepherd-service (documentation "Run the MPD (Music Player Daemon)") @@ -490,11 +496,7 @@ (define (mpd-shepherd-service config) (list #$(file-append package "/bin/mpd") "--no-daemon" #$config-file) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string (passwd:uid (getpwnam #$user)))))))) + #:environment-variables '#$environment-variables))) (stop #~(make-kill-destructor)) (actions (list (shepherd-configuration-action config-file) -- 2.38.1 From debbugs-submit-bounces@debbugs.gnu.org Thu Feb 02 16:08:13 2023 Received: (at 59866) by debbugs.gnu.org; 2 Feb 2023 21:08:13 +0000 Received: from localhost ([127.0.0.1]:35978 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNgoX-0003Av-50 for submit@debbugs.gnu.org; Thu, 02 Feb 2023 16:08:13 -0500 Received: from mail-ed1-f67.google.com ([209.85.208.67]:33452) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pNgoU-0003Ab-TV for 59866@debbugs.gnu.org; Thu, 02 Feb 2023 16:08:11 -0500 Received: by mail-ed1-f67.google.com with SMTP id x7so3417034edr.0 for <59866@debbugs.gnu.org>; Thu, 02 Feb 2023 13:08:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=TWE+EN4fhv7jn19p222cn9N2gGC/YnDlAOxisjcqVNw=; b=Dt7IJDzR072krK8IJRexGtWrBS6X751adskhZrsk6B83kaULEYVRXCOlGBbVLtlbID 8J+1k2Q2TM4lcdb+56n0KtW+yKxuNANeC/jYS3YhcSiIg1Umh5V2p3TGUl3iJwcOwrh6 ol1PUVKqN0w2O7j80VS82yY/OVEguU5p7qgg7JzuGU95aI1EbY3T5Sh/q0SC5M9nBb8m X9aYHuc+UVpbd0cwzxDm/xr33T+ACmBxFQw3zrBkX0y4HBfUMpG4sphohDEYRpPtc9wv h2otGpwIPHpMjkNdD8pLKNZGHuskea0rzUJ4MUfwN0qc+tkYiFqblkmCzcz3LT9ftqnW TezA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=TWE+EN4fhv7jn19p222cn9N2gGC/YnDlAOxisjcqVNw=; b=DmI10wwV9fROLXbZMVLrwWNnUU7f89YI5pSmcDOKueAUE1/SWplzZOGGjPUEEUxxf2 6l3TeUvP68QOvKlnc+TxG6Ot/rj3N/oCo6fjIU41X9z1F9ek54D1qGVw412ZIyTZTmQA OiG3v8uV1ZE9LxEM+sqV1TVIQbA0kbc9WAU4CnfGbKvHwphC4mLpRosx+u4e90IDLWb2 XDqILAtQ4MMBPXYUei5g92vpiG6uyKNwZW5ZmtcmhIvEauJ1BLpbUy5irNZofm7Tbqp/ RiLJghjz1q5R/7Jen25qDeaOgxF7HfTyrukcvu5mH1eqB7Lh73l+FrM4Oie83NYw6OuC 5LBA== X-Gm-Message-State: AO0yUKVUJNutgZ8v0cns5+Is23BrU4HR898QuXAsJ1e1YIqFo33J3ZiH TS43KaIXgrT1PHkJRJ2ANWc= X-Google-Smtp-Source: AK7set/MYiqqsKJPC4ldKhQLkZa4A3x9bQerOMAG02vNCpMM8NTLshLueDraJY4lzZxFFjQknyvpSw== X-Received: by 2002:a05:6402:3894:b0:4a3:43c1:843b with SMTP id fd20-20020a056402389400b004a343c1843bmr3202943edb.15.1675372084889; Thu, 02 Feb 2023 13:08:04 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id s22-20020aa7cb16000000b004a236384909sm234528edt.10.2023.02.02.13.08.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Feb 2023 13:08:04 -0800 (PST) Message-ID: <88e71adf846525fbc1a964b24fb45e3e4b5c9208.camel@gmail.com> Subject: Re: [PATCH v6 2/3] services: mpd: Refactor MPD service. From: Liliana Marie Prikler To: Bruno Victal , 59866@debbugs.gnu.org Date: Thu, 02 Feb 2023 22:08:02 +0100 In-Reply-To: References: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@makinata.eu> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Not a complete review yet, just some quick pointers. Am Donnerstag, dem 02.02.2023 um 20:07 +0000 schrieb Bruno Victal: > Refactor mpd-service-type to support additional mpd.conf directives > and move activation-service-extension into service constructor. >=20 > * gnu/services/audio.scm > (mpd-plugin, mpd-partition): New record. No need to break the line before the paren here. > (mpd-serialize-boolean, mpd-serialize-field): Integrate serializers > into a single procedure for alist interop. That's not a good docstring here. I think=C2=A0 (mpd-serialize-boolean): Delete variable. Move logic into... (mpd-serialize-field): ... this. explains what's going on better. > [...] > =C2=A0=C2=A0 #:use-module (srfi srfi-1) > +=C2=A0 #:use-module (srfi srfi-8) > =C2=A0=C2=A0 #:use-module (srfi srfi-26) We generally prefer SRFI 71. Cheers From debbugs-submit-bounces@debbugs.gnu.org Sun Feb 05 01:11:19 2023 Received: (at 59866-done) by debbugs.gnu.org; 5 Feb 2023 06:11:19 +0000 Received: from localhost ([127.0.0.1]:43851 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pOYFD-0003DU-24 for submit@debbugs.gnu.org; Sun, 05 Feb 2023 01:11:19 -0500 Received: from mail-ej1-f67.google.com ([209.85.218.67]:33728) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pOYFA-0003DB-0J for 59866-done@debbugs.gnu.org; Sun, 05 Feb 2023 01:11:16 -0500 Received: by mail-ej1-f67.google.com with SMTP id ml19so26107226ejb.0 for <59866-done@debbugs.gnu.org>; Sat, 04 Feb 2023 22:11:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=goVjraSUa4fGeJArwkLMNIITf4M8S0XvdkGYISXSnb0=; b=ARjc6HS8wEVf1aWivIS9zmebAAOATtr8xwLTo5VbRqePSb6nfR5voTaUPtJ/fs5ITs ddaBNGcZ1uMBxwzMd1MR0QbAAfs2Ta4Vcb+WnkJ/d9KQq8EVFPZmx9qgitEjFgN06Xor 5n6QthC3oyy74CtwLWeseE6S4XZbutQFsbZdaKbUy+aanWvSKO5Ks1N+G5+qhTx/OBoe 59AMQzD6D2fgkdbevFWknfG5n7hqKe9Q+IaxllohrTC8dat463f7jJf73xDK8f8HmVr3 XtChkGtDLcN10T/V9PSbjxP5Z31lOEdl9St9bbu+uxpqdoTEqJWMPbtnLUPpuGfaeuNv JGug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=goVjraSUa4fGeJArwkLMNIITf4M8S0XvdkGYISXSnb0=; b=hd+dzOVzyp5lYjoit/8+I9XfK9p36yhrkiFUBM618GybkbA3rnjlu8p7DKtTA995RN huuzmCTrtmuwhprqejWOgp/0jPulG+3RV1IrP/wHPqeN5QCnnl7mSap12VUWN0aEM78m u1BXrDwCQFMvCIS0mu74YXMIbVdEiaULLeOoeXd8XwFSYmaemHhwOgIRCy+kD59HTamZ aji9CpPiU9QGQH5tpzGAThL32eRQNhQtpVGloy62zZWcH8P/qSRwYE3miZSScQgmm3K1 YCv1GSmLSW+yAe9xDfejiJwsFnc1emYWoomWAdCWW1lcRK5g3+CJ2povCdAhnGFp3mhr /5fg== X-Gm-Message-State: AO0yUKXXOeQhEXa1KkuEqBleQzGx3vvhHag9t/tgLaCbTcAsIxkIkSgs pdkH5Vw3A7DHqDRS5Wi/vWw= X-Google-Smtp-Source: AK7set/awmXtBxNhizVGtC9z1IKLvUImgq0hlqhQfpdcBcwOPB3BMzzyGkXfduqXPZQkvUMBAXjSYQ== X-Received: by 2002:a17:907:3e82:b0:85f:5d72:1841 with SMTP id hs2-20020a1709073e8200b0085f5d721841mr21176610ejc.39.1675577470076; Sat, 04 Feb 2023 22:11:10 -0800 (PST) Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at. [85.127.52.93]) by smtp.gmail.com with ESMTPSA id a26-20020a17090640da00b0087851a76573sm3733737ejk.74.2023.02.04.22.11.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 04 Feb 2023 22:11:09 -0800 (PST) Message-ID: Subject: Re: [PATCH v6 2/3] services: mpd: Refactor MPD service. From: Liliana Marie Prikler To: Bruno Victal , 59866-done@debbugs.gnu.org Date: Sun, 05 Feb 2023 07:11:08 +0100 In-Reply-To: <88e71adf846525fbc1a964b24fb45e3e4b5c9208.camel@gmail.com> References: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@makinata.eu> <88e71adf846525fbc1a964b24fb45e3e4b5c9208.camel@gmail.com> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.46.0 MIME-Version: 1.0 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 59866-done X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Am Donnerstag, dem 02.02.2023 um 22:08 +0100 schrieb Liliana Marie Prikler: > Not a complete review yet, just some quick pointers. >=20 > Am Donnerstag, dem 02.02.2023 um 20:07 +0000 schrieb Bruno Victal: > > Refactor mpd-service-type to support additional mpd.conf directives > > and move activation-service-extension into service constructor. > >=20 > > * gnu/services/audio.scm > > (mpd-plugin, mpd-partition): New record. > No need to break the line before the paren here. >=20 > > (mpd-serialize-boolean, mpd-serialize-field): Integrate serializers > > into a single procedure for alist interop. > That's not a good docstring here.=C2=A0 I think=C2=A0 > =C2=A0 (mpd-serialize-boolean): Delete variable.=C2=A0 Move logic into... > =C2=A0 (mpd-serialize-field): ... this. > explains what's going on better. It actually didn't, because mpd-serialize-boolean wasn't deleted, but aliased. > > [...] > > =C2=A0=C2=A0 #:use-module (srfi srfi-1) > > +=C2=A0 #:use-module (srfi srfi-8) > > =C2=A0=C2=A0 #:use-module (srfi srfi-26) > We generally prefer SRFI 71. I fixed up the above, plus some compiler warnings and pushed it. Cheers From unknown Wed Jun 18 00:21:10 2025 Received: (at fakecontrol) by fakecontrolmessage; To: internal_control@debbugs.gnu.org From: Debbugs Internal Request Subject: Internal Control Message-Id: bug archived. Date: Sun, 05 Mar 2023 12:24:07 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator