Webrtc datachannel.send() call stalls briefly when a large amount of data is sent

814 views
Skip to first unread message

tyler...@gmail.com

unread,
Jun 3, 2018, 12:01:49 PM6/3/18
to discuss-webrtc

I am working on an application that implements several different features using WebRTC for peer-to-peer communication between an ElectronJS app and a UWP app (using the Org.WebRTC UWP Nuget), including real-time audio/video streaming of both webcam feeds and screen/window captures (using the desktopCapture API), as well as several RTCDataChannels for a few different purposes. Everything 'works', but I have a quality-of-life issue that I don't understand, and I can't find any advice regarding this specific issue.

I have everything set up and functioning, but at one point I send a fairly large amount of data (~10mb) over a reliable, ordered RTCDataChannel, and (with no predictability I can identify) sometimes there is a delay of five to ten seconds before that data starts arriving on the other end. The data is both strings and binary messages interleaved together, where the binary messages are all <= 64kb large.

In those instances where the delay happens, immediately upon finishing all of the send calls, the iceconnectionstate for the RTCPeerConnection changes from "complete" to either "connected" or (rarely) "disconnected", then eventually back to "complete", suggesting some part of the connection is broken and reestablished, hence the delay. But I can't figure out what is causing the issue or how to fix it, and it is preventing completion of a required feature for the app I am working on.

Any advice or insight would be greatly appreciated. I use google groups like this often for finding already answered questions, but I don't post questions, so apologies for any inadvertent breaches of etiquette. Please let me know if there is any additional info I can provide that would help in answering my question.

Thanks!

Eric Davies

unread,
Jun 3, 2018, 11:47:52 PM6/3/18
to discuss-webrtc
are you trying to write that data all at once, or do you check the buffer state and write appropriately.

tyler...@gmail.com

unread,
Jun 4, 2018, 8:31:16 PM6/4/18
to discuss-webrtc
I have tried a few approaches, including queuing up sends and dispatching them in the onbufferamountlow event callback, if that is what you mean. But I'm not exactly certain I've used that callback correctly, and it doesn't get called in the state I expect. If I set the buffer threshold to N, and print out the buffered amount inside of that callback before I send anything new, it is sometimes higher than N, which doesn't make sense to me. I've had trouble finding good examples of using that callback correctly. I'm not doing any other checks before I send inside that callback; should I be?

Eric Davies

unread,
Jun 4, 2018, 10:17:23 PM6/4/18
to discuss...@googlegroups.com
I just took a look in easyrtc to see how we did it there. There, we used a sliding window approach: the receiver had to send an ack every some many packets or we'd stop sending until we received one. At the time, the buffer checking method didn't exist, though I seem to recall using some place else once.

You might try checking out the file sharing demo a https://demo.easyrtc.com/demos/demo_data_channel_filesharing.html to see if it has the same issues. If it does not, then you could possibly adapt the easyrtc_ft.js code (where all the file sharing over data channel logic is) to fit your own data structures. 

On Mon, Jun 4, 2018 at 5:31 PM, <tyler...@gmail.com> wrote:
I have tried a few approaches, including queuing up sends and dispatching them in the onbufferamountlow event callback, if that is what you mean. But I'm not exactly certain I've used that callback correctly, and it doesn't get called in the state I expect. If I set the buffer threshold to N, and print out the buffered amount inside of that callback before I send anything new, it is sometimes higher than N, which doesn't make sense to me. I've had trouble finding good examples of using that callback correctly. I'm not doing any other checks before I send inside that callback; should I be?

--

---
You received this message because you are subscribed to a topic in the Google Groups "discuss-webrtc" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/discuss-webrtc/EjevtDTsxuE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to discuss-webrtc+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/discuss-webrtc/62379198-4bdc-4faf-948b-b732fd1966c1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Eric Davies

Lennart Grahl

unread,
Jun 5, 2018, 2:54:54 PM6/5/18
to discuss-webrtc
Unless you want to continue transferring data after the connection has been lost and re-established, I don't see why this would be necessary.

Cheers
Lennart

On Tuesday, 5 June 2018 04:17:23 UTC+2, Eric Davies wrote:
I just took a look in easyrtc to see how we did it there. There, we used a sliding window approach: the receiver had to send an ack every some many packets or we'd stop sending until we received one. At the time, the buffer checking method didn't exist, though I seem to recall using some place else once.

You might try checking out the file sharing demo a https://demo.easyrtc.com/demos/demo_data_channel_filesharing.html to see if it has the same issues. If it does not, then you could possibly adapt the easyrtc_ft.js code (where all the file sharing over data channel logic is) to fit your own data structures. 
On Mon, Jun 4, 2018 at 5:31 PM, <tyler...@gmail.com> wrote:
I have tried a few approaches, including queuing up sends and dispatching them in the onbufferamountlow event callback, if that is what you mean. But I'm not exactly certain I've used that callback correctly, and it doesn't get called in the state I expect. If I set the buffer threshold to N, and print out the buffered amount inside of that callback before I send anything new, it is sometimes higher than N, which doesn't make sense to me. I've had trouble finding good examples of using that callback correctly. I'm not doing any other checks before I send inside that callback; should I be?

--

---
You received this message because you are subscribed to a topic in the Google Groups "discuss-webrtc" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/discuss-webrtc/EjevtDTsxuE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to discuss-webrt...@googlegroups.com.

tyler...@gmail.com

unread,
Jun 5, 2018, 3:23:15 PM6/5/18
to discuss-webrtc
I added explicit acknowledgement logic for each message, and this appears to have eliminated instances of the connection being lost and re-established, which has gotten me close enough to the app's feature spec to move on. But it seems like all I've really done is throttle the speed at which I am sending data, and that if the datachannel buffering worked the way I expected I would not have to do this and would ultimately be able to get the data to the other end more quickly. I am not the most sophisticated engineer when it comes to networking, so maybe I am missing something.

I'm still pretty confused about how the onbufferedamountlow callback is supposed to work (see my second comment in this thread), and it seems like that callback is intended to address this particularly scenario. Can anyone comment on this callback? Has anyone managed to use it successfully?

Lennart Grahl

unread,
Jun 5, 2018, 4:26:32 PM6/5/18
to discuss-webrtc
Sure, it's not trivial but there you go: https://lgrahl.de/examples/dc/dc-stress-buffering.html (relevant stuff starts at line 281)
Because this is ugly and hard to get right, I have suggested a streams extension for data channels: https://github.com/w3c/webrtc-pc/issues/1732

Cheers
Lennart

tyler...@gmail.com

unread,
Jun 7, 2018, 12:13:03 PM6/7/18
to discuss-webrtc
I am still having trouble getting this right. 

As far as I can tell, my logic is functionally equivalent to the logic in the dc-stress-buffering example, but I am still experiencing the ice disconnection and re-establishment behavior. Right before the disconnection/reconnection happens, onbufferedamountlow gets called repeatedly in a state I believe it shouldn't be, i.e. when bufferedAmount is well above bufferedAmountLowThreshold. This seems like it must be a bug, somewhere above the level of my own code. This is an electronjs application, so if this is a bug, maybe it is specific to electronjs and does not reproduce in the browser? I have not tested this and am too pressed for time to do so right now.

Could someone confirm my understanding of onbufferedamountlow, and that the behavior I am seeing, that it is called when bufferedAmount is not actually low, in fact seems like a bug, and that I'm not just confused about what should be happening? Thanks in advance.

Lennart Grahl

unread,
Jun 8, 2018, 3:15:34 PM6/8/18
to discuss-webrtc
Make sure you don't buffer more than ~16 MiB because that's when Chrome closes the data channel. All I can say is that I've never seen such behaviour before and, yes, it might be a bug in Electron. I don't know your understanding of onbufferedamountlow, so I can't tell if you're right or wrong. However, the spec states:

The bufferedAmountLowThreshold attribute sets the threshold at which the bufferedAmount is considered to be low. When the bufferedAmount decreases from above this threshold to equal or below it, the bufferedamountlow event fires. The bufferedAmountLowThreshold is initially zero on each new RTCDataChannel, but the application may change its value at any time.

Cheers
Lennart
Reply all
Reply to author
Forward
0 new messages