diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2021-01-21 21:21:29 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2021-01-25 15:43:05 +0300 |
commit | d4ce1a33f2257ea19f873711c78b7b57d5cb7e5f (patch) | |
tree | 7a4ff75e550640afd69786a2d8a41f07b6b6c593 /generic/threadshare | |
parent | 875c3efb916f2400df355f8517f1daeff6f7ae85 (diff) |
Update for glib/gstreamer bindings API changes
Diffstat (limited to 'generic/threadshare')
-rw-r--r-- | generic/threadshare/src/appsrc/imp.rs | 265 | ||||
-rw-r--r-- | generic/threadshare/src/inputselector/imp.rs | 162 | ||||
-rw-r--r-- | generic/threadshare/src/jitterbuffer/imp.rs | 295 | ||||
-rw-r--r-- | generic/threadshare/src/proxy/imp.rs | 316 | ||||
-rw-r--r-- | generic/threadshare/src/queue/imp.rs | 215 | ||||
-rw-r--r-- | generic/threadshare/src/tcpclientsrc/imp.rs | 212 | ||||
-rw-r--r-- | generic/threadshare/src/udpsink/imp.rs | 599 | ||||
-rw-r--r-- | generic/threadshare/src/udpsrc/imp.rs | 316 | ||||
-rw-r--r-- | generic/threadshare/tests/pad.rs | 178 |
9 files changed, 1314 insertions, 1244 deletions
diff --git a/generic/threadshare/src/appsrc/imp.rs b/generic/threadshare/src/appsrc/imp.rs index 908b99a53..e34ef3150 100644 --- a/generic/threadshare/src/appsrc/imp.rs +++ b/generic/threadshare/src/appsrc/imp.rs @@ -66,58 +66,6 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 5] = [ - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("max-buffers", |name| { - glib::ParamSpec::uint( - name, - "Max Buffers", - "Maximum number of buffers to queue up", - 1, - u32::MAX, - DEFAULT_MAX_BUFFERS, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("caps", |name| { - glib::ParamSpec::boxed( - name, - "Caps", - "Caps to use", - gst::Caps::static_type(), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("do-timestamp", |name| { - glib::ParamSpec::boolean( - name, - "Do Timestamp", - "Timestamp buffers with the current running time on arrival", - DEFAULT_DO_TIMESTAMP, - glib::ParamFlags::READWRITE, - ) - }), -]; - static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { gst::DebugCategory::new( "ts-appsrc", @@ -560,68 +508,12 @@ impl ObjectSubclass for AppSrc { const NAME: &'static str = "RsTsAppSrc"; type Type = super::AppSrc; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing app source", - "Source/Generic", - "Thread-sharing app source", - "Sebastian Dröge <sebastian@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - - klass.install_properties(&PROPERTIES); - - klass.add_signal_with_class_handler( - "push-buffer", - glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION, - &[gst::Buffer::static_type()], - bool::static_type(), - |_, args| { - let element = args[0] - .get::<super::AppSrc>() - .expect("signal arg") - .expect("missing signal arg"); - let buffer = args[1] - .get::<gst::Buffer>() - .expect("signal arg") - .expect("missing signal arg"); - let appsrc = Self::from_instance(&element); - - Some(appsrc.push_buffer(&element, buffer).to_value()) - }, - ); - - klass.add_signal_with_class_handler( - "end-of-stream", - glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION, - &[], - bool::static_type(), - |_, args| { - let element = args[0] - .get::<super::AppSrc>() - .expect("signal arg") - .expect("missing signal arg"); - let appsrc = Self::from_instance(&element); - Some(appsrc.end_of_stream(&element).to_value()) - }, - ); - } - fn with_class(klass: &Self::Class) -> Self { let src_pad_handler = AppSrcPadHandler::default(); @@ -639,43 +531,134 @@ impl ObjectSubclass for AppSrc { } impl ObjectImpl for AppSrc { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "max-buffers", + "Max Buffers", + "Maximum number of buffers to queue up", + 1, + u32::MAX, + DEFAULT_MAX_BUFFERS, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boxed( + "caps", + "Caps", + "Caps to use", + gst::Caps::static_type(), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boolean( + "do-timestamp", + "Do Timestamp", + "Timestamp buffers with the current running time on arrival", + DEFAULT_DO_TIMESTAMP, + glib::ParamFlags::READWRITE, + ), + ] + }); + + PROPERTIES.as_ref() + } + fn signals() -> &'static [glib::subclass::Signal] { + static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| { + vec![ + glib::subclass::Signal::builder( + "push-buffer", + &[gst::Buffer::static_type()], + bool::static_type(), + ) + .action() + .class_handler(|_, args| { + let element = args[0] + .get::<super::AppSrc>() + .expect("signal arg") + .expect("missing signal arg"); + let buffer = args[1] + .get::<gst::Buffer>() + .expect("signal arg") + .expect("missing signal arg"); + let appsrc = AppSrc::from_instance(&element); + + Some(appsrc.push_buffer(&element, buffer).to_value()) + }) + .build(), + glib::subclass::Signal::builder("end-of-stream", &[], bool::static_type()) + .action() + .class_handler(|_, args| { + let element = args[0] + .get::<super::AppSrc>() + .expect("signal arg") + .expect("missing signal arg"); + let appsrc = AppSrc::from_instance(&element); + + Some(appsrc.end_of_stream(&element).to_value()) + }) + .build(), + ] + }); + + SIGNALS.as_ref() + } + + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { let mut settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("context", ..) => { + match pspec.get_name() { + "context" => { settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { settings.context_wait = value.get_some().expect("type checked upstream"); } - subclass::Property("caps", ..) => { + "caps" => { settings.caps = value.get().expect("type checked upstream"); } - subclass::Property("max-buffers", ..) => { + "max-buffers" => { settings.max_buffers = value.get_some().expect("type checked upstream"); } - subclass::Property("do-timestamp", ..) => { + "do-timestamp" => { settings.do_timestamp = value.get_some().expect("type checked upstream"); } _ => unimplemented!(), } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES[id]; - + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { let settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("context", ..) => settings.context.to_value(), - subclass::Property("context-wait", ..) => settings.context_wait.to_value(), - subclass::Property("caps", ..) => settings.caps.to_value(), - subclass::Property("max-buffers", ..) => settings.max_buffers.to_value(), - subclass::Property("do-timestamp", ..) => settings.do_timestamp.to_value(), + match pspec.get_name() { + "context" => settings.context.to_value(), + "context-wait" => settings.context_wait.to_value(), + "caps" => settings.caps.to_value(), + "max-buffers" => settings.max_buffers.to_value(), + "do-timestamp" => settings.do_timestamp.to_value(), _ => unimplemented!(), } } @@ -690,6 +673,36 @@ impl ObjectImpl for AppSrc { } impl ElementImpl for AppSrc { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing app source", + "Source/Generic", + "Thread-sharing app source", + "Sebastian Dröge <sebastian@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/src/inputselector/imp.rs b/generic/threadshare/src/inputselector/imp.rs index 3b03add30..36c736495 100644 --- a/generic/threadshare/src/inputselector/imp.rs +++ b/generic/threadshare/src/inputselector/imp.rs @@ -55,38 +55,6 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 3] = [ - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("active-pad", |name| { - glib::ParamSpec::object( - name, - "Active Pad", - "Currently active pad", - gst::Pad::static_type(), - glib::ParamFlags::READWRITE, - ) - }), -]; - #[derive(Debug)] struct InputSelectorPadSinkHandlerInner { segment: Option<gst::Segment>, @@ -429,42 +397,12 @@ impl ObjectSubclass for InputSelector { const NAME: &'static str = "RsTsInputSelector"; type Type = super::InputSelector; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing input selector", - "Generic", - "Simple input selector element", - "Mathieu Duponchelle <mathieu@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - - let sink_pad_template = gst::PadTemplate::new( - "sink_%u", - gst::PadDirection::Sink, - gst::PadPresence::Request, - &caps, - ) - .unwrap(); - klass.add_pad_template(sink_pad_template); - - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - - klass.install_properties(&PROPERTIES); - } - fn with_class(klass: &Self::Class) -> Self { Self { src_pad: PadSrc::new( @@ -479,22 +417,58 @@ impl ObjectSubclass for InputSelector { } impl ObjectImpl for InputSelector { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::object( + "active-pad", + "Active Pad", + "Currently active pad", + gst::Pad::static_type(), + glib::ParamFlags::READWRITE, + ), + ] + }); + + PROPERTIES.as_ref() + } - match *prop { - subclass::Property("context", ..) => { + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { + match pspec.get_name() { + "context" => { let mut settings = self.settings.lock().unwrap(); settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { let mut settings = self.settings.lock().unwrap(); settings.context_wait = value.get_some().expect("type checked upstream"); } - subclass::Property("active-pad", ..) => { + "active-pad" => { let pad = value.get::<gst::Pad>().expect("type checked upstream"); let mut state = self.state.lock().unwrap(); let pads = self.pads.lock().unwrap(); @@ -526,19 +500,17 @@ impl ObjectImpl for InputSelector { } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES[id]; - - match *prop { - subclass::Property("context", ..) => { + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + match pspec.get_name() { + "context" => { let settings = self.settings.lock().unwrap(); settings.context.to_value() } - subclass::Property("context-wait", ..) => { + "context-wait" => { let settings = self.settings.lock().unwrap(); settings.context_wait.to_value() } - subclass::Property("active-pad", ..) => { + "active-pad" => { let state = self.state.lock().unwrap(); let active_pad = state.active_sinkpad.clone(); active_pad.to_value() @@ -556,6 +528,44 @@ impl ObjectImpl for InputSelector { } impl ElementImpl for InputSelector { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing input selector", + "Generic", + "Simple input selector element", + "Mathieu Duponchelle <mathieu@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + let sink_pad_template = gst::PadTemplate::new( + "sink_%u", + gst::PadDirection::Sink, + gst::PadPresence::Request, + &caps, + ) + .unwrap(); + + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![sink_pad_template, src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/src/jitterbuffer/imp.rs b/generic/threadshare/src/jitterbuffer/imp.rs index 430f8fd35..19e376900 100644 --- a/generic/threadshare/src/jitterbuffer/imp.rs +++ b/generic/threadshare/src/jitterbuffer/imp.rs @@ -72,80 +72,6 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 7] = [ - subclass::Property("latency", |name| { - glib::ParamSpec::uint( - name, - "Buffer latency in ms", - "Amount of ms to buffer", - 0, - std::u32::MAX, - DEFAULT_LATENCY_MS, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("do-lost", |name| { - glib::ParamSpec::boolean( - name, - "Do Lost", - "Send an event downstream when a packet is lost", - DEFAULT_DO_LOST, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("max-dropout-time", |name| { - glib::ParamSpec::uint( - name, - "Max dropout time", - "The maximum time (milliseconds) of missing packets tolerated.", - 0, - std::u32::MAX, - DEFAULT_MAX_DROPOUT_TIME, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("max-misorder-time", |name| { - glib::ParamSpec::uint( - name, - "Max misorder time", - "The maximum time (milliseconds) of misordered packets tolerated.", - 0, - std::u32::MAX, - DEFAULT_MAX_MISORDER_TIME, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("stats", |name| { - glib::ParamSpec::boxed( - name, - "Statistics", - "Various statistics", - gst::Structure::static_type(), - glib::ParamFlags::READABLE, - ) - }), - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), -]; - #[derive(Eq)] struct GapPacket { buffer: gst::Buffer, @@ -1413,63 +1339,12 @@ impl ObjectSubclass for JitterBuffer { const NAME: &'static str = "RsTsJitterBuffer"; type Type = super::JitterBuffer; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing jitterbuffer", - "Generic", - "Simple jitterbuffer", - "Mathieu Duponchelle <mathieu@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - - let sink_pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(sink_pad_template); - klass.add_signal( - "request-pt-map", - glib::SignalFlags::RUN_LAST, - &[u32::static_type()], - gst::Caps::static_type(), - ); - - klass.add_signal_with_class_handler( - "clear-pt-map", - glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION, - &[], - glib::types::Type::Unit, - |_, args| { - let element = args[0] - .get::<super::JitterBuffer>() - .expect("signal arg") - .expect("missing signal arg"); - let jb = Self::from_instance(&element); - jb.clear_pt_map(&element); - None - }, - ); - - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - klass.install_properties(&PROPERTIES); - } - fn with_class(klass: &Self::Class) -> Self { let sink_pad_handler = SinkHandler::default(); let src_pad_handler = SrcHandler::default(); @@ -1493,11 +1368,102 @@ impl ObjectSubclass for JitterBuffer { } impl ObjectImpl for JitterBuffer { - fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "latency", + "Buffer latency in ms", + "Amount of ms to buffer", + 0, + std::u32::MAX, + DEFAULT_LATENCY_MS, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boolean( + "do-lost", + "Do Lost", + "Send an event downstream when a packet is lost", + DEFAULT_DO_LOST, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "max-dropout-time", + "Max dropout time", + "The maximum time (milliseconds) of missing packets tolerated.", + 0, + std::u32::MAX, + DEFAULT_MAX_DROPOUT_TIME, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "max-misorder-time", + "Max misorder time", + "The maximum time (milliseconds) of misordered packets tolerated.", + 0, + std::u32::MAX, + DEFAULT_MAX_MISORDER_TIME, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boxed( + "stats", + "Statistics", + "Various statistics", + gst::Structure::static_type(), + glib::ParamFlags::READABLE, + ), + ] + }); + + PROPERTIES.as_ref() + } + + fn signals() -> &'static [glib::subclass::Signal] { + static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| { + vec![ + glib::subclass::Signal::builder("clear-pt-map", &[], glib::types::Type::Unit) + .action() + .class_handler(|_, args| { + let element = args[0] + .get::<super::JitterBuffer>() + .expect("signal arg") + .expect("missing signal arg"); + let jb = JitterBuffer::from_instance(&element); + jb.clear_pt_map(&element); + None + }) + .build(), + ] + }); + + SIGNALS.as_ref() + } - match *prop { - subclass::Property("latency", ..) => { + fn set_property( + &self, + obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { + match pspec.get_name() { + "latency" => { let latency_ms = { let mut settings = self.settings.lock().unwrap(); settings.latency_ms = value.get_some().expect("type checked upstream"); @@ -1509,26 +1475,26 @@ impl ObjectImpl for JitterBuffer { let _ = obj.post_message(gst::message::Latency::builder().src(obj).build()); } - subclass::Property("do-lost", ..) => { + "do-lost" => { let mut settings = self.settings.lock().unwrap(); settings.do_lost = value.get_some().expect("type checked upstream"); } - subclass::Property("max-dropout-time", ..) => { + "max-dropout-time" => { let mut settings = self.settings.lock().unwrap(); settings.max_dropout_time = value.get_some().expect("type checked upstream"); } - subclass::Property("max-misorder-time", ..) => { + "max-misorder-time" => { let mut settings = self.settings.lock().unwrap(); settings.max_misorder_time = value.get_some().expect("type checked upstream"); } - subclass::Property("context", ..) => { + "context" => { let mut settings = self.settings.lock().unwrap(); settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { let mut settings = self.settings.lock().unwrap(); settings.context_wait = value.get_some().expect("type checked upstream"); } @@ -1536,27 +1502,25 @@ impl ObjectImpl for JitterBuffer { } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES[id]; - - match *prop { - subclass::Property("latency", ..) => { + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + match pspec.get_name() { + "latency" => { let settings = self.settings.lock().unwrap(); settings.latency_ms.to_value() } - subclass::Property("do-lost", ..) => { + "do-lost" => { let settings = self.settings.lock().unwrap(); settings.do_lost.to_value() } - subclass::Property("max-dropout-time", ..) => { + "max-dropout-time" => { let settings = self.settings.lock().unwrap(); settings.max_dropout_time.to_value() } - subclass::Property("max-misorder-time", ..) => { + "max-misorder-time" => { let settings = self.settings.lock().unwrap(); settings.max_misorder_time.to_value() } - subclass::Property("stats", ..) => { + "stats" => { let state = self.state.lock().unwrap(); let s = gst::Structure::new( "application/x-rtp-jitterbuffer-stats", @@ -1568,11 +1532,11 @@ impl ObjectImpl for JitterBuffer { ); s.to_value() } - subclass::Property("context", ..) => { + "context" => { let settings = self.settings.lock().unwrap(); settings.context.to_value() } - subclass::Property("context-wait", ..) => { + "context-wait" => { let settings = self.settings.lock().unwrap(); settings.context_wait.to_value() } @@ -1590,6 +1554,45 @@ impl ObjectImpl for JitterBuffer { } impl ElementImpl for JitterBuffer { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing jitterbuffer", + "Generic", + "Simple jitterbuffer", + "Mathieu Duponchelle <mathieu@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + + let sink_pad_template = gst::PadTemplate::new( + "sink", + gst::PadDirection::Sink, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![sink_pad_template, src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/src/proxy/imp.rs b/generic/threadshare/src/proxy/imp.rs index 52d408242..bc13654d4 100644 --- a/generic/threadshare/src/proxy/imp.rs +++ b/generic/threadshare/src/proxy/imp.rs @@ -93,81 +93,6 @@ impl Default for SettingsSrc { } } -static PROPERTIES_SRC: [subclass::Property; 6] = [ - subclass::Property("max-size-buffers", |name| { - glib::ParamSpec::uint( - name, - "Max Size Buffers", - "Maximum number of buffers to queue (0=unlimited)", - 0, - u32::MAX, - DEFAULT_MAX_SIZE_BUFFERS, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("max-size-bytes", |name| { - glib::ParamSpec::uint( - name, - "Max Size Bytes", - "Maximum number of bytes to queue (0=unlimited)", - 0, - u32::MAX, - DEFAULT_MAX_SIZE_BYTES, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("max-size-time", |name| { - glib::ParamSpec::uint64( - name, - "Max Size Time", - "Maximum number of nanoseconds to queue (0=unlimited)", - 0, - u64::MAX - 1, - DEFAULT_MAX_SIZE_TIME, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("proxy-context", |name| { - glib::ParamSpec::string( - name, - "Proxy Context", - "Context name of the proxy to share with", - Some(DEFAULT_PROXY_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), -]; - -static PROPERTIES_SINK: [subclass::Property; 1] = [subclass::Property("proxy-context", |name| { - glib::ParamSpec::string( - name, - "Proxy Context", - "Context name of the proxy to share with", - Some(DEFAULT_PROXY_CONTEXT), - glib::ParamFlags::READWRITE, - ) -})]; - // TODO: Refactor into a Sender and Receiver instead of the have_ booleans #[derive(Debug, Default)] @@ -650,34 +575,13 @@ impl ProxySink { impl ObjectSubclass for ProxySink { const NAME: &'static str = "RsTsProxySink"; type Type = super::ProxySink; + type Interfaces = (); type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing proxy sink", - "Sink/Generic", - "Thread-sharing proxy sink", - "Sebastian Dröge <sebastian@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - - let sink_pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(sink_pad_template); - - klass.install_properties(&PROPERTIES_SINK); - } - fn with_class(klass: &Self::Class) -> Self { Self { sink_pad: PadSink::new( @@ -691,12 +595,30 @@ impl ObjectSubclass for ProxySink { } impl ObjectImpl for ProxySink { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES_SINK[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![glib::ParamSpec::string( + "proxy-context", + "Proxy Context", + "Context name of the proxy to share with", + Some(DEFAULT_PROXY_CONTEXT), + glib::ParamFlags::READWRITE, + )] + }); + + PROPERTIES.as_ref() + } + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { let mut settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("proxy-context", ..) => { + match pspec.get_name() { + "proxy-context" => { settings.proxy_context = value .get() .expect("type checked upstream") @@ -706,12 +628,10 @@ impl ObjectImpl for ProxySink { } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES_SINK[id]; - + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { let settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("proxy-context", ..) => settings.proxy_context.to_value(), + match pspec.get_name() { + "proxy-context" => settings.proxy_context.to_value(), _ => unimplemented!(), } } @@ -726,6 +646,37 @@ impl ObjectImpl for ProxySink { } impl ElementImpl for ProxySink { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing proxy sink", + "Sink/Generic", + "Thread-sharing proxy sink", + "Sebastian Dröge <sebastian@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + + let sink_pad_template = gst::PadTemplate::new( + "sink", + gst::PadDirection::Sink, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![sink_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, @@ -1166,33 +1117,12 @@ impl ObjectSubclass for ProxySrc { const NAME: &'static str = "RsTsProxySrc"; type Type = super::ProxySrc; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing proxy source", - "Source/Generic", - "Thread-sharing proxy source", - "Sebastian Dröge <sebastian@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - - klass.install_properties(&PROPERTIES_SRC); - } - fn new() -> Self { unreachable!() } @@ -1212,30 +1142,93 @@ impl ObjectSubclass for ProxySrc { } impl ObjectImpl for ProxySrc { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES_SRC[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::string( + "proxy-context", + "Proxy Context", + "Context name of the proxy to share with", + Some(DEFAULT_PROXY_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "max-size-buffers", + "Max Size Buffers", + "Maximum number of buffers to queue (0=unlimited)", + 0, + u32::MAX, + DEFAULT_MAX_SIZE_BUFFERS, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "max-size-bytes", + "Max Size Bytes", + "Maximum number of bytes to queue (0=unlimited)", + 0, + u32::MAX, + DEFAULT_MAX_SIZE_BYTES, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint64( + "max-size-time", + "Max Size Time", + "Maximum number of nanoseconds to queue (0=unlimited)", + 0, + u64::MAX - 1, + DEFAULT_MAX_SIZE_TIME, + glib::ParamFlags::READWRITE, + ), + ] + }); + + PROPERTIES.as_ref() + } + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { let mut settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("max-size-buffers", ..) => { + match pspec.get_name() { + "max-size-buffers" => { settings.max_size_buffers = value.get_some().expect("type checked upstream"); } - subclass::Property("max-size-bytes", ..) => { + "max-size-bytes" => { settings.max_size_bytes = value.get_some().expect("type checked upstream"); } - subclass::Property("max-size-time", ..) => { + "max-size-time" => { settings.max_size_time = value.get_some().expect("type checked upstream"); } - subclass::Property("context", ..) => { + "context" => { settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { settings.context_wait = value.get_some().expect("type checked upstream"); } - subclass::Property("proxy-context", ..) => { + "proxy-context" => { settings.proxy_context = value .get() .expect("type checked upstream") @@ -1245,17 +1238,15 @@ impl ObjectImpl for ProxySrc { } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES_SRC[id]; - + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { let settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("max-size-buffers", ..) => settings.max_size_buffers.to_value(), - subclass::Property("max-size-bytes", ..) => settings.max_size_bytes.to_value(), - subclass::Property("max-size-time", ..) => settings.max_size_time.to_value(), - subclass::Property("context", ..) => settings.context.to_value(), - subclass::Property("context-wait", ..) => settings.context_wait.to_value(), - subclass::Property("proxy-context", ..) => settings.proxy_context.to_value(), + match pspec.get_name() { + "max-size-buffers" => settings.max_size_buffers.to_value(), + "max-size-bytes" => settings.max_size_bytes.to_value(), + "max-size-time" => settings.max_size_time.to_value(), + "context" => settings.context.to_value(), + "context-wait" => settings.context_wait.to_value(), + "proxy-context" => settings.proxy_context.to_value(), _ => unimplemented!(), } } @@ -1270,6 +1261,37 @@ impl ObjectImpl for ProxySrc { } impl ElementImpl for ProxySrc { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing proxy source", + "Source/Generic", + "Thread-sharing proxy source", + "Sebastian Dröge <sebastian@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/src/queue/imp.rs b/generic/threadshare/src/queue/imp.rs index 8f0d98c05..dd257cadc 100644 --- a/generic/threadshare/src/queue/imp.rs +++ b/generic/threadshare/src/queue/imp.rs @@ -65,62 +65,6 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 5] = [ - subclass::Property("max-size-buffers", |name| { - glib::ParamSpec::uint( - name, - "Max Size Buffers", - "Maximum number of buffers to queue (0=unlimited)", - 0, - u32::MAX, - DEFAULT_MAX_SIZE_BUFFERS, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("max-size-bytes", |name| { - glib::ParamSpec::uint( - name, - "Max Size Bytes", - "Maximum number of bytes to queue (0=unlimited)", - 0, - u32::MAX, - DEFAULT_MAX_SIZE_BYTES, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("max-size-time", |name| { - glib::ParamSpec::uint64( - name, - "Max Size Time", - "Maximum number of nanoseconds to queue (0=unlimited)", - 0, - u64::MAX - 1, - DEFAULT_MAX_SIZE_TIME, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), -]; - #[derive(Debug)] struct PendingQueue { more_queue_space_sender: Option<oneshot::Sender<()>>, @@ -752,42 +696,12 @@ impl ObjectSubclass for Queue { const NAME: &'static str = "RsTsQueue"; type Type = super::Queue; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing queue", - "Generic", - "Simple data queue", - "Sebastian Dröge <sebastian@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - - let sink_pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(sink_pad_template); - - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - - klass.install_properties(&PROPERTIES); - } - fn with_class(klass: &Self::Class) -> Self { Self { sink_pad: PadSink::new( @@ -808,43 +722,97 @@ impl ObjectSubclass for Queue { } impl ObjectImpl for Queue { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "max-size-buffers", + "Max Size Buffers", + "Maximum number of buffers to queue (0=unlimited)", + 0, + u32::MAX, + DEFAULT_MAX_SIZE_BUFFERS, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "max-size-bytes", + "Max Size Bytes", + "Maximum number of bytes to queue (0=unlimited)", + 0, + u32::MAX, + DEFAULT_MAX_SIZE_BYTES, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint64( + "max-size-time", + "Max Size Time", + "Maximum number of nanoseconds to queue (0=unlimited)", + 0, + u64::MAX - 1, + DEFAULT_MAX_SIZE_TIME, + glib::ParamFlags::READWRITE, + ), + ] + }); + + PROPERTIES.as_ref() + } + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { let mut settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("max-size-buffers", ..) => { + match pspec.get_name() { + "max-size-buffers" => { settings.max_size_buffers = value.get_some().expect("type checked upstream"); } - subclass::Property("max-size-bytes", ..) => { + "max-size-bytes" => { settings.max_size_bytes = value.get_some().expect("type checked upstream"); } - subclass::Property("max-size-time", ..) => { + "max-size-time" => { settings.max_size_time = value.get_some().expect("type checked upstream"); } - subclass::Property("context", ..) => { + "context" => { settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { settings.context_wait = value.get_some().expect("type checked upstream"); } _ => unimplemented!(), } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES[id]; - + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { let settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("max-size-buffers", ..) => settings.max_size_buffers.to_value(), - subclass::Property("max-size-bytes", ..) => settings.max_size_bytes.to_value(), - subclass::Property("max-size-time", ..) => settings.max_size_time.to_value(), - subclass::Property("context", ..) => settings.context.to_value(), - subclass::Property("context-wait", ..) => settings.context_wait.to_value(), + match pspec.get_name() { + "max-size-buffers" => settings.max_size_buffers.to_value(), + "max-size-bytes" => settings.max_size_bytes.to_value(), + "max-size-time" => settings.max_size_time.to_value(), + "context" => settings.context.to_value(), + "context-wait" => settings.context_wait.to_value(), _ => unimplemented!(), } } @@ -858,6 +826,45 @@ impl ObjectImpl for Queue { } impl ElementImpl for Queue { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing queue", + "Generic", + "Simple data queue", + "Sebastian Dröge <sebastian@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + + let sink_pad_template = gst::PadTemplate::new( + "sink", + gst::PadDirection::Sink, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![sink_pad_template, src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/src/tcpclientsrc/imp.rs b/generic/threadshare/src/tcpclientsrc/imp.rs index afd23423b..4b584b07e 100644 --- a/generic/threadshare/src/tcpclientsrc/imp.rs +++ b/generic/threadshare/src/tcpclientsrc/imp.rs @@ -75,69 +75,6 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 6] = [ - subclass::Property("host", |name| { - glib::ParamSpec::string( - name, - "Host", - "The host IP address to receive packets from", - DEFAULT_HOST, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("port", |name| { - glib::ParamSpec::int( - name, - "Port", - "Port to receive packets from", - 0, - u16::MAX as i32, - DEFAULT_PORT, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("caps", |name| { - glib::ParamSpec::boxed( - name, - "Caps", - "Caps to use", - gst::Caps::static_type(), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("blocksize", |name| { - glib::ParamSpec::uint( - name, - "Blocksize", - "Size in bytes to read per buffer (-1 = default)", - 0, - u32::MAX, - DEFAULT_BLOCKSIZE, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), -]; - struct TcpClientReader(tokio::net::TcpStream); impl TcpClientReader { @@ -612,32 +549,12 @@ impl ObjectSubclass for TcpClientSrc { const NAME: &'static str = "RsTsTcpClientSrc"; type Type = super::TcpClientSrc; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing TCP client source", - "Source/Network", - "Receives data over the network via TCP", - "Sebastian Dröge <sebastian@centricular.com>, LEE Dongjun <redongjun@gmail.com>", - ); - - let caps = gst::Caps::new_any(); - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - - klass.install_properties(&PROPERTIES); - } - fn with_class(klass: &Self::Class) -> Self { let src_pad_handler = TcpClientSrcPadHandler::default(); @@ -654,47 +571,106 @@ impl ObjectSubclass for TcpClientSrc { } impl ObjectImpl for TcpClientSrc { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::string( + "host", + "Host", + "The host IP address to receive packets from", + DEFAULT_HOST, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::int( + "port", + "Port", + "Port to receive packets from", + 0, + u16::MAX as i32, + DEFAULT_PORT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boxed( + "caps", + "Caps", + "Caps to use", + gst::Caps::static_type(), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "blocksize", + "Blocksize", + "Size in bytes to read per buffer (-1 = default)", + 0, + u32::MAX, + DEFAULT_BLOCKSIZE, + glib::ParamFlags::READWRITE, + ), + ] + }); + + PROPERTIES.as_ref() + } + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { let mut settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("host", ..) => { + match pspec.get_name() { + "host" => { settings.host = value.get().expect("type checked upstream"); } - subclass::Property("port", ..) => { + "port" => { settings.port = value.get_some().expect("type checked upstream"); } - subclass::Property("caps", ..) => { + "caps" => { settings.caps = value.get().expect("type checked upstream"); } - subclass::Property("blocksize", ..) => { + "blocksize" => { settings.blocksize = value.get_some().expect("type checked upstream"); } - subclass::Property("context", ..) => { + "context" => { settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { settings.context_wait = value.get_some().expect("type checked upstream"); } _ => unimplemented!(), } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES[id]; - + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { let settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("host", ..) => settings.host.to_value(), - subclass::Property("port", ..) => settings.port.to_value(), - subclass::Property("caps", ..) => settings.caps.to_value(), - subclass::Property("blocksize", ..) => settings.blocksize.to_value(), - subclass::Property("context", ..) => settings.context.to_value(), - subclass::Property("context-wait", ..) => settings.context_wait.to_value(), + match pspec.get_name() { + "host" => settings.host.to_value(), + "port" => settings.port.to_value(), + "caps" => settings.caps.to_value(), + "blocksize" => settings.blocksize.to_value(), + "context" => settings.context.to_value(), + "context-wait" => settings.context_wait.to_value(), _ => unimplemented!(), } } @@ -709,6 +685,36 @@ impl ObjectImpl for TcpClientSrc { } impl ElementImpl for TcpClientSrc { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing TCP client source", + "Source/Network", + "Receives data over the network via TCP", + "Sebastian Dröge <sebastian@centricular.com>, LEE Dongjun <redongjun@gmail.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/src/udpsink/imp.rs b/generic/threadshare/src/udpsink/imp.rs index bd991bbc1..8b44588c1 100644 --- a/generic/threadshare/src/udpsink/imp.rs +++ b/generic/threadshare/src/udpsink/imp.rs @@ -118,174 +118,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { ) }); -static PROPERTIES: [subclass::Property; 17] = [ - subclass::Property("sync", |name| { - glib::ParamSpec::boolean( - name, - "Sync", - "Sync on the clock", - DEFAULT_SYNC, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("bind-address", |name| { - glib::ParamSpec::string( - name, - "Bind Address", - "Address to bind the socket to", - Some(DEFAULT_BIND_ADDRESS), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("bind-port", |name| { - glib::ParamSpec::int( - name, - "Bind Port", - "Port to bind the socket to", - 0, - u16::MAX as i32, - DEFAULT_BIND_PORT, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("bind-address-v6", |name| { - glib::ParamSpec::string( - name, - "Bind Address V6", - "Address to bind the V6 socket to", - Some(DEFAULT_BIND_ADDRESS_V6), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("bind-port-v6", |name| { - glib::ParamSpec::int( - name, - "Bind Port", - "Port to bind the V6 socket to", - 0, - u16::MAX as i32, - DEFAULT_BIND_PORT_V6, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("socket", |name| { - glib::ParamSpec::object( - name, - "Socket", - "Socket to use for UDP transmission. (None == allocate)", - gio::Socket::static_type(), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("used-socket", |name| { - glib::ParamSpec::object( - name, - "Used Socket", - "Socket currently in use for UDP transmission. (None = no socket)", - gio::Socket::static_type(), - glib::ParamFlags::READABLE, - ) - }), - subclass::Property("socket-v6", |name| { - glib::ParamSpec::object( - name, - "Socket V6", - "IPV6 Socket to use for UDP transmission. (None == allocate)", - gio::Socket::static_type(), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("used-socket-v6", |name| { - glib::ParamSpec::object( - name, - "Used Socket V6", - "V6 Socket currently in use for UDP transmission. (None = no socket)", - gio::Socket::static_type(), - glib::ParamFlags::READABLE, - ) - }), - subclass::Property("auto-multicast", |name| { - glib::ParamSpec::boolean( - name, - "Auto multicast", - "Automatically join/leave the multicast groups, FALSE means user has to do it himself", - DEFAULT_AUTO_MULTICAST, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("loop", |name| { - glib::ParamSpec::boolean( - name, - "Loop", - "Set the multicast loop parameter.", - DEFAULT_LOOP, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("ttl", |name| { - glib::ParamSpec::uint( - name, - "Time To Live", - "Used for setting the unicast TTL parameter", - 0, - u8::MAX as u32, - DEFAULT_TTL, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("ttl-mc", |name| { - glib::ParamSpec::uint( - name, - "Time To Live Multicast", - "Used for setting the multicast TTL parameter", - 0, - u8::MAX as u32, - DEFAULT_TTL_MC, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("qos-dscp", |name| { - glib::ParamSpec::int( - name, - "QoS DSCP", - "Quality of Service, differentiated services code point (-1 default)", - -1, - 63, - DEFAULT_QOS_DSCP, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("clients", |name| { - glib::ParamSpec::string( - name, - "Clients", - "A comma separated list of host:port pairs with destinations", - Some(DEFAULT_CLIENTS), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), -]; - #[derive(Debug)] enum TaskItem { Buffer(gst::Buffer), @@ -1127,107 +959,12 @@ impl ObjectSubclass for UdpSink { const NAME: &'static str = "RsTsUdpSink"; type Type = super::UdpSink; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing UDP sink", - "Sink/Network", - "Thread-sharing UDP sink", - "Mathieu <mathieu@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - - let sink_pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(sink_pad_template); - klass.add_signal_with_class_handler( - "add", - glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION, - &[String::static_type(), i32::static_type()], - glib::types::Type::Unit, - |_, args| { - let element = args[0] - .get::<super::UdpSink>() - .expect("signal arg") - .expect("missing signal arg"); - let host = args[1] - .get::<String>() - .expect("signal arg") - .expect("missing signal arg"); - let port = args[2] - .get::<i32>() - .expect("signal arg") - .expect("missing signal arg"); - - if let Ok(addr) = try_into_socket_addr(&element, &host, port) { - let udpsink = Self::from_instance(&element); - udpsink.add_client(addr); - } - - None - }, - ); - - klass.add_signal_with_class_handler( - "remove", - glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION, - &[String::static_type(), i32::static_type()], - glib::types::Type::Unit, - |_, args| { - let element = args[0] - .get::<super::UdpSink>() - .expect("signal arg") - .expect("missing signal arg"); - let host = args[1] - .get::<String>() - .expect("signal arg") - .expect("missing signal arg"); - let port = args[2] - .get::<i32>() - .expect("signal arg") - .expect("missing signal arg"); - - let udpsink = Self::from_instance(&element); - - if let Ok(addr) = try_into_socket_addr(&element, &host, port) { - udpsink.remove_client(addr); - } - - None - }, - ); - - klass.add_signal_with_class_handler( - "clear", - glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION, - &[], - glib::types::Type::Unit, - |_, args| { - let element = args[0] - .get::<super::UdpSink>() - .expect("signal arg") - .expect("missing signal arg"); - - let udpsink = Self::from_instance(&element); - udpsink.clear_clients(std::iter::empty()); - - None - }, - ); - - klass.install_properties(&PROPERTIES); - } - fn with_class(klass: &Self::Class) -> Self { let settings = Arc::new(StdMutex::new(Settings::default())); let sink_pad_handler = UdpSinkPadHandler::new(Arc::clone(&settings)); @@ -1245,66 +982,289 @@ impl ObjectSubclass for UdpSink { } impl ObjectImpl for UdpSink { - fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boolean( + "sync", + "Sync", + "Sync on the clock", + DEFAULT_SYNC, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::string( + "bind-address", + "Bind Address", + "Address to bind the socket to", + Some(DEFAULT_BIND_ADDRESS), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::int( + "bind-port", + "Bind Port", + "Port to bind the socket to", + 0, + u16::MAX as i32, + DEFAULT_BIND_PORT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::string( + "bind-address-v6", + "Bind Address V6", + "Address to bind the V6 socket to", + Some(DEFAULT_BIND_ADDRESS_V6), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::int( + "bind-port-v6", + "Bind Port", + "Port to bind the V6 socket to", + 0, + u16::MAX as i32, + DEFAULT_BIND_PORT_V6, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::object( + "socket", + "Socket", + "Socket to use for UDP transmission. (None == allocate)", + gio::Socket::static_type(), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::object( + "used-socket", + "Used Socket", + "Socket currently in use for UDP transmission. (None = no socket)", + gio::Socket::static_type(), + glib::ParamFlags::READABLE, + ), + glib::ParamSpec::object( + "socket-v6", + "Socket V6", + "IPV6 Socket to use for UDP transmission. (None == allocate)", + gio::Socket::static_type(), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::object( + "used-socket-v6", + "Used Socket V6", + "V6 Socket currently in use for UDP transmission. (None = no socket)", + gio::Socket::static_type(), + glib::ParamFlags::READABLE, + ), + glib::ParamSpec::boolean( + "auto-multicast", + "Auto multicast", + "Automatically join/leave the multicast groups, FALSE means user has to do it himself", + DEFAULT_AUTO_MULTICAST, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boolean( + "loop", + "Loop", + "Set the multicast loop parameter.", + DEFAULT_LOOP, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "ttl", + "Time To Live", + "Used for setting the unicast TTL parameter", + 0, + u8::MAX as u32, + DEFAULT_TTL, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "ttl-mc", + "Time To Live Multicast", + "Used for setting the multicast TTL parameter", + 0, + u8::MAX as u32, + DEFAULT_TTL_MC, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::int( + "qos-dscp", + "QoS DSCP", + "Quality of Service, differentiated services code point (-1 default)", + -1, + 63, + DEFAULT_QOS_DSCP, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::string( + "clients", + "Clients", + "A comma separated list of host:port pairs with destinations", + Some(DEFAULT_CLIENTS), + glib::ParamFlags::READWRITE, + ), + ] + }); + + PROPERTIES.as_ref() + } + + fn signals() -> &'static [glib::subclass::Signal] { + static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| { + vec![ + glib::subclass::Signal::builder( + "add", + &[String::static_type(), i32::static_type()], + glib::types::Type::Unit, + ) + .action() + .class_handler(|_, args| { + let element = args[0] + .get::<super::UdpSink>() + .expect("signal arg") + .expect("missing signal arg"); + let host = args[1] + .get::<String>() + .expect("signal arg") + .expect("missing signal arg"); + let port = args[2] + .get::<i32>() + .expect("signal arg") + .expect("missing signal arg"); + + if let Ok(addr) = try_into_socket_addr(&element, &host, port) { + let udpsink = UdpSink::from_instance(&element); + udpsink.add_client(addr); + } + + None + }) + .build(), + glib::subclass::Signal::builder( + "remove", + &[String::static_type(), i32::static_type()], + glib::types::Type::Unit, + ) + .action() + .class_handler(|_, args| { + let element = args[0] + .get::<super::UdpSink>() + .expect("signal arg") + .expect("missing signal arg"); + let host = args[1] + .get::<String>() + .expect("signal arg") + .expect("missing signal arg"); + let port = args[2] + .get::<i32>() + .expect("signal arg") + .expect("missing signal arg"); + + if let Ok(addr) = try_into_socket_addr(&element, &host, port) { + let udpsink = UdpSink::from_instance(&element); + udpsink.remove_client(addr); + } + + None + }) + .build(), + glib::subclass::Signal::builder("clear", &[], glib::types::Type::Unit) + .action() + .class_handler(|_, args| { + let element = args[0] + .get::<super::UdpSink>() + .expect("signal arg") + .expect("missing signal arg"); + + let udpsink = UdpSink::from_instance(&element); + udpsink.clear_clients(std::iter::empty()); + + None + }) + .build(), + ] + }); + SIGNALS.as_ref() + } + + fn set_property( + &self, + obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { let mut settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("sync", ..) => { + match pspec.get_name() { + "sync" => { settings.sync = value.get_some().expect("type checked upstream"); } - subclass::Property("bind-address", ..) => { + "bind-address" => { settings.bind_address = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("bind-port", ..) => { + "bind-port" => { settings.bind_port = value.get_some().expect("type checked upstream"); } - subclass::Property("bind-address-v6", ..) => { + "bind-address-v6" => { settings.bind_address_v6 = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("bind-port-v6", ..) => { + "bind-port-v6" => { settings.bind_port_v6 = value.get_some().expect("type checked upstream"); } - subclass::Property("socket", ..) => { + "socket" => { settings.socket = value .get::<gio::Socket>() .expect("type checked upstream") .map(|socket| GioSocketWrapper::new(&socket)); } - subclass::Property("used-socket", ..) => { + "used-socket" => { unreachable!(); } - subclass::Property("socket-v6", ..) => { + "socket-v6" => { settings.socket_v6 = value .get::<gio::Socket>() .expect("type checked upstream") .map(|socket| GioSocketWrapper::new(&socket)); } - subclass::Property("used-socket-v6", ..) => { + "used-socket-v6" => { unreachable!(); } - subclass::Property("auto-multicast", ..) => { + "auto-multicast" => { settings.auto_multicast = value.get_some().expect("type checked upstream"); } - subclass::Property("loop", ..) => { + "loop" => { settings.multicast_loop = value.get_some().expect("type checked upstream"); } - subclass::Property("ttl", ..) => { + "ttl" => { settings.ttl = value.get_some().expect("type checked upstream"); } - subclass::Property("ttl-mc", ..) => { + "ttl-mc" => { settings.ttl_mc = value.get_some().expect("type checked upstream"); } - subclass::Property("qos-dscp", ..) => { + "qos-dscp" => { settings.qos_dscp = value.get_some().expect("type checked upstream"); } - subclass::Property("clients", ..) => { + "clients" => { let clients: String = value .get() .expect("type checked upstream") @@ -1329,55 +1289,53 @@ impl ObjectImpl for UdpSink { self.clear_clients(clients_iter); } - subclass::Property("context", ..) => { + "context" => { settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { settings.context_wait = value.get_some().expect("type checked upstream"); } _ => unimplemented!(), } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES[id]; - + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { let settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("sync", ..) => settings.sync.to_value(), - subclass::Property("bind-address", ..) => settings.bind_address.to_value(), - subclass::Property("bind-port", ..) => settings.bind_port.to_value(), - subclass::Property("bind-address-v6", ..) => settings.bind_address_v6.to_value(), - subclass::Property("bind-port-v6", ..) => settings.bind_port_v6.to_value(), - subclass::Property("socket", ..) => settings + match pspec.get_name() { + "sync" => settings.sync.to_value(), + "bind-address" => settings.bind_address.to_value(), + "bind-port" => settings.bind_port.to_value(), + "bind-address-v6" => settings.bind_address_v6.to_value(), + "bind-port-v6" => settings.bind_port_v6.to_value(), + "socket" => settings .socket .as_ref() .map(GioSocketWrapper::as_socket) .to_value(), - subclass::Property("used-socket", ..) => settings + "used-socket" => settings .used_socket .as_ref() .map(GioSocketWrapper::as_socket) .to_value(), - subclass::Property("socket-v6", ..) => settings + "socket-v6" => settings .socket_v6 .as_ref() .map(GioSocketWrapper::as_socket) .to_value(), - subclass::Property("used-socket-v6", ..) => settings + "used-socket-v6" => settings .used_socket_v6 .as_ref() .map(GioSocketWrapper::as_socket) .to_value(), - subclass::Property("auto-multicast", ..) => settings.sync.to_value(), - subclass::Property("loop", ..) => settings.multicast_loop.to_value(), - subclass::Property("ttl", ..) => settings.ttl.to_value(), - subclass::Property("ttl-mc", ..) => settings.ttl_mc.to_value(), - subclass::Property("qos-dscp", ..) => settings.qos_dscp.to_value(), - subclass::Property("clients", ..) => { + "auto-multicast" => settings.sync.to_value(), + "loop" => settings.multicast_loop.to_value(), + "ttl" => settings.ttl.to_value(), + "ttl-mc" => settings.ttl_mc.to_value(), + "qos-dscp" => settings.qos_dscp.to_value(), + "clients" => { drop(settings); let clients: Vec<String> = self @@ -1389,8 +1347,8 @@ impl ObjectImpl for UdpSink { clients.join(",").to_value() } - subclass::Property("context", ..) => settings.context.to_value(), - subclass::Property("context-wait", ..) => settings.context_wait.to_value(), + "context" => settings.context.to_value(), + "context-wait" => settings.context_wait.to_value(), _ => unimplemented!(), } } @@ -1405,6 +1363,37 @@ impl ObjectImpl for UdpSink { } impl ElementImpl for UdpSink { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing UDP sink", + "Sink/Network", + "Thread-sharing UDP sink", + "Mathieu <mathieu@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + + let sink_pad_template = gst::PadTemplate::new( + "sink", + gst::PadDirection::Sink, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![sink_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/src/udpsrc/imp.rs b/generic/threadshare/src/udpsrc/imp.rs index 1d42561c9..b8d92e143 100644 --- a/generic/threadshare/src/udpsrc/imp.rs +++ b/generic/threadshare/src/udpsrc/imp.rs @@ -84,105 +84,6 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 10] = [ - subclass::Property("address", |name| { - glib::ParamSpec::string( - name, - "Address", - "Address/multicast group to listen on", - DEFAULT_ADDRESS, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("port", |name| { - glib::ParamSpec::int( - name, - "Port", - "Port to listen on", - 0, - u16::MAX as i32, - DEFAULT_PORT, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("reuse", |name| { - glib::ParamSpec::boolean( - name, - "Reuse", - "Allow reuse of the port", - DEFAULT_REUSE, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("caps", |name| { - glib::ParamSpec::boxed( - name, - "Caps", - "Caps to use", - gst::Caps::static_type(), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("mtu", |name| { - glib::ParamSpec::uint( - name, - "MTU", - "Maximum expected packet size. This directly defines the allocation size of the receive buffer pool", - 0, - i32::MAX as u32, - DEFAULT_MTU, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("socket", |name| { - glib::ParamSpec::object( - name, - "Socket", - "Socket to use for UDP reception. (None == allocate)", - gio::Socket::static_type(), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("used-socket", |name| { - glib::ParamSpec::object( - name, - "Used Socket", - "Socket currently in use for UDP reception. (None = no socket)", - gio::Socket::static_type(), - glib::ParamFlags::READABLE, - ) - }), - subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("context-wait", |name| { - glib::ParamSpec::uint( - name, - "Context Wait", - "Throttle poll loop to run at most once every this many ms", - 0, - 1000, - DEFAULT_CONTEXT_WAIT, - glib::ParamFlags::READWRITE, - ) - }), - subclass::Property("retrieve-sender-address", |name| { - glib::ParamSpec::boolean( - name, - "Retrieve sender address", - "Whether to retrieve the sender address and add it to buffers as meta. Disabling this might result in minor performance improvements in certain scenarios", - DEFAULT_RETRIEVE_SENDER_ADDRESS, - glib::ParamFlags::READWRITE, - ) - }), -]; - #[derive(Debug)] struct UdpReader(tokio::net::UdpSocket); @@ -789,48 +690,12 @@ impl ObjectSubclass for UdpSrc { const NAME: &'static str = "RsTsUdpSrc"; type Type = super::UdpSrc; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing UDP source", - "Source/Network", - "Receives data over the network via UDP", - "Sebastian Dröge <sebastian@centricular.com>", - ); - - let caps = gst::Caps::new_any(); - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - - #[cfg(not(windows))] - { - klass.install_properties(&PROPERTIES); - } - #[cfg(windows)] - { - let properties = PROPERTIES - .iter() - .filter(|p| match *p { - subclass::Property("socket", ..) | subclass::Property("used-socket", ..) => { - false - } - _ => true, - }) - .collect::<Vec<_>>(); - klass.install_properties(properties.as_slice()); - } - } - fn with_class(klass: &Self::Class) -> Self { let src_pad_handler = UdpSrcPadHandler::default(); @@ -847,76 +712,167 @@ impl ObjectSubclass for UdpSrc { } impl ObjectImpl for UdpSrc { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + let mut properties = vec![ + glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "context-wait", + "Context Wait", + "Throttle poll loop to run at most once every this many ms", + 0, + 1000, + DEFAULT_CONTEXT_WAIT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::string( + "address", + "Address", + "Address/multicast group to listen on", + DEFAULT_ADDRESS, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::int( + "port", + "Port", + "Port to listen on", + 0, + u16::MAX as i32, + DEFAULT_PORT, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boolean( + "reuse", + "Reuse", + "Allow reuse of the port", + DEFAULT_REUSE, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boxed( + "caps", + "Caps", + "Caps to use", + gst::Caps::static_type(), + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::uint( + "mtu", + "MTU", + "Maximum expected packet size. This directly defines the allocation size of the receive buffer pool", + 0, + i32::MAX as u32, + DEFAULT_MTU, + glib::ParamFlags::READWRITE, + ), + glib::ParamSpec::boolean( + "retrieve-sender-address", + "Retrieve sender address", + "Whether to retrieve the sender address and add it to buffers as meta. Disabling this might result in minor performance improvements in certain scenarios", + DEFAULT_RETRIEVE_SENDER_ADDRESS, + glib::ParamFlags::READWRITE, + ), + ]; + + #[cfg(not(windows))] + { + properties.push(glib::ParamSpec::object( + "socket", + "Socket", + "Socket to use for UDP reception. (None == allocate)", + gio::Socket::static_type(), + glib::ParamFlags::READWRITE, + )); + properties.push(glib::ParamSpec::object( + "used-socket", + "Used Socket", + "Socket currently in use for UDP reception. (None = no socket)", + gio::Socket::static_type(), + glib::ParamFlags::READABLE, + )); + } + properties + }); + + PROPERTIES.as_ref() + } + + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { let mut settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("address", ..) => { + match pspec.get_name() { + "address" => { settings.address = value.get().expect("type checked upstream"); } - subclass::Property("port", ..) => { + "port" => { settings.port = value.get_some().expect("type checked upstream"); } - subclass::Property("reuse", ..) => { + "reuse" => { settings.reuse = value.get_some().expect("type checked upstream"); } - subclass::Property("caps", ..) => { + "caps" => { settings.caps = value.get().expect("type checked upstream"); } - subclass::Property("mtu", ..) => { + "mtu" => { settings.mtu = value.get_some().expect("type checked upstream"); } - subclass::Property("socket", ..) => { + "socket" => { settings.socket = value .get::<gio::Socket>() .expect("type checked upstream") .map(|socket| GioSocketWrapper::new(&socket)); } - subclass::Property("used-socket", ..) => { + "used-socket" => { unreachable!(); } - subclass::Property("context", ..) => { + "context" => { settings.context = value .get() .expect("type checked upstream") .unwrap_or_else(|| "".into()); } - subclass::Property("context-wait", ..) => { + "context-wait" => { settings.context_wait = value.get_some().expect("type checked upstream"); } - subclass::Property("retrieve-sender-address", ..) => { + "retrieve-sender-address" => { settings.retrieve_sender_address = value.get_some().expect("type checked upstream"); } _ => unimplemented!(), } } - fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value { - let prop = &PROPERTIES[id]; - + fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { let settings = self.settings.lock().unwrap(); - match *prop { - subclass::Property("address", ..) => settings.address.to_value(), - subclass::Property("port", ..) => settings.port.to_value(), - subclass::Property("reuse", ..) => settings.reuse.to_value(), - subclass::Property("caps", ..) => settings.caps.to_value(), - subclass::Property("mtu", ..) => settings.mtu.to_value(), - subclass::Property("socket", ..) => settings + match pspec.get_name() { + "address" => settings.address.to_value(), + "port" => settings.port.to_value(), + "reuse" => settings.reuse.to_value(), + "caps" => settings.caps.to_value(), + "mtu" => settings.mtu.to_value(), + "socket" => settings .socket .as_ref() .map(GioSocketWrapper::as_socket) .to_value(), - subclass::Property("used-socket", ..) => settings + "used-socket" => settings .used_socket .as_ref() .map(GioSocketWrapper::as_socket) .to_value(), - subclass::Property("context", ..) => settings.context.to_value(), - subclass::Property("context-wait", ..) => settings.context_wait.to_value(), - subclass::Property("retrieve-sender-address", ..) => { - settings.retrieve_sender_address.to_value() - } + "context" => settings.context.to_value(), + "context-wait" => settings.context_wait.to_value(), + "retrieve-sender-address" => settings.retrieve_sender_address.to_value(), _ => unimplemented!(), } } @@ -931,6 +887,36 @@ impl ObjectImpl for UdpSrc { } impl ElementImpl for UdpSrc { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing UDP source", + "Source/Network", + "Receives data over the network via UDP", + "Sebastian Dröge <sebastian@centricular.com>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, diff --git a/generic/threadshare/tests/pad.rs b/generic/threadshare/tests/pad.rs index ee8bc2457..e7d8bb960 100644 --- a/generic/threadshare/tests/pad.rs +++ b/generic/threadshare/tests/pad.rs @@ -69,17 +69,6 @@ struct ItemSender { mod imp_src { use super::*; - static SRC_PROPERTIES: [glib::subclass::Property; 1] = - [glib::subclass::Property("context", |name| { - glib::ParamSpec::string( - name, - "Context", - "Context name to share threads with", - Some(DEFAULT_CONTEXT), - glib::ParamFlags::READWRITE, - ) - })]; - #[derive(Clone, Debug, Default)] struct Settings { context: String, @@ -316,32 +305,12 @@ mod imp_src { const NAME: &'static str = "TsElementSrcTest"; type Type = super::ElementSrcTest; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = glib::subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing Test Src Element", - "Generic", - "Src Element for Pad Src Test", - "François Laignel <fengalin@free.fr>", - ); - - let caps = gst::Caps::new_any(); - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(src_pad_template); - - klass.install_properties(&SRC_PROPERTIES); - } - fn with_class(klass: &Self::Class) -> Self { ElementSrcTest { src_pad: PadSrc::new( @@ -356,11 +325,29 @@ mod imp_src { } impl ObjectImpl for ElementSrcTest { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &SRC_PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![glib::ParamSpec::string( + "context", + "Context", + "Context name to share threads with", + Some(DEFAULT_CONTEXT), + glib::ParamFlags::WRITABLE, + )] + }); + + PROPERTIES.as_ref() + } - match *prop { - glib::subclass::Property("context", ..) => { + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { + match pspec.get_name() { + "context" => { let context = value .get() .expect("type checked upstream") @@ -380,6 +367,36 @@ mod imp_src { } impl ElementImpl for ElementSrcTest { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing Test Src Element", + "Generic", + "Src Element for Pad Src Test", + "François Laignel <fengalin@free.fr>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![src_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, @@ -452,17 +469,6 @@ unsafe impl Sync for ElementSrcTest {} mod imp_sink { use super::*; - static SINK_PROPERTIES: [glib::subclass::Property; 1] = - [glib::subclass::Property("sender", |name| { - glib::ParamSpec::boxed( - name, - "Sender", - "Channel sender to forward the incoming items to", - ItemSender::get_type(), - glib::ParamFlags::WRITABLE, - ) - })]; - #[derive(Clone, Debug, Default)] struct PadSinkTestHandler; @@ -634,32 +640,12 @@ mod imp_sink { const NAME: &'static str = "TsElementSinkTest"; type Type = super::ElementSinkTest; type ParentType = gst::Element; + type Interfaces = (); type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = glib::subclass::simple::ClassStruct<Self>; glib::object_subclass!(); - fn class_init(klass: &mut Self::Class) { - klass.set_metadata( - "Thread-sharing Test Sink Element", - "Generic", - "Sink Element for Pad Test", - "François Laignel <fengalin@free.fr>", - ); - - let caps = gst::Caps::new_any(); - let sink_pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - klass.add_pad_template(sink_pad_template); - - klass.install_properties(&SINK_PROPERTIES); - } - fn with_class(klass: &Self::Class) -> Self { ElementSinkTest { sink_pad: PadSink::new( @@ -673,11 +659,29 @@ mod imp_sink { } impl ObjectImpl for ElementSinkTest { - fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { - let prop = &SINK_PROPERTIES[id]; + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { + vec![glib::ParamSpec::boxed( + "sender", + "Sender", + "Channel sender to forward the incoming items to", + ItemSender::get_type(), + glib::ParamFlags::WRITABLE, + )] + }); + + PROPERTIES.as_ref() + } - match *prop { - glib::subclass::Property("sender", ..) => { + fn set_property( + &self, + _obj: &Self::Type, + _id: usize, + value: &glib::Value, + pspec: &glib::ParamSpec, + ) { + match pspec.get_name() { + "sender" => { let ItemSender { sender } = value .get::<&ItemSender>() .expect("type checked upstream") @@ -697,6 +701,36 @@ mod imp_sink { } impl ElementImpl for ElementSinkTest { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "Thread-sharing Test Sink Element", + "Generic", + "Sink Element for Pad Test", + "François Laignel <fengalin@free.fr>", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| { + let caps = gst::Caps::new_any(); + let sink_pad_template = gst::PadTemplate::new( + "sink", + gst::PadDirection::Sink, + gst::PadPresence::Always, + &caps, + ) + .unwrap(); + + vec![sink_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + fn change_state( &self, element: &Self::Type, |