1use crate::output::{traits::Outputable, OutputInfo, OutputInfoBuilder};
2use crate::source::{traits::Sourceable, SourceInfo, SourceInfoBuilder};
3use crate::string::ObsString;
4use obs_sys::{
5 obs_module_t, obs_output_info, obs_register_output_s, obs_register_source_s, obs_source_info,
6 size_t,
7};
8use std::marker::PhantomData;
9
10pub struct LoadContext {
11 __marker: PhantomData<()>,
12 sources: Vec<*mut obs_source_info>,
13 outputs: Vec<*mut obs_output_info>,
14}
15
16impl LoadContext {
17 pub unsafe fn new() -> LoadContext {
21 LoadContext {
22 __marker: PhantomData,
23 sources: vec![],
24 outputs: vec![],
25 }
26 }
27
28 pub fn create_source_builder<D: Sourceable>(&self) -> SourceInfoBuilder<D> {
29 SourceInfoBuilder::new()
30 }
31
32 pub fn create_output_builder<D: Outputable>(&self) -> OutputInfoBuilder<D> {
33 OutputInfoBuilder::new()
34 }
35
36 pub fn register_source(&mut self, source: SourceInfo) {
37 let pointer = source.into_raw();
38 unsafe {
39 obs_register_source_s(pointer, std::mem::size_of::<obs_source_info>() as size_t);
40 };
41 self.sources.push(pointer);
42 }
43
44 pub fn register_output(&mut self, output: OutputInfo) {
45 let pointer = unsafe {
46 let pointer = output.into_raw();
47 obs_register_output_s(pointer, std::mem::size_of::<obs_output_info>() as size_t);
48 pointer
49 };
50 self.outputs.push(pointer);
51 }
52}
53
54impl Drop for LoadContext {
55 fn drop(&mut self) {
56 unsafe {
57 for pointer in self.sources.drain(..) {
58 drop(Box::from_raw(pointer))
59 }
60 for pointer in self.outputs.drain(..) {
61 drop(Box::from_raw(pointer))
62 }
63 }
64 }
65}
66
67pub trait Module {
68 fn new(ctx: ModuleContext) -> Self;
69 fn get_ctx(&self) -> &ModuleContext;
70 fn load(&mut self, _load_context: &mut LoadContext) -> bool {
71 true
72 }
73 fn unload(&mut self) {}
74 fn post_load(&mut self) {}
75 fn description() -> ObsString;
76 fn name() -> ObsString;
77 fn author() -> ObsString;
78}
79
80#[macro_export]
81macro_rules! obs_register_module {
82 ($t:ty) => {
83 static mut OBS_MODULE: Option<$t> = None;
84 static mut LOAD_CONTEXT: Option<$crate::module::LoadContext> = None;
85
86 #[allow(missing_safety_doc)]
87 #[no_mangle]
88 pub unsafe extern "C" fn obs_module_set_pointer(raw: *mut $crate::obs_sys::obs_module_t) {
89 OBS_MODULE = Some(<$t>::new(ModuleContext::new(raw)));
90 }
91
92 #[allow(missing_safety_doc)]
93 #[no_mangle]
94 pub unsafe extern "C" fn obs_current_module() -> *mut $crate::obs_sys::obs_module_t {
95 if let Some(module) = &OBS_MODULE {
96 module.get_ctx().get_raw()
97 } else {
98 panic!("Could not get current module!");
99 }
100 }
101
102 #[allow(missing_safety_doc)]
103 #[no_mangle]
104 pub unsafe extern "C" fn obs_module_ver() -> u32 {
105 $crate::obs_sys::LIBOBS_API_MAJOR_VER
106 }
107
108 #[allow(missing_safety_doc)]
109 #[no_mangle]
110 pub unsafe extern "C" fn obs_module_load() -> bool {
111 let mut module = OBS_MODULE.as_mut().expect("Could not get current module!");
112 let mut context = unsafe { $crate::module::LoadContext::new() };
113 let ret = module.load(&mut context);
114 LOAD_CONTEXT = Some(context);
115
116 ret
117 }
118
119 #[allow(missing_safety_doc)]
120 #[no_mangle]
121 pub unsafe extern "C" fn obs_module_unload() {
122 let mut module = OBS_MODULE.as_mut().expect("Could not get current module!");
123 module.unload();
124 }
125
126 #[allow(missing_safety_doc)]
127 #[no_mangle]
128 pub unsafe extern "C" fn obs_module_post_load() {
129 let mut module = OBS_MODULE.as_mut().expect("Could not get current module!");
130 module.post_load();
131 }
132
133 #[allow(missing_safety_doc)]
134 #[no_mangle]
135 pub unsafe extern "C" fn obs_module_name() -> *const std::os::raw::c_char {
136 <$t>::name().as_ptr()
137 }
138
139 #[allow(missing_safety_doc)]
140 #[no_mangle]
141 pub unsafe extern "C" fn obs_module_description() -> *const std::os::raw::c_char {
142 <$t>::description().as_ptr()
143 }
144
145 #[allow(missing_safety_doc)]
146 #[no_mangle]
147 pub unsafe extern "C" fn obs_module_author() -> *const std::os::raw::c_char {
148 <$t>::author().as_ptr()
149 }
150 };
151}
152
153pub struct ModuleContext {
154 raw: *mut obs_module_t,
155}
156
157impl ModuleContext {
158 pub unsafe fn new(raw: *mut obs_module_t) -> Self {
162 Self { raw }
163 }
164
165 pub unsafe fn get_raw(&self) -> *mut obs_module_t {
169 self.raw
170 }
171}