Skip to main content

gstreamer_audio/subclass/
audio_src.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::mem;
4
5use glib::{prelude::*, translate::*};
6use gst::LoggableError;
7use gst_base::subclass::prelude::*;
8
9use super::prelude::*;
10use crate::{AudioRingBufferSpec, AudioSrc, ffi};
11
12pub trait AudioSrcImpl: AudioBaseSrcImpl + ObjectSubclass<Type: IsA<AudioSrc>> {
13    /// close the device
14    fn close(&self) -> Result<(), LoggableError> {
15        self.parent_close()
16    }
17
18    /// the number of frames queued in the device
19    fn delay(&self) -> u32 {
20        self.parent_delay()
21    }
22
23    /// open the device with the specified caps
24    fn open(&self) -> Result<(), LoggableError> {
25        self.parent_open()
26    }
27
28    /// configure device with format
29    fn prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> {
30        AudioSrcImplExt::parent_prepare(self, spec)
31    }
32
33    /// undo the configuration
34    fn unprepare(&self) -> Result<(), LoggableError> {
35        self.parent_unprepare()
36    }
37
38    /// Read samples from the device.
39    ///
40    /// # Returns
41    ///
42    ///
43    /// ## `timestamp`
44    /// a `GstClockTime`
45    fn read(&self, audio_data: &mut [u8]) -> Result<(u32, Option<gst::ClockTime>), LoggableError> {
46        self.parent_read(audio_data)
47    }
48
49    /// unblock a read to the device and reset.
50    fn reset(&self) {
51        self.parent_reset()
52    }
53}
54
55pub trait AudioSrcImplExt: AudioSrcImpl {
56    fn parent_close(&self) -> Result<(), LoggableError> {
57        unsafe {
58            let data = Self::type_data();
59            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSrcClass;
60            let f = match (*parent_class).close {
61                None => return Ok(()),
62                Some(f) => f,
63            };
64            gst::result_from_gboolean!(
65                f(self.obj().unsafe_cast_ref::<AudioSrc>().to_glib_none().0),
66                gst::CAT_RUST,
67                "Failed to close element using the parent function"
68            )
69        }
70    }
71
72    fn parent_delay(&self) -> u32 {
73        unsafe {
74            let data = Self::type_data();
75            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSrcClass;
76            let f = match (*parent_class).delay {
77                Some(f) => f,
78                None => return 0,
79            };
80            f(self.obj().unsafe_cast_ref::<AudioSrc>().to_glib_none().0)
81        }
82    }
83
84    fn parent_open(&self) -> Result<(), LoggableError> {
85        unsafe {
86            let data = Self::type_data();
87            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSrcClass;
88            let f = match (*parent_class).open {
89                Some(f) => f,
90                None => return Ok(()),
91            };
92            gst::result_from_gboolean!(
93                f(self.obj().unsafe_cast_ref::<AudioSrc>().to_glib_none().0),
94                gst::CAT_RUST,
95                "Failed to open element using the parent function"
96            )
97        }
98    }
99
100    fn parent_prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> {
101        unsafe {
102            let data = Self::type_data();
103            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSrcClass;
104            let f = match (*parent_class).prepare {
105                Some(f) => f,
106                None => return Ok(()),
107            };
108            gst::result_from_gboolean!(
109                f(
110                    self.obj().unsafe_cast_ref::<AudioSrc>().to_glib_none().0,
111                    &mut spec.0
112                ),
113                gst::CAT_RUST,
114                "Failed to prepare element using the parent function"
115            )
116        }
117    }
118
119    fn parent_unprepare(&self) -> Result<(), LoggableError> {
120        unsafe {
121            let data = Self::type_data();
122            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSrcClass;
123            let f = match (*parent_class).unprepare {
124                Some(f) => f,
125                None => {
126                    return Err(gst::loggable_error!(
127                        gst::CAT_RUST,
128                        "Unprepare is not implemented!"
129                    ));
130                }
131            };
132            gst::result_from_gboolean!(
133                f(self.obj().unsafe_cast_ref::<AudioSrc>().to_glib_none().0),
134                gst::CAT_RUST,
135                "Failed to unprepare element using the parent function"
136            )
137        }
138    }
139
140    fn parent_read(
141        &self,
142        buffer: &mut [u8],
143    ) -> Result<(u32, Option<gst::ClockTime>), LoggableError> {
144        unsafe {
145            let data = Self::type_data();
146            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSrcClass;
147            let f = match (*parent_class).read {
148                Some(f) => f,
149                None => return Ok((0, gst::ClockTime::NONE)),
150            };
151            let buffer_ptr = buffer.as_mut_ptr() as *mut _;
152            let mut timestamp = mem::MaybeUninit::uninit();
153            let ret = f(
154                self.obj().unsafe_cast_ref::<AudioSrc>().to_glib_none().0,
155                buffer_ptr,
156                buffer.len() as u32,
157                timestamp.as_mut_ptr(),
158            );
159            if ret > 0 {
160                Ok((ret, from_glib(timestamp.assume_init())))
161            } else {
162                Err(gst::loggable_error!(
163                    gst::CAT_RUST,
164                    "Failed to read using the parent function"
165                ))
166            }
167        }
168    }
169
170    fn parent_reset(&self) {
171        unsafe {
172            let data = Self::type_data();
173            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSrcClass;
174            if let Some(f) = (*parent_class).reset {
175                f(self.obj().unsafe_cast_ref::<AudioSrc>().to_glib_none().0)
176            }
177        }
178    }
179}
180
181impl<T: AudioSrcImpl> AudioSrcImplExt for T {}
182
183unsafe impl<T: AudioSrcImpl> IsSubclassable<T> for AudioSrc {
184    fn class_init(klass: &mut glib::Class<Self>) {
185        Self::parent_class_init::<T>(klass);
186        let klass = klass.as_mut();
187        klass.close = Some(audiosrc_close::<T>);
188        klass.delay = Some(audiosrc_delay::<T>);
189        klass.open = Some(audiosrc_open::<T>);
190        klass.prepare = Some(audiosrc_prepare::<T>);
191        klass.unprepare = Some(audiosrc_unprepare::<T>);
192        klass.read = Some(audiosrc_read::<T>);
193        klass.reset = Some(audiosrc_reset::<T>);
194    }
195}
196
197unsafe extern "C" fn audiosrc_close<T: AudioSrcImpl>(
198    ptr: *mut ffi::GstAudioSrc,
199) -> glib::ffi::gboolean {
200    unsafe {
201        let instance = &*(ptr as *mut T::Instance);
202        let imp = instance.imp();
203
204        gst::panic_to_error!(imp, false, {
205            match imp.close() {
206                Ok(()) => true,
207                Err(err) => {
208                    err.log_with_imp(imp);
209                    false
210                }
211            }
212        })
213        .into_glib()
214    }
215}
216
217unsafe extern "C" fn audiosrc_delay<T: AudioSrcImpl>(ptr: *mut ffi::GstAudioSrc) -> u32 {
218    unsafe {
219        let instance = &*(ptr as *mut T::Instance);
220        let imp = instance.imp();
221
222        gst::panic_to_error!(imp, 0, { imp.delay() })
223    }
224}
225
226unsafe extern "C" fn audiosrc_open<T: AudioSrcImpl>(
227    ptr: *mut ffi::GstAudioSrc,
228) -> glib::ffi::gboolean {
229    unsafe {
230        let instance = &*(ptr as *mut T::Instance);
231        let imp = instance.imp();
232
233        gst::panic_to_error!(imp, false, {
234            match imp.open() {
235                Ok(()) => true,
236                Err(err) => {
237                    err.log_with_imp(imp);
238                    false
239                }
240            }
241        })
242        .into_glib()
243    }
244}
245
246unsafe extern "C" fn audiosrc_prepare<T: AudioSrcImpl>(
247    ptr: *mut ffi::GstAudioSrc,
248    spec: *mut ffi::GstAudioRingBufferSpec,
249) -> glib::ffi::gboolean {
250    unsafe {
251        let instance = &*(ptr as *mut T::Instance);
252        let imp = instance.imp();
253
254        let spec = &mut *(spec as *mut AudioRingBufferSpec);
255
256        gst::panic_to_error!(imp, false, {
257            match AudioSrcImpl::prepare(imp, spec) {
258                Ok(()) => true,
259                Err(err) => {
260                    err.log_with_imp(imp);
261                    false
262                }
263            }
264        })
265        .into_glib()
266    }
267}
268
269unsafe extern "C" fn audiosrc_unprepare<T: AudioSrcImpl>(
270    ptr: *mut ffi::GstAudioSrc,
271) -> glib::ffi::gboolean {
272    unsafe {
273        let instance = &*(ptr as *mut T::Instance);
274        let imp = instance.imp();
275
276        gst::panic_to_error!(imp, false, {
277            match imp.unprepare() {
278                Ok(()) => true,
279                Err(err) => {
280                    err.log_with_imp(imp);
281                    false
282                }
283            }
284        })
285        .into_glib()
286    }
287}
288
289unsafe extern "C" fn audiosrc_read<T: AudioSrcImpl>(
290    ptr: *mut ffi::GstAudioSrc,
291    data: glib::ffi::gpointer,
292    length: u32,
293    timestamp: *mut gst::ffi::GstClockTime,
294) -> u32 {
295    unsafe {
296        let instance = &*(ptr as *mut T::Instance);
297        let imp = instance.imp();
298        let data_slice = if length == 0 {
299            &mut []
300        } else {
301            std::slice::from_raw_parts_mut(data as *mut u8, length as usize)
302        };
303
304        gst::panic_to_error!(imp, 0, {
305            let (res, timestamp_res) = imp.read(data_slice).unwrap_or((0, gst::ClockTime::NONE));
306            *timestamp = timestamp_res.into_glib();
307
308            res
309        })
310    }
311}
312
313unsafe extern "C" fn audiosrc_reset<T: AudioSrcImpl>(ptr: *mut ffi::GstAudioSrc) {
314    unsafe {
315        let instance = &*(ptr as *mut T::Instance);
316        let imp = instance.imp();
317
318        gst::panic_to_error!(imp, (), {
319            imp.reset();
320        });
321    }
322}