home: services: Add 'pulseaudio-rtp-sink' and 'pulseaudio-rtp-source'.
* gnu/home/services/sound.scm: New file. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. * doc/guix.texi (Sound Home Services): New section.master
parent
833febb522
commit
674d893316
114
doc/guix.texi
114
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}
|
||||
|
||||
|
|
|
@ -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)))
|
|
@ -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 \
|
||||
|
|
Reference in New Issue