Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-1243GitHub issuePublicReceived

omarchy-audio-output-sink doesn't resolve EasyEffects' native PipeWire filter-chain routing — volume keys/panel control the wrong sink

Reported by rabbitgti04930 · filed Aug 29, 2026Closed upstream on 2026-10-04 by the merge of PR #13396 (closed by dhh). GitHub close reason: completed.

Received and recorded verbatim. Nothing has been checked yet.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
Not yet mapped to any requirement or component.
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. No decision has been recorded yet.

Original report

omarchy-audio-output-sink doesn't resolve EasyEffects' native PipeWire filter-chain routing — volume keys/panel control the wrong sinkrevision 1 · captured 2026-09-28 21:24 UTC via poll

Summary

With EasyEffects Sink selected as the audio output, the volume keys
(omarchy-audio-output-volume) and the audio panel's master OUTPUT slider
have almost no audible effect. They end up adjusting easyeffects_sink's own
pre-processing gain (upstream of the effects chain) instead of the real
hardware output, so changes get partly absorbed by compressor/limiter
plugins downstream. Selecting the physical output device directly (e.g.
"Built-in Audio Analog Stereo") makes volume control work correctly again,
but that bypasses EasyEffects processing entirely — defeating the point of
having it selected.

Reproduced on Apple hardware (CS4208 codec, MacBook Air), which is likely
common among Omarchy's Apple-Silicon/Quattro users running EasyEffects for
speaker tuning — but the bug is hardware-independent; it's in how the
resolver detects EasyEffects' internal routing.

Cause

omarchy-audio-output-sink (used by both the volume-key script and
plugins/panels/audio/Panel.qml's volumeSinkName resolution) is designed
to resolve a DSP sink like easyeffects_sink through to the physical sink it
feeds, specifically to keep volume keys/slider meaningful when a tuning or
EasyEffects is selected as the output (see the comment block at the top of
the script).

It does this by scanning pactl list sink-inputs for a PulseAudio-visible
sink-input either named after the virtual sink or tagged
application.name = "EasyEffects".

Current EasyEffects builds wire their DSP chain using **native PipeWire
filter-chain nodes** (ee_soe_filter, ee_soe_equalizer,
ee_soe_multiband_compressor, ee_soe_limiter, ee_soe_output_level, etc.,
mirrored by ee_sie_* on the input side) rather than a classic
GStreamer/PulseAudio sink-input loopback. These native links never appear in
pactl list sink-inputs — it returns empty even when the chain is fully
connected and audio is flowing correctly (verified with pw-link -l, which
does show the real link graph). The lookup in
omarchy-audio-output-sink silently fails and falls back to returning the
DSP sink itself, so the "resolve through to hardware" behavior the script
exists to provide never triggers for these EasyEffects builds.

Reproduction

$ pactl set-default-sink easyeffects_sink
$ pactl list sink-inputs
# (empty, even though EasyEffects is actively processing audio)

$ pw-link -l | grep -A1 easyeffects_sink
easyeffects_sink:monitor_FL
  |-> ee_soe_filter:input_FL
easyeffects_sink:monitor_FR
  |-> ee_soe_filter:input_FR
# ...chain continues natively through ee_soe_* nodes down to alsa_output...

$ omarchy-audio-output-sink
easyeffects_sink        # should resolve to alsa_output.pci-...

$ omarchy-audio-output-volume raise
$ pactl list sinks | grep -A3 easyeffects_sink
# easyeffects_sink volume moved instead of the hardware sink

Fix

Add a fallback to omarchy-audio-output-sink: when the PulseAudio
sink-input lookup finds nothing, walk the native pw-link -l graph forward
from the DSP sink's ports (BFS over "X |<- Y" edges), through however many
filter-chain hops, until a real alsa_output.* sink turns up. Keeps the
existing pactl-based detection as the first attempt, so behavior for setups
where that already works (e.g. an actual sink-input-based tuning) is
unchanged.

I've tested this fix locally and it correctly resolves easyeffects_sink →
the real hardware sink, and volume keys / mute now move real loudness with
EasyEffects selected as the output. Happy to open a PR with the patch if
that's useful — sharing the diagnosis here first in case there's a preferred
approach (e.g. fixing it via the Panel.qml side instead, similar in spirit
to #8651).

Environment

  • omarchy 4.0.1-1
  • EasyEffects (Qt/QML build with native PipeWire filter-chain backend —

processing nodes named ee_soe_*/ee_sie_*, not GStreamer)
- pipewire 1.6.8
- Apple CS4208 codec (MacBook Air), but root cause is hardware-independent

Related

#8651 — a different bug in the same general area (device-sink volume/mute
writes from the panel not applying gain), not a duplicate of this one.


swv w/ claude code

View raw text
## Summary

With EasyEffects Sink selected as the audio output, the volume keys
(`omarchy-audio-output-volume`) and the audio panel's master OUTPUT slider
have almost no audible effect. They end up adjusting `easyeffects_sink`'s own
pre-processing gain (upstream of the effects chain) instead of the real
hardware output, so changes get partly absorbed by compressor/limiter
plugins downstream. Selecting the physical output device directly (e.g.
"Built-in Audio Analog Stereo") makes volume control work correctly again,
but that bypasses EasyEffects processing entirely — defeating the point of
having it selected.

Reproduced on Apple hardware (CS4208 codec, MacBook Air), which is likely
common among Omarchy's Apple-Silicon/Quattro users running EasyEffects for
speaker tuning — but the bug is hardware-independent; it's in how the
resolver detects EasyEffects' internal routing.

## Cause

`omarchy-audio-output-sink` (used by both the volume-key script and
`plugins/panels/audio/Panel.qml`'s `volumeSinkName` resolution) is designed
to resolve a DSP sink like `easyeffects_sink` through to the physical sink it
feeds, specifically to keep volume keys/slider meaningful when a tuning or
EasyEffects is selected as the output (see the comment block at the top of
the script).

It does this by scanning `pactl list sink-inputs` for a PulseAudio-visible
sink-input either named after the virtual sink or tagged
`application.name = "EasyEffects"`.

Current EasyEffects builds wire their DSP chain using **native PipeWire
filter-chain nodes** (`ee_soe_filter`, `ee_soe_equalizer`,
`ee_soe_multiband_compressor`, `ee_soe_limiter`, `ee_soe_output_level`, etc.,
mirrored by `ee_sie_*` on the input side) rather than a classic
GStreamer/PulseAudio sink-input loopback. These native links never appear in
`pactl list sink-inputs` — it returns empty even when the chain is fully
connected and audio is flowing correctly (verified with `pw-link -l`, which
does show the real link graph). The lookup in
`omarchy-audio-output-sink` silently fails and falls back to returning the
DSP sink itself, so the "resolve through to hardware" behavior the script
exists to provide never triggers for these EasyEffects builds.

## Reproduction

```console
$ pactl set-default-sink easyeffects_sink
$ pactl list sink-inputs
# (empty, even though EasyEffects is actively processing audio)

$ pw-link -l | grep -A1 easyeffects_sink
easyeffects_sink:monitor_FL
  |-> ee_soe_filter:input_FL
easyeffects_sink:monitor_FR
  |-> ee_soe_filter:input_FR
# ...chain continues natively through ee_soe_* nodes down to alsa_output...

$ omarchy-audio-output-sink
easyeffects_sink        # should resolve to alsa_output.pci-...

$ omarchy-audio-output-volume raise
$ pactl list sinks | grep -A3 easyeffects_sink
# easyeffects_sink volume moved instead of the hardware sink
```

## Fix

Add a fallback to `omarchy-audio-output-sink`: when the PulseAudio
sink-input lookup finds nothing, walk the native `pw-link -l` graph forward
from the DSP sink's ports (BFS over "X `|<-` Y" edges), through however many
filter-chain hops, until a real `alsa_output.*` sink turns up. Keeps the
existing pactl-based detection as the first attempt, so behavior for setups
where that already works (e.g. an actual sink-input-based tuning) is
unchanged.

I've tested this fix locally and it correctly resolves `easyeffects_sink` →
the real hardware sink, and volume keys / mute now move real loudness with
EasyEffects selected as the output. Happy to open a PR with the patch if
that's useful — sharing the diagnosis here first in case there's a preferred
approach (e.g. fixing it via the Panel.qml side instead, similar in spirit
to #8651).

## Environment

- omarchy 4.0.1-1
- EasyEffects (Qt/QML build with native PipeWire filter-chain backend —
  processing nodes named `ee_soe_*`/`ee_sie_*`, not GStreamer)
- pipewire 1.6.8
- Apple CS4208 codec (MacBook Air), but root cause is hardware-independent

## Related

#8651 — a different bug in the same general area (device-sink volume/mute
writes from the panel not applying gain), not a duplicate of this one.

---
*swv w/ claude code*

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

No decision has been recorded yet.