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 b7e018abf..9cfda2174 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 34b6ac9ab..03bafb275 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 835560aa1..2f8486faa 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));