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 D72CF23405; Mon, 28 Jul 2025 06:03:37 +0000 (UTC) Received: by atuin.qyliss.net (Postfix, from userid 993) id 6474F233CD; Mon, 28 Jul 2025 06:03:35 +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.9 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DMARC_PASS,FREEMAIL_FROM,PDS_OTHER_BAD_TLD, RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=no autolearn_force=no version=4.0.1 Received: from mail-qk1-x732.google.com (mail-qk1-x732.google.com [IPv6:2607:f8b0:4864:20::732]) by atuin.qyliss.net (Postfix) with ESMTPS id 6924123372 for ; Mon, 28 Jul 2025 06:03:33 +0000 (UTC) Received: by mail-qk1-x732.google.com with SMTP id af79cd13be357-7df981428abso643297585a.1 for ; Sun, 27 Jul 2025 23:03:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1753682612; x=1754287412; darn=spectrum-os.org; h=content-transfer-encoding:autocrypt:cc:to:in-reply-to :content-language:references:subject:from:user-agent:mime-version :date:message-id:from:to:cc:subject:date:message-id:reply-to; bh=ZsrKQKCeg9T7M1q6dq4b/7hcXsbyccO89a4b2lU5uok=; b=MK1MWaekteIS258hsFqxDvh66p6jLJUA5feaKudffo3u0TjVKh4vTBK7244vB4PqZk Rw0UHYtbueaMNf1LehMxL2Vf4PvsQInkM5I9GDLLKvv0Z435Q9vwvjnO/fAPOiAESC1Y +xdLWNFZ4JXY4JBbR438njjIX/L6SKYDzihFlf54X92lXZJzsra68O7YS1auBRzty1Rx RgGgSsH1gPpewgeR1kjECdxyZzgNm89HWJkAMrG2pDA7N06yPdU8nRe/Cz+GQD3+Gng2 LbAyvCulCPFYAb/XHwqDtYdU6nYdldvN4kPSnKRjpozZY4Xswx98KGsKcALRr/LzqKp1 utLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753682612; x=1754287412; h=content-transfer-encoding:autocrypt:cc:to:in-reply-to :content-language:references:subject:from:user-agent:mime-version :date:message-id:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=ZsrKQKCeg9T7M1q6dq4b/7hcXsbyccO89a4b2lU5uok=; b=KTABFvzWM1t6uYkOm9GdSXHfXa4PHvnxg7HCvWZ4fH0pRWcDrjCtVmQxX9A9DQJXiu 5w/jP90cJKh9xgO4mld7jf/xMG4k9Qdfuu6Dwv7SfdEZFgO1onhoC0TM8sz+X3T16jCw tlnfm5RuQ7lrhBgVIjmyhGMetMi+2hXHuqX3PUcEb7qmxzK/hYXFoMxrYngch0HbZaaB WNve4PBIcFhF/IRCrVc2U3UBQDj+IPIKafUPgqh235oieiQpE7GLp2Ge3qENiPPUzFTu KgwASVNL2iGPVHnYXzXQ5h+hCoi7agKRsuJaIujNkc6BbRxXwqNQswraaDlylrqQV5W5 KiIg== X-Gm-Message-State: AOJu0YwoJFPkll0tcRKRgc3RwfXHdRwa/GioUTMjOCs5354ZsyIlUEMX 6F7zVqCjbCq/9Uk7v8e54XuPk+Ydze+iBynzxLSUSyo6KyX95h3+XBMsHqF7ZA== X-Gm-Gg: ASbGncv7O59IioPM9zP6CSWHSF2EaWKk7H7qtRareEUnI2Nx+zptXbdXOBTeO0nKd8o UIyeOdGOeFVgvWORysP2QgIzXQDh8dtQjrM4dhvhK2lhfcnTbsSzAg8XxMOE/rAn/3bDqp1Kgzu yJFof3qXv6UHKOq2IfegByxx2q0Vh1jE5cWEXbLiKQqOmV+L39GJywDnxsCbkl2CiM9WD7hob6f MYKVUMs7xe9ROltd1Uh2WPJRQpklj8TOAgBg60UEj0mbg3jA8rAyJ4GHjOXpgk8VYloWMcDB41n FBLqTOMDql9/y77SgjZArYOQ8reymBRrIUaMrcTFQW82OF2xMB47edwBW11BBypzx09dnX8OHm/ 3kTyS5FMrAGVa+ZrhCZ+UA5t7mhw= X-Google-Smtp-Source: AGHT+IHJd3TKA2OaO41gT6oj/wh1lVYV5/5UGZJnnyd9TPZToMa6xDo5ICdNqb6y15VYMMXYdBvMAA== X-Received: by 2002:a05:620a:4e55:b0:7e6:2417:e429 with SMTP id af79cd13be357-7e63bfc4471mr1130430985a.41.1753682611743; Sun, 27 Jul 2025 23:03:31 -0700 (PDT) Received: from [10.138.10.6] ([89.187.178.201]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e64327d41esm260071785a.15.2025.07.27.23.03.30 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 27 Jul 2025 23:03:31 -0700 (PDT) Message-ID: <40464bdd-6326-4521-9ccd-bb5cf31439a1@gmail.com> Date: Mon, 28 Jul 2025 02:03:30 -0400 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Demi Marie Obenour Subject: [PATCH v7 2/2] img/app: Run PipeWire and WirePlumber in the VMs References: <263f81f2-9e86-4bb1-be80-41f7731a9a63@gmail.com> Content-Language: en-US In-Reply-To: <263f81f2-9e86-4bb1-be80-41f7731a9a63@gmail.com> To: Spectrum OS Development Autocrypt: addr=demiobenour@gmail.com; keydata= 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 +MYSfkEjBz0E8CLOcAw7JIwAaeBT Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-ID-Hash: UW2M3YZWTA2O643644KR37NR5AHCTELA X-Message-ID-Hash: UW2M3YZWTA2O643644KR37NR5AHCTELA X-MailFrom: demiobenour@gmail.com 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 CC: Alyssa Ross 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: 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. If WirePlumber is allowed to enable monitor nodes for the ALSA output device, WirePlumber prefers the monitor over the ALSA input device [1]. This breaks audio recording. To work around this, set node.features.audio.monitor-ports to false. 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. [1]: https://gitlab.freedesktop.org/pipewire/wireplumber/-/issues/829 Signed-off-by: Demi Marie Obenour --- Changes since v6: - Fix spelling errors in commit message. - 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. The copyright notice on the WirePlumber drop-in was kept because it is based on fragments in the upstream config file and because when in doubt, keeping the copyright notice is always safer. Changes since v5: - Remove "directories" service in favor of creating the directories from rc.init. - 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 | 199 ++++++++++++++++++ .../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 | 45 ++++ 17 files changed, 298 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_spectrum.conf diff --git a/img/app/Makefile b/img/app/Makefile index 4b4d64f81d99a01eebe777f3737fef813ebb6d3f..c2186c9eba52207dfaa94f9ac8364a7dba844c34 100644 --- a/img/app/Makefile +++ b/img/app/Makefile @@ -40,6 +40,7 @@ VM_FILES = \ 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 = \ 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/notification-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 = 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 $(PACKAGES_FILE) $(VM_FILES) $(V VM_S6_RC_FILES = \ 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 = \ 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 build/etc/s6-rc: $(VM_S6_RC_FILES) mkdir -p $$(dirname $@) @@ -147,6 +158,7 @@ run-qemu: $(imgdir)/appvm/blk/root.img start-vhost-user-net start-virtiofsd -chardev socket,id=virtiofsd,path=build/virtiofsd.sock \ -device vhost-user-fs-pci,chardev=virtiofsd,tag=virtiofs0 \ -device virtio-gpu-rutabaga-pci,cross-domain=on,hostmem=8G \ + -audio driver=pipewire,model=virtio \ -object memory-backend-memfd,id=mem,size=256M,share=on \ -numa node,memdev=mem \ -device vhost-vsock-pci,guest-cid=3 \ diff --git a/img/app/default.nix b/img/app/default.nix index 740643ac41f6473cdb6f6b0fd1f5f47f4493240d..d3eed1f0accdc8968d1ba5bdec74ab597789082f 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..0e4a1a088522c05da9e0ce15fe135c40d6cf3064 100644 --- a/img/app/etc/mdev.conf +++ b/img/app/etc/mdev.conf @@ -5,3 +5,4 @@ $INTERFACE=.* 0:0 660 ! +/etc/mdev/iface $MODALIAS=virtio: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/pipewire.conf new file mode 100644 index 0000000000000000000000000000000000000000..e5a413a409f46e7fe176102bbd6780db14f85dba --- /dev/null +++ b/img/app/etc/pipewire/pipewire.conf @@ -0,0 +1,199 @@ +# SPDX-License-Identifier: MIT + +# Copyright © 2018 Wim Taymans +# Copyright © 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 "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# 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 next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# 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 PipeWire. +# 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 = { + # Upstream defaults. + link.max-buffers = 16 + core.daemon = true + core.name = pipewire-0 + # Account for running in a VM + default.clock.min-quantum = 1024 +} + +# Upstream defaults, with support for AVB, V4L2, libcamera +# bluez, Vulkan, JACK, and video conversion omitted. +context.spa-libs = { + audio.convert.* = audioconvert/libspa-audioconvert + api.alsa.* = alsa/libspa-alsa + support.* = support/libspa-support +} + +context.modules = [ + # Upstream defaults + { name = libpipewire-module-rt + args = { nice.level = -11, rt.prio = 88 } + } + { name = libpipewire-module-protocol-native } + { name = libpipewire-module-metadata } + { name = libpipewire-module-spa-device-factory } + { name = libpipewire-module-spa-node-factory } + { name = libpipewire-module-client-node } + { name = libpipewire-module-access } + { name = libpipewire-module-client-device } + { name = libpipewire-module-portal } + { name = libpipewire-module-adapter } + { name = libpipewire-module-link-factory } + { name = 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 = libpipewire-module-protocol-pulse + args = { + server.address = [ "unix:native" ] + pulse.min.quantum = 1024/48000 + } + } +] + +context.objects = [ + # Upstream defaults + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Dummy-Driver + node.group = pipewire.dummy + node.sync-group = sync.dummy + priority.driver = 200000 + } + } + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Freewheel-Driver + priority.driver = 190000 + node.group = pipewire.freewheel + node.sync-group = sync.dummy + node.freewheel = true + } + } + + # Spectrum doesn't use udev, so device nodes must be created statically. + # Creating them with pw-cli works as long as pw-cli is running, but + # the nodes are destroyed when pw-cli exits. + { factory = adapter + args = { + alsa.card = 0, + alsa.card_name = "VirtIO SoundCard" + alsa.device = 0 + alsa.driver_name = "virtio_snd" + alsa.id = "SoundCard" + alsa.long_card_name = "VirtIO SoundCard at pci/0000:00:01.0/virtio0" + alsa.name = "VirtIO SoundCard" + alsa.subdevice = 0 + alsa.subdevice_name = "subdevice #0" + api.alsa.card.longname = "VirtIO SoundCard at pci/0000:00:01.0/virtio0" + api.alsa.card.name = "VirtIO SoundCard" + api.alsa.headroom = 0 + api.alsa.path = "hw:0,0,0" + api.alsa.pcm.card = 0, + api.alsa.pcm.stream = "playback" + audio.allowed-rates = [ ] + audio.channels = 2 + audio.format = "S32" + audio.position = "FL,FR" + audio.rate = 48000 + factory.name = "api.alsa.pcm.sink" + media.class = "Audio/Sink" + node.name = "alsa_output.pci-0000_00_01.0.analog-stereo" + node.suspend-on-idle = true + } + } + { factory = adapter + args = { + alsa.card = 0, + alsa.card_name = "VirtIO SoundCard" + alsa.device = 0 + alsa.driver_name = "virtio_snd" + alsa.id = "SoundCard" + alsa.long_card_name = "VirtIO SoundCard at pci/0000:00:01.0/virtio0" + alsa.name = "VirtIO SoundCard" + alsa.subdevice = 0 + alsa.subdevice_name = "subdevice #0" + api.alsa.card.longname = "VirtIO SoundCard at pci/0000:00:01.0/virtio0" + api.alsa.card.name = "VirtIO SoundCard" + api.alsa.headroom = 0 + api.alsa.path = "hw:0,0,0" + api.alsa.pcm.card = 0, + api.alsa.pcm.stream = "capture" + audio.allowed-rates = [ ] + audio.channels = 2 + audio.format = "S32" + audio.position = "FL,FR" + audio.rate = 48000 + factory.name = "api.alsa.pcm.source" + media.class = "Audio/Source" + node.name = "alsa_input.pci-0000_00_01.0.analog-stereo" + node.suspend-on-idle = true + } + } +] + +# Load the modules that are in the default config *except* +# for ones whose job is to maintain state. +pulse.cmd = [ + { cmd = "load-module" args = "module-always-sink" flags = [ ] } + { cmd = "load-module" args = "module-device-manager" flags = [ ] } +] + +# More default stuff. +pulse.rules = [ + { + matches = [ + { application.process.binary = "teams" } + { application.process.binary = "teams-insiders" } + { application.process.binary = "teams-for-linux" } + { application.process.binary = "skypeforlinux" } + ] + actions = { quirks = [ force-s16-info ] } + } + { + matches = [ { application.process.binary = "firefox" } ] + actions = { quirks = [ remove-capture-dont-move ] } + } + { + matches = [ { application.name = "~speech-dispatcher.*" } ] + actions = { + update-props = { + pulse.min.req = 512/48000 + pulse.min.quantum = 512/48000 + pulse.idle.timeout = 5 + } + } + } +] + +context.exec = [] diff --git a/img/app/etc/s6-rc/app/dependencies.d/wireplumber b/img/app/etc/s6-rc/app/dependencies.d/wireplumber new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 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..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 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..7ed6ff82de6bcc2a78243fc9c54d3ef5ac14da69 --- /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..c4a0586a407fe14c3e0855749a7524ac3871dda4 --- /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..c5cf090fb4779e0f3ede1782ada5c95ce5b25702 --- /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 + +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..5883cff0cd1514b2836f4ffa39fdac769a5213cb --- /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..c4a0586a407fe14c3e0855749a7524ac3871dda4 --- /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..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 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..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/img/app/etc/s6-rc/wireplumber/run b/img/app/etc/s6-rc/wireplumber/run new file mode 100644 index 0000000000000000000000000000000000000000..d58f1971c7387c896256a91ad0c92386a02fd9e2 --- /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/wireplumber/type new file mode 100644 index 0000000000000000000000000000000000000000..5883cff0cd1514b2836f4ffa39fdac769a5213cb --- /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..c4a0586a407fe14c3e0855749a7524ac3871dda4 --- /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..75672bc4e2acc90dfc481905e6ce71615977dc0d --- /dev/null +++ b/img/app/etc/wireplumber/wireplumber.conf.d/99_spectrum.conf @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2019-2021 Collabora Ltd. +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour + +# Copyright © 2019-2021 Collabora Ltd. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# 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 next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# 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 = { + spectrum = { + # Spectrum VMs are essentially embedded systems, in that they are + # not at all general-purpose. + inherits = [ main-embedded ] + # Disable video and Bluetooth + hardware.video-capture = disabled + hardware.bluetooth = disabled + # Media Session is definitely not running + check.no-media-session = disabled + } +} + +wireplumber.settings = { + # Default to 100% sink volume. The host will adjust this as needed. + device.routes.default-sink-volume = 1.0 + # Disable monitor ports so WirePlumber cannot select them: + # https://gitlab.freedesktop.org/pipewire/wireplumber/-/issues/829 + node.features.audio.monitor-ports = false +} -- Sincerely, Demi Marie Obenour (she/her/hers)