Rosenthal/rosenthal/packages/patches/rust-pipewire.patch
Hilton Chain f8c9cd9dcc
rosenthal: Add niri.
* rosenthal/packages/patches/niri.patch: New file.
* rosenthal/packages/patches/rust-libspa-sys.patch: New file.
* rosenthal/packages/patches/rust-libspa.patch: New file.
* rosenthal/packages/patches/rust-pipewire.patch: New file.
* rosenthal/packages/patches/rust-smithay.patch: New file.
* rosenthal/packages/rust-crates.scm (niri-cargo-inputs): New variable.
* rosenthal/packages/rust-apps.scm (niri): New variable.
* README.org (Packages): Add it.
* etc/manifest: Add it.
2025-02-26 21:33:15 +08:00

346 lines
11 KiB
Diff

diff --git a/Cargo.toml b/Cargo.toml
index bef8079..f795a3e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -45,7 +45,7 @@ version = "2"
version = "0.2"
[dependencies.nix]
-version = "0.27"
+version = "0.29"
features = [
"signal",
"fs",
diff --git a/src/channel.rs b/src/channel.rs
index 3c8c742..672cddc 100644
--- a/src/channel.rs
+++ b/src/channel.rs
@@ -89,7 +89,11 @@ impl<T: 'static> Receiver<T> {
F: Fn(T) + 'static,
{
let channel = self.channel.clone();
- let readfd = channel.lock().expect("Channel mutex lock poisoned").readfd;
+ let readfd = channel
+ .lock()
+ .expect("Channel mutex lock poisoned")
+ .readfd
+ .as_raw_fd();
// Attach the pipe as an IO source to the loop.
// Whenever the pipe is written to, call the users callback with each message in the queue.
@@ -97,7 +101,7 @@ impl<T: 'static> Receiver<T> {
let mut channel = channel.lock().expect("Channel mutex lock poisoned");
// Read from the pipe to make it block until written to again.
- let _ = nix::unistd::read(channel.readfd, &mut [0]);
+ let _ = nix::unistd::read(channel.readfd.as_raw_fd(), &mut [0]);
channel.queue.drain(..).for_each(&callback);
});
@@ -162,7 +166,7 @@ impl<T> Sender<T> {
// If no messages are waiting already, signal the receiver to read some.
// Because the channel mutex is locked, it is alright to do this before pushing the message.
if channel.queue.is_empty() {
- match nix::unistd::write(channel.writefd, &[1u8]) {
+ match nix::unistd::write(&channel.writefd, &[1u8]) {
Ok(_) => (),
Err(_) => return Err(t),
}
@@ -178,21 +182,12 @@ impl<T> Sender<T> {
/// Shared state between the [`Sender`]s and the [`Receiver`].
struct Channel<T> {
/// A pipe used to signal the loop the receiver is attached to that messages are waiting.
- readfd: RawFd,
- writefd: RawFd,
+ readfd: OwnedFd,
+ writefd: OwnedFd,
/// Queue of any messages waiting to be received.
queue: VecDeque<T>,
}
-impl<T> Drop for Channel<T> {
- fn drop(&mut self) {
- // We do not error check here, because the pipe does not contain any data that might be lost,
- // and because there is no way to handle an error in a `Drop` implementation anyways.
- let _ = nix::unistd::close(self.readfd);
- let _ = nix::unistd::close(self.writefd);
- }
-}
-
/// Create a Sender-Receiver pair, where the sender can be used to send messages to the receiver.
///
/// This functions similar to [`std::sync::mpsc`], but with a receiver that can be attached to any
diff --git a/src/client.rs b/src/client.rs
index cd28024..89f71e7 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -5,7 +5,10 @@ use bitflags::bitflags;
use libc::c_void;
use std::ops::Deref;
use std::pin::Pin;
-use std::{ffi::CString, ptr};
+use std::{
+ ffi::{CStr, CString},
+ ptr,
+};
use std::{fmt, mem};
use crate::{
@@ -53,7 +56,11 @@ impl Client {
pub fn error(&self, id: u32, res: i32, message: &str) {
let message = CString::new(message).expect("Null byte in message parameter");
+ let message_cstr = message.as_c_str();
+ Client::error_cstr(self, id, res, message_cstr)
+ }
+ pub fn error_cstr(&self, id: u32, res: i32, message: &CStr) {
unsafe {
spa_interface_call_method!(
self.proxy.as_ptr(),
diff --git a/src/core.rs b/src/core.rs
index 960c3c2..1feb79f 100644
--- a/src/core.rs
+++ b/src/core.rs
@@ -126,8 +126,17 @@ impl CoreRef {
factory_name: &str,
properties: &impl AsRef<spa::utils::dict::DictRef>,
) -> Result<P, Error> {
- let type_ = P::type_();
let factory_name = CString::new(factory_name).expect("Null byte in factory_name parameter");
+ let factory_name_cstr = factory_name.as_c_str();
+ CoreRef::create_object_cstr(self, factory_name_cstr, properties)
+ }
+
+ pub fn create_object_cstr<P: ProxyT>(
+ &self,
+ factory_name: &CStr,
+ properties: &impl AsRef<spa::utils::dict::DictRef>,
+ ) -> Result<P, Error> {
+ let type_ = P::type_();
let type_str = CString::new(type_.to_string())
.expect("Null byte in string representation of type_ parameter");
diff --git a/src/lib.rs b/src/lib.rs
index e63490c..7f100df 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -140,12 +140,6 @@ mod utils;
pub use pw_sys as sys;
pub use spa;
-// Re-export all the traits in a prelude module, so that applications
-// can always "use pipewire::prelude::*" without getting conflicts
-pub mod prelude {
- pub use spa::prelude::*;
-}
-
use std::ptr;
/// Initialize PipeWire
diff --git a/src/loop_.rs b/src/loop_.rs
index 01560c4..3dfa8bc 100644
--- a/src/loop_.rs
+++ b/src/loop_.rs
@@ -635,7 +635,14 @@ impl<'l> TimerSource<'l> {
fn duration_to_timespec(duration: Duration) -> spa_sys::timespec {
spa_sys::timespec {
tv_sec: duration.as_secs().try_into().expect("Duration too long"),
- tv_nsec: duration.subsec_nanos().try_into().unwrap(),
+ // `Into` is only implemented on some platforms for these types,
+ // so use a fallible conversion.
+ // As there are a limited amount of nanoseconds in a second, this shouldn't fail
+ #[allow(clippy::unnecessary_fallible_conversions)]
+ tv_nsec: duration
+ .subsec_nanos()
+ .try_into()
+ .expect("Nanoseconds should fit into timespec"),
}
}
diff --git a/src/metadata.rs b/src/metadata.rs
index 64a68e1..ebdc3e7 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -55,6 +55,18 @@ impl Metadata {
let key = CString::new(key).expect("Invalid byte in metadata key");
let type_ = type_.map(|t| CString::new(t).expect("Invalid byte in metadata type"));
let value = value.map(|v| CString::new(v).expect("Invalid byte in metadata value"));
+ let key_cstr = key.as_c_str();
+
+ Metadata::set_property_cstr(self, subject, key_cstr, type_.as_deref(), value.as_deref())
+ }
+
+ pub fn set_property_cstr(
+ &self,
+ subject: u32,
+ key: &CStr,
+ type_: Option<&CStr>,
+ value: Option<&CStr>,
+ ) {
unsafe {
spa::spa_interface_call_method!(
self.proxy.as_ptr(),
@@ -62,8 +74,8 @@ impl Metadata {
set_property,
subject,
key.as_ptr() as *const _,
- type_.as_deref().map_or_else(ptr::null, CStr::as_ptr) as *const _,
- value.as_deref().map_or_else(ptr::null, CStr::as_ptr) as *const _
+ type_.map_or_else(ptr::null, CStr::as_ptr) as *const _,
+ value.map_or_else(ptr::null, CStr::as_ptr) as *const _
);
}
}
diff --git a/src/permissions.rs b/src/permissions.rs
index bdb011c..7d445ad 100644
--- a/src/permissions.rs
+++ b/src/permissions.rs
@@ -16,17 +16,33 @@ bitflags! {
}
}
+#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Permission(pw_sys::pw_permission);
impl Permission {
+ pub fn new(id: u32, flags: PermissionFlags) -> Self {
+ Self(pw_sys::pw_permission {
+ id,
+ permissions: flags.bits(),
+ })
+ }
+
pub fn id(&self) -> u32 {
self.0.id
}
+ pub fn set_id(&mut self, id: u32) {
+ self.0.id = id;
+ }
+
pub fn permission_flags(&self) -> PermissionFlags {
PermissionFlags::from_bits_retain(self.0.permissions)
}
+
+ pub fn set_permission_flags(&mut self, flags: PermissionFlags) {
+ self.0.permissions = flags.bits();
+ }
}
impl fmt::Debug for Permission {
diff --git a/src/properties.rs b/src/properties.rs
index c71cf72..008bed6 100644
--- a/src/properties.rs
+++ b/src/properties.rs
@@ -1,4 +1,10 @@
-use std::{ffi::CString, fmt, mem::ManuallyDrop, ops::Deref, ptr};
+use std::{
+ ffi::{CStr, CString},
+ fmt,
+ mem::ManuallyDrop,
+ ops::Deref,
+ ptr,
+};
/// A collection of key/value pairs.
///
@@ -36,7 +42,6 @@ pub struct Properties {
///
/// Any expression that evaluates to a `impl Into<Vec<u8>>` can be used for both keys and values.
/// ```rust
-/// use pipewire::prelude::*;
/// use pipewire::properties::properties;
///
/// let key = String::from("Key");
@@ -149,6 +154,19 @@ impl Clone for Properties {
}
}
+impl<K, V> FromIterator<(K, V)> for Properties
+where
+ K: Into<Vec<u8>>,
+ V: Into<Vec<u8>>,
+{
+ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
+ let mut props = Self::new();
+ props.extend(iter);
+
+ props
+ }
+}
+
impl Drop for Properties {
fn drop(&mut self) {
unsafe { pw_sys::pw_properties_free(self.ptr.as_ptr()) }
@@ -196,6 +214,11 @@ impl PropertiesRef {
pub fn get(&self, key: &str) -> Option<&str> {
let key = CString::new(key).expect("key contains null byte");
+ let key_cstr = key.as_c_str();
+ PropertiesRef::get_cstr(self, key_cstr)
+ }
+
+ pub fn get_cstr(&self, key: &CStr) -> Option<&str> {
let res =
unsafe { pw_sys::pw_properties_get(self.as_raw_ptr().cast_const(), key.as_ptr()) };
@@ -245,6 +268,18 @@ impl fmt::Debug for PropertiesRef {
}
}
+impl<K, V> Extend<(K, V)> for PropertiesRef
+where
+ K: Into<Vec<u8>>,
+ V: Into<Vec<u8>>,
+{
+ fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
+ for (k, v) in iter {
+ self.insert(k, v);
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/stream.rs b/src/stream.rs
index ff28af8..e04ff64 100644
--- a/src/stream.rs
+++ b/src/stream.rs
@@ -64,6 +64,13 @@ impl Stream {
/// Initialises a new stream with the given `name` and `properties`.
pub fn new(core: &Core, name: &str, properties: Properties) -> Result<Self, Error> {
let name = CString::new(name).expect("Invalid byte in stream name");
+
+ let c_str = name.as_c_str();
+ Stream::new_cstr(core, c_str, properties)
+ }
+
+ /// Initialises a new stream with the given `name` as Cstr and `properties`.
+ pub fn new_cstr(core: &Core, name: &CStr, properties: Properties) -> Result<Self, Error> {
let stream = unsafe {
pw_sys::pw_stream_new(core.as_raw_ptr(), name.as_ptr(), properties.into_raw())
};
@@ -249,8 +256,18 @@ impl StreamRef {
///
pub fn set_error(&mut self, res: i32, error: &str) {
let error = CString::new(error).expect("failed to convert error to CString");
+ let error_cstr = error.as_c_str();
+ StreamRef::set_error_cstr(self, res, error_cstr)
+ }
+
+ /// Set the stream in error state with CStr
+ ///
+ /// # Panics
+ /// Will panic if `error` contains a 0 byte.
+ ///
+ pub fn set_error_cstr(&mut self, res: i32, error: &CStr) {
unsafe {
- pw_sys::pw_stream_set_error(self.as_raw_ptr(), res, error.as_c_str().as_ptr());
+ pw_sys::pw_stream_set_error(self.as_raw_ptr(), res, error.as_ptr());
}
}