// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use gst::LoggableError; use gst_base::subclass::prelude::*; use super::prelude::*; use crate::{AudioRingBufferSpec, AudioSink}; pub trait AudioSinkImpl: AudioSinkImplExt + AudioBaseSinkImpl { fn close(&self) -> Result<(), LoggableError> { self.parent_close() } fn delay(&self) -> u32 { self.parent_delay() } fn open(&self) -> Result<(), LoggableError> { self.parent_open() } fn prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> { AudioSinkImplExt::parent_prepare(self, spec) } fn unprepare(&self) -> Result<(), LoggableError> { self.parent_unprepare() } fn write(&self, audio_data: &[u8]) -> Result { self.parent_write(audio_data) } fn reset(&self) { self.parent_reset() } } mod sealed { pub trait Sealed {} impl Sealed for T {} } pub trait AudioSinkImplExt: sealed::Sealed + ObjectSubclass { fn parent_close(&self) -> Result<(), LoggableError> { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass; let f = match (*parent_class).close { None => return Ok(()), Some(f) => f, }; gst::result_from_gboolean!( f(self.obj().unsafe_cast_ref::().to_glib_none().0), gst::CAT_RUST, "Failed to close element using the parent function" ) } } fn parent_delay(&self) -> u32 { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass; let f = match (*parent_class).delay { Some(f) => f, None => return 0, }; f(self.obj().unsafe_cast_ref::().to_glib_none().0) } } fn parent_open(&self) -> Result<(), LoggableError> { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass; let f = match (*parent_class).open { Some(f) => f, None => return Ok(()), }; gst::result_from_gboolean!( f(self.obj().unsafe_cast_ref::().to_glib_none().0), gst::CAT_RUST, "Failed to open element using the parent function" ) } } fn parent_prepare(&self, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass; let f = match (*parent_class).prepare { Some(f) => f, None => return Ok(()), }; gst::result_from_gboolean!( f( self.obj().unsafe_cast_ref::().to_glib_none().0, &mut spec.0 ), gst::CAT_RUST, "Failed to prepare element using the parent function" ) } } fn parent_unprepare(&self) -> Result<(), LoggableError> { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass; let f = match (*parent_class).unprepare { Some(f) => f, None => { return Err(gst::loggable_error!( gst::CAT_RUST, "Unprepare is not implemented!" )) } }; gst::result_from_gboolean!( f(self.obj().unsafe_cast_ref::().to_glib_none().0), gst::CAT_RUST, "Failed to unprepare element using the parent function" ) } } fn parent_write(&self, buffer: &[u8]) -> Result { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass; let f = match (*parent_class).write { Some(f) => f, None => return Ok(-1), }; let buffer_ptr = buffer.as_ptr() as *const _ as *mut _; let ret = f( self.obj().unsafe_cast_ref::().to_glib_none().0, buffer_ptr, buffer.len() as u32, ); if ret > 0 { Ok(ret) } else { Err(gst::loggable_error!( gst::CAT_RUST, "Failed to write using the parent function" )) } } } fn parent_reset(&self) { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioSinkClass; if let Some(f) = (*parent_class).reset { f(self.obj().unsafe_cast_ref::().to_glib_none().0) } } } } impl AudioSinkImplExt for T {} unsafe impl IsSubclassable for AudioSink { fn class_init(klass: &mut glib::Class) { Self::parent_class_init::(klass); let klass = klass.as_mut(); klass.close = Some(audiosink_close::); klass.delay = Some(audiosink_delay::); klass.open = Some(audiosink_open::); klass.prepare = Some(audiosink_prepare::); klass.unprepare = Some(audiosink_unprepare::); klass.write = Some(audiosink_write::); klass.reset = Some(audiosink_reset::); } } unsafe extern "C" fn audiosink_close( ptr: *mut ffi::GstAudioSink, ) -> glib::ffi::gboolean { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); gst::panic_to_error!(imp, false, { match imp.close() { Ok(()) => true, Err(err) => { err.log_with_imp(imp); false } } }) .into_glib() } unsafe extern "C" fn audiosink_delay(ptr: *mut ffi::GstAudioSink) -> u32 { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); gst::panic_to_error!(imp, 0, { imp.delay() }) } unsafe extern "C" fn audiosink_open( ptr: *mut ffi::GstAudioSink, ) -> glib::ffi::gboolean { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); gst::panic_to_error!(imp, false, { match imp.open() { Ok(()) => true, Err(err) => { err.log_with_imp(imp); false } } }) .into_glib() } unsafe extern "C" fn audiosink_prepare( ptr: *mut ffi::GstAudioSink, spec: *mut ffi::GstAudioRingBufferSpec, ) -> glib::ffi::gboolean { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); let spec = &mut *(spec as *mut AudioRingBufferSpec); gst::panic_to_error!(imp, false, { match AudioSinkImpl::prepare(imp, spec) { Ok(()) => true, Err(err) => { err.log_with_imp(imp); false } } }) .into_glib() } unsafe extern "C" fn audiosink_unprepare( ptr: *mut ffi::GstAudioSink, ) -> glib::ffi::gboolean { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); gst::panic_to_error!(imp, false, { match imp.unprepare() { Ok(()) => true, Err(err) => { err.log_with_imp(imp); false } } }) .into_glib() } unsafe extern "C" fn audiosink_write( ptr: *mut ffi::GstAudioSink, data: glib::ffi::gpointer, length: u32, ) -> i32 { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); let data_slice = if length == 0 { &[] } else { std::slice::from_raw_parts(data as *const u8, length as usize) }; gst::panic_to_error!(imp, -1, { imp.write(data_slice).unwrap_or(-1) }) } unsafe extern "C" fn audiosink_reset(ptr: *mut ffi::GstAudioSink) { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); gst::panic_to_error!(imp, (), { imp.reset(); }); }