From 7c9e805cbe43667267af0c8a14c15ac32269b71e Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 28 Apr 2026 10:25:12 -0400 Subject: [PATCH] port audioservice fix --- quickshell/Services/AudioService.qml | 33 +++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/quickshell/Services/AudioService.qml b/quickshell/Services/AudioService.qml index 20293d95..fa940b2b 100644 --- a/quickshell/Services/AudioService.qml +++ b/quickshell/Services/AudioService.qml @@ -71,6 +71,36 @@ Singleton { return Pipewire.nodes.values.filter(node => node.audio && node.isSink && !node.isStream && !hidden.includes(node.name)); } + // Resolve a PwNode by name from the live typed list and assign it as the + // default sink. Going through Pipewire.nodes.values directly (no .filter + // / spread / .sort / property var) avoids QML type erasure to QObject*, + // which newer quickshell rejects when assigning to preferredDefaultAudioSink. + function setDefaultSinkByName(name) { + if (!name) + return false; + for (let i = 0; i < Pipewire.nodes.values.length; i++) { + const node = Pipewire.nodes.values[i]; + if (node && node.name === name && node.audio && node.isSink && !node.isStream) { + Pipewire.preferredDefaultAudioSink = node; + return true; + } + } + return false; + } + + function setDefaultSourceByName(name) { + if (!name) + return false; + for (let i = 0; i < Pipewire.nodes.values.length; i++) { + const node = Pipewire.nodes.values[i]; + if (node && node.name === name && node.audio && !node.isSink && !node.isStream) { + Pipewire.preferredDefaultAudioSource = node; + return true; + } + } + return false; + } + function cycleAudioOutput() { const sinks = getAvailableSinks(); if (sinks.length < 2) @@ -80,7 +110,8 @@ Singleton { const currentIndex = sinks.findIndex(s => s.name === currentName); const nextIndex = (currentIndex + 1) % sinks.length; const nextSink = sinks[nextIndex]; - Pipewire.preferredDefaultAudioSink = nextSink; + if (!setDefaultSinkByName(nextSink.name)) + Pipewire.preferredDefaultAudioSink = nextSink; const name = displayName(nextSink); audioOutputCycled(name, sinkIcon(nextSink)); return name;