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::{ffi, AudioRingBufferSpec, AudioSrc};
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    let instance = &*(ptr as *mut T::Instance);
201    let imp = instance.imp();
202
203    gst::panic_to_error!(imp, false, {
204        match imp.close() {
205            Ok(()) => true,
206            Err(err) => {
207                err.log_with_imp(imp);
208                false
209            }
210        }
211    })
212    .into_glib()
213}
214
215unsafe extern "C" fn audiosrc_delay<T: AudioSrcImpl>(ptr: *mut ffi::GstAudioSrc) -> u32 {
216    let instance = &*(ptr as *mut T::Instance);
217    let imp = instance.imp();
218
219    gst::panic_to_error!(imp, 0, { imp.delay() })
220}
221
222unsafe extern "C" fn audiosrc_open<T: AudioSrcImpl>(
223    ptr: *mut ffi::GstAudioSrc,
224) -> glib::ffi::gboolean {
225    let instance = &*(ptr as *mut T::Instance);
226    let imp = instance.imp();
227
228    gst::panic_to_error!(imp, false, {
229        match imp.open() {
230            Ok(()) => true,
231            Err(err) => {
232                err.log_with_imp(imp);
233                false
234            }
235        }
236    })
237    .into_glib()
238}
239
240unsafe extern "C" fn audiosrc_prepare<T: AudioSrcImpl>(
241    ptr: *mut ffi::GstAudioSrc,
242    spec: *mut ffi::GstAudioRingBufferSpec,
243) -> glib::ffi::gboolean {
244    let instance = &*(ptr as *mut T::Instance);
245    let imp = instance.imp();
246
247    let spec = &mut *(spec as *mut AudioRingBufferSpec);
248
249    gst::panic_to_error!(imp, false, {
250        match AudioSrcImpl::prepare(imp, spec) {
251            Ok(()) => true,
252            Err(err) => {
253                err.log_with_imp(imp);
254                false
255            }
256        }
257    })
258    .into_glib()
259}
260
261unsafe extern "C" fn audiosrc_unprepare<T: AudioSrcImpl>(
262    ptr: *mut ffi::GstAudioSrc,
263) -> glib::ffi::gboolean {
264    let instance = &*(ptr as *mut T::Instance);
265    let imp = instance.imp();
266
267    gst::panic_to_error!(imp, false, {
268        match imp.unprepare() {
269            Ok(()) => true,
270            Err(err) => {
271                err.log_with_imp(imp);
272                false
273            }
274        }
275    })
276    .into_glib()
277}
278
279unsafe extern "C" fn audiosrc_read<T: AudioSrcImpl>(
280    ptr: *mut ffi::GstAudioSrc,
281    data: glib::ffi::gpointer,
282    length: u32,
283    timestamp: *mut gst::ffi::GstClockTime,
284) -> u32 {
285    let instance = &*(ptr as *mut T::Instance);
286    let imp = instance.imp();
287    let data_slice = if length == 0 {
288        &mut []
289    } else {
290        std::slice::from_raw_parts_mut(data as *mut u8, length as usize)
291    };
292
293    gst::panic_to_error!(imp, 0, {
294        let (res, timestamp_res) = imp.read(data_slice).unwrap_or((0, gst::ClockTime::NONE));
295        *timestamp = timestamp_res.into_glib();
296
297        res
298    })
299}
300
301unsafe extern "C" fn audiosrc_reset<T: AudioSrcImpl>(ptr: *mut ffi::GstAudioSrc) {
302    let instance = &*(ptr as *mut T::Instance);
303    let imp = instance.imp();
304
305    gst::panic_to_error!(imp, (), {
306        imp.reset();
307    });
308}