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
// Copyright 2017 Lyndon Brown // // This file is part of the PulseAudio Rust language binding. // // Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not // copy, modify, or distribute this file except in compliance with said license. You can find copies // of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at // <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0> // respectively. // // Portions of documentation are copied from the LGPL 2.1+ licensed PulseAudio C headers on a // fair-use basis, as discussed in the overall project readme (available in the git repository). //! A binding for the PulseAudio ‘GLIB mainloop’ component (`libpulse-mainloop-glib` system //! library). //! //! # About //! //! This binding enables Rust projects to make use of the ‘GLIB mainloop’ component of the //! [PulseAudio] client system library. It builds upon the [separate raw FFI crate][sys] to provide //! a more “Rusty” interface. //! //! This component provides a wrapper around the GLIB main loop. Use this to embed PulseAudio into //! your GLIB/GTK+/GNOME programs. //! //! Note that you will need components of the primary [`libpulse-binding`] crate to make use of //! this. //! //! # Introduction //! //! The GLIB main loop bindings are extremely easy to use. All that is required is to create a //! Mainloop object using [`Mainloop::new()`]. When the main loop abstraction is needed, it is //! provided by [`Mainloop::get_api()`]. //! //! # Usage //! //! Start by adding a dependency on the crate, along with the main binding crate, in your program’s //! `Cargo.toml` file. Note that it is recommended that you rename the crates such that you can //! refer to them by shorter names within your code (such as `pulse` and `pulse_glib`). Such //! renaming can be done [within your `Cargo.toml` file][rename] with cargo version 1.31 or newer, //! or otherwise with `extern crate` statements. //! //! See the documentation in [`libpulse-binding`] for further information regarding actual usage of //! libpulse mainloops. //! //! [sys]: https://docs.rs/libpulse-mainloop-glib-sys //! [`libpulse-binding`]: https://docs.rs/libpulse-binding //! [PulseAudio]: https://en.wikipedia.org/wiki/PulseAudio //! [rename]: https://doc.rust-lang.org/1.31.0/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml #![doc(html_logo_url = "https://github.com/jnqnfe/pulse-binding-rust/raw/master/logo.svg", html_favicon_url = "https://github.com/jnqnfe/pulse-binding-rust/raw/master/favicon.ico")] #![warn(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] extern crate libpulse_binding as pulse; extern crate libpulse_mainloop_glib_sys as capi; use std::rc::Rc; use std::ptr::{null, null_mut}; use glib_sys::GMainContext; use glib::{MainContext, translate::ToGlibPtr}; use std::mem; use pulse::mainloop::api::{MainloopInternalType, MainloopInner, MainloopApi}; use pulse::mainloop::signal::MainloopSignals; use pulse::mainloop::api::Mainloop as MainloopTrait; /* Note, we cannot simply use the object defined in the ‘sys’ crate, since either the type or the * trait need to be defined locally in order to link them. Thus, we create the below type (an empty * one, just used as an opaque pointer), and transmute to the ‘sys’ crate one. */ /// An opaque GLIB main loop object. #[repr(C)] pub struct MainloopInternal { _private: [u8; 0] } impl MainloopInternalType for MainloopInternal {} /// This acts as a safe interface to the internal PA Mainloop. /// /// The mainloop object pointers are further enclosed here in a ref counted wrapper, allowing this /// outer wrapper to have clean methods for creating event objects, which can cleanly pass a copy of /// the inner ref counted mainloop object to them. Giving this to events serves two purposes, /// firstly because they need the API pointer, secondly, it ensures that event objects do not /// outlive the mainloop object. pub struct Mainloop { /// The ref-counted inner data. pub _inner: Rc<MainloopInner<MainloopInternal>>, } impl MainloopTrait for Mainloop { type MI = MainloopInner<MainloopInternal>; fn inner(&self) -> Rc<MainloopInner<MainloopInternal>> { Rc::clone(&self._inner) } } impl MainloopSignals for Mainloop {} /// Drop function for MainloopInner<MainloopInternal>. fn drop_actual(self_: &mut MainloopInner<MainloopInternal>) { unsafe { capi::pa_glib_mainloop_free(mem::transmute(self_.ptr)) }; self_.ptr = null_mut::<MainloopInternal>(); self_.api = null::<MainloopApi>(); } impl Mainloop { /// Creates a new GLIB main loop object for the specified GLIB main loop context. /// /// Takes an argument `context` for the [`glib::MainContext`] to use. If context is `None` the /// default context is used. /// /// This returns the object in an Rc wrapper, allowing multiple references to be held, which /// allows event objects to hold one, thus ensuring they do not outlive it. pub fn new(context: Option<&mut MainContext>) -> Option<Self> { let p_ctx = context.map_or(null_mut::<GMainContext>(), |c| c.to_glib_none().0); let ptr = unsafe { capi::pa_glib_mainloop_new(p_ctx) }; if ptr.is_null() { return None; } let api_ptr = unsafe { mem::transmute(capi::pa_glib_mainloop_get_api(ptr)) }; Some( Self { _inner: Rc::new( MainloopInner::<MainloopInternal> { ptr: unsafe { mem::transmute(ptr) }, api: api_ptr, dropfn: drop_actual, supports_rtclock: false, } ), } ) } /// Gets the abstract main loop abstraction layer vtable for this main loop. /// /// No need to free the API as it is owned by the loop and is destroyed when the loop is freed. /// /// Talking to PA directly with C requires fetching this pointer explicitly via this function. /// This is actually unnecessary through this binding. The pointer is retrieved automatically /// upon Mainloop creation, stored internally, and automatically obtained from it by functions /// that need it. pub fn get_api<'a>(&self) -> &'a MainloopApi { let ptr = (*self._inner).api; assert_eq!(false, ptr.is_null()); unsafe { &*ptr } } }