1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
use std::{cell::Cell, rc::Rc};
use once_cell::unsync::OnceCell;
use pipewire as pw;
use pw::types::ObjectType;
fn main() {
// Initialize library and get the basic structures we need.
pw::init();
let mainloop =
pw::main_loop::MainLoopRc::new(None).expect("Failed to create Pipewire Mainloop");
let context =
pw::context::ContextRc::new(&mainloop, None).expect("Failed to create Pipewire Context");
let core = context
.connect_rc(None)
.expect("Failed to connect to Pipewire Core");
let registry = core.get_registry().expect("Failed to get Registry");
// Setup a registry listener that will obtain the name of a link factory and write it into `factory`.
let factory: Rc<OnceCell<String>> = Rc::new(OnceCell::new());
let factory_clone = factory.clone();
let mainloop_clone = mainloop.clone();
let reg_listener = registry
.add_listener_local()
.global(move |global| {
if let Some(props) = global.props {
// Check that the global is a factory that creates the right type.
if props.get("factory.type.name") == Some(ObjectType::Link.to_str()) {
let factory_name = props.get("factory.name").expect("Factory has no name");
factory_clone
.set(factory_name.to_owned())
.expect("Factory name already set");
// We found the factory we needed, so quit the loop.
mainloop_clone.quit();
}
}
})
.register();
// Process all pending events to get the factory.
do_roundtrip(&mainloop, &core);
// Now that we have our factory, we are no longer interested in any globals from the registry,
// so we unregister the listener by dropping it.
std::mem::drop(reg_listener);
// Now that we have the name of a link factory, we can create an object with it!
let link = core
.create_object::<pw::link::Link>(
factory.get().expect("No link factory found"),
&pw::properties::properties! {
"link.output.port" => "1",
"link.input.port" => "2",
"link.output.node" => "3",
"link.input.node" => "4",
// Don't remove the object on the remote when we destroy our proxy.
"object.linger" => "1"
},
)
.expect("Failed to create object");
// Do another roundtrip so that the link gets created on the server side.
do_roundtrip(&mainloop, &core);
// We have our object, now manually destroy it on the remote again.
core.destroy_object(link).expect("destroy object failed");
// Do a final roundtrip to destroy the link on the server side again.
do_roundtrip(&mainloop, &core);
}
/// Do a single roundtrip to process all events.
/// See the example in roundtrip.rs for more details on this.
fn do_roundtrip(mainloop: &pw::main_loop::MainLoopRc, core: &pw::core::CoreRc) {
let done = Rc::new(Cell::new(false));
let done_clone = done.clone();
let loop_clone = mainloop.clone();
// Trigger the sync event. The server's answer won't be processed until we start the main loop,
// so we can safely do this before setting up a callback. This lets us avoid using a Cell.
let pending = core.sync(0).expect("sync failed");
let _listener_core = core
.add_listener_local()
.done(move |id, seq| {
if id == pw::core::PW_ID_CORE && seq == pending {
done_clone.set(true);
loop_clone.quit();
}
})
.register();
while !done.get() {
mainloop.run();
}
}
|