Skip to main content

gstreamer_audio/subclass/
audio_sink.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{prelude::*, translate::*};
4use gst::LoggableError;
5use gst_base::subclass::prelude::*;
6
7use super::prelude::*;
8use crate::{AudioRingBufferSpec, AudioSink, ffi};
9
10pub trait AudioSinkImpl: AudioBaseSinkImpl + ObjectSubclass<Type: IsA<AudioSink>> {
11    /// Close the device.
12    fn close(&self) -> Result<(), LoggableError> {
13        self.parent_close()
14    }
15
16    /// Return how many frames are still in the device. Participates in
17    ///  computing the time for audio clocks and drives the synchronisation.
18    fn delay(&self) -> u32 {
19        self.parent_delay()
20    }
21
22    /// Open the device. No configuration needs to be done at this point.
23    ///  This function is also used to check if the device is available.
24    fn open(&self) -> Result<(), LoggableError> {
25        self.parent_open()
26    }
27
28    /// Prepare the device to operate with the specified parameters.
29    fn prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> {
30        AudioSinkImplExt::parent_prepare(self, spec)
31    }
32
33    /// Undo operations done in prepare.
34    fn unprepare(&self) -> Result<(), LoggableError> {
35        self.parent_unprepare()
36    }
37
38    /// Write samples to the device.
39    fn write(&self, audio_data: &[u8]) -> Result<i32, LoggableError> {
40        self.parent_write(audio_data)
41    }
42
43    /// Returns as quickly as possible from a write and flush any pending
44    ///  samples from the device.
45    ///  This vmethod is deprecated. Please provide pause and stop instead.
46    fn reset(&self) {
47        self.parent_reset()
48    }
49}
50
51pub trait AudioSinkImplExt: AudioSinkImpl {
52    fn parent_close(&self) -> Result<(), LoggableError> {
53        unsafe {
54            let data = Self::type_data();
55            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
56            let f = match (*parent_class).close {
57                None => return Ok(()),
58                Some(f) => f,
59            };
60            gst::result_from_gboolean!(
61                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
62                gst::CAT_RUST,
63                "Failed to close element using the parent function"
64            )
65        }
66    }
67
68    fn parent_delay(&self) -> u32 {
69        unsafe {
70            let data = Self::type_data();
71            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
72            let f = match (*parent_class).delay {
73                Some(f) => f,
74                None => return 0,
75            };
76            f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0)
77        }
78    }
79
80    fn parent_open(&self) -> Result<(), LoggableError> {
81        unsafe {
82            let data = Self::type_data();
83            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
84            let f = match (*parent_class).open {
85                Some(f) => f,
86                None => return Ok(()),
87            };
88            gst::result_from_gboolean!(
89                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
90                gst::CAT_RUST,
91                "Failed to open element using the parent function"
92            )
93        }
94    }
95
96    fn parent_prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> {
97        unsafe {
98            let data = Self::type_data();
99            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
100            let f = match (*parent_class).prepare {
101                Some(f) => f,
102                None => return Ok(()),
103            };
104            gst::result_from_gboolean!(
105                f(
106                    self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0,
107                    &mut spec.0
108                ),
109                gst::CAT_RUST,
110                "Failed to prepare element using the parent function"
111            )
112        }
113    }
114
115    fn parent_unprepare(&self) -> Result<(), LoggableError> {
116        unsafe {
117            let data = Self::type_data();
118            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
119            let f = match (*parent_class).unprepare {
120                Some(f) => f,
121                None => {
122                    return Err(gst::loggable_error!(
123                        gst::CAT_RUST,
124                        "Unprepare is not implemented!"
125                    ));
126                }
127            };
128            gst::result_from_gboolean!(
129                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
130                gst::CAT_RUST,
131                "Failed to unprepare element using the parent function"
132            )
133        }
134    }
135
136    fn parent_write(&self, buffer: &[u8]) -> Result<i32, LoggableError> {
137        unsafe {
138            let data = Self::type_data();
139            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
140            let f = match (*parent_class).write {
141                Some(f) => f,
142                None => return Ok(-1),
143            };
144            let buffer_ptr = buffer.as_ptr() as glib::ffi::gpointer;
145            let ret = f(
146                self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0,
147                buffer_ptr,
148                buffer.len() as u32,
149            );
150            if ret > 0 {
151                Ok(ret)
152            } else {
153                Err(gst::loggable_error!(
154                    gst::CAT_RUST,
155                    "Failed to write using the parent function"
156                ))
157            }
158        }
159    }
160
161    fn parent_reset(&self) {
162        unsafe {
163            let data = Self::type_data();
164            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
165            if let Some(f) = (*parent_class).reset {
166                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0)
167            }
168        }
169    }
170}
171
172impl<T: AudioSinkImpl> AudioSinkImplExt for T {}
173
174unsafe impl<T: AudioSinkImpl> IsSubclassable<T> for AudioSink {
175    fn class_init(klass: &mut glib::Class<Self>) {
176        Self::parent_class_init::<T>(klass);
177        let klass = klass.as_mut();
178        klass.close = Some(audiosink_close::<T>);
179        klass.delay = Some(audiosink_delay::<T>);
180        klass.open = Some(audiosink_open::<T>);
181        klass.prepare = Some(audiosink_prepare::<T>);
182        klass.unprepare = Some(audiosink_unprepare::<T>);
183        klass.write = Some(audiosink_write::<T>);
184        klass.reset = Some(audiosink_reset::<T>);
185    }
186}
187
188unsafe extern "C" fn audiosink_close<T: AudioSinkImpl>(
189    ptr: *mut ffi::GstAudioSink,
190) -> glib::ffi::gboolean {
191    unsafe {
192        let instance = &*(ptr as *mut T::Instance);
193        let imp = instance.imp();
194
195        gst::panic_to_error!(imp, false, {
196            match imp.close() {
197                Ok(()) => true,
198                Err(err) => {
199                    err.log_with_imp(imp);
200                    false
201                }
202            }
203        })
204        .into_glib()
205    }
206}
207
208unsafe extern "C" fn audiosink_delay<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) -> u32 {
209    unsafe {
210        let instance = &*(ptr as *mut T::Instance);
211        let imp = instance.imp();
212
213        gst::panic_to_error!(imp, 0, { imp.delay() })
214    }
215}
216
217unsafe extern "C" fn audiosink_open<T: AudioSinkImpl>(
218    ptr: *mut ffi::GstAudioSink,
219) -> glib::ffi::gboolean {
220    unsafe {
221        let instance = &*(ptr as *mut T::Instance);
222        let imp = instance.imp();
223
224        gst::panic_to_error!(imp, false, {
225            match imp.open() {
226                Ok(()) => true,
227                Err(err) => {
228                    err.log_with_imp(imp);
229                    false
230                }
231            }
232        })
233        .into_glib()
234    }
235}
236
237unsafe extern "C" fn audiosink_prepare<T: AudioSinkImpl>(
238    ptr: *mut ffi::GstAudioSink,
239    spec: *mut ffi::GstAudioRingBufferSpec,
240) -> glib::ffi::gboolean {
241    unsafe {
242        let instance = &*(ptr as *mut T::Instance);
243        let imp = instance.imp();
244
245        let spec = &mut *(spec as *mut AudioRingBufferSpec);
246
247        gst::panic_to_error!(imp, false, {
248            match AudioSinkImpl::prepare(imp, spec) {
249                Ok(()) => true,
250                Err(err) => {
251                    err.log_with_imp(imp);
252                    false
253                }
254            }
255        })
256        .into_glib()
257    }
258}
259
260unsafe extern "C" fn audiosink_unprepare<T: AudioSinkImpl>(
261    ptr: *mut ffi::GstAudioSink,
262) -> glib::ffi::gboolean {
263    unsafe {
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}
279
280unsafe extern "C" fn audiosink_write<T: AudioSinkImpl>(
281    ptr: *mut ffi::GstAudioSink,
282    data: glib::ffi::gpointer,
283    length: u32,
284) -> i32 {
285    unsafe {
286        let instance = &*(ptr as *mut T::Instance);
287        let imp = instance.imp();
288        let data_slice = if length == 0 {
289            &[]
290        } else {
291            std::slice::from_raw_parts(data as *const u8, length as usize)
292        };
293
294        gst::panic_to_error!(imp, -1, { imp.write(data_slice).unwrap_or(-1) })
295    }
296}
297
298unsafe extern "C" fn audiosink_reset<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) {
299    unsafe {
300        let instance = &*(ptr as *mut T::Instance);
301        let imp = instance.imp();
302
303        gst::panic_to_error!(imp, (), {
304            imp.reset();
305        });
306    }
307}