From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from atuin.qyliss.net (localhost [IPv6:::1]) by atuin.qyliss.net (Postfix) with ESMTP id 9F9433C82; Tue, 29 Jul 2025 13:08:23 +0000 (UTC) Received: by atuin.qyliss.net (Postfix, from userid 993) id 8BAF93BF1; Tue, 29 Jul 2025 13:08:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on atuin.qyliss.net X-Spam-Level: * X-Spam-Status: No, score=1.2 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DMARC_MISSING,PDS_OTHER_BAD_TLD,RCVD_IN_DNSWL_LOW, SPF_HELO_PASS autolearn=no autolearn_force=no version=4.0.1 Received: from fout-a3-smtp.messagingengine.com (fout-a3-smtp.messagingengine.com [103.168.172.146]) by atuin.qyliss.net (Postfix) with ESMTPS id D941F3BF0 for ; Tue, 29 Jul 2025 13:08:17 +0000 (UTC) Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfout.phl.internal (Postfix) with ESMTP id E5C1FEC0227; Tue, 29 Jul 2025 09:08:16 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-01.internal (MEProxy); Tue, 29 Jul 2025 09:08:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alyssa.is; h=cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1753794496; x=1753880896; bh=wfdS2CxIoi G/xfntqeRliFtqgRR4X6Grvgs71J2WQV0=; b=nEnlPrM0nD1lOx24gkSgQdWMna TkO/6Lx9k/eXC+/Kz1lDlL2oyMv/+PGDeY2wA9O2TKF55/o00YC2xBwJt3hUMqJR X3H2tPyr0Aey8HDQ+FYG8YkTuHf+q2jiKwkCRdahb0OV20/yPBT+iR+CilgpiqbA RzDl1Es2JMCm4G7ucibzHob6GqWsTrJ9ga9SX1cgp1bBSeFJ0KRk4zS2F8XuYu65 SCb5R0TbPKpxluKYPvc7VBsIAA6iOnkuB91gz8o/0IOpOEEHvVfj1YKVnat5o74t 2eCU4sB87QVtHOwaEDttyprPkWhbDb2OES8sbaQtZv1p8mEE+0NCcZJyOJ+Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1753794496; x=1753880896; bh=wfdS2CxIoiG/xfntqeRliFtqgRR4X6Grvgs 71J2WQV0=; b=Ee5LBGLrW100WhOAjfLqgFlVRTiAmFuKW6cOKugfaP20YQ6maR+ hhGuK8h3UFifUG0lqVpVazKfgfUJ6MUPO1AB0GMARfY+PZnDOEFL211nbizIqzbV Hr+eTEaR/JhnngHauEY+bg17tsACBW9h6DiFTuLOiPYPX8/LtigYbTuoAi4RUtZp IhNCRyvYc5sRhoUocpmYU/ymtmWncn8jHeYnCIPJOX3eK152NWxwLqmue9GsDRqM vW/C09+Mt5kv2Jkc+2q78VeB+qWp44WAGfiYF5f3p86fEe0Fr7DNyIGh0P7PtuGw uyedFcDdhfbOZhwpU+N9I+3wuq2cgpgmQdw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdelhedufecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefhvffujghffffkgggtsehgtderredttdejnecuhfhrohhmpeetlhihshhsrgcutfho shhsuceohhhisegrlhihshhsrgdrihhsqeenucggtffrrghtthgvrhhnpeegfeektdeije fgveeigfeuveefgeeigffggeduffdvueevffetgeekueelvdelfeenucffohhmrghinhep shhhuhhtughofihnrdhfihhnrghlpdgtrghrugdrnhgrmhgvpdhptghmrdhsthhrvggrmh enucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehhihes rghlhihsshgrrdhishdpnhgspghrtghpthhtohepvddpmhhouggvpehsmhhtphhouhhtpd hrtghpthhtohepuggvmhhiohgsvghnohhurhesghhmrghilhdrtghomhdprhgtphhtthho peguvghvvghlsehsphgvtghtrhhumhdqohhsrdhorhhg X-ME-Proxy: Feedback-ID: i12284293:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 29 Jul 2025 09:08:16 -0400 (EDT) Received: by sf.qyliss.net (Postfix, from userid 1000) id 5B65B2DCA5C98; Tue, 29 Jul 2025 15:08:10 +0200 (CEST) From: Alyssa Ross To: Demi Marie Obenour , Spectrum OS Development Subject: Re: [PATCH v9 2/2] img/app: Run PipeWire and WirePlumber in the VMs In-Reply-To: <1139f3559979e28a38e99a0e9486d79dabb3d8a3.1753748336.git.demiobenour@gmail.com> References: <20250728231303.2416-1-demiobenour@gmail.com> <1139f3559979e28a38e99a0e9486d79dabb3d8a3.1753748336.git.demiobenour@gmail.com> Date: Tue, 29 Jul 2025 15:08:08 +0200 Message-ID: <875xfbdu13.fsf@alyssa.is> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" Message-ID-Hash: BDUKQH74IYMFEIO6KWMWVISNMVUA3FI2 X-Message-ID-Hash: BDUKQH74IYMFEIO6KWMWVISNMVUA3FI2 X-MailFrom: hi@alyssa.is X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-devel.spectrum-os.org-0; header-match-devel.spectrum-os.org-1; header-match-devel.spectrum-os.org-2; header-match-devel.spectrum-os.org-3; header-match-devel.spectrum-os.org-4; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.9 Precedence: list List-Id: Patches and low-level development discussion Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Demi Marie Obenour writes: > WirePlumber is completely overkill as a session manager here, and > ideally a trivial session manager would be used instead. PipeWire is > configured to listen on the PulseAudio socket, so PulseAudio > compatibility works. pw-record and pw-play both work, and if PulseAudio > is installed paplay and parecord also work. This does install a lot of > unnecessary files into the VMs, which will hopefully be removed > later as part of a debloating effort. > > Only run-qemu has had a virtio-sound device added, as crosvm and Cloud > Hypervisor require a virtio-user sound device and that is more complex > to set up. > > Signed-off-by: Demi Marie Obenour > --- > Changes since v8: > - Add longer explanation for the priority.driver and priority.session > values. > - Give credit to George Kiagiadakis. > - Fix spelling errors in comments. > > Changes since v7: > - Give the capture node a higher priority.session than the playback > node, so WirePlumber links recording applications to the capture node > instead of the monitor of the playback node. > - Give the capture node a higher priority.driver than the playback node, > so PipeWire has the capture node drive the graph. This is better > because capture xruns lead to permanently corrupted data, whereas > playback xruns do not. > - Re-enable monitor node creation in WirePlumber. > > Changes since v6: > - Fix spelling errors in commit messages. > - Sort lines in Makefile. > - Don't disable support.settings as a comment in wireplumber.conf says > to not do that. Instead, tell WirePlumber to not create monitor > nodes. This is a workaround for WirePlumber bug 829. > - Don't remove "-cpu host" from make run-qemu's QEMU command line. This > was needed for local testing with KVM disabled but should not have > been submitted upstream. Hardware with KVM support should be used > instead. > > Changes since v5: > > - Use a drop-in configuration file for WirePlumber instead of overriding > wireplumber.conf. This should be more robust to future WirePlumber > changes. > --- > img/app/Makefile | 16 +- > img/app/default.nix | 3 + > img/app/etc/mdev.conf | 1 + > img/app/etc/pipewire/pipewire.conf | 229 ++++++++++++++++++ > .../etc/s6-rc/app/dependencies.d/wireplumber | 0 > .../etc/s6-rc/pipewire/dependencies.d/dbus | 0 > img/app/etc/s6-rc/pipewire/notification-fd | 1 + > .../s6-rc/pipewire/notification-fd.license | 2 + > img/app/etc/s6-rc/pipewire/run | 23 ++ > img/app/etc/s6-rc/pipewire/type | 1 + > img/app/etc/s6-rc/pipewire/type.license | 2 + > .../etc/s6-rc/wireplumber/dependencies.d/dbus | 0 > .../s6-rc/wireplumber/dependencies.d/pipewire | 0 > img/app/etc/s6-rc/wireplumber/run | 4 + > img/app/etc/s6-rc/wireplumber/type | 1 + > img/app/etc/s6-rc/wireplumber/type.license | 2 + > .../wireplumber.conf.d/99_spectrum.conf | 42 ++++ > 17 files changed, 325 insertions(+), 2 deletions(-) > create mode 100644 img/app/etc/pipewire/pipewire.conf > create mode 100644 img/app/etc/s6-rc/app/dependencies.d/wireplumber > create mode 100644 img/app/etc/s6-rc/pipewire/dependencies.d/dbus > create mode 100644 img/app/etc/s6-rc/pipewire/notification-fd > create mode 100644 img/app/etc/s6-rc/pipewire/notification-fd.license > create mode 100644 img/app/etc/s6-rc/pipewire/run > create mode 100644 img/app/etc/s6-rc/pipewire/type > create mode 100644 img/app/etc/s6-rc/pipewire/type.license > create mode 100644 img/app/etc/s6-rc/wireplumber/dependencies.d/dbus > create mode 100644 img/app/etc/s6-rc/wireplumber/dependencies.d/pipewire > create mode 100644 img/app/etc/s6-rc/wireplumber/run > create mode 100644 img/app/etc/s6-rc/wireplumber/type > create mode 100644 img/app/etc/s6-rc/wireplumber/type.license > create mode 100644 img/app/etc/wireplumber/wireplumber.conf.d/99_spectru= m.conf We have app depending on wireplumber, but no notification-fd for wireplumber. What's actually required here? Does Wireplumber actually need to be running (for whatever definition thereof) by the time an application starts, or does it just need to start at some reasonable point? > diff --git a/img/app/Makefile b/img/app/Makefile > index 4b4d64f81d99a01eebe777f3737fef813ebb6d3f..c2186c9eba52207dfaa94f9ac= 8364a7dba844c34 100644 > --- a/img/app/Makefile > +++ b/img/app/Makefile > @@ -40,6 +40,7 @@ VM_FILES =3D \ > etc/mdev/virtiofs \ > etc/mdev/wait \ > etc/passwd \ > + etc/pipewire/pipewire.conf \ > etc/resolv.conf \ > etc/s6-linux-init/env/DBUS_SESSION_BUS_ADDRESS \ > etc/s6-linux-init/env/DISPLAY \ > @@ -47,13 +48,15 @@ VM_FILES =3D \ > etc/s6-linux-init/env/NIX_XDG_DESKTOP_PORTAL_DIR \ > etc/s6-linux-init/env/WAYLAND_DISPLAY \ > etc/s6-linux-init/env/XDG_RUNTIME_DIR \ > + etc/s6-linux-init/run-image/service/getty-hvc0/run \ > etc/s6-linux-init/run-image/service/s6-linux-init-shutdownd/notificatio= n-fd \ > etc/s6-linux-init/run-image/service/s6-linux-init-shutdownd/run \ > - etc/s6-linux-init/run-image/service/getty-hvc0/run \ > etc/s6-linux-init/scripts/rc.init \ > etc/s6-linux-init/scripts/rc.shutdown \ > etc/s6-linux-init/scripts/rc.shutdown.final \ > + etc/wireplumber/wireplumber.conf.d/99_spectrum.conf \ > etc/xdg/xdg-desktop-portal/portals.conf > + > VM_DIRS =3D dev run proc sys tmp \ > etc/s6-linux-init/run-image/service \ > etc/s6-linux-init/run-image/user \ > @@ -85,6 +88,7 @@ build/rootfs.erofs: ../../scripts/make-erofs.sh $(PACKA= GES_FILE) $(VM_FILES) $(V > VM_S6_RC_FILES =3D \ > etc/s6-rc/app/dependencies.d/dbus \ > etc/s6-rc/app/dependencies.d/wayland-proxy-virtwl \ > + etc/s6-rc/app/dependencies.d/wireplumber \ > etc/s6-rc/app/run \ > etc/s6-rc/app/type \ > etc/s6-rc/dbus/notification-fd \ > @@ -98,9 +102,16 @@ VM_S6_RC_FILES =3D \ > etc/s6-rc/mdevd/type \ > etc/s6-rc/ok-all/contents \ > etc/s6-rc/ok-all/type \ > + etc/s6-rc/pipewire/notification-fd \ > + etc/s6-rc/pipewire/run \ > + etc/s6-rc/pipewire/type \ > etc/s6-rc/wayland-proxy-virtwl/notification-fd \ > etc/s6-rc/wayland-proxy-virtwl/run \ > - etc/s6-rc/wayland-proxy-virtwl/type > + etc/s6-rc/wayland-proxy-virtwl/type \ > + etc/s6-rc/wireplumber/dependencies.d/dbus \ > + etc/s6-rc/wireplumber/dependencies.d/pipewire \ > + etc/s6-rc/wireplumber/run \ > + etc/s6-rc/wireplumber/type >=20=20 > build/etc/s6-rc: $(VM_S6_RC_FILES) > mkdir -p $$(dirname $@) > @@ -147,6 +158,7 @@ run-qemu: $(imgdir)/appvm/blk/root.img start-vhost-us= er-net start-virtiofsd > -chardev socket,id=3Dvirtiofsd,path=3Dbuild/virtiofsd.sock \ > -device vhost-user-fs-pci,chardev=3Dvirtiofsd,tag=3Dvirtiofs0 \ > -device virtio-gpu-rutabaga-pci,cross-domain=3Don,hostmem=3D8G \ > + -audio driver=3Dpipewire,model=3Dvirtio \ > -object memory-backend-memfd,id=3Dmem,size=3D256M,share=3Don \ > -numa node,memdev=3Dmem \ > -device vhost-vsock-pci,guest-cid=3D3 \ > diff --git a/img/app/default.nix b/img/app/default.nix > index 740643ac41f6473cdb6f6b0fd1f5f47f4493240d..d3eed1f0accdc8968d1ba5bde= c74ab597789082f 100644 > --- a/img/app/default.nix > +++ b/img/app/default.nix > @@ -48,6 +48,9 @@ let > pkgs.xwayland > pkgs.xdg-desktop-portal > pkgs.xdg-desktop-portal-gtk > + # Depends on pulseaudio libs > + pkgs.pipewire > + pkgs.wireplumber > ]; > })).fhsenv; > in > diff --git a/img/app/etc/mdev.conf b/img/app/etc/mdev.conf > index f2101e1f683c49808358b25520080c59ed2afa8e..0e4a1a088522c05da9e0ce15f= e135c40d6cf3064 100644 > --- a/img/app/etc/mdev.conf > +++ b/img/app/etc/mdev.conf > @@ -5,3 +5,4 @@ > $INTERFACE=3D.* 0:0 660 ! +/etc/mdev/iface > $MODALIAS=3Dvirtio:d0000001Av.* 0:0 660 ! +/etc/mdev/virtiofs > dri/card0 0:0 660 +background { /etc/mdev/listen card0 } > +snd/controlC0 0:0 660 +background { /etc/mdev/listen controlC0 } > diff --git a/img/app/etc/pipewire/pipewire.conf b/img/app/etc/pipewire/pi= pewire.conf > new file mode 100644 > index 0000000000000000000000000000000000000000..0dceb81ed46d3c264c6b12d9a= 1141e1b1b2135b7 > --- /dev/null > +++ b/img/app/etc/pipewire/pipewire.conf > @@ -0,0 +1,229 @@ > +# SPDX-License-Identifier: MIT > + > +# Copyright =C2=A9 2018 Wim Taymans > +# Copyright =C2=A9 2025 Demi Marie Obenour > +# > +# Permission is hereby granted, free of charge, to any person obtaining a > +# copy of this software and associated documentation files (the "Softwar= e"), > +# to deal in the Software without restriction, including without limitat= ion > +# the rights to use, copy, modify, merge, publish, distribute, sublicens= e, > +# and/or sell copies of the Software, and to permit persons to whom the > +# Software is furnished to do so, subject to the following conditions: > +# > +# The above copyright notice and this permission notice (including the n= ext > +# paragraph) shall be included in all copies or substantial portions of = the > +# Software. > +# > +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRES= S OR > +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILIT= Y, > +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHA= LL > +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR O= THER > +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > +# DEALINGS IN THE SOFTWARE. > + > +# This file is based on the upstream default configuration. This can be > +# found in upstream GitLab or in any distro with a recent version of Pip= eWire. > +# The following changes have been made: > +# > +# - Conditions that have known values in Spectrum VMs are omitted. > +# - Modules for hardware devices Spectrum VMs don't have are not loaded. > +# - The PulseAudio emulation server is loaded. > +# - Settings for VMs are applied unconditionally. > +# - Most comments in the upstream files have been removed. > +# - Device nodes for virtio-sound devices have been added. > +# - Integration with udev and logind is removed. > +context.properties =3D { > + # Upstream defaults. > + link.max-buffers =3D 16 > + core.daemon =3D true > + core.name =3D pipewire-0 > + # Account for running in a VM > + default.clock.min-quantum =3D 1024 > +} > + > +# Upstream defaults, with support for AVB, V4L2, libcamera > +# bluez, Vulkan, JACK, and video conversion omitted. > +context.spa-libs =3D { > + audio.convert.* =3D audioconvert/libspa-audioconvert > + api.alsa.* =3D alsa/libspa-alsa > + support.* =3D support/libspa-support > +} > + > +context.modules =3D [ > + # Upstream defaults > + { name =3D libpipewire-module-rt > + args =3D { nice.level =3D -11, rt.prio =3D 88 } > + } > + { name =3D libpipewire-module-protocol-native } > + { name =3D libpipewire-module-metadata } > + { name =3D libpipewire-module-spa-device-factory } > + { name =3D libpipewire-module-spa-node-factory } > + { name =3D libpipewire-module-client-node } > + { name =3D libpipewire-module-access } > + { name =3D libpipewire-module-client-device } > + { name =3D libpipewire-module-portal } > + { name =3D libpipewire-module-adapter } > + { name =3D libpipewire-module-link-factory } > + { name =3D libpipewire-module-session-manager } > + > + # Load the PulseAudio server into PipeWire. > + # This avoids needing a separate pipewire-pulse > + # process. The args are those used when running > + # in a VM. > + { name =3D libpipewire-module-protocol-pulse > + args =3D { > + server.address =3D [ "unix:native" ] > + pulse.min.quantum =3D 1024/48000 > + } > + } > +] > + > +context.objects =3D [ > + # Upstream defaults > + { factory =3D spa-node-factory > + args =3D { > + factory.name =3D support.node.driver > + node.name =3D Dummy-Driver > + node.group =3D pipewire.dummy > + node.sync-group =3D sync.dummy > + priority.driver =3D 200000 > + } > + } > + { factory =3D spa-node-factory > + args =3D { > + factory.name =3D support.node.driver > + node.name =3D Freewheel-Driver > + priority.driver =3D 190000 > + node.group =3D pipewire.freewheel > + node.sync-group =3D sync.dummy > + node.freewheel =3D true > + } > + } > + > + # Spectrum doesn't use udev, so device nodes must be created statica= lly. > + # Creating them with pw-cli works as long as pw-cli is running, but > + # the nodes are destroyed when pw-cli exits. > + # > + # PipeWire chooses the node with the highest priority.driver value as > + # graph driver, which is the node that decides when the processing g= raph > + # is going to run. If both the capture node and playback node are in > + # the same graph, the capture node should be chosen as the driver. = This > + # is because the driver gets to choose the rate of the graph and so = is > + # much less likely to xrun. Since capture xruns result in corrupted > + # audio recordings, while playback xruns just result in a glitch, it > + # is more important to avoid capture xruns. > + # > + # When there are multiple sources or sinks that could be used, > + # WirePlumber links application nodes to the one with the highest > + # priority.session value. In the configuration created here, > + # there are two valid audio sources: the virtio sound card's > + # capture stream and the monitor of its playback stream. The > + # capture stream is the correct choice, so its priority.session > + # should be higher. > + # > + # The recommendation to give the capture device higher values > + # for priority.driver and priority.session comes from George > + # Kiagiadakis of Collabora, who also provided the values > + # used (2000 and 1000) and why they must be different. > + # The explanation for why it is more important to avoid > + # capture xruns than playback xruns comes from past discussions > + # that I (Demi Marie Obenour) had with Wim Taymans. Just checking: they're okay with being credited, right? (Important for me to be confident before mentioning anybody in an immutable log.) > + { factory =3D adapter > + args =3D { > + alsa.card =3D 0, > + alsa.card_name =3D "VirtIO SoundCard" > + alsa.device =3D 0 > + alsa.driver_name =3D "virtio_snd" > + alsa.id =3D "SoundCard" > + alsa.long_card_name =3D "VirtIO SoundCard at pci/0000:00:= 01.0/virtio0" > + alsa.name =3D "VirtIO SoundCard" > + alsa.subdevice =3D 0 > + alsa.subdevice_name =3D "subdevice #0" > + api.alsa.card.longname =3D "VirtIO SoundCard at pci/0000:00:= 01.0/virtio0" > + api.alsa.card.name =3D "VirtIO SoundCard" > + api.alsa.headroom =3D 0 > + api.alsa.path =3D "hw:0,0,0" > + api.alsa.pcm.card =3D 0, > + api.alsa.pcm.stream =3D "playback" > + audio.allowed-rates =3D [ ] > + audio.channels =3D 2 > + audio.format =3D "S32" > + audio.position =3D "FL,FR" > + audio.rate =3D 48000 > + factory.name =3D "api.alsa.pcm.sink" > + media.class =3D "Audio/Sink" > + node.name =3D "alsa_output.pci-0000_00_01.0.ana= log-stereo" > + node.suspend-on-idle =3D true > + priority.driver =3D 1000 > + priority.session =3D 1000 > + } > + } > + > + { factory =3D adapter > + args =3D { > + alsa.card =3D 0, > + alsa.card_name =3D "VirtIO SoundCard" > + alsa.device =3D 0 > + alsa.driver_name =3D "virtio_snd" > + alsa.id =3D "SoundCard" > + alsa.long_card_name =3D "VirtIO SoundCard at pci/0000:00:= 01.0/virtio0" > + alsa.name =3D "VirtIO SoundCard" > + alsa.subdevice =3D 0 > + alsa.subdevice_name =3D "subdevice #0" > + api.alsa.card.longname =3D "VirtIO SoundCard at pci/0000:00:= 01.0/virtio0" > + api.alsa.card.name =3D "VirtIO SoundCard" > + api.alsa.headroom =3D 0 > + api.alsa.path =3D "hw:0,0,0" > + api.alsa.pcm.card =3D 0, > + api.alsa.pcm.stream =3D "capture" > + audio.allowed-rates =3D [ ] > + audio.channels =3D 2 > + audio.format =3D "S32" > + audio.position =3D "FL,FR" > + audio.rate =3D 48000 > + factory.name =3D "api.alsa.pcm.source" > + media.class =3D "Audio/Source" > + node.name =3D "alsa_input.pci-0000_00_01.0.anal= og-stereo" > + node.suspend-on-idle =3D true > + priority.driver =3D 2000 > + priority.session =3D 2000 > + } > + } > +] > + > +# Load the modules that are in the default config *except* > +# for ones whose job is to maintain state. > +pulse.cmd =3D [ > + { cmd =3D "load-module" args =3D "module-always-sink" flags =3D [ ] } > + { cmd =3D "load-module" args =3D "module-device-manager" flags =3D [= ] } > +] > + > +# More default stuff. > +pulse.rules =3D [ > + { > + matches =3D [ > + { application.process.binary =3D "teams" } > + { application.process.binary =3D "teams-insiders" } > + { application.process.binary =3D "teams-for-linux" } > + { application.process.binary =3D "skypeforlinux" } > + ] > + actions =3D { quirks =3D [ force-s16-info ] } > + } > + { > + matches =3D [ { application.process.binary =3D "firefox" } ] > + actions =3D { quirks =3D [ remove-capture-dont-move ] } > + } > + { > + matches =3D [ { application.name =3D "~speech-dispatcher.*" } ] > + actions =3D { > + update-props =3D { > + pulse.min.req =3D 512/48000 > + pulse.min.quantum =3D 512/48000 > + pulse.idle.timeout =3D 5 > + } > + } > + } > +] > + > +context.exec =3D [] > diff --git a/img/app/etc/s6-rc/app/dependencies.d/wireplumber b/img/app/e= tc/s6-rc/app/dependencies.d/wireplumber > new file mode 100644 > index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae7= 75ad8c2e48c5391 > diff --git a/img/app/etc/s6-rc/pipewire/dependencies.d/dbus b/img/app/etc= /s6-rc/pipewire/dependencies.d/dbus > new file mode 100644 > index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae7= 75ad8c2e48c5391 > diff --git a/img/app/etc/s6-rc/pipewire/notification-fd b/img/app/etc/s6-= rc/pipewire/notification-fd > new file mode 100644 > index 0000000000000000000000000000000000000000..7ed6ff82de6bcc2a78243fc9c= 54d3ef5ac14da69 > --- /dev/null > +++ b/img/app/etc/s6-rc/pipewire/notification-fd > @@ -0,0 +1 @@ > +5 > diff --git a/img/app/etc/s6-rc/pipewire/notification-fd.license b/img/app= /etc/s6-rc/pipewire/notification-fd.license > new file mode 100644 > index 0000000000000000000000000000000000000000..c4a0586a407fe14c3e0855749= a7524ac3871dda4 > --- /dev/null > +++ b/img/app/etc/s6-rc/pipewire/notification-fd.license > @@ -0,0 +1,2 @@ > +SPDX-License-Identifier: CC0-1.0 > +SPDX-FileCopyrightText: 2025 Demi Marie Obenour > diff --git a/img/app/etc/s6-rc/pipewire/run b/img/app/etc/s6-rc/pipewire/= run > new file mode 100644 > index 0000000000000000000000000000000000000000..c5cf090fb4779e0f3ede1782a= da5c95ce5b25702 > --- /dev/null > +++ b/img/app/etc/s6-rc/pipewire/run > @@ -0,0 +1,23 @@ > +#!/bin/execlineb -P > +# SPDX-License-Identifier: EUPL-1.2+ > +# SPDX-FileCopyrightText: 2023-2024 Alyssa Ross > +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour > + > +s6-ipcserver-socketbinder -B /run/user/0/pipewire-0 > +fdmove -c 3 0 > + > +s6-ipcserver-socketbinder -B /run/user/0/pipewire-0-manager > +fdmove -c 4 0 > + > +redirfd -r 0 /dev/null > + > +# Wait for sound devices to be available > +if { /etc/mdev/wait controlC0 } > + > +# Notify readiness. > +if { fdmove 1 5 echo } > +fdclose 5 We could move this earlier, right? If things connect before the sound devices are available, PipeWire won't have been started yet so the connection will just not be accepted until they are. > + > +export LISTEN_FDS 2 > +getpid LISTEN_PID > +pipewire > diff --git a/img/app/etc/s6-rc/pipewire/type b/img/app/etc/s6-rc/pipewire= /type > new file mode 100644 > index 0000000000000000000000000000000000000000..5883cff0cd1514b2836f4ffa3= 9fdac769a5213cb > --- /dev/null > +++ b/img/app/etc/s6-rc/pipewire/type > @@ -0,0 +1 @@ > +longrun > diff --git a/img/app/etc/s6-rc/pipewire/type.license b/img/app/etc/s6-rc/= pipewire/type.license > new file mode 100644 > index 0000000000000000000000000000000000000000..c4a0586a407fe14c3e0855749= a7524ac3871dda4 > --- /dev/null > +++ b/img/app/etc/s6-rc/pipewire/type.license > @@ -0,0 +1,2 @@ > +SPDX-License-Identifier: CC0-1.0 > +SPDX-FileCopyrightText: 2025 Demi Marie Obenour > diff --git a/img/app/etc/s6-rc/wireplumber/dependencies.d/dbus b/img/app/= etc/s6-rc/wireplumber/dependencies.d/dbus > new file mode 100644 > index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae7= 75ad8c2e48c5391 > diff --git a/img/app/etc/s6-rc/wireplumber/dependencies.d/pipewire b/img/= app/etc/s6-rc/wireplumber/dependencies.d/pipewire > new file mode 100644 > index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae7= 75ad8c2e48c5391 > diff --git a/img/app/etc/s6-rc/wireplumber/run b/img/app/etc/s6-rc/wirepl= umber/run > new file mode 100644 > index 0000000000000000000000000000000000000000..d58f1971c7387c896256a91ad= 0c92386a02fd9e2 > --- /dev/null > +++ b/img/app/etc/s6-rc/wireplumber/run > @@ -0,0 +1,4 @@ > +#!/bin/execlineb -P > +# SPDX-License-Identifier: EUPL-1.2+ > +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour > +wireplumber --profile spectrum > diff --git a/img/app/etc/s6-rc/wireplumber/type b/img/app/etc/s6-rc/wirep= lumber/type > new file mode 100644 > index 0000000000000000000000000000000000000000..5883cff0cd1514b2836f4ffa3= 9fdac769a5213cb > --- /dev/null > +++ b/img/app/etc/s6-rc/wireplumber/type > @@ -0,0 +1 @@ > +longrun > diff --git a/img/app/etc/s6-rc/wireplumber/type.license b/img/app/etc/s6-= rc/wireplumber/type.license > new file mode 100644 > index 0000000000000000000000000000000000000000..c4a0586a407fe14c3e0855749= a7524ac3871dda4 > --- /dev/null > +++ b/img/app/etc/s6-rc/wireplumber/type.license > @@ -0,0 +1,2 @@ > +SPDX-License-Identifier: CC0-1.0 > +SPDX-FileCopyrightText: 2025 Demi Marie Obenour > diff --git a/img/app/etc/wireplumber/wireplumber.conf.d/99_spectrum.conf = b/img/app/etc/wireplumber/wireplumber.conf.d/99_spectrum.conf > new file mode 100644 > index 0000000000000000000000000000000000000000..277e6019c46582afba12af9b1= a27bb16ddd9e804 > --- /dev/null > +++ b/img/app/etc/wireplumber/wireplumber.conf.d/99_spectrum.conf > @@ -0,0 +1,42 @@ > +# SPDX-License-Identifier: MIT > +# SPDX-FileCopyrightText: 2019-2021 Collabora Ltd. > +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour > + > +# Copyright =C2=A9 2019-2021 Collabora Ltd. Once again I'm surprised any of this is =C2=A9 Collabora=E2=80=A6 > +# > +# Permission is hereby granted, free of charge, to any person obtaining a > +# copy of this software and associated documentation files (the "Softwar= e"), > +# to deal in the Software without restriction, including without limitat= ion > +# the rights to use, copy, modify, merge, publish, distribute, sublicens= e, > +# and/or sell copies of the Software, and to permit persons to whom the > +# Software is furnished to do so, subject to the following conditions: > +# > +# The above copyright notice and this permission notice (including the n= ext > +# paragraph) shall be included in all copies or substantial portions of = the > +# Software. > +# > +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRES= S OR > +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILIT= Y, > +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHA= LL > +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR O= THER > +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > +# DEALINGS IN THE SOFTWARE. > + > +wireplumber.profiles =3D { > + spectrum =3D { > + # Spectrum VMs are essentially embedded systems, in that they are > + # not at all general-purpose. > + inherits =3D [ main-embedded ] > + # Disable video and Bluetooth > + hardware.video-capture =3D disabled > + hardware.bluetooth =3D disabled > + # Media Session is definitely not running > + check.no-media-session =3D disabled > + } > +} > + > +wireplumber.settings =3D { > + # Default to 100% sink volume. The host will adjust this as needed. > + device.routes.default-sink-volume =3D 1.0 > +} --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iHUEARYKAB0WIQRV/neXydHjZma5XLJbRZGEIw/wogUCaIjHuAAKCRBbRZGEIw/w ok/7AP0fBdaVFYeOhT/0yfxZPO4dTgjIEtXRh5AaAv6msb+PPAEA0KpRdLbiGB+l aQ1hTJ5sNc2g04xfhCpvDXlDSLYwhAE= =lG+U -----END PGP SIGNATURE----- --=-=-=--