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: Timeout) -> i32 {
100 unsafe {
101 self.enter();
102 let res = self.iterate_unguarded(timeout);
103 self.leave();
104
105 res
106 }
107 }
108
109 pub unsafe fn iterate_unguarded(&self, timeout: Timeout) -> i32 {
114 let mut iface = self.as_raw().control.as_ref().unwrap().iface;
115
116 let timeout: c_int = c_int::from(timeout);
117
118 spa_interface_call_method!(
119 &mut iface as *mut spa_sys::spa_interface,
120 spa_sys::spa_loop_control_methods,
121 iterate,
122 timeout
123 )
124 }
125
126 #[must_use]
133 pub fn add_io<I, F>(&self, io: I, event_mask: IoFlags, callback: F) -> IoSource<'_, I>
134 where
135 I: AsRawFd,
136 F: Fn(&mut I) + 'static,
137 Self: Sized,
138 {
139 unsafe extern "C" fn call_closure<I>(data: *mut c_void, _fd: RawFd, _mask: u32)
140 where
141 I: AsRawFd,
142 {
143 let (io, callback) = (data as *mut IoSourceData<I>).as_mut().unwrap();
144 callback(io);
145 }
146
147 let fd = io.as_raw_fd();
148 let data = Box::into_raw(Box::new((io, Box::new(callback) as Box<dyn Fn(&mut I)>)));
149
150 let (source, data) = unsafe {
151 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
152
153 let source = spa_interface_call_method!(
154 &mut iface as *mut spa_sys::spa_interface,
155 spa_sys::spa_loop_utils_methods,
156 add_io,
157 fd,
158 event_mask.bits(),
159 false,
161 Some(call_closure::<I>),
162 data as *mut _
163 );
164
165 (source, Box::from_raw(data))
166 };
167
168 let ptr = ptr::NonNull::new(source).expect("source is NULL");
169
170 IoSource {
171 ptr,
172 loop_: self,
173 _data: data,
174 }
175 }
176
177 #[must_use]
182 pub fn add_idle<F>(&self, enabled: bool, callback: F) -> IdleSource<'_>
183 where
184 F: Fn() + 'static,
185 {
186 unsafe extern "C" fn call_closure<F>(data: *mut c_void)
187 where
188 F: Fn(),
189 {
190 let callback = (data as *mut F).as_ref().unwrap();
191 callback();
192 }
193
194 let data = Box::into_raw(Box::new(callback));
195
196 let (source, data) = unsafe {
197 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
198
199 let source = spa_interface_call_method!(
200 &mut iface as *mut spa_sys::spa_interface,
201 spa_sys::spa_loop_utils_methods,
202 add_idle,
203 enabled,
204 Some(call_closure::<F>),
205 data as *mut _
206 );
207
208 (source, Box::from_raw(data))
209 };
210
211 let ptr = ptr::NonNull::new(source).expect("source is NULL");
212
213 IdleSource {
214 ptr,
215 loop_: self,
216 _data: data,
217 }
218 }
219
220 #[must_use]
224 pub fn add_signal_local<F>(&self, signal: Signal, callback: F) -> SignalSource<'_>
225 where
226 F: Fn() + 'static,
227 Self: Sized,
228 {
229 assert_main_thread();
230
231 unsafe extern "C" fn call_closure<F>(data: *mut c_void, _signal: c_int)
232 where
233 F: Fn(),
234 {
235 let callback = (data as *mut F).as_ref().unwrap();
236 callback();
237 }
238
239 let data = Box::into_raw(Box::new(callback));
240
241 let (source, data) = unsafe {
242 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
243
244 let source = spa_interface_call_method!(
245 &mut iface as *mut spa_sys::spa_interface,
246 spa_sys::spa_loop_utils_methods,
247 add_signal,
248 signal as c_int,
249 Some(call_closure::<F>),
250 data as *mut _
251 );
252
253 (source, Box::from_raw(data))
254 };
255
256 let ptr = ptr::NonNull::new(source).expect("source is NULL");
257
258 SignalSource {
259 ptr,
260 loop_: self,
261 _data: data,
262 }
263 }
264
265 #[must_use]
269 pub fn add_event<F>(&self, callback: F) -> EventSource<'_>
270 where
271 F: Fn() + 'static,
272 Self: Sized,
273 {
274 unsafe extern "C" fn call_closure<F>(data: *mut c_void, _count: u64)
275 where
276 F: Fn(),
277 {
278 let callback = (data as *mut F).as_ref().unwrap();
279 callback();
280 }
281
282 let data = Box::into_raw(Box::new(callback));
283
284 let (source, data) = unsafe {
285 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
286
287 let source = spa_interface_call_method!(
288 &mut iface as *mut spa_sys::spa_interface,
289 spa_sys::spa_loop_utils_methods,
290 add_event,
291 Some(call_closure::<F>),
292 data as *mut _
293 );
294 (source, Box::from_raw(data))
295 };
296
297 let ptr = ptr::NonNull::new(source).expect("source is NULL");
298
299 EventSource {
300 ptr,
301 loop_: self,
302 _data: data,
303 }
304 }
305
306 #[must_use]
312 pub fn add_timer<F>(&self, callback: F) -> TimerSource<'_>
313 where
314 F: Fn(u64) + 'static,
315 Self: Sized,
316 {
317 unsafe extern "C" fn call_closure<F>(data: *mut c_void, expirations: u64)
318 where
319 F: Fn(u64),
320 {
321 let callback = (data as *mut F).as_ref().unwrap();
322 callback(expirations);
323 }
324
325 let data = Box::into_raw(Box::new(callback));
326
327 let (source, data) = unsafe {
328 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
329
330 let source = spa_interface_call_method!(
331 &mut iface as *mut spa_sys::spa_interface,
332 spa_sys::spa_loop_utils_methods,
333 add_timer,
334 Some(call_closure::<F>),
335 data as *mut _
336 );
337 (source, Box::from_raw(data))
338 };
339
340 let ptr = ptr::NonNull::new(source).expect("source is NULL");
341
342 TimerSource {
343 ptr,
344 loop_: self,
345 _data: data,
346 }
347 }
348
349 unsafe fn destroy_source<S>(&self, source: &S)
354 where
355 S: IsSource,
356 Self: Sized,
357 {
358 let mut iface = self.as_raw().utils.as_ref().unwrap().iface;
359
360 spa_interface_call_method!(
361 &mut iface as *mut spa_sys::spa_interface,
362 spa_sys::spa_loop_utils_methods,
363 destroy_source,
364 source.as_ptr()
365 )
366 }
367}
368
369#[derive(Debug, Clone)]
371pub enum Timeout {
372 None,
373 Infinite,
374 Finite(Duration),
375}
376
377impl From<Timeout> for c_int {
378 fn from(value: Timeout) -> Self {
382 match value {
383 Timeout::None => 0,
384 Timeout::Infinite => -1,
385 Timeout::Finite(duration) => duration
386 .as_millis()
387 .try_into()
388 .expect("Provided timeout does not fit in a c_int"),
389 }
390 }
391}
392
393pub trait IsSource {
394 fn as_ptr(&self) -> *mut spa_sys::spa_source;
396}
397
398type IoSourceData<I> = (I, Box<dyn Fn(&mut I) + 'static>);
399
400pub struct IoSource<'l, I>
404where
405 I: AsRawFd,
406{
407 ptr: ptr::NonNull<spa_sys::spa_source>,
408 loop_: &'l Loop,
409 _data: Box<IoSourceData<I>>,
411}
412
413impl<'l, I> IsSource for IoSource<'l, I>
414where
415 I: AsRawFd,
416{
417 fn as_ptr(&self) -> *mut spa_sys::spa_source {
418 self.ptr.as_ptr()
419 }
420}
421
422impl<'l, I> Drop for IoSource<'l, I>
423where
424 I: AsRawFd,
425{
426 fn drop(&mut self) {
427 unsafe { self.loop_.destroy_source(self) }
428 }
429}
430
431pub struct IdleSource<'l> {
435 ptr: ptr::NonNull<spa_sys::spa_source>,
436 loop_: &'l Loop,
437 _data: Box<dyn Fn() + 'static>,
439}
440
441impl<'l> IdleSource<'l> {
442 pub fn enable(&self, enable: bool) {
444 unsafe {
445 let mut iface = self.loop_.as_raw().utils.as_ref().unwrap().iface;
446
447 spa_interface_call_method!(
448 &mut iface as *mut spa_sys::spa_interface,
449 spa_sys::spa_loop_utils_methods,
450 enable_idle,
451 self.as_ptr(),
452 enable
453 );
454 }
455 }
456}
457
458impl<'l> IsSource for IdleSource<'l> {
459 fn as_ptr(&self) -> *mut spa_sys::spa_source {
460 self.ptr.as_ptr()
461 }
462}
463
464impl<'l> Drop for IdleSource<'l> {
465 fn drop(&mut self) {
466 unsafe { self.loop_.destroy_source(self) }
467 }
468}
469
470pub struct SignalSource<'l> {
474 ptr: ptr::NonNull<spa_sys::spa_source>,
475 loop_: &'l Loop,
476 _data: Box<dyn Fn() + 'static>,
478}
479
480impl<'l> IsSource for SignalSource<'l> {
481 fn as_ptr(&self) -> *mut spa_sys::spa_source {
482 self.ptr.as_ptr()
483 }
484}
485
486impl<'l> Drop for SignalSource<'l> {
487 fn drop(&mut self) {
488 unsafe { self.loop_.destroy_source(self) }
489 }
490}
491
492pub struct EventSource<'l> {
499 ptr: ptr::NonNull<spa_sys::spa_source>,
500 loop_: &'l Loop,
501 _data: Box<dyn Fn() + 'static>,
503}
504
505impl<'l> IsSource for EventSource<'l> {
506 fn as_ptr(&self) -> *mut spa_sys::spa_source {
507 self.ptr.as_ptr()
508 }
509}
510
511impl<'l> EventSource<'l> {
512 pub fn signal(&self) -> SpaResult {
515 let res = unsafe {
516 let mut iface = self.loop_.as_raw().utils.as_ref().unwrap().iface;
517
518 spa_interface_call_method!(
519 &mut iface as *mut spa_sys::spa_interface,
520 spa_sys::spa_loop_utils_methods,
521 signal_event,
522 self.as_ptr()
523 )
524 };
525
526 SpaResult::from_c(res)
527 }
528}
529
530impl<'l> Drop for EventSource<'l> {
531 fn drop(&mut self) {
532 unsafe { self.loop_.destroy_source(self) }
533 }
534}
535
536pub struct TimerSource<'l> {
543 ptr: ptr::NonNull<spa_sys::spa_source>,
544 loop_: &'l Loop,
545 _data: Box<dyn Fn(u64) + 'static>,
547}
548
549impl<'l> TimerSource<'l> {
550 pub fn update_timer(&self, value: Option<Duration>, interval: Option<Duration>) -> SpaResult {
561 fn duration_to_timespec(duration: Duration) -> spa_sys::timespec {
562 spa_sys::timespec {
563 tv_sec: duration.as_secs().try_into().expect("Duration too long"),
564 #[allow(clippy::unnecessary_fallible_conversions)]
568 tv_nsec: duration
569 .subsec_nanos()
570 .try_into()
571 .expect("Nanoseconds should fit into timespec"),
572 }
573 }
574
575 let value = duration_to_timespec(value.unwrap_or_default());
576 let interval = duration_to_timespec(interval.unwrap_or_default());
577
578 let res = unsafe {
579 let mut iface = self.loop_.as_raw().utils.as_ref().unwrap().iface;
580
581 spa_interface_call_method!(
582 &mut iface as *mut spa_sys::spa_interface,
583 spa_sys::spa_loop_utils_methods,
584 update_timer,
585 self.as_ptr(),
586 &value as *const _ as *mut _,
587 &interval as *const _ as *mut _,
588 false
589 )
590 };
591
592 SpaResult::from_c(res)
593 }
594}
595
596impl<'l> IsSource for TimerSource<'l> {
597 fn as_ptr(&self) -> *mut spa_sys::spa_source {
598 self.ptr.as_ptr()
599 }
600}
601
602impl<'l> Drop for TimerSource<'l> {
603 fn drop(&mut self) {
604 unsafe { self.loop_.destroy_source(self) }
605 }
606}