From 73c397627aeade073273fc0f4623a1328fa8c612 Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Tue, 22 Sep 2026 10:09:12 +0800 Subject: [PATCH 1/2] chore: bump libwebrtc to m150 and add WARP support. --- .changeset/webrtc-150-warp-defaults.md | 11 +++++++++++ gradle/libs.versions.toml | 2 +- .../main/java/io/livekit/android/ConnectOptions.kt | 3 ++- .../main/java/io/livekit/android/dagger/RTCModule.kt | 12 ++++++++++++ .../livekit/android/room/PeerConnectionTransport.kt | 10 ++++++++++ .../main/java/io/livekit/android/room/RTCEngine.kt | 6 ++++++ .../io/livekit/android/webrtc/PeerConnectionExt.kt | 1 + 7 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 .changeset/webrtc-150-warp-defaults.md diff --git a/.changeset/webrtc-150-warp-defaults.md b/.changeset/webrtc-150-warp-defaults.md new file mode 100644 index 00000000..6f9fe8c6 --- /dev/null +++ b/.changeset/webrtc-150-warp-defaults.md @@ -0,0 +1,11 @@ +--- +"client-sdk-android": patch +--- + +Update libwebrtc to 150.7871.01 and turn on WARP (draft-uberti-tsvwg-warp) by default. + +Two connection-setup accelerations are now enabled out of the box: the `WebRTC-IceHandshakeDtls` +field trial, which carries the DTLS handshake inside the ICE STUN binding exchange so DTLS and ICE +negotiate in parallel, and `RTCConfiguration.enableSctpSnap`, which puts the SCTP INIT parameters +in the SDP so a data channel skips SCTP's cookie exchange. Both are negotiated with the server and +fall back to the plain DTLS/SCTP setup when it doesn't support them. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e0e6c0fd..a5a95198 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -webrtc = "144.7559.14" +webrtc = "150.7871.01" androidJainSipRi = "1.3.0-91" androidx-activity = "1.9.0" diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/ConnectOptions.kt b/livekit-android-sdk/src/main/java/io/livekit/android/ConnectOptions.kt index b7fe11b8..b180535b 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/ConnectOptions.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/ConnectOptions.kt @@ -38,7 +38,8 @@ data class ConnectOptions( * A user-provided RTCConfiguration to override options. * * Note: LiveKit requires [PeerConnection.SdpSemantics.UNIFIED_PLAN] and - * [PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY]. + * [PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY], and always enables + * `enableSctpSnap`. These are overwritten even if set otherwise here. */ val rtcConfig: PeerConnection.RTCConfiguration? = null, /** diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt index bf4a692d..2e8a672e 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt @@ -81,6 +81,17 @@ internal object RTCModule { */ private var hasInitializedWebrtc = false + /** + * libwebrtc field trials that LiveKit enables by default. + * + * `WebRTC-IceHandshakeDtls` carries the DTLS handshake inside the ICE STUN binding exchange + * (draft-uberti-tsvwg-warp), so DTLS and ICE negotiate in parallel rather than one after the + * other. Together with `RTCConfiguration.enableSctpSnap` this is the client half of WARP; it + * is negotiated with the server and falls back to plain DTLS when the server doesn't support + * it. + */ + private const val DEFAULT_FIELD_TRIALS = "WebRTC-IceHandshakeDtls/Enabled/" + /** * Certain classes require libwebrtc to be initialized prior to use. * @@ -111,6 +122,7 @@ internal object RTCModule { PeerConnectionFactory.InitializationOptions .builder(appContext) .setNativeLibraryName("lkjingle_peerconnection_so") + .setFieldTrials(DEFAULT_FIELD_TRIALS) .setInjectableLogger( { s, severity, s2 -> if (!LiveKit.enableWebRTCLogging) { diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt index efae279a..f81e7ca9 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt @@ -202,6 +202,16 @@ constructor( if (isClosed()) { return@launchRTCIfNotClosed } + + // WARP (draft-uberti-tsvwg-warp) shows up as a=goog-sped-v1 (DTLS handshake carried + // in the ICE exchange) and a=sctp-init (SCTP INIT params in the SDP, skipping the + // cookie exchange). libwebrtc only emits them when the acceleration is actually in + // use, so this reports what went on the wire. + LKLog.i { + "WARP: SPED ${if (sdpOffer.description.contains("a=goog-sped-v1")) "enabled" else "disabled"}, " + + "SNAP ${if (sdpOffer.description.contains("a=sctp-init")) "enabled" else "disabled"}" + } + // munge sdp val sdpDescription = sdpFactory.createSessionDescription(sdpOffer.description) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/RTCEngine.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/RTCEngine.kt index bc4c8235..9c23d232 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/RTCEngine.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/RTCEngine.kt @@ -1107,6 +1107,12 @@ internal constructor( PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY } + // WARP: SNAP (SCTP Negotiation Acceleration Protocol) puts this side's SCTP INIT parameters + // into the SDP data m-section, letting a data channel skip SCTP's cookie exchange and saving + // up to two round trips on setup. It's negotiated with the server and falls back to plain + // SCTP when unsupported, so it's enabled unconditionally, even over a user-provided config. + rtcConfig.enableSctpSnap = true + val clientConfig = when (serverResponse) { is Either.Left -> { if (serverResponse.value.hasClientConfiguration()) { diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/PeerConnectionExt.kt b/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/PeerConnectionExt.kt index 326c522f..82d6655f 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/PeerConnectionExt.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/PeerConnectionExt.kt @@ -64,6 +64,7 @@ fun RTCConfiguration.copyFrom(config: RTCConfiguration) { enableDscp = config.enableDscp enableIceGatheringOnAnyAddressPorts = config.enableIceGatheringOnAnyAddressPorts enableImplicitRollback = config.enableImplicitRollback + enableSctpSnap = config.enableSctpSnap iceBackupCandidatePairPingInterval = config.iceBackupCandidatePairPingInterval iceCandidatePoolSize = config.iceCandidatePoolSize iceCheckIntervalStrongConnectivityMs = config.iceCheckIntervalStrongConnectivityMs From 15aa6506ba002613beea67f2475b3eb4e0643344 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 22 Sep 2026 10:22:17 +0800 Subject: [PATCH 2/2] Update livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../java/io/livekit/android/room/PeerConnectionTransport.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt index f81e7ca9..5747430d 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/PeerConnectionTransport.kt @@ -208,7 +208,7 @@ constructor( // cookie exchange). libwebrtc only emits them when the acceleration is actually in // use, so this reports what went on the wire. LKLog.i { - "WARP: SPED ${if (sdpOffer.description.contains("a=goog-sped-v1")) "enabled" else "disabled"}, " + + "WARP: SPED ${if (sdpOffer.description.contains("goog-sped-v1")) "enabled" else "disabled"}, " + "SNAP ${if (sdpOffer.description.contains("a=sctp-init")) "enabled" else "disabled"}" }