diff --git a/net/webrtc/src/signaller/iface.rs b/net/webrtc/src/signaller/iface.rs index 177d15f7..0abd1ea8 100644 --- a/net/webrtc/src/signaller/iface.rs +++ b/net/webrtc/src/signaller/iface.rs @@ -51,6 +51,19 @@ unsafe impl prelude::ObjectInterface for Signallable { self.end_session = Signallable::end_session; } + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy> = Lazy::new(|| { + vec![glib::ParamSpecBoolean::builder("manual-sdp-munging") + .nick("Manual SDP munging") + .blurb("Whether the signaller manages SDP munging itself") + .default_value(false) + .read_only() + .build()] + }); + + PROPERTIES.as_ref() + } + fn signals() -> &'static [Signal] { static SIGNALS: Lazy> = Lazy::new(|| { vec![ @@ -302,6 +315,46 @@ unsafe impl prelude::ObjectInterface for Signallable { Signal::builder("consumer-removed") .param_types([String::static_type(), gst::Element::static_type()]) .build(), + /** + * GstRSWebRTCSignallableIface::munge-session-description: + * @self: The object implementing #GstRSWebRTCSignallableIface + * @session_id: Id of the session being described + * @description: The WebRTC session description to modify + * + * For special-case handling, a callback can be registered to modify the session + * description before the signaller sends it to the peer. + * + * Return: A modified session description + */ + Signal::builder("munge-session-description") + .run_last() + .param_types([ + str::static_type(), + gst_webrtc::WebRTCSessionDescription::static_type(), + ]) + .return_type::() + .class_handler(|_tokens, args| { + let _ = args[0usize] + .get::<&super::Signallable>() + .unwrap_or_else(|e| { + panic!("Wrong type for argument {}: {:?}", 0usize, e) + }); + let _ = args[1usize].get::<&str>().unwrap_or_else(|e| { + panic!("Wrong type for argument {}: {:?}", 1usize, e) + }); + let desc = args[2usize] + .get::<&gst_webrtc::WebRTCSessionDescription>() + .unwrap_or_else(|e| { + panic!("Wrong type for argument {}: {:?}", 2usize, e) + }); + + Some(desc.clone().into()) + }) + .accumulator(move |_hint, output, input| { + *output = input.clone(); + false + }) + .build(), /** * GstRSWebRTCSignallableIface::send-session-description: * @self: The object implementing #GstRSWebRTCSignallableIface @@ -435,18 +488,6 @@ where } iface.stop = vstop_trampoline::; - fn send_sdp_trampoline( - this: &super::Signallable, - session_id: &str, - sdp: &gst_webrtc::WebRTCSessionDescription, - ) { - let this = this - .dynamic_cast_ref::<::Type>() - .unwrap(); - SignallableImpl::send_sdp(this.imp(), session_id, sdp) - } - iface.send_sdp = send_sdp_trampoline::; - fn add_ice_trampoline( this: &super::Signallable, session_id: &str, @@ -492,6 +533,11 @@ pub trait SignallableImpl: object::ObjectImpl + Send + Sync + 'static { pub trait SignallableExt: 'static { fn start(&self); fn stop(&self); + fn munge_sdp( + &self, + session_id: &str, + sdp: &gst_webrtc::WebRTCSessionDescription, + ) -> gst_webrtc::WebRTCSessionDescription; fn send_sdp(&self, session_id: &str, sdp: &gst_webrtc::WebRTCSessionDescription); fn add_ice( &self, @@ -512,6 +558,17 @@ impl> SignallableExt for Obj { self.emit_by_name::("stop", &[]); } + fn munge_sdp( + &self, + session_id: &str, + sdp: &gst_webrtc::WebRTCSessionDescription, + ) -> gst_webrtc::WebRTCSessionDescription { + self.emit_by_name::( + "munge-session-description", + &[&session_id, sdp], + ) + } + fn send_sdp(&self, session_id: &str, sdp: &gst_webrtc::WebRTCSessionDescription) { self.emit_by_name::("send-session-description", &[&session_id, sdp]); } diff --git a/net/webrtc/src/webrtcsink/imp.rs b/net/webrtc/src/webrtcsink/imp.rs index 3d8ec849..5e2e2539 100644 --- a/net/webrtc/src/webrtcsink/imp.rs +++ b/net/webrtc/src/webrtcsink/imp.rs @@ -2130,7 +2130,17 @@ impl BaseWebRTCSink { .emit_by_name::<()>("set-local-description", &[&offer, &None::]); drop(state); - signaller.send_sdp(session_id, &offer); + let maybe_munged_offer = if signaller + .has_property("manual-sdp-munging", Some(bool::static_type())) + && signaller.property("manual-sdp-munging") + { + // Don't munge, signaller will manage this + offer + } else { + // Use the default munging mechanism (signal registered by user) + signaller.munge_sdp(session_id, &offer) + }; + signaller.send_sdp(session_id, &maybe_munged_offer); } } @@ -2174,7 +2184,19 @@ impl BaseWebRTCSink { } drop(state); - signaller.send_sdp(&session_id, &answer); + + let maybe_munged_answer = if signaller + .has_property("manual-sdp-munging", Some(bool::static_type())) + && signaller.property("manual-sdp-munging") + { + // Don't munge, signaller will manage this + answer + } else { + // Use the default munging mechanism (signal registered by user) + signaller.munge_sdp(session_id.as_str(), &answer) + }; + + signaller.send_sdp(&session_id, &maybe_munged_answer); self.on_remote_description_set(element, session_id) } diff --git a/net/webrtc/src/whip_signaller/imp.rs b/net/webrtc/src/whip_signaller/imp.rs index b3b41996..81ffdd41 100644 --- a/net/webrtc/src/whip_signaller/imp.rs +++ b/net/webrtc/src/whip_signaller/imp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use crate::signaller::{Signallable, SignallableImpl}; +use crate::signaller::{Signallable, SignallableExt, SignallableImpl}; use crate::utils::{ build_link_header, build_reqwest_client, parse_redirect_location, set_ice_servers, wait, wait_async, WaitError, @@ -120,7 +120,7 @@ impl WhipClient { self.raise_error("Local description is not set".to_string()); return; } - Some(offer) => offer, + Some(offer) => self.obj().munge_sdp("unique", &offer), }; gst::debug!( @@ -562,6 +562,12 @@ impl ObjectImpl for WhipClient { .maximum(3600) .default_value(DEFAULT_TIMEOUT) .build(), + glib::ParamSpecBoolean::builder("manual-sdp-munging") + .nick("Manual SDP munging") + .blurb("Whether the signaller manages SDP munging itself") + .default_value(false) + .read_only() + .build(), ] }); @@ -608,6 +614,7 @@ impl ObjectImpl for WhipClient { let settings = self.settings.lock().unwrap(); settings.timeout.to_value() } + "manual-sdp-munging" => true.to_value(), _ => unimplemented!(), } }