tie breaking racing jingle message proposals. fixes #3698
This commit is contained in:
parent
2c5bed61a1
commit
4d3d3a7038
|
@ -9,6 +9,7 @@ import com.google.common.base.Preconditions;
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
|
import com.google.common.collect.ComparisonChain;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
@ -132,6 +133,40 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<RtpSessionProposal> findMatchingSessionProposal(final Account account, final Jid with, final Set<Media> media) {
|
||||||
|
synchronized (this.rtpSessionProposals) {
|
||||||
|
for (Map.Entry<RtpSessionProposal, DeviceDiscoveryState> entry : this.rtpSessionProposals.entrySet()) {
|
||||||
|
final RtpSessionProposal proposal = entry.getKey();
|
||||||
|
final DeviceDiscoveryState state = entry.getValue();
|
||||||
|
final boolean openProposal = state == DeviceDiscoveryState.DISCOVERED || state == DeviceDiscoveryState.SEARCHING;
|
||||||
|
if (openProposal
|
||||||
|
&& proposal.account == account
|
||||||
|
&& proposal.with.equals(with.asBareJid())
|
||||||
|
&& proposal.media.equals(media)) {
|
||||||
|
return Optional.of(proposal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasMatchingRtpSession(final Account account, final Jid with, final Set<Media> media) {
|
||||||
|
for (AbstractJingleConnection connection : this.connections.values()) {
|
||||||
|
if (connection instanceof JingleRtpConnection) {
|
||||||
|
final JingleRtpConnection rtpConnection = (JingleRtpConnection) connection;
|
||||||
|
if (rtpConnection.isTerminated()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rtpConnection.getId().account == account
|
||||||
|
&& rtpConnection.getId().with.asBareJid().equals(with.asBareJid())
|
||||||
|
&& rtpConnection.getMedia().equals(media)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isWithStrangerAndStrangerNotificationsAreOff(final Account account, Jid with) {
|
private boolean isWithStrangerAndStrangerNotificationsAreOff(final Account account, Jid with) {
|
||||||
final boolean notifyForStrangers = mXmppConnectionService.getNotificationService().notificationsFromStrangers();
|
final boolean notifyForStrangers = mXmppConnectionService.getNotificationService().notificationsFromStrangers();
|
||||||
if (notifyForStrangers) {
|
if (notifyForStrangers) {
|
||||||
|
@ -227,6 +262,26 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": encountered unknown media in session proposal. " + propose);
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": encountered unknown media in session proposal. " + propose);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final Optional<RtpSessionProposal> matchingSessionProposal = findMatchingSessionProposal(account, id.with, ImmutableSet.copyOf(media));
|
||||||
|
if (matchingSessionProposal.isPresent()) {
|
||||||
|
final String ourSessionId = matchingSessionProposal.get().sessionId;
|
||||||
|
final String theirSessionId = id.sessionId;
|
||||||
|
if (ComparisonChain.start()
|
||||||
|
.compare(ourSessionId, theirSessionId)
|
||||||
|
.compare(account.getJid().toEscapedString(), id.with.toEscapedString())
|
||||||
|
.result() > 0) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": our session lost tie break. automatically accepting their session. winning Session=" + theirSessionId);
|
||||||
|
//TODO a retract for this reason should probably include some indication of tie break
|
||||||
|
retractSessionProposal(matchingSessionProposal.get());
|
||||||
|
final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, from);
|
||||||
|
this.connections.put(id, rtpConnection);
|
||||||
|
rtpConnection.setProposedMedia(ImmutableSet.copyOf(media));
|
||||||
|
rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp);
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": our session won tie break. waiting for other party to accept. winningSession=" + ourSessionId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
final boolean stranger = isWithStrangerAndStrangerNotificationsAreOff(account, id.with);
|
final boolean stranger = isWithStrangerAndStrangerNotificationsAreOff(account, id.with);
|
||||||
if (isBusy() || stranger) {
|
if (isBusy() || stranger) {
|
||||||
writeLogMissedIncoming(account, id.with.asBareJid(), id.sessionId, serverMsgId, timestamp);
|
writeLogMissedIncoming(account, id.with.asBareJid(), id.sessionId, serverMsgId, timestamp);
|
||||||
|
@ -289,7 +344,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retrieved out of order jingle message");
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retrieved out of order jingle message"+message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -449,15 +504,20 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (matchingProposal != null) {
|
if (matchingProposal != null) {
|
||||||
|
retractSessionProposal(matchingProposal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void retractSessionProposal(RtpSessionProposal rtpSessionProposal) {
|
||||||
|
final Account account = rtpSessionProposal.account;
|
||||||
toneManager.transition(RtpEndUserState.ENDED);
|
toneManager.transition(RtpEndUserState.ENDED);
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retracting rtp session proposal with " + with);
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retracting rtp session proposal with " + rtpSessionProposal.with);
|
||||||
this.rtpSessionProposals.remove(matchingProposal);
|
this.rtpSessionProposals.remove(rtpSessionProposal);
|
||||||
final MessagePacket messagePacket = mXmppConnectionService.getMessageGenerator().sessionRetract(matchingProposal);
|
final MessagePacket messagePacket = mXmppConnectionService.getMessageGenerator().sessionRetract(rtpSessionProposal);
|
||||||
writeLogMissedOutgoing(account, matchingProposal.with, matchingProposal.sessionId, null, System.currentTimeMillis());
|
writeLogMissedOutgoing(account, rtpSessionProposal.with, rtpSessionProposal.sessionId, null, System.currentTimeMillis());
|
||||||
mXmppConnectionService.sendMessagePacket(account, messagePacket);
|
mXmppConnectionService.sendMessagePacket(account, messagePacket);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void proposeJingleRtpSession(final Account account, final Jid with, final Set<Media> media) {
|
public void proposeJingleRtpSession(final Account account, final Jid with, final Set<Media> media) {
|
||||||
synchronized (this.rtpSessionProposals) {
|
synchronized (this.rtpSessionProposals) {
|
||||||
|
@ -479,6 +539,10 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isBusy()) {
|
if (isBusy()) {
|
||||||
|
if (hasMatchingRtpSession(account, with, media)) {
|
||||||
|
Log.d(Config.LOGTAG, "ignoring request to propose jingle session because the other party already created one for us");
|
||||||
|
return;
|
||||||
|
}
|
||||||
throw new IllegalStateException("There is already a running RTP session. This should have been caught by the UI");
|
throw new IllegalStateException("There is already a running RTP session. This should have been caught by the UI");
|
||||||
}
|
}
|
||||||
final RtpSessionProposal proposal = RtpSessionProposal.of(account, with.asBareJid(), media);
|
final RtpSessionProposal proposal = RtpSessionProposal.of(account, with.asBareJid(), media);
|
||||||
|
|
|
@ -1066,6 +1066,9 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
return webRTCWrapper.isVideoEnabled();
|
return webRTCWrapper.isVideoEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVideoEnabled(final boolean enabled) {
|
||||||
|
webRTCWrapper.setVideoEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCameraSwitchable() {
|
public boolean isCameraSwitchable() {
|
||||||
return webRTCWrapper.isCameraSwitchable();
|
return webRTCWrapper.isCameraSwitchable();
|
||||||
|
@ -1079,10 +1082,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
return webRTCWrapper.switchCamera();
|
return webRTCWrapper.switchCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVideoEnabled(final boolean enabled) {
|
|
||||||
webRTCWrapper.setVideoEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAudioDeviceChanged(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set<AppRTCAudioManager.AudioDevice> availableAudioDevices) {
|
public void onAudioDeviceChanged(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set<AppRTCAudioManager.AudioDevice> availableAudioDevices) {
|
||||||
xmppConnectionService.notifyJingleRtpConnectionUpdate(selectedAudioDevice, availableAudioDevices);
|
xmppConnectionService.notifyJingleRtpConnectionUpdate(selectedAudioDevice, availableAudioDevices);
|
||||||
|
|
Loading…
Reference in New Issue