Field trials
The native WebRTC engine ships some features turned off, behind field trials. A trial has a name, like
WebRTC-Sctp-Snap, and a group, usually Enabled. Browsers set them with a command-line flag. In Python WebRTC,
webrtc.field_trials sets them: a mapping of names to groups that works like os.environ.
import webrtc
webrtc.field_trials['WebRTC-Sctp-Snap'] = 'Enabled'
webrtc.field_trials.update({'WebRTC-IceHandshakeDtls': 'Enabled'})
pc = webrtc.RTCPeerConnection()
The WRTC_FIELD_TRIALS environment variable sets them without changing the code. It takes the format of the browsers’
flag, each name and group followed by a /:
WRTC_FIELD_TRIALS='WebRTC-Sctp-Snap/Enabled/WebRTC-IceHandshakeDtls/Enabled/' python app.py
It’s read when webrtc is imported, and a malformed value fails the import. Code can then add trials or change
them. str(webrtc.field_trials) gives the same format back.
Before the first connection
The engine reads the trials once, when it starts: on the first RTCPeerConnection or
RTCIceTransport. From then on they’re fixed for the life of the process, and changing them raises
InvalidStateError, even after every connection is closed. To try other trials, start a new process.
Trial names change between releases of the engine, which is libwebrtc M152 in this release. An unknown name is accepted and does nothing, as it does in the browsers, so check the spelling.
Socket receive buffer
Python WebRTC gives every UDP socket a receive buffer of at least 8 MB, so a burst of data channel messages isn’t
dropped while the engine is busy. Setting WebRTC-SetSocketReceiveBuffer to any group turns this off: Enabled-<kb>
sets your size, and Disabled leaves it to the engine and the system.
Linux caps the buffer at net.core.rmem_max, often about 200 KB. With that cap, a flood of data channel messages
overflows the buffer, and the channel can stall for seconds while SCTP recovers the lost packets. To lift the cap:
sudo sysctl -w net.core.rmem_max=8388608
Add net.core.rmem_max = 8388608 to /etc/sysctl.conf to keep it after a reboot.
Connected sockets
On macOS and Linux, when one remote address both sends to a UDP socket and receives from it, like the peer of a busy data channel, Python WebRTC gives that peer a second socket on the same local address, connected to it. The kernel then skips its route and socket lookups on every datagram, which makes data channels faster. Packets on the wire don’t change, so the peer can’t tell, and every other address keeps using the first socket.
Set PythonWebRTC-ConnectedSockets to Disabled to keep one socket per address, as the engine does on its own: to
rule this out while debugging a connection, or on a machine shared with other users, as the second socket shares the
address while it binds.
WARP
WARP connects faster by saving round trips. It’s made of four parts, and each of them works on its own: a peer that lacks one falls back to the usual handshake for it.
Part |
Saves |
How |
|---|---|---|
1 round trip of the DTLS handshake |
On by default |
|
up to 2 round trips: the SCTP handshake goes in the SDP ( |
|
|
1 round trip: the DTLS handshake rides on the ICE checks |
|
|
A negotiated data channel |
the channel opens without asking the remote peer |
|
webrtc.field_trials.update({'WebRTC-Sctp-Snap': 'Enabled', 'WebRTC-IceHandshakeDtls': 'Enabled'})
pc = webrtc.RTCPeerConnection()
events = pc.create_data_channel('events', webrtc.RTCDataChannelInit(negotiated=True, id=4))
The server has to know the id of the channel, so the signalling sends it along with the offer, as
OpenAI’s WARP guide describes. The
GPT-Live example connects this way.
With both trials, a data channel between two Python WebRTC peers opens 50% sooner, and a GPT-Live session starts 62% sooner once the API has answered.