libpulse_glib_binding/
lib.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//! A binding for the PulseAudio ‘GLIB mainloop’ component (`libpulse-mainloop-glib` system
15//! library).
16//!
17//! # About
18//!
19//! This binding enables Rust projects to make use of the ‘GLIB mainloop’ component of the
20//! [PulseAudio] client system library. It builds upon the [separate raw FFI crate][sys] to provide
21//! a more “Rusty” interface.
22//!
23//! This component provides a wrapper around the GLIB main loop. Use this to embed PulseAudio into
24//! your GLIB/GTK+/GNOME programs.
25//!
26//! Note that you will need components of the primary [`libpulse-binding`] crate to make use of
27//! this.
28//!
29//! # Introduction
30//!
31//! The GLIB main loop bindings are extremely easy to use. All that is required is to create a
32//! Mainloop object using [`Mainloop::new()`]. When the main loop abstraction is needed, it is
33//! provided by [`Mainloop::get_api()`].
34//!
35//! # Usage
36//!
37//! Start by adding a dependency on the crate, along with the main binding crate, in your program’s
38//! `Cargo.toml` file. Note that it is recommended that you rename the crates such that you can
39//! refer to them by shorter names within your code (such as `pulse` and `pulse_glib`). Such
40//! renaming can be done [within your `Cargo.toml` file][rename] with cargo version 1.31 or newer,
41//! or otherwise with `extern crate` statements.
42//!
43//! See the documentation in [`libpulse-binding`] for further information regarding actual usage of
44//! libpulse mainloops.
45//!
46//! [sys]: https://docs.rs/libpulse-mainloop-glib-sys
47//! [`libpulse-binding`]: https://docs.rs/libpulse-binding
48//! [PulseAudio]: https://en.wikipedia.org/wiki/PulseAudio
49//! [rename]: https://doc.rust-lang.org/1.31.0/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml
50
51#![doc(
52    html_logo_url = "https://github.com/jnqnfe/pulse-binding-rust/raw/master/logo.svg",
53    html_favicon_url = "https://github.com/jnqnfe/pulse-binding-rust/raw/master/favicon.ico"
54)]
55
56#![warn(missing_docs)]
57
58#![cfg_attr(docsrs, feature(doc_cfg))]
59
60extern crate libpulse_binding as pulse;
61extern crate libpulse_mainloop_glib_sys as capi;
62
63use std::rc::Rc;
64use std::ptr::null_mut;
65use glib_sys::GMainContext;
66use glib::{MainContext, translate::ToGlibPtr};
67use std::mem;
68use pulse::mainloop::api::{MainloopInternalType, MainloopInner, MainloopInnerType, MainloopApi};
69use pulse::mainloop::signal::MainloopSignals;
70use pulse::mainloop::api::Mainloop as MainloopTrait;
71
72/* Note, we cannot simply use the object defined in the ‘sys’ crate, since either the type or the
73 * trait need to be defined locally in order to link them. Thus, we create the below type (an empty
74 * one, just used as an opaque pointer), and transmute to the ‘sys’ crate one.
75 */
76
77/// An opaque GLIB main loop object.
78#[repr(C)] pub struct MainloopInternal { _private: [u8; 0] }
79
80impl MainloopInternalType for MainloopInternal {}
81
82/// This acts as a safe interface to the internal PA Mainloop.
83///
84/// The mainloop object pointers are further enclosed here in a ref counted wrapper, allowing this
85/// outer wrapper to have clean methods for creating event objects, which can cleanly pass a copy of
86/// the inner ref counted mainloop object to them. Giving this to events serves two purposes,
87/// firstly because they need the API pointer, secondly, it ensures that event objects do not
88/// outlive the mainloop object.
89pub struct Mainloop {
90    /// The ref-counted inner data.
91    pub _inner: Rc<MainloopInner<MainloopInternal>>,
92}
93
94impl MainloopTrait for Mainloop {
95    type MI = MainloopInner<MainloopInternal>;
96
97    #[inline(always)]
98    fn inner(&self) -> Rc<MainloopInner<MainloopInternal>> {
99        Rc::clone(&self._inner)
100    }
101}
102
103impl MainloopSignals for Mainloop {}
104
105/// Drop function for MainloopInner<MainloopInternal>.
106#[inline(always)]
107fn drop_actual(self_: &mut MainloopInner<MainloopInternal>) {
108    unsafe { capi::pa_glib_mainloop_free(mem::transmute(self_.get_ptr())) };
109}
110
111impl Mainloop {
112    /// Creates a new GLIB main loop object for the specified GLIB main loop context.
113    ///
114    /// Takes an argument `context` for the [`glib::MainContext`] to use. If context is `None` the
115    /// default context is used.
116    ///
117    /// This returns the object in an Rc wrapper, allowing multiple references to be held, which
118    /// allows event objects to hold one, thus ensuring they do not outlive it.
119    pub fn new(context: Option<&mut MainContext>) -> Option<Self> {
120        let p_ctx = context.map_or(null_mut::<GMainContext>(), |c| c.to_glib_none().0);
121
122        let ptr = unsafe { capi::pa_glib_mainloop_new(p_ctx) };
123        if ptr.is_null() {
124            return None;
125        }
126        let api_ptr = unsafe {
127            mem::transmute(capi::pa_glib_mainloop_get_api(ptr))
128        };
129        let ml_inner = unsafe {
130            MainloopInner::<MainloopInternal>::new(mem::transmute(ptr), api_ptr, drop_actual, false)
131        };
132        Some(Self { _inner: Rc::new(ml_inner) })
133    }
134
135    /// Gets the abstract main loop abstraction layer vtable for this main loop.
136    ///
137    /// No need to free the API as it is owned by the loop and is destroyed when the loop is freed.
138    ///
139    /// Talking to PA directly with C requires fetching this pointer explicitly via this function.
140    /// This is actually unnecessary through this binding. The pointer is retrieved automatically
141    /// upon Mainloop creation, stored internally, and automatically obtained from it by functions
142    /// that need it.
143    pub fn get_api<'a>(&self) -> &'a MainloopApi {
144        let ptr = self._inner.get_api_ptr();
145        assert_eq!(false, ptr.is_null());
146        unsafe { &*ptr }
147    }
148}