Skip to content

Enable WARP (SPED + SNAP), gated by the server - #1138

Open
pblazej wants to merge 1 commit into
mainfrom
blaze/warp
Open

pblazej wants to merge 1 commit into
mainfrom
blaze/warp

Conversation

@pblazej

@pblazej pblazej commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Enables WARP (draft-uberti-tsvwg-warp). This is the best of #1128 (@cloudwebrtc) and #1094 (@hiroshihorie) merged into one PR, and it supersedes both.

  • SPED (DTLS in STUN): the WebRTC-IceHandshakeDtls field trial, passed to LKRTCPeerConnectionFactory.configureFieldTrials right before the factory is built. This avoids the deprecated LKRTCInitFieldTrialDictionary.
  • SNAP (SCTP INIT in SDP): enableSctpSnap = true in LKRTCConfiguration.liveKitDefault(). Every configuration, including the setConfiguration calls on quick reconnect and early-publisher adoption, is built from it. So this immutable field never changes after the peer connection exists, which was the INVALID_MODIFICATION trap in Add WARP support (DTLS handshake carried in the ICE exchange) #1128.

WARP is always on, with no public API and no runtime switch, the same as rust-sdks#1342. The server decides whether WARP engages. A server without WARP ignores the offer and the connection falls back to the standard handshake.

SPED was turned off in #1015 on suspicion of #929. That crash turned out to be the ADM fine_audio_buffer_ null dereference, fixed in #1041.

Testing

WARPTests checks that the offer carries both goog-sped-v1 and a=sctp-init:. Removing either leg makes it fail (verified).

End to end, against local livekit-server 1.13.7 (the latest release; it ships the livekit/ice v4.4.0-warp.2 / dtls v3.1.5-warp.1 / webrtc-pion v4.2.18-warp.1 forks). The test connects two rooms and sends one reliable packet:

rtc.enable_warp: true WARP off
SPED completes on both active transports: libwebrtc logs DTLS-STUN piggyback complete with success=1, the SFU logs Done with the SPED handshake not engaged
SNAP a=sctp-init in all four SDPs (client offer, SFU answer, SFU offer, client answer) only in the client offer; the SFU drops it
data round trip ✅ ✅

To reproduce, add this to the server config: rtc: { enable_warp: true } and logging: { pion_level: debug }.

Known issue: SPED plus a data burst right after connect

Against a WARP server, PublishDataTests (100 concurrent publishes right after connect) loses messages when SPED is on. I ran each variant against the same server:

variant runs result
SPED + SNAP 4 4 failed
SPED only 3 3 failed
SNAP only 4 4 passed
neither 1 passed
SPED + SNAP, WARP off 1 passed

libwebrtc marks DTLS connected but defers set_writable until ICE is writable. The SFU finishes its DTLS side and starts sending SCTP in that gap, and the client's dcsctp rejects those packets (Packet has invalid verification tag: …, expected 00000000). SCTP recovers only after RTO backoff, about 2.5 s. Meanwhile the SFU's downlink buffer for that subscriber fills: it forwarded 83 of 98 messages, about 8 KB, and dropped the rest. The first data-channel packets in each direction are affected.

This is interop timing between libwebrtc m150 and the pion WARP forks, not something this PR touches. Other SDKs that already ship SPED (Rust) should behave the same way. The data-stream and data-track suites showed the same symptom against a WARP server. CI's dev server doesn't enable WARP, so CI stays green either way.

Always on, no runtime switch: SPED (DTLS in STUN) via the
WebRTC-IceHandshakeDtls field trial passed to configureFieldTrials before
the factory is built, SNAP (SCTP INIT in SDP) via enableSctpSnap on the
default configuration. Neither engages unless the server negotiates it.

Supersedes #1128 and #1094.

Co-Authored-By: cloudwebrtc <duanweiwei1982@gmail.com>
Co-Authored-By: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Devin Review


// WARP SPED (DTLS in STUN); SNAP is on `LKRTCConfiguration.liveKitDefault()`.
// Both engage only when the server negotiates them.
LKRTCPeerConnectionFactory.configureFieldTrials("\(kLKRTCFieldTrialIceHandshakeDtlsKey)/\(kLKRTCFieldTrialEnabledValue)/")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Early data packets lost on WARP servers

On WARP servers, configureFieldTrials enables SPED, and data bursts immediately after connection lose messages. SCTP rejects early packets before ICE becomes writable; retransmission delays fill the server's downlink buffer.

Learn more

SPED carries the DTLS handshake in ICE, so DTLS can report connected before ICE is writable. On a WARP-enabled server, this allows the SFU to send SCTP traffic while the client's association still rejects packets with an invalid verification tag. Retransmission takes long enough for the SFU's subscriber downlink buffer to fill during the 100-packet burst in PublishDataTests. The reported runs lost messages with SPED enabled and passed with SNAP alone or WARP disabled.

Example: Two clients connect to a WARP-enabled server and one publishes 100 reliable packets immediately. The SFU forwards only part of the burst; the receiver never sees the rest, even though every publish call completed.

Recommended fix: Resolve the libwebrtc/Pion SPED readiness interop before enabling the field trial by default. Until then, leave SPED disabled while retaining SNAP, or gate SPED to configurations known to avoid early SCTP loss. Add an end-to-end burst test against a WARP-enabled server.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blaze, what do you think about this devin's comment, as minimal, I'd think it is a corner cases and shouldn't blocking this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, based on my measurements the delay is real (>10s) and can hit important use cases like pre-connect audio buffer or initial RPC.

I'm trying to create some WebRTC patch (learn sth from this PR webrtc-sdk/webrtc#287)

@pblazej

pblazej commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

Stability fixes should come after #1131

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants