refactor: adding reconnecting logic and visuals

This commit is contained in:
jubb 2022-03-03 17:03:32 +11:00
parent 573f0930df
commit a90bd89c9a
6 changed files with 47 additions and 22 deletions

View File

@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_CONNECTED
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_INCOMING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_OUTGOING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_PRE_INIT
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_RECONNECTING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_RINGING
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.EARPIECE
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.SPEAKER_PHONE
@ -223,6 +224,8 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
state !in listOf(CALL_CONNECTED, CALL_RINGING, CALL_PRE_INIT) || wantsToAnswer
incomingControlGroup.isVisible =
state in listOf(CALL_RINGING, CALL_PRE_INIT) && !wantsToAnswer
reconnectingText.isVisible = state == CALL_RECONNECTING
endCallButton.isVisible = endCallButton.isVisible || state == CALL_RECONNECTING
}
}
}

View File

@ -51,6 +51,7 @@ import org.webrtc.SessionDescription
import java.util.UUID
import java.util.concurrent.ExecutionException
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import org.thoughtcrime.securesms.webrtc.data.State as CallState
@ -101,7 +102,8 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
const val INVALID_NOTIFICATION_ID = -1
private const val TIMEOUT_SECONDS = 90L
private const val MAX_TIMEOUTS = 3
private const val RECONNECT_SECONDS = 5L
private const val MAX_RECONNECTS = 5
fun cameraEnabled(context: Context, enabled: Boolean) = Intent(context, WebRtcCallService::class.java)
.setAction(ACTION_SET_MUTE_VIDEO)
@ -188,6 +190,9 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
private var wantsToAnswer = false
private var currentTimeouts = 0
private var isNetworkAvailable = true
private var scheduledTimeout: ScheduledFuture<*>? = null
private var scheduledReconnectTimeout: ScheduledFuture<*>? = null
private var scheduledReconnect: ScheduledFuture<*>? = null
private val lockManager by lazy { LockManager(this) }
private val serviceExecutor = Executors.newSingleThreadExecutor()
@ -407,7 +412,7 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
callManager.startOutgoingRinger(OutgoingRinger.Type.RINGING)
setCallInProgressNotification(TYPE_OUTGOING_RINGING, callManager.recipient)
callManager.insertCallMessage(recipient.address.serialize(), CallMessageType.CALL_OUTGOING)
timeoutExecutor.schedule(TimeoutRunnable(callId, this), TIMEOUT_SECONDS, TimeUnit.SECONDS)
scheduledTimeout = timeoutExecutor.schedule(TimeoutRunnable(callId, this), TIMEOUT_SECONDS, TimeUnit.SECONDS)
callManager.setAudioEnabled(true)
val expectedState = callManager.currentConnectionState
@ -463,7 +468,7 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
callManager.silenceIncomingRinger()
callManager.postViewModelState(CallViewModel.State.CALL_INCOMING)
timeoutExecutor.schedule(TimeoutRunnable(callId, this), TIMEOUT_SECONDS, TimeUnit.SECONDS)
scheduledTimeout = timeoutExecutor.schedule(TimeoutRunnable(callId, this), TIMEOUT_SECONDS, TimeUnit.SECONDS)
callManager.initializeAudioForCall()
callManager.initializeVideo(this)
@ -598,8 +603,13 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
val callId = callManager.callId ?: return
val numTimeouts = ++currentTimeouts
if (callId == getCallId(intent) && isNetworkAvailable && numTimeouts <= 5) {
if (callId == getCallId(intent) && isNetworkAvailable && numTimeouts <= MAX_RECONNECTS) {
Log.d("Loki", "Trying to re-connect")
callManager.networkReestablished()
scheduledTimeout = timeoutExecutor.schedule(TimeoutRunnable(callId, this), TIMEOUT_SECONDS, TimeUnit.SECONDS)
} else {
Log.d("Loki", "Network isn't available, timeouts == $numTimeouts out of $MAX_RECONNECTS")
scheduledReconnect = timeoutExecutor.schedule(CheckReconnectedRunnable(callId, this), RECONNECT_SECONDS, TimeUnit.SECONDS)
}
}
@ -783,17 +793,22 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener {
override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState?) {
if (newState == CONNECTED) {
scheduledTimeout?.cancel(false)
scheduledReconnect?.cancel(false)
scheduledReconnectTimeout?.cancel(false)
scheduledTimeout = null
scheduledReconnect = null
scheduledReconnectTimeout = null
val intent = Intent(this, WebRtcCallService::class.java)
.setAction(ACTION_ICE_CONNECTED)
startService(intent)
} else if (newState == FAILED) {
val intent = hangupIntent(this)
startService(intent)
} else if (newState == DISCONNECTED) {
} else if (newState in arrayOf(FAILED, DISCONNECTED) && scheduledReconnectTimeout == null) {
callManager.callId?.let { callId ->
callManager.postViewModelState(CallViewModel.State.CALL_RECONNECTING)
timeoutExecutor.schedule(CheckReconnectedRunnable(callId, this), 5, TimeUnit.SECONDS)
timeoutExecutor.schedule(ReconnectTimeoutRunnable(callId, this), TIMEOUT_SECONDS, TimeUnit.SECONDS)
callManager.postConnectionEvent(Event.IceDisconnect) {
callManager.postViewModelState(CallViewModel.State.CALL_RECONNECTING)
scheduledReconnect = timeoutExecutor.schedule(CheckReconnectedRunnable(callId, this), RECONNECT_SECONDS, TimeUnit.SECONDS)
scheduledReconnectTimeout = timeoutExecutor.schedule(ReconnectTimeoutRunnable(callId, this), TIMEOUT_SECONDS, TimeUnit.SECONDS)
}
} ?: run {
val intent = hangupIntent(this)
startService(intent)

View File

@ -675,17 +675,15 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
val callId = callId ?: return
val recipient = recipient ?: return
if (isReestablishing) return
isReestablishing = true
Log.d("Loki", "start re-establish")
postConnectionEvent(Event.NetworkReconnect) {
Log.d("Loki", "start re-establish")
val offer = connection.createOffer(MediaConstraints().apply {
mandatory.add(MediaConstraints.KeyValuePair("IceRestart", "true"))
})
connection.setLocalDescription(offer)
val offer = connection.createOffer(MediaConstraints().apply {
mandatory.add(MediaConstraints.KeyValuePair("IceRestart", "true"))
})
connection.setLocalDescription(offer)
MessageSender.sendNonDurably(CallMessage.offer(offer.description, callId), recipient.address).success {
isReestablishing = false
MessageSender.sendNonDurably(CallMessage.offer(offer.description, callId), recipient.address)
}
}

View File

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.webrtc.video
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.webrtc.data.quadrantRotation
import org.webrtc.VideoFrame
import org.webrtc.VideoSink
@ -19,7 +18,6 @@ class RemoteRotationVideoProxySink: VideoSink {
val modifiedRotation = thisFrame.rotation - quadrantRotation
val newFrame = VideoFrame(thisFrame.buffer, modifiedRotation, thisFrame.timestampNs)
Log.d("Loki", "sending frame: w=${newFrame.buffer.width}, h=${newFrame.buffer.height}, rw=${newFrame.rotatedWidth}, rh=${newFrame.rotatedHeight}, rot=${newFrame.rotation}")
thisSink.onFrame(newFrame)
}

View File

@ -46,6 +46,16 @@
app:layout_constraintTop_toBottomOf="@id/remote_recipient"
tools:visibility="visible" />
<TextView
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/remote_loading_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/WebRtcCallActivity_Reconnecting"
android:id="@+id/reconnecting_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/sessionCallText"
android:layout_width="wrap_content"

View File

@ -903,5 +903,6 @@
<string name="CallNotificationBuilder_first_call_title">Call Missed</string>
<string name="CallNotificationBuilder_first_call_message">You missed a call because you need to enable the \'Voice and video calls\' permission in the Privacy Settings.</string>
<string name="WebRtcCallActivity_Session_Call">Session Call</string>
<string name="WebRtcCallActivity_Reconnecting">Reconnecting…</string>
</resources>