pipewire_native_spa/interface/
plugin.rs

1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: Copyright (c) 2025 Asymptotic Inc.
3// SPDX-FileCopyrightText: Copyright (c) 2025 Arun Raghavan
4
5use std::{any::TypeId, pin::Pin, sync::Arc};
6
7use crate::dict::Dict;
8
9use super::ffi::CInterface;
10
11pub const LOG_FACTORY: &str = "support.log";
12pub const SYSTEM_FACTORY: &str = "support.system";
13pub const CPU_FACTORY: &str = "support.cpu";
14pub const LOOP_FACTORY: &str = "support.loop";
15
16pub trait Interface {
17    /// Return a C-compatible spa_interface pointer
18    ///
19    /// # Safety
20    /// The caller must manually free the returned pointer using `free_native()`.
21    unsafe fn make_native(&self) -> *mut CInterface;
22
23    /// Return a C-compatible spa_interface pointer
24    ///
25    /// # Safety
26    /// The pointer must have been allocated using `make_native()`.
27    unsafe fn free_native(cpu: *mut CInterface)
28    where
29        Self: Sized;
30
31    fn type_id(&self) -> TypeId
32    where
33        Self: 'static,
34    {
35        TypeId::of::<Self>()
36    }
37}
38
39impl std::fmt::Debug for dyn Interface {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        f.debug_struct("Interface")
42            .field("type_id", &self.type_id())
43            .finish()
44    }
45}
46
47type ArcPinBox<T> = Arc<Pin<Box<T>>>;
48
49impl dyn Interface {
50    pub fn is<T>(&self) -> bool
51    where
52        T: 'static,
53    {
54        TypeId::of::<T>() == self.type_id()
55    }
56
57    pub fn downcast_box<T>(self: Box<Self>) -> Result<Box<T>, Box<Self>>
58    where
59        T: 'static,
60    {
61        if self.is::<T>() {
62            Ok(unsafe { Box::from_raw(Box::into_raw(self) as *mut T) })
63        } else {
64            Err(self)
65        }
66    }
67
68    pub fn downcast_arc_pin_box<T>(self: ArcPinBox<Self>) -> Result<ArcPinBox<T>, ArcPinBox<Self>>
69    where
70        T: 'static,
71    {
72        if self.is::<T>() {
73            Ok(unsafe { Arc::from_raw(Arc::into_raw(self) as *mut Pin<Box<T>>) })
74        } else {
75            Err(self)
76        }
77    }
78}
79
80pub struct InterfaceInfo {
81    pub type_: String,
82}
83
84pub trait HandleFactory {
85    /* Data fields */
86    fn version(&self) -> u32;
87    fn name(&self) -> &str;
88    fn info(&self) -> Option<&Dict>;
89
90    /* Methods */
91    fn init(
92        &self,
93        info: Option<Dict>,
94        support: &super::Support,
95    ) -> std::io::Result<Box<dyn Handle + Send + Sync>>;
96    fn enum_interface_info(&self) -> Vec<InterfaceInfo>;
97}
98
99pub trait Handle {
100    /* Data fields */
101    fn version(&self) -> u32;
102
103    /* Methods */
104    /* FIXME: The interface implicitly depends on the Handle, and we likely should express that as
105     * a lifetime dependency between the Handle and the Interface. We could also return a
106     * reference, but then the caller might have to perform some shenanigans to keep both the
107     * handle and a reference to something from the handle around. */
108    fn get_interface(&self, type_: &str) -> Option<Box<dyn Interface>>;
109}