-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Summary
Add SettingEngine API to configure DSCP (Differentiated Services Code Point) marking on RTP/RTCP and SCTP packets, enabling QoS-aware network treatment for WebRTC media and data channels.
Motivation
Real-time video streaming applications (e.g., remote desktop, cloud gaming) require low-latency, low-jitter delivery. DSCP marking allows intermediate routers and switches to prioritize WebRTC traffic over bulk data, significantly improving quality on managed networks.
Use cases:
- Mark video RTP packets with AF41 (DSCP 34) for assured forwarding with low drop probability
- Mark audio RTP packets with EF (DSCP 46) for expedited forwarding (lowest latency)
- Mark SCTP data channel traffic with AF21 (DSCP 18) for control messages (touch/gesture)
Expected outcome: Applications can set per-track or per-connection DSCP values through SettingEngine, and pion automatically applies the corresponding IP TOS byte on outgoing UDP sockets.
Other implementations:
- libwebrtc (Chrome/Chromium): Supports DSCP via
RtpParameters.encodings[].networkPriorityandRTCPeerConnection.setConfiguration({ dscp: true }). See W3C WebRTC Priority API. - GStreamer webrtcbin: Supports
dscp-qosproperty on the pipeline. - Otracker/Janus: Configurable via
dscp_tosparameter.
Why primitives are insufficient: Currently the only workaround is to:
- Create a
net.UDPConnmanually - Call
syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_TOS, dscpValue<<2)(Linux/macOS) - Pass it via
SetICEUDPMux
This approach is platform-specific (Linux IP_TOS vs Windows SIO_SET_QOS), error-prone (requires raw FD extraction via SyscallConn()), and cannot differentiate between audio/video/data channels sharing the same UDP mux socket.
Describe alternatives you've considered
-
OS-level
syscall.SetsockoptInton UDPMux connections — Works on Linux/macOS but not Windows withoutSIO_SET_QOS. Cannot distinguish audio vs video vs data channel traffic on a bundled connection since all share one UDP socket. -
iptables/nftables rules matching on port ranges — Fragile, requires root access, and doesn't work when
ICEUDPMuxbinds all PeerConnections to a single port. -
net.Dialer.Controlhook — Can set TOS at socket creation time but pion's internal UDP listeners don't expose a Control function inSettingEngine.
Additional context
Proposed API sketch:
se := webrtc.SettingEngine{}
// Option A: Global DSCP for all media
se.SetDSCP(0x22) // AF41 = 34 decimal
// Option B: Per-track-type DSCP (preferred)
se.SetDSCPForMedia(webrtc.RTPCodecTypeVideo, 0x22) // AF41
se.SetDSCPForMedia(webrtc.RTPCodecTypeAudio, 0x2E) // EF
se.SetDSCPForDataChannel(0x12) // AF21This came up while optimizing a large-scale remote-control WebRTC deployment (~10k concurrent sessions). Without DSCP, video/control packets compete equally with background traffic on enterprise networks, causing jitter spikes of 50-200ms. With DSCP marking at the application layer, managed switches can properly queue media packets, reducing P99 jitter by ~60% in our testing with tc/netem simulations.
Platform support matrix:
| OS | Mechanism | Notes |
|---|---|---|
| Linux | IP_TOS / IPV6_TCLASS |
Works with setsockopt |
| macOS | IP_TOS / IPV6_TCLASS |
Same as Linux |
| Windows | SIO_SET_QOS or IP_TOS |
Requires admin or Group Policy |
| Android | IP_TOS (via JNI or Go syscall) |
Works on rooted / system apps |