add 20s busy timeout to incoming calls

This commit is contained in:
Daniel Gultsch 2020-04-22 21:59:20 +02:00
parent 22e93e4169
commit a008993d06
2 changed files with 38 additions and 2 deletions

View File

@ -23,6 +23,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
@ -50,6 +53,7 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import rocks.xmpp.addr.Jid; import rocks.xmpp.addr.Jid;
public class JingleConnectionManager extends AbstractConnectionManager { public class JingleConnectionManager extends AbstractConnectionManager {
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
private final HashMap<RtpSessionProposal, DeviceDiscoveryState> rtpSessionProposals = new HashMap<>(); private final HashMap<RtpSessionProposal, DeviceDiscoveryState> rtpSessionProposals = new HashMap<>();
private final Map<AbstractJingleConnection.Id, AbstractJingleConnection> connections = new ConcurrentHashMap<>(); private final Map<AbstractJingleConnection.Id, AbstractJingleConnection> connections = new ConcurrentHashMap<>();
@ -135,6 +139,10 @@ public class JingleConnectionManager extends AbstractConnectionManager {
return !contact.showInContactList(); return !contact.showInContactList();
} }
public ScheduledFuture<?> schedule(final Runnable runnable, final long delay, final TimeUnit timeUnit) {
return this.scheduledExecutorService.schedule(runnable, delay, timeUnit);
}
public void respondWithJingleError(final Account account, final IqPacket original, String jingleCondition, String condition, String conditionType) { public void respondWithJingleError(final Account account, final IqPacket original, String jingleCondition, String condition, String conditionType) {
final IqPacket response = original.generateResponse(IqPacket.TYPE.ERROR); final IqPacket response = original.generateResponse(IqPacket.TYPE.ERROR);
final Element error = response.addChild("error"); final Element error = response.addChild("error");

View File

@ -24,6 +24,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
@ -46,6 +48,8 @@ import rocks.xmpp.addr.Jid;
public class JingleRtpConnection extends AbstractJingleConnection implements WebRTCWrapper.EventCallback { public class JingleRtpConnection extends AbstractJingleConnection implements WebRTCWrapper.EventCallback {
private static final long BUSY_TIME_OUT = 20;
public static final List<State> STATES_SHOWING_ONGOING_CALL = Arrays.asList( public static final List<State> STATES_SHOWING_ONGOING_CALL = Arrays.asList(
State.PROCEED, State.PROCEED,
State.SESSION_INITIALIZED, State.SESSION_INITIALIZED,
@ -118,6 +122,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
private RtpContentMap initiatorRtpContentMap; private RtpContentMap initiatorRtpContentMap;
private RtpContentMap responderRtpContentMap; private RtpContentMap responderRtpContentMap;
private long rtpConnectionStarted = 0; //time of 'connected' private long rtpConnectionStarted = 0; //time of 'connected'
private ScheduledFuture<?> ringingTimeoutFuture;
JingleRtpConnection(JingleConnectionManager jingleConnectionManager, Id id, Jid initiator) { JingleRtpConnection(JingleConnectionManager jingleConnectionManager, Id id, Jid initiator) {
super(jingleConnectionManager, id, initiator); super(jingleConnectionManager, id, initiator);
@ -536,9 +541,29 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
private void startRinging() { private void startRinging() {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received call from " + id.with + ". start ringing"); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received call from " + id.with + ". start ringing");
ringingTimeoutFuture = jingleConnectionManager.schedule(this::ringingTimeout, BUSY_TIME_OUT, TimeUnit.SECONDS);
xmppConnectionService.getNotificationService().showIncomingCallNotification(id, getMedia()); xmppConnectionService.getNotificationService().showIncomingCallNotification(id, getMedia());
} }
private synchronized void ringingTimeout() {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": timeout reached for ringing");
switch (this.state) {
case PROPOSED:
rejectCallFromProposed();
break;
case SESSION_INITIALIZED:
rejectCallFromSessionInitiate();
break;
}
}
private void cancelRingingTimeout() {
final ScheduledFuture<?> future = this.ringingTimeoutFuture;
if (future != null && !future.isCancelled()) {
future.cancel(false);
}
}
private void receiveProceed(final Jid from, final String serverMsgId, final long timestamp) { private void receiveProceed(final Jid from, final String serverMsgId, final long timestamp) {
final Set<Media> media = Preconditions.checkNotNull(this.proposedMedia, "Proposed media has to be set before handling proceed"); final Set<Media> media = Preconditions.checkNotNull(this.proposedMedia, "Proposed media has to be set before handling proceed");
Preconditions.checkState(media.size() > 0, "Proposed media should not be empty"); Preconditions.checkState(media.size() > 0, "Proposed media should not be empty");
@ -781,17 +806,19 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
public synchronized void acceptCall() { public synchronized void acceptCall() {
switch (this.state) { switch (this.state) {
case PROPOSED: case PROPOSED:
cancelRingingTimeout();
acceptCallFromProposed(); acceptCallFromProposed();
break; break;
case SESSION_INITIALIZED: case SESSION_INITIALIZED:
cancelRingingTimeout();
acceptCallFromSessionInitialized(); acceptCallFromSessionInitialized();
break; break;
case ACCEPTED: case ACCEPTED:
Log.w(Config.LOGTAG,id.account.getJid().asBareJid()+": the call has already been accepted with another client. UI was just lagging behind"); Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": the call has already been accepted with another client. UI was just lagging behind");
break; break;
case PROCEED: case PROCEED:
case SESSION_ACCEPTED: case SESSION_ACCEPTED:
Log.w(Config.LOGTAG,id.account.getJid().asBareJid()+": the call has already been accepted. user probably double tapped the UI"); Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": the call has already been accepted. user probably double tapped the UI");
break; break;
default: default:
throw new IllegalStateException("Can not accept call from " + this.state); throw new IllegalStateException("Can not accept call from " + this.state);
@ -1069,6 +1096,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
} }
private void finish() { private void finish() {
this.cancelRingingTimeout();
this.webRTCWrapper.verifyClosed(); this.webRTCWrapper.verifyClosed();
this.jingleConnectionManager.finishConnection(this); this.jingleConnectionManager.finishConnection(this);
} }