diff --git a/gstreamer/src/element.rs b/gstreamer/src/element.rs index 41983a5e7..8d786f4c2 100644 --- a/gstreamer/src/element.rs +++ b/gstreamer/src/element.rs @@ -10,8 +10,9 @@ use Element; use glib; use glib::IsA; -use glib::translate::{from_glib, from_glib_full, from_glib_none, FromGlib, FromGlibPtrContainer, - ToGlib, ToGlibPtr}; +use glib::translate::{from_glib, from_glib_full, from_glib_none, FromGlib, FromGlibPtrBorrow, + FromGlibPtrContainer, ToGlib, ToGlibPtr}; +use glib::object::Downcast; use QueryRef; use Event; use Pad; @@ -28,6 +29,7 @@ use std::mem; use libc; use ffi; +use glib_ffi; use gobject_ffi; impl Element { @@ -174,6 +176,11 @@ pub trait ElementExtManual { seek_flags: ::SeekFlags, seek_pos: V, ) -> Result<(), glib::error::BoolError>; + + #[cfg(any(feature = "v1_10", feature = "dox"))] + fn call_async(&self, func: F) + where + F: FnOnce(&Self) + Send + 'static; } impl> ElementExtManual for O { @@ -562,6 +569,42 @@ impl> ElementExtManual for O { ) } } + + #[cfg(any(feature = "v1_10", feature = "dox"))] + fn call_async(&self, func: F) + where + F: FnOnce(&Self) + Send + 'static, + { + let user_data: Box>> = Box::new(Some(Box::new(func))); + + unsafe extern "C" fn trampoline, F: FnOnce(&O) + Send + 'static>( + element: *mut ffi::GstElement, + user_data: glib_ffi::gpointer, + ) { + callback_guard!(); + let user_data: &mut Option> = &mut *(user_data as *mut _); + let callback = user_data.take().unwrap(); + + callback(&Element::from_glib_borrow(element).downcast_unchecked()); + } + + unsafe extern "C" fn free_user_data, F: FnOnce(&O) + Send + 'static>( + user_data: glib_ffi::gpointer, + ) { + let _: Box>> = Box::from_raw(user_data as *mut _); + } + + let trampoline = trampoline::; + let free_user_data = free_user_data::; + unsafe { + ffi::gst_element_call_async( + self.to_glib_none().0, + Some(trampoline), + Box::into_raw(user_data) as *mut _, + Some(free_user_data), + ); + } + } } lazy_static!{ @@ -1042,6 +1085,7 @@ macro_rules! gst_element_info( mod tests { use super::*; use prelude::*; + use std::sync::mpsc::channel; #[test] fn test_get_pads() { @@ -1073,4 +1117,18 @@ mod tests { pad_names.sort(); assert_eq!(pad_names, vec![String::from("src")]); } + + #[test] + fn test_call_async() { + ::init().unwrap(); + + let identity = ::ElementFactory::make("identity", None).unwrap(); + let (sender, receiver) = channel(); + + identity.call_async(move |_| { + sender.send(()).unwrap(); + }); + + assert_eq!(receiver.recv(), Ok(())); + } }