Skip to content

Commit 2d4b55d

Browse files
committed
Require pipewire-gobject 0.3.7 for active route checks
1 parent 3ac8a44 commit 2d4b55d

25 files changed

Lines changed: 1361 additions & 49 deletions

.github/workflows/ci.yml

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ on:
1111
description: Run the experimental Flatpak PipeWire routing smoke test
1212
type: boolean
1313
default: false
14+
headless_pipewire_runtime_smoke:
15+
description: Run the headless PipeWire/WirePlumber controller smoke test
16+
type: boolean
17+
default: false
1418
live_ui_runtime_smoke:
1519
description: Run the live GTK/AT-SPI/PipeWire smoke test
1620
type: boolean
@@ -49,8 +53,8 @@ concurrency:
4953
cancel-in-progress: true
5054

5155
env:
52-
PWG_VERSION: "0.3.6"
53-
PWG_REQUIREMENT: "pipewire-gobject>=0.3.6,<0.4"
56+
PWG_VERSION: "0.3.7"
57+
PWG_REQUIREMENT: "pipewire-gobject>=0.3.7,<0.4"
5458

5559
jobs:
5660
changes:
@@ -135,7 +139,7 @@ jobs:
135139
README.md|pyproject.toml|MANIFEST.in|src/*|tests/*|data/*|extensions/*)
136140
test=true
137141
;;
138-
tools/check_gnome_shell_extension.py|tools/pack_gnome_shell_extension.sh|tools/prepare_release.py|tools/release_gates.py|tools/release_preflight.py|tools/release_runtime_gate.py|tools/release_status.py|tools/run_live_ui_runtime_smoke_ci.sh)
142+
tools/check_gnome_shell_extension.py|tools/check_headless_pipewire_runtime.py|tools/pack_gnome_shell_extension.sh|tools/prepare_release.py|tools/release_gates.py|tools/release_preflight.py|tools/release_runtime_gate.py|tools/release_status.py|tools/run_headless_pipewire_runtime_smoke_ci.sh|tools/run_live_ui_runtime_smoke_ci.sh)
139143
test=true
140144
;;
141145
esac
@@ -153,7 +157,7 @@ jobs:
153157
esac
154158
155159
case "$path" in
156-
.github/workflows/*.yml|tools/check_pipewire_gobject.py|tools/release_gates.py|tools/release_runtime_gate.py|src/mini_eq/pipewire_backend.py|src/mini_eq/analyzer.py)
160+
.github/workflows/*.yml|tools/check_headless_pipewire_runtime.py|tools/check_pipewire_gobject.py|tools/release_gates.py|tools/release_runtime_gate.py|tools/run_headless_pipewire_runtime_smoke_ci.sh|src/mini_eq/pipewire_backend.py|src/mini_eq/analyzer.py)
157161
pwg=true
158162
;;
159163
esac
@@ -484,6 +488,49 @@ jobs:
484488
MINI_EQ_FLATPAK_EXPECT_VERSION: ${{ inputs.flatpak_runtime_expected_version }}
485489
run: tools/run_flatpak_runtime_smoke_ci.sh
486490

491+
headless-pipewire-runtime-smoke:
492+
needs: changes
493+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.headless_pipewire_runtime_smoke }}
494+
runs-on: ubuntu-24.04
495+
timeout-minutes: 45
496+
497+
steps:
498+
- name: Require change detection
499+
if: ${{ needs.changes.result != 'success' }}
500+
run: exit 1
501+
502+
- name: Check out repository
503+
uses: actions/checkout@v6
504+
505+
- name: Install headless PipeWire runtime dependencies
506+
run: |
507+
sudo apt-get update
508+
sudo apt-get install -y \
509+
build-essential \
510+
dbus-user-session \
511+
gobject-introspection \
512+
libebur128-1 \
513+
libgirepository1.0-dev \
514+
libglib2.0-dev \
515+
libpipewire-0.3-dev \
516+
libspa-0.2-modules \
517+
meson \
518+
ninja-build \
519+
pipewire \
520+
pipewire-bin \
521+
pkg-config \
522+
python3 \
523+
python3-dev \
524+
python3-gi \
525+
python3-numpy \
526+
python3-pip \
527+
python3-setuptools \
528+
python3-venv \
529+
wireplumber
530+
531+
- name: Build source environment and run headless PipeWire smoke
532+
run: tools/run_headless_pipewire_runtime_smoke_ci.sh
533+
487534
live-ui-runtime-smoke:
488535
needs: changes
489536
if: ${{ github.event_name == 'workflow_dispatch' && inputs.live_ui_runtime_smoke }}

AGENTS.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,27 @@ nested headless GNOME Shell session:
7979
MINI_EQ_RUN_ATSPI=1 .venv/bin/python -m pytest tests/test_mini_eq_atspi_widgets.py -q
8080
```
8181

82-
For a deeper live runtime smoke, run the real GTK app in a private
83-
PipeWire/WirePlumber graph with synthetic playback and AT-SPI UI driving:
82+
For PipeWire graph behavior without nested GNOME/AT-SPI, run the headless
83+
controller smoke. It owns synthetic stream routing, default-output moves,
84+
monitor toggles, and active processing-link assertions:
85+
86+
```bash
87+
.venv/bin/python tools/check_headless_pipewire_runtime.py --timeout 35 --cycles 2
88+
```
89+
90+
For a deeper live UI smoke, run the real GTK app in a private PipeWire/WirePlumber
91+
graph with synthetic playback and AT-SPI UI driving:
8492

8593
```bash
8694
.venv/bin/python tools/check_live_ui_runtime.py --timeout 35 --cycles 1
8795
MINI_EQ_RUN_LIVE_UI=1 .venv/bin/python -m pytest tests/test_mini_eq_live_ui_runtime.py -q
8896
```
8997

90-
The live UI smoke is opt-in locally because it needs nested GNOME Shell,
91-
AT-SPI, PipeWire, and WirePlumber. Treat it as a maintainer confidence check on
92-
a supported recent GNOME/GTK stack; the blocking public release runtime gate is
93-
the Flatpak routing smoke.
98+
The headless PipeWire smoke is the stable native controller/graph gate and is
99+
part of release preflight. The live UI smoke is opt-in locally because it needs
100+
nested GNOME Shell, AT-SPI, PipeWire, and WirePlumber. Treat it as a maintainer
101+
confidence check on a supported recent GNOME/GTK stack; the blocking public
102+
release runtime gates are release preflight and the Flatpak routing smoke.
94103

95104
For manual GNOME Shell extension testing against an installed Flatpak build,
96105
run the nested devkit smoke. It loads the extension from this checkout and
@@ -113,8 +122,11 @@ before being installed into a `--system-site-packages` Mini EQ venv.
113122
- Keep the pipewire-gobject API boundary small, general-purpose, and
114123
app-facing. Mini EQ may validate new pipewire-gobject API in a real GTK app,
115124
but do not add Mini EQ-shaped concepts, preset/filter-chain policy, or
116-
hardware-selection policy to pipewire-gobject. WirePlumber stays the host
117-
session manager, not a bundled GI dependency.
125+
hardware-selection policy to pipewire-gobject. When changing public
126+
pipewire-gobject API, follow the sibling checkout's `AGENTS.md` bindable API
127+
gate: plain C/C99 public scalar types, no public GLib collections, explicit
128+
ownership/nullability annotations, and generated GIR/test updates. WirePlumber
129+
stays the host session manager, not a bundled GI dependency.
118130
- Treat the Mini EQ D-Bus control interface as a project-internal app/Shell
119131
extension contract with version-skew tolerance. Keep `api_version = 1`
120132
additive only: add state fields, methods, and capabilities when needed, but do

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
- Run filter-chain readiness callbacks from the GLib main context when PipeWire
66
reports the virtual sink asynchronously, avoiding thread-loop sync failures
77
during system-wide EQ startup.
8-
- Re-apply the active filter controls when PipeWire creates a link to the Mini
9-
EQ virtual sink, so a newly routed stream starts processing without requiring
10-
an A/B toggle.
8+
- Require pipewire-gobject 0.3.7 and re-apply the active filter controls when
9+
PipeWire creates or activates links on the Mini EQ processing path, so audio
10+
resumed after silence starts processing without requiring an A/B toggle.
1111
- Refresh port-aware output preset scope when PipeWire reports route parameter
1212
serial changes on the active output device.
1313

data/io.github.bhack.mini-eq.metainfo.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@
4747
<releases>
4848
<release version="0.7.4" date="2026-05-11">
4949
<description>
50-
<p>Run filter-chain readiness callbacks from the GLib main context when PipeWire reports the virtual sink asynchronously, avoiding thread-loop sync failures during system-wide EQ startup.</p>
50+
<ul>
51+
<li>Run filter-chain readiness callbacks from the GLib main context when PipeWire reports the virtual sink asynchronously.</li>
52+
<li>Re-apply active filter controls when PipeWire creates or activates links on the Mini EQ processing path.</li>
53+
<li>Refresh port-aware output preset scope when PipeWire reports route parameter serial changes on the active output device.</li>
54+
</ul>
5155
</description>
5256
</release>
5357
<release version="0.7.3" date="2026-05-11">

docker/preflight.Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ RUN apt-get update \
2222
meson \
2323
ninja-build \
2424
pipewire \
25+
pipewire-bin \
2526
pkg-config \
2627
python3 \
2728
python3-cairo \

docs/development.md

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ Install the Python package after the system packages are present:
8787
```bash
8888
python3 -m venv /tmp/mini-eq-pwg-build
8989
/tmp/mini-eq-pwg-build/bin/python -m pip install --upgrade pip
90-
/tmp/mini-eq-pwg-build/bin/python -m pip wheel 'pipewire-gobject>=0.3.6,<0.4' -w /tmp/mini-eq-wheelhouse
90+
/tmp/mini-eq-pwg-build/bin/python -m pip wheel 'pipewire-gobject>=0.3.7,<0.4' -w /tmp/mini-eq-wheelhouse
9191

9292
python3 -m venv --system-site-packages ~/.local/share/mini-eq/venv
9393
~/.local/share/mini-eq/venv/bin/python -m pip install --upgrade pip
94-
~/.local/share/mini-eq/venv/bin/python -m pip install --no-index --find-links /tmp/mini-eq-wheelhouse 'pipewire-gobject>=0.3.6,<0.4'
94+
~/.local/share/mini-eq/venv/bin/python -m pip install --no-index --find-links /tmp/mini-eq-wheelhouse 'pipewire-gobject>=0.3.7,<0.4'
9595
~/.local/share/mini-eq/venv/bin/python -m pip install mini-eq
9696
~/.local/share/mini-eq/venv/bin/mini-eq --check-deps
9797
~/.local/share/mini-eq/venv/bin/mini-eq
@@ -144,7 +144,16 @@ For real GTK widget behavior, run the opt-in AT-SPI smoke test:
144144
MINI_EQ_RUN_ATSPI=1 python3 -m pytest tests/test_mini_eq_atspi_widgets.py -q
145145
```
146146

147-
For a deeper live runtime smoke, run the real GTK app in a private
147+
For PipeWire graph behavior without GTK or AT-SPI, run the headless controller
148+
smoke. It starts a private PipeWire/WirePlumber graph, synthetic playback,
149+
Mini EQ's routing controller, and checks route toggles, default-output moves,
150+
monitor toggles, and active processing links:
151+
152+
```bash
153+
python3 tools/check_headless_pipewire_runtime.py --timeout 35 --cycles 2
154+
```
155+
156+
For a deeper live UI smoke, run the real GTK app in a private
148157
PipeWire/WirePlumber graph with synthetic playback and AT-SPI UI driving:
149158

150159
```bash
@@ -153,10 +162,12 @@ MINI_EQ_RUN_LIVE_UI=1 python3 -m pytest tests/test_mini_eq_live_ui_runtime.py -q
153162
```
154163

155164
These integration smokes are intentionally separate from the default pytest
156-
suite because they require nested GNOME Shell, AT-SPI services, PipeWire, and
157-
WirePlumber. Use the live UI smoke as a maintainer confidence check on a
158-
supported recent GNOME/GTK stack; the public release workflow does not treat
159-
the hosted Ubuntu native GTK stack as the blocking UI runtime.
165+
suite because they require PipeWire and WirePlumber; the live UI smoke also
166+
requires nested GNOME Shell and AT-SPI services. Use the headless smoke for
167+
stable controller/graph coverage and the live UI smoke as a maintainer
168+
confidence check on a supported recent GNOME/GTK stack; the public release
169+
workflow does not treat the hosted Ubuntu native GTK stack as the blocking UI
170+
runtime.
160171

161172
## Local Flatpak Build
162173

docs/release.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ graph behaves correctly. Treat their claims narrowly:
8484
- Unit and seam tests verify deterministic model, routing, metadata, and UI
8585
state transitions.
8686
- The release preflight verifies source cleanliness, package build/install,
87-
dependency importability, metadata, and the full default pytest suite.
87+
dependency importability, metadata, the full default pytest suite, and a
88+
headless PipeWire/WirePlumber controller smoke with synthetic stream routing,
89+
default-output moves, monitor toggles, and active processing-link assertions.
8890
- The Flatpak routing smoke verifies the installed Flatpak can route and
8991
restore a synthetic stream in an isolated PipeWire/WirePlumber graph.
9092
- The live UI smoke verifies the real GTK app can be driven through AT-SPI
@@ -169,7 +171,8 @@ preflight and post-publish checks.
169171

170172
Prefer the containerized preflight. It keeps host machines clean while testing a
171173
fresh venv, `pipewire-gobject` sdist build dependencies, package metadata, a
172-
private PipeWire/WirePlumber session, the leak scan, and release smoke checks:
174+
private PipeWire/WirePlumber session, the headless controller/graph smoke, the
175+
leak scan, and release smoke checks:
173176

174177
```bash
175178
tools/run_release_preflight_container.sh
@@ -189,8 +192,8 @@ Flathub manifest still has old bundled dependencies or permissions.
189192

190193
The preflight prints change-aware notices for GNOME Shell extension upload,
191194
Flatpak runtime smoke, and background portal smoke. Treat those notices as
192-
release gates when they apply; the generic preflight deliberately does not
193-
mutate the host audio graph.
195+
release gates when they apply; the generic preflight deliberately uses a private
196+
PipeWire graph instead of mutating the host audio graph.
194197

195198
## Runtime Checks
196199

@@ -201,6 +204,15 @@ access, Flatpak permissions, runtime dependencies, or shutdown behavior changed:
201204
python3 tools/check_flatpak_runtime.py --app-ref <installed-app-ref>
202205
```
203206

207+
Run the native headless PipeWire smoke when working on routing, analyzer
208+
capture, monitor toggles, output following, or `pipewire-gobject` integration.
209+
The containerized release preflight runs this automatically, but it is useful as
210+
a focused local loop:
211+
212+
```bash
213+
python3 tools/check_headless_pipewire_runtime.py --timeout 35 --cycles 2
214+
```
215+
204216
For background portal changes, run one clean-permission Flatpak smoke in a real
205217
GNOME session. Enable **Keep Running in Background**, approve the portal
206218
prompt, enable **Start at Login**, close the window, and confirm the app stays

io.github.bhack.mini-eq.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ modules:
124124
sources:
125125
- type: git
126126
url: https://github.com/bhack/pipewire-gobject.git
127-
tag: 0.3.6
128-
commit: 7e20b29865c0a869695bc730bacb68e2f0853077
127+
tag: 0.3.7
128+
commit: 1cd6ccc0f5e0d1d62ab8fd42dc9f200a112554f6
129129

130130
- python3-dependencies.yaml
131131

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ classifiers = [
4040
"Topic :: Multimedia :: Sound/Audio :: Analysis",
4141
"Topic :: Multimedia :: Sound/Audio :: Mixers",
4242
]
43-
dependencies = ["numpy>=1.26", "pipewire-gobject>=0.3.6,<0.4"]
43+
dependencies = ["numpy>=1.26", "pipewire-gobject>=0.3.7,<0.4"]
4444

4545
[project.urls]
4646
Homepage = "https://github.com/bhack/mini-eq"

src/mini_eq/deps.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
Status = Literal["ok", "missing", "warning"]
1414

15-
PWG_REQUIRED_VERSION = "0.3.6"
16-
PWG_REQUIRED_VERSION_PARTS = (0, 3, 6)
15+
PWG_REQUIRED_VERSION = "0.3.7"
16+
PWG_REQUIRED_VERSION_PARTS = (0, 3, 7)
1717
PWG_REQUIRED_SYMBOLS = (
1818
"Core.set_pipewire_property",
1919
"Core.sync",
@@ -23,6 +23,9 @@
2323
"Device.new",
2424
"Device.subscribe_params",
2525
"Device.sync",
26+
"Link.get_state",
27+
"Link.new",
28+
"Link.sync",
2629
"Metadata.sync",
2730
"Node.sync",
2831
"Param.new_props_controls",

0 commit comments

Comments
 (0)