deliver session-initiate before integrating call

Daniel Gultsch created

otherwise there could potentially be race conditions with
showIncomingCallUi being called before we have media information

Change summary

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java | 44 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java     | 18 
2 files changed, 37 insertions(+), 25 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java 🔗

@@ -128,33 +128,31 @@ public class JingleConnectionManager extends AbstractConnectionManager {
                 return;
             }
             connections.put(id, connection);
-
-            if (connection instanceof JingleRtpConnection) {
-                if (!CallIntegrationConnectionService.addNewIncomingCall(
-                        mXmppConnectionService, id)) {
-                    connections.remove(id);
-                    Log.e(
-                            Config.LOGTAG,
-                            account.getJid().asBareJid() + ": could not add incoming call");
-                    sendSessionTerminate(account, packet, id);
-                    writeLogMissedIncoming(
-                            account,
-                            id.with,
-                            id.sessionId,
-                            null,
-                            System.currentTimeMillis(),
-                            false);
-                }
-            }
-
             mXmppConnectionService.updateConversationUi();
             connection.deliverPacket(packet);
+            if (connection instanceof JingleRtpConnection rtpConnection) {
+                addNewIncomingCall(rtpConnection);
+            }
         } else {
             Log.d(Config.LOGTAG, "unable to route jingle packet: " + packet);
             respondWithJingleError(account, packet, "unknown-session", "item-not-found", "cancel");
         }
     }
 
+    private void addNewIncomingCall(final JingleRtpConnection rtpConnection) {
+        if (rtpConnection.isTerminated()) {
+            Log.d(
+                    Config.LOGTAG,
+                    "skip call integration because something must have gone during initiate");
+            return;
+        }
+        if (CallIntegrationConnectionService.addNewIncomingCall(
+                mXmppConnectionService, rtpConnection.getId())) {
+            return;
+        }
+        rtpConnection.integrationFailure();
+    }
+
     private void sendSessionTerminate(final Account account, final IqPacket request, final AbstractJingleConnection.Id id) {
         mXmppConnectionService.sendIqPacket(
                 account, request.generateResponse(IqPacket.TYPE.RESULT), null);
@@ -398,9 +396,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
                         this.connections.put(id, rtpConnection);
                         rtpConnection.setProposedMedia(ImmutableSet.copyOf(media));
                         rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp);
-
-                        CallIntegrationConnectionService.addNewIncomingCall(
-                                getXmppConnectionService(), id);
+                        addNewIncomingCall(rtpConnection);
                         // TODO actually do the automatic accept?!
                     } else {
                         Log.d(
@@ -450,9 +446,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
                     this.connections.put(id, rtpConnection);
                     rtpConnection.setProposedMedia(ImmutableSet.copyOf(media));
                     rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp);
-
-                    CallIntegrationConnectionService.addNewIncomingCall(
-                            getXmppConnectionService(), id);
+                    addNewIncomingCall(rtpConnection);
                 }
             } else {
                 Log.d(

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java 🔗

@@ -2237,6 +2237,24 @@ public class JingleRtpConnection extends AbstractJingleConnection
         }
     }
 
+    public synchronized void integrationFailure() {
+        final var state = getState();
+        if (state == State.PROPOSED) {
+            Log.e(
+                    Config.LOGTAG,
+                    id.account.getJid().asBareJid()
+                            + ": failed call integration in state proposed");
+            rejectCallFromProposed();
+        } else if (state == State.SESSION_INITIALIZED) {
+            Log.e(Config.LOGTAG, id.account.getJid().asBareJid() + ": failed call integration");
+            this.webRTCWrapper.close();
+            sendSessionTerminate(Reason.FAILED_APPLICATION, "CallIntegration failed");
+        } else {
+            throw new IllegalStateException(
+                    String.format("Can not fail integration in state %s", state));
+        }
+    }
+
     public synchronized void endCall() {
         if (isTerminated()) {
             Log.w(