From 6efded531e7cf79c0c0ee421c2ed1390bc787562 Mon Sep 17 00:00:00 2001 From: "yongjun6.outsourcing" Date: Wed, 19 Aug 2026 14:52:53 +0800 Subject: [PATCH] Add publisher initial video bitrate API --- .changeset/bright-bitrates-start.md | 5 ++++ .../java/io/livekit/android/room/RTCEngine.kt | 20 +++++++++++++++ .../main/java/io/livekit/android/room/Room.kt | 25 +++++++++++++++++++ .../android/test/mock/MockPeerConnection.kt | 2 ++ .../android/room/RTCEngineMockE2ETest.kt | 16 ++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 .changeset/bright-bitrates-start.md diff --git a/.changeset/bright-bitrates-start.md b/.changeset/bright-bitrates-start.md new file mode 100644 index 000000000..be0ae0a25 --- /dev/null +++ b/.changeset/bright-bitrates-start.md @@ -0,0 +1,5 @@ +--- +"client-sdk-android": minor +--- + +Add `Room.setPublisherInitialVideoBitrate` to configure the publisher PeerConnection's current and maximum video bitrate after connecting. 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 e0e64e7db..7a7c5bff4 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 @@ -443,6 +443,26 @@ internal constructor( return SenderTransceiverHandle(publisher, transceiver, sessionState) } + /** + * Sets the publisher PeerConnection's initial video bitrate. + */ + internal suspend fun setPublisherInitialVideoBitrate( + initialBitrateBps: Int, + maxBitrateBps: Int, + ): Boolean { + require(initialBitrateBps > 0) + require(maxBitrateBps >= initialBitrateBps) + + val publisherTransport = publisher ?: return false + return publisherTransport.withPeerConnection { + setBitrate( + null, + initialBitrateBps, + maxBitrateBps, + ) + } == true + } + fun updateSubscriptionPermissions( allParticipants: Boolean, participantTrackPermissions: List, diff --git a/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt b/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt index 10aa87821..6575d641f 100644 --- a/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt +++ b/livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt @@ -1623,6 +1623,31 @@ constructor( */ fun getPublisherRTCStats(callback: RTCStatsCollectorCallback) = engine.getPublisherRTCStats(callback) + /** + * Sets the local publisher's initial video bitrate. + * + * Call this after the room has connected and before or immediately after publishing video. + * For example: + * ``` + * room.setPublisherInitialVideoBitrate( + * initialBitrateBps = 1_500_000, + * maxBitrateBps = 3_500_000, + * ) + * ``` + * + * @return `true` when WebRTC accepts the bitrate configuration, otherwise `false`. + * @throws IllegalArgumentException if either bitrate is invalid. + */ + suspend fun setPublisherInitialVideoBitrate( + initialBitrateBps: Int, + maxBitrateBps: Int, + ): Boolean { + return engine.setPublisherInitialVideoBitrate( + initialBitrateBps = initialBitrateBps, + maxBitrateBps = maxBitrateBps, + ) + } + /** * Get stats for the subscriber peer connection. * diff --git a/livekit-android-test/src/main/java/io/livekit/android/test/mock/MockPeerConnection.kt b/livekit-android-test/src/main/java/io/livekit/android/test/mock/MockPeerConnection.kt index 6a51cfebe..5a9695703 100644 --- a/livekit-android-test/src/main/java/io/livekit/android/test/mock/MockPeerConnection.kt +++ b/livekit-android-test/src/main/java/io/livekit/android/test/mock/MockPeerConnection.kt @@ -46,6 +46,7 @@ class MockPeerConnection( private var closed = false var localDesc: SessionDescription? = null var remoteDesc: SessionDescription? = null + var lastBitrateSettings: Triple? = null private val signalStateMachine = SignalStateMachine { newState -> observer?.onSignalingChange(newState) @@ -210,6 +211,7 @@ class MockPeerConnection( } override fun setBitrate(min: Int?, current: Int?, max: Int?): Boolean { + lastBitrateSettings = Triple(min, current, max) return true } 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 6225fb1ec..0df8115f6 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 @@ -149,6 +149,22 @@ class RTCEngineMockE2ETest : MockE2ETest() { ) } + @Test + fun setPublisherInitialVideoBitrate() = runTest { + connect() + + val applied = room.setPublisherInitialVideoBitrate( + initialBitrateBps = 1_500_000, + maxBitrateBps = 3_500_000, + ) + + assertTrue(applied) + assertEquals( + Triple(null, 1_500_000, 3_500_000), + getPublisherPeerConnection().lastBitrateSettings, + ) + } + @Test fun iceSubscriberConnect() = runTest { connect()