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 CC272F3BD; Thu, 24 Jul 2025 22:36:59 +0000 (UTC) Received: by atuin.qyliss.net (Postfix, from userid 993) id 1854CF374; Thu, 24 Jul 2025 22:36:57 +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-qt1-x82f.google.com (mail-qt1-x82f.google.com [IPv6:2607:f8b0:4864:20::82f]) by atuin.qyliss.net (Postfix) with ESMTPS id BE144F3A6 for ; Thu, 24 Jul 2025 22:36:55 +0000 (UTC) Received: by mail-qt1-x82f.google.com with SMTP id d75a77b69052e-4ab5aec969eso28472721cf.3 for ; Thu, 24 Jul 2025 15:36:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1753396615; x=1754001415; 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=TrtfUDE6fGjhaAxYmCzhydtZXFeNBuTFRQjaQBLmbnM=; b=ZjrPTniQX4g9TXLw7GlRiOUq9A3sgdKJhpiQYIRQDhTLMd5IAJ41rnfR4TZacS0SSO vaFMx+faZ2v+SM5ZaT4CGNvtPlNkCuPqDa8lhRPcFH7IbB4QhHkMzus6mT++Y9T+Gmzw fD2Cxc7jGm1c2lQ/Z4NHVvQiOrLlXDA7ygdWACtKI+cY3u/970m7ZsmL8PJFkjpwuzuc TpYvIey53/gjA3PXmpTbFF+7dw2Pg/2uU4pO5KQe22a8faidmPjF0nwi6+wmsjnFAXIw SbETSQ1xNVeT/Jc+ll7aY5O7E+Fy0IFVUtqieMHafr+Y0c8gvYXFdwlU5kvS5np0rjpr HNRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753396615; x=1754001415; 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=TrtfUDE6fGjhaAxYmCzhydtZXFeNBuTFRQjaQBLmbnM=; b=LPuM7ATSaZrwnQLGKtxdrPfS10hBsjtnljxtbMQn5kXDXHczEuP+Xjrb4W/Q9l47uM kYPXGLYMAp/+/ufeAN+ars4pMvlZAacDLyGUB9/I9A5T2J4oYPLWDH7oMvo9dl2AjUyT kAn8W1WAIBdh/NdiB4IbhATsNUvdgYfclu3P/uIbFeU6QKPXKBYX8upwhUvtG2QrKJks mLivMdSb/Jz/FHaksK5qZ+S5X3yNtSI99whgZBYd1IQzeBWzHw6iFDQw0JeINFvjKXnh IYs+EoXlpUfxa5hVQ1QNt1L3dIhwYHz7jum6SVRLlfe0Y3KmjerHy//uVK/KS5RQlpED SzRQ== X-Gm-Message-State: AOJu0Yzpeu8SWQerPlYtdwWfPNh6sCq0Gi8pTEj2RxF9e8DWaXBlBhY0 DZfjS01Dai5KqnYHT2n3XChcqQ8mHUX2Tg0VVVmMD04TNOU+rRLQmxlM5POXRQ== X-Gm-Gg: ASbGncsdZCzXW88iBHRsBPUZexZvLLulWgZGs2Z9X/U9D14vISVIdU7xXX3/xK63ILZ cSfbkIcIW5YVnp66kI/pqYmntEM6t5uvExSqHVeiWrsvg+9lU6DnEF45BiJrpxPZzh4bxUvVcxu dooFzKNbv/PnwIYRYVS0eQasIuol3q2+o3gk0hZ2GHydyD249r/NUvDQyMmUrypPUJn8otdrUkS 3EknBhy/1YVwhgqTEqWneJRaAF9mSn5Y7xMqhSbHswXC2m0XEhldx9lpVJHCD3L23oBDcJvM6iS fm3C3o07XGQp2BOaXV+1EcIrwbdHOsgawVk3QC65LQ1c2oqhqVLXeW+cAjXaj7KHEVIWxEeLVnY nyhUbLcRgPjGW/rIwyUMm9sM9Y6c= X-Google-Smtp-Source: AGHT+IGINCNI3rvTqmq3+o2bHGaKLkf55iFz280paDUrXXtMfYqtCci/fI+LwxeCu9OqiEQ8hBRpnA== X-Received: by 2002:ac8:5cc5:0:b0:4ab:1a4a:1cfc with SMTP id d75a77b69052e-4ae6dece587mr120545791cf.22.1753396614450; Thu, 24 Jul 2025 15:36:54 -0700 (PDT) Received: from [10.138.10.6] ([89.187.178.201]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-4ae7e51790bsm17104671cf.38.2025.07.24.15.36.53 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 24 Jul 2025 15:36:53 -0700 (PDT) Message-ID: <5286585c-360a-4ef3-a6fc-752a5963d855@gmail.com> Date: Thu, 24 Jul 2025 18:36:52 -0400 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird From: Demi Marie Obenour Subject: [PATCH v6 5/5] img/app: Run PipeWire and WirePlumber in the VMs References: <2862317f-1419-4405-870d-f7631bcd1d2a@gmail.com> Content-Language: en-US In-Reply-To: <2862317f-1419-4405-870d-f7631bcd1d2a@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: PXG2HZJLMOFPBVSHMFGYRCCWOODNAZAW X-Message-ID-Hash: PXG2HZJLMOFPBVSHMFGYRCCWOODNAZAW 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. Signed-off-by: Demi Marie Obenour --- img/app/Makefile | 18 +- 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 | 39 ++++ 17 files changed, 293 insertions(+), 3 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..69bc9afc0756b0628ddc1fe53913a75b45b3213b 100644 --- a/img/app/Makefile +++ b/img/app/Makefile @@ -53,7 +53,10 @@ VM_FILES = \ etc/s6-linux-init/scripts/rc.init \ etc/s6-linux-init/scripts/rc.shutdown \ etc/s6-linux-init/scripts/rc.shutdown.final \ - etc/xdg/xdg-desktop-portal/portals.conf + etc/xdg/xdg-desktop-portal/portals.conf \ + etc/pipewire/pipewire.conf \ + etc/wireplumber/wireplumber.conf.d/99_spectrum.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 $@) @@ -137,7 +148,7 @@ start-virtiofsd: scripts/start-virtiofsd.elb .PHONY: start-virtiofsd run-qemu: $(imgdir)/appvm/blk/root.img start-vhost-user-net start-virtiofsd - @../../scripts/run-qemu.sh -m 256 -cpu host -kernel $(KERNEL) -vga none \ + @../../scripts/run-qemu.sh -m 256 -kernel $(KERNEL) -vga none \ -drive file=$(imgdir)/appvm/blk/root.img,if=virtio,format=raw,readonly=on \ -append "root=PARTLABEL=root nokaslr" \ -gdb unix:build/gdb.sock,server,nowait \ @@ -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..ff2f464395aaf7c8f0a739b0f01552c4ee987740 --- /dev/null +++ b/img/app/etc/wireplumber/wireplumber.conf.d/99_spectrum.conf @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: MIT + +# 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. + +# Disable various stuff Spectrum doesn't need and which causes errors. +wireplumber.profiles = { + spectrum = { + inherits = [ main-embedded ] + hardware.video-capture = disabled + hardware.bluetooth = disabled + support.settings = disabled + check.no-media-session = disabled + policy.standard = required + } +} + +# Default to 100% sink volume. The host will adjust this as needed. +wireplumber.settings = { + device.routes.default-sink-volume = 1.0 +} -- Sincerely, Demi Marie Obenour (she/her/hers)