| .sisyphus/notepads/warppipe-node-editor | ||
| .vim | ||
| docs | ||
| examples | ||
| gui | ||
| include/warppipe | ||
| perf | ||
| src | ||
| tests | ||
| .clangd | ||
| .envrc | ||
| .envrc.example | ||
| .gitignore | ||
| clangd-wrapper.sh | ||
| CMakeLists.txt | ||
| GUI_PLAN.md | ||
| LSP_SETUP.md | ||
| PLAN.md | ||
| README.md | ||
warppipe
A C++17 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
- 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++17 compiler
cmake -S . -B build
cmake --build build
Targets: warppipe (library), warppipe_example, warppipe_cli, warppipe_tests, warppipe_perf
Dependencies
- libpipewire-0.3 — system package
- nlohmann/json — fetched automatically via CMake FetchContent
- Catch2 v3 — fetched automatically via CMake FetchContent
Quick Start
#include <warppipe/warppipe.hpp>
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 <node-id>
warppipe_cli list-links
warppipe_cli list-rules
warppipe_cli create-sink <name> [--rate N] [--channels N]
warppipe_cli create-source <name> [--rate N] [--channels N]
warppipe_cli link <out-node> <out-port> <in-node> <in-port> [--passive] [--linger]
warppipe_cli unlink <link-id>
warppipe_cli add-rule --app <name> --target <node> [--process <bin>] [--role <role>]
warppipe_cli remove-rule <rule-id>
warppipe_cli save-config <path>
warppipe_cli load-config <path>
warppipe_cli defaults
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.
{
"version": 1,
"virtual_nodes": [
{
"name": "warppipe-gaming-sink",
"is_source": false,
"rate": 48000,
"channels": 2,
"loopback": false,
"target_node": ""
}
],
"route_rules": [
{
"match": {
"application_name": "Firefox",
"process_binary": "",
"media_role": ""
},
"target_node": "warppipe-gaming-sink"
}
]
}
See docs/config-schema.md for full schema documentation.
Policy-Only Mode
When running alongside WirePlumber, enable policy_only to prevent warppipe from creating links that conflict with the session manager:
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 — full API, threading model, error model, performance notes
- Config Schema — JSON configuration format and persistence behavior
Tests
./build/warppipe_tests
31 test cases covering connection, registry, virtual nodes, links, route rules, policy engine, persistence, and metadata.
Performance
./build/warppipe_perf --mode <create-destroy|registry|links|policy|e2e>
| 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 |