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