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 02b05b726..769200cda 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 @@ -694,7 +694,11 @@ internal constructor( @CheckResult internal suspend fun sendData(dataPacket: LivekitModels.DataPacket): Result { - ensurePublisherConnected(dataPacket.kind) + try { + ensurePublisherConnected(dataPacket.kind) + } catch (e: Exception) { + return Result.failure(e) + } fun sendDataImpl(dataPacket: LivekitModels.DataPacket): Result { try { diff --git a/livekit-android-test/src/test/java/io/livekit/android/room/participant/LocalParticipantMockE2ETest.kt b/livekit-android-test/src/test/java/io/livekit/android/room/participant/LocalParticipantMockE2ETest.kt index 30463e5b5..79f4fa0d9 100644 --- a/livekit-android-test/src/test/java/io/livekit/android/room/participant/LocalParticipantMockE2ETest.kt +++ b/livekit-android-test/src/test/java/io/livekit/android/room/participant/LocalParticipantMockE2ETest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 LiveKit, Inc. + * Copyright 2023-2026 LiveKit, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import io.livekit.android.events.ParticipantEvent import io.livekit.android.events.RoomEvent import io.livekit.android.room.DefaultsManager import io.livekit.android.room.RTCEngine +import io.livekit.android.room.RoomException import io.livekit.android.room.track.LocalVideoTrack import io.livekit.android.room.track.LocalVideoTrackOptions import io.livekit.android.room.track.ScreenSharePresets @@ -879,4 +880,19 @@ class LocalParticipantMockE2ETest : MockE2ETest() { assertTrue(headerPacket.user.payload.toByteArray().contentEquals(data)) } + + @Test + fun publishDataReturnsFailureWhenPublisherChannelIsMissing() = runTest { + connect() + + val rtcEngine = component.rtcEngine() + val reliableDataChannelField = RTCEngine::class.java.getDeclaredField("reliableDataChannel") + reliableDataChannelField.isAccessible = true + reliableDataChannelField.set(rtcEngine, null) + + val result = room.localParticipant.publishData("hello".toByteArray()) + + assertTrue(result.isFailure) + assertTrue(result.exceptionOrNull() is RoomException.ConnectException) + } }