diff --git a/gstreamer-audio/src/audio_ring_buffer_spec.rs b/gstreamer-audio/src/audio_ring_buffer_spec.rs index 26e5523b7..07b5b35c8 100644 --- a/gstreamer-audio/src/audio_ring_buffer_spec.rs +++ b/gstreamer-audio/src/audio_ring_buffer_spec.rs @@ -17,12 +17,12 @@ impl AudioRingBufferSpec { self.0.type_ = value.to_glib(); } - pub fn get_caps(&mut self) -> Caps { + pub fn get_caps(&self) -> Caps { unsafe { Caps::from_glib_none(self.0.caps) } } - pub fn get_audio_info(&mut self) -> AudioInfo { - unsafe { AudioInfo::from_glib_none(&mut self.0.info) } + pub fn get_audio_info(&self) -> AudioInfo { + unsafe { AudioInfo::from_glib_none(mut_override(&self.0.info)) } } pub fn get_latency_time(&self) -> u64 { diff --git a/gstreamer-audio/src/subclass/audio_sink.rs b/gstreamer-audio/src/subclass/audio_sink.rs new file mode 100644 index 000000000..0a9f70f80 --- /dev/null +++ b/gstreamer-audio/src/subclass/audio_sink.rs @@ -0,0 +1,314 @@ +use glib_sys; +use gst_audio_sys; + +use glib::translate::*; + +use glib::subclass::prelude::*; +use gst::subclass::prelude::*; +use gst::LoggableError; +use gst_base::subclass::prelude::*; + +use AudioRingBufferSpec; +use AudioSink; +use AudioSinkClass; + +pub trait AudioSinkImpl: AudioSinkImplExt + BaseSinkImpl + Send + Sync + 'static { + fn close(&self, sink: &mut AudioSink) -> Result<(), LoggableError> { + self.parent_close(sink) + } + + fn delay(&self, sink: &AudioSink) -> u32 { + self.parent_delay(sink) + } + + fn open(&self, sink: &AudioSink) -> Result<(), LoggableError> { + self.parent_open(sink) + } + + fn prepare( + &self, + sink: &AudioSink, + spec: &mut AudioRingBufferSpec, + ) -> Result<(), LoggableError> { + AudioSinkImplExt::parent_prepare(self, sink, spec) + } + + fn unprepare(&self, sink: &AudioSink) -> Result<(), LoggableError> { + self.parent_unprepare(sink) + } + + fn write(&self, sink: &AudioSink, audio_data: &[u8]) -> Result; +} + +pub trait AudioSinkImplExt { + fn parent_close(&self, sink: &mut AudioSink) -> Result<(), LoggableError>; + fn parent_delay(&self, sink: &AudioSink) -> u32; + fn parent_open(&self, sink: &AudioSink) -> Result<(), LoggableError>; + fn parent_prepare( + &self, + sink: &AudioSink, + spec: &mut AudioRingBufferSpec, + ) -> Result<(), LoggableError>; + fn parent_unprepare(&self, sink: &AudioSink) -> Result<(), LoggableError>; + fn parent_write(&self, sink: &AudioSink, audio_data: &[u8]) -> Result; +} + +impl AudioSinkImplExt for T { + fn parent_close(&self, sink: &mut AudioSink) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSinkClass; + let f = match (*parent_class).close { + None => return Ok(()), + Some(f) => f, + }; + gst_result_from_gboolean!( + f(sink.to_glib_none().0), + gst::CAT_RUST, + "Failed to close element using the parent function" + ) + } + } + + fn parent_delay(&self, sink: &AudioSink) -> u32 { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSinkClass; + let f = match (*parent_class).delay { + Some(f) => f, + None => return 0, + }; + f(sink.to_glib_none().0) + } + } + + fn parent_open(&self, sink: &AudioSink) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSinkClass; + let f = match (*parent_class).open { + Some(f) => f, + None => return Ok(()), + }; + gst_result_from_gboolean!( + f(sink.to_glib_none().0), + gst::CAT_RUST, + "Failed to open element using the parent function" + ) + } + } + + fn parent_prepare( + &self, + sink: &AudioSink, + 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::GstAudioSinkClass; + let f = match (*parent_class).prepare { + Some(f) => f, + None => return Ok(()), + }; + gst_result_from_gboolean!( + f(sink.to_glib_none().0, &mut spec.0), + gst::CAT_RUST, + "Failed to prepare element using the parent function" + ) + } + } + + fn parent_unprepare(&self, sink: &AudioSink) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioSinkClass; + 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(sink.to_glib_none().0), + gst::CAT_RUST, + "Failed to unprepare element using the parent function" + ) + } + } + + fn parent_write(&self, sink: &AudioSink, buffer: &[u8]) -> Result { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::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(sink.to_glib_none().0, buffer_ptr, buffer.len() as u32); + if ret > 0 { + Ok(ret) + } else { + Err(gst::gst_loggable_error!( + gst::CAT_RUST, + "Failed to write using the parent function" + )) + } + } + } +} + +unsafe impl IsSubclassable for AudioSinkClass +where + ::Instance: PanicPoison, +{ + fn override_vfuncs(&mut self) { + >::override_vfuncs(self); + unsafe { + let klass = &mut *(self as *mut Self as *mut gst_audio_sys::GstAudioSinkClass); + 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::); + } + } +} + +unsafe extern "C" fn audiosink_close( + ptr: *mut gst_audio_sys::GstAudioSink, +) -> glib_sys::gboolean +where + T: AudioSinkImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let mut wrap: AudioSink = 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 audiosink_delay( + ptr: *mut gst_audio_sys::GstAudioSink, +) -> u32 +where + T: AudioSinkImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSink = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), 0, { imp.delay(&wrap) }) +} + +unsafe extern "C" fn audiosink_open( + ptr: *mut gst_audio_sys::GstAudioSink, +) -> glib_sys::gboolean +where + T: AudioSinkImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSink = 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 audiosink_prepare( + ptr: *mut gst_audio_sys::GstAudioSink, + spec: *mut gst_audio_sys::GstAudioRingBufferSpec, +) -> glib_sys::gboolean +where + T: AudioSinkImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSink = from_glib_borrow(ptr); + + let spec = &mut *(spec as *mut AudioRingBufferSpec); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match AudioSinkImpl::prepare(imp, &wrap, spec) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audiosink_unprepare( + ptr: *mut gst_audio_sys::GstAudioSink, +) -> glib_sys::gboolean +where + T: AudioSinkImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSink = 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 audiosink_write( + ptr: *mut gst_audio_sys::GstAudioSink, + data: glib_sys::gpointer, + length: u32, +) -> i32 +where + T: AudioSinkImpl, + T::Instance: PanicPoison, +{ + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioSink = from_glib_borrow(ptr); + let data_slice = std::slice::from_raw_parts(data as *const u8, length as usize); + + gst_panic_to_error!(&wrap, &instance.panicked(), -1, { + imp.write(&wrap, data_slice).unwrap_or(-1) + }) +} diff --git a/gstreamer-audio/src/subclass/mod.rs b/gstreamer-audio/src/subclass/mod.rs index f451e24f0..1ad30b006 100644 --- a/gstreamer-audio/src/subclass/mod.rs +++ b/gstreamer-audio/src/subclass/mod.rs @@ -14,4 +14,5 @@ pub mod audio_sink; pub mod prelude { pub use super::audio_decoder::{AudioDecoderImpl, AudioDecoderImplExt}; pub use super::audio_encoder::{AudioEncoderImpl, AudioEncoderImplExt}; + pub use super::audio_sink::{AudioSinkImpl, AudioSinkImplExt}; }