pipewire_native/proxy/
module.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::sync::{Arc, Mutex, RwLock};
6
7use bitflags::bitflags;
8use pipewire_native_spa as spa;
9
10use crate::{
11    core::Core,
12    new_refcounted,
13    properties::Properties,
14    proxy::{HasProxy, Proxy},
15    refcounted, types, HookId, Id,
16};
17
18refcounted! {
19    /// Proxy that represents a module that is loaded on the server.
20    pub struct Module {
21        proxy: RwLock<Option<Proxy<Module>>>,
22        hooks: Arc<Mutex<spa::hook::HookList<ModuleEvents>>>,
23    }
24}
25
26bitflags! {
27    /// A bit mask of changes signalled in the [ModuleEvents::info] event.
28    #[repr(C)]
29    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
30    pub struct ModuleChangeMask : u32 {
31        /// Module properties changed.
32        const PROPS = (1 << 0);
33    }
34}
35
36/// Module information that is provided in a [ModuleEvents::info] event.
37pub struct ModuleInfo<'a> {
38    /// The ID of the module.
39    pub id: Id,
40    /// The name of the module
41    pub name: &'a str,
42    /// The file name the module was loaded from.
43    pub file_name: &'a str,
44    /// Arguments the module was loaded with.
45    pub args: Option<&'a str>,
46    /// What changed since the last call.
47    pub mask: ModuleChangeMask,
48    /// The module's properties.
49    pub props: &'a Properties,
50}
51
52/// Module events that can be subscribed to.
53#[allow(clippy::type_complexity)]
54#[derive(Default)]
55pub struct ModuleEvents {
56    /// Module information became available, or changed.
57    pub info: Option<Box<dyn FnMut(&ModuleInfo<'_>) + Send>>,
58}
59
60impl HasProxy for Module {
61    fn type_(&self) -> types::ObjectType {
62        types::interface::MODULE
63    }
64
65    fn version(&self) -> u32 {
66        3
67    }
68
69    fn proxy(&self) -> Proxy<Self> {
70        self.inner
71            .proxy
72            .read()
73            .unwrap()
74            .as_ref()
75            .expect("Module proxy should be initialised on creation")
76            .clone()
77    }
78}
79
80impl Module {
81    pub(crate) fn new(core: &Core) -> Self {
82        let this = Self {
83            inner: new_refcounted(InnerModule::new()),
84        };
85
86        let id = core.next_proxy_id();
87        this.inner
88            .proxy
89            .write()
90            .unwrap()
91            .replace(Proxy::new(id, &this));
92        core.add_proxy(&this, id);
93
94        this
95    }
96
97    /// Register for notifications of module events.
98    pub fn add_listener(&self, events: ModuleEvents) -> HookId {
99        self.inner.hooks.lock().unwrap().append(events)
100    }
101
102    /// Remove a set of event listeners.
103    pub fn remove_listener(&self, hook_id: HookId) {
104        self.inner.hooks.lock().unwrap().remove(hook_id);
105    }
106
107    pub(crate) fn events(&self) -> Arc<Mutex<spa::hook::HookList<ModuleEvents>>> {
108        self.inner.hooks.clone()
109    }
110}
111
112impl InnerModule {
113    fn new() -> Self {
114        Self {
115            proxy: RwLock::new(None),
116            hooks: spa::hook::HookList::new(),
117        }
118    }
119}