#3392·webrtc

Feature: Add SettingEngine API for DSCP (QoS) marking on RTP/RTCP/SCTP packets

Author: AwuqingCreated Mar 7, 2026Updated Mar 7, 2026

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[].networkPriority and RTCPeerConnection.setConfiguration({ dscp: true }). See W3C WebRTC Priority API.
  • GStreamer webrtcbin: Supports dscp-qos property on the pipeline.
  • Otracker/Janus: Configurable via dscp_tos parameter.

Why primitives are insufficient: Currently the only workaround is to:

  1. Create a net.UDPConn manually
  2. Call syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_TOS, dscpValue<<2) (Linux/macOS)
  3. 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

  1. OS-level syscall.SetsockoptInt on UDPMux connections — Works on Linux/macOS but not Windows without SIO_SET_QOS. Cannot distinguish audio vs video vs data channel traffic on a bundled connection since all share one UDP socket.

  2. iptables/nftables rules matching on port ranges — Fragile, requires root access, and doesn't work when ICEUDPMux binds all PeerConnections to a single port.

  3. net.Dialer.Control hook — Can set TOS at socket creation time but pion's internal UDP listeners don't expose a Control function in SettingEngine.

Additional context

Proposed API sketch:

go
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)                       // AF21

This 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