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    fn close(&self) -> Result<(), LoggableError> {
12        self.parent_close()
13    }
14
15    fn delay(&self) -> u32 {
16        self.parent_delay()
17    }
18
19    fn open(&self) -> Result<(), LoggableError> {
20        self.parent_open()
21    }
22
23    fn prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> {
24        AudioSinkImplExt::parent_prepare(self, spec)
25    }
26
27    fn unprepare(&self) -> Result<(), LoggableError> {
28        self.parent_unprepare()
29    }
30
31    fn write(&self, audio_data: &[u8]) -> Result<i32, LoggableError> {
32        self.parent_write(audio_data)
33    }
34
35    fn reset(&self) {
36        self.parent_reset()
37    }
38}
39
40pub trait AudioSinkImplExt: AudioSinkImpl {
41    fn parent_close(&self) -> Result<(), LoggableError> {
42        unsafe {
43            let data = Self::type_data();
44            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
45            let f = match (*parent_class).close {
46                None => return Ok(()),
47                Some(f) => f,
48            };
49            gst::result_from_gboolean!(
50                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
51                gst::CAT_RUST,
52                "Failed to close element using the parent function"
53            )
54        }
55    }
56
57    fn parent_delay(&self) -> u32 {
58        unsafe {
59            let data = Self::type_data();
60            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
61            let f = match (*parent_class).delay {
62                Some(f) => f,
63                None => return 0,
64            };
65            f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0)
66        }
67    }
68
69    fn parent_open(&self) -> Result<(), LoggableError> {
70        unsafe {
71            let data = Self::type_data();
72            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
73            let f = match (*parent_class).open {
74                Some(f) => f,
75                None => return Ok(()),
76            };
77            gst::result_from_gboolean!(
78                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
79                gst::CAT_RUST,
80                "Failed to open element using the parent function"
81            )
82        }
83    }
84
85    fn parent_prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> {
86        unsafe {
87            let data = Self::type_data();
88            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
89            let f = match (*parent_class).prepare {
90                Some(f) => f,
91                None => return Ok(()),
92            };
93            gst::result_from_gboolean!(
94                f(
95                    self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0,
96                    &mut spec.0
97                ),
98                gst::CAT_RUST,
99                "Failed to prepare element using the parent function"
100            )
101        }
102    }
103
104    fn parent_unprepare(&self) -> Result<(), LoggableError> {
105        unsafe {
106            let data = Self::type_data();
107            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
108            let f = match (*parent_class).unprepare {
109                Some(f) => f,
110                None => {
111                    return Err(gst::loggable_error!(
112                        gst::CAT_RUST,
113                        "Unprepare is not implemented!"
114                    ));
115                }
116            };
117            gst::result_from_gboolean!(
118                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
119                gst::CAT_RUST,
120                "Failed to unprepare element using the parent function"
121            )
122        }
123    }
124
125    fn parent_write(&self, buffer: &[u8]) -> Result<i32, LoggableError> {
126        unsafe {
127            let data = Self::type_data();
128            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
129            let f = match (*parent_class).write {
130                Some(f) => f,
131                None => return Ok(-1),
132            };
133            let buffer_ptr = buffer.as_ptr() as glib::ffi::gpointer;
134            let ret = f(
135                self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0,
136                buffer_ptr,
137                buffer.len() as u32,
138            );
139            if ret > 0 {
140                Ok(ret)
141            } else {
142                Err(gst::loggable_error!(
143                    gst::CAT_RUST,
144                    "Failed to write using the parent function"
145                ))
146            }
147        }
148    }
149
150    fn parent_reset(&self) {
151        unsafe {
152            let data = Self::type_data();
153            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
154            if let Some(f) = (*parent_class).reset {
155                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0)
156            }
157        }
158    }
159}
160
161impl<T: AudioSinkImpl> AudioSinkImplExt for T {}
162
163unsafe impl<T: AudioSinkImpl> IsSubclassable<T> for AudioSink {
164    fn class_init(klass: &mut glib::Class<Self>) {
165        Self::parent_class_init::<T>(klass);
166        let klass = klass.as_mut();
167        klass.close = Some(audiosink_close::<T>);
168        klass.delay = Some(audiosink_delay::<T>);
169        klass.open = Some(audiosink_open::<T>);
170        klass.prepare = Some(audiosink_prepare::<T>);
171        klass.unprepare = Some(audiosink_unprepare::<T>);
172        klass.write = Some(audiosink_write::<T>);
173        klass.reset = Some(audiosink_reset::<T>);
174    }
175}
176
177unsafe extern "C" fn audiosink_close<T: AudioSinkImpl>(
178    ptr: *mut ffi::GstAudioSink,
179) -> glib::ffi::gboolean {
180    unsafe {
181        let instance = &*(ptr as *mut T::Instance);
182        let imp = instance.imp();
183
184        gst::panic_to_error!(imp, false, {
185            match imp.close() {
186                Ok(()) => true,
187                Err(err) => {
188                    err.log_with_imp(imp);
189                    false
190                }
191            }
192        })
193        .into_glib()
194    }
195}
196
197unsafe extern "C" fn audiosink_delay<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) -> u32 {
198    unsafe {
199        let instance = &*(ptr as *mut T::Instance);
200        let imp = instance.imp();
201
202        gst::panic_to_error!(imp, 0, { imp.delay() })
203    }
204}
205
206unsafe extern "C" fn audiosink_open<T: AudioSinkImpl>(
207    ptr: *mut ffi::GstAudioSink,
208) -> glib::ffi::gboolean {
209    unsafe {
210        let instance = &*(ptr as *mut T::Instance);
211        let imp = instance.imp();
212
213        gst::panic_to_error!(imp, false, {
214            match imp.open() {
215                Ok(()) => true,
216                Err(err) => {
217                    err.log_with_imp(imp);
218                    false
219                }
220            }
221        })
222        .into_glib()
223    }
224}
225
226unsafe extern "C" fn audiosink_prepare<T: AudioSinkImpl>(
227    ptr: *mut ffi::GstAudioSink,
228    spec: *mut ffi::GstAudioRingBufferSpec,
229) -> glib::ffi::gboolean {
230    unsafe {
231        let instance = &*(ptr as *mut T::Instance);
232        let imp = instance.imp();
233
234        let spec = &mut *(spec as *mut AudioRingBufferSpec);
235
236        gst::panic_to_error!(imp, false, {
237            match AudioSinkImpl::prepare(imp, spec) {
238                Ok(()) => true,
239                Err(err) => {
240                    err.log_with_imp(imp);
241                    false
242                }
243            }
244        })
245        .into_glib()
246    }
247}
248
249unsafe extern "C" fn audiosink_unprepare<T: AudioSinkImpl>(
250    ptr: *mut ffi::GstAudioSink,
251) -> glib::ffi::gboolean {
252    unsafe {
253        let instance = &*(ptr as *mut T::Instance);
254        let imp = instance.imp();
255
256        gst::panic_to_error!(imp, false, {
257            match imp.unprepare() {
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 audiosink_write<T: AudioSinkImpl>(
270    ptr: *mut ffi::GstAudioSink,
271    data: glib::ffi::gpointer,
272    length: u32,
273) -> i32 {
274    unsafe {
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}
286
287unsafe extern "C" fn audiosink_reset<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) {
288    unsafe {
289        let instance = &*(ptr as *mut T::Instance);
290        let imp = instance.imp();
291
292        gst::panic_to_error!(imp, (), {
293            imp.reset();
294        });
295    }
296}