diff --git a/src/rsfilesink.rs b/src/rsfilesink.rs index 2912b83a..e573073b 100644 --- a/src/rsfilesink.rs +++ b/src/rsfilesink.rs @@ -62,24 +62,24 @@ impl FileSink { } impl Sink for FileSink { - fn set_uri(&self, uri: Option) -> bool { + fn set_uri(&self, uri: Option) -> Result<(), (UriError, String)> { let location = &mut self.settings.lock().unwrap().location; match uri { None => { *location = None; - true + Ok(()) } Some(ref uri) => { match uri.to_file_path().ok() { Some(p) => { *location = Some(p); - true + Ok(()) } None => { *location = None; - println_err!("Unsupported file URI '{}'", uri.as_str()); - false + Err((UriError::UnsupportedProtocol, + format!("Unsupported file URI '{}'", uri.as_str()))) } } } diff --git a/src/rsfilesrc.rs b/src/rsfilesrc.rs index 917b8df3..42279323 100644 --- a/src/rsfilesrc.rs +++ b/src/rsfilesrc.rs @@ -63,24 +63,24 @@ impl FileSrc { } impl Source for FileSrc { - fn set_uri(&self, uri: Option) -> bool { + fn set_uri(&self, uri: Option) -> Result<(), (UriError, String)> { let location = &mut self.settings.lock().unwrap().location; match uri { None => { *location = None; - true + Ok(()) } Some(ref uri) => { match uri.to_file_path().ok() { Some(p) => { *location = Some(p); - true + Ok(()) } None => { *location = None; - println_err!("Unsupported file URI '{}'", uri.as_str()); - false + Err((UriError::UnsupportedProtocol, + format!("Unsupported file URI '{}'", uri.as_str()))) } } } diff --git a/src/rshttpsrc.rs b/src/rshttpsrc.rs index 9718d357..fd271dec 100644 --- a/src/rshttpsrc.rs +++ b/src/rshttpsrc.rs @@ -141,22 +141,22 @@ impl HttpSrc { } impl Source for HttpSrc { - fn set_uri(&self, uri: Option) -> bool { + fn set_uri(&self, uri: Option) -> Result<(), (UriError, String)> { let url = &mut self.settings.lock().unwrap().url; match uri { None => { *url = None; - true + Ok(()) } Some(uri) => { if uri.scheme() == "http" || uri.scheme() == "https" { *url = Some(uri); - true + Ok(()) } else { *url = None; - println_err!("Unsupported URI '{}'", uri.as_str()); - false + Err((UriError::UnsupportedProtocol, + format!("Unsupported URI '{}'", uri.as_str()))) } } } diff --git a/src/rssink.c b/src/rssink.c index f6e1f9e8..dfa0962f 100644 --- a/src/rssink.c +++ b/src/rssink.c @@ -38,7 +38,7 @@ static GHashTable *sinks; extern gboolean sinks_register (void *plugin); extern void *sink_new (GstRsSink * sink, void *create_instance); extern GstFlowReturn sink_render (void *rssink, void *data, size_t data_len); -extern gboolean sink_set_uri (void *rssink, const char *uri); +extern gboolean sink_set_uri (void *rssink, const char *uri, GError ** err); extern char *sink_get_uri (void *rssink); extern gboolean sink_start (void *rssink); extern gboolean sink_stop (void *rssink); @@ -140,7 +140,7 @@ gst_rs_sink_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_URI: - sink_set_uri (sink->instance, g_value_get_string (value)); + sink_set_uri (sink->instance, g_value_get_string (value), NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -229,11 +229,8 @@ gst_rs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri, { GstRsSink *sink = GST_RS_SINK (handler); - if (!sink_set_uri (sink->instance, uri)) { - g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, - "Can't handle URI '%s'", uri); + if (!sink_set_uri (sink->instance, uri, err)) return FALSE; - } return TRUE; } diff --git a/src/rssink.rs b/src/rssink.rs index 9f413c9c..b0a34792 100644 --- a/src/rssink.rs +++ b/src/rssink.rs @@ -21,7 +21,6 @@ use std::os::raw::c_void; use std::ffi::{CStr, CString}; use std::slice; use std::ptr; -use std::io::Write; use url::Url; @@ -40,7 +39,7 @@ impl SinkController { pub trait Sink: Sync + Send { // Called from any thread at any time - fn set_uri(&self, uri: Option) -> bool; + fn set_uri(&self, uri: Option) -> Result<(), (UriError, String)>; fn get_uri(&self) -> Option; // Called from the streaming thread only @@ -62,19 +61,37 @@ pub unsafe extern "C" fn sink_drop(ptr: *mut Box) { } #[no_mangle] -pub unsafe extern "C" fn sink_set_uri(ptr: *mut Box, uri_ptr: *const c_char) -> GBoolean { +pub unsafe extern "C" fn sink_set_uri(ptr: *mut Box, + uri_ptr: *const c_char, + cerr: *mut c_void) + -> GBoolean { let sink: &mut Box = &mut *ptr; if uri_ptr.is_null() { - GBoolean::from_bool(sink.set_uri(None)) + if let Err((code, msg)) = sink.set_uri(None) { + code.into_gerror(cerr, Some(&msg)); + GBoolean::False + } else { + GBoolean::True + } } else { let uri_str = CStr::from_ptr(uri_ptr).to_str().unwrap(); match Url::parse(uri_str) { - Ok(uri) => GBoolean::from_bool(sink.set_uri(Some(uri))), + Ok(uri) => { + if let Err((code, msg)) = sink.set_uri(Some(uri)) { + code.into_gerror(cerr, Some(&msg)); + GBoolean::False + } else { + GBoolean::True + } + } Err(err) => { - sink.set_uri(None); - println_err!("Failed to parse URI '{}': {}", uri_str, err); + let _ = sink.set_uri(None); + UriError::BadUri.into_gerror(cerr, + Some(&format!("Failed to parse URI '{}': {}", + uri_str, + err))); GBoolean::False } } diff --git a/src/rssource.c b/src/rssource.c index 5a545867..8c7bc470 100644 --- a/src/rssource.c +++ b/src/rssource.c @@ -39,7 +39,7 @@ extern void source_drop (void *rssource); extern GstFlowReturn source_fill (void *rssource, uint64_t offset, void *data, size_t * data_len); extern gboolean source_do_seek (void *rssource, uint64_t start, uint64_t stop); -extern gboolean source_set_uri (void *rssource, const char *uri); +extern gboolean source_set_uri (void *rssource, const char *uri, GError ** err); extern char *source_get_uri (void *rssource); extern uint64_t source_get_size (void *rssource); extern gboolean source_is_seekable (void *rssource); @@ -149,7 +149,7 @@ gst_rs_src_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_URI: - source_set_uri (src->instance, g_value_get_string (value)); + source_set_uri (src->instance, g_value_get_string (value), NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -274,11 +274,8 @@ gst_rs_src_uri_set_uri (GstURIHandler * handler, const gchar * uri, { GstRsSrc *src = GST_RS_SRC (handler); - if (!source_set_uri (src->instance, uri)) { - g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, - "Can't handle URI '%s'", uri); + if (!source_set_uri (src->instance, uri, err)) return FALSE; - } return TRUE; } diff --git a/src/rssource.rs b/src/rssource.rs index 60ffef26..ee30861f 100644 --- a/src/rssource.rs +++ b/src/rssource.rs @@ -20,7 +20,6 @@ use std::os::raw::c_void; use std::ffi::{CStr, CString}; use std::slice; use std::ptr; -use std::io::Write; use url::Url; @@ -39,7 +38,7 @@ impl SourceController { pub trait Source: Sync + Send { // Called from any thread at any time - fn set_uri(&self, uri: Option) -> bool; + fn set_uri(&self, uri: Option) -> Result<(), (UriError, String)>; fn get_uri(&self) -> Option; // Called from any thread between start/stop @@ -66,19 +65,37 @@ pub unsafe extern "C" fn source_drop(ptr: *mut Box) { } #[no_mangle] -pub unsafe extern "C" fn source_set_uri(ptr: *mut Box, uri_ptr: *const c_char) -> GBoolean { +pub unsafe extern "C" fn source_set_uri(ptr: *mut Box, + uri_ptr: *const c_char, + cerr: *mut c_void) + -> GBoolean { let source: &mut Box = &mut *ptr; if uri_ptr.is_null() { - GBoolean::from_bool(source.set_uri(None)) + if let Err((code, msg)) = source.set_uri(None) { + code.into_gerror(cerr, Some(&msg)); + GBoolean::False + } else { + GBoolean::True + } } else { let uri_str = CStr::from_ptr(uri_ptr).to_str().unwrap(); match Url::parse(uri_str) { - Ok(uri) => GBoolean::from_bool(source.set_uri(Some(uri))), + Ok(uri) => { + if let Err((code, msg)) = source.set_uri(Some(uri)) { + code.into_gerror(cerr, Some(&msg)); + GBoolean::False + } else { + GBoolean::True + } + } Err(err) => { - source.set_uri(None); - println_err!("Failed to parse URI '{}': {}", uri_str, err); + let _ = source.set_uri(None); + UriError::BadUri.into_gerror(cerr, + Some(&format!("Failed to parse URI '{}': {}", + uri_str, + err))); GBoolean::False } } diff --git a/src/utils.rs b/src/utils.rs index 4ca934d0..8bcd8753 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -17,7 +17,9 @@ // // use libc::c_char; +use std::os::raw::c_void; use std::ffi::CString; +use std::ptr; #[macro_export] macro_rules! println_err( @@ -54,3 +56,27 @@ impl GBoolean { pub unsafe extern "C" fn cstring_drop(ptr: *mut c_char) { CString::from_raw(ptr); } + +#[repr(C)] +pub enum UriError { + UnsupportedProtocol = 0, + BadUri, + BadState, + BadReference, +} + +extern "C" { + fn g_set_error_literal(err: *mut c_void, domain: u32, code: i32, message: *const c_char); + fn gst_uri_error_quark() -> u32; +} + +impl UriError { + pub unsafe fn into_gerror(self, err: *mut c_void, message: Option<&String>) { + if let Some(msg) = message { + let cmsg = CString::new(msg.as_str()).unwrap(); + g_set_error_literal(err, gst_uri_error_quark(), self as i32, cmsg.as_ptr()); + } else { + g_set_error_literal(err, gst_uri_error_quark(), self as i32, ptr::null()); + } + } +}