Skip to content

Commit 3226b84

Browse files
committed
loop: Add bindings for pw_loop.
This adds a `Loop` struct for creating and managing a `pw_loop` struct. It also adds a `LoopRef` struct that is a transparent wrapper around `pw_loop`, and can be obtained from both a `Loop` and `MainLoop`. The methods previously on the loop trait are moved there, and the loop trait is now only responsible for obtaining such a `LoopRef` from any loop.
1 parent d60e8fc commit 3226b84

File tree

7 files changed

+312
-179
lines changed

7 files changed

+312
-179
lines changed

pipewire/examples/pw-mon.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,21 @@ fn monitor(remote: Option<String>) -> Result<()> {
5757
let main_loop = pw::MainLoop::new()?;
5858

5959
let main_loop_weak = main_loop.downgrade();
60-
let _sig_int = main_loop.add_signal_local(Signal::SIGINT, move || {
61-
if let Some(main_loop) = main_loop_weak.upgrade() {
62-
main_loop.quit();
63-
}
64-
});
60+
let _sig_int = main_loop
61+
.as_loop()
62+
.add_signal_local(Signal::SIGINT, move || {
63+
if let Some(main_loop) = main_loop_weak.upgrade() {
64+
main_loop.quit();
65+
}
66+
});
6567
let main_loop_weak = main_loop.downgrade();
66-
let _sig_term = main_loop.add_signal_local(Signal::SIGTERM, move || {
67-
if let Some(main_loop) = main_loop_weak.upgrade() {
68-
main_loop.quit();
69-
}
70-
});
68+
let _sig_term = main_loop
69+
.as_loop()
70+
.add_signal_local(Signal::SIGTERM, move || {
71+
if let Some(main_loop) = main_loop_weak.upgrade() {
72+
main_loop.quit();
73+
}
74+
});
7175

7276
let context = pw::Context::new(&main_loop)?;
7377
let props = remote.map(|remote| {

pipewire/src/channel.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// ignored because https://gitlab.freedesktop.org/pipewire/pipewire-rs/-/issues/19
1414
//! ```no_run
1515
//! use std::{time::Duration, sync::mpsc, thread};
16-
//! use pipewire::{MainLoop, Loop};
16+
//! use pipewire::{MainLoop, IsLoop};
1717
//!
1818
//! // Our message to the pipewire loop, this tells it to terminate.
1919
//! struct Terminate;
@@ -51,7 +51,7 @@
5151
//! });
5252
//!
5353
//! // Every 100ms, send `"Hello"` to the main thread.
54-
//! let timer = mainloop.add_timer(move |_| {
54+
//! let timer = mainloop.as_loop().add_timer(move |_| {
5555
//! main_sender.send(String::from("Hello"));
5656
//! });
5757
//! timer.update_timer(
@@ -70,7 +70,7 @@ use std::{
7070
sync::{Arc, Mutex},
7171
};
7272

73-
use crate::{IoSource, Loop};
73+
use crate::{IoSource, IsLoop};
7474
use spa::flags::IoFlags;
7575

7676
/// A receiver that has not been attached to a loop.
@@ -85,17 +85,17 @@ impl<T: 'static> Receiver<T> {
8585
///
8686
/// This will make the loop call the callback with any messages that get sent to the receiver.
8787
#[must_use]
88-
pub fn attach<F, L>(self, loop_: &L, callback: F) -> AttachedReceiver<T, L>
88+
pub fn attach<F, L>(self, loop_: &L, callback: F) -> AttachedReceiver<T>
8989
where
9090
F: Fn(T) + 'static,
91-
L: Loop,
91+
L: IsLoop,
9292
{
9393
let channel = self.channel.clone();
9494
let eventfd = channel.lock().expect("Channel mutex lock poisoned").eventfd;
9595

9696
// Attach the eventfd as an IO source to the loop.
9797
// Whenever the eventfd is signaled, call the users callback with each message in the queue.
98-
let iosource = loop_.add_io(eventfd, IoFlags::IN, move |_| {
98+
let iosource = loop_.as_loop().add_io(eventfd, IoFlags::IN, move |_| {
9999
let mut channel = channel.lock().expect("Channel mutex lock poisoned");
100100

101101
// Read from the eventfd to make it block until written to again.
@@ -121,19 +121,17 @@ impl<T: 'static> Receiver<T> {
121121
/// A [`Receiver`] that has been attached to a loop.
122122
///
123123
/// Dropping this will cause it to be deattached from the loop, so no more messages will be received.
124-
pub struct AttachedReceiver<'l, T, L>
124+
pub struct AttachedReceiver<'l, T>
125125
where
126126
T: 'static,
127-
L: Loop,
128127
{
129-
_source: IoSource<'l, RawFd, L>,
128+
_source: IoSource<'l, RawFd>,
130129
receiver: Receiver<T>,
131130
}
132131

133-
impl<'l, T, L> AttachedReceiver<'l, T, L>
132+
impl<'l, T> AttachedReceiver<'l, T>
134133
where
135134
T: 'static,
136-
L: Loop,
137135
{
138136
/// Deattach the receiver from the loop.
139137
///

pipewire/src/context.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,23 @@ use std::{os::unix::prelude::RawFd, ptr};
55

66
use crate::core_::Core;
77
use crate::error::Error;
8-
use crate::loop_::Loop;
8+
use crate::loop_::IsLoop;
99
use crate::properties::Properties;
1010

1111
#[derive(Debug)]
12-
pub struct Context<T: Loop + Clone> {
12+
pub struct Context<T: IsLoop + Clone> {
1313
ptr: ptr::NonNull<pw_sys::pw_context>,
1414
/// Store the loop here, so that the loop is not dropped before the context, which may lead to
1515
/// undefined behaviour.
1616
_loop: T,
1717
}
1818

19-
impl<T: Loop + Clone> Context<T> {
19+
impl<T: IsLoop + Clone> Context<T> {
2020
fn new_internal(loop_: &T, properties: Option<Properties>) -> Result<Self, Error> {
2121
let props = properties.map_or(ptr::null(), |props| props.into_raw()) as *mut _;
22-
let context = unsafe { pw_sys::pw_context_new(loop_.as_ptr(), props, 0) };
22+
let context = unsafe {
23+
pw_sys::pw_context_new(loop_.as_loop().as_raw() as *const _ as *mut _, props, 0)
24+
};
2325
let context = ptr::NonNull::new(context).ok_or(Error::CreationFailed)?;
2426

2527
Ok(Context {
@@ -63,7 +65,7 @@ impl<T: Loop + Clone> Context<T> {
6365
}
6466
}
6567

66-
impl<T: Loop + Clone> Drop for Context<T> {
68+
impl<T: IsLoop + Clone> Drop for Context<T> {
6769
fn drop(&mut self) {
6870
unsafe { pw_sys::pw_context_destroy(self.as_ptr()) }
6971
}

pipewire/src/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@
7777
//! For example, we can call a function on an interval:
7878
//!
7979
//! ```no_run
80-
//! // We also need to include the `Loop` trait for this.
81-
//! use pipewire::{MainLoop, Loop};
80+
//! // We also need to include the `IsLoop` trait for this.
81+
//! use pipewire::{MainLoop, IsLoop};
8282
//! use std::time::Duration;
8383
//!
8484
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
8585
//! let mainloop = MainLoop::new()?;
8686
//!
87-
//! let timer = mainloop.add_timer(|_| println!("Hello"));
87+
//! let timer = mainloop.as_loop().add_timer(|_| println!("Hello"));
8888
//! // Call the first time in half a second, and then in a one second interval.
8989
//! timer.update_timer(Some(Duration::from_millis(500)), Some(Duration::from_secs(1))).into_result()?;
9090
//!
@@ -95,7 +95,7 @@
9595
//! ```
9696
//! This program will print out "Hello" every second forever.
9797
//!
98-
//! You can also react to IO or Signals using similar methods on the [`Loop`] trait.
98+
//! Using similar methods, you can also react to IO or Signals, or call a callback whenever the loop is idle.
9999
//!
100100
//! ## Multithreading
101101
//! The pipewire library is not really thread-safe, so pipewire objects do not implement [`Send`](`std::marker::Send`)
@@ -146,7 +146,7 @@ mod utils;
146146
pub mod prelude {
147147
pub use spa::prelude::*;
148148

149-
pub use crate::loop_::Loop;
149+
pub use crate::loop_::IsLoop;
150150
pub use crate::stream::ListenerBuilderT;
151151
}
152152

0 commit comments

Comments
 (0)