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}