Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/webrtc-150-warp-defaults.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
webrtc = "144.7559.14"
webrtc = "150.7871.01"

androidJainSipRi = "1.3.0-91"
androidx-activity = "1.9.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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("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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading