-
Notifications
You must be signed in to change notification settings - Fork 164
Scale the video start bitrate hint by connection setup time #1031
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "client-sdk-android": patch | ||
| --- | ||
|
|
||
| Scale the `x-google-start-bitrate` hint by connection setup time: the 1 Mbps camera cap now applies to connections that set up within 1.5 s and ramps linearly down to 300 kbps at 3.5 s or slower, with screen share capped the same way once the cap is below 1 Mbps. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -128,6 +128,12 @@ internal constructor( | |
| ) : SignalClient.Listener { | ||
| internal var listener: Listener? = null | ||
|
|
||
| /** | ||
| * When the current connection attempt began, taken at the top of [joinImpl]. Cleared once the | ||
| * primary transport connects, so the attempt is timed exactly once. | ||
| */ | ||
| private var connectStartedAtMs: Long? = null | ||
|
|
||
| /** | ||
| * Reflects the combined connection state of SignalClient and primary PeerConnection. | ||
| */ | ||
|
|
@@ -140,6 +146,9 @@ internal constructor( | |
| when (newVal) { | ||
| ConnectionState.CONNECTED -> { | ||
| signalSessionState = SignalSessionState(ended = false) | ||
| if (oldVal != ConnectionState.RESUMING) { | ||
| recordConnectionSetupTime() | ||
| } | ||
|
Comment on lines
+149
to
+151
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Early resume leaves video setup timer running When signaling drops before initial ICE connection, Learn moreA soft resume reuses the existing peer connection. If signaling closes during the initial connection, reconnect sets Example: An initial join starts at 0 ms, signaling drops before ICE connects, and soft resume completes at 2 s. A camera first published at 30 s gets the 300 kbps hint rather than a value based on the completed connection. Recommended fix: On Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| if (oldVal == ConnectionState.DISCONNECTED || oldVal == ConnectionState.CONNECTING) { | ||
| LKLog.d { "primary ICE connected" } | ||
| listener?.onEngineConnected() | ||
|
|
@@ -266,12 +275,30 @@ internal constructor( | |
| return joinImpl(url, token, options, roomOptions) | ||
| } | ||
|
|
||
| /** | ||
| * Hands the time from the start of [joinImpl] to the primary transport connecting to the | ||
| * publisher, which lowers the start bitrate hint for a slow connection. Runs for the initial | ||
| * join and for a full reconnect, which both go through [joinImpl] and build a new publisher; | ||
| * a resume keeps its peer connections and their estimator, so it never records one. The | ||
| * publisher also knows when the attempt began, so a video offer created before this fires | ||
| * (an app publishing as soon as the join completes) uses the time elapsed so far. | ||
| */ | ||
| private fun recordConnectionSetupTime() { | ||
| val startedAtMs = connectStartedAtMs ?: return | ||
| connectStartedAtMs = null | ||
| val setupTime = (SystemClock.elapsedRealtime() - startedAtMs).milliseconds | ||
| LKLog.i { "connection setup took ${setupTime.inWholeMilliseconds} ms" } | ||
| publisher?.setConnectionSetupTime(setupTime) | ||
| } | ||
|
|
||
| suspend fun joinImpl( | ||
| url: String, | ||
| token: String, | ||
| options: ConnectOptions, | ||
| roomOptions: RoomOptions, | ||
| ): JoinResponse = coroutineScope { | ||
| val startedAtMs = SystemClock.elapsedRealtime() | ||
| connectStartedAtMs = startedAtMs | ||
| if (connectionState == ConnectionState.DISCONNECTED) { | ||
| connectionState = ConnectionState.CONNECTING | ||
| } | ||
|
|
@@ -298,6 +325,9 @@ internal constructor( | |
| isSubscriberPrimary = joinResponse.subscriberPrimary | ||
|
|
||
| configure(joinResponse, options) | ||
| // The publisher created above needs the attempt's start time before its first offer, in | ||
| // case video is published before the primary transport connects. | ||
| publisher?.setConnectStartedAt(startedAtMs) | ||
|
|
||
| // Subscriber-primary defers the publisher PC until something is published. After a full | ||
| // reconnect `hasPublished` is still set, so re-negotiate here — otherwise the ICE wait | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.