diff --git a/gstreamer-audio/src/subclass/audio_src.rs b/gstreamer-audio/src/subclass/audio_src.rs new file mode 100644 index 000000000..a62935da9 --- /dev/null +++ b/gstreamer-audio/src/subclass/audio_src.rs @@ -0,0 +1,334 @@ +use glib_sys; +use gst_audio_sys; + +use std::mem; + +use glib::translate::*; + +use glib::subclass::prelude::*; +use gst::subclass::prelude::*; +use gst::LoggableError; +use gst_base::subclass::prelude::*; + +use AudioRingBufferSpec; +use AudioSrc; +use AudioSrcClass; + +pub trait AudioSrcImpl: AudioSrcImplExt + BaseSrcImpl + Send + Sync + 'static { + fn close(&self, src: &mut AudioSrc) -> Result<(), LoggableError> { + self.parent_close(src) + } + + fn delay(&self, src: &AudioSrc) -> u32 { + self.parent_delay(src) + } + + fn open(&self, src: &AudioSrc) -> Result<(), LoggableError> { + self.parent_open(src) + } + + fn prepare(&self, src: &AudioSrc, spec: &mut AudioRingBufferSpec) -> Result<(), LoggableError> { + AudioSrcImplExt::parent_prepare(self, src, spec) + } + + fn unprepare(&self, src: &AudioSrc) -> Result<(), LoggableError> { + self.parent_unprepare(src) + } + + fn read( + &self, + src: &AudioSrc, + audio_data: &mut [u8], + ) -> Result<(u32, gst::ClockTime), LoggableError>; +} + +pub trait AudioSrcImplExt { + fn parent_close(&self, src: &mut AudioSrc) -> Result<(), LoggableError>; + fn parent_delay(&self, src: &AudioSrc) -> u32; + fn parent_open(&self, src: &AudioSrc) -> Result<(), LoggableError>; + fn parent_prepare( + &self, + src: &AudioSrc, + spec: &mut AudioRingBufferSpec, + ) -> Result<(), LoggableError>; + fn parent_unprepare(&self, src: &AudioSrc) -> Result<(), LoggableError>; + fn parent_read( + &self, + src: &AudioSrc, + audio_data: &mut [u8], + ) -> Result<(u32, gst::ClockTime), LoggableError>; +} + +impl AudioSrcImplExt for T { + fn parent_close(&self, src: &mut AudioSrc) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSrcClass; + let f = match (*parent_class).close { + None => return Ok(()), + Some(f) => f, + }; + gst_result_from_gboolean!( + f(src.to_glib_none().0), + gst::CAT_RUST, + "Failed to close element using the parent function" + ) + } + } + + fn parent_delay(&self, src: &AudioSrc) -> u32 { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSrcClass; + let f = match (*parent_class).delay { + Some(f) => f, + None => return 0, + }; + f(src.to_glib_none().0) + } + } + + fn parent_open(&self, src: &AudioSrc) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSrcClass; + let f = match (*parent_class).open { + Some(f) => f, + None => return Ok(()), + }; + gst_result_from_gboolean!( + f(src.to_glib_none().0), + gst::CAT_RUST, + "Failed to open element using the parent function" + ) + } + } + + fn parent_prepare( + &self, + src: &AudioSrc, + spec: &mut AudioRingBufferSpec, + ) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSrcClass; + let f = match (*parent_class).prepare { + Some(f) => f, + None => return Ok(()), + }; + gst_result_from_gboolean!( + f(src.to_glib_none().0, &mut spec.0), + gst::CAT_RUST, + "Failed to prepare element using the parent function" + ) + } + } + + fn parent_unprepare(&self, src: &AudioSrc) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSrcClass; + let f = match (*parent_class).unprepare { + Some(f) => f, + None => { + return Err(gst::gst_loggable_error!( + gst::CAT_RUST, + "Unprepare is not implemented!" + )) + } + }; + gst_result_from_gboolean!( + f(src.to_glib_none().0), + gst::CAT_RUST, + "Failed to unprepare element using the parent function" + ) + } + } + + fn parent_read( + &self, + src: &AudioSrc, + buffer: &mut [u8], + ) -> Result<(u32, gst::ClockTime), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSrcClass; + let f = match (*parent_class).read { + Some(f) => f, + None => return Ok((0, gst::CLOCK_TIME_NONE)), + }; + let buffer_ptr = buffer.as_mut_ptr() as *mut _; + let mut timestamp = mem::MaybeUninit::uninit(); + let ret = f( + src.to_glib_none().0, + buffer_ptr, + buffer.len() as u32, + timestamp.as_mut_ptr(), + ); + if ret > 0 { + Ok((ret, from_glib(timestamp.assume_init()))) + } else { + Err(gst::gst_loggable_error!( + gst::CAT_RUST, + "Failed to read using the parent function" + )) + } + } + } +} + +unsafe impl IsSubclassable for AudioSrcClass +where + ::Instance: PanicPoison, +{ + fn override_vfuncs(&mut self) { + >::override_vfuncs(self); + unsafe { + let klass = &mut *(self as *mut Self as *mut gst_audio_sys::GstAudioSrcClass); + klass.close = Some(audiosrc_close::); + klass.delay = Some(audiosrc_delay::); + klass.open = Some(audiosrc_open::); + klass.prepare = Some(audiosrc_prepare::); + klass.unprepare = Some(audiosrc_unprepare::); + klass.read = Some(audiosrc_read::); + } + } +} + +unsafe extern "C" fn audiosrc_close( + ptr: *mut gst_audio_sys::GstAudioSrc, +) -> glib_sys::gboolean +where + T: AudioSrcImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let mut wrap: AudioSrc = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.close(&mut wrap) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audiosrc_delay(ptr: *mut gst_audio_sys::GstAudioSrc) -> u32 +where + T: AudioSrcImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSrc = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), 0, { imp.delay(&wrap) }) +} + +unsafe extern "C" fn audiosrc_open( + ptr: *mut gst_audio_sys::GstAudioSrc, +) -> glib_sys::gboolean +where + T: AudioSrcImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSrc = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.open(&wrap) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audiosrc_prepare( + ptr: *mut gst_audio_sys::GstAudioSrc, + spec: *mut gst_audio_sys::GstAudioRingBufferSpec, +) -> glib_sys::gboolean +where + T: AudioSrcImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSrc = from_glib_borrow(ptr); + + let spec = &mut *(spec as *mut AudioRingBufferSpec); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match AudioSrcImpl::prepare(imp, &wrap, spec) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audiosrc_unprepare( + ptr: *mut gst_audio_sys::GstAudioSrc, +) -> glib_sys::gboolean +where + T: AudioSrcImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSrc = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.unprepare(&wrap) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audiosrc_read( + ptr: *mut gst_audio_sys::GstAudioSrc, + data: glib_sys::gpointer, + length: u32, + timestamp: *mut gst_sys::GstClockTime, +) -> u32 +where + T: AudioSrcImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSrc = from_glib_borrow(ptr); + let data_slice = std::slice::from_raw_parts_mut(data as *mut u8, length as usize); + + gst_panic_to_error!(&wrap, &instance.panicked(), 0, { + let (res, timestamp_res) = imp + .read(&wrap, data_slice) + .unwrap_or((0, gst::CLOCK_TIME_NONE)); + *timestamp = timestamp_res.to_glib(); + + res + }) +} diff --git a/gstreamer-audio/src/subclass/mod.rs b/gstreamer-audio/src/subclass/mod.rs index 1ad30b006..1cbb83a23 100644 --- a/gstreamer-audio/src/subclass/mod.rs +++ b/gstreamer-audio/src/subclass/mod.rs @@ -10,9 +10,11 @@ pub mod audio_decoder; pub mod audio_encoder; pub mod audio_sink; +pub mod audio_src; pub mod prelude { pub use super::audio_decoder::{AudioDecoderImpl, AudioDecoderImplExt}; pub use super::audio_encoder::{AudioEncoderImpl, AudioEncoderImplExt}; pub use super::audio_sink::{AudioSinkImpl, AudioSinkImplExt}; + pub use super::audio_src::{AudioSrcImpl, AudioSrcImplExt}; }