-
Notifications
You must be signed in to change notification settings - Fork 59
Ensure smoother Ringing to Active transition
#1633
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
Merged
aleksandar-apostolov
merged 20 commits into
develop
from
feature/rahullohra/improve-transition-to-ringing-active-state
Apr 1, 2026
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
b9db4dc
fix: Add active state transition class to handle the transitioning
rahul-lohra 4f2e430
fix: update test cases
rahul-lohra d63bceb
fix: update test cases
rahul-lohra f67c18f
fix: update test cases
rahul-lohra 0c4ffbd
fix: update rtc session
rahul-lohra 8c4affe
fix: update rtc session
rahul-lohra a98814a
fix: demo-app test cases
rahul-lohra 951bb0e
fix: update demo-app test cases
rahul-lohra 227a869
fix: refactor names
rahul-lohra 72db0af
fix: Add logic first rtp-packet arrived
rahul-lohra 85975bf
fix: add logic for first-rtp-packet arrived
rahul-lohra 2e9ab3e
Update e2e tests
testableapple b12f806
Fix spotless
testableapple fa72c25
chore: Add debug prefix to all the logic which will be removed after …
rahul-lohra 3dc997e
revert: Use Publisher Connected strategy
rahul-lohra fd645f5
refactor: update tests
rahul-lohra 7bf4b7c
refactor: refactor code
rahul-lohra ee1f9a4
Merge branch 'refs/heads/develop' into feature/rahullohra/improve-tra…
rahul-lohra 442baba
refactor: refactor code
rahul-lohra daf21fb
refactor: refactor monitorPubConnectionState
rahul-lohra File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ActiveStateGate.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| /* | ||
| * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. | ||
| * | ||
| * Licensed under the Stream License; | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * https://github.com/GetStream/stream-video-android/blob/main/LICENSE | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package io.getstream.video.android.core | ||
|
|
||
| import io.getstream.log.taggedLogger | ||
| import kotlinx.coroutines.CoroutineScope | ||
| import kotlinx.coroutines.Job | ||
| import kotlinx.coroutines.flow.emptyFlow | ||
| import kotlinx.coroutines.flow.filter | ||
| import kotlinx.coroutines.flow.filterNotNull | ||
| import kotlinx.coroutines.flow.first | ||
| import kotlinx.coroutines.flow.flatMapLatest | ||
| import kotlinx.coroutines.flow.map | ||
| import kotlinx.coroutines.isActive | ||
| import kotlinx.coroutines.launch | ||
| import kotlinx.coroutines.withTimeoutOrNull | ||
| import org.webrtc.PeerConnection | ||
|
|
||
| private const val PEER_CONNECTION_OBSERVER_TIMEOUT = 5_000L | ||
|
|
||
| internal class ActiveStateGate( | ||
| private val coroutineScope: CoroutineScope, | ||
| private val previousRingingStates: Set<RingingState>, | ||
| private val strategy: TransitionToRingingStateStrategy = TransitionToRingingStateStrategy.PUBLISHER_CONNECTED, | ||
| private val timeoutMs: Long = PEER_CONNECTION_OBSERVER_TIMEOUT, | ||
| ) { | ||
| private val logger by taggedLogger("ActiveStateGate") | ||
| private var peerConnectionObserverJob: Job? = null | ||
|
|
||
| internal fun awaitAndTransition( | ||
| currentRingingState: RingingState, | ||
| call: Call, | ||
| onReady: () -> Unit, | ||
| ) { | ||
| logger.d { "[awaitAndTransition], ringingState: $currentRingingState" } | ||
| when (strategy) { | ||
| TransitionToRingingStateStrategy.LEGACY_BEHAVIOUR -> { | ||
| onReady() | ||
| } | ||
|
|
||
| else -> { | ||
| val isIncomingOrOutgoing = | ||
| previousRingingStates.any { it is RingingState.Incoming || it is RingingState.Outgoing } | ||
|
|
||
| if (isIncomingOrOutgoing && currentRingingState !is RingingState.Active) { | ||
| observePeerConnection( | ||
| call, | ||
| onReady, | ||
| strategy, | ||
| ) | ||
| } else if (!isIncomingOrOutgoing) { | ||
| onReady() | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun observePeerConnection(call: Call, onReady: () -> Unit, strategy: TransitionToRingingStateStrategy) { | ||
| if (peerConnectionObserverJob?.isActive == true) return | ||
|
|
||
| peerConnectionObserverJob = coroutineScope.launch { | ||
| val start = System.currentTimeMillis() | ||
|
|
||
| val result = withTimeoutOrNull(timeoutMs) { | ||
| call.session | ||
| .filterNotNull() | ||
| .flatMapLatest { session -> | ||
|
|
||
| val publisherFlow = session.publisher | ||
| .filterNotNull() | ||
| .flatMapLatest { it.state } | ||
|
|
||
| when (strategy) { | ||
| TransitionToRingingStateStrategy.LEGACY_BEHAVIOUR -> { | ||
| emptyFlow<Int>() | ||
| .map { "none" to it } | ||
| } | ||
| TransitionToRingingStateStrategy.PUBLISHER_CONNECTED -> { | ||
|
aleksandar-apostolov marked this conversation as resolved.
|
||
| publisherFlow.filter { it == PeerConnection.PeerConnectionState.CONNECTED } | ||
| .map { "publisher" to it } | ||
| } | ||
| } | ||
| } | ||
| .first() | ||
| } | ||
|
|
||
| val duration = System.currentTimeMillis() - start | ||
|
|
||
| if (result != null) { | ||
| val (source, state) = result | ||
| logger.d { | ||
| "[observeConnection-$strategy] $source reached $state in ${duration}ms" | ||
| } | ||
| } else { | ||
| logger.w { | ||
| "[observeConnection-$strategy] Timeout after ${duration}ms" | ||
| } | ||
| } | ||
| if (isActive) { | ||
| onReady() | ||
| cleanup() | ||
| } | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| fun cleanup() { | ||
| peerConnectionObserverJob?.cancel() | ||
| peerConnectionObserverJob = null | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.