Skip to content
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

[Element Call] Keep MatrixClient alive while the call is working #1695

Conversation

jmartinesp
Copy link
Contributor

@jmartinesp jmartinesp commented Oct 30, 2023

Type of change

  • Feature
  • Bugfix
  • Technical
  • Other :

Content

  • When a call starts in CallType.RoomCall mode and is in foreground, we get the MatrixClient and start the sync.
  • When the call screen is put to background or closed, we stop the sync again.

Motivation and context

Before this fix we were experiencing a bug that consistently made EC work only 50% of the times it was launched. This happened because the EC Widget needs some data from the Rust SDK that can only be retrieved while the sync is active.

Since in LoggedInFlowNode we stop the sync when it's sent to the background, these events we requested were never received and the call only actually worked if it had some cached membership events from the previous attempt to make a call, working only 50% of the time, after a previous failed attempt to establish a call.

Tests

  • Join a call several times in a row.

If they all work, this is working.

Tested devices

  • Physical
  • Emulator
  • OS version(s): 11

Checklist

@jmartinesp jmartinesp changed the title Fix issues with stuck 'loading...' state and hangup [Element Call] Keep MatrixClient alive while the call is working Oct 30, 2023
@jmartinesp jmartinesp force-pushed the fix/jme/element-call-keep-matrix-client-alive branch from 9554f6c to d223cb5 Compare October 30, 2023 17:21
@codecov
Copy link

codecov bot commented Oct 31, 2023

Codecov Report

Attention: 11 lines in your changes are missing coverage. Please review.

Comparison is base (6bf400c) 63.64% compared to head (affaddb) 63.67%.
Report is 2 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1695      +/-   ##
===========================================
+ Coverage    63.64%   63.67%   +0.02%     
===========================================
  Files         1267     1267              
  Lines        32881    32904      +23     
  Branches      6809     6815       +6     
===========================================
+ Hits         20928    20950      +22     
+ Misses        8805     8801       -4     
- Partials      3148     3153       +5     
Files Coverage Δ
...o/element/android/appnav/di/MatrixClientsHolder.kt 77.14% <ø> (ø)
...ement/android/features/call/ui/CallScreenEvents.kt 100.00% <100.00%> (ø)
...lement/android/features/call/ui/CallScreenState.kt 100.00% <100.00%> (ø)
.../libraries/matrix/test/FakeMatrixClientProvider.kt 75.00% <0.00%> (+8.33%) ⬆️
...element/android/features/call/ui/CallScreenView.kt 23.52% <0.00%> (ø)
...nt/android/features/call/ui/CallScreenPresenter.kt 74.39% <72.00%> (-0.61%) ⬇️

... and 2 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jmartinesp jmartinesp marked this pull request as ready for review October 31, 2023 07:25
@jmartinesp jmartinesp requested a review from a team as a code owner October 31, 2023 07:25
@jmartinesp jmartinesp requested review from bmarty and removed request for a team October 31, 2023 07:25
}
)

// We need to restart the Matrix client to get the needed call events
if (state.isInWidgetMode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it a bit weird to have the view dictate if it should start or stop the sync, could we not manage this entirely in the Presenter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd need to use the OnLifecycleEvent there instead, which is possible, but then we need to provide a LocalLifecycleOwner in a Molecule test, which is both difficult and kind of weird.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe we could just replace it with a DisposableEffect, but that way we don't stop syncing when the call screen goes to background, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually a DisposableEffect might be a better solution in the end. I'm replacing it, thanks!

@jmartinesp jmartinesp force-pushed the fix/jme/element-call-keep-matrix-client-alive branch from 7146f70 to affaddb Compare October 31, 2023 12:35
@jmartinesp jmartinesp added the Z-NextRelease For issues and PRs which should be included in the NextRelease. label Oct 31, 2023
Copy link
Member

@bmarty bmarty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@Composable
private fun HandleMatrixClientSyncState() {
val coroutineScope = rememberCoroutineScope()
DisposableEffect(Unit) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need the DisposableEffect? The coroutineScope might be enough

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could manually stop the sync process when either we hang up the call or we receive a hang up message, but it seems safer to do it automatically when this is disposed.

appCoroutineScope.launch {
client.syncService().run {
if (syncState.value == SyncState.Running) {
stopSync()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there no risk of stopping the sync after it's been restarted inside LoggedInFlowNode?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoggedInFlowNode already tracks the current state and tries to restart the flow automatically in LoggedInFlowNode.observeSyncStateAndNetworkStatus, similar to what I do here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I just tried debugging it and the stopSync is called first, then startSync. I can't guarantee this will always happen, but the subscription in LoggedInFlowNode should help against any race conditions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, what happens if the network is lost? (airplane)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, nice catch. Endless loops of syncService starting.

Copy link
Contributor

@ganfra ganfra Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this code could be extracted and reusable :

combine(
                    // small debounce to avoid spamming startSync when the state is changing quickly in case of error.
                    syncService.syncState.debounce(100),
                    networkMonitor.connectivity
                ) { syncState, networkStatus ->
                    Pair(syncState, networkStatus)
                }
                    .collect { (syncState, networkStatus) ->
                        Timber.d("Sync state: $syncState, network status: $networkStatus")
                        if (syncState != SyncState.Running && networkStatus == NetworkStatus.Online) {
                            syncService.startSync()
                        }
                    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I just copied it, we'll see how we can extract this to some other component or extension function.

Copy link
Contributor

@ganfra ganfra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's iterate later.

@jmartinesp jmartinesp merged commit 355ee95 into element-hq:develop Oct 31, 2023
22 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Z-NextRelease For issues and PRs which should be included in the NextRelease.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants