libobs_wrapper\sources/
mod.rs

1mod builder;
2pub use builder::*;
3
4use libobs::{obs_scene_item, obs_scene_t, obs_source_t};
5
6use crate::{
7    data::{immutable::ImmutableObsData, ObsData},
8    impl_obs_drop, impl_signal_manager,
9    macros::impl_eq_of_ptr,
10    run_with_obs,
11    runtime::ObsRuntime,
12    unsafe_send::{Sendable, SendableComp},
13    utils::{traits::ObsUpdatable, ObsError, ObsString},
14};
15
16use std::{
17    collections::HashMap,
18    hash::Hash,
19    sync::{Arc, RwLock},
20};
21
22#[derive(Debug, Clone)]
23#[allow(dead_code)]
24pub struct ObsSourceRef {
25    /// Disconnect signals first
26    pub(crate) signal_manager: Arc<ObsSourceSignals>,
27
28    pub(crate) source: Sendable<*mut obs_source_t>,
29    pub(crate) id: ObsString,
30    pub(crate) name: ObsString,
31    pub(crate) settings: Arc<ImmutableObsData>,
32    pub(crate) hotkey_data: Arc<ImmutableObsData>,
33
34    /// This is a map to all attached scene items of this source.
35    /// If the corresponding scene gets dropped, the scene will remove itself from the map and drop the scene item as well.
36    pub(crate) scene_items:
37        Arc<RwLock<HashMap<SendableComp<*mut obs_scene_t>, Sendable<*mut obs_scene_item>>>>,
38    _guard: Arc<_ObsSourceGuard>,
39    pub(crate) runtime: ObsRuntime,
40}
41
42impl_eq_of_ptr!(ObsSourceRef, source);
43impl ObsSourceRef {
44    pub fn new<T: Into<ObsString> + Sync + Send, K: Into<ObsString> + Sync + Send>(
45        id: T,
46        name: K,
47        mut settings: Option<ObsData>,
48        mut hotkey_data: Option<ObsData>,
49        runtime: ObsRuntime,
50    ) -> Result<Self, ObsError> {
51        let id = id.into();
52        let name = name.into();
53
54        let settings = match settings.take() {
55            Some(x) => ImmutableObsData::from(x),
56            None => ImmutableObsData::new(&runtime)?,
57        };
58
59        let hotkey_data = match hotkey_data.take() {
60            Some(x) => ImmutableObsData::from(x),
61            None => ImmutableObsData::new(&runtime)?,
62        };
63
64        let hotkey_data_ptr = hotkey_data.as_ptr();
65        let settings_ptr = settings.as_ptr();
66        let id_ptr = id.as_ptr();
67        let name_ptr = name.as_ptr();
68
69        let source = run_with_obs!(
70            runtime,
71            (hotkey_data_ptr, settings_ptr, id_ptr, name_ptr),
72            move || unsafe {
73                Sendable(libobs::obs_source_create(
74                    id_ptr,
75                    name_ptr,
76                    settings_ptr,
77                    hotkey_data_ptr,
78                ))
79            }
80        )?;
81
82        if source.0.is_null() {
83            return Err(ObsError::NullPointer);
84        }
85
86        let signals = ObsSourceSignals::new(&source, runtime.clone())?;
87        Ok(Self {
88            source: source.clone(),
89            id,
90            name,
91            settings: Arc::new(settings),
92            hotkey_data: Arc::new(hotkey_data),
93            _guard: Arc::new(_ObsSourceGuard {
94                source,
95                runtime: runtime.clone(),
96            }),
97            scene_items: Arc::new(RwLock::new(HashMap::new())),
98            runtime,
99            signal_manager: Arc::new(signals),
100        })
101    }
102
103    pub fn settings(&self) -> &ImmutableObsData {
104        &self.settings
105    }
106
107    pub fn hotkey_data(&self) -> &ImmutableObsData {
108        &self.hotkey_data
109    }
110
111    pub fn name(&self) -> String {
112        self.name.to_string()
113    }
114
115    pub fn id(&self) -> String {
116        self.id.to_string()
117    }
118
119    pub fn signal_manager(&self) -> Arc<ObsSourceSignals> {
120        self.signal_manager.clone()
121    }
122
123    pub fn as_ptr(&self) -> *mut obs_source_t {
124        self.source.0
125    }
126}
127
128impl ObsUpdatable for ObsSourceRef {
129    fn update_raw(&mut self, data: ObsData) -> Result<(), ObsError> {
130        let data_ptr = data.as_ptr();
131        let source_ptr = self.source.clone();
132        log::trace!("Updating source: {:?}", self.source);
133        run_with_obs!(self.runtime, (source_ptr, data_ptr), move || unsafe {
134            libobs::obs_source_update(source_ptr, data_ptr);
135        })
136    }
137
138    fn reset_and_update_raw(&mut self, data: ObsData) -> Result<(), ObsError> {
139        let source_ptr = self.source.clone();
140        run_with_obs!(self.runtime, (source_ptr), move || unsafe {
141            libobs::obs_source_reset_settings(source_ptr, data.as_ptr().0);
142        })
143    }
144
145    fn runtime(&self) -> ObsRuntime {
146        self.runtime.clone()
147    }
148
149    fn get_settings(&self) -> Result<ImmutableObsData, ObsError> {
150        log::trace!("Getting settings for source: {:?}", self.source);
151        let source_ptr = self.source.clone();
152        let res = run_with_obs!(self.runtime, (source_ptr), move || unsafe {
153            Sendable(libobs::obs_source_get_settings(source_ptr))
154        })?;
155
156        log::trace!("Got settings: {:?}", res);
157        Ok(ImmutableObsData::from_raw(res, self.runtime.clone()))
158    }
159}
160
161impl_signal_manager!(|ptr| unsafe { libobs::obs_source_get_signal_handler(ptr) }, ObsSourceSignals for ObsSourceRef<*mut libobs::obs_source_t>, [
162    "destroy": {},
163    "remove": {},
164    "update": {},
165    "save": {},
166    "load": {},
167    "activate": {},
168    "deactivate": {},
169    "show": {},
170    "hide": {},
171    "mute": { struct MuteSignal {
172        muted: bool
173    } },
174    "push_to_mute_changed": {struct PushToMuteChangedSignal {
175        enabled: bool
176    }},
177    "push_to_mute_delay": {struct PushToMuteDelaySignal {
178        delay: i64
179    }},
180    "push_to_talk_changed": {struct PushToTalkChangedSignal {
181        enabled: bool
182    }},
183    "push_to_talk_delay": {struct PushToTalkDelaySignal {
184        delay: i64
185    }},
186    "enable": {struct EnableSignal {
187        enabled: bool
188    }},
189    "rename": {struct NewNameSignal {
190        new_name: String,
191        prev_name: String
192    }},
193    "update_properties": {},
194    "update_flags": {struct UpdateFlagsSignal {
195        flags: i64
196    }},
197    "audio_sync": {struct AudioSyncSignal {
198        offset: i64,
199    }},
200    "audio_balance": {struct AudioBalanceSignal {
201        balance: f64,
202    }},
203    "audio_mixers": {struct AudioMixersSignal {
204        mixers: i64,
205    }},
206    "audio_activate": {},
207    "audio_deactivate": {},
208    "filter_add": {struct FilterAddSignal {
209        POINTERS {
210            filter: *mut libobs::obs_source_t,
211        }
212    }},
213    "filter_remove": {struct FilterRemoveSignal {
214        POINTERS {
215            filter: *mut libobs::obs_source_t,
216        }
217    }},
218    "reorder_filters": {},
219    "transition_start": {},
220    "transition_video_stop": {},
221    "transition_stop": {},
222    "media_started": {},
223    "media_ended":{},
224    "media_pause": {},
225    "media_play": {},
226    "media_restart": {},
227    "media_stopped": {},
228    "media_next": {},
229    "media_previous": {},
230    /// This is just for sources that are of the `game-capture`, `window-capture` or `win-wasapi` type. Other sources will never emit this signal.
231    //TODO Add support for the `linux-capture` type as it does not contain the `title` field (its 'name' instead)
232    "hooked": {struct HookedSignal {
233        title: String,
234        class: String,
235        executable: String;
236        POINTERS {
237            source: *mut libobs::obs_source_t,
238        }
239    }},
240    /// This is just for sources that are of the `game-capture`, `window-capture` or `win-wasapi` type. Other sources will never emit this signal.
241    //TODO Add support for the `linux-capture` type as it does not contain the `title` field (its 'name' instead)
242    "unhooked": {struct UnhookedSignal {
243        POINTERS {
244            source: *mut libobs::obs_source_t,
245        }
246    }},
247]);
248
249#[derive(Debug)]
250struct _ObsSourceGuard {
251    source: Sendable<*mut obs_source_t>,
252    runtime: ObsRuntime,
253}
254
255impl_obs_drop!(_ObsSourceGuard, (source), move || unsafe {
256    libobs::obs_source_release(source);
257});
258
259pub type ObsFilterRef = ObsSourceRef;