webrtc icon indicating copy to clipboard operation
webrtc copied to clipboard

RTCPeerConnection.setLocalDescription() without arguments

Open data-retriever opened this issue 2 years ago • 6 comments

The Perfect Negotiation document says that the set local description method shouldn't receive a argument for a perfect negotiation.

Is this feature already on the roadmap?

data-retriever avatar Mar 20 '22 19:03 data-retriever

Not on the roadmap at the moment, but part of what you mentioned is implemented i.e. you can pass an argument to set_local_description with an empty sdp field and it will re-use the last offer but it will not detect the need to generate a new offer.

k0nserv avatar May 23 '22 16:05 k0nserv

If anyone wishes to implement support for this the details are available here:

https://w3c.github.io/webrtc-pc/#dom-peerconnection-setlocaldescription

k0nserv avatar Jun 24 '22 10:06 k0nserv

I've managed to achieve a connection using "perfect negotiation" scheme using my implementation: https://github.com/zduny/webrtc/commit/5ceff6ad826c37bd751ba9dc7104fbbc0e5fad33#diff-7df0115dc6a55f713e6ad5ede4c7808165f5f0f12e2447091ca989dbbf11dbeb

But TBH have no idea if it is fully compliant with the specs...

zduny avatar Jan 18 '23 13:01 zduny

~EDIT: The text below is just a partial solution. I think it was only working because my dummy_sdp value was being parsed. I'm going to continue working on this. It's just one of many changes that needs to be had to make rollbacks work, :crying_cat_face:~

EDIT (2): Added another patch at the end of this comment that includes the changes necessary to omit the dummy_sdp value by introducing a new RTCSessionDescription::rollback() function.


Also, the existing logic in check_next_signaling_state does not permit rollbacks from RTCSignalingState::HaveLocalOffer. The attached patch below fixes this so it's possible to manually set the local description to type Rollback, which is valid according to:

https://w3c.github.io/webrtc-pc/#set-the-session-description

From f5635c18e1122af4499fe32af3b651fc527d30af Mon Sep 17 00:00:00 2001
From: Dimitri <[email protected]>
Date: Thu, 11 Jan 2024 09:36:11 -0800
Subject: pc/signaling-state: support rollbacks for have local offer

---
 webrtc/src/peer_connection/signaling_state.rs | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/webrtc/src/peer_connection/signaling_state.rs b/webrtc/src/peer_connection/signaling_state.rs
index 2edd613b..bca7716d 100644
--- a/webrtc/src/peer_connection/signaling_state.rs
+++ b/webrtc/src/peer_connection/signaling_state.rs
@@ -156,11 +156,20 @@ pub(crate) fn check_next_signaling_state(
                     }
                     _ => {}
                 }
-            } else if op == StateChangeOp::SetLocal
-                && sdp_type == RTCSdpType::Offer
-                && next == RTCSignalingState::HaveLocalOffer
-            {
-                return Ok(next);
+            } else if op == StateChangeOp::SetLocal {
+                match sdp_type {
+                    RTCSdpType::Offer => {
+                        if next == RTCSignalingState::HaveLocalOffer {
+                            return Ok(next);
+                        }
+                    },
+                    RTCSdpType::Rollback => {
+                        if next == RTCSignalingState::Stable {
+                            return Ok(next);
+                        }
+                    }
+                    _ => {}
+                }
             }
         }
         RTCSignalingState::HaveRemotePranswer => {
-- 
cgit v1.2.3

Now, the call to peer_connection.set_local_description with a SDP of type rollback will be accepted!

This also seems to solve my perfect negotiation problems, but as @zduny said: I'm not sure if this is 100% compliant with the specification (e.g. maybe there needs to be more work destroying listeners, etc. on rollback to the stable state?), but it gets me past my current block.

Also, currently, there is no way to create an SDP of type rollback, so I'm using this hack to get around that (I may make another patch to remove this dummy_sdp string from my code though):

let rollback_sdp = {
  let dummy_sdp = "v=0\r\no=- 934697676791585089 442572738 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=fingerprint:sha-256 BC:AC:A4:A4:76:A1:0F:E8:0A:97:BA:37:AD:02:44:72:A3:A4:03:6C:53:37:CA:26:54:AB:E7:BA:4A:D5:3C:9D\r\na=group:BUNDLE 0\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=setup:actpass\r\na=mid:0\r\na=sendrecv\r\na=sctp-port:5000\r\na=ice-ufrag:fbwPVDMJduBiMCbV\r\na=ice-pwd:HuwKsQYkDRogpMHUmXHkLOCLQzoiSQtY\r\n";
  let mut s = RTCSessionDescription::offer(dummy_sdp.into())?;
  s.sdp_type = RTCSdpType::Rollback;
  s
};

peer_connection.set_local_description(rollback_sdp).await?;

Update: The above hackish rollback creation with dummy_sdp can be removed entirely and replaced with:

peer_connection.set_local_description(RTCSessionDescription::rollback()?).await?;

Using the following patch:

From 52748e96cea76debf3bd56dbf55acb6956b78fff Mon Sep 17 00:00:00 2001
From: Dimitri <[email protected]>
Date: Thu, 11 Jan 2024 10:24:47 -0800
Subject: pc/sdp: add rollback create fn & support setting as local desc

---
 webrtc/src/peer_connection/mod.rs                  | 28 ++++++++++++----------
 .../src/peer_connection/sdp/session_description.rs | 12 ++++++++++
 2 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/webrtc/src/peer_connection/mod.rs b/webrtc/src/peer_connection/mod.rs
index b4989cef..8caeef8b 100644
--- a/webrtc/src/peer_connection/mod.rs
+++ b/webrtc/src/peer_connection/mod.rs
@@ -1215,22 +1215,26 @@ impl RTCPeerConnection {
             current_local_description.is_some()
         };
 
-        // JSEP 5.4
-        if desc.sdp.is_empty() {
-            match desc.sdp_type {
-                RTCSdpType::Answer | RTCSdpType::Pranswer => {
-                    let last_answer = self.internal.last_answer.lock().await;
-                    desc.sdp = last_answer.clone();
-                }
-                RTCSdpType::Offer => {
-                    let last_offer = self.internal.last_offer.lock().await;
-                    desc.sdp = last_offer.clone();
+
+        if desc.sdp_type != RTCSdpType::Rollback {
+            // JSEP 5.4
+            if desc.sdp.is_empty() {
+                match desc.sdp_type {
+                    RTCSdpType::Answer | RTCSdpType::Pranswer => {
+                        let last_answer = self.internal.last_answer.lock().await;
+                        desc.sdp = last_answer.clone();
+                    }
+                    RTCSdpType::Offer => {
+                        let last_offer = self.internal.last_offer.lock().await;
+                        desc.sdp = last_offer.clone();
+                    }
+                    _ => return Err(Error::ErrPeerConnSDPTypeInvalidValueSetLocalDescription),
                 }
-                _ => return Err(Error::ErrPeerConnSDPTypeInvalidValueSetLocalDescription),
             }
+
+            desc.parsed = Some(desc.unmarshal()?);
         }
 
-        desc.parsed = Some(desc.unmarshal()?);
         self.set_description(&desc, StateChangeOp::SetLocal).await?;
 
         let we_answer = desc.sdp_type == RTCSdpType::Answer;
diff --git a/webrtc/src/peer_connection/sdp/session_description.rs b/webrtc/src/peer_connection/sdp/session_description.rs
index 7085f34d..443bfd44 100644
--- a/webrtc/src/peer_connection/sdp/session_description.rs
+++ b/webrtc/src/peer_connection/sdp/session_description.rs
@@ -66,6 +66,18 @@ impl RTCSessionDescription {
         Ok(desc)
     }
 
+    /// Create a rollback RTCSessionDescription that can be given to
+    /// an RTCPeerConnection.
+    pub fn rollback() -> Result<RTCSessionDescription> {
+        let desc = RTCSessionDescription {
+            sdp: "".into(),
+            sdp_type: RTCSdpType::Rollback,
+            parsed: None,
+        };
+
+        Ok(desc)
+    }
+
     /// Unmarshal is a helper to deserialize the sdp
     pub fn unmarshal(&self) -> Result<SessionDescription> {
         let mut reader = Cursor::new(self.sdp.as_bytes());
-- 
cgit v1.2.3

dimitri-lenkov avatar Jan 11 '24 17:01 dimitri-lenkov