aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi114
-rw-r--r--gnu/home/services/sound.scm151
-rw-r--r--gnu/local.mk3
3 files changed, 258 insertions, 10 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 74658dbc86..6671ba9305 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41679,15 +41679,16 @@ service with the @code{simple-service} procedure from @code{(gnu
services)}.
@menu
-* Essential Home Services:: Environment variables, packages, on-* scripts.
-* Shells: Shells Home Services. POSIX shells, Bash, Zsh.
-* Mcron: Mcron Home Service. Scheduled User's Job Execution.
-* Power Management: Power Management Home Services. Services for battery power.
-* Shepherd: Shepherd Home Service. Managing User's Daemons.
-* SSH: Secure Shell. Setting up the secure shell client.
-* Desktop: Desktop Home Services. Services for graphical environments.
-* Guix: Guix Home Services. Services for Guix.
-* Fonts: Fonts Home Services. Services for managing User's fonts.
+* Essential Home Services:: Environment variables, packages, on-* scripts.
+* Shells: Shells Home Services. POSIX shells, Bash, Zsh.
+* Mcron: Mcron Home Service. Scheduled User's Job Execution.
+* Power Management: Power Management Home Services. Services for battery power.
+* Shepherd: Shepherd Home Service. Managing User's Daemons.
+* SSH: Secure Shell. Setting up the secure shell client.
+* Desktop: Desktop Home Services. Services for graphical environments.
+* Guix: Guix Home Services. Services for Guix.
+* Fonts: Fonts Home Services. Services for managing User's fonts.
+* Sound: Sound Home Services. Dealing with audio.
@end menu
@c In addition to that Home Services can provide
@@ -42601,6 +42602,101 @@ like this:
@end lisp
@end defvar
+@node Sound Home Services
+@subsection Sound Home Services
+
+The @code{(gnu home services sound)} module provides services related to
+sound support.
+
+@cindex PulseAudio, home service
+@cindex RTP, for PulseAudio
+
+The following services dynamically reconfigure the
+@uref{https://pulseaudio.org,PulseAudio sound server}: they let you
+toggle broadcast of audio output over the network using the
+@acronym{RTP, real-time transport protocol} and, correspondingly,
+playback of sound received over RTP. Once
+@code{home-pulseaudio-rtp-sink-service-type} is among your home
+services, you can start broadcasting audio output by running this
+command:
+
+@example
+herd start pulseaudio-rtp-sink
+@end example
+
+You can then run a PulseAudio-capable mixer, such as @code{pavucontrol}
+or @code{pulsemixer} (both from the same-named package) to control which
+audio stream(s) should be sent to the RTP ``sink''.
+
+By default, audio is broadcasted to a multicast address: any device on
+the @acronym{LAN, local area network} receives it and may play it.
+Using multicast in this way puts a lot of pressure on the network and
+degrades its performance, so you may instead prefer sending to
+specifically one device. The first way to do that is by specifying the
+IP address of the target device when starting the service:
+
+@example
+herd start pulseaudio-rtp-sink 192.168.1.42
+@end example
+
+The other option is to specify this IP address as the one to use by
+default in your home environment configuration:
+
+@lisp
+(service home-pulseaudio-rtp-sink-service-type
+ "192.168.1.42")
+@end lisp
+
+On the device where you intend to receive and play the RTP stream, you
+can use @code{home-pulseaudio-rtp-source-service-type}, like so:
+
+@lisp
+(service home-pulseaudio-rtp-source-service-type)
+@end lisp
+
+This will then let you start the receiving module for PulseAudio:
+
+@example
+herd start pulseaudio-rtp-source
+@end example
+
+Again, by default it will listen on the multicast address. If, instead,
+you'd like it to listen for direct incoming connections, you can do that
+by running:
+
+@lisp
+(service home-pulseaudio-rtp-source-service-type
+ "0.0.0.0")
+@end lisp
+
+The reference of these services is given below.
+
+@defvar home-pulseaudio-rtp-sink-service-type
+@defvarx home-pulseaudio-rtp-source-service-type
+This is the type of the service to send, respectively receive, audio
+streams over @acronym{RTP, real-time transport protocol}.
+
+The value associated with this service is the IP address (a string)
+where to send, respectively receive, the audio stream. By default,
+audio is sent/received on multicast address
+@code{%pulseaudio-rtp-multicast-address}.
+
+This service defines one Shepherd service: @code{pulseaudio-rtp-sink},
+respectively @code{pulseaudio-rtp-source}. The service is not started
+by default, so you have to explicitly start it when you want to turn it
+on, as in this example:
+
+@example
+herd start pulseaudio-rtp-sink
+@end example
+
+Stopping the Shepherd service turns off broadcasting.
+@end defvar
+
+@defvar %pulseaudio-rtp-multicast-address
+This is the multicast address used by default by the two services above.
+@end defvar
+
@node Invoking guix home
@section Invoking @command{guix home}
diff --git a/gnu/home/services/sound.scm b/gnu/home/services/sound.scm
new file mode 100644
index 0000000000..22c1a99250
--- /dev/null
+++ b/gnu/home/services/sound.scm
@@ -0,0 +1,151 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home services sound)
+ #:use-module (gnu home services)
+ #:use-module (gnu home services shepherd)
+ #:use-module (guix records)
+ #:use-module (guix gexp)
+ #:use-module (srfi srfi-1)
+ #:use-module (ice-9 match)
+ #:export (home-pulseaudio-rtp-sink-service-type
+ home-pulseaudio-rtp-source-service-type
+ %pulseaudio-rtp-multicast-address))
+
+
+;;;
+;;; PulseAudio support.
+;;;
+
+(define (with-pulseaudio-connection sock exp)
+ ;; Wrap EXP in an expression where SOCK is bound to a socket connected to
+ ;; the user's PulseAudio command-line interface socket.
+ #~(let* ((#$sock (socket AF_UNIX SOCK_STREAM 0))
+ (pulse-user-file
+ (lambda (name)
+ (string-append "/run/user/" (number->string (getuid))
+ "/pulse/" name)))
+ (file (pulse-user-file "cli")))
+ (let loop ((tries 0))
+ (catch #t
+ (lambda ()
+ (connect #$sock AF_UNIX file)
+ (let ((result #$exp))
+ (close-port #$sock)
+ result))
+ (lambda (key . args)
+ (if (and (eq? key 'system-error)
+ (= ENOENT (system-error-errno (cons key args)))
+ (< tries 3))
+ ;; The CLI socket doesn't exist yet, so send pulseaudio
+ ;; SIGUSR2 so that it creates it and listens to it.
+ (let ((pid (call-with-input-file (pulse-user-file "pid")
+ read)))
+ (when (and (integer? pid) (> pid 1))
+ (kill pid SIGUSR2))
+ ((@ (fibers) sleep) 1)
+ (loop (+ tries 1)))
+ (begin
+ (close-port #$sock)
+ (apply throw key args))))))))
+
+(define %pulseaudio-rtp-multicast-address
+ ;; Default address used by 'module-rtp-sink' and 'module-rtp-recv'. This is
+ ;; a multicast address, for the Session Announcement Protocol (SAP) and the
+ ;; Session Description Protocol (SDP).
+ "224.0.0.56")
+
+(define (pulseaudio-rtp-sink-shepherd-services destination-ip)
+ (list (shepherd-service
+ (provision '(pulseaudio-rtp-sink))
+ (start
+ #~(lambda* (#:optional (destination-ip #$destination-ip))
+ #$(with-pulseaudio-connection
+ #~sock
+ #~(begin
+ (display "\
+load-module module-null-sink \
+sink_name=rtp sink_properties=\"device.description='RTP network output'\"\n"
+ sock)
+ (display (string-append "\
+load-module module-rtp-send source=rtp.monitor"
+ (if destination-ip
+ (string-append
+ " destination_ip="
+ destination-ip)
+ "")
+ "\n")
+ sock)
+ #t))))
+ (stop
+ #~(lambda (_)
+ #$(with-pulseaudio-connection
+ #~sock
+ #~(begin
+ (display "unload-module module-rtp-send\n"
+ sock)
+ (display "unload-module module-null-sink\n"
+ sock)
+ #f))))
+ (auto-start? #f))))
+
+(define home-pulseaudio-rtp-sink-service-type
+ (service-type
+ (name 'pulseaudio-rtp-sink)
+ (extensions
+ (list (service-extension home-shepherd-service-type
+ pulseaudio-rtp-sink-shepherd-services)))
+ (description
+ "Define a PulseAudio sink to broadcast audio output over RTP, which can
+then by played by another PulseAudio instance.")
+
+ ;; By default, send to the SAP multicast address, 224.0.0.56, which can be
+ ;; network-intensive.
+ (default-value %pulseaudio-rtp-multicast-address)))
+
+(define (pulseaudio-rtp-source-shepherd-services source-ip)
+ (list (shepherd-service
+ (provision '(pulseaudio-rtp-source))
+ (start
+ #~(lambda* (#:optional (source-ip #$source-ip))
+ #$(with-pulseaudio-connection
+ #~sock
+ #~(begin
+ (format sock "\
+load-module module-rtp-recv sap_address=~a\n" source-ip)
+ #t))))
+ (stop
+ #~(lambda (_)
+ #$(with-pulseaudio-connection
+ #~sock
+ #~(begin
+ (display "unload-module module-rtp-recv\n"
+ sock)
+ #f))))
+ (auto-start? #f))))
+
+(define home-pulseaudio-rtp-source-service-type
+ (service-type
+ (name 'pulseaudio-rtp-source)
+ (extensions
+ (list (service-extension home-shepherd-service-type
+ pulseaudio-rtp-source-shepherd-services)))
+ (description
+ "Define a PulseAudio source to receive audio broadcasted over RTP by
+another PulseAudio instance.")
+ (default-value %pulseaudio-rtp-multicast-address)))
diff --git a/gnu/local.mk b/gnu/local.mk
index e286e0b076..70dab40087 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1,5 +1,5 @@
# GNU Guix --- Functional package management for GNU
-# Copyright © 2012-2021, 2021-2022 Ludovic Courtès <ludo@gnu.org>
+# Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2022 Andreas Enge <andreas@enge.fr>
# Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
# Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Mark H Weaver <mhw@netris.org>
@@ -94,6 +94,7 @@ GNU_SYSTEM_MODULES = \
%D%/home/services/pm.scm \
%D%/home/services/shells.scm \
%D%/home/services/shepherd.scm \
+ %D%/home/services/sound.scm \
%D%/home/services/ssh.scm \
%D%/home/services/mcron.scm \
%D%/home/services/utils.scm \