6.7 KiB
6.7 KiB
Warppipe Plan (C++ libpipewire library)
-
Milestone 0 - Groundwork and constraints
- Choose build system: CMake (confirmed). Define minimal library target and example app target.
- Define public API surface (namespaces, class/struct layout, error model, threading model).
- Define performance budget and metrics (e.g., 200 create/modify/delete ops in < 1s on typical desktop).
- Choose identity strategy for ephemeral sources (match rules on application.name, application.process.binary, media.role, node.name, fallback to client properties; avoid serial IDs).
- Tests to add (non-happy path/edge cases): instructions: create unit tests that fail on missing PipeWire daemon, missing libpipewire-module-link-factory, missing libpipewire-module-metadata, and misconfigured runtime properties (e.g., invalid PW_KEY_MEDIA_CLASS).
- Performance tests: instructions: add a microbenchmark harness that measures connect->create->destroy of N no-op objects (no links) and asserts subsecond N=200 on a warm PipeWire connection.
-
Milestone 1 - Core runtime and registry model
- Implement a WarpContext (pw_main_loop/pw_thread_loop + pw_context + pw_core) with lifecycle and reconnect handling.
- Implement registry cache for nodes/ports/links with event listeners, and a stable "object identity" resolver (node name, application properties).
- Expose a query API to list nodes, ports, and identify sinks/sources.
- Add Catch2 test harness with smoke coverage for connection modes.
- Add warppipe_cli for list-nodes, list-ports, list-links.
- Tests to add (non-happy path/edge cases): instructions: simulate registry events where nodes/ports disappear mid-iteration; ensure safe iteration and cleanup; verify reconnection logic after daemon restart.
- Performance tests: instructions: measure time to ingest registry snapshot of 1000 objects and process 100 add/remove events; assert latency per event and total under subsecond.
-
Milestone 2 - Virtual sinks and sources
- Implement virtual sink/source creation via pw_stream_new with PW_KEY_MEDIA_CLASS set to Audio/Sink or Audio/Source and autoconnect flags as needed (see src/pipewire/stream.h).
- Support "null" behavior (discard) and "loopback" behavior (sink that forwards to target) using stream properties and explicit links.
- Provide a naming scheme and metadata tags for virtual nodes to ensure stable identification.
- Tests to add (non-happy path/edge cases): instructions: create sink/source with missing media class and expect validation error; create duplicate node name; attempt to connect when target node is absent.
- Performance tests: instructions: create/destroy 100 virtual sinks and 100 virtual sources in a tight loop; measure wall time and ensure it stays within the target budget.
-
Milestone 3 - Link management API
- Implement link creation via link-factory (load libpipewire-module-link-factory and call pw_core_create_object with link.input.* and link.output.* props; see src/modules/module-link-factory.c, src/examples/internal.c, src/tools/pw-link.c).
- Support linking by node+port names and by object IDs; add object.linger and link.passive options.
- Add link deletion and link reconciliation (auto-remove stale links when endpoints vanish).
- Tests to add (non-happy path/edge cases): instructions: link to non-existent port; link output-to-output or input-to-input; remove node while link is initializing; create two links to same port and validate policy behavior.
- Performance tests: instructions: create 200 links between existing ports; measure create+destroy time and verify subsecond target where possible.
-
Milestone 4 - Persistence and "ephemeral source" policy
- Implement persistence (JSON or TOML) for: virtual nodes, links, and per-app routing rules. Persist on change; load on startup.
- Implement policy engine:
- Watch for node/port appearance; apply stored rules to auto-link ephemeral sources to preferred sinks.
-
Store mapping by rule (app identity -> target sink/source). Avoid serial IDs; use stable metadata (app/process/role).
- Allow user override to update rule and persist.
- 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.
- 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.
- 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).
-
Milestone 5 - Stability, compatibility, and tooling
- Provide a simple CLI (optional) to inspect nodes, create virtual nodes, link/unlink, and export/import config (useful for manual testing).
- Add documentation: API usage patterns, threading model, and performance notes.
- Validate behavior with PipeWire session manager present (WirePlumber) to avoid fighting policy; allow “policy-only” mode (observes and sets metadata without forcing links).
- Tests to add (non-happy path/edge cases): instructions: run with session manager disabled/enabled and verify no infinite re-link loops; ensure policy mode doesn’t override user defaults unexpectedly.
- Performance tests: instructions: end-to-end scenario (virtual sink + app connect + reroute + disconnect + reconnect) repeated 200 times; measure median/95th percentile latency.
Design notes grounded in PipeWire code/docs
- Virtual sinks/sources via pw_stream_new and PW_KEY_MEDIA_CLASS (Audio/Sink, Audio/Source): src/pipewire/stream.h.
- Explicit link creation via link-factory and link.input./link.output. properties: src/modules/module-link-factory.c, src/examples/internal.c, src/tools/pw-link.c.
- Metadata store creation and defaults (default.audio.sink/source and configured defaults): src/modules/module-metadata.c; metadata tools in src/tools/pw-metadata.c; pulse-related defaults/metadata in src/modules/module-protocol-pulse/*.
- Official concepts: nodes/ports/links and session manager policy: https://docs.pipewire.org/page_objects_design.html and https://docs.pipewire.org/page_session_manager.html
Key behavior for ephemeral sources
- Store per-app routing rules keyed by stable application metadata (name/process/role) and apply on node appearance.
- When an app reappears, re-link its output port(s) to the saved target sink (instead of default speakers).