treat delayed destruction call integration as busy

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/CallIntegration.java                  | 15 
src/main/java/eu/siacs/conversations/services/CallIntegrationConnectionService.java |  6 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java       | 40 
3 files changed, 45 insertions(+), 16 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/CallIntegration.java 🔗

@@ -43,6 +43,7 @@ public class CallIntegration extends Connection {
     private AudioDevice initialAudioDevice = null;
     private final AtomicBoolean initialAudioDeviceConfigured = new AtomicBoolean(false);
     private final AtomicBoolean delayedDestructionInitiated = new AtomicBoolean(false);
+    private final AtomicBoolean isDestroyed = new AtomicBoolean(false);
 
     private List<CallEndpoint> availableEndpoints = Collections.emptyList();
 
@@ -363,7 +364,6 @@ public class CallIntegration extends Connection {
         final var toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, DEFAULT_VOLUME);
         toneGenerator.startTone(ToneGenerator.TONE_CDMA_CALLDROP_LITE, 375);
         this.destroyWithDelay(new DisconnectCause(DisconnectCause.ERROR, null), 375);
-        this.destroyWith(new DisconnectCause(DisconnectCause.ERROR, null));
     }
 
     public void retracted() {
@@ -389,7 +389,7 @@ public class CallIntegration extends Connection {
             JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.schedule(
                     () -> {
                         this.setDisconnected(disconnectCause);
-                        this.destroy();
+                        this.destroyCallIntegration();
                     },
                     delay,
                     TimeUnit.MILLISECONDS);
@@ -404,7 +404,7 @@ public class CallIntegration extends Connection {
             return;
         }
         this.setDisconnected(disconnectCause);
-        this.destroy();
+        this.destroyCallIntegration();
         Log.d(Config.LOGTAG, "destroyed!");
     }
 
@@ -472,6 +472,15 @@ public class CallIntegration extends Connection {
                                 audioManager.getAudioDevices()));
     }
 
+    private void destroyCallIntegration() {
+        super.destroy();
+        this.isDestroyed.set(true);
+    }
+
+    public boolean isDestroyed() {
+        return this.isDestroyed.get();
+    }
+
     /** AudioDevice is the names of possible audio devices that we currently support. */
     public enum AudioDevice {
         NONE,

src/main/java/eu/siacs/conversations/services/CallIntegrationConnectionService.java 🔗

@@ -347,14 +347,14 @@ public class CallIntegrationConnectionService extends ConnectionService {
         }
     }
 
-    public static void addNewIncomingCall(
+    public static boolean addNewIncomingCall(
             final Context context, final AbstractJingleConnection.Id id) {
         if (CallIntegration.notSelfManaged(context)) {
             Log.d(
                     Config.LOGTAG,
                     "not adding incoming call to TelecomManager on Android "
                             + Build.VERSION.RELEASE);
-            return;
+            return true;
         }
         final var phoneAccountHandle =
                 CallIntegrationConnectionService.getHandle(context, id.account);
@@ -373,7 +373,9 @@ public class CallIntegrationConnectionService extends ConnectionService {
                     Config.LOGTAG,
                     id.account.getJid().asBareJid() + ": call integration not available",
                     e);
+            return false;
         }
+        return true;
     }
 
     public static class ServiceConnectionService {

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

@@ -109,13 +109,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
                                     + sessionEnded
                                     + ", stranger="
                                     + stranger);
-                    mXmppConnectionService.sendIqPacket(
-                            account, packet.generateResponse(IqPacket.TYPE.RESULT), null);
-                    final JinglePacket sessionTermination =
-                            new JinglePacket(JinglePacket.Action.SESSION_TERMINATE, id.sessionId);
-                    sessionTermination.setTo(id.with);
-                    sessionTermination.setReason(Reason.BUSY, null);
-                    mXmppConnectionService.sendIqPacket(account, sessionTermination, null);
+                    sendSessionTerminate(account, packet, id);
                     if (busy || stranger) {
                         writeLogMissedIncoming(
                                 account,
@@ -136,7 +130,21 @@ public class JingleConnectionManager extends AbstractConnectionManager {
             connections.put(id, connection);
 
             if (connection instanceof JingleRtpConnection) {
-                CallIntegrationConnectionService.addNewIncomingCall(getXmppConnectionService(), id);
+                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();
@@ -147,14 +155,24 @@ public class JingleConnectionManager extends AbstractConnectionManager {
         }
     }
 
+    private void sendSessionTerminate(final Account account, final IqPacket request, final AbstractJingleConnection.Id id) {
+        mXmppConnectionService.sendIqPacket(
+                account, request.generateResponse(IqPacket.TYPE.RESULT), null);
+        final JinglePacket sessionTermination =
+                new JinglePacket(JinglePacket.Action.SESSION_TERMINATE, id.sessionId);
+        sessionTermination.setTo(id.with);
+        sessionTermination.setReason(Reason.BUSY, null);
+        mXmppConnectionService.sendIqPacket(account, sessionTermination, null);
+    }
+
     private boolean isUsingClearNet(final Account account) {
         return !account.isOnion() && !mXmppConnectionService.useTorToConnect();
     }
 
     public boolean isBusy() {
-        for (AbstractJingleConnection connection : this.connections.values()) {
-            if (connection instanceof JingleRtpConnection) {
-                if (connection.isTerminated()) {
+        for (final AbstractJingleConnection connection : this.connections.values()) {
+            if (connection instanceof JingleRtpConnection rtpConnection) {
+                if (connection.isTerminated() && rtpConnection.getCallIntegration().isDestroyed()) {
                     continue;
                 }
                 return true;