diff --git a/Cargo.lock b/Cargo.lock index 173c8d2..b99ad94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,6 +164,16 @@ dependencies = [ "libc", ] +[[package]] +name = "annotate-snippets" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +dependencies = [ + "unicode-width", + "yansi-term", +] + [[package]] name = "anyhow" version = "1.0.79" @@ -499,16 +509,17 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bindgen" -version = "0.66.1" +version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ + "annotate-snippets", "bitflags 2.4.2", "cexpr", "clang-sys", + "itertools", "lazy_static", "lazycell", - "peeking_take_while", "proc-macro2", "quote", "regex", @@ -1191,6 +1202,12 @@ dependencies = [ "egui", ] +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "emath" version = "0.26.2" @@ -1803,6 +1820,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "jni" version = "0.21.1" @@ -1922,8 +1948,8 @@ dependencies = [ [[package]] name = "libspa" -version = "0.7.2" -source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f#7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f" +version = "0.8.0" +source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=605d15996f3258b3e1cc34e445dfbdf16a366c7e#605d15996f3258b3e1cc34e445dfbdf16a366c7e" dependencies = [ "bitflags 2.4.2", "cc", @@ -1931,15 +1957,15 @@ dependencies = [ "cookie-factory", "libc", "libspa-sys", - "nix", + "nix 0.27.1", "nom", "system-deps", ] [[package]] name = "libspa-sys" -version = "0.7.2" -source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f#7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f" +version = "0.8.0" +source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=605d15996f3258b3e1cc34e445dfbdf16a366c7e#605d15996f3258b3e1cc34e445dfbdf16a366c7e" dependencies = [ "bindgen", "cc", @@ -2114,7 +2140,17 @@ dependencies = [ "cfg-if", "libc", "memoffset 0.7.1", - "pin-utils", +] + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "libc", ] [[package]] @@ -2319,12 +2355,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -2356,15 +2386,15 @@ dependencies = [ [[package]] name = "pipewire" -version = "0.7.2" -source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f#7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f" +version = "0.8.0" +source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=605d15996f3258b3e1cc34e445dfbdf16a366c7e#605d15996f3258b3e1cc34e445dfbdf16a366c7e" dependencies = [ "anyhow", "bitflags 2.4.2", "libc", "libspa", "libspa-sys", - "nix", + "nix 0.27.1", "once_cell", "pipewire-sys", "thiserror", @@ -2372,8 +2402,8 @@ dependencies = [ [[package]] name = "pipewire-sys" -version = "0.7.2" -source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f#7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f" +version = "0.8.0" +source = "git+https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git?rev=605d15996f3258b3e1cc34e445dfbdf16a366c7e#605d15996f3258b3e1cc34e445dfbdf16a366c7e" dependencies = [ "bindgen", "libspa-sys", @@ -3897,7 +3927,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" dependencies = [ "gethostname 0.3.0", - "nix", + "nix 0.26.4", "winapi", "winapi-wsapoll", "x11rb-protocol 0.12.0", @@ -3924,7 +3954,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc" dependencies = [ - "nix", + "nix 0.26.4", ] [[package]] @@ -3974,6 +4004,15 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" +[[package]] +name = "yansi-term" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" +dependencies = [ + "winapi", +] + [[package]] name = "zbus" version = "3.15.0" @@ -3998,7 +4037,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix", + "nix 0.26.4", "once_cell", "ordered-stream", "rand", diff --git a/Cargo.toml b/Cargo.toml index 1d6a12b..284b0e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ categories = ["gui", "multimedia"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -pipewire = {version = "*", git = "https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git", rev = "7bd8b2d3c5d91f56b20c345e97244fff9e58ea0f"} +pipewire = {version = "*", git = "https://gitlab.freedesktop.org/dimtpap/pipewire-rs.git", rev = "605d15996f3258b3e1cc34e445dfbdf16a366c7e"} egui_node_graph = {version = "*", git = "https://github.com/dimtpap/egui_node_graph.git", rev = "a2e93a2826f90c21f13fa8fecf9076da611432fd"} eframe = {version = "0.26.2", features = ["wayland"]} egui_plot = "0.26.2" diff --git a/src/backend/bind.rs b/src/backend/bind.rs index b890cc6..37f0f29 100644 --- a/src/backend/bind.rs +++ b/src/backend/bind.rs @@ -21,7 +21,7 @@ use pipewire::{ self as pw, proxy::{Proxy, ProxyT}, registry::GlobalObject, - spa::ForeignDict, + spa::utils::dict::DictRef, types::ObjectType, }; @@ -66,9 +66,9 @@ impl From for Error { } impl BoundGlobal { - pub fn bind_to( + pub fn bind_to>( registry: &pw::registry::Registry, - global: &GlobalObject, + global: &GlobalObject<&P>, sx: &std::sync::mpsc::Sender, proxy_removed: impl Fn() + 'static, ) -> Result { @@ -135,7 +135,7 @@ impl BoundGlobal { } ObjectMethod::ClientUpdateProperties(props) => { if let Global::Client(ref client) = self.global { - client.update_properties(&util::key_val_to_props(props.into_iter())); + client.update_properties(util::key_val_to_props(props.into_iter()).dict()); } } ObjectMethod::MetadataSetProperty { diff --git a/src/backend/connection.rs b/src/backend/connection.rs index f82ae93..a5aa9c3 100644 --- a/src/backend/connection.rs +++ b/src/backend/connection.rs @@ -90,11 +90,11 @@ impl From for Error { } #[cfg(not(feature = "xdg_desktop_portals"))] -pub struct Connection(pw::Core); +pub struct Connection(pw::core::Core); #[cfg(not(feature = "xdg_desktop_portals"))] impl Connection { pub fn connect( - context: &pw::Context, + context: &pw::context::Context, context_properties: Vec<(String, String)>, remote: RemoteInfo, ) -> Result { @@ -106,21 +106,21 @@ impl Connection { )?)) } - pub const fn core(&self) -> &pw::Core { + pub const fn core(&self) -> &pw::core::Core { &self.0 } } #[cfg(feature = "xdg_desktop_portals")] pub enum Connection<'s> { - Simple(pw::Core), - PortalWithSession(pw::Core, Session<'s>), + Simple(pw::core::Core), + PortalWithSession(pw::core::Core, Session<'s>), } #[cfg(feature = "xdg_desktop_portals")] impl<'s> Connection<'s> { pub fn connect( - context: &pw::Context, + context: &pw::context::Context, context_properties: Vec<(String, String)>, remote: RemoteInfo, ) -> Result { @@ -147,7 +147,7 @@ impl<'s> Connection<'s> { } } - pub const fn core(&self) -> &pw::Core { + pub const fn core(&self) -> &pw::core::Core { match self { Self::Simple(core) | Self::PortalWithSession(core, _) => core, } diff --git a/src/backend/listeners.rs b/src/backend/listeners.rs index 18fe843..828512c 100644 --- a/src/backend/listeners.rs +++ b/src/backend/listeners.rs @@ -163,8 +163,8 @@ pub fn port(port: pw::port::Port, id: u32, sx: std::sync::mpsc::Sender) - .info({ move |info| { let direction = match info.direction() { - pw::spa::Direction::Input => "Input", - pw::spa::Direction::Output => "Output", + pw::spa::utils::Direction::Input => "Input", + pw::spa::utils::Direction::Output => "Output", _ => "Invalid", } .to_owned(); diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 2f4ae64..eb8fa37 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -31,7 +31,7 @@ pub enum ObjectMethod { index: u32, num: u32, }, - ClientUpdatePermissions(Vec), + ClientUpdatePermissions(Vec), ClientUpdateProperties(std::collections::BTreeMap), MetadataSetProperty { subject: u32, @@ -66,7 +66,7 @@ pub enum Event { GlobalRemoved(u32), GlobalInfo(u32, Box<[(&'static str, String)]>), GlobalProperties(u32, std::collections::BTreeMap), - ClientPermissions(u32, u32, Vec), + ClientPermissions(u32, u32, Vec), ProfilerProfile(Vec), MetadataProperty { id: u32, diff --git a/src/backend/pipewire.rs b/src/backend/pipewire.rs index e036ff2..e0473c6 100644 --- a/src/backend/pipewire.rs +++ b/src/backend/pipewire.rs @@ -36,18 +36,20 @@ pub fn pipewire_thread( struct LocalProxy(pw::proxy::Proxy, pw::proxy::ProxyListener); let (mainloop, context, connection, registry): ( - pw::MainLoop, - Rc, + pw::main_loop::MainLoop, + pw::context::Context, Connection, Rc, ) = match (|| { let mainloop = if mainloop_properties.is_empty() { - pw::MainLoop::new()? + pw::main_loop::MainLoop::new(None)? } else { - pw::MainLoop::with_properties(&util::key_val_to_props(mainloop_properties.into_iter()))? + pw::main_loop::MainLoop::new(Some( + &util::key_val_to_props(mainloop_properties.into_iter()).dict(), + ))? }; - let context = pw::Context::new(&mainloop)?; + let context = pw::context::Context::new(&mainloop)?; if context .load_module("libpipewire-module-profiler", None, None) .is_err() @@ -59,9 +61,7 @@ pub fn pipewire_thread( let registry = connection.core().get_registry()?; - // Context needs to be moved to the loop listener - // but must outlive it to prevent resource leaks - Ok((mainloop, Rc::new(context), connection, Rc::new(registry))) + Ok((mainloop, context, connection, Rc::new(registry))) })() { Ok(instance) => instance, Err(e) => { @@ -87,10 +87,10 @@ pub fn pipewire_thread( let binds = Rc::new(RefCell::new(HashMap::::new())); - let _receiver = pwrx.attach(&mainloop, { + let _receiver = pwrx.attach(mainloop.loop_(), { let sx = sx.clone(); let mainloop = mainloop.clone(); - let context = Rc::clone(&context); + let context = context.clone(); let core = core.clone(); let registry = Rc::clone(®istry); @@ -109,31 +109,31 @@ pub fn pipewire_thread( let proxy = match object_type { ObjectType::Link => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Port => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Node => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Client => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Device => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Factory => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Metadata => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Module => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), ObjectType::Profiler => core - .create_object::(factory.as_str(), &props) + .create_object::(factory.as_str(), &props) .map(ProxyT::upcast), _ => { eprintln!("{object_type} unimplemented"); @@ -196,10 +196,10 @@ pub fn pipewire_thread( } } Request::GetContextProperties => { - sx.send(Event::ContextProperties(util::dict_to_map(&context.properties()))).ok(); + sx.send(Event::ContextProperties(util::dict_to_map(context.properties().dict()))).ok(); } Request::UpdateContextProperties(props) => { - context.update_properties(&util::key_val_to_props(props.into_iter())); + context.update_properties(&util::key_val_to_props(props.into_iter()).dict()); } Request::CallObjectMethod(id, method) => { if let Some(object) = binds.borrow().get(&id) { @@ -238,7 +238,7 @@ pub fn pipewire_thread( sx.send(Event::GlobalInfo(0, infos)).ok(); if let (true, Some(props)) = ( - info.change_mask().contains(pw::ChangeMask::PROPS), + info.change_mask().contains(pw::core::ChangeMask::PROPS), info.props(), ) { sx.send(Event::GlobalProperties(0, util::dict_to_map(props))) @@ -273,7 +273,7 @@ pub fn pipewire_thread( sx.send(Event::GlobalAdded( global.id, global.type_.clone(), - global.props.as_ref().map(util::dict_to_map), + global.props.map(util::dict_to_map), )) .ok(); @@ -307,7 +307,7 @@ pub fn pipewire_thread( .register(); sx.send(Event::ContextProperties(util::dict_to_map( - &context.properties(), + context.properties().dict(), ))) .ok(); diff --git a/src/backend/util.rs b/src/backend/util.rs index b4f087d..5457418 100644 --- a/src/backend/util.rs +++ b/src/backend/util.rs @@ -16,12 +16,9 @@ use std::collections::BTreeMap; -use pipewire::{ - self as pw, - spa::{ReadableDict, WritableDict}, -}; +use pipewire::{self as pw, spa::utils::dict::DictRef}; -pub fn dict_to_map<'a, K, V>(dict: &'a impl ReadableDict) -> BTreeMap +pub fn dict_to_map<'a, K, V>(dict: &'a DictRef) -> BTreeMap where K: From<&'a str> + Ord, V: From<&'a str>, @@ -35,8 +32,8 @@ where pub fn key_val_to_props( kv: impl Iterator>, impl Into>)>, -) -> pw::Properties { - let mut props = pw::Properties::new(); +) -> pw::properties::Properties { + let mut props = pw::properties::Properties::new(); for (k, v) in kv { props.insert(k, v); } @@ -44,10 +41,10 @@ pub fn key_val_to_props( } pub fn connect_override_env( - context: &pw::Context, - mut context_properties: pw::Properties, + context: &pw::context::Context, + mut context_properties: pw::properties::Properties, remote_name: String, -) -> Result { +) -> Result { let env_remote = std::env::var_os("PIPEWIRE_REMOTE"); if env_remote.is_some() { std::env::remove_var("PIPEWIRE_REMOTE"); diff --git a/src/ui/global.rs b/src/ui/global.rs index fc5c0c8..5f6aaef 100644 --- a/src/ui/global.rs +++ b/src/ui/global.rs @@ -22,38 +22,42 @@ use std::{ }; use eframe::egui; -use pipewire::{self as pw, permissions::Permissions, registry::Permission, types::ObjectType}; +use pipewire::{ + self as pw, + permissions::{Permission, PermissionFlags}, + types::ObjectType, +}; use crate::{ backend::{self, ObjectMethod, Request}, ui::util::uis::{key_val_display, map_editor, EditableKVList}, }; -fn draw_permissions(ui: &mut egui::Ui, p: &mut Permissions) { - static PERMISSIONS: OnceLock<&[(Permission, &'static str)]> = OnceLock::new(); +fn draw_permissions(ui: &mut egui::Ui, p: &mut Permission) { + static PERMISSIONS: OnceLock<&[(PermissionFlags, &'static str)]> = OnceLock::new(); ui.label("ID"); - ui.add(egui::widgets::DragValue::new(&mut p.id)); + ui.add(egui::widgets::DragValue::new(&mut p.id())); for (permission, label) in PERMISSIONS .get_or_init(|| { #[cfg(feature = "pw_v0_3_77")] if crate::backend::remote_version().is_some_and(|ver| ver.0 > 0 || ver.2 >= 77) { return [ - (Permission::R, "Read"), - (Permission::W, "Write"), - (Permission::X, "Execute"), - (Permission::M, "Metadata"), - (Permission::L, "Link"), + (PermissionFlags::R, "Read"), + (PermissionFlags::W, "Write"), + (PermissionFlags::X, "Execute"), + (PermissionFlags::M, "Metadata"), + (PermissionFlags::L, "Link"), ] .as_slice(); } [ - (Permission::R, "Read"), - (Permission::W, "Write"), - (Permission::X, "Execute"), - (Permission::M, "Metadata"), + (PermissionFlags::R, "Read"), + (PermissionFlags::W, "Write"), + (PermissionFlags::X, "Execute"), + (PermissionFlags::M, "Metadata"), ] .as_slice() }) @@ -61,10 +65,13 @@ fn draw_permissions(ui: &mut egui::Ui, p: &mut Permissions) { .map(|(p, l)| (*p, *l)) { if ui - .selectable_label(p.permissions.contains(permission), label) + .selectable_label(p.permission_flags().contains(permission), label) .clicked() { - p.permissions.toggle(permission); + let mut flags = p.permission_flags(); + flags.toggle(permission); + + p.set_permission_flags(flags); } } } @@ -72,8 +79,8 @@ fn draw_permissions(ui: &mut egui::Ui, p: &mut Permissions) { /// Object type specific data pub enum ObjectData { Client { - permissions: Option>, - user_permissions: Vec, + permissions: Option>, + user_permissions: Vec, user_properties: EditableKVList, }, Other(ObjectType), @@ -143,10 +150,7 @@ impl ObjectData { }); if ui.button("Add").clicked() { - user_permissions.push(Permissions { - id: 0, - permissions: Permission::empty(), - }); + user_permissions.push(Permission::new(0, PermissionFlags::empty())); } });