libpulse_binding/mainloop/events/
timer.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//! Main loop timer events.
15//!
16//! # Notes
17//!
18//! Time events may be created (or reset) with either Unix time values or real-time (monotonic)
19//! based values (though if the mainloop does not support monotonic time value, they may be silently
20//! converted to unix time).
21//!
22//! Note that time events created with one form of time value can be freely restarted with the other
23//! form of time value.
24
25use std::os::raw::c_void;
26use std::rc::Rc;
27use libc::timeval;
28use crate::mainloop::api::{MainloopApi, MainloopInnerType};
29use crate::time::{UnixTs, MonotonicTs, Timeval, MicroSeconds};
30use crate::callbacks::MultiUseCallback;
31
32pub use capi::pa_time_event as TimeEventInternal;
33
34/// A timer event source
35pub struct TimeEvent<T>
36    where T: MainloopInnerType
37{
38    /// Internal object pointer
39    ptr: *mut TimeEventInternal,
40    /// Source mainloop.
41    owner: Rc<T>,
42    /// Saved callback closure, for later destruction.
43    _saved_cb: EventCb,
44}
45
46/// A reference to a timer event source, provided to the callback, allowing modification within the
47/// callback itself.
48pub struct TimeEventRef<T: 'static>
49    where T: MainloopInnerType
50{
51    /// Internal object pointer
52    ptr: *mut TimeEventInternal,
53    /// Source mainloop
54    owner: Rc<T>,
55}
56
57pub(crate) type EventCb = MultiUseCallback<dyn FnMut(*mut TimeEventInternal),
58    extern "C" fn(a: *const MainloopApi, e: *mut TimeEventInternal, tv: *const timeval,
59    userdata: *mut c_void)>;
60
61impl<T> TimeEvent<T>
62    where T: MainloopInnerType
63{
64    #[inline]
65    pub(crate) fn from_raw(ptr: *mut TimeEventInternal, mainloop_inner: Rc<T>, callback: EventCb)
66        -> Self
67    {
68        assert_eq!(false, ptr.is_null());
69        Self { ptr: ptr, owner: mainloop_inner, _saved_cb: callback }
70    }
71
72    /// Restarts this timer event source (whether still running or already expired) with a new Unix
73    /// time.
74    #[inline]
75    pub fn restart(&mut self, t: &UnixTs) {
76        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
77        fn_ptr(self.ptr, &(t.0).0);
78    }
79
80    /// Restarts this timer event source (whether still running or already expired) with a new
81    /// monotonic time.
82    pub fn restart_rt(&mut self, t: MonotonicTs) {
83        assert_ne!(t.0, MicroSeconds::INVALID);
84        let mut tv = Timeval::new_zero();
85        tv.set_rt(t.0, (*self.owner).supports_rtclock());
86
87        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
88        fn_ptr(self.ptr, &tv.0);
89    }
90}
91
92impl<T> TimeEventRef<T>
93    where T: MainloopInnerType
94{
95    pub(crate) fn from_raw(ptr: *mut TimeEventInternal, mainloop_inner: Rc<T>) -> Self {
96        assert_eq!(false, ptr.is_null());
97        Self { ptr: ptr, owner: mainloop_inner }
98    }
99
100    /// Restarts this timer event source (whether still running or already expired) with a new Unix
101    /// time.
102    #[inline]
103    pub fn restart(&mut self, t: &UnixTs) {
104        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
105        fn_ptr(self.ptr, &(t.0).0);
106    }
107
108    /// Restarts this timer event source (whether still running or already expired) with a new
109    /// monotonic time.
110    pub fn restart_rt(&mut self, t: MonotonicTs) {
111        assert_ne!(t.0, MicroSeconds::INVALID);
112        let mut tv = Timeval::new_zero();
113        tv.set_rt(t.0, (*self.owner).supports_rtclock());
114
115        let fn_ptr = (*self.owner).get_api().time_restart.unwrap();
116        fn_ptr(self.ptr, &tv.0);
117    }
118}
119
120impl<T> Drop for TimeEvent<T>
121    where T: MainloopInnerType
122{
123    fn drop(&mut self) {
124        let fn_ptr = (*self.owner).get_api().time_free.unwrap();
125        fn_ptr(self.ptr);
126    }
127}
128
129/// Proxy for the event callback.
130///
131/// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
132/// must be accomplished separately to avoid a memory leak.
133pub(crate)
134extern "C"
135fn event_cb_proxy(_: *const MainloopApi, e: *mut TimeEventInternal, _: *const timeval,
136    userdata: *mut c_void)
137{
138    let _ = std::panic::catch_unwind(|| {
139        let callback = EventCb::get_callback(userdata);
140        (callback)(e);
141    });
142}