diff --git a/changelog.d/3710.feature b/changelog.d/3710.feature new file mode 100644 index 0000000000..74134d7ee5 --- /dev/null +++ b/changelog.d/3710.feature @@ -0,0 +1 @@ +Show missed call notification. \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt index 2dbd1c9b01..47a63b4a25 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.call +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason + sealed class CallState { /** Idle, setting up objects */ @@ -42,6 +44,6 @@ sealed class CallState { * */ data class Connected(val iceConnectionState: MxPeerConnectionState) : CallState() - /** Terminated. Incoming/Outgoing call, the call is terminated */ - object Terminated : CallState() + /** Ended. Incoming/Outgoing call, the call is terminated */ + data class Ended(val reason: EndCallReason? = null) : CallState() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt index fcc9f7072d..dd23e81cc6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.call import org.matrix.android.sdk.api.session.room.model.call.CallCandidate import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities -import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.matrix.android.sdk.api.util.Optional @@ -69,7 +69,7 @@ interface MxCall : MxCallDetail { /** * End the call */ - fun hangUp(reason: CallHangupContent.Reason? = null) + fun hangUp(reason: EndCallReason? = null) /** * Start a call diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt index 9d6e1a7eae..31f801dd6f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt @@ -43,29 +43,5 @@ data class CallHangupContent( * or `invite_timeout` for when the other party did not answer in time. * One of: ["ice_failed", "invite_timeout"] */ - @Json(name = "reason") val reason: Reason? = null -) : CallSignalingContent { - @JsonClass(generateAdapter = false) - enum class Reason { - @Json(name = "ice_failed") - ICE_FAILED, - - @Json(name = "ice_timeout") - ICE_TIMEOUT, - - @Json(name = "user_hangup") - USER_HANGUP, - - @Json(name = "replaced") - REPLACED, - - @Json(name = "user_media_failed") - USER_MEDIA_FAILED, - - @Json(name = "invite_timeout") - INVITE_TIMEOUT, - - @Json(name = "unknown_error") - UNKWOWN_ERROR - } -} + @Json(name = "reason") val reason: EndCallReason? = null +) : CallSignalingContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt index ea412fbe3e..1b9a7186e2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt @@ -36,5 +36,10 @@ data class CallRejectContent( /** * Required. The version of the VoIP specification this message adheres to. */ - @Json(name = "version") override val version: String? + @Json(name = "version") override val version: String?, + + /** + * Optional error reason for the reject. + */ + @Json(name = "reason") val reason: EndCallReason? = null ) : CallSignalingContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt new file mode 100644 index 0000000000..60e038b2f9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 org.matrix.android.sdk.api.session.room.model.call + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = false) +enum class EndCallReason { + @Json(name = "ice_failed") + ICE_FAILED, + + @Json(name = "ice_timeout") + ICE_TIMEOUT, + + @Json(name = "user_hangup") + USER_HANGUP, + + @Json(name = "replaced") + REPLACED, + + @Json(name = "user_media_failed") + USER_MEDIA_FAILED, + + @Json(name = "invite_timeout") + INVITE_TIMEOUT, + + @Json(name = "unknown_error") + UNKWOWN_ERROR, + + @Json(name = "user_busy") + USER_BUSY, + + @Json(name = "answered_elsewhere") + ANSWERED_ELSEWHERE +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index b0901af719..6863f52435 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -166,7 +166,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa Timber.v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } - if (call.state != CallState.Terminated) { + if (call.state !is CallState.Ended) { activeCallHandler.removeCall(content.callId) callListenersDispatcher.onCallHangupReceived(content) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt index f101685a4b..31f3e114e5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt @@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService @@ -153,20 +154,20 @@ internal class MxCallImpl( ) .let { createEventAndLocalEcho(type = EventType.CALL_REJECT, roomId = roomId, content = it.toContent()) } .also { eventSenderProcessor.postEvent(it) } - state = CallState.Terminated + state = CallState.Ended(reason = EndCallReason.USER_HANGUP) } - override fun hangUp(reason: CallHangupContent.Reason?) { + override fun hangUp(reason: EndCallReason?) { Timber.v("## VOIP hangup $callId") CallHangupContent( callId = callId, partyId = ourPartyId, - reason = reason ?: CallHangupContent.Reason.USER_HANGUP, + reason = reason ?: EndCallReason.USER_HANGUP, version = MxCall.VOIP_PROTO_VERSION.toString() ) .let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) } .also { eventSenderProcessor.postEvent(it) } - state = CallState.Terminated + state = CallState.Ended(reason) } override fun accept(sdpString: String) { diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index b0766d1cdb..e5ba2ea10c 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -37,7 +37,7 @@ import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.popup.IncomingCallAlert import im.vector.app.features.popup.PopupAlertManager -import org.matrix.android.sdk.api.session.content.ContentUrlResolver +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.util.MatrixItem import timber.log.Timber @@ -192,7 +192,8 @@ class CallService : VectorService() { private fun handleCallTerminated(intent: Intent) { val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" - val isRejected = intent.getBooleanExtra(EXTRA_IS_REJECTED, false) + val endCallReason = intent.getSerializableExtra(EXTRA_END_CALL_REASON) as EndCallReason + val rejected = intent.getBooleanExtra(EXTRA_END_CALL_REJECTED, false) alertManager.cancelAlert(callId) val terminatedCall = knownCalls.firstOrNull { it.callId == callId } if (terminatedCall == null) { @@ -206,13 +207,13 @@ class CallService : VectorService() { myStopSelf() } val wasConnected = connectedCallIds.remove(callId) - if (wasConnected || terminatedCall.isOutgoing || isRejected) { - val notification = notificationUtils.buildCallEndedNotification(terminatedCall.isVideoCall) - notificationManager.notify(callId.hashCode(), notification) - } else { + if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) { val notification = notificationUtils.buildCallMissedNotification(terminatedCall) notificationManager.cancel(callId.hashCode()) notificationManager.notify(MISSED_CALL_TAG, terminatedCall.nativeRoomId.hashCode(), notification) + } else { + val notification = notificationUtils.buildCallEndedNotification(terminatedCall.isVideoCall) + notificationManager.notify(callId.hashCode(), notification) } } @@ -287,7 +288,7 @@ class CallService : VectorService() { connections[callConnection.callId] = callConnection } - private fun WebRtcCall.toCallInformation(): CallInformation{ + private fun WebRtcCall.toCallInformation(): CallInformation { return CallInformation( callId = this.callId, nativeRoomId = this.nativeRoomId, @@ -306,7 +307,7 @@ class CallService : VectorService() { val opponentUserId: String, val matrixItem: MatrixItem?, val isVideoCall: Boolean, - val isOutgoing: Boolean, + val isOutgoing: Boolean ) companion object { @@ -324,7 +325,8 @@ class CallService : VectorService() { private const val EXTRA_CALL_ID = "EXTRA_CALL_ID" private const val EXTRA_IS_IN_BG = "EXTRA_IS_IN_BG" - private const val EXTRA_IS_REJECTED = "EXTRA_IS_REJECTED" + private const val EXTRA_END_CALL_REJECTED = "EXTRA_END_CALL_REJECTED" + private const val EXTRA_END_CALL_REASON = "EXTRA_END_CALL_REASON" fun onIncomingCallRinging(context: Context, callId: String, @@ -360,12 +362,13 @@ class CallService : VectorService() { ContextCompat.startForegroundService(context, intent) } - fun onCallTerminated(context: Context, callId: String, isRejected: Boolean) { + fun onCallTerminated(context: Context, callId: String, endCallReason: EndCallReason, rejected: Boolean) { val intent = Intent(context, CallService::class.java) .apply { action = ACTION_CALL_TERMINATED putExtra(EXTRA_CALL_ID, callId) - putExtra(EXTRA_IS_REJECTED, isRejected) + putExtra(EXTRA_END_CALL_REASON, endCallReason) + putExtra(EXTRA_END_CALL_REJECTED, rejected) } ContextCompat.startForegroundService(context, intent) } diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt index 1a54551072..3742de6271 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt @@ -118,7 +118,7 @@ class CallControlsView @JvmOverloads constructor( views.connectedControls.isVisible = false } } - is CallState.Terminated, + is CallState.Ended, null -> { views.ringingControls.isVisible = false views.connectedControls.isVisible = false diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 7e84811102..702f50af57 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -196,7 +196,7 @@ class VectorCallActivity : VectorBaseActivity(), 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 @@ -246,10 +246,10 @@ class VectorCallActivity : VectorBaseActivity(), CallContro views.callConnectingProgress.isVisible = true } } - is CallState.Terminated -> { + is CallState.Ended -> { finish() } - null -> { + null -> { } } } diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt index 0f37ccaa29..0217551260 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt @@ -57,7 +57,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState: private val call = callManager.getCallById(initialState.callId) private val callListener = object : WebRtcCall.Listener { override fun onStateUpdate(call: MxCall) { - if (call.state == CallState.Terminated) { + if (call.state is CallState.Ended) { _viewEvents.post(CallTransferViewEvents.Dismiss) } } diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 086a3be9d3..7ec6715b42 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -57,6 +57,9 @@ import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent +import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent +import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.threeten.bp.Duration import org.webrtc.AudioSource @@ -99,7 +102,7 @@ class WebRtcCall( private val sessionProvider: Provider, private val peerConnectionFactoryProvider: Provider, private val onCallBecomeActive: (WebRtcCall) -> Unit, - private val onCallEnded: (String, Boolean) -> Unit + private val onCallEnded: (String, EndCallReason, Boolean) -> Unit ) : MxCall.StateListener { interface Listener : MxCall.StateListener { @@ -227,7 +230,7 @@ class WebRtcCall( // Allow a short time for initial candidates to be gathered delay(200) } - if (mxCall.state == CallState.Terminated) { + if (mxCall.state is CallState.Ended) { return@launch } if (mxCall.state == CallState.CreateOffer) { @@ -285,7 +288,7 @@ class WebRtcCall( createCallId = CallIdGenerator.generate(), awaitCallId = null ) - endCall(sendEndSignaling = false) + terminate(EndCallReason.REPLACED) } } @@ -307,8 +310,8 @@ class WebRtcCall( createCallId = newCallId, awaitCallId = null ) - endCall(sendEndSignaling = false) - transferTargetCall.endCall(sendEndSignaling = false) + terminate(EndCallReason.REPLACED) + transferTargetCall.terminate(EndCallReason.REPLACED) } } @@ -461,7 +464,7 @@ class WebRtcCall( peerConnection?.awaitSetRemoteDescription(offerSdp) } catch (failure: Throwable) { Timber.v("Failure putting remote description") - endCall(true, CallHangupContent.Reason.UNKWOWN_ERROR) + endCall(reason = EndCallReason.UNKWOWN_ERROR) return@withContext } // 2) Access camera + microphone, create local stream @@ -767,7 +770,7 @@ class WebRtcCall( if (stream.audioTracks.size > 1 || stream.videoTracks.size > 1) { Timber.e("## VOIP StreamObserver weird looking stream: $stream") // TODO maybe do something more?? - endCall(true) + endCall(EndCallReason.UNKWOWN_ERROR) return@launch } if (stream.audioTracks.size == 1) { @@ -795,33 +798,34 @@ class WebRtcCall( } } - fun endCall(sendEndSignaling: Boolean = true, reason: CallHangupContent.Reason? = null) { + fun endCall(reason: EndCallReason? = null) { sessionScope?.launch(dispatcher) { - if (mxCall.state == CallState.Terminated) { + if (mxCall.state is CallState.Ended) { return@launch } - // Close tracks ASAP - localVideoTrack?.setEnabled(false) - localVideoTrack?.setEnabled(false) - cameraAvailabilityCallback?.let { cameraAvailabilityCallback -> - val cameraManager = context.getSystemService()!! - cameraManager.unregisterAvailabilityCallback(cameraAvailabilityCallback) - } - val wasRinging = mxCall.state is CallState.LocalRinging - mxCall.state = CallState.Terminated - release() - val isRejected = wasRinging && sendEndSignaling - onCallEnded(callId, isRejected) - if (sendEndSignaling) { - if (wasRinging) { - mxCall.reject() - } else { - mxCall.hangUp(reason) - } + val reject = mxCall.state is CallState.LocalRinging + terminate(EndCallReason.USER_HANGUP, reject) + if (reject) { + mxCall.reject() + } else { + mxCall.hangUp(reason) } } } + private suspend fun terminate(reason: EndCallReason? = null, rejected: Boolean = false) = withContext(dispatcher) { + // Close tracks ASAP + localVideoTrack?.setEnabled(false) + localVideoTrack?.setEnabled(false) + cameraAvailabilityCallback?.let { cameraAvailabilityCallback -> + val cameraManager = context.getSystemService()!! + cameraManager.unregisterAvailabilityCallback(cameraAvailabilityCallback) + } + mxCall.state = CallState.Ended(reason ?: EndCallReason.USER_HANGUP) + release() + onCallEnded(callId, reason ?: EndCallReason.USER_HANGUP, rejected) + } + // Call listener fun onCallIceCandidateReceived(iceCandidatesContent: CallCandidatesContent) { @@ -844,7 +848,7 @@ class WebRtcCall( try { peerConnection?.awaitSetRemoteDescription(sdp) } catch (failure: Throwable) { - endCall(true, CallHangupContent.Reason.UNKWOWN_ERROR) + endCall(EndCallReason.UNKWOWN_ERROR) return@launch } if (mxCall.opponentPartyId?.hasValue().orFalse()) { @@ -905,6 +909,29 @@ class WebRtcCall( } } + fun onCallHangupReceived(callHangupContent: CallHangupContent) { + sessionScope?.launch(dispatcher) { + terminate(callHangupContent.reason) + } + } + + fun onCallRejectReceived(callRejectContent: CallRejectContent) { + sessionScope?.launch(dispatcher) { + terminate(callRejectContent.reason, true) + } + } + + fun onCallSelectedAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) { + sessionScope?.launch(dispatcher) { + val selectedPartyId = callSelectAnswerContent.selectedPartyId + if (selectedPartyId != mxCall.ourPartyId) { + Timber.i("Got select_answer for party ID $selectedPartyId: we are party ID ${mxCall.ourPartyId}.") + // The other party has picked somebody else's answer + terminate() + } + } + } + fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) { sessionScope?.launch(dispatcher) { val session = sessionProvider.get() ?: return@launch diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index d7628cef90..24400afb42 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -29,7 +29,9 @@ import im.vector.app.features.call.lookup.CallProtocolsChecker import im.vector.app.features.call.lookup.CallUserMapper import im.vector.app.features.call.utils.EglUtils import im.vector.app.features.call.vectorCallService +import im.vector.app.features.session.coroutineScope import im.vector.app.push.fcm.FcmHelper +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.asCoroutineDispatcher import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull @@ -45,6 +47,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.webrtc.DefaultVideoDecoderFactory import org.webrtc.DefaultVideoEncoderFactory import org.webrtc.PeerConnectionFactory @@ -75,6 +78,9 @@ class WebRtcCallManager @Inject constructor( private val callUserMapper: CallUserMapper? get() = currentSession?.vectorCallService?.userMapper + private val sessionScope: CoroutineScope? + get() = currentSession?.coroutineScope + interface CurrentCallListener { fun onCurrentCallChange(call: WebRtcCall?) {} fun onAudioDevicesChange() {} @@ -232,12 +238,12 @@ class WebRtcCallManager @Inject constructor( this.currentCall.setAndNotify(call) } - private fun onCallEnded(callId: String, isRejected: Boolean) { + private fun onCallEnded(callId: String, endCallReason: EndCallReason, rejected: Boolean) { Timber.v("## VOIP WebRtcPeerConnectionManager onCall ended: $callId") val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also { Timber.v("On call ended for unknown call $callId") } - CallService.onCallTerminated(context, callId, isRejected) + CallService.onCallTerminated(context, callId, endCallReason, rejected) callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall) callsByRoomId[webRtcCall.nativeRoomId]?.remove(webRtcCall) transferees.remove(callId) @@ -329,8 +335,8 @@ class WebRtcCallManager @Inject constructor( return webRtcCall } - fun endCallForRoom(roomId: String, originatedByMe: Boolean = true) { - callsByRoomId[roomId]?.firstOrNull()?.endCall(originatedByMe) + fun endCallForRoom(roomId: String) { + callsByRoomId[roomId]?.firstOrNull()?.endCall() } override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) { @@ -386,7 +392,7 @@ class WebRtcCallManager @Inject constructor( ?: return Unit.also { Timber.w("onCallHangupReceived for non active call? ${callHangupContent.callId}") } - call.endCall(false) + call.onCallHangupReceived(callHangupContent) } override fun onCallRejectReceived(callRejectContent: CallRejectContent) { @@ -394,7 +400,7 @@ class WebRtcCallManager @Inject constructor( ?: return Unit.also { Timber.w("onCallRejectReceived for non active call? ${callRejectContent.callId}") } - call.endCall(false) + call.onCallRejectReceived(callRejectContent) } override fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) { @@ -402,12 +408,7 @@ class WebRtcCallManager @Inject constructor( ?: return Unit.also { Timber.w("onCallSelectAnswerReceived for non active call? ${callSelectAnswerContent.callId}") } - val selectedPartyId = callSelectAnswerContent.selectedPartyId - if (selectedPartyId != call.mxCall.ourPartyId) { - Timber.i("Got select_answer for party ID $selectedPartyId: we are party ID ${call.mxCall.ourPartyId}.") - // The other party has picked somebody else's answer - call.endCall(false) - } + call.onCallSelectedAnswerReceived(callSelectAnswerContent) } override fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent) { @@ -420,7 +421,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallManagedByOtherSession(callId: String) { Timber.v("## VOIP onCallManagedByOtherSession: $callId") - onCallEnded(callId, false) + onCallEnded(callId, EndCallReason.ANSWERED_ELSEWHERE, false) } override fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) {