1use bitflags::bitflags;
5use libc::c_void;
6use std::ops::Deref;
7use std::pin::Pin;
8use std::{ffi::CStr, ptr};
9use std::{fmt, mem};
10
11use crate::{
12 proxy::{Listener, Proxy, ProxyT},
13 types::ObjectType,
14};
15use spa::spa_interface_call_method;
16
17#[derive(Debug)]
18pub struct Factory {
19 proxy: Proxy,
20}
21
22impl ProxyT for Factory {
23 fn type_() -> ObjectType {
24 ObjectType::Factory
25 }
26
27 fn upcast(self) -> Proxy {
28 self.proxy
29 }
30
31 fn upcast_ref(&self) -> &Proxy {
32 &self.proxy
33 }
34
35 unsafe fn from_proxy_unchecked(proxy: Proxy) -> Self
36 where
37 Self: Sized,
38 {
39 Self { proxy }
40 }
41}
42
43impl Factory {
44 #[must_use]
46 pub fn add_listener_local(&self) -> FactoryListenerLocalBuilder<'_> {
47 FactoryListenerLocalBuilder {
48 factory: self,
49 cbs: ListenerLocalCallbacks::default(),
50 }
51 }
52}
53
54#[derive(Default)]
55struct ListenerLocalCallbacks {
56 #[allow(clippy::type_complexity)]
57 info: Option<Box<dyn Fn(&FactoryInfoRef)>>,
58}
59
60pub struct FactoryListenerLocalBuilder<'a> {
61 factory: &'a Factory,
62 cbs: ListenerLocalCallbacks,
63}
64
65#[repr(transparent)]
66pub struct FactoryInfoRef(pw_sys::pw_factory_info);
67
68impl FactoryInfoRef {
69 pub fn as_raw(&self) -> &pw_sys::pw_factory_info {
70 &self.0
71 }
72
73 pub fn as_raw_ptr(&self) -> *mut pw_sys::pw_factory_info {
74 std::ptr::addr_of!(self.0).cast_mut()
75 }
76
77 pub fn id(&self) -> u32 {
78 self.0.id
79 }
80
81 pub fn type_(&self) -> ObjectType {
82 ObjectType::from_str(unsafe { CStr::from_ptr(self.0.type_).to_str().unwrap() })
83 }
84
85 pub fn version(&self) -> u32 {
86 self.0.version
87 }
88
89 pub fn change_mask(&self) -> FactoryChangeMask {
90 FactoryChangeMask::from_bits(self.0.change_mask).expect("invalid change_mask")
91 }
92
93 pub fn props(&self) -> Option<&spa::utils::dict::DictRef> {
94 let props_ptr: *mut spa::utils::dict::DictRef = self.0.props.cast();
95 ptr::NonNull::new(props_ptr).map(|ptr| unsafe { ptr.as_ref() })
96 }
97}
98
99impl fmt::Debug for FactoryInfoRef {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.debug_struct("FactoryInfoRef")
102 .field("id", &self.id())
103 .field("type", &self.type_())
104 .field("version", &self.version())
105 .field("change_mask", &self.change_mask())
106 .field("props", &self.props())
107 .finish()
108 }
109}
110
111pub struct FactoryInfo {
112 ptr: ptr::NonNull<pw_sys::pw_factory_info>,
113}
114
115impl FactoryInfo {
116 pub fn new(ptr: ptr::NonNull<pw_sys::pw_factory_info>) -> Self {
117 Self { ptr }
118 }
119
120 pub fn from_raw(raw: *mut pw_sys::pw_factory_info) -> Self {
121 Self {
122 ptr: ptr::NonNull::new(raw).expect("Provided pointer is null"),
123 }
124 }
125
126 pub fn into_raw(self) -> *mut pw_sys::pw_factory_info {
127 std::mem::ManuallyDrop::new(self).ptr.as_ptr()
128 }
129}
130
131impl Drop for FactoryInfo {
132 fn drop(&mut self) {
133 unsafe { pw_sys::pw_factory_info_free(self.ptr.as_ptr()) }
134 }
135}
136
137impl std::ops::Deref for FactoryInfo {
138 type Target = FactoryInfoRef;
139
140 fn deref(&self) -> &Self::Target {
141 unsafe { self.ptr.cast::<FactoryInfoRef>().as_ref() }
142 }
143}
144
145impl AsRef<FactoryInfoRef> for FactoryInfo {
146 fn as_ref(&self) -> &FactoryInfoRef {
147 self.deref()
148 }
149}
150
151bitflags! {
152 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
153 pub struct FactoryChangeMask: u64 {
154 const PROPS = pw_sys::PW_FACTORY_CHANGE_MASK_PROPS as u64;
155 }
156}
157
158impl fmt::Debug for FactoryInfo {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 f.debug_struct("FactoryInfo")
161 .field("id", &self.id())
162 .field("type", &self.type_())
163 .field("version", &self.version())
164 .field("change_mask", &self.change_mask())
165 .field("props", &self.props())
166 .finish()
167 }
168}
169
170pub struct FactoryListener {
171 #[allow(dead_code)]
173 events: Pin<Box<pw_sys::pw_factory_events>>,
174 listener: Pin<Box<spa_sys::spa_hook>>,
175 #[allow(dead_code)]
176 data: Box<ListenerLocalCallbacks>,
177}
178
179impl Listener for FactoryListener {}
180
181impl Drop for FactoryListener {
182 fn drop(&mut self) {
183 spa::utils::hook::remove(*self.listener);
184 }
185}
186
187impl<'a> FactoryListenerLocalBuilder<'a> {
188 #[must_use]
189 pub fn info<F>(mut self, info: F) -> Self
190 where
191 F: Fn(&FactoryInfoRef) + 'static,
192 {
193 self.cbs.info = Some(Box::new(info));
194 self
195 }
196
197 #[must_use]
198 pub fn register(self) -> FactoryListener {
199 unsafe extern "C" fn factory_events_info(
200 data: *mut c_void,
201 info: *const pw_sys::pw_factory_info,
202 ) {
203 let callbacks = (data as *mut ListenerLocalCallbacks).as_ref().unwrap();
204 let info =
205 ptr::NonNull::new(info as *mut pw_sys::pw_factory_info).expect("info is NULL");
206 let info = info.cast::<FactoryInfoRef>().as_ref();
207 callbacks.info.as_ref().unwrap()(info);
208 }
209
210 let e = unsafe {
211 let mut e: Pin<Box<pw_sys::pw_factory_events>> = Box::pin(mem::zeroed());
212 e.version = pw_sys::PW_VERSION_FACTORY_EVENTS;
213
214 if self.cbs.info.is_some() {
215 e.info = Some(factory_events_info);
216 }
217
218 e
219 };
220
221 let (listener, data) = unsafe {
222 let factory = &self.factory.proxy.as_ptr();
223
224 let data = Box::into_raw(Box::new(self.cbs));
225 let mut listener: Pin<Box<spa_sys::spa_hook>> = Box::pin(mem::zeroed());
226 let listener_ptr: *mut spa_sys::spa_hook = listener.as_mut().get_unchecked_mut();
227
228 spa_interface_call_method!(
229 factory,
230 pw_sys::pw_factory_methods,
231 add_listener,
232 listener_ptr.cast(),
233 e.as_ref().get_ref(),
234 data as *mut _
235 );
236
237 (listener, Box::from_raw(data))
238 };
239
240 FactoryListener {
241 events: e,
242 listener,
243 data,
244 }
245 }
246}