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