From 8531cf447bc1bad5c568a499cd595362f5f0c428 Mon Sep 17 00:00:00 2001 From: Adrian Niculescu <15037449+adrian-niculescu@users.noreply.github.com> Date: Sat, 20 Dec 2025 15:51:32 +0200 Subject: [PATCH] Fixed file descriptor leak in ByteStreamSender. --- .changeset/fix-byte-stream-source-leak.md | 5 +++ .../datastream/outgoing/ByteStreamSender.kt | 31 ++++++++++--------- 2 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 .changeset/fix-byte-stream-source-leak.md diff --git a/.changeset/fix-byte-stream-source-leak.md b/.changeset/fix-byte-stream-source-leak.md new file mode 100644 index 000000000..36e599806 --- /dev/null +++ b/.changeset/fix-byte-stream-source-leak.md @@ -0,0 +1,5 @@ +--- +"client-sdk-android": patch +--- + +Fixed file descriptor leak in ByteStreamSender where Source was not closed after reading. diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/datastream/outgoing/ByteStreamSender.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/datastream/outgoing/ByteStreamSender.kt index aa50ad74e..95a7eb6db 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/datastream/outgoing/ByteStreamSender.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/datastream/outgoing/ByteStreamSender.kt @@ -86,25 +86,28 @@ suspend fun ByteStreamSender.write(input: InputStream): Result { /** * Reads the source and sends it to the data stream. + * + * The source will be closed when this function completes, whether it succeeds or fails. */ @CheckResult suspend fun ByteStreamSender.write(source: Source): Result { - val buffer = Buffer() - while (true) { - try { - val readLen = source.read(buffer, 4096) - if (readLen == -1L) { - break - } + return try { + source.use { src -> + val buffer = Buffer() + while (true) { + val readLen = src.read(buffer, 4096) + if (readLen == -1L) { + break + } - val result = write(buffer.readByteArray()) - if (result.isFailure) { - return result + val result = write(buffer.readByteArray()) + if (result.isFailure) { + return@use result + } } - } catch (e: Exception) { - return Result.failure(e) + Result.success(Unit) } + } catch (e: Exception) { + Result.failure(e) } - - return Result.success(Unit) }