diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt index 859d47e03e..4d17148530 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt @@ -13,8 +13,6 @@ import android.telephony.PhoneStateListener import android.telephony.TelephonyManager import androidx.core.content.ContextCompat import dagger.hilt.android.AndroidEntryPoint -import org.session.libsession.messaging.messages.control.CallMessage -import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.utilities.Address import org.session.libsession.utilities.FutureTaskListener import org.session.libsession.utilities.TextSecurePreferences @@ -113,13 +111,14 @@ class WebRtcCallService: Service(), PeerConnection.Observer { .putExtra(EXTRA_CALL_ID, callId) .putExtra(EXTRA_REMOTE_DESCRIPTION, sdp) - fun iceCandidates(context: Context, iceCandidates: List, callId: UUID) = + fun iceCandidates(context: Context, address: Address, iceCandidates: List, callId: UUID) = Intent(context, WebRtcCallService::class.java) .setAction(ACTION_ICE_MESSAGE) .putExtra(EXTRA_CALL_ID, callId) .putExtra(EXTRA_ICE_SDP, iceCandidates.map(IceCandidate::sdp).toTypedArray()) .putExtra(EXTRA_ICE_SDP_LINE_INDEX, iceCandidates.map(IceCandidate::sdpMLineIndex).toIntArray()) .putExtra(EXTRA_ICE_SDP_MID, iceCandidates.map(IceCandidate::sdpMid).toTypedArray()) + .putExtra(EXTRA_RECIPIENT_ADDRESS, address) fun denyCallIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_DENY_CALL) @@ -283,8 +282,8 @@ class WebRtcCallService: Service(), PeerConnection.Observer { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setCallInProgressNotification(TYPE_INCOMING_RINGING, recipient) } - callManager.onIncomingRing(offer, callId, recipient, timestamp) callManager.clearPendingIceUpdates() + callManager.onIncomingRing(offer, callId, recipient, timestamp) callManager.postConnectionEvent(STATE_LOCAL_RINGING) if (TextSecurePreferences.isCallNotificationsEnabled(this)) { callManager.startIncomingRinger() @@ -481,7 +480,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer { private fun handleIceConnected(intent: Intent) { val recipient = callManager.recipient ?: return - if (callManager.currentConnectionState in arrayOf(STATE_ANSWERING, STATE_LOCAL_RINGING)) { + if (callManager.currentConnectionState in arrayOf(STATE_ANSWERING, STATE_DIALING)) { callManager.postConnectionEvent(STATE_CONNECTED) callManager.postViewModelState(CallViewModel.State.CALL_CONNECTED) } else { @@ -646,7 +645,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer { startService(intent) } else if (newState == FAILED) { val intent = Intent(this, WebRtcCallService::class.java) - .setAction(ACTION_REMOTE_HANGUP) + .setAction(ACTION_LOCAL_HANGUP) .putExtra(EXTRA_CALL_ID, callManager.callId) startService(intent) diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt index 3ffc28d1a7..a8478d6663 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallManager.kt @@ -108,7 +108,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne private val pendingOutgoingIceUpdates = ArrayDeque() private val pendingIncomingIceUpdates = ArrayDeque() - private val outgoingIceDebouncer = Debouncer(2_000L) + private val outgoingIceDebouncer = Debouncer(200L) var localRenderer: SurfaceViewRenderer? = null var remoteRenderer: SurfaceViewRenderer? = null @@ -224,6 +224,13 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne val expectedCallId = this.callId ?: return val expectedRecipient = this.recipient ?: return pendingOutgoingIceUpdates.add(iceCandidate) + + if (peerConnection?.readyForIce != true) return + + queueOutgoingIce(expectedCallId, expectedRecipient) + } + + private fun queueOutgoingIce(expectedCallId: UUID, expectedRecipient: Recipient) { outgoingIceDebouncer.publish { val currentCallId = this.callId ?: return@publish val currentRecipient = this.recipient ?: return@publish @@ -331,10 +338,6 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne localCameraState = newCameraState } - fun enableLocalCamera() { - setVideoEnabled(true) - } - fun onIncomingRing(offer: String, callId: UUID, recipient: Recipient, callTime: Long) { if (currentConnectionState != CallState.STATE_IDLE) return @@ -342,6 +345,7 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne this.recipient = recipient this.pendingOffer = offer this.pendingOfferTime = callTime + startIncomingRinger() } fun onIncomingCall(context: Context, isAlwaysTurn: Boolean = false): Promise { @@ -523,6 +527,10 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne val connection = peerConnection ?: throw AssertionError("assert") connection.setRemoteDescription(answer) + while (pendingIncomingIceUpdates.isNotEmpty()) { + connection.addIceCandidate(pendingIncomingIceUpdates.pop()) + } + queueOutgoingIce(callId, recipient) } fun handleRemoteIceCandidate(iceCandidates: List, callId: UUID) { @@ -531,11 +539,12 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne return } - peerConnection?.let { connection -> + val connection = peerConnection + if (connection != null && connection.readyForIce) { iceCandidates.forEach { candidate -> connection.addIceCandidate(candidate) } - } ?: run { + } else { pendingIncomingIceUpdates.addAll(iceCandidates) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt index 27c6af4002..cb5239b363 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt @@ -55,6 +55,7 @@ class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) { private fun handleIceCandidates(callMessage: CallMessage) { val callId = callMessage.callId ?: return + val sender = callMessage.sender ?: return val iceCandidates = callMessage.iceCandidates() if (iceCandidates.isEmpty()) return @@ -62,7 +63,8 @@ class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) { val iceIntent = WebRtcCallService.iceCandidates( context = context, iceCandidates = iceCandidates, - callId = callId + callId = callId, + address = Address.fromSerialized(sender) ) context.startService(iceIntent) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt index 93347c75ca..2b9464b757 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt @@ -24,6 +24,9 @@ class PeerConnectionWrapper(context: Context, private val videoSource: VideoSource? private val videoTrack: VideoTrack? + val readyForIce + get() = peerConnection.localDescription != null && peerConnection.remoteDescription != null + init { val stun = PeerConnection.IceServer.builder("stun:freyr.getsession.org:5349").createIceServer() val turn = PeerConnection.IceServer.builder("turn:freyr.getsession.org:5349").setUsername("webrtc").setPassword("webrtc").createIceServer()