warppipe -> Warp Pipe

This commit is contained in:
Joey Yakimowich-Payne 2026-01-31 11:44:55 -07:00
commit 00e997a204
4 changed files with 16 additions and 16 deletions

View file

@ -1,14 +1,14 @@
# Warp Pipe GUI Plan (Qt6 Node-Based Audio Router) # Warp Pipe GUI Plan (Qt6 Node-Based Audio Router)
## Overview ## Overview
A Qt6-based node editor GUI for warppipe using the QtNodes (nodeeditor) library. Visualizes PipeWire audio nodes, ports, and links as draggable nodes with connection lines. Supports creating virtual sinks/sources via context menu and displays ephemeral sources with visual fade when inactive. A Qt6-based node editor GUI for Warp Pipe using the QtNodes (nodeeditor) library. Visualizes PipeWire audio nodes, ports, and links as draggable nodes with connection lines. Supports creating virtual sinks/sources via context menu and displays ephemeral sources with visual fade when inactive.
--- ---
## Milestones ## Milestones
- [x] Milestone 0 - Qt6 Project Setup - [x] Milestone 0 - Qt6 Project Setup
- [x] Create `gui/` subdirectory in warppipe project - [x] Create `gui/` subdirectory in Warp Pipe project
- [x] Add Qt6 + QtNodes to CMakeLists.txt (FetchContent for nodeeditor from github.com/paceholder/nodeeditor) - [x] Add Qt6 + QtNodes to CMakeLists.txt (FetchContent for nodeeditor from github.com/paceholder/nodeeditor)
- [x] Create `warppipe-gui` target with Qt6::Widgets and QtNodes dependencies - [x] Create `warppipe-gui` target with Qt6::Widgets and QtNodes dependencies
- [x] Enable CMAKE_AUTOMOC, CMAKE_AUTORCC, CMAKE_AUTOUIC - [x] Enable CMAKE_AUTOMOC, CMAKE_AUTORCC, CMAKE_AUTOUIC
@ -29,7 +29,7 @@ A Qt6-based node editor GUI for warppipe using the QtNodes (nodeeditor) library.
- [x] If `application_name` is non-empty and differs from `name`, use `application_name` as title - [x] If `application_name` is non-empty and differs from `name`, use `application_name` as title
- [x] Otherwise use `name` field - [x] Otherwise use `name` field
- [x] Store synthesized title in `nodeData(NodeRole::Caption)` - [x] Store synthesized title in `nodeData(NodeRole::Caption)`
- [x] Map warppipe ports to QtNodes ports: - [x] Map Warp Pipe ports to QtNodes ports:
- [x] Input ports (is_input=true) appear on LEFT side of node (QtNodes PortType::In) - [x] Input ports (is_input=true) appear on LEFT side of node (QtNodes PortType::In)
- [x] Output ports (is_input=false) appear on RIGHT side of node (QtNodes PortType::Out) - [x] Output ports (is_input=false) appear on RIGHT side of node (QtNodes PortType::Out)
- [x] Use port name from PortInfo as port label - [x] Use port name from PortInfo as port label
@ -39,8 +39,8 @@ A Qt6-based node editor GUI for warppipe using the QtNodes (nodeeditor) library.
- [x] Define node type classification based on `media_class`: - [x] Define node type classification based on `media_class`:
- [x] Sink → "Hardware Sink" (blue-gray base color) - [x] Sink → "Hardware Sink" (blue-gray base color)
- [x] Source → "Hardware Source" (blue-gray base color) - [x] Source → "Hardware Source" (blue-gray base color)
- [x] Virtual sinks created by warppipe → "Virtual Sink" (green base color) - [x] Virtual sinks created by Warp Pipe → "Virtual Sink" (green base color)
- [x] Virtual sources created by warppipe → "Virtual Source" (green base color) - [x] Virtual sources created by Warp Pipe → "Virtual Source" (green base color)
- [x] Application audio streams (ephemeral) → "Application" (brown/orange base color) - [x] Application audio streams (ephemeral) → "Application" (brown/orange base color)
- [x] Implement custom NodeStyle via `nodeData(NodeRole::Style)`: - [x] Implement custom NodeStyle via `nodeData(NodeRole::Style)`:
- [x] Return QtNodes::NodeStyle::toJson().toVariantMap() - [x] Return QtNodes::NodeStyle::toJson().toVariantMap()
@ -69,7 +69,7 @@ A Qt6-based node editor GUI for warppipe using the QtNodes (nodeeditor) library.
- [x] If successful, add connection to m_connections - [x] If successful, add connection to m_connections
- [x] If failed, emit error and do NOT add to graph - [x] If failed, emit error and do NOT add to graph
- [x] Implement `deleteConnection(ConnectionId)`: - [x] Implement `deleteConnection(ConnectionId)`:
- [x] Find corresponding warppipe LinkId from connection - [x] Find corresponding Warp Pipe LinkId from connection
- [x] Call `Client::RemoveLink(linkId)` - [x] Call `Client::RemoveLink(linkId)`
- [x] Remove from m_connections - [x] Remove from m_connections
- [x] Verify: Drag connection from output port to input port creates PipeWire link; delete removes it - [x] Verify: Drag connection from output port to input port creates PipeWire link; delete removes it
@ -150,7 +150,7 @@ A Qt6-based node editor GUI for warppipe using the QtNodes (nodeeditor) library.
- [x] Screenshot smoke tests (require QT_QPA_PLATFORM=offscreen): - [x] Screenshot smoke tests (require QT_QPA_PLATFORM=offscreen):
- [x] Gated behind `WARPPIPE_GUI_VISUAL_TESTS` CMake option (default OFF) - [x] Gated behind `WARPPIPE_GUI_VISUAL_TESTS` CMake option (default OFF)
- [x] Launch warppipe-gui with --screenshot → CTest verifies exit code 0 - [x] Launch warppipe-gui with --screenshot → CTest verifies exit code 0
- [x] Integration tests with warppipe test harness: - [x] Integration tests with Warp Pipe test harness:
- [x] Create Client with WARPPIPE_TESTING → inject nodes/ports/links → construct WarpGraphModel → verify graph state matches injected data - [x] Create Client with WARPPIPE_TESTING → inject nodes/ports/links → construct WarpGraphModel → verify graph state matches injected data
- [x] Inject node, then remove → verify ghost state in model - [x] Inject node, then remove → verify ghost state in model
- [x] Inject node, remove, re-insert with same name → verify ghost reactivation - [x] Inject node, remove, re-insert with same name → verify ghost reactivation
@ -345,7 +345,7 @@ Tracking strategy:
| Type | Base Color | Description | | Type | Base Color | Description |
|------|------------|-------------| |------|------------|-------------|
| Hardware Sink/Source | Blue-gray (72, 94, 118) | Physical audio devices | | Hardware Sink/Source | Blue-gray (72, 94, 118) | Physical audio devices |
| Virtual Sink/Source | Green (62, 122, 104) | Virtual nodes created by warppipe | | Virtual Sink/Source | Green (62, 122, 104) | Virtual nodes created by Warp Pipe |
| Application | Brown/Orange (138, 104, 72) | Ephemeral app audio streams | | Application | Brown/Orange (138, 104, 72) | Ephemeral app audio streams |
Active vs Ghost: Active vs Ghost:
@ -467,7 +467,7 @@ endif()
- Qt6 >= 6.2 (Core, Widgets) - Qt6 >= 6.2 (Core, Widgets)
- QtNodes (nodeeditor) — fetched via CMake FetchContent - QtNodes (nodeeditor) — fetched via CMake FetchContent
- Catch2 v3 — required for GUI tests (via `find_package`) - Catch2 v3 — required for GUI tests (via `find_package`)
- warppipe library (existing) - Warp Pipe library (target `warppipe`)
--- ---
@ -528,7 +528,7 @@ connect(m_scene, &QtNodes::BasicGraphicsScene::connectionDeleted,
### Three test tiers ### Three test tiers
**Tier 1 — Model Unit Tests (no display server)** **Tier 1 — Model Unit Tests (no display server)**
Pure logic tests for WarpGraphModel. Use warppipe's WARPPIPE_TESTING helpers to inject fake nodes/ports/links into a Client, then construct the model and assert state. These tests run everywhere (CI, headless, local). Pure logic tests for WarpGraphModel. Use Warp Pipe's WARPPIPE_TESTING helpers to inject fake nodes/ports/links into a Client, then construct the model and assert state. These tests run everywhere (CI, headless, local).
Coverage targets: Coverage targets:
- Node mapping (PipeWire ID → QtNodes NodeId, caption synthesis, style by type) - Node mapping (PipeWire ID → QtNodes NodeId, caption synthesis, style by type)
@ -586,7 +586,7 @@ The AI can then use its multimodal capabilities to examine the PNGs, compare exp
- **Routing rule editor**: Visual panel to add/edit/remove per-app routing rules - **Routing rule editor**: Visual panel to add/edit/remove per-app routing rules
- **Audio level meters**: Real-time level monitoring (requires PipeWire param API) - **Audio level meters**: Real-time level monitoring (requires PipeWire param API)
- **Volume/mute controls**: Inline controls on nodes (requires warppipe volume API) - **Volume/mute controls**: Inline controls on nodes (requires Warp Pipe volume API)
- **Presets**: Save/load full configurations (nodes + links + rules) - **Presets**: Save/load full configurations (nodes + links + rules)
- **Search/filter**: Filter nodes by type, name, connection status - **Search/filter**: Filter nodes by type, name, connection status
- **Minimap**: Overview of entire graph in large setups - **Minimap**: Overview of entire graph in large setups
@ -599,5 +599,5 @@ The AI can then use its multimodal capabilities to examine the PNGs, compare exp
- **potato project**: ~/Projects/potato/ (reference implementation using QtNodes + PipeWire) - **potato project**: ~/Projects/potato/ (reference implementation using QtNodes + PipeWire)
- **QtNodes library**: https://github.com/paceholder/nodeeditor - **QtNodes library**: https://github.com/paceholder/nodeeditor
- **warppipe API**: include/warppipe/warppipe.hpp, docs/api.md - **Warp Pipe API**: `include/warppipe/warppipe.hpp`, docs/api.md
- **Qt6 Widgets**: https://doc.qt.io/qt-6/qtwidgets-index.html - **Qt6 Widgets**: https://doc.qt.io/qt-6/qtwidgets-index.html

View file

@ -1,4 +1,4 @@
# LSP Setup for warppipe # LSP Setup for Warp Pipe
This project uses GCC 15 from Homebrew, which requires special configuration for clangd to find standard library headers. This project uses GCC 15 from Homebrew, which requires special configuration for clangd to find standard library headers.

View file

@ -37,7 +37,7 @@
- [x] Watch for node/port appearance; apply stored rules to auto-link ephemeral sources to preferred sinks. - [x] Watch for node/port appearance; apply stored rules to auto-link ephemeral sources to preferred sinks.
- [x] Store mapping by rule (app identity -> target sink/source). Avoid serial IDs; use stable metadata (app/process/role). - [x] Store mapping by rule (app identity -> target sink/source). Avoid serial IDs; use stable metadata (app/process/role).
- [x] Allow user override to update rule and persist. - [x] Allow user override to update rule and persist.
- [x] Integrate metadata store for defaults and routing hints using libpipewire-module-metadata (see src/modules/module-metadata.c). Track default.audio.sink/source and default.configured.audio.sink/source for stable defaults; use a dedicated warppipe.* metadata namespace to avoid conflicts. - [x] Integrate metadata store for defaults and routing hints using libpipewire-module-metadata (see src/modules/module-metadata.c). Track default.audio.sink/source and default.configured.audio.sink/source for stable defaults; use a dedicated `warppipe.*` metadata namespace to avoid conflicts.
- [x] Tests to add (non-happy path/edge cases): instructions: rule for app that disappears and reappears under a different PID; verify re-routing; conflicting rules (two matches) resolved deterministically; persistence file corrupted; metadata module not available. - [x] Tests to add (non-happy path/edge cases): instructions: rule for app that disappears and reappears under a different PID; verify re-routing; conflicting rules (two matches) resolved deterministically; persistence file corrupted; metadata module not available.
- [x] Performance tests: instructions: simulate 200 ephemeral sources (connect/disconnect) and measure time to apply routing rules and create links; ensure rule lookup is O(1) or O(log n). - [x] Performance tests: instructions: simulate 200 ephemeral sources (connect/disconnect) and measure time to apply routing rules and create links; ensure rule lookup is O(1) or O(log n).

View file

@ -1,4 +1,4 @@
# warppipe # Warp Pipe
Warp Pipe is a C++20 static library wrapping libpipewire for virtual audio node management, link routing, and per-app routing policy. Warp Pipe is a C++20 static library wrapping libpipewire for virtual audio node management, link routing, and per-app routing policy.
@ -131,7 +131,7 @@ See [docs/config-schema.md](docs/config-schema.md) for full schema documentation
## Policy-Only Mode ## Policy-Only Mode
When running alongside WirePlumber, enable `policy_only` to prevent warppipe from creating links that conflict with the session manager: When running alongside WirePlumber, enable `policy_only` to prevent Warp Pipe from creating links that conflict with the session manager:
```cpp ```cpp
warppipe::ConnectionOptions opts; warppipe::ConnectionOptions opts;