fixed race conditions around PROCEED state. fixes #3989
This commit is contained in:
parent
6e3dc0eef6
commit
7330d8a7f0
|
@ -126,6 +126,7 @@ public abstract class AbstractJingleConnection {
|
||||||
ACCEPTED,
|
ACCEPTED,
|
||||||
PROCEED,
|
PROCEED,
|
||||||
REJECTED,
|
REJECTED,
|
||||||
|
REJECTED_RACED, //used when we want to reject but haven’t received session init yet
|
||||||
RETRACTED,
|
RETRACTED,
|
||||||
RETRACTED_RACED, //used when receiving a retract after we already asked to proceed
|
RETRACTED_RACED, //used when receiving a retract after we already asked to proceed
|
||||||
SESSION_INITIALIZED, //equal to 'PENDING'
|
SESSION_INITIALIZED, //equal to 'PENDING'
|
||||||
|
|
|
@ -60,6 +60,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
private static final List<State> TERMINATED = Arrays.asList(
|
private static final List<State> TERMINATED = Arrays.asList(
|
||||||
State.ACCEPTED,
|
State.ACCEPTED,
|
||||||
State.REJECTED,
|
State.REJECTED,
|
||||||
|
State.REJECTED_RACED,
|
||||||
State.RETRACTED,
|
State.RETRACTED,
|
||||||
State.RETRACTED_RACED,
|
State.RETRACTED_RACED,
|
||||||
State.TERMINATED_SUCCESS,
|
State.TERMINATED_SUCCESS,
|
||||||
|
@ -87,6 +88,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
State.TERMINATED_CONNECTIVITY_ERROR //only used when the xmpp connection rebinds
|
State.TERMINATED_CONNECTIVITY_ERROR //only used when the xmpp connection rebinds
|
||||||
));
|
));
|
||||||
transitionBuilder.put(State.PROCEED, ImmutableList.of(
|
transitionBuilder.put(State.PROCEED, ImmutableList.of(
|
||||||
|
State.REJECTED_RACED,
|
||||||
State.RETRACTED_RACED,
|
State.RETRACTED_RACED,
|
||||||
State.SESSION_INITIALIZED_PRE_APPROVED,
|
State.SESSION_INITIALIZED_PRE_APPROVED,
|
||||||
State.TERMINATED_SUCCESS,
|
State.TERMINATED_SUCCESS,
|
||||||
|
@ -523,10 +525,23 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receiveReject(Jid from, String serverMsgId, long timestamp) {
|
private void receiveReject(final Jid from, final String serverMsgId, final long timestamp) {
|
||||||
final boolean originatedFromMyself = from.asBareJid().equals(id.account.getJid().asBareJid());
|
final boolean originatedFromMyself = from.asBareJid().equals(id.account.getJid().asBareJid());
|
||||||
//reject from another one of my clients
|
//reject from another one of my clients
|
||||||
if (originatedFromMyself) {
|
if (originatedFromMyself) {
|
||||||
|
receiveRejectFromMyself(serverMsgId, timestamp);
|
||||||
|
} else if (isInitiator()) {
|
||||||
|
if (from.equals(id.with)) {
|
||||||
|
receiveRejectFromResponder();
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, id.account.getJid() + ": ignoring reject from " + from + " for session with " + id.with);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, id.account.getJid() + ": ignoring reject from " + from + " for session with " + id.with);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveRejectFromMyself(String serverMsgId, long timestamp) {
|
||||||
if (transition(State.REJECTED)) {
|
if (transition(State.REJECTED)) {
|
||||||
this.xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
|
this.xmppConnectionService.getNotificationService().cancelIncomingCallNotification();
|
||||||
this.finish();
|
this.finish();
|
||||||
|
@ -539,15 +554,26 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, "not able to transition into REJECTED because already in " + this.state);
|
Log.d(Config.LOGTAG, "not able to transition into REJECTED because already in " + this.state);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG, id.account.getJid() + ": ignoring reject from " + from + " for session with " + id.with);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void receiveRejectFromResponder() {
|
||||||
|
if (isInState(State.PROCEED)) {
|
||||||
|
Log.d(Config.LOGTAG, id.account.getJid() + ": received reject while still in proceed. callee reconsidered");
|
||||||
|
closeTransitionLogFinish(State.REJECTED_RACED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isInState(State.SESSION_INITIALIZED_PRE_APPROVED)) {
|
||||||
|
Log.d(Config.LOGTAG, id.account.getJid() + ": received reject while in SESSION_INITIATED_PRE_APPROVED. callee reconsidered before receiving session-init");
|
||||||
|
closeTransitionLogFinish(State.TERMINATED_DECLINED_OR_BUSY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.d(Config.LOGTAG, id.account.getJid() + ": ignoring reject from responder because already in state " + this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receivePropose(final Jid from, final Propose propose, final String serverMsgId, final long timestamp) {
|
private void receivePropose(final Jid from, final Propose propose, final String serverMsgId, final long timestamp) {
|
||||||
final boolean originatedFromMyself = from.asBareJid().equals(id.account.getJid().asBareJid());
|
final boolean originatedFromMyself = from.asBareJid().equals(id.account.getJid().asBareJid());
|
||||||
if (originatedFromMyself) {
|
if (originatedFromMyself) {
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": saw proposal from mysql. ignoring");
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": saw proposal from myself. ignoring");
|
||||||
} else if (transition(State.PROPOSED, () -> {
|
} else if (transition(State.PROPOSED, () -> {
|
||||||
final Collection<RtpDescription> descriptions = Collections2.transform(
|
final Collection<RtpDescription> descriptions = Collections2.transform(
|
||||||
Collections2.filter(propose.getDescriptions(), d -> d instanceof RtpDescription),
|
Collections2.filter(propose.getDescriptions(), d -> d instanceof RtpDescription),
|
||||||
|
@ -830,6 +856,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
return rtpConnectionStarted == 0 ? RtpEndUserState.CONNECTIVITY_ERROR : RtpEndUserState.CONNECTIVITY_LOST_ERROR;
|
return rtpConnectionStarted == 0 ? RtpEndUserState.CONNECTIVITY_ERROR : RtpEndUserState.CONNECTIVITY_LOST_ERROR;
|
||||||
}
|
}
|
||||||
case REJECTED:
|
case REJECTED:
|
||||||
|
case REJECTED_RACED:
|
||||||
case TERMINATED_DECLINED_OR_BUSY:
|
case TERMINATED_DECLINED_OR_BUSY:
|
||||||
if (isInitiator()) {
|
if (isInitiator()) {
|
||||||
return RtpEndUserState.DECLINED_OR_BUSY;
|
return RtpEndUserState.DECLINED_OR_BUSY;
|
||||||
|
@ -842,7 +869,11 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
case TERMINATED_CANCEL_OR_TIMEOUT:
|
case TERMINATED_CANCEL_OR_TIMEOUT:
|
||||||
return RtpEndUserState.ENDED;
|
return RtpEndUserState.ENDED;
|
||||||
case RETRACTED_RACED:
|
case RETRACTED_RACED:
|
||||||
|
if (isInitiator()) {
|
||||||
|
return RtpEndUserState.ENDED;
|
||||||
|
} else {
|
||||||
return RtpEndUserState.RETRACTED;
|
return RtpEndUserState.RETRACTED;
|
||||||
|
}
|
||||||
case TERMINATED_CONNECTIVITY_ERROR:
|
case TERMINATED_CONNECTIVITY_ERROR:
|
||||||
return rtpConnectionStarted == 0 ? RtpEndUserState.CONNECTIVITY_ERROR : RtpEndUserState.CONNECTIVITY_LOST_ERROR;
|
return rtpConnectionStarted == 0 ? RtpEndUserState.CONNECTIVITY_ERROR : RtpEndUserState.CONNECTIVITY_LOST_ERROR;
|
||||||
case TERMINATED_APPLICATION_FAILURE:
|
case TERMINATED_APPLICATION_FAILURE:
|
||||||
|
@ -938,10 +969,11 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isInState(State.PROCEED)) {
|
if (isInState(State.PROCEED)) {
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ending call while in state PROCEED just means ending the connection");
|
if (isInitiator()) {
|
||||||
this.webRTCWrapper.close();
|
retractFromProceed();
|
||||||
transitionOrThrow(State.TERMINATED_SUCCESS); //arguably this wasn't success; but not a real failure either
|
} else {
|
||||||
this.finish();
|
rejectCallFromProceed();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isInitiator() && isInState(State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED)) {
|
if (isInitiator() && isInState(State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED)) {
|
||||||
|
@ -965,6 +997,19 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
throw new IllegalStateException("called 'endCall' while in state " + this.state + ". isInitiator=" + isInitiator());
|
throw new IllegalStateException("called 'endCall' while in state " + this.state + ". isInitiator=" + isInitiator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void retractFromProceed() {
|
||||||
|
Log.d(Config.LOGTAG, "retract from proceed");
|
||||||
|
this.sendJingleMessage("retract");
|
||||||
|
closeTransitionLogFinish(State.RETRACTED_RACED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeTransitionLogFinish(final State state) {
|
||||||
|
this.webRTCWrapper.close();
|
||||||
|
transitionOrThrow(state);
|
||||||
|
writeLogMessage(state);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
private void setupWebRTC(final Set<Media> media, final List<PeerConnection.IceServer> iceServers) throws WebRTCWrapper.InitializationException {
|
private void setupWebRTC(final Set<Media> media, final List<PeerConnection.IceServer> iceServers) throws WebRTCWrapper.InitializationException {
|
||||||
this.jingleConnectionManager.ensureConnectionIsRegistered(this);
|
this.jingleConnectionManager.ensureConnectionIsRegistered(this);
|
||||||
final AppRTCAudioManager.SpeakerPhonePreference speakerPhonePreference;
|
final AppRTCAudioManager.SpeakerPhonePreference speakerPhonePreference;
|
||||||
|
@ -992,6 +1037,11 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void rejectCallFromProceed() {
|
||||||
|
this.sendJingleMessage("reject");
|
||||||
|
closeTransitionLogFinish(State.REJECTED_RACED);
|
||||||
|
}
|
||||||
|
|
||||||
private void rejectCallFromSessionInitiate() {
|
private void rejectCallFromSessionInitiate() {
|
||||||
webRTCWrapper.close();
|
webRTCWrapper.close();
|
||||||
sendSessionTerminate(Reason.DECLINE);
|
sendSessionTerminate(Reason.DECLINE);
|
||||||
|
|
Loading…
Reference in New Issue