Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebRTC Direct transport implementation #2337

Merged
merged 86 commits into from
Sep 12, 2023
Merged

WebRTC Direct transport implementation #2337

merged 86 commits into from
Sep 12, 2023

Conversation

marten-seemann
Copy link
Contributor

No description provided.

@justin0mcateer
Copy link

We are interested in using this. Is this just waiting to be reviewed and merged, or is there more work to do?

@marten-seemann
Copy link
Contributor Author

@justin0mcateer It’s not working 100% correctly yet. As you can see, all the tests are failing. We expect to make some progress in the next couple of weeks.

Can you tell us some more about your use case?

@filefilegoadmin
Copy link

filefilegoadmin commented Aug 16, 2023

@marten-seemann Is this PR going to be merged for the Aug 28th release?
We plan to experiment video streaming with libp2p

@marten-seemann
Copy link
Contributor Author

@marten-seemann Is this PR going to be merged for the Aug 28th release? We plan to experiment video streaming with libp2p

Hopefully, if we get it to work properly by that date. Are you planning to use the WebRTC transport?

@filefilegoadmin
Copy link

@marten-seemann Is this PR going to be merged for the Aug 28th release? We plan to experiment video streaming with libp2p

Hopefully, if we get it to work properly by that date. Are you planning to use the WebRTC transport?

Currently using tcp for transport. We would like to experiment with a feature to play videos using webrtc.

@marten-seemann
Copy link
Contributor Author

@MarcoPolo
Copy link
Collaborator

MarcoPolo commented Aug 29, 2023

I've debugged the interop issue. The problem is we close the stream right after sending the echo back. In Pion (maybe an SCTP thing?) closing a channel resets the stream. So the write isn't acknowledged by the peer.

We can fix this by waiting. Here I'm waiting for the buffered amount to be 0. There might be a better way here.

diff --git a/p2p/transport/webrtc/stream.go b/p2p/transport/webrtc/stream.go
index b86128dc..24c69a0a 100644
--- a/p2p/transport/webrtc/stream.go
+++ b/p2p/transport/webrtc/stream.go
@@ -192,6 +192,10 @@ func (s *stream) maybeDeclareStreamDone() {
 		(s.receiveState == receiveStateReset || s.receiveState == receiveStateDataRead) &&
 		len(s.controlMsgQueue) == 0 {
 		_ = s.SetReadDeadline(time.Now().Add(-1 * time.Hour)) // pion ignores zero times
+		s.dataChannel.SetBufferedAmountLowThreshold(0)
+		ch := make(chan struct{})
+		s.dataChannel.OnBufferedAmountLow(func() { ch <- struct{}{} })
+		<-ch
 		_ = s.dataChannel.Close()
 		// TODO: write for the spawned reader to return
 		s.onDone()

Copy link
Collaborator

@MarcoPolo MarcoPolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! let's get this in!

@marten-seemann
Copy link
Contributor Author

I've debugged the interop issue. The problem is we close the stream right after sending the echo back. In Pion (maybe an SCTP thing?) closing a channel resets the stream. So the write isn't acknowledged by the peer.

We can fix this by waiting. Here I'm waiting for the buffered amount to be 0. There might be a better way here.

diff --git a/p2p/transport/webrtc/stream.go b/p2p/transport/webrtc/stream.go
index b86128dc..24c69a0a 100644
--- a/p2p/transport/webrtc/stream.go
+++ b/p2p/transport/webrtc/stream.go
@@ -192,6 +192,10 @@ func (s *stream) maybeDeclareStreamDone() {
 		(s.receiveState == receiveStateReset || s.receiveState == receiveStateDataRead) &&
 		len(s.controlMsgQueue) == 0 {
 		_ = s.SetReadDeadline(time.Now().Add(-1 * time.Hour)) // pion ignores zero times
+		s.dataChannel.SetBufferedAmountLowThreshold(0)
+		ch := make(chan struct{})
+		s.dataChannel.OnBufferedAmountLow(func() { ch <- struct{}{} })
+		<-ch
 		_ = s.dataChannel.Close()
 		// TODO: write for the spawned reader to return
 		s.onDone()

This fix doesn't work. First of all, it's racy: SetBufferedAmountLowThreshold and OnBufferedAmountLow would need to happen atomically. I don't think this is the problem though, the transport tests still fail when I try to work around this:

@@ -192,6 +193,16 @@ func (s *stream) maybeDeclareStreamDone() {
                (s.receiveState == receiveStateReset || s.receiveState == receiveStateDataRead) &&
                len(s.controlMsgQueue) == 0 {
                _ = s.SetReadDeadline(time.Now().Add(-1 * time.Hour)) // pion ignores zero times
+               s.dataChannel.SetBufferedAmountLowThreshold(0)
+               ch := make(chan struct{}, 1)
+               s.dataChannel.OnBufferedAmountLow(func() { ch <- struct{}{} })
+               if s.dataChannel.BufferedAmount() > 0 {
+                       select {
+                       case <-ch:
+                       case <-time.After(5 * time.Second):
+                               fmt.Println("sending close took too long", s.dataChannel.BufferedAmount())
+                       }
+               }
                _ = s.dataChannel.Close()
                // TODO: write for the spawned reader to return
                s.onDone()

Lots of test cases run into the 5s timeout, with a non-zero buffered amount.

@BigLep
Copy link
Contributor

BigLep commented Sep 11, 2023

It's been a couple of weeks since saw activity here. Is the interop issue what we're working on here?

@marten-seemann
Copy link
Contributor Author

@BigLep libp2p/test-plans#279 is what has slowed us down for ~2 weeks. It's resolved now. I'll update this issue with a status update tomorrow.

@marten-seemann
Copy link
Contributor Author

I wrote up libp2p/specs#575 explaining the problem, and implemented the workaround described there. This should allow us to merge this PR and get WebRTC support out. It's limited to 512 streams per WebRTC connection, which is pretty terrible, but probably enough for most use cases.

@marten-seemann
Copy link
Contributor Author

CI is happy with this PR. I am not really happy, but we need to get this out somehow. Merging.

@marten-seemann marten-seemann changed the title WebRTC transport implementation WebRTC Direct transport implementation Sep 12, 2023
@marten-seemann marten-seemann merged commit 31ffac2 into master Sep 12, 2023
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

webrtc: public/browser-to-public/server
8 participants