mirror of
https://gitlab.freedesktop.org/pipewire/helvum
synced 2026-03-15 19:46:10 +08:00
Delete items from graph when they are removed by the pipewire server.
This commit is contained in:
@@ -1,50 +1,64 @@
|
||||
use crate::PipewireLink;
|
||||
use crate::pipewire_state::PipewireState;
|
||||
|
||||
use gtk::glib::{self, clone};
|
||||
use pipewire as pw;
|
||||
use pw::{port::Direction, registry::ObjectType, PW_ID_CORE};
|
||||
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
/// This struct is responsible for communication with the pipewire server.
|
||||
/// It handles new globals appearing as well as globals being removed.
|
||||
///
|
||||
/// It's `roundtrip` function must be called regularly to receive updates.
|
||||
pub struct PipewireConnection {
|
||||
mainloop: pw::MainLoop,
|
||||
_context: pw::Context<pw::MainLoop>,
|
||||
core: pw::Core,
|
||||
core: Rc<pw::Core>,
|
||||
_registry: pw::registry::Registry,
|
||||
_reg_listeners: pw::registry::Listener,
|
||||
_listeners: pw::registry::Listener,
|
||||
_state: Rc<RefCell<PipewireState>>,
|
||||
}
|
||||
|
||||
impl PipewireConnection {
|
||||
pub fn new(graphview: Rc<RefCell<crate::view::GraphView>>) -> Result<Self, String> {
|
||||
pub fn new(state: PipewireState) -> Result<Self, String> {
|
||||
// Initialize pipewire lib and obtain needed pipewire objects.
|
||||
pw::init();
|
||||
let mainloop = pw::MainLoop::new().map_err(|_| "Failed to create pipewire mainloop!")?;
|
||||
let context =
|
||||
pw::Context::new(&mainloop).map_err(|_| "Failed to create pipewire context")?;
|
||||
let core = context
|
||||
.connect()
|
||||
.map_err(|_| "Failed to connect to pipewire core")?;
|
||||
let core = Rc::new(
|
||||
context
|
||||
.connect()
|
||||
.map_err(|_| "Failed to connect to pipewire core")?,
|
||||
);
|
||||
let registry = core.get_registry();
|
||||
|
||||
let graphview = Rc::downgrade(&graphview.clone());
|
||||
let reg_listeners = registry
|
||||
let state = Rc::new(RefCell::new(state));
|
||||
|
||||
// Notify state on globals added / removed
|
||||
let _listeners = registry
|
||||
.add_listener_local()
|
||||
.global(move |global| {
|
||||
PipewireConnection::handle_global(graphview.upgrade().unwrap(), global)
|
||||
})
|
||||
.global_remove(|_| { /* TODO */ })
|
||||
.global(clone!(@weak state => @default-panic, move |global| {
|
||||
state.borrow_mut().global(global);
|
||||
}))
|
||||
.global_remove(clone!(@weak state => @default-panic, move |id| {
|
||||
state.borrow_mut().global_remove(id);
|
||||
}))
|
||||
.register();
|
||||
|
||||
Ok(Self {
|
||||
mainloop,
|
||||
mainloop: mainloop,
|
||||
_context: context,
|
||||
core,
|
||||
_registry: registry,
|
||||
_reg_listeners: reg_listeners,
|
||||
_listeners,
|
||||
_state: state,
|
||||
})
|
||||
}
|
||||
|
||||
/// Receive all events from the pipewire server, sending them to the `pipewire_state` struct for processing.
|
||||
pub fn roundtrip(&self) {
|
||||
let done = Rc::new(Cell::new(false));
|
||||
let pending = self.core.sync(0);
|
||||
@@ -56,7 +70,7 @@ impl PipewireConnection {
|
||||
.core
|
||||
.add_listener_local()
|
||||
.done(move |id, seq| {
|
||||
if id == PW_ID_CORE && seq == pending {
|
||||
if id == pw::PW_ID_CORE && seq == pending {
|
||||
done_clone.set(true);
|
||||
loop_clone.quit();
|
||||
}
|
||||
@@ -67,89 +81,4 @@ impl PipewireConnection {
|
||||
self.mainloop.run();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_global(
|
||||
graphview: Rc<RefCell<crate::view::GraphView>>,
|
||||
global: pw::registry::GlobalObject,
|
||||
) {
|
||||
match global.type_ {
|
||||
ObjectType::Node => {
|
||||
let node_widget = crate::view::Node::new(&format!(
|
||||
"{}",
|
||||
global
|
||||
.props
|
||||
.map(|dict| String::from(
|
||||
dict.get("node.nick")
|
||||
.or(dict.get("node.description"))
|
||||
.or(dict.get("node.name"))
|
||||
.unwrap_or_default()
|
||||
))
|
||||
.unwrap_or_default()
|
||||
));
|
||||
|
||||
graphview.borrow_mut().add_node(global.id, node_widget);
|
||||
}
|
||||
ObjectType::Port => {
|
||||
let props = global.props.expect("Port object is missing properties");
|
||||
let port_label = format!("{}", props.get("port.name").unwrap_or_default());
|
||||
let node_id: u32 = props
|
||||
.get("node.id")
|
||||
.expect("Port has no node.id property!")
|
||||
.parse()
|
||||
.expect("Could not parse node.id property");
|
||||
let port = crate::view::port::Port::new(
|
||||
global.id,
|
||||
&port_label,
|
||||
if matches!(props.get("port.direction"), Some("in")) {
|
||||
Direction::Input
|
||||
} else {
|
||||
Direction::Output
|
||||
},
|
||||
);
|
||||
|
||||
graphview
|
||||
.borrow_mut()
|
||||
.add_port_to_node(node_id, global.id, port);
|
||||
}
|
||||
ObjectType::Link => {
|
||||
let props = global.props.expect("Link object is missing properties");
|
||||
let input_node: u32 = props
|
||||
.get("link.input.node")
|
||||
.expect("Link has no link.input.node property")
|
||||
.parse()
|
||||
.expect("Could not parse link.input.node property");
|
||||
let input_port: u32 = props
|
||||
.get("link.input.port")
|
||||
.expect("Link has no link.input.port property")
|
||||
.parse()
|
||||
.expect("Could not parse link.input.port property");
|
||||
let output_node: u32 = props
|
||||
.get("link.output.node")
|
||||
.expect("Link has no link.input.node property")
|
||||
.parse()
|
||||
.expect("Could not parse link.input.node property");
|
||||
let output_port: u32 = props
|
||||
.get("link.output.port")
|
||||
.expect("Link has no link.output.port property")
|
||||
.parse()
|
||||
.expect("Could not parse link.output.port property");
|
||||
graphview.borrow_mut().add_link(
|
||||
global.id,
|
||||
PipewireLink {
|
||||
node_from: output_node,
|
||||
port_from: output_port,
|
||||
node_to: input_node,
|
||||
port_to: input_port,
|
||||
},
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*impl Drop for PipewireConnection {
|
||||
fn drop(&mut self) {
|
||||
unsafe { pw::deinit() }
|
||||
}
|
||||
}*/
|
||||
|
||||
Reference in New Issue
Block a user