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: AudioSinkImplExt + AudioBaseSinkImpl {
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
40mod sealed {
41    pub trait Sealed {}
42    impl<T: super::AudioSinkImplExt> Sealed for T {}
43}
44
45pub trait AudioSinkImplExt: sealed::Sealed + ObjectSubclass {
46    fn parent_close(&self) -> Result<(), LoggableError> {
47        unsafe {
48            let data = Self::type_data();
49            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
50            let f = match (*parent_class).close {
51                None => return Ok(()),
52                Some(f) => f,
53            };
54            gst::result_from_gboolean!(
55                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
56                gst::CAT_RUST,
57                "Failed to close element using the parent function"
58            )
59        }
60    }
61
62    fn parent_delay(&self) -> u32 {
63        unsafe {
64            let data = Self::type_data();
65            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
66            let f = match (*parent_class).delay {
67                Some(f) => f,
68                None => return 0,
69            };
70            f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0)
71        }
72    }
73
74    fn parent_open(&self) -> Result<(), LoggableError> {
75        unsafe {
76            let data = Self::type_data();
77            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
78            let f = match (*parent_class).open {
79                Some(f) => f,
80                None => return Ok(()),
81            };
82            gst::result_from_gboolean!(
83                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
84                gst::CAT_RUST,
85                "Failed to open element using the parent function"
86            )
87        }
88    }
89
90    fn parent_prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> {
91        unsafe {
92            let data = Self::type_data();
93            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
94            let f = match (*parent_class).prepare {
95                Some(f) => f,
96                None => return Ok(()),
97            };
98            gst::result_from_gboolean!(
99                f(
100                    self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0,
101                    &mut spec.0
102                ),
103                gst::CAT_RUST,
104                "Failed to prepare element using the parent function"
105            )
106        }
107    }
108
109    fn parent_unprepare(&self) -> Result<(), LoggableError> {
110        unsafe {
111            let data = Self::type_data();
112            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
113            let f = match (*parent_class).unprepare {
114                Some(f) => f,
115                None => {
116                    return Err(gst::loggable_error!(
117                        gst::CAT_RUST,
118                        "Unprepare is not implemented!"
119                    ))
120                }
121            };
122            gst::result_from_gboolean!(
123                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0),
124                gst::CAT_RUST,
125                "Failed to unprepare element using the parent function"
126            )
127        }
128    }
129
130    fn parent_write(&self, buffer: &[u8]) -> Result<i32, LoggableError> {
131        unsafe {
132            let data = Self::type_data();
133            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
134            let f = match (*parent_class).write {
135                Some(f) => f,
136                None => return Ok(-1),
137            };
138            let buffer_ptr = buffer.as_ptr() as glib::ffi::gpointer;
139            let ret = f(
140                self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0,
141                buffer_ptr,
142                buffer.len() as u32,
143            );
144            if ret > 0 {
145                Ok(ret)
146            } else {
147                Err(gst::loggable_error!(
148                    gst::CAT_RUST,
149                    "Failed to write using the parent function"
150                ))
151            }
152        }
153    }
154
155    fn parent_reset(&self) {
156        unsafe {
157            let data = Self::type_data();
158            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass;
159            if let Some(f) = (*parent_class).reset {
160                f(self.obj().unsafe_cast_ref::<AudioSink>().to_glib_none().0)
161            }
162        }
163    }
164}
165
166impl<T: AudioSinkImpl> AudioSinkImplExt for T {}
167
168unsafe impl<T: AudioSinkImpl> IsSubclassable<T> for AudioSink {
169    fn class_init(klass: &mut glib::Class<Self>) {
170        Self::parent_class_init::<T>(klass);
171        let klass = klass.as_mut();
172        klass.close = Some(audiosink_close::<T>);
173        klass.delay = Some(audiosink_delay::<T>);
174        klass.open = Some(audiosink_open::<T>);
175        klass.prepare = Some(audiosink_prepare::<T>);
176        klass.unprepare = Some(audiosink_unprepare::<T>);
177        klass.write = Some(audiosink_write::<T>);
178        klass.reset = Some(audiosink_reset::<T>);
179    }
180}
181
182unsafe extern "C" fn audiosink_close<T: AudioSinkImpl>(
183    ptr: *mut ffi::GstAudioSink,
184) -> glib::ffi::gboolean {
185    let instance = &*(ptr as *mut T::Instance);
186    let imp = instance.imp();
187
188    gst::panic_to_error!(imp, false, {
189        match imp.close() {
190            Ok(()) => true,
191            Err(err) => {
192                err.log_with_imp(imp);
193                false
194            }
195        }
196    })
197    .into_glib()
198}
199
200unsafe extern "C" fn audiosink_delay<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) -> u32 {
201    let instance = &*(ptr as *mut T::Instance);
202    let imp = instance.imp();
203
204    gst::panic_to_error!(imp, 0, { imp.delay() })
205}
206
207unsafe extern "C" fn audiosink_open<T: AudioSinkImpl>(
208    ptr: *mut ffi::GstAudioSink,
209) -> glib::ffi::gboolean {
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
225unsafe extern "C" fn audiosink_prepare<T: AudioSinkImpl>(
226    ptr: *mut ffi::GstAudioSink,
227    spec: *mut ffi::GstAudioRingBufferSpec,
228) -> glib::ffi::gboolean {
229    let instance = &*(ptr as *mut T::Instance);
230    let imp = instance.imp();
231
232    let spec = &mut *(spec as *mut AudioRingBufferSpec);
233
234    gst::panic_to_error!(imp, false, {
235        match AudioSinkImpl::prepare(imp, spec) {
236            Ok(()) => true,
237            Err(err) => {
238                err.log_with_imp(imp);
239                false
240            }
241        }
242    })
243    .into_glib()
244}
245
246unsafe extern "C" fn audiosink_unprepare<T: AudioSinkImpl>(
247    ptr: *mut ffi::GstAudioSink,
248) -> glib::ffi::gboolean {
249    let instance = &*(ptr as *mut T::Instance);
250    let imp = instance.imp();
251
252    gst::panic_to_error!(imp, false, {
253        match imp.unprepare() {
254            Ok(()) => true,
255            Err(err) => {
256                err.log_with_imp(imp);
257                false
258            }
259        }
260    })
261    .into_glib()
262}
263
264unsafe extern "C" fn audiosink_write<T: AudioSinkImpl>(
265    ptr: *mut ffi::GstAudioSink,
266    data: glib::ffi::gpointer,
267    length: u32,
268) -> i32 {
269    let instance = &*(ptr as *mut T::Instance);
270    let imp = instance.imp();
271    let data_slice = if length == 0 {
272        &[]
273    } else {
274        std::slice::from_raw_parts(data as *const u8, length as usize)
275    };
276
277    gst::panic_to_error!(imp, -1, { imp.write(data_slice).unwrap_or(-1) })
278}
279
280unsafe extern "C" fn audiosink_reset<T: AudioSinkImpl>(ptr: *mut ffi::GstAudioSink) {
281    let instance = &*(ptr as *mut T::Instance);
282    let imp = instance.imp();
283
284    gst::panic_to_error!(imp, (), {
285        imp.reset();
286    });
287}