libpulse_binding/mainloop/standard.rs
1// Copyright 2017 Lyndon Brown
2//
3// This file is part of the PulseAudio Rust language binding.
4//
5// Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not
6// copy, modify, or distribute this file except in compliance with said license. You can find copies
7// of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at
8// <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0>
9// respectively.
10//
11// Portions of documentation are copied from the LGPL 2.1+ licensed PulseAudio C headers on a
12// fair-use basis, as discussed in the overall project readme (available in the git repository).
13
14//! Standard/minimal main loop implementation based on poll().
15//!
16//! # Overview
17//!
18//! This ‘standard’ (minimal) main loop implementation is based on the poll() system call. It
19//! supports the functions defined in the main loop abstraction
20//! ([`mainloop::api`](mod@crate::mainloop::api)) and very little else.
21//!
22//! This implementation is thread safe as long as you access the main loop object from a single
23//! thread only.
24//!
25//! # Usage
26//!
27//! A [`Mainloop`] is created using [`Mainloop::new()`]. To get access to the main loop abstraction,
28//! [`Mainloop::get_api()`] is used.
29//!
30//! Destruction of the [`Mainloop`] object is done automatically when the object falls out of scope.
31//! (Rust’s `Drop` trait has been implemented and takes care of it).
32//!
33//! # Iteration
34//!
35//! The main loop is designed around the concept of iterations. Each iteration consists of three
36//! steps that repeat during the application’s entire lifetime:
37//!
38//! * Prepare - Build a list of file descriptors that need to be monitored and calculate the next
39//! timeout.
40//! * Poll - Execute the actual poll() system call.
41//! * Dispatch - Dispatch any events that have fired.
42//!
43//! When using the main loop, the application can either execute each iteration, one at a time,
44//! using [`Mainloop::iterate()`], or let the library iterate automatically using
45//! [`Mainloop::run()`].
46//!
47//! # Threads
48//!
49//! The main loop functions are designed to be thread safe, but the objects are not. What this means
50//! is that multiple main loops can be used, but only one object per thread.
51//!
52//! # Example
53//!
54//! An example program using the standard mainloop:
55//!
56//! ```rust
57//! extern crate libpulse_binding as pulse;
58//!
59//! use std::sync::atomic;
60//! use std::rc::Rc;
61//! use std::cell::RefCell;
62//! use std::ops::Deref;
63//! use pulse::mainloop::standard::Mainloop;
64//! use pulse::context::{Context, FlagSet as ContextFlagSet};
65//! use pulse::stream::{Stream, FlagSet as StreamFlagSet};
66//! use pulse::sample::{Spec, Format};
67//! use pulse::proplist::Proplist;
68//! use pulse::mainloop::standard::IterateResult;
69//! use pulse::def::Retval;
70//!
71//! fn main() {
72//! let spec = Spec {
73//! format: Format::S16NE,
74//! channels: 2,
75//! rate: 44100,
76//! };
77//! assert!(spec.is_valid());
78//!
79//! let mut proplist = Proplist::new().unwrap();
80//! proplist.set_str(pulse::proplist::properties::APPLICATION_NAME, "FooApp")
81//! .unwrap();
82//!
83//! let mut mainloop = Rc::new(RefCell::new(Mainloop::new()
84//! .expect("Failed to create mainloop")));
85//!
86//! let mut context = Rc::new(RefCell::new(Context::new_with_proplist(
87//! mainloop.borrow().deref(),
88//! "FooAppContext",
89//! &proplist
90//! ).expect("Failed to create new context")));
91//!
92//! context.borrow_mut().connect(None, ContextFlagSet::NOFLAGS, None)
93//! .expect("Failed to connect context");
94//!
95//! // Wait for context to be ready
96//! loop {
97//! match mainloop.borrow_mut().iterate(false) {
98//! IterateResult::Quit(_) |
99//! IterateResult::Err(_) => {
100//! eprintln!("Iterate state was not success, quitting...");
101//! return;
102//! },
103//! IterateResult::Success(_) => {},
104//! }
105//! match context.borrow().get_state() {
106//! pulse::context::State::Ready => { break; },
107//! pulse::context::State::Failed |
108//! pulse::context::State::Terminated => {
109//! eprintln!("Context state failed/terminated, quitting...");
110//! return;
111//! },
112//! _ => {},
113//! }
114//! }
115//!
116//! let mut stream = Rc::new(RefCell::new(Stream::new(
117//! &mut context.borrow_mut(),
118//! "Music",
119//! &spec,
120//! None
121//! ).expect("Failed to create new stream")));
122//!
123//! stream.borrow_mut().connect_playback(None, None, StreamFlagSet::START_CORKED,
124//! None, None).expect("Failed to connect playback");
125//!
126//! // Wait for stream to be ready
127//! loop {
128//! match mainloop.borrow_mut().iterate(false) {
129//! IterateResult::Quit(_) |
130//! IterateResult::Err(_) => {
131//! eprintln!("Iterate state was not success, quitting...");
132//! return;
133//! },
134//! IterateResult::Success(_) => {},
135//! }
136//! match stream.borrow().get_state() {
137//! pulse::stream::State::Ready => { break; },
138//! pulse::stream::State::Failed |
139//! pulse::stream::State::Terminated => {
140//! eprintln!("Stream state failed/terminated, quitting...");
141//! return;
142//! },
143//! _ => {},
144//! }
145//! }
146//!
147//! // Our main logic (to output a stream of audio data)
148//! # let mut count = 0; // For automatic unit tests, we’ll spin a few times
149//! let drained = Rc::new(RefCell::new(false));
150//! loop {
151//! match mainloop.borrow_mut().iterate(false) {
152//! IterateResult::Quit(_) |
153//! IterateResult::Err(_) => {
154//! eprintln!("Iterate state was not success, quitting...");
155//! return;
156//! },
157//! IterateResult::Success(_) => {},
158//! }
159//!
160//! // Write some data with stream.write()
161//!
162//! if stream.borrow().is_corked().unwrap() {
163//! stream.borrow_mut().uncork(None);
164//! }
165//!
166//! // Wait for our data to be played
167//! let _o = {
168//! let drain_state_ref = Rc::clone(&drained);
169//! stream.borrow_mut().drain(Some(Box::new(move |_success: bool| {
170//! *drain_state_ref.borrow_mut() = true;
171//! })))
172//! };
173//! while *drained.borrow_mut() == false {
174//! match mainloop.borrow_mut().iterate(false) {
175//! IterateResult::Quit(_) |
176//! IterateResult::Err(_) => {
177//! eprintln!("Iterate state was not success, quitting...");
178//! return;
179//! },
180//! IterateResult::Success(_) => {},
181//! }
182//! }
183//! *drained.borrow_mut() = false;
184//!
185//! // Remember to break out of the loop once done writing all data (or whatever).
186//! #
187//! # // Hack: Stop test getting stuck in infinite loop!
188//! # count += 1;
189//! # if count == 3 {
190//! # break;
191//! # }
192//! }
193//!
194//! // Clean shutdown
195//! mainloop.borrow_mut().quit(Retval(0)); // uncertain whether this is necessary
196//! stream.borrow_mut().disconnect().unwrap();
197//! }
198//! ```
199
200use std::os::raw::{c_ulong, c_void};
201use std::rc::Rc;
202#[cfg(not(windows))]
203use libc::pollfd;
204#[cfg(windows)]
205use winapi::um::winsock2::WSAPOLLFD as pollfd;
206use crate::def;
207use crate::error::{Code as ErrCode, PAErr};
208use crate::mainloop::api::{MainloopInternalType, MainloopInner, MainloopInnerType, MainloopApi,
209 Mainloop as MainloopTrait};
210use crate::mainloop::signal::MainloopSignals;
211use crate::time::MicroSeconds;
212
213pub use capi::pa_mainloop as MainloopInternal;
214
215impl MainloopInternalType for MainloopInternal {}
216
217/// Generic prototype of a poll() like function.
218pub type PollFn = extern "C" fn(ufds: *mut pollfd, nfds: c_ulong, timeout: i32,
219 userdata: *mut c_void) -> i32;
220
221/// Return type for [`Mainloop::iterate()`].
222#[derive(Debug, Copy, Clone, PartialEq, Eq)]
223pub enum IterateResult {
224 /// Success, with number of sources dispatched.
225 Success(u32),
226 /// Quit was called, with quit’s retval.
227 Quit(def::Retval),
228 /// An error occurred, with error value.
229 Err(PAErr),
230}
231
232impl IterateResult {
233 /// Checks if the result is a `Success` value (returns `true` if so).
234 #[inline]
235 pub fn is_success(&self) -> bool {
236 match *self {
237 IterateResult::Success(_) => true,
238 _ => false,
239 }
240 }
241
242 /// Checks if the result is a `Quit` value (returns `true` if so).
243 #[inline]
244 pub fn is_quit(&self) -> bool {
245 match *self {
246 IterateResult::Quit(_) => true,
247 _ => false,
248 }
249 }
250
251 /// Checks` if the result is an `Error` value (returns `true` if so).
252 #[inline]
253 pub fn is_error(&self) -> bool {
254 match *self {
255 IterateResult::Err(_) => true,
256 _ => false,
257 }
258 }
259}
260
261/// This acts as a safe interface to the internal PA Mainloop.
262///
263/// The mainloop object pointers are further enclosed here in a ref counted wrapper, allowing this
264/// outer wrapper to have clean methods for creating event objects, which can cleanly pass a copy of
265/// the inner ref counted mainloop object to them. Giving this to events serves two purposes,
266/// firstly because they need the API pointer, secondly, it ensures that event objects do not
267/// outlive the mainloop object.
268pub struct Mainloop {
269 /// The ref-counted inner data.
270 pub _inner: Rc<MainloopInner<MainloopInternal>>,
271}
272
273impl MainloopTrait for Mainloop {
274 type MI = MainloopInner<MainloopInternal>;
275
276 #[inline(always)]
277 fn inner(&self) -> Rc<super::api::MainloopInner<MainloopInternal>> {
278 Rc::clone(&self._inner)
279 }
280}
281
282impl MainloopSignals for Mainloop {}
283
284impl MainloopInner<MainloopInternal> {
285 #[inline(always)]
286 fn drop_actual(&mut self) {
287 unsafe { capi::pa_mainloop_free(self.get_ptr()) };
288 }
289}
290
291impl Mainloop {
292 /// Allocates a new main loop object.
293 pub fn new() -> Option<Self> {
294 let ptr = unsafe { capi::pa_mainloop_new() };
295 if ptr.is_null() {
296 return None;
297 }
298 let api_ptr = unsafe { capi::pa_mainloop_get_api(ptr) };
299 assert!(!api_ptr.is_null());
300 let ml_inner = unsafe {
301 MainloopInner::<MainloopInternal>::new(ptr, std::mem::transmute(api_ptr),
302 MainloopInner::<MainloopInternal>::drop_actual, true)
303 };
304 Some(Self { _inner: Rc::new(ml_inner) })
305 }
306
307 /// Prepares for a single iteration of the main loop.
308 ///
309 /// Returns `Err` on error or exit request.
310 ///
311 /// `timeout` specifies a maximum timeout for the subsequent poll. `None` requests blocking
312 /// behaviour.
313 ///
314 /// Note, should the microseconds timeout value provided be too large to pass to the underlying
315 /// C API (larger than [`std::i32::MAX`]), then the [`PAErr`] form of the [`Code::TooLarge`]
316 /// error will be returned (within [`Result::Err`]).
317 ///
318 /// [`Code::TooLarge`]: crate::error::Code::TooLarge
319 pub fn prepare(&mut self, timeout: Option<MicroSeconds>) -> Result<(), PAErr> {
320 let t: i32 = match timeout {
321 // A negative value represents a request for 'blocking' behaviour in the C API
322 None => -1,
323 // This is just in case we ever changed `MicroSeconds` to hold unsigned values
324 #[allow(unused_comparisons)]
325 Some(MicroSeconds(i)) if i < 0 => unreachable!(),
326 // Check value is no larger than i32::MAX considering API takes an i32
327 Some(MicroSeconds(i)) if i <= std::i32::MAX as u64 => i as i32,
328 // If larger, we must error
329 _ => return Err((ErrCode::TooLarge).into()),
330 };
331 match unsafe { capi::pa_mainloop_prepare(self._inner.get_ptr(), t) } {
332 0 => Ok(()),
333 e => Err(PAErr(e)),
334 }
335 }
336
337 /// Executes the previously prepared poll.
338 pub fn poll(&mut self) -> Result<u32, PAErr> {
339 match unsafe { capi::pa_mainloop_poll(self._inner.get_ptr()) } {
340 e if e >= 0 => Ok(e as u32),
341 e => Err(PAErr(e)),
342 }
343 }
344
345 /// Dispatchs timeout, IO and deferred events from the previously executed poll.
346 ///
347 /// On success returns the number of source dispatched.
348 pub fn dispatch(&mut self) -> Result<u32, PAErr> {
349 match unsafe { capi::pa_mainloop_dispatch(self._inner.get_ptr()) } {
350 e if e >= 0 => Ok(e as u32),
351 e => Err(PAErr(e)),
352 }
353 }
354
355 /// Gets the return value as specified with the main loop’s [`quit()`](Self::quit) routine.
356 #[inline]
357 pub fn get_retval(&self) -> def::Retval {
358 def::Retval(unsafe { capi::pa_mainloop_get_retval(self._inner.get_ptr()) })
359 }
360
361 /// Runs a single iteration of the main loop.
362 ///
363 /// This is a convenience function for [`prepare()`], [`poll()`] and [`dispatch()`].
364 ///
365 /// If `block` is `true`, block for events if none are queued.
366 ///
367 /// Returns an [`IterateResult`] variant:
368 ///
369 /// * On success, returns `IterateResult::Success` containing the number of sources dispatched
370 /// in this iteration.
371 /// * If exit was requested, returns `IterateResult::Quit` containing quit’s retval.
372 /// * On error, returns `IterateResult::Err` containing error value.
373 ///
374 /// [`prepare()`]: Self::prepare
375 /// [`poll()`]: Self::poll
376 /// [`dispatch()`]: Self::dispatch
377 pub fn iterate(&mut self, block: bool) -> IterateResult {
378 let mut retval: i32 = 0;
379 match unsafe {
380 capi::pa_mainloop_iterate(self._inner.get_ptr(), block as i32, &mut retval)
381 } {
382 r if r >= 0 => IterateResult::Success(r as u32),
383 -2 => IterateResult::Quit(def::Retval(retval)),
384 e => IterateResult::Err(PAErr(e)),
385 }
386 }
387
388 /// Runs unlimited iterations of the main loop object until the main loop’s
389 /// [`quit()`](Self::quit) routine is called.
390 ///
391 /// On success, returns `Ok` containing quit’s return value. On error returns `Err` containing a
392 /// tuple of the error value and quit’s return value.
393 pub fn run(&mut self) -> Result<def::Retval, (PAErr, def::Retval)> {
394 let mut retval: i32 = 0;
395 match unsafe { capi::pa_mainloop_run(self._inner.get_ptr(), &mut retval) } {
396 r if r >= 0 => Ok(def::Retval(retval)),
397 r => Err((PAErr(r), def::Retval(retval))),
398 }
399 }
400
401 /// Gets the abstract main loop abstraction layer vtable for this main loop.
402 ///
403 /// No need to free the API as it is owned by the loop and is destroyed when the loop is freed.
404 ///
405 /// Talking to PA directly with C requires fetching this pointer explicitly via this function.
406 /// This is actually unnecessary through this binding. The pointer is retrieved automatically
407 /// upon Mainloop creation, stored internally, and automatically obtained from it by functions
408 /// that need it.
409 #[inline]
410 pub fn get_api<'a>(&self) -> &'a MainloopApi {
411 let ptr = self._inner.get_api_ptr();
412 assert_eq!(false, ptr.is_null());
413 unsafe { &*ptr }
414 }
415
416 /// Shuts down the main loop with the specified return value.
417 #[inline]
418 pub fn quit(&mut self, retval: def::Retval) {
419 unsafe { capi::pa_mainloop_quit(self._inner.get_ptr(), retval.0); }
420 }
421
422 /// Interrupts a running poll (for threaded systems).
423 #[inline]
424 pub fn wakeup(&mut self) {
425 unsafe { capi::pa_mainloop_wakeup(self._inner.get_ptr()); }
426 }
427
428 /// Changes the poll() implementation.
429 #[inline]
430 pub fn set_poll_func(&mut self, poll_cb: (PollFn, *mut c_void)) {
431 unsafe {
432 capi::pa_mainloop_set_poll_func(self._inner.get_ptr(), Some(poll_cb.0), poll_cb.1);
433 }
434 }
435}