# Warp Pipe Warp Pipe is a C++20 static library wrapping libpipewire for virtual audio node management, link routing, and per-app routing policy. ## Features - **Virtual sinks/sources** — create Audio/Sink and Audio/Source nodes with configurable sample rate and channels - **Link management** — connect and disconnect ports by node+port name or ID, with passive and linger options - **Per-app routing rules** — match applications by name, process binary, or media role and auto-route to target sinks - **Persistence** — JSON config with atomic writes, auto-save on change, auto-load on startup - **Volume control** — set per-node volume and mute state - **Audio metering** — per-node and master peak meters - **Metadata integration** — read and set default audio sink/source via PipeWire metadata - **Policy-only mode** — observe and set metadata without creating links (avoids fighting WirePlumber) - **Thread-safe** — dedicated PipeWire thread loop; all public methods callable from any thread ## Build Requirements: - CMake 3.20+ - pkg-config - libpipewire-0.3 development files - C++20 compiler - Qt6 6.2+ (for the GUI target; disable with `-DWARPPIPE_BUILD_GUI=OFF`) - Catch2 v3 (for tests; required when `-DWARPPIPE_BUILD_TESTS=ON`) ```sh cmake -S . -B build cmake --build build ``` Targets: `warppipe` (library), `warppipe_example`, `warppipe_cli`, `warppipe_tests`, `warppipe_perf`, `warppipe-gui`, `warppipe-gui-tests` ### Dependencies - [libpipewire-0.3](https://pipewire.org/) — system package - [nlohmann/json](https://github.com/nlohmann/json) — fetched automatically if not installed - [Catch2 v3](https://github.com/catchorg/Catch2) — required for tests (via `find_package`) - [Qt6](https://www.qt.io/) — required for `warppipe-gui` (default on) - [QtNodes](https://github.com/paceholder/nodeeditor) — fetched automatically when GUI is enabled ## Quick Start ```cpp #include warppipe::ConnectionOptions opts; opts.application_name = "my-app"; opts.config_path = "/home/user/.config/warppipe/config.json"; auto result = warppipe::Client::Create(opts); auto& client = result.value; // Create a virtual sink auto sink = client->CreateVirtualSink("my-sink"); // Route Firefox audio to it warppipe::RouteRule rule; rule.match.application_name = "Firefox"; rule.target_node = "my-sink"; client->AddRouteRule(rule); // The policy engine auto-links Firefox when it starts playing ``` ## CLI `warppipe_cli` provides full access to the library for manual testing and scripting: ``` warppipe_cli list-nodes warppipe_cli list-ports warppipe_cli list-links warppipe_cli list-rules warppipe_cli create-sink [--rate N] [--channels N] warppipe_cli create-source [--rate N] [--channels N] warppipe_cli link [--passive] [--linger] warppipe_cli unlink warppipe_cli add-rule --app --target [--process ] [--role ] warppipe_cli remove-rule warppipe_cli save-config warppipe_cli load-config warppipe_cli defaults ``` `link` uses node and port names (not IDs). `--passive` sets `PW_KEY_LINK_PASSIVE`, and `--linger` sets `PW_KEY_OBJECT_LINGER` so links persist after the client exits. `defaults` prints the current and configured default sink/source names. `create-sink` and `create-source` block until interrupted with Ctrl-C. ## Configuration Config is JSON. Set `ConnectionOptions::config_path` to enable auto-save/load, or use `SaveConfig`/`LoadConfig` manually. The config persists virtual nodes, routing rules, saved links, and per-node volume/mute state. ```json { "version": 1, "virtual_nodes": [ { "name": "warppipe-gaming-sink", "is_source": false, "rate": 48000, "channels": 2, "loopback": false, "target_node": "", "volume": 1.0, "mute": false } ], "route_rules": [ { "match": { "application_name": "Firefox", "process_binary": "", "media_role": "" }, "target_node": "warppipe-gaming-sink" } ], "links": [ { "out_node": "Firefox", "out_port": "output_FL", "in_node": "warppipe-gaming-sink", "in_port": "input_FL" } ] } ``` See [docs/config-schema.md](docs/config-schema.md) for full schema documentation. ## Policy-Only Mode When running alongside WirePlumber, enable `policy_only` to prevent Warp Pipe from creating links that conflict with the session manager: ```cpp warppipe::ConnectionOptions opts; opts.policy_only = true; ``` In this mode the policy engine still evaluates rules but does not create links. Metadata defaults can still be read and set. ## Documentation - [API Reference](docs/api.md) — full API, threading model, error model, performance notes - [Config Schema](docs/config-schema.md) — JSON configuration format and persistence behavior - [GUI Usage](docs/gui-usage.md) — how to run the Qt GUI and capture screenshots - [Examples](docs/examples.md) — common patterns and usage recipes ## Tests ```sh ./build/warppipe_tests ``` 31 test cases covering connection, registry, virtual nodes, links, route rules, policy engine, persistence, and metadata. ## Performance ```sh ./build/warppipe_perf --mode ``` | Mode | Workload | Typical Result | |------|----------|----------------| | create-destroy | 200 sink create/destroy | < 1s | | registry | 1000 object ingest + 100 events | < 1s | | links | 200 link create/destroy | < 1s | | policy | 200 ephemeral sources routed | ~370ms | | e2e | 200 full iterations (sink + rule + source + teardown) | median ~3ms, p95 ~4ms |