libobs_wrapper\encoders/
audio.rs1use libobs::audio_output;
2use std::{
3 ptr,
4 sync::{Arc, RwLock},
5};
6
7use crate::{
8 data::{
9 object::{inner_fn_update_settings, ObsObjectTrait, ObsObjectTraitPrivate},
10 ImmutableObsData, ObsDataPointers,
11 },
12 encoders::{_ObsEncoderDropGuard, ObsEncoderTrait},
13 run_with_obs,
14 runtime::ObsRuntime,
15 unsafe_send::{Sendable, SmartPointerSendable},
16 utils::{AudioEncoderInfo, ObsError, ObsString},
17};
18
19#[derive(Clone, Debug)]
20#[allow(dead_code)]
21pub struct ObsAudioEncoder {
25 pub(crate) id: ObsString,
26 pub(crate) name: ObsString,
27 pub(crate) settings: Arc<RwLock<ImmutableObsData>>,
28 pub(crate) hotkey_data: Arc<RwLock<ImmutableObsData>>,
29 pub(crate) runtime: ObsRuntime,
30 pub(crate) encoder: SmartPointerSendable<*mut libobs::obs_encoder_t>,
31}
32
33impl ObsAudioEncoder {
34 pub fn new_from_info(
36 info: AudioEncoderInfo,
37 mixer_idx: usize,
38 runtime: ObsRuntime,
39 ) -> Result<Arc<Self>, ObsError> {
40 let AudioEncoderInfo {
41 id,
42 name,
43 settings,
44 hotkey_data,
45 } = info;
46
47 let settings_ptr = settings.as_ref().map(|s| s.as_ptr());
48 let hotkey_data_ptr = hotkey_data.as_ref().map(|h| h.as_ptr());
49
50 let encoder = run_with_obs!(
51 runtime,
52 (id, name, settings_ptr, hotkey_data_ptr),
53 move || {
54 let settings_ptr_raw = match settings_ptr {
55 Some(s) => s.get_ptr(),
56 None => ptr::null_mut(),
57 };
58
59 let hotkey_data_ptr_raw = match hotkey_data_ptr {
60 Some(h) => h.get_ptr(),
61 None => ptr::null_mut(),
62 };
63
64 let ptr = unsafe {
65 libobs::obs_audio_encoder_create(
67 id.as_ptr().0,
68 name.as_ptr().0,
69 settings_ptr_raw,
70 mixer_idx,
71 hotkey_data_ptr_raw,
72 )
73 };
74
75 if ptr.is_null() {
76 Err(ObsError::NullPointer(None))
77 } else {
78 Ok(Sendable(ptr))
79 }
80 }
81 )??;
82
83 let encoder = SmartPointerSendable::new(
84 encoder.0,
85 Arc::new(_ObsEncoderDropGuard {
86 encoder,
87 runtime: runtime.clone(),
88 }),
89 runtime.native_registry(),
90 );
91
92 let settings = {
93 let settings_ptr = run_with_obs!(runtime, (encoder), move || unsafe {
94 Sendable(libobs::obs_encoder_get_settings(encoder.get_ptr()))
96 })?;
97
98 ImmutableObsData::from_raw_pointer(settings_ptr, runtime.clone())
99 };
100
101 let hotkey_data = match hotkey_data {
102 Some(h) => h,
103 None => ImmutableObsData::new(&runtime)?,
104 };
105
106 Ok(Arc::new(Self {
107 encoder,
108 id,
109 name,
110 settings: Arc::new(RwLock::new(settings)),
111 hotkey_data: Arc::new(RwLock::new(hotkey_data)),
112 runtime,
113 }))
114 }
115
116 pub unsafe fn set_audio_context(&self, handler: *mut audio_output) -> Result<(), ObsError> {
120 let handler = Sendable(handler);
121 let encoder_ptr = self.encoder.clone();
122
123 run_with_obs!(self.runtime, (handler, encoder_ptr), move || {
124 unsafe {
125 libobs::obs_encoder_set_audio(encoder_ptr.get_ptr(), handler.0)
127 }
128 })
129 }
130}
131
132impl ObsObjectTraitPrivate for ObsAudioEncoder {
133 fn __internal_replace_settings(&self, settings: ImmutableObsData) -> Result<(), ObsError> {
134 self.settings
135 .write()
136 .map_err(|_| {
137 ObsError::LockError(
138 "Failed to acquire lock for replacing settings in the audio encoder".into(),
139 )
140 })
141 .map(|mut guard| {
142 *guard = settings;
143 })
144 }
145
146 fn __internal_replace_hotkey_data(
147 &self,
148 hotkey_data: ImmutableObsData,
149 ) -> Result<(), ObsError> {
150 self.hotkey_data
151 .write()
152 .map_err(|_| {
153 ObsError::LockError(
154 "Failed to acquire lock for replacing hotkey data in the audio encoder".into(),
155 )
156 })
157 .map(|mut guard| {
158 *guard = hotkey_data;
159 })
160 }
161}
162
163impl ObsObjectTrait for ObsAudioEncoder {
164 type Native = *mut libobs::obs_encoder;
165
166 fn __native_handle(&self) -> SmartPointerSendable<Self::Native> {
167 self.encoder.clone()
168 }
169
170 fn runtime(&self) -> &ObsRuntime {
171 &self.runtime
172 }
173
174 fn settings(&self) -> Result<ImmutableObsData, ObsError> {
175 self.settings
176 .read()
177 .map_err(|_| {
178 ObsError::LockError("Failed to acquire read lock on audio encoder settings".into())
179 })
180 .map(|s| s.clone())
181 }
182
183 fn hotkey_data(&self) -> Result<ImmutableObsData, ObsError> {
184 self.hotkey_data
185 .read()
186 .map_err(|_| {
187 ObsError::LockError(
188 "Failed to acquire read lock on audio encoder hotkey data".into(),
189 )
190 })
191 .map(|h| h.clone())
192 }
193
194 fn id(&self) -> ObsString {
195 self.id.clone()
196 }
197
198 fn name(&self) -> ObsString {
199 self.name.clone()
200 }
201
202 fn update_settings(&self, settings: crate::data::ObsData) -> Result<(), ObsError> {
203 if self.is_active()? {
204 return Err(ObsError::EncoderActive);
205 }
206
207 inner_fn_update_settings!(self, libobs::obs_encoder_update, settings)
208 }
209}
210
211impl ObsEncoderTrait for ObsAudioEncoder {}