From 4d620cd737c386eac3076dd1dac8d3ae80906a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 16 Jan 2020 12:18:57 +0200 Subject: [PATCH] Allow connecting to either an NDI name or URL/address again Apparently the SDK allows both but the documentation was a bit confusing. --- src/ndi.rs | 22 +++++++++++++++------- src/ndiaudiosrc.rs | 8 ++++---- src/ndivideosrc.rs | 10 ++++++---- src/receiver.rs | 29 +++++++++++++++++++++-------- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/ndi.rs b/src/ndi.rs index 516631e1..1ff54499 100644 --- a/src/ndi.rs +++ b/src/ndi.rs @@ -182,7 +182,8 @@ impl<'a> PartialEq for Source<'a> { #[derive(Debug)] pub struct RecvBuilder<'a> { - source_to_connect_to: (&'a str, Option<&'a str>), + ndi_name: Option<&'a str>, + url_address: Option<&'a str>, allow_video_fields: bool, bandwidth: NDIlib_recv_bandwidth_e, color_format: NDIlib_recv_color_format_e, @@ -211,15 +212,20 @@ impl<'a> RecvBuilder<'a> { pub fn build(self) -> Option { unsafe { let ndi_recv_name = ffi::CString::new(self.ndi_recv_name).unwrap(); - let ndi_name = ffi::CString::new(self.source_to_connect_to.0).unwrap(); + let ndi_name = self + .ndi_name + .as_ref() + .map(|s| ffi::CString::new(*s).unwrap()); let url_address = self - .source_to_connect_to - .1 + .url_address .as_ref() .map(|s| ffi::CString::new(*s).unwrap()); let ptr = NDIlib_recv_create_v3(&NDIlib_recv_create_v3_t { source_to_connect_to: NDIlib_source_t { - p_ndi_name: ndi_name.as_ptr(), + p_ndi_name: ndi_name + .as_ref() + .map(|s| s.as_ptr()) + .unwrap_or_else(|| ptr::null_mut()), p_url_address: url_address .as_ref() .map(|s| s.as_ptr()) @@ -258,11 +264,13 @@ unsafe impl Sync for RecvInstanceInner {} impl RecvInstance { pub fn builder<'a>( - source_to_connect_to: (&'a str, Option<&'a str>), + ndi_name: Option<&'a str>, + url_address: Option<&'a str>, ndi_recv_name: &'a str, ) -> RecvBuilder<'a> { RecvBuilder { - source_to_connect_to, + ndi_name, + url_address, allow_video_fields: true, bandwidth: NDIlib_recv_bandwidth_highest, color_format: NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA, diff --git a/src/ndiaudiosrc.rs b/src/ndiaudiosrc.rs index 884436d5..cfcf390a 100644 --- a/src/ndiaudiosrc.rs +++ b/src/ndiaudiosrc.rs @@ -60,7 +60,7 @@ static PROPERTIES: [subclass::Property; 7] = [ glib::ParamSpec::string( name, "URL/Address", - "URL/address and port of the sender, e.g. 127.0.0.1:5961. This is used as an additional filter together with the NDI name.", + "URL/address and port of the sender, e.g. 127.0.0.1:5961", None, glib::ParamFlags::READWRITE, ) @@ -401,17 +401,17 @@ impl BaseSrcImpl for NdiAudioSrc { *self.state.lock().unwrap() = Default::default(); let settings = self.settings.lock().unwrap().clone(); - if settings.ndi_name.is_none() { + if settings.ndi_name.is_none() && settings.url_address.is_none() { return Err(gst_error_msg!( gst::LibraryError::Settings, - ["No IP address or NDI name given"] + ["No NDI name or URL/address given"] )); } let receiver = connect_ndi( self.cat, element, - settings.ndi_name.as_ref().unwrap().as_str(), + settings.ndi_name.as_ref().map(String::as_str), settings.url_address.as_ref().map(String::as_str), &settings.receiver_ndi_name, settings.connect_timeout, diff --git a/src/ndivideosrc.rs b/src/ndivideosrc.rs index c4d048bf..e983d9fe 100644 --- a/src/ndivideosrc.rs +++ b/src/ndivideosrc.rs @@ -61,7 +61,7 @@ static PROPERTIES: [subclass::Property; 7] = [ glib::ParamSpec::string( name, "URL/Address", - "URL/address and port of the sender, e.g. 127.0.0.1:5961. This is used as an additional filter together with the NDI name.", + "URL/address and port of the sender, e.g. 127.0.0.1:5961", None, glib::ParamFlags::READWRITE, ) @@ -436,17 +436,17 @@ impl BaseSrcImpl for NdiVideoSrc { *self.state.lock().unwrap() = Default::default(); let settings = self.settings.lock().unwrap().clone(); - if settings.ndi_name.is_none() { + if settings.ndi_name.is_none() && settings.url_address.is_none() { return Err(gst_error_msg!( gst::LibraryError::Settings, - ["No NDI name given"] + ["No NDI name or URL/address given"] )); } let receiver = connect_ndi( self.cat, element, - settings.ndi_name.as_ref().unwrap().as_str(), + settings.ndi_name.as_ref().map(String::as_str), settings.url_address.as_ref().map(String::as_str), &settings.receiver_ndi_name, settings.connect_timeout, @@ -502,6 +502,8 @@ impl BaseSrcImpl for NdiVideoSrc { let max = 5 * state.current_latency; + println!("Returning latency min {} max {}", min, max,); + gst_debug!( self.cat, obj: element, diff --git a/src/receiver.rs b/src/receiver.rs index 371cdf2b..ba5dc399 100644 --- a/src/receiver.rs +++ b/src/receiver.rs @@ -17,7 +17,7 @@ use super::*; pub struct ReceiverInfo { id: usize, - ndi_name: String, + ndi_name: Option, url_address: Option, recv: RecvInstance, video: Option>>, @@ -521,7 +521,7 @@ impl Drop for ReceiverInner { pub fn connect_ndi( cat: gst::DebugCategory, element: &gst_base::BaseSrc, - ndi_name: &str, + ndi_name: Option<&str>, url_address: Option<&str>, receiver_ndi_name: &str, connect_timeout: u32, @@ -534,12 +534,24 @@ where { gst_debug!(cat, obj: element, "Starting NDI connection..."); + assert!(ndi_name.is_some() || url_address.is_some()); + let mut receivers = HASHMAP_RECEIVERS.lock().unwrap(); // Check if we already have a receiver for this very stream for receiver in receivers.values_mut() { - if receiver.ndi_name == ndi_name - && receiver.url_address.as_ref().map(String::as_str) == url_address + // If both are provided they both must match, if only one is provided + // then that one has to match and the other one does not matter + if (ndi_name.is_some() + && url_address.is_some() + && receiver.ndi_name.as_ref().map(String::as_str) == ndi_name + && receiver.url_address.as_ref().map(String::as_str) == url_address) + || (ndi_name.is_some() + && url_address.is_none() + && receiver.ndi_name.as_ref().map(String::as_str) == ndi_name) + || (ndi_name.is_none() + && url_address.is_some() + && receiver.url_address.as_ref().map(String::as_str) == url_address) { if (receiver.video.is_some() || !T::IS_VIDEO) && (receiver.audio.is_some() || T::IS_VIDEO) @@ -548,8 +560,9 @@ where element, gst::ResourceError::OpenRead, [ - "Source with ndi-name '{}' already in use for {}", + "Source with NDI name '{:?}' / URL/address '{:?}' already in use for {}", receiver.ndi_name, + receiver.url_address, if T::IS_VIDEO { "video" } else { "audio" } ] ); @@ -572,14 +585,14 @@ where gst_debug!( cat, obj: element, - "Connecting to NDI source with ndi-name '{}' and URL/Address {:?}", + "Connecting to NDI source with NDI name '{:?}' and URL/Address {:?}", ndi_name, url_address, ); // FIXME: Ideally we would use NDIlib_recv_color_format_fastest here but that seems to be // broken with interlaced content currently - let recv = RecvInstance::builder((ndi_name, url_address), &receiver_ndi_name) + let recv = RecvInstance::builder(ndi_name, url_address, &receiver_ndi_name) .bandwidth(bandwidth) .color_format(NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA) .allow_video_fields(true) @@ -604,7 +617,7 @@ where let id_receiver = ID_RECEIVER.fetch_add(1, Ordering::SeqCst); let mut info = ReceiverInfo { id: id_receiver, - ndi_name: String::from(ndi_name), + ndi_name: ndi_name.map(String::from), url_address: url_address.map(String::from), recv, video: None,