synchronize setDescription calls

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java             |  1 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java | 30 
src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java       | 33 
3 files changed, 34 insertions(+), 30 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java πŸ”—

@@ -54,7 +54,6 @@ import javax.net.ssl.X509TrustManager;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.crypto.DomainHostnameVerifier;
 import eu.siacs.conversations.crypto.XmppDomainVerifier;
 import eu.siacs.conversations.crypto.axolotl.AxolotlService;
 import eu.siacs.conversations.crypto.sasl.Anonymous;

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java πŸ”—

@@ -311,7 +311,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
                 restartContentMap = existing.modifiedCredentials(newCredentials, IceUdpTransportInfo.Setup.ACTPASS);
             } else {
                 final IceUdpTransportInfo.Setup setup = getPeerDtlsSetup();
-                Log.d(Config.LOGTAG, "received confirmation of ICE restart" + newCredentials.values()+" peer_setup="+setup);
+                Log.d(Config.LOGTAG, "received confirmation of ICE restart" + newCredentials.values() + " peer_setup=" + setup);
                 // DTLS setup attribute needs to be rewritten to reflect current peer state
                 // https://groups.google.com/g/discuss-webrtc/c/DfpIMwvUfeM
                 restartContentMap = existing.modifiedCredentials(newCredentials, setup);
@@ -319,12 +319,18 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
             if (applyIceRestart(jinglePacket, restartContentMap, isOffer)) {
                 return isOffer;
             } else {
+                Log.d(Config.LOGTAG,"ignored ice restart. offer="+isOffer);
                 respondWithTieBreak(jinglePacket);
                 return true;
             }
         } catch (final Exception exception) {
             respondOk(jinglePacket);
             final Throwable rootCause = Throwables.getRootCause(exception);
+            if (rootCause instanceof WebRTCWrapper.PeerConnectionNotInitialized) {
+                Log.d(Config.LOGTAG,"ignoring PeerConnectionNotInitialized");
+                //TODO don’t respond OK but respond with out-of-order
+                return true;
+            }
             Log.d(Config.LOGTAG, "failure to apply ICE restart", rootCause);
             webRTCWrapper.close();
             sendSessionTerminate(Reason.ofThrowable(rootCause), rootCause.getMessage());
@@ -1466,21 +1472,18 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
         }
 
         final boolean neverConnected = !this.stateHistory.contains(PeerConnection.PeerConnectionState.CONNECTED);
-        final boolean failedOrDisconnected = Arrays.asList(
-                PeerConnection.PeerConnectionState.FAILED,
-                PeerConnection.PeerConnectionState.DISCONNECTED
-        ).contains(newState);
-
 
-        if (neverConnected && failedOrDisconnected) {
-            if (isTerminated()) {
-                Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": not sending session-terminate after connectivity error because session is already in state " + this.state);
+        if (newState == PeerConnection.PeerConnectionState.FAILED) {
+            if (neverConnected) {
+                if (isTerminated()) {
+                    Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": not sending session-terminate after connectivity error because session is already in state " + this.state);
+                    return;
+                }
+                webRTCWrapper.execute(this::closeWebRTCSessionAfterFailedConnection);
                 return;
+            } else {
+                webRTCWrapper.restartIce();
             }
-            webRTCWrapper.execute(this::closeWebRTCSessionAfterFailedConnection);
-        } else if (newState == PeerConnection.PeerConnectionState.FAILED) {
-            Log.d(Config.LOGTAG, "attempting to restart ICE");
-            webRTCWrapper.restartIce();
         }
         updateEndUserState();
     }
@@ -1491,6 +1494,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
     }
 
     private void initiateIceRestart() {
+        this.stateHistory.clear();
         this.webRTCWrapper.setIsReadyToReceiveIceCandidates(false);
         final SessionDescription sessionDescription;
         try {

src/main/java/eu/siacs/conversations/xmpp/jingle/WebRTCWrapper.java πŸ”—

@@ -431,7 +431,7 @@ public class WebRTCWrapper {
         videoTrack.setEnabled(enabled);
     }
 
-    ListenableFuture<SessionDescription> setLocalDescription() {
+    synchronized ListenableFuture<SessionDescription> setLocalDescription() {
         return Futures.transformAsync(getPeerConnectionFuture(), peerConnection -> {
             final SettableFuture<SessionDescription> future = SettableFuture.create();
             peerConnection.setLocalDescription(new SetSdpObserver() {
@@ -458,7 +458,7 @@ public class WebRTCWrapper {
         }
     }
 
-    ListenableFuture<Void> setRemoteDescription(final SessionDescription sessionDescription) {
+    synchronized ListenableFuture<Void> setRemoteDescription(final SessionDescription sessionDescription) {
         Log.d(EXTENDED_LOGGING_TAG, "setting remote description:");
         logDescription(sessionDescription);
         return Futures.transformAsync(getPeerConnectionFuture(), peerConnection -> {
@@ -482,12 +482,20 @@ public class WebRTCWrapper {
     private ListenableFuture<PeerConnection> getPeerConnectionFuture() {
         final PeerConnection peerConnection = this.peerConnection;
         if (peerConnection == null) {
-            return Futures.immediateFailedFuture(new IllegalStateException("initialize PeerConnection first"));
+            return Futures.immediateFailedFuture(new PeerConnectionNotInitialized());
         } else {
             return Futures.immediateFuture(peerConnection);
         }
     }
 
+    private PeerConnection requirePeerConnection() {
+        final PeerConnection peerConnection = this.peerConnection;
+        if (peerConnection == null) {
+            throw new PeerConnectionNotInitialized();
+        }
+        return peerConnection;
+    }
+
     void addIceCandidate(IceCandidate iceCandidate) {
         requirePeerConnection().addIceCandidate(iceCandidate);
     }
@@ -512,10 +520,15 @@ public class WebRTCWrapper {
         }
     }
 
-    public PeerConnection.PeerConnectionState getState() {
+    PeerConnection.PeerConnectionState getState() {
         return requirePeerConnection().connectionState();
     }
 
+    public PeerConnection.SignalingState getSignalingState() {
+        return requirePeerConnection().signalingState();
+    }
+
+
     EglBase.Context getEglBaseContext() {
         return this.eglBase.getEglBaseContext();
     }
@@ -528,14 +541,6 @@ public class WebRTCWrapper {
         return Optional.fromNullable(this.remoteVideoTrack);
     }
 
-    private PeerConnection requirePeerConnection() {
-        final PeerConnection peerConnection = this.peerConnection;
-        if (peerConnection == null) {
-            throw new PeerConnectionNotInitialized();
-        }
-        return peerConnection;
-    }
-
     private Context requireContext() {
         final Context context = this.context;
         if (context == null) {
@@ -552,10 +557,6 @@ public class WebRTCWrapper {
         executorService.execute(command);
     }
 
-    public PeerConnection.SignalingState getSignalingState() {
-        return requirePeerConnection().signalingState();
-    }
-
     public interface EventCallback {
         void onIceCandidate(IceCandidate iceCandidate);