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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright The pipewire-rs Contributors.
// SPDX-License-Identifier: MIT
//! # Rust bindings for pipewire
//! `pipewire` is a crate offering Rust bindings to `libpipewire`, the library for interacting
//! with the pipewire server.
//!
//! Programs that interact with pipewire usually react to events from the server by registering callbacks
//! and invoke methods on objects on the server by calling methods on local proxy objects.
//!
//! ## Getting started
//! Most programs that interact with pipewire will need the same few basic objects:
//! - A [`MainLoop`](`main_loop::MainLoop`) that drives the program, reacting to any incoming events and dispatching method calls.
//! Most of a time, the program/thread will sit idle in this loop, waiting on events to occur.
//! - A [`Context`](`context::Context`) that keeps track of any pipewire resources.
//! - A [`Core`](`core::Core`) that is a proxy for the remote pipewire instance, used to send messages to and receive events from the
//! remote server.
//! - Optionally, a [`Registry`](`registry::Registry`) that can be used to manage and track available objects on the server.
//!
//! This is how they can be created:
//! ```no_run
//! use pipewire::{main_loop::MainLoopBox, context::ContextBox};
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mainloop = MainLoopBox::new(None)?;
//! let context = ContextBox::new(&mainloop.loop_(), None)?;
//! let core = context.connect(None)?;
//! let registry = core.get_registry()?;
//!
//! Ok(())
//! }
//! ```
//!
//! ## Smart pointers to PipeWire objects
//! The example above uses [`std::boxed::Box`]-like smart pointers to create the needed objects.
//! Those boxes use lifetimes to ensure the objects dependencies (e.g. `Core` depends on `MainLoop`)
//! outlive the object itself.
//! If more flexibility is needed, [`std::rc::Rc`]-like reference-counting smart pointers also exist.
//! Those will automatically keep the objects dependencies alive until the object is destroyed.
//!
//! Both of these kinds of types will automatically dereference to non-owning references for shared
//! functionality, e.g. [`&MainLoop`](`main_loop::MainLoop`) or [`&Core`](`core::Core`).
//!
//! The same example as above, but using `Rc` types:
//! ```no_run
//! use pipewire::{main_loop::MainLoopRc, context::ContextRc};
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mainloop = MainLoopRc::new(None)?;
//! let context = ContextRc::new(&mainloop, None)?;
//! let core = context.connect_rc(None)?;
//! let registry = core.get_registry_rc()?;
//!
//! Ok(())
//! }
//! ```
//! ## Listening for events
//! Once the needed objects are created, you can start hooking up different kinds of callbacks to
//! them to react to events, and call methods to change the state of the remote.
//! ```no_run
//! use pipewire::{main_loop::MainLoopBox, context::ContextBox};
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mainloop = MainLoopBox::new(None)?;
//! let context = ContextBox::new(&mainloop.loop_(), None)?;
//! let core = context.connect(None)?;
//! let registry = core.get_registry()?;
//!
//! // Register a callback to the `global` event on the registry, which notifies of any new global objects
//! // appearing on the remote.
//! // The callback will only get called as long as we keep the returned listener alive.
//! let _listener = registry
//! .add_listener_local()
//! .global(|global| println!("New global: {:?}", global))
//! .register();
//!
//! // Calling the `destroy_global` method on the registry will destroy the object with the specified id on the remote.
//! // We don't have a specific object to destroy now, so this is commented out.
//! # // FIXME: Find a better method for this example we can actually call.
//! // registry.destroy_global(313).into_result()?;
//!
//! mainloop.run();
//!
//! Ok(())
//! }
//! ```
//! Note that registering any callback requires the closure to have the `'static` lifetime, so if you need to capture
//! any variables, use `move ||` closures, and use [`std::rc::Rc`]s to access shared variables
//! and some [`std::cell`] variant if you need to mutate them.
//!
//! Also note that we called `mainloop.run()` at the end.
//! This will enter the loop, and won't return until we call `mainloop.quit()` from some event.
//! If we didn't run the loop, events and method invocations would not be processed, so the program would terminate
//! without doing much.
//!
//! ## The main loop
//! Sometimes, other stuff needs to be done even though we are waiting inside the main loop. \
//! This can be done by adding sources to the loop.
//!
//! For example, we can call a function on an interval:
//!
//! ```no_run
//! use pipewire::main_loop::MainLoopBox;
//! use std::time::Duration;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mainloop = MainLoopBox::new(None)?;
//!
//! let timer = mainloop.loop_().add_timer(|_| println!("Hello"));
//! // Call the first time in half a second, and then in a one second interval.
//! timer.update_timer(Some(Duration::from_millis(500)), Some(Duration::from_secs(1))).into_result()?;
//!
//! mainloop.run();
//!
//! Ok(())
//! }
//! ```
//! This program will print out "Hello" every second forever.
//!
//! Using similar methods, you can also react to IO or Signals, or call a callback whenever the loop is idle.
//!
//! ## Multithreading
//! The pipewire library is not really thread-safe, so pipewire objects do not implement [`Send`](`std::marker::Send`)
//! or [`Sync`](`std::marker::Sync`).
//!
//! However, you can spawn a [`MainLoop`](`main_loop::MainLoop`) in another thread and do bidirectional communication using two channels.
//!
//! To send messages to the main thread, we can easily use a [`std::sync::mpsc`].
//! Because we are stuck in the main loop in the pipewire thread and can't just block on receiving a message,
//! we use a [`pipewire::channel`](`crate::channel`) instead.
//!
//! See the [`pipewire::channel`](`crate::channel`) module for details.
//!
//! # Useful links
//! For info on more general concepts about PipeWire as well as the C library `libpipewire`, see [PipeWire's
//! documentation](https://docs.pipewire.org/). Some notable pages are:
//! - [The PipeWire overview](https://docs.pipewire.org/page_overview.html)
//! - [A short overview of PipeWire's design](https://docs.pipewire.org/page_design.html)
//! - [A design reference on the various objects that exist in PipeWire](https://docs.pipewire.org/page_objects_design.html)
//! - [The libpipewire overview](https://docs.pipewire.org/page_library.html)
pub use *;
pub use pw_sys as sys;
pub use spa;
use ptr;
/// Initialize PipeWire
///
/// Initialize the PipeWire system and set up debugging
/// through the environment variable `PIPEWIRE_DEBUG`.
/// Deinitialize PipeWire
///
/// # Safety
/// This must only be called once during the lifetime of the process, once no PipeWire threads
/// are running anymore and all PipeWire resources are released.
pub unsafe