From 552e17e39abe7af0faafcfc8580cb74a060716eb Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 11 Jun 2020 21:17:13 +0200 Subject: [PATCH] remember terminal RTP session state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit if the activity is not connected during finish it won’t receive the last end user state. this code remembers it even if the actual session is already gone. so when activity reconnects and we can’t find the real rtp session we can look up the last state instead. --- .../conversations/ui/RtpSessionActivity.java | 23 ++++++++++++++++- .../xmpp/jingle/JingleConnectionManager.java | 25 ++++++++++++++----- .../xmpp/jingle/JingleRtpConnection.java | 2 +- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index b7e018abf617b228a109b8a730ce05fc09cf32ab..9cfda2174447b4bfc24253e5e2146a7b83b79f88 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -53,6 +53,7 @@ import eu.siacs.conversations.utils.PermissionUtils; import eu.siacs.conversations.utils.TimeFrameUtils; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection; +import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.jingle.RtpEndUserState; @@ -427,7 +428,13 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe final WeakReference reference = xmppConnectionService.getJingleConnectionManager() .findJingleRtpConnection(account, with, sessionId); if (reference == null || reference.get() == null) { - throw new IllegalStateException("failed to initialize activity with running rtp session. session not found"); + final JingleConnectionManager.TerminatedRtpSession terminatedRtpSession = xmppConnectionService + .getJingleConnectionManager().getTerminalSessionState(with, sessionId); + if (terminatedRtpSession == null) { + throw new IllegalStateException("failed to initialize activity with running rtp session. session not found"); + } + initializeWithTerminatedSessionState(account, with, terminatedRtpSession); + return true; } this.rtpConnectionReference = reference; final RtpEndUserState currentState = requireRtpConnection().getEndUserState(); @@ -451,6 +458,20 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe return false; } + private void initializeWithTerminatedSessionState(final Account account, final Jid with, final JingleConnectionManager.TerminatedRtpSession terminatedRtpSession) { + Log.d(Config.LOGTAG,"initializeWithTerminatedSessionState()"); + if (terminatedRtpSession.state == RtpEndUserState.ENDED) { + finish(); + return; + } + RtpEndUserState state = terminatedRtpSession.state; + resetIntent(account, with, terminatedRtpSession.state, terminatedRtpSession.media); + updateButtonConfiguration(state); + updateStateDisplay(state); + updateProfilePicture(state); + binding.with.setText(account.getRoster().getContact(with).getDisplayName()); + } + private void reInitializeActivityWithRunningRtpSession(final Account account, Jid with, String sessionId) { runOnUiThread(() -> initializeActivityWithRunningRtpSession(account, with, sessionId)); resetIntent(account, with, sessionId); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 34b6ac9ab3af7a88191428391751e8cd595a6eaa..03bafb2751dce570585c981c090e1a30b75ac6a5 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -11,7 +11,6 @@ import com.google.common.cache.CacheBuilder; import com.google.common.collect.Collections2; import com.google.common.collect.ComparisonChain; import com.google.common.collect.ImmutableSet; -import com.google.j2objc.annotations.Weak; import java.lang.ref.WeakReference; import java.security.SecureRandom; @@ -57,8 +56,8 @@ public class JingleConnectionManager extends AbstractConnectionManager { private final HashMap rtpSessionProposals = new HashMap<>(); private final ConcurrentHashMap connections = new ConcurrentHashMap<>(); - private final Cache endedSessions = CacheBuilder.newBuilder() - .expireAfterWrite(30, TimeUnit.MINUTES) + private final Cache terminatedSessions = CacheBuilder.newBuilder() + .expireAfterWrite(24, TimeUnit.HOURS) .build(); private HashMap primaryCandidates = new HashMap<>(); @@ -92,7 +91,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { if (FileTransferDescription.NAMESPACES.contains(descriptionNamespace)) { connection = new JingleFileTransferConnection(this, id, from); } else if (Namespace.JINGLE_APPS_RTP.equals(descriptionNamespace) && !usesTor(account)) { - final boolean sessionEnded = this.endedSessions.asMap().containsKey(PersistableSessionId.of(id)); + final boolean sessionEnded = this.terminatedSessions.asMap().containsKey(PersistableSessionId.of(id)); final boolean stranger = isWithStrangerAndStrangerNotificationsAreOff(account, id.with); if (isBusy() || sessionEnded || stranger) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": rejected session with " + id.with + " because busy. sessionEnded=" + sessionEnded + ", stranger=" + stranger); @@ -684,8 +683,12 @@ public class JingleConnectionManager extends AbstractConnectionManager { throw e; } - void endSession(AbstractJingleConnection.Id id, final AbstractJingleConnection.State state) { - this.endedSessions.put(PersistableSessionId.of(id), state); + void setTerminalSessionState(AbstractJingleConnection.Id id, final RtpEndUserState state, final Set media) { + this.terminatedSessions.put(PersistableSessionId.of(id), new TerminatedRtpSession(state, media)); + } + + public TerminatedRtpSession getTerminalSessionState(final Jid with, final String sessionId) { + return this.terminatedSessions.getIfPresent(new PersistableSessionId(with, sessionId)); } private static class PersistableSessionId { @@ -716,6 +719,16 @@ public class JingleConnectionManager extends AbstractConnectionManager { } } + public static class TerminatedRtpSession { + public final RtpEndUserState state; + public final Set media; + + TerminatedRtpSession(RtpEndUserState state, Set media) { + this.state = state; + this.media = media; + } + } + public enum DeviceDiscoveryState { SEARCHING, DISCOVERED, FAILED; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 835560aa14593a12f3c9079bcf806e75d5ca34fa..2f8486faaf7bfb1c272827f7f13b35cc00449ba0 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -912,7 +912,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web } if (isInState(State.PROCEED)) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ending call while in state PROCEED just means ending the connection"); - this.jingleConnectionManager.endSession(id, State.TERMINATED_SUCCESS); this.webRTCWrapper.close(); transitionOrThrow(State.TERMINATED_SUCCESS); //arguably this wasn't success; but not a real failure either this.finish(); @@ -1189,6 +1188,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web if (isTerminated()) { this.cancelRingingTimeout(); this.webRTCWrapper.verifyClosed(); + this.jingleConnectionManager.setTerminalSessionState(id, getEndUserState(), getMedia()); this.jingleConnectionManager.finishConnectionOrThrow(this); } else { throw new IllegalStateException(String.format("Unable to call finish from %s", this.state));