From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id +Kh9OzUVo2PJQQAAbAwnHQ (envelope-from ) for ; Wed, 21 Dec 2022 15:16:22 +0100 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id cAaAOzUVo2PoggEA9RJhRA (envelope-from ) for ; Wed, 21 Dec 2022 15:16:21 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 81BD4214B8 for ; Wed, 21 Dec 2022 15:16:21 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p7zt7-0000ND-IY; Wed, 21 Dec 2022 09:16:05 -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 1p7zt4-0000EO-Qo for guix-patches@gnu.org; Wed, 21 Dec 2022 09:16:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p7zt4-0008Ki-If for guix-patches@gnu.org; Wed, 21 Dec 2022 09:16:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1p7zt3-0006Yc-Vh for guix-patches@gnu.org; Wed, 21 Dec 2022 09:16:01 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#59866] [PATCH v4 1/2] services: mpd: use 'define-configuration'. References: In-Reply-To: Resent-From: mirai@makinata.eu Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Wed, 21 Dec 2022 14:16:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 59866 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 59866@debbugs.gnu.org Cc: Bruno Victal Received: via spool by 59866-submit@debbugs.gnu.org id=B59866.167163215125200 (code B ref 59866); Wed, 21 Dec 2022 14:16:01 +0000 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 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-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Seal: i=1; s=key1; d=yhetil.org; t=1671632181; a=rsa-sha256; cv=none; b=nPBeS0MHLvzLkdSQG4H1h0Tv5bWsh+F3jg1BhHKh0377uxLxorHCddJ1O4mxoAAK7EpGGx SAOnQR21Y+pcWUQsa6zw7ND/2/cc5TQFKa6FzEnELZyNvzIr08r7zRZjQjd54QgI0u+emw 1RwsJyFiCTx2by6q3zVIcVAsf5u07uPWsSym7TCEDWOc+r5XjytEgtBXGHs+Fwgwj+HQmx LRB3TOBjplcG9NfQa2jRcWT0d4aZGE3NUaVW7j1SyJIWzTJqK2KwYRT8HxJkeLNfNAW59B 4ziAQzXRYX7mFgZ5dgYIxEUyUa8LLO1huPp6a+ij95D5JBGrSS7kCu5f1VV+hw== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=none; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1671632181; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post; bh=fPK9uWnnCs2LcnY99Nxh37Oje0W/13eopfLovJwu7P4=; b=OLEeQitTrR7M07ETrQVGuUJCVA0ts29nkp/sBZnp6NUA6wJqOCI29VV5GMFYSmfGhNZwOp iddpW488zK0kj9H1iJ3PoDXkCRVH1IdoMojpFeBXWA1H56RZ9UTZIQt7TvWGS8RYahvLTY 99N08PRm4eV/lk8hdVvEKJRH1gwKIXJo2Ce0sdJSF0J1Od0Wp6q5eMbE9pTIyEUz0yE2Yg EjSqBKa1mbcgdzuz++5YNNPXfqxlE2Sbp7Qougn81pB5KelPjbArtT2MbYQvd3AluNGWoI cZHP9lv9PUmGYzNrdtGNhEqwacDzn+2aDZVyUyy0VsN5rXnv4oObesYywbpKbQ== X-Spam-Score: -2.99 X-Migadu-Queue-Id: 81BD4214B8 Authentication-Results: aspmx1.migadu.com; dkim=none; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=none X-Migadu-Scanner: scn0.migadu.com X-Migadu-Spam-Score: -2.99 X-TUID: O+zwFs/1Mt1v 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