libobs_wrapper\encoders/
audio.rs1use libobs::{audio_output, obs_encoder};
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::{ObsEncoderTrait, _ObsEncoderDropGuard},
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 );
90
91 let settings = {
92 let settings_ptr = run_with_obs!(runtime, (encoder), move || unsafe {
93 Sendable(libobs::obs_encoder_get_settings(encoder.get_ptr()))
95 })?;
96
97 ImmutableObsData::from_raw_pointer(settings_ptr, runtime.clone())
98 };
99
100 let hotkey_data = match hotkey_data {
101 Some(h) => h,
102 None => ImmutableObsData::new(&runtime)?,
103 };
104
105 Ok(Arc::new(Self {
106 encoder,
107 id,
108 name,
109 settings: Arc::new(RwLock::new(settings)),
110 hotkey_data: Arc::new(RwLock::new(hotkey_data)),
111 runtime,
112 }))
113 }
114
115 pub unsafe fn set_audio_context(
119 &mut self,
120 handler: Sendable<*mut audio_output>,
121 ) -> Result<(), ObsError> {
122 let encoder_ptr = self.encoder.clone();
123
124 run_with_obs!(self.runtime, (handler, encoder_ptr), move || {
125 unsafe {
126 libobs::obs_encoder_set_audio(encoder_ptr.get_ptr(), handler.0)
128 }
129 })
130 }
131}
132
133impl ObsObjectTraitPrivate for ObsAudioEncoder {
134 fn __internal_replace_settings(&self, settings: ImmutableObsData) -> Result<(), ObsError> {
135 self.settings
136 .write()
137 .map_err(|_| {
138 ObsError::LockError(
139 "Failed to acquire lock for replacing settings in the audio encoder".into(),
140 )
141 })
142 .map(|mut guard| {
143 *guard = settings;
144 })
145 }
146
147 fn __internal_replace_hotkey_data(
148 &self,
149 hotkey_data: ImmutableObsData,
150 ) -> Result<(), ObsError> {
151 self.hotkey_data
152 .write()
153 .map_err(|_| {
154 ObsError::LockError(
155 "Failed to acquire lock for replacing hotkey data in the audio encoder".into(),
156 )
157 })
158 .map(|mut guard| {
159 *guard = hotkey_data;
160 })
161 }
162}
163
164impl ObsObjectTrait<*mut libobs::obs_encoder> for ObsAudioEncoder {
165 fn runtime(&self) -> &ObsRuntime {
166 &self.runtime
167 }
168
169 fn settings(&self) -> Result<ImmutableObsData, ObsError> {
170 self.settings
171 .read()
172 .map_err(|_| {
173 ObsError::LockError("Failed to acquire read lock on audio encoder settings".into())
174 })
175 .map(|s| s.clone())
176 }
177
178 fn hotkey_data(&self) -> Result<ImmutableObsData, ObsError> {
179 self.hotkey_data
180 .read()
181 .map_err(|_| {
182 ObsError::LockError(
183 "Failed to acquire read lock on audio encoder hotkey data".into(),
184 )
185 })
186 .map(|h| h.clone())
187 }
188
189 fn id(&self) -> ObsString {
190 self.id.clone()
191 }
192
193 fn name(&self) -> ObsString {
194 self.name.clone()
195 }
196
197 fn update_settings(&self, settings: crate::data::ObsData) -> Result<(), ObsError> {
198 if self.is_active()? {
199 return Err(ObsError::EncoderActive);
200 }
201
202 inner_fn_update_settings!(self, libobs::obs_encoder_update, settings)
203 }
204
205 fn as_ptr(&self) -> SmartPointerSendable<*mut obs_encoder> {
206 self.encoder.clone()
207 }
208}
209
210impl ObsEncoderTrait for ObsAudioEncoder {}