sound.scm 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2018, 2020 Oleg Pykhalov <go.wigust@gmail.com>
  3. ;;; Copyright © 2020 Liliana Marie Prikler <liliana.prikler@gmail.com>
  4. ;;; Copyright © 2020 Marius Bakke <mbakke@fastmail.com>
  5. ;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  21. (define-module (gnu services sound)
  22. #:use-module (gnu services base)
  23. #:use-module (gnu services configuration)
  24. #:use-module (gnu services shepherd)
  25. #:use-module (gnu services)
  26. #:use-module (gnu system pam)
  27. #:use-module (gnu system shadow)
  28. #:use-module (guix diagnostics)
  29. #:use-module (guix gexp)
  30. #:use-module (guix packages)
  31. #:use-module (guix records)
  32. #:use-module (guix store)
  33. #:use-module (guix ui)
  34. #:use-module (gnu packages audio)
  35. #:use-module (gnu packages linux)
  36. #:use-module (gnu packages pulseaudio)
  37. #:use-module (ice-9 match)
  38. #:use-module (srfi srfi-1)
  39. #:export (alsa-configuration
  40. alsa-configuration?
  41. alsa-configuration-alsa-plugins
  42. alsa-configuration-pulseaudio?
  43. alsa-configuration-extra-options
  44. alsa-service-type
  45. pulseaudio-configuration
  46. pulseaudio-configuration?
  47. pulseaudio-configuration-client-conf
  48. pulseaudio-configuration-daemon-conf
  49. pulseaudio-configuration-script-file
  50. pulseaudio-configuration-extra-script-files
  51. pulseaudio-configuration-system-script-file
  52. pulseaudio-service-type
  53. ladspa-configuration
  54. ladspa-configuration?
  55. ladspa-configuration-plugins
  56. ladspa-service-type))
  57. ;;; Commentary:
  58. ;;;
  59. ;;; Sound services.
  60. ;;;
  61. ;;; Code:
  62. ;;;
  63. ;;; ALSA
  64. ;;;
  65. (define-record-type* <alsa-configuration>
  66. alsa-configuration make-alsa-configuration alsa-configuration?
  67. (alsa-plugins alsa-configuration-alsa-plugins ;file-like
  68. (default alsa-plugins))
  69. (pulseaudio? alsa-configuration-pulseaudio? ;boolean
  70. (default #t))
  71. (extra-options alsa-configuration-extra-options ;string
  72. (default "")))
  73. (define alsa-config-file
  74. ;; Return the ALSA configuration file.
  75. (match-lambda
  76. (($ <alsa-configuration> alsa-plugins pulseaudio? extra-options)
  77. (apply mixed-text-file "asound.conf"
  78. `("# Generated by 'alsa-service'.\n\n"
  79. ,@(if pulseaudio?
  80. `("# Use PulseAudio by default
  81. pcm_type.pulse {
  82. lib \"" ,#~(string-append #$alsa-plugins:pulseaudio
  83. "/lib/alsa-lib/libasound_module_pcm_pulse.so") "\"
  84. }
  85. ctl_type.pulse {
  86. lib \"" ,#~(string-append #$alsa-plugins:pulseaudio
  87. "/lib/alsa-lib/libasound_module_ctl_pulse.so") "\"
  88. }
  89. pcm.!default {
  90. type pulse
  91. fallback \"sysdefault\"
  92. hint {
  93. show on
  94. description \"Default ALSA Output (currently PulseAudio Sound Server)\"
  95. }
  96. }
  97. ctl.!default {
  98. type pulse
  99. fallback \"sysdefault\"
  100. }\n\n")
  101. '())
  102. ,extra-options)))))
  103. (define (alsa-etc-service config)
  104. (list `("asound.conf" ,(alsa-config-file config))))
  105. (define alsa-service-type
  106. (service-type
  107. (name 'alsa)
  108. (extensions
  109. (list (service-extension etc-service-type alsa-etc-service)))
  110. (default-value (alsa-configuration))
  111. (description "Configure low-level Linux sound support, ALSA.")))
  112. ;;;
  113. ;;; PulseAudio
  114. ;;;
  115. (define-record-type* <pulseaudio-configuration>
  116. pulseaudio-configuration make-pulseaudio-configuration
  117. pulseaudio-configuration?
  118. (client-conf pulseaudio-configuration-client-conf
  119. (default '()))
  120. (daemon-conf pulseaudio-configuration-daemon-conf
  121. ;; Flat volumes may cause unpleasant experiences to users
  122. ;; when applications inadvertently max out the system volume
  123. ;; (see e.g. <https://bugs.gnu.org/38172>).
  124. (default '((flat-volumes . no))))
  125. (script-file pulseaudio-configuration-script-file
  126. (default (file-append pulseaudio "/etc/pulse/default.pa")))
  127. (extra-script-files pulseaudio-configuration-extra-script-files
  128. (default '()))
  129. (system-script-file pulseaudio-configuration-system-script-file
  130. (default
  131. (file-append pulseaudio "/etc/pulse/system.pa"))))
  132. (define (pulseaudio-conf-entry arg)
  133. (match arg
  134. ((key . value)
  135. (format #f "~a = ~s~%" key value))
  136. ((? string? _)
  137. (string-append arg "\n"))))
  138. (define pulseaudio-environment
  139. (match-lambda
  140. (($ <pulseaudio-configuration> client-conf daemon-conf default-script-file)
  141. ;; These config files kept at a fixed location, so that the following
  142. ;; environment values are stable and do not require the user to reboot to
  143. ;; effect their PulseAudio configuration changes.
  144. '(("PULSE_CONFIG" . "/etc/pulse/daemon.conf")
  145. ("PULSE_CLIENTCONFIG" . "/etc/pulse/client.conf")))))
  146. (define (extra-script-files->file-union extra-script-files)
  147. "Return a G-exp obtained by processing EXTRA-SCRIPT-FILES with FILE-UNION."
  148. (define (file-like->name file)
  149. (match file
  150. ((? local-file?)
  151. (local-file-name file))
  152. ((? plain-file?)
  153. (plain-file-name file))
  154. ((? computed-file?)
  155. (computed-file-name file))
  156. (_ (leave (G_ "~a is not a local-file, plain-file or \
  157. computed-file object~%") file))))
  158. (define (assert-pulseaudio-script-file-name name)
  159. (unless (string-suffix? ".pa" name)
  160. (leave (G_ "`~a' lacks the required `.pa' file name extension~%") name))
  161. name)
  162. (let ((labels (map (compose assert-pulseaudio-script-file-name
  163. file-like->name)
  164. extra-script-files)))
  165. (file-union "default.pa.d" (zip labels extra-script-files))))
  166. (define (append-include-directive script-file)
  167. "Append an include directive to source scripts under /etc/pulse/default.pa.d."
  168. (computed-file "default.pa"
  169. #~(begin
  170. (use-modules (ice-9 textual-ports))
  171. (define script-text
  172. (call-with-input-file #$script-file get-string-all))
  173. (call-with-output-file #$output
  174. (lambda (port)
  175. (format port (string-append script-text "
  176. ### Added by Guix to include scripts specified in extra-script-files.
  177. .nofail
  178. .include /etc/pulse/default.pa.d~%")))))))
  179. (define pulseaudio-etc
  180. (match-lambda
  181. (($ <pulseaudio-configuration> client-conf daemon-conf default-script-file
  182. extra-script-files system-script-file)
  183. `(("pulse"
  184. ,(file-union
  185. "pulse"
  186. `(("default.pa"
  187. ,(if (null? extra-script-files)
  188. default-script-file
  189. (append-include-directive default-script-file)))
  190. ("system.pa" ,system-script-file)
  191. ,@(if (null? extra-script-files)
  192. '()
  193. `(("default.pa.d" ,(extra-script-files->file-union
  194. extra-script-files))))
  195. ("daemon.conf"
  196. ,(apply mixed-text-file "daemon.conf"
  197. "default-script-file = /etc/pulse/default.pa\n"
  198. (map pulseaudio-conf-entry daemon-conf)))
  199. ("client.conf"
  200. ,(apply mixed-text-file "client.conf"
  201. (map pulseaudio-conf-entry client-conf))))))))))
  202. (define pulseaudio-service-type
  203. (service-type
  204. (name 'pulseaudio)
  205. (extensions
  206. (list (service-extension session-environment-service-type
  207. pulseaudio-environment)
  208. (service-extension etc-service-type pulseaudio-etc)
  209. (service-extension udev-service-type (const (list pulseaudio)))))
  210. (default-value (pulseaudio-configuration))
  211. (description "Configure PulseAudio sound support.")))
  212. ;;;
  213. ;;; LADSPA
  214. ;;;
  215. (define-record-type* <ladspa-configuration>
  216. ladspa-configuration make-ladspa-configuration
  217. ladspa-configuration?
  218. (plugins ladspa-configuration-plugins (default '())))
  219. (define (ladspa-environment config)
  220. ;; Define this variable in the global environment such that
  221. ;; pulseaudio swh-plugins (and similar LADSPA plugins) work.
  222. `(("LADSPA_PATH" .
  223. (string-join
  224. ',(map (lambda (package) (file-append package "/lib/ladspa"))
  225. (ladspa-configuration-plugins config))
  226. ":"))))
  227. (define ladspa-service-type
  228. (service-type
  229. (name 'ladspa)
  230. (extensions
  231. (list (service-extension session-environment-service-type
  232. ladspa-environment)))
  233. (default-value (ladspa-configuration))
  234. (description "Configure LADSPA plugins.")))
  235. ;;; sound.scm ends here