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::{ffi, AudioRingBufferSpec, AudioSink};
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    let instance = &*(ptr as *mut T::Instance);
192    let imp = instance.imp();
193
194    gst::panic_to_error!(imp, false, {
195        match imp.close() {
196            Ok(()) => true,
197            Err(err) => {
198                err.log_with_imp(imp);
199                false
200            }
201        }
202    })
203    .into_glib()
204}
205
206unsafe extern "C" fn audiosink_delay<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) -> u32 {
207    let instance = &*(ptr as *mut T::Instance);
208    let imp = instance.imp();
209
210    gst::panic_to_error!(imp, 0, { imp.delay() })
211}
212
213unsafe extern "C" fn audiosink_open<T: AudioSinkImpl>(
214    ptr: *mut ffi::GstAudioSink,
215) -> glib::ffi::gboolean {
216    let instance = &*(ptr as *mut T::Instance);
217    let imp = instance.imp();
218
219    gst::panic_to_error!(imp, false, {
220        match imp.open() {
221            Ok(()) => true,
222            Err(err) => {
223                err.log_with_imp(imp);
224                false
225            }
226        }
227    })
228    .into_glib()
229}
230
231unsafe extern "C" fn audiosink_prepare<T: AudioSinkImpl>(
232    ptr: *mut ffi::GstAudioSink,
233    spec: *mut ffi::GstAudioRingBufferSpec,
234) -> glib::ffi::gboolean {
235    let instance = &*(ptr as *mut T::Instance);
236    let imp = instance.imp();
237
238    let spec = &mut *(spec as *mut AudioRingBufferSpec);
239
240    gst::panic_to_error!(imp, false, {
241        match AudioSinkImpl::prepare(imp, spec) {
242            Ok(()) => true,
243            Err(err) => {
244                err.log_with_imp(imp);
245                false
246            }
247        }
248    })
249    .into_glib()
250}
251
252unsafe extern "C" fn audiosink_unprepare<T: AudioSinkImpl>(
253    ptr: *mut ffi::GstAudioSink,
254) -> glib::ffi::gboolean {
255    let instance = &*(ptr as *mut T::Instance);
256    let imp = instance.imp();
257
258    gst::panic_to_error!(imp, false, {
259        match imp.unprepare() {
260            Ok(()) => true,
261            Err(err) => {
262                err.log_with_imp(imp);
263                false
264            }
265        }
266    })
267    .into_glib()
268}
269
270unsafe extern "C" fn audiosink_write<T: AudioSinkImpl>(
271    ptr: *mut ffi::GstAudioSink,
272    data: glib::ffi::gpointer,
273    length: u32,
274) -> i32 {
275    let instance = &*(ptr as *mut T::Instance);
276    let imp = instance.imp();
277    let data_slice = if length == 0 {
278        &[]
279    } else {
280        std::slice::from_raw_parts(data as *const u8, length as usize)
281    };
282
283    gst::panic_to_error!(imp, -1, { imp.write(data_slice).unwrap_or(-1) })
284}
285
286unsafe extern "C" fn audiosink_reset<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) {
287    let instance = &*(ptr as *mut T::Instance);
288    let imp = instance.imp();
289
290    gst::panic_to_error!(imp, (), {
291        imp.reset();
292    });
293}