Expose live application audio groups
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
import "services/AudioStreams.js" as AudioStreams
|
import "services/AudioStreams.js" as AudioStreams
|
||||||
|
import qs.services
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
readonly property int audioOutStreamFlag: 4
|
readonly property int audioOutStreamFlag: 4
|
||||||
@@ -112,5 +114,23 @@ ShellRoot {
|
|||||||
muted: chromium.nodes.map(node => node.audio.muted)
|
muted: chromium.nodes.map(node => node.audio.muted)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function serviceSummary(): string {
|
||||||
|
const applications = AudioDevices.applications;
|
||||||
|
return JSON.stringify({
|
||||||
|
count: applications.length,
|
||||||
|
validTypes: applications.every(application =>
|
||||||
|
application.nodes.every(node =>
|
||||||
|
(node.type & PwNodeType.AudioOutStream)
|
||||||
|
=== PwNodeType.AudioOutStream))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function invalidMutations(): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
nullVolume: AudioDevices.setApplicationVolume(null, 0.5),
|
||||||
|
emptyMute: AudioDevices.setApplicationMuted({ nodes: [] }, true)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import Quickshell
|
|||||||
import Quickshell.Services.Pipewire
|
import Quickshell.Services.Pipewire
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
|
import "AudioStreams.js" as AudioStreams
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -18,6 +20,13 @@ Singleton {
|
|||||||
!node.isStream
|
!node.isStream
|
||||||
&& (node.type & PwNodeType.AudioSource) === PwNodeType.AudioSource)
|
&& (node.type & PwNodeType.AudioSource) === PwNodeType.AudioSource)
|
||||||
|
|
||||||
|
readonly property var playbackStreams: Pipewire.nodes.values.filter(node =>
|
||||||
|
node.ready && node.audio
|
||||||
|
&& (node.type & PwNodeType.AudioOutStream) === PwNodeType.AudioOutStream)
|
||||||
|
|
||||||
|
readonly property var applications: AudioStreams.group(
|
||||||
|
root.playbackStreams, PwNodeType.AudioOutStream)
|
||||||
|
|
||||||
function nodes(output: bool): var {
|
function nodes(output: bool): var {
|
||||||
return output ? root.outputs : root.inputs;
|
return output ? root.outputs : root.inputs;
|
||||||
}
|
}
|
||||||
@@ -40,4 +49,20 @@ Singleton {
|
|||||||
return "Unknown device";
|
return "Unknown device";
|
||||||
return node.description || node.nickname || node.name || "Unknown device";
|
return node.description || node.nickname || node.name || "Unknown device";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applicationVolume(application: var): real {
|
||||||
|
return AudioStreams.volume(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applicationMuted(application: var): bool {
|
||||||
|
return AudioStreams.muted(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setApplicationVolume(application: var, value: real): bool {
|
||||||
|
return AudioStreams.setVolume(application, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setApplicationMuted(application: var, muted: bool): bool {
|
||||||
|
return AudioStreams.setMuted(application, muted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,14 @@ mute_result="$(qs_for_harness ipc call application-volume-test mutateMute)"
|
|||||||
jq -e '.changed == true and .muted == [true, true]' <<<"$mute_result" >/dev/null \
|
jq -e '.changed == true and .muted == [true, true]' <<<"$mute_result" >/dev/null \
|
||||||
|| fail "mute mutation did not reach every stream: $mute_result"
|
|| fail "mute mutation did not reach every stream: $mute_result"
|
||||||
|
|
||||||
|
service_summary="$(qs_for_harness ipc call application-volume-test serviceSummary)"
|
||||||
|
jq -e '.count >= 0 and .validTypes == true' <<<"$service_summary" >/dev/null \
|
||||||
|
|| fail "live service exposed invalid playback groups: $service_summary"
|
||||||
|
|
||||||
|
invalid_result="$(qs_for_harness ipc call application-volume-test invalidMutations)"
|
||||||
|
jq -e '.nullVolume == false and .emptyMute == false' <<<"$invalid_result" >/dev/null \
|
||||||
|
|| fail "service mutators accepted missing audio nodes: $invalid_result"
|
||||||
|
|
||||||
if rg -n 'ReferenceError|TypeError|Binding loop|Cannot assign|PwObjectTracker' "$shell_log"; then
|
if rg -n 'ReferenceError|TypeError|Binding loop|Cannot assign|PwObjectTracker' "$shell_log"; then
|
||||||
fail 'isolated harness emitted a QML runtime error'
|
fail 'isolated harness emitted a QML runtime error'
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user