Debugging network QoS with webrtcbin

Hi everyone,

I have a streaming application using webrtcbin that’s generally working fine. However, there’s one exception: when I use it on our university network (no matter if via Wifi, LAN, or VPN), audio and video is horribly chunky and garbled.

On my home connection, everything streams just fine - I had a four-hour intercontinental connection last week, and despite crappy Wifi on the US side, everything still worked.

Notably, other video call software (e.g. Zoom) doesn’t seem to have the same issues with our uni network, that works fine in both cases, it’s just my GStreamer webrtc setup that seems to croak.

I’m a bit lost how to debug this, TBH - what could I analyze and/or tweak to see where this issue is coming from? I already asked our admins, and they had no idea either :person_shrugging:

Thanks and best, Florian

Hello,

I’m interested in this topic. When my computer has both Ethernet and Wi-Fi connections active, it seems that WebRTC (especially with webrtcsink) doesn’t automatically prefer the Ethernet connection, which could lead to reduced streaming quality. How can I determine which network card is being used by WebRTC, and is there a way to analyze the network path it’s taking?

Thanks

Right now, there is no logic for this in libnice. It’s just the order in which they are received from getifaddrs(). On Windows, we use GetBestInterfaceEx, but I don’t know of a similar API on Linux or BSD platforms.

Another interesting option would be to actually measure the STUN response time in libnice and prefer the lowest ping.

In any case, the solution for this kind of problem belongs in libnice.

It seems like the solution on Linux implies reading the routes using rtnetlink, implementation welcome …

@ocrete OK, that’s related to the streaming path question, but would you also have any ideas for solving (or at least debugging) the original issue (very bad streaming quality on some networks, which does not seem to affect other video livestream software)? Thanks!

You’d have to look at the stats from webrtcbin maybe to see if it gives you a hint. Is the jitter super high? Which transport is used, etc ?

You mention webrtcbin, do you also have retransmissions in your application, this can make a big difference.

The other bit that can help is adapting the bitrate, this is not trivial, but luckily, we have webrtcbin (in gst-plugins-rs) that implements that.

Thanks for the hints! I’ve implemented the get-stats signal right now, but there’s a lot of data coming out, it’s going to take a moment to sift through.

I’m using standard webrtcbin and don’t have any code relating to retransmissions, I was actually assuming this would happen transparently? How would I be able to turn them on?

Right now, I’m using a fixed bitrate of 3 MBit which IMHO should be low enough to not cause any problems, but dynamic bitrate is something I’ve already been considering.

Thanks again and best, Florian

Retransmissions are not enabled by default. You need to set the do-nack property on each transceiver for retransmissions to take effect.

1 Like

Thanks! But hm, how do I actually do that? I assumed that the right way is to set a handler for on-new-transceiver on the webrtcbin and then set the do-nack property on the transceiver object in the handler, but it doesn’t look like that signal actually ever gets triggered…

Connect to on-new-transceiver before creating pads. Or use get-transceiver after creating pads.

Connect to on-new-transceiver before creating pads. Or use get-transceiver after creating pads.

Thank you, that was kinda obvious in hindsight :sweat_smile:

Interesting observation: newest Chrome (119) seems to dislike the offer which is created when do-nack is enabled, and spits out something like Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Failed to add remote stream ssrc: 212544496 to {mid: audio0, media_type: audio} Is this a known issue? Couldn’t find anything related.

Firefox works nicely so far, as does the Python client. I’ll dig a bit more…

I would need to look at the SDP for anything inconsistent to be able to tell you more on the chrome issue.

Thanks - here’s the SDP:

v=0
o=- 5957392827258361073 0 IN IP4 0.0.0.0
s=-
t=0 0
a=ice-options:trickle
a=group:BUNDLE video0 audio1 video2 application3
m=video 9 UDP/TLS/RTP/SAVPF 96 99
c=IN IP4 0.0.0.0
a=setup:actpass
a=ice-ufrag:pYs4YtR5qZjNi3Rc5gfiRFbkdtcb+zLo
a=ice-pwd:2JnlwDjkk8oDOzrMLiM6yAcWOfkDjNBS
a=rtcp-mux
a=rtcp-rsize
a=sendrecv
a=rtpmap:96 H264/90000
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 transport-cc
a=framerate:15
a=fmtp:96 packetization-mode=1;profile-level-id=42c01f;level-asymmetry-allowed=1
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=96
a=ssrc-group:FID 1678703777 955270214
a=ssrc:1678703777 msid:user1515347876@host-4204f5f1 webrtctransceiver0
a=ssrc:1678703777 cname:user1515347876@host-4204f5f1
a=ssrc:955270214 msid:user1515347876@host-4204f5f1 webrtctransceiver0
a=ssrc:955270214 cname:user1515347876@host-4204f5f1
a=mid:video0
a=fingerprint:sha-256 B0:AE:4B:89:C8:19:C7:FA:24:CC:2D:CC:F8:49:4C:C8:9D:9A:22:B5:21:E8:96:04:E7:C2:49:3A:D7:FA:B3:3C
a=rtcp-mux-only
m=audio 0 UDP/TLS/RTP/SAVPF 97 100
c=IN IP4 0.0.0.0
a=setup:actpass
a=ice-ufrag:pYs4YtR5qZjNi3Rc5gfiRFbkdtcb+zLo
a=ice-pwd:2JnlwDjkk8oDOzrMLiM6yAcWOfkDjNBS
a=bundle-only
a=rtcp-mux
a=rtcp-rsize
a=sendrecv
a=rtpmap:97 OPUS/48000/2
a=rtcp-fb:97 nack
a=rtcp-fb:97 transport-cc
a=fmtp:97 sprop-stereo=0;sprop-maxcapturerate=48000
a=rtpmap:100 rtx/48000
a=fmtp:100 apt=97
a=ssrc-group:FID 198368932 2711631353
a=ssrc:198368932 msid:user1515347876@host-4204f5f1 webrtctransceiver1
a=ssrc:198368932 cname:user1515347876@host-4204f5f1
a=ssrc:2711631353 msid:user1515347876@host-4204f5f1 webrtctransceiver1
a=ssrc:2711631353 cname:user1515347876@host-4204f5f1
a=mid:audio1
a=fingerprint:sha-256 B0:AE:4B:89:C8:19:C7:FA:24:CC:2D:CC:F8:49:4C:C8:9D:9A:22:B5:21:E8:96:04:E7:C2:49:3A:D7:FA:B3:3C
a=rtcp-mux-only
m=video 0 UDP/TLS/RTP/SAVPF 98 101
c=IN IP4 0.0.0.0
a=setup:actpass
a=ice-ufrag:pYs4YtR5qZjNi3Rc5gfiRFbkdtcb+zLo
a=ice-pwd:2JnlwDjkk8oDOzrMLiM6yAcWOfkDjNBS
a=bundle-only
a=rtcp-mux
a=rtcp-rsize
a=sendrecv
a=rtpmap:98 H264/90000
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 transport-cc
a=framerate:15
a=fmtp:98 packetization-mode=1;profile-level-id=42c01f;level-asymmetry-allowed=1
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=98
a=ssrc-group:FID 1806424788 1332022124
a=ssrc:1806424788 msid:user1515347876@host-4204f5f1 webrtctransceiver2
a=ssrc:1806424788 cname:user1515347876@host-4204f5f1
a=ssrc:1332022124 msid:user1515347876@host-4204f5f1 webrtctransceiver2
a=ssrc:1332022124 cname:user1515347876@host-4204f5f1
a=mid:video2
a=fingerprint:sha-256 B0:AE:4B:89:C8:19:C7:FA:24:CC:2D:CC:F8:49:4C:C8:9D:9A:22:B5:21:E8:96:04:E7:C2:49:3A:D7:FA:B3:3C
a=rtcp-mux-only
m=application 0 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 0.0.0.0
a=setup:actpass
a=ice-ufrag:pYs4YtR5qZjNi3Rc5gfiRFbkdtcb+zLo
a=ice-pwd:2JnlwDjkk8oDOzrMLiM6yAcWOfkDjNBS
a=bundle-only
a=mid:application3
a=sctp-port:5000
a=fingerprint:sha-256 B0:AE:4B:89:C8:19:C7:FA:24:CC:2D:CC:F8:49:4C:C8:9D:9A:22:B5:21:E8:96:04:E7:C2:49:3A:D7:FA:B3:3C

And for this exact SDP, the Chrome error is: stream.js:6 DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Failed to add remote stream ssrc: 198368932 to {mid: audio1, media_type: audio}

So it’s the RTX SSRC for audio. Are retransmissions incompatible with Opus?

EDIT: just to clarify, when I don’t set do-nack, the SDP has only one SSRC per stream and then Chrome doesn’t complain.

Yes, chrome does not like RTX for audio streams and only supports RTX for video streams.

Ah sheesh. Would you be able to suggest a Chrome-compatible way to get a bit more error tolerance into the whole streaming path?

Just a quick follow-up: I came across GStreamer-devel - webrtcbin and ulpfec issue when using more than one track while searching a bit more, and tried enabling do-nack as well as fec-type. This does work in principle (as long as I leave do-nack off for audio in Chrome).

However, looking at the streaming stats, the packet loss rate reported e.g. by Firefox is somewhere around 50%, and I assume this is just something where no amount of error correction can help anymore.

My current suspicion is that the VPN has some custom QoS rules for known video streaming software like Zoom, Skype etc. and just extremely horrible drop rates for plain old UDP (which AFAICT is how the WebRTC traffic looks to the VPN) :expressionless:

P.S. Finally figured out the root cause: the VPN has a MTU of 1395, while the default MTU for all RTP payloader elements is 1400 :expressionless:

Changed the MTU to 1200 and suddenly everything is peachy again.