From 706d0f00955e85991bbacdd96cce46a031cf7c50 Mon Sep 17 00:00:00 2001 From: davidliu Date: Tue, 4 Aug 2026 21:54:30 +0900 Subject: [PATCH] Fix custom RTCConfigurations not picking up server-provided ice servers when needed --- .changeset/tricky-grapes-compare.md | 5 +++ .../java/io/livekit/android/room/RTCEngine.kt | 9 +++-- .../android/room/RTCEngineMockE2ETest.kt | 33 +++++++++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 .changeset/tricky-grapes-compare.md diff --git a/.changeset/tricky-grapes-compare.md b/.changeset/tricky-grapes-compare.md new file mode 100644 index 00000000..3dedf82d --- /dev/null +++ b/.changeset/tricky-grapes-compare.md @@ -0,0 +1,5 @@ +--- +"client-sdk-android": patch +--- + +Fix custom RTCConfigurations not picking up server-provided ice servers when user-provided list is empty 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 b43c3cf3..e0e64e7d 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 @@ -998,14 +998,13 @@ internal constructor( // Only use server-provided servers if user doesn't provide any. if (mergedServers.isEmpty()) { - iceServers.forEach { server -> - if (!mergedServers.contains(server)) { - mergedServers.add(server) - } - } + mergedServers.addAll(serverIceServers) } iceServers = mergedServers + sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN + continualGatheringPolicy = + PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY } ?: RTCConfiguration(serverIceServers).apply { sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN diff --git a/livekit-android-test/src/test/java/io/livekit/android/room/RTCEngineMockE2ETest.kt b/livekit-android-test/src/test/java/io/livekit/android/room/RTCEngineMockE2ETest.kt index 19a9d1c6..6225fb1e 100644 --- a/livekit-android-test/src/test/java/io/livekit/android/room/RTCEngineMockE2ETest.kt +++ b/livekit-android-test/src/test/java/io/livekit/android/room/RTCEngineMockE2ETest.kt @@ -17,6 +17,7 @@ package io.livekit.android.room import com.google.protobuf.ByteString +import io.livekit.android.ConnectOptions import io.livekit.android.room.track.TrackException import io.livekit.android.test.MockE2ETest import io.livekit.android.test.events.FlowCollector @@ -84,6 +85,38 @@ class RTCEngineMockE2ETest : MockE2ETest() { assertEquals(sentIceServers, subPeerConnection.rtcConfig.iceServers) } + @Test + fun customRtcConfigWithEmptyIceServersUsesServerIceServers() = runTest { + val connectJob = async { + room.connect( + url = TestData.EXAMPLE_URL, + token = "token", + options = ConnectOptions( + rtcConfig = PeerConnection.RTCConfiguration(emptyList()).apply { + iceTransportsType = PeerConnection.IceTransportsType.RELAY + }, + ), + ) + } + prepareSignal(TestData.JOIN) + connectJob.await() + connectPeerConnection() + + val subPeerConnection = getSubscriberPeerConnection() + assertEquals(PeerConnection.IceTransportsType.RELAY, subPeerConnection.rtcConfig.iceTransportsType) + val sentIceServers = TestData.JOIN.join.iceServersList + .map { it.toWebrtc() } + assertEquals(sentIceServers, subPeerConnection.rtcConfig.iceServers) + assertEquals( + PeerConnection.SdpSemantics.UNIFIED_PLAN, + subPeerConnection.rtcConfig.sdpSemantics, + ) + assertEquals( + PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY, + subPeerConnection.rtcConfig.continualGatheringPolicy, + ) + } + @Test fun roomConnectDoesNotHangOnWebSocketFailure() = runTest { val connectJob = async {