obs_wrapper/source/
ffi.rs

1use super::audio::AudioDataContext;
2use super::context::{CreatableSourceContext, GlobalContext, VideoRenderContext};
3use super::video::VideoDataContext;
4use super::{traits::*, SourceContext};
5use super::{EnumActiveContext, EnumAllContext};
6use crate::{
7    data::DataObj,
8    hotkey::{Hotkey, HotkeyCallbacks},
9    wrapper::PtrWrapper,
10};
11use paste::item;
12use std::collections::HashMap;
13use std::convert::TryFrom;
14use std::ffi::c_void;
15use std::mem::forget;
16use std::os::raw::c_char;
17
18use obs_sys::{
19    gs_effect_t, obs_audio_data, obs_data_t, obs_hotkey_id, obs_hotkey_register_source,
20    obs_hotkey_t, obs_key_event, obs_media_state, obs_mouse_event, obs_properties,
21    obs_source_audio_mix, obs_source_enum_proc_t, obs_source_frame, obs_source_t, size_t,
22};
23
24struct DataWrapper<D> {
25    data: D,
26    #[allow(clippy::type_complexity)]
27    hotkey_callbacks: HashMap<obs_hotkey_id, Box<dyn FnMut(&mut Hotkey, &mut D)>>,
28}
29
30impl<D> DataWrapper<D> {
31    pub(crate) unsafe fn register_callbacks(
32        &mut self,
33        callbacks: HotkeyCallbacks<D>,
34        source: *mut obs_source_t,
35        data: *mut c_void,
36    ) {
37        for (name, description, func) in callbacks.into_iter() {
38            let id = obs_hotkey_register_source(
39                source,
40                name.as_ptr(),
41                description.as_ptr(),
42                Some(hotkey_callback::<D>),
43                data,
44            );
45
46            self.hotkey_callbacks.insert(id, func);
47        }
48    }
49}
50
51impl<D> From<D> for DataWrapper<D> {
52    fn from(data: D) -> Self {
53        Self {
54            data,
55            hotkey_callbacks: HashMap::new(),
56        }
57    }
58}
59
60macro_rules! impl_simple_fn {
61    ($($name:ident => $trait:ident $(-> $ret:ty)?)*) => ($(
62        item! {
63            pub unsafe extern "C" fn $name<D: $trait>(
64                data: *mut std::os::raw::c_void,
65            ) $(-> $ret)? {
66                let wrapper = &mut *(data as *mut DataWrapper<D>);
67                D::$name(&mut wrapper.data)
68            }
69        }
70    )*)
71}
72
73pub unsafe extern "C" fn get_name<D: GetNameSource>(_type_data: *mut c_void) -> *const c_char {
74    D::get_name().as_ptr()
75}
76
77impl_simple_fn!(
78    get_width => GetWidthSource -> u32
79    get_height => GetHeightSource -> u32
80
81    activate => ActivateSource
82    deactivate => DeactivateSource
83);
84
85pub unsafe extern "C" fn create<D: Sourceable>(
86    settings: *mut obs_data_t,
87    source: *mut obs_source_t,
88) -> *mut c_void {
89    let mut global = GlobalContext::default();
90    let settings = DataObj::from_raw(settings);
91    let mut context = CreatableSourceContext::from_raw(settings, &mut global);
92    let source_context = SourceContext::from_raw(source);
93
94    let data = D::create(&mut context, source_context);
95
96    let wrapper = DataWrapper::from(data);
97    forget(context.settings);
98    let callbacks = context.hotkey_callbacks;
99
100    let pointer = Box::into_raw(Box::new(wrapper));
101
102    pointer
103        .as_mut()
104        .unwrap()
105        .register_callbacks(callbacks, source, pointer as *mut c_void);
106
107    pointer as *mut c_void
108}
109
110pub unsafe extern "C" fn destroy<D>(data: *mut c_void) {
111    let wrapper: Box<DataWrapper<D>> = Box::from_raw(data as *mut DataWrapper<D>);
112    drop(wrapper);
113}
114
115pub unsafe extern "C" fn update<D: UpdateSource>(data: *mut c_void, settings: *mut obs_data_t) {
116    let mut global = GlobalContext::default();
117    let data: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
118    let mut settings = DataObj::from_raw(settings);
119    D::update(&mut data.data, &mut settings, &mut global);
120    forget(settings);
121}
122
123pub unsafe extern "C" fn video_render<D: VideoRenderSource>(
124    data: *mut std::os::raw::c_void,
125    _effect: *mut gs_effect_t,
126) {
127    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
128    let mut global = GlobalContext::default();
129    let mut render = VideoRenderContext::default();
130    D::video_render(&mut wrapper.data, &mut global, &mut render);
131}
132
133pub unsafe extern "C" fn audio_render<D: AudioRenderSource>(
134    data: *mut std::os::raw::c_void,
135    _ts_out: *mut u64,
136    _audio_output: *mut obs_source_audio_mix,
137    _mixers: u32,
138    _channels: size_t,
139    _sample_rate: size_t,
140) -> bool {
141    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
142    let mut global = GlobalContext::default();
143    D::audio_render(&mut wrapper.data, &mut global);
144    // TODO: understand what this bool is
145    true
146}
147
148pub unsafe extern "C" fn get_properties<D: GetPropertiesSource>(
149    data: *mut std::os::raw::c_void,
150) -> *mut obs_properties {
151    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
152    let properties = D::get_properties(&mut wrapper.data);
153    properties.into_raw()
154}
155
156pub unsafe extern "C" fn enum_active_sources<D: EnumActiveSource>(
157    data: *mut std::os::raw::c_void,
158    _enum_callback: obs_source_enum_proc_t,
159    _param: *mut std::os::raw::c_void,
160) {
161    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
162    let context = EnumActiveContext {};
163    D::enum_active_sources(&mut wrapper.data, &context);
164}
165
166pub unsafe extern "C" fn enum_all_sources<D: EnumAllSource>(
167    data: *mut std::os::raw::c_void,
168    _enum_callback: obs_source_enum_proc_t,
169    _param: *mut std::os::raw::c_void,
170) {
171    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
172    let context = EnumAllContext {};
173    D::enum_all_sources(&mut wrapper.data, &context);
174}
175
176impl_simple_fn!(
177    transition_start => TransitionStartSource
178    transition_stop => TransitionStopSource
179);
180
181pub unsafe extern "C" fn video_tick<D: VideoTickSource>(
182    data: *mut std::os::raw::c_void,
183    seconds: f32,
184) {
185    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
186    D::video_tick(&mut wrapper.data, seconds);
187}
188
189pub unsafe extern "C" fn filter_audio<D: FilterAudioSource>(
190    data: *mut std::os::raw::c_void,
191    audio: *mut obs_audio_data,
192) -> *mut obs_audio_data {
193    let mut context = AudioDataContext::from_raw(audio);
194    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
195    D::filter_audio(&mut wrapper.data, &mut context);
196    audio
197}
198
199pub unsafe extern "C" fn filter_video<D: FilterVideoSource>(
200    data: *mut std::os::raw::c_void,
201    video: *mut obs_source_frame,
202) -> *mut obs_source_frame {
203    let mut context = VideoDataContext::from_raw(video);
204    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
205    D::filter_video(&mut wrapper.data, &mut context);
206    video
207}
208
209pub unsafe extern "C" fn media_play_pause<D: MediaPlayPauseSource>(
210    data: *mut std::os::raw::c_void,
211    pause: bool,
212) {
213    let wrapper = &mut *(data as *mut DataWrapper<D>);
214    D::play_pause(&mut wrapper.data, pause);
215}
216
217pub unsafe extern "C" fn media_get_state<D: MediaGetStateSource>(
218    data: *mut std::os::raw::c_void,
219) -> obs_media_state {
220    let wrapper = &mut *(data as *mut DataWrapper<D>);
221    D::get_state(&mut wrapper.data).to_native()
222}
223
224pub unsafe extern "C" fn media_set_time<D: MediaSetTimeSource>(
225    data: *mut std::os::raw::c_void,
226    milliseconds: i64,
227) {
228    let wrapper = &mut *(data as *mut DataWrapper<D>);
229    D::set_time(&mut wrapper.data, milliseconds);
230}
231
232macro_rules! impl_media {
233    ($($name:ident => $trait:ident $(-> $ret:ty)?)*) => ($(
234        item! {
235            pub unsafe extern "C" fn [<media_$name>]<D: $trait>(
236                data: *mut std::os::raw::c_void,
237            ) $(-> $ret)? {
238                let wrapper = &mut *(data as *mut DataWrapper<D>);
239                D::$name(&mut wrapper.data)
240            }
241        }
242    )*)
243}
244
245impl_media!(
246    stop => MediaStopSource
247    restart => MediaRestartSource
248    next => MediaNextSource
249    previous => MediaPreviousSource
250    get_duration => MediaGetDurationSource -> i64
251    get_time => MediaGetTimeSource -> i64
252);
253
254pub unsafe extern "C" fn get_defaults<D: GetDefaultsSource>(settings: *mut obs_data_t) {
255    let mut settings = DataObj::from_raw(settings);
256    D::get_defaults(&mut settings);
257    forget(settings);
258}
259
260pub unsafe extern "C" fn hotkey_callback<D>(
261    data: *mut c_void,
262    id: obs_hotkey_id,
263    hotkey: *mut obs_hotkey_t,
264    pressed: bool,
265) {
266    let wrapper: &mut DataWrapper<D> = &mut *(data as *mut DataWrapper<D>);
267
268    let data = &mut wrapper.data;
269    let hotkey_callbacks = &mut wrapper.hotkey_callbacks;
270    let mut key = Hotkey::from_raw(hotkey, pressed);
271
272    if let Some(callback) = hotkey_callbacks.get_mut(&id) {
273        callback(&mut key, data);
274    }
275}
276
277pub unsafe extern "C" fn mouse_click<D: MouseClickSource>(
278    data: *mut std::os::raw::c_void,
279    event: *const obs_mouse_event,
280    type_: i32,
281    mouse_up: bool,
282    click_count: u32,
283) {
284    let wrapper = &mut *(data as *mut DataWrapper<D>);
285    D::mouse_click(
286        &mut wrapper.data,
287        *event,
288        super::MouseButton::try_from(type_ as u32).unwrap(),
289        !mouse_up,
290        click_count as u8,
291    )
292}
293
294pub unsafe extern "C" fn mouse_move<D: MouseMoveSource>(
295    data: *mut std::os::raw::c_void,
296    event: *const obs_mouse_event,
297    mouse_leave: bool,
298) {
299    let wrapper = &mut *(data as *mut DataWrapper<D>);
300    D::mouse_move(&mut wrapper.data, *event, mouse_leave);
301}
302
303pub unsafe extern "C" fn mouse_wheel<D: MouseWheelSource>(
304    data: *mut std::os::raw::c_void,
305    event: *const obs_mouse_event,
306    xdelta: i32,
307    ydelta: i32,
308) {
309    let wrapper = &mut *(data as *mut DataWrapper<D>);
310    D::mouse_wheel(&mut wrapper.data, *event, xdelta, ydelta);
311}
312
313pub unsafe extern "C" fn key_click<D: KeyClickSource>(
314    data: *mut std::os::raw::c_void,
315    event: *const obs_key_event,
316    key_up: bool,
317) {
318    let wrapper = &mut *(data as *mut DataWrapper<D>);
319    D::key_click(&mut wrapper.data, *event, !key_up);
320}
321
322pub unsafe extern "C" fn focus<D: FocusSource>(data: *mut std::os::raw::c_void, focus: bool) {
323    let wrapper = &mut *(data as *mut DataWrapper<D>);
324    D::focus(&mut wrapper.data, focus);
325}