Call ended: handle busy reason and invite timeout.
This commit is contained in:
parent
37e722e85d
commit
99a0d17dfc
|
@ -0,0 +1 @@
|
|||
Call: show dialog for some ended reasons.
|
|
@ -26,6 +26,7 @@ import android.os.Bundle
|
|||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.isInvisible
|
||||
|
@ -58,6 +59,7 @@ import org.matrix.android.sdk.api.logger.LoggerTag
|
|||
import org.matrix.android.sdk.api.session.call.CallState
|
||||
import org.matrix.android.sdk.api.session.call.MxPeerConnectionState
|
||||
import org.matrix.android.sdk.api.session.call.TurnServerResponse
|
||||
import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
|
||||
import org.webrtc.EglBase
|
||||
import org.webrtc.RendererCommon
|
||||
import timber.log.Timber
|
||||
|
@ -133,6 +135,12 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||
renderState(it)
|
||||
}
|
||||
|
||||
callViewModel.asyncSubscribe(this, VectorCallViewState::callState) {
|
||||
if (it is CallState.Ended) {
|
||||
handleCallEnded(it)
|
||||
}
|
||||
}
|
||||
|
||||
callViewModel.viewEvents
|
||||
.observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
@ -199,7 +207,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||
views.callConnectingProgress.isVisible = true
|
||||
configureCallInfo(state)
|
||||
}
|
||||
is CallState.Connected -> {
|
||||
is CallState.Connected -> {
|
||||
if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
|
||||
if (state.isLocalOnHold || state.isRemoteOnHold) {
|
||||
views.smallIsHeldIcon.isVisible = true
|
||||
|
@ -249,14 +257,44 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||
views.callConnectingProgress.isVisible = true
|
||||
}
|
||||
}
|
||||
is CallState.Ended -> {
|
||||
finish()
|
||||
is CallState.Ended -> {
|
||||
views.callVideoGroup.isInvisible = true
|
||||
views.callInfoGroup.isVisible = true
|
||||
views.callStatusText.setText(R.string.call_ended)
|
||||
configureCallInfo(state)
|
||||
}
|
||||
null -> {
|
||||
else -> {
|
||||
views.callVideoGroup.isInvisible = true
|
||||
views.callInfoGroup.isInvisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCallEnded(callState: CallState.Ended) {
|
||||
when (callState.reason) {
|
||||
EndCallReason.USER_BUSY -> {
|
||||
showEndCallDialog(R.string.call_ended_user_busy_title, R.string.call_ended_user_busy_description)
|
||||
}
|
||||
EndCallReason.INVITE_TIMEOUT -> {
|
||||
showEndCallDialog(R.string.call_ended_invite_timeout_title, R.string.call_error_user_not_responding)
|
||||
}
|
||||
else -> {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showEndCallDialog(@StringRes title: Int, @StringRes description: Int) {
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(title)
|
||||
.setMessage(description)
|
||||
.setNegativeButton(R.string.ok) { _, _ -> }
|
||||
.setOnDismissListener {
|
||||
finish()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun configureCallInfo(state: VectorCallViewState, blurAvatar: Boolean = false) {
|
||||
state.callInfo?.opponentUserItem?.let {
|
||||
val colorFilter = ContextCompat.getColor(this, R.color.bg_call_screen_blur)
|
||||
|
@ -340,9 +378,6 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||
private fun handleViewEvents(event: VectorCallViewEvents?) {
|
||||
Timber.tag(loggerTag.value).v("handleViewEvents $event")
|
||||
when (event) {
|
||||
VectorCallViewEvents.DismissNoCall -> {
|
||||
finish()
|
||||
}
|
||||
is VectorCallViewEvents.ConnectionTimeout -> {
|
||||
onErrorTimoutConnect(event.turn)
|
||||
}
|
||||
|
@ -364,7 +399,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||
// TODO ask to use default stun, etc...
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.call_failed_no_connection)
|
||||
.setMessage(getString(R.string.call_failed_no_connection_description))
|
||||
.setMessage(R.string.call_failed_no_connection_description)
|
||||
.setNegativeButton(R.string.ok) { _, _ ->
|
||||
callViewModel.handle(VectorCallViewActions.EndCall)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.call.TurnServerResponse
|
|||
|
||||
sealed class VectorCallViewEvents : VectorViewEvents {
|
||||
|
||||
object DismissNoCall : VectorCallViewEvents()
|
||||
data class ConnectionTimeout(val turn: TurnServerResponse?) : VectorCallViewEvents()
|
||||
data class ShowSoundDeviceChooser(
|
||||
val available: Set<CallAudioManager.Device>,
|
||||
|
|
|
@ -137,9 +137,7 @@ class VectorCallViewModel @AssistedInject constructor(
|
|||
private val currentCallListener = object : WebRtcCallManager.CurrentCallListener {
|
||||
|
||||
override fun onCurrentCallChange(call: WebRtcCall?) {
|
||||
if (call == null) {
|
||||
_viewEvents.post(VectorCallViewEvents.DismissNoCall)
|
||||
} else {
|
||||
if (call != null) {
|
||||
updateOtherKnownCall(call)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ import io.reactivex.disposables.Disposable
|
|||
import io.reactivex.subjects.PublishSubject
|
||||
import io.reactivex.subjects.ReplaySubject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -91,6 +93,7 @@ private const val STREAM_ID = "userMedia"
|
|||
private const val AUDIO_TRACK_ID = "${STREAM_ID}a0"
|
||||
private const val VIDEO_TRACK_ID = "${STREAM_ID}v0"
|
||||
private val DEFAULT_AUDIO_CONSTRAINTS = MediaConstraints()
|
||||
private const val INVITE_TIMEOUT_IN_MS = 60_000L
|
||||
|
||||
private val loggerTag = LoggerTag("WebRtcCall", LoggerTag.VOIP)
|
||||
|
||||
|
@ -165,6 +168,8 @@ class WebRtcCall(
|
|||
}
|
||||
}
|
||||
|
||||
private var inviteTimeout: Deferred<Unit>? = null
|
||||
|
||||
// Mute status
|
||||
var micMuted = false
|
||||
private set
|
||||
|
@ -239,6 +244,10 @@ class WebRtcCall(
|
|||
if (mxCall.state == CallState.CreateOffer) {
|
||||
// send offer to peer
|
||||
mxCall.offerSdp(sessionDescription.description)
|
||||
inviteTimeout = async {
|
||||
delay(INVITE_TIMEOUT_IN_MS)
|
||||
endCall(EndCallReason.INVITE_TIMEOUT)
|
||||
}
|
||||
} else {
|
||||
mxCall.negotiate(sessionDescription.description, SdpType.OFFER)
|
||||
}
|
||||
|
@ -807,7 +816,7 @@ class WebRtcCall(
|
|||
return@launch
|
||||
}
|
||||
val reject = mxCall.state is CallState.LocalRinging
|
||||
terminate(EndCallReason.USER_HANGUP, reject)
|
||||
terminate(reason, reject)
|
||||
if (reject) {
|
||||
mxCall.reject()
|
||||
} else {
|
||||
|
@ -824,6 +833,8 @@ class WebRtcCall(
|
|||
val cameraManager = context.getSystemService<CameraManager>()!!
|
||||
cameraManager.unregisterAvailabilityCallback(cameraAvailabilityCallback)
|
||||
}
|
||||
inviteTimeout?.cancel()
|
||||
inviteTimeout = null
|
||||
mxCall.state = CallState.Ended(reason ?: EndCallReason.USER_HANGUP)
|
||||
release()
|
||||
onCallEnded(callId, reason ?: EndCallReason.USER_HANGUP, rejected)
|
||||
|
@ -845,6 +856,8 @@ class WebRtcCall(
|
|||
}
|
||||
|
||||
fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) {
|
||||
inviteTimeout?.cancel()
|
||||
inviteTimeout = null
|
||||
sessionScope?.launch(dispatcher) {
|
||||
Timber.tag(loggerTag.value).v("onCallAnswerReceived ${callAnswerContent.callId}")
|
||||
val sdp = SessionDescription(SessionDescription.Type.ANSWER, callAnswerContent.answer.sdp)
|
||||
|
|
|
@ -749,6 +749,9 @@
|
|||
<string name="call_held_by_user">%s held the call</string>
|
||||
<string name="call_held_by_you">You held the call</string>
|
||||
|
||||
<string name="call_ended_user_busy_title">User busy</string>
|
||||
<string name="call_ended_user_busy_description">The user you called is busy."</string>
|
||||
<string name="call_ended_invite_timeout_title">No answer</string>
|
||||
<string name="call_error_user_not_responding">The remote side failed to pick up.</string>
|
||||
<string name="call_error_ice_failed">Media Connection Failed</string>
|
||||
<string name="call_error_camera_init_failed">Cannot initialize the camera</string>
|
||||
|
|
Loading…
Reference in New Issue