1use bitflags::bitflags;
9use libc::c_void;
10use std::ops::Deref;
11use std::pin::Pin;
12use std::{ffi::CStr, ptr};
13use std::{fmt, mem};
14
15use crate::{
16 proxy::{Listener, Proxy, ProxyT},
17 types::ObjectType,
18};
19use spa::spa_interface_call_method;
20
21#[derive(Debug)]
23pub struct Factory {
24 proxy: Proxy,
25}
26
27impl ProxyT for Factory {
28 fn type_() -> ObjectType {
29 ObjectType::Factory
30 }
31
32 fn upcast(self) -> Proxy {
33 self.proxy
34 }
35
36 fn upcast_ref(&self) -> &Proxy {
37 &self.proxy
38 }
39
40 unsafe fn from_proxy_unchecked(proxy: Proxy) -> Self
41 where
42 Self: Sized,
43 {
44 Self { proxy }
45 }
46}
47
48impl Factory {
49 #[must_use = "Use the builder to register event callbacks"]
51 pub fn add_listener_local(&self) -> FactoryListenerLocalBuilder<'_> {
52 FactoryListenerLocalBuilder {
53 factory: self,
54 cbs: ListenerLocalCallbacks::default(),
55 }
56 }
57}
58
59#[derive(Default)]
60struct ListenerLocalCallbacks {
61 #[allow(clippy::type_complexity)]
62 info: Option<Box<dyn Fn(&FactoryInfoRef)>>,
63}
64
65pub struct FactoryListenerLocalBuilder<'a> {
80 factory: &'a Factory,
81 cbs: ListenerLocalCallbacks,
82}
83
84#[repr(transparent)]
85pub struct FactoryInfoRef(pw_sys::pw_factory_info);
86
87impl FactoryInfoRef {
88 pub fn as_raw(&self) -> &pw_sys::pw_factory_info {
89 &self.0
90 }
91
92 pub fn as_raw_ptr(&self) -> *mut pw_sys::pw_factory_info {
93 std::ptr::addr_of!(self.0).cast_mut()
94 }
95
96 pub fn id(&self) -> u32 {
97 self.0.id
98 }
99
100 pub fn type_(&self) -> ObjectType {
101 ObjectType::from_str(unsafe { CStr::from_ptr(self.0.type_).to_str().unwrap() })
102 }
103
104 pub fn version(&self) -> u32 {
105 self.0.version
106 }
107
108 pub fn change_mask(&self) -> FactoryChangeMask {
109 FactoryChangeMask::from_bits(self.0.change_mask).expect("invalid change_mask")
110 }
111
112 pub fn props(&self) -> Option<&spa::utils::dict::DictRef> {
113 let props_ptr: *mut spa::utils::dict::DictRef = self.0.props.cast();
114 ptr::NonNull::new(props_ptr).map(|ptr| unsafe { ptr.as_ref() })
115 }
116}
117
118impl fmt::Debug for FactoryInfoRef {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 f.debug_struct("FactoryInfoRef")
121 .field("id", &self.id())
122 .field("type", &self.type_())
123 .field("version", &self.version())
124 .field("change_mask", &self.change_mask())
125 .field("props", &self.props())
126 .finish()
127 }
128}
129
130pub struct FactoryInfo {
131 ptr: ptr::NonNull<pw_sys::pw_factory_info>,
132}
133
134impl FactoryInfo {
135 pub fn new(ptr: ptr::NonNull<pw_sys::pw_factory_info>) -> Self {
136 Self { ptr }
137 }
138
139 pub fn from_raw(raw: *mut pw_sys::pw_factory_info) -> Self {
140 Self {
141 ptr: ptr::NonNull::new(raw).expect("Provided pointer is null"),
142 }
143 }
144
145 pub fn into_raw(self) -> *mut pw_sys::pw_factory_info {
146 std::mem::ManuallyDrop::new(self).ptr.as_ptr()
147 }
148}
149
150impl Drop for FactoryInfo {
151 fn drop(&mut self) {
152 unsafe { pw_sys::pw_factory_info_free(self.ptr.as_ptr()) }
153 }
154}
155
156impl std::ops::Deref for FactoryInfo {
157 type Target = FactoryInfoRef;
158
159 fn deref(&self) -> &Self::Target {
160 unsafe { self.ptr.cast::<FactoryInfoRef>().as_ref() }
161 }
162}
163
164impl AsRef<FactoryInfoRef> for FactoryInfo {
165 fn as_ref(&self) -> &FactoryInfoRef {
166 self.deref()
167 }
168}
169
170bitflags! {
171 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
172 pub struct FactoryChangeMask: u64 {
173 const PROPS = pw_sys::PW_FACTORY_CHANGE_MASK_PROPS as u64;
174 }
175}
176
177impl fmt::Debug for FactoryInfo {
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 f.debug_struct("FactoryInfo")
180 .field("id", &self.id())
181 .field("type", &self.type_())
182 .field("version", &self.version())
183 .field("change_mask", &self.change_mask())
184 .field("props", &self.props())
185 .finish()
186 }
187}
188
189#[must_use = "Listeners unregister themselves when dropped. Keep the listener alive in order to receive events."]
194pub struct FactoryListener {
195 #[allow(dead_code)]
197 events: Pin<Box<pw_sys::pw_factory_events>>,
198 listener: Pin<Box<spa_sys::spa_hook>>,
199 #[allow(dead_code)]
200 data: Box<ListenerLocalCallbacks>,
201}
202
203impl Listener for FactoryListener {}
204
205impl Drop for FactoryListener {
206 fn drop(&mut self) {
207 spa::utils::hook::remove(*self.listener);
208 }
209}
210
211impl<'a> FactoryListenerLocalBuilder<'a> {
212 #[must_use = "Call `.register()` to start receiving events"]
227 pub fn info<F>(mut self, info: F) -> Self
228 where
229 F: Fn(&FactoryInfoRef) + 'static,
230 {
231 self.cbs.info = Some(Box::new(info));
232 self
233 }
234
235 pub fn register(self) -> FactoryListener {
237 unsafe extern "C" fn factory_events_info(
238 data: *mut c_void,
239 info: *const pw_sys::pw_factory_info,
240 ) {
241 let callbacks = (data as *mut ListenerLocalCallbacks).as_ref().unwrap();
242 let info =
243 ptr::NonNull::new(info as *mut pw_sys::pw_factory_info).expect("info is NULL");
244 let info = info.cast::<FactoryInfoRef>().as_ref();
245 callbacks.info.as_ref().unwrap()(info);
246 }
247
248 let e = unsafe {
249 let mut e: Pin<Box<pw_sys::pw_factory_events>> = Box::pin(mem::zeroed());
250 e.version = pw_sys::PW_VERSION_FACTORY_EVENTS;
251
252 if self.cbs.info.is_some() {
253 e.info = Some(factory_events_info);
254 }
255
256 e
257 };
258
259 let (listener, data) = unsafe {
260 let factory = &self.factory.proxy.as_ptr();
261
262 let data = Box::into_raw(Box::new(self.cbs));
263 let mut listener: Pin<Box<spa_sys::spa_hook>> = Box::pin(mem::zeroed());
264 let listener_ptr: *mut spa_sys::spa_hook = listener.as_mut().get_unchecked_mut();
265
266 spa_interface_call_method!(
267 factory,
268 pw_sys::pw_factory_methods,
269 add_listener,
270 listener_ptr.cast(),
271 e.as_ref().get_ref(),
272 data as *mut _
273 );
274
275 (listener, Box::from_raw(data))
276 };
277
278 FactoryListener {
279 events: e,
280 listener,
281 data,
282 }
283 }
284}