1use std::{convert::TryInto, os::unix::prelude::*, ptr, time::Duration};
5
6use libc::{c_int, c_void};
7pub use nix::sys::signal::Signal;
8use spa::{spa_interface_call_method, support::system::IoFlags, utils::result::SpaResult};
9
10use crate::utils::assert_main_thread;
11
12mod box_;
13pub use box_::*;
14mod rc;
15pub use rc::*;
16
17#[repr(transparent)]
25pub struct Loop(pw_sys::pw_loop);
26
27impl Loop {
28 pub fn as_raw(&self) -> &pw_sys::pw_loop {
29 &self.0
30 }
31
32 pub fn as_raw_ptr(&self) -> *mut pw_sys::pw_loop {
33 std::ptr::addr_of!(self.0).cast_mut()
34 }
35
36 pub fn fd(&self) -> BorrowedFd<'_> {
38 unsafe {
39 let mut iface = self.as_raw().control.as_ref().unwrap().iface;
40
41 let raw_fd = spa_interface_call_method!(
42 &mut iface as *mut spa_sys::spa_interface,
43 spa_sys::spa_loop_control_methods,
44 get_fd,
45 );
46
47 BorrowedFd::borrow_raw(raw_fd)
48 }
49 }
50
51 pub unsafe fn enter(&self) {
60 let mut iface = self.as_raw().control.as_ref().unwrap().iface;
61
62 spa_interface_call_method!(
63 &mut iface as *mut spa_sys::spa_interface,
64 spa_sys::spa_loop_control_methods,
65 enter,
66 )
67 }
68
69 pub unsafe fn leave(&self) {
77 let mut iface = self.as_raw().control.as_ref().unwrap().iface;
78
79 spa_interface_call_method!(
80 &mut iface as *mut spa_sys::spa_interface,
81 spa_sys::spa_loop_control_methods,
82 leave,
83 )
84 }
85
86 pub fn iterate(&self, timeout: std::time::Duration) -> i32 {
101 unsafe {
102 self.enter();
103 let res = self.iterate_unguarded(timeout);
104 self.leave();
105
106 res
107 }
108 }
109
110 pub unsafe fn iterate_unguarded(&self, timeout: std::time::Duration) -> i32 {
115 let mut iface = self.as_raw().control.as_ref().unwrap().iface;
116
117 let timeout: c_int = timeout
118 .as_millis()
119 .try_into()
120 .expect("Provided timeout does not fit in a c_int");
121
122 spa_interface_call_method!(
123 &mut iface as *mut spa_sys::spa_interface,
124 spa_sys::spa_loop_control_methods,
125 iterate,
126 timeout
127 )
128 }
129
130 #[must_use]
137 pub fn add_io<I, F>(&self, io: I, event_mask: IoFlags, callback: F) -> IoSource<'_, I>
138 where
139 I: AsRawFd,
140 F: Fn(&mut I) + 'static,
141 Self: Sized,
142 {
143 unsafe extern "C" fn call_closure<I>(data: *mut c_void, _fd: RawFd, _mask: u32)
144 where
145 I: AsRawFd,
146 {
147 let (io, callback) = (data as *mut IoSourceData<I>).as_mut().unwrap();
148 callback(io);
149 }
150
151 let fd = io.as_raw_fd();
152 let data = Box::into_raw(Box::new((io, Box::new(callback) as Box<dyn Fn(&mut I)>)));
153
154 let (source, data) = unsafe {
155 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
156
157 let source = spa_interface_call_method!(
158 &mut iface as *mut spa_sys::spa_interface,
159 spa_sys::spa_loop_utils_methods,
160 add_io,
161 fd,
162 event_mask.bits(),
163 false,
165 Some(call_closure::<I>),
166 data as *mut _
167 );
168
169 (source, Box::from_raw(data))
170 };
171
172 let ptr = ptr::NonNull::new(source).expect("source is NULL");
173
174 IoSource {
175 ptr,
176 loop_: self,
177 _data: data,
178 }
179 }
180
181 #[must_use]
186 pub fn add_idle<F>(&self, enabled: bool, callback: F) -> IdleSource<'_>
187 where
188 F: Fn() + 'static,
189 {
190 unsafe extern "C" fn call_closure<F>(data: *mut c_void)
191 where
192 F: Fn(),
193 {
194 let callback = (data as *mut F).as_ref().unwrap();
195 callback();
196 }
197
198 let data = Box::into_raw(Box::new(callback));
199
200 let (source, data) = unsafe {
201 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
202
203 let source = spa_interface_call_method!(
204 &mut iface as *mut spa_sys::spa_interface,
205 spa_sys::spa_loop_utils_methods,
206 add_idle,
207 enabled,
208 Some(call_closure::<F>),
209 data as *mut _
210 );
211
212 (source, Box::from_raw(data))
213 };
214
215 let ptr = ptr::NonNull::new(source).expect("source is NULL");
216
217 IdleSource {
218 ptr,
219 loop_: self,
220 _data: data,
221 }
222 }
223
224 #[must_use]
228 pub fn add_signal_local<F>(&self, signal: Signal, callback: F) -> SignalSource<'_>
229 where
230 F: Fn() + 'static,
231 Self: Sized,
232 {
233 assert_main_thread();
234
235 unsafe extern "C" fn call_closure<F>(data: *mut c_void, _signal: c_int)
236 where
237 F: Fn(),
238 {
239 let callback = (data as *mut F).as_ref().unwrap();
240 callback();
241 }
242
243 let data = Box::into_raw(Box::new(callback));
244
245 let (source, data) = unsafe {
246 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
247
248 let source = spa_interface_call_method!(
249 &mut iface as *mut spa_sys::spa_interface,
250 spa_sys::spa_loop_utils_methods,
251 add_signal,
252 signal as c_int,
253 Some(call_closure::<F>),
254 data as *mut _
255 );
256
257 (source, Box::from_raw(data))
258 };
259
260 let ptr = ptr::NonNull::new(source).expect("source is NULL");
261
262 SignalSource {
263 ptr,
264 loop_: self,
265 _data: data,
266 }
267 }
268
269 #[must_use]
273 pub fn add_event<F>(&self, callback: F) -> EventSource<'_>
274 where
275 F: Fn() + 'static,
276 Self: Sized,
277 {
278 unsafe extern "C" fn call_closure<F>(data: *mut c_void, _count: u64)
279 where
280 F: Fn(),
281 {
282 let callback = (data as *mut F).as_ref().unwrap();
283 callback();
284 }
285
286 let data = Box::into_raw(Box::new(callback));
287
288 let (source, data) = unsafe {
289 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
290
291 let source = spa_interface_call_method!(
292 &mut iface as *mut spa_sys::spa_interface,
293 spa_sys::spa_loop_utils_methods,
294 add_event,
295 Some(call_closure::<F>),
296 data as *mut _
297 );
298 (source, Box::from_raw(data))
299 };
300
301 let ptr = ptr::NonNull::new(source).expect("source is NULL");
302
303 EventSource {
304 ptr,
305 loop_: self,
306 _data: data,
307 }
308 }
309
310 #[must_use]
316 pub fn add_timer<F>(&self, callback: F) -> TimerSource<'_>
317 where
318 F: Fn(u64) + 'static,
319 Self: Sized,
320 {
321 unsafe extern "C" fn call_closure<F>(data: *mut c_void, expirations: u64)
322 where
323 F: Fn(u64),
324 {
325 let callback = (data as *mut F).as_ref().unwrap();
326 callback(expirations);
327 }
328
329 let data = Box::into_raw(Box::new(callback));
330
331 let (source, data) = unsafe {
332 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
333
334 let source = spa_interface_call_method!(
335 &mut iface as *mut spa_sys::spa_interface,
336 spa_sys::spa_loop_utils_methods,
337 add_timer,
338 Some(call_closure::<F>),
339 data as *mut _
340 );
341 (source, Box::from_raw(data))
342 };
343
344 let ptr = ptr::NonNull::new(source).expect("source is NULL");
345
346 TimerSource {
347 ptr,
348 loop_: self,
349 _data: data,
350 }
351 }
352
353 unsafe fn destroy_source<S>(&self, source: &S)
358 where
359 S: IsSource,
360 Self: Sized,
361 {
362 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
363
364 spa_interface_call_method!(
365 &mut iface as *mut spa_sys::spa_interface,
366 spa_sys::spa_loop_utils_methods,
367 destroy_source,
368 source.as_ptr()
369 )
370 }
371}
372
373pub trait IsSource {
374 fn as_ptr(&self) -> *mut spa_sys::spa_source;
376}
377
378type IoSourceData<I> = (I, Box<dyn Fn(&mut I) + 'static>);
379
380pub struct IoSource<'l, I>
384where
385 I: AsRawFd,
386{
387 ptr: ptr::NonNull<spa_sys::spa_source>,
388 loop_: &'l Loop,
389 _data: Box<IoSourceData<I>>,
391}
392
393impl<'l, I> IsSource for IoSource<'l, I>
394where
395 I: AsRawFd,
396{
397 fn as_ptr(&self) -> *mut spa_sys::spa_source {
398 self.ptr.as_ptr()
399 }
400}
401
402impl<'l, I> Drop for IoSource<'l, I>
403where
404 I: AsRawFd,
405{
406 fn drop(&mut self) {
407 unsafe { self.loop_.destroy_source(self) }
408 }
409}
410
411pub struct IdleSource<'l> {
415 ptr: ptr::NonNull<spa_sys::spa_source>,
416 loop_: &'l Loop,
417 _data: Box<dyn Fn() + 'static>,
419}
420
421impl<'l> IdleSource<'l> {
422 pub fn enable(&self, enable: bool) {
424 unsafe {
425 let mut iface = self.loop_.as_raw().utils.as_ref().unwrap().iface;
426
427 spa_interface_call_method!(
428 &mut iface as *mut spa_sys::spa_interface,
429 spa_sys::spa_loop_utils_methods,
430 enable_idle,
431 self.as_ptr(),
432 enable
433 );
434 }
435 }
436}
437
438impl<'l> IsSource for IdleSource<'l> {
439 fn as_ptr(&self) -> *mut spa_sys::spa_source {
440 self.ptr.as_ptr()
441 }
442}
443
444impl<'l> Drop for IdleSource<'l> {
445 fn drop(&mut self) {
446 unsafe { self.loop_.destroy_source(self) }
447 }
448}
449
450pub struct SignalSource<'l> {
454 ptr: ptr::NonNull<spa_sys::spa_source>,
455 loop_: &'l Loop,
456 _data: Box<dyn Fn() + 'static>,
458}
459
460impl<'l> IsSource for SignalSource<'l> {
461 fn as_ptr(&self) -> *mut spa_sys::spa_source {
462 self.ptr.as_ptr()
463 }
464}
465
466impl<'l> Drop for SignalSource<'l> {
467 fn drop(&mut self) {
468 unsafe { self.loop_.destroy_source(self) }
469 }
470}
471
472pub struct EventSource<'l> {
479 ptr: ptr::NonNull<spa_sys::spa_source>,
480 loop_: &'l Loop,
481 _data: Box<dyn Fn() + 'static>,
483}
484
485impl<'l> IsSource for EventSource<'l> {
486 fn as_ptr(&self) -> *mut spa_sys::spa_source {
487 self.ptr.as_ptr()
488 }
489}
490
491impl<'l> EventSource<'l> {
492 pub fn signal(&self) -> SpaResult {
495 let res = unsafe {
496 let mut iface = self.loop_.as_raw().utils.as_ref().unwrap().iface;
497
498 spa_interface_call_method!(
499 &mut iface as *mut spa_sys::spa_interface,
500 spa_sys::spa_loop_utils_methods,
501 signal_event,
502 self.as_ptr()
503 )
504 };
505
506 SpaResult::from_c(res)
507 }
508}
509
510impl<'l> Drop for EventSource<'l> {
511 fn drop(&mut self) {
512 unsafe { self.loop_.destroy_source(self) }
513 }
514}
515
516pub struct TimerSource<'l> {
523 ptr: ptr::NonNull<spa_sys::spa_source>,
524 loop_: &'l Loop,
525 _data: Box<dyn Fn(u64) + 'static>,
527}
528
529impl<'l> TimerSource<'l> {
530 pub fn update_timer(&self, value: Option<Duration>, interval: Option<Duration>) -> SpaResult {
541 fn duration_to_timespec(duration: Duration) -> spa_sys::timespec {
542 spa_sys::timespec {
543 tv_sec: duration.as_secs().try_into().expect("Duration too long"),
544 #[allow(clippy::unnecessary_fallible_conversions)]
548 tv_nsec: duration
549 .subsec_nanos()
550 .try_into()
551 .expect("Nanoseconds should fit into timespec"),
552 }
553 }
554
555 let value = duration_to_timespec(value.unwrap_or_default());
556 let interval = duration_to_timespec(interval.unwrap_or_default());
557
558 let res = unsafe {
559 let mut iface = self.loop_.as_raw().utils.as_ref().unwrap().iface;
560
561 spa_interface_call_method!(
562 &mut iface as *mut spa_sys::spa_interface,
563 spa_sys::spa_loop_utils_methods,
564 update_timer,
565 self.as_ptr(),
566 &value as *const _ as *mut _,
567 &interval as *const _ as *mut _,
568 false
569 )
570 };
571
572 SpaResult::from_c(res)
573 }
574}
575
576impl<'l> IsSource for TimerSource<'l> {
577 fn as_ptr(&self) -> *mut spa_sys::spa_source {
578 self.ptr.as_ptr()
579 }
580}
581
582impl<'l> Drop for TimerSource<'l> {
583 fn drop(&mut self) {
584 unsafe { self.loop_.destroy_source(self) }
585 }
586}