store entire transport info for after session was accepted. fixes #3790
This commit is contained in:
parent
a5430d5ce1
commit
fada3a63c9
|
@ -39,6 +39,7 @@ import eu.siacs.conversations.services.AppRTCAudioManager;
|
||||||
import eu.siacs.conversations.utils.IP;
|
import eu.siacs.conversations.utils.IP;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
||||||
|
@ -47,7 +48,6 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
|
||||||
|
|
||||||
public class JingleRtpConnection extends AbstractJingleConnection implements WebRTCWrapper.EventCallback {
|
public class JingleRtpConnection extends AbstractJingleConnection implements WebRTCWrapper.EventCallback {
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
}
|
}
|
||||||
|
|
||||||
private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this);
|
private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this);
|
||||||
private final ArrayDeque<IceCandidate> pendingIceCandidates = new ArrayDeque<>();
|
private final ArrayDeque<Set<Map.Entry<String, RtpContentMap.DescriptionTransport>>> pendingIceCandidates = new ArrayDeque<>();
|
||||||
private final Message message;
|
private final Message message;
|
||||||
private State state = State.NULL;
|
private State state = State.NULL;
|
||||||
private StateTransitionException stateTransitionException;
|
private StateTransitionException stateTransitionException;
|
||||||
|
@ -237,13 +237,12 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents; ignoring", e);
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents; ignoring", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final RtpContentMap rtpContentMap = isInitiator() ? this.responderRtpContentMap : this.initiatorRtpContentMap;
|
final Set<Map.Entry<String, RtpContentMap.DescriptionTransport>> candidates = contentMap.contents.entrySet();
|
||||||
final Group originalGroup = rtpContentMap != null ? rtpContentMap.group : null;
|
if (this.state == State.SESSION_ACCEPTED) {
|
||||||
final List<String> identificationTags = originalGroup == null ? Collections.emptyList() : originalGroup.getIdentificationTags();
|
processCandidates(candidates);
|
||||||
if (identificationTags.size() == 0) {
|
} else {
|
||||||
Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": no identification tags found in initial offer. we won't be able to calculate mLineIndices");
|
pendingIceCandidates.push(candidates);
|
||||||
}
|
}
|
||||||
receiveCandidates(identificationTags, contentMap.contents.entrySet());
|
|
||||||
} else {
|
} else {
|
||||||
if (isTerminated()) {
|
if (isTerminated()) {
|
||||||
respondOk(jinglePacket);
|
respondOk(jinglePacket);
|
||||||
|
@ -255,7 +254,17 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receiveCandidates(final List<String> identificationTags, final Set<Map.Entry<String, RtpContentMap.DescriptionTransport>> contents) {
|
private void processCandidates(final Set<Map.Entry<String, RtpContentMap.DescriptionTransport>> contents) {
|
||||||
|
final RtpContentMap rtpContentMap = isInitiator() ? this.responderRtpContentMap : this.initiatorRtpContentMap;
|
||||||
|
final Group originalGroup = rtpContentMap.group;
|
||||||
|
final List<String> identificationTags = originalGroup == null ? rtpContentMap.getNames() : originalGroup.getIdentificationTags();
|
||||||
|
if (identificationTags.size() == 0) {
|
||||||
|
Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": no identification tags found in initial offer. we won't be able to calculate mLineIndices");
|
||||||
|
}
|
||||||
|
processCandidates(identificationTags, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processCandidates(final List<String> indices, final Set<Map.Entry<String, RtpContentMap.DescriptionTransport>> contents) {
|
||||||
for (final Map.Entry<String, RtpContentMap.DescriptionTransport> content : contents) {
|
for (final Map.Entry<String, RtpContentMap.DescriptionTransport> content : contents) {
|
||||||
final String ufrag = content.getValue().transport.getAttribute("ufrag");
|
final String ufrag = content.getValue().transport.getAttribute("ufrag");
|
||||||
for (final IceUdpTransportInfo.Candidate candidate : content.getValue().transport.getCandidates()) {
|
for (final IceUdpTransportInfo.Candidate candidate : content.getValue().transport.getCandidates()) {
|
||||||
|
@ -267,15 +276,10 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final String sdpMid = content.getKey();
|
final String sdpMid = content.getKey();
|
||||||
final int mLineIndex = identificationTags.indexOf(sdpMid);
|
final int mLineIndex = indices.indexOf(sdpMid);
|
||||||
final IceCandidate iceCandidate = new IceCandidate(sdpMid, mLineIndex, sdp);
|
final IceCandidate iceCandidate = new IceCandidate(sdpMid, mLineIndex, sdp);
|
||||||
if (isInState(State.SESSION_ACCEPTED)) {
|
Log.d(Config.LOGTAG, "received candidate: " + iceCandidate);
|
||||||
Log.d(Config.LOGTAG, "received candidate: " + iceCandidate);
|
this.webRTCWrapper.addIceCandidate(iceCandidate);
|
||||||
this.webRTCWrapper.addIceCandidate(iceCandidate);
|
|
||||||
} else {
|
|
||||||
this.pendingIceCandidates.offer(iceCandidate);
|
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": put ICE candidate on backlog");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,8 +322,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
}
|
}
|
||||||
if (transition(target, () -> this.initiatorRtpContentMap = contentMap)) {
|
if (transition(target, () -> this.initiatorRtpContentMap = contentMap)) {
|
||||||
respondOk(jinglePacket);
|
respondOk(jinglePacket);
|
||||||
final List<String> identificationTags = contentMap.group == null ? Collections.emptyList() : contentMap.group.getIdentificationTags();
|
pendingIceCandidates.push(contentMap.contents.entrySet());
|
||||||
receiveCandidates(identificationTags, contentMap.contents.entrySet());
|
|
||||||
if (target == State.SESSION_INITIALIZED_PRE_APPROVED) {
|
if (target == State.SESSION_INITIALIZED_PRE_APPROVED) {
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": automatically accepting session-initiate");
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": automatically accepting session-initiate");
|
||||||
sendSessionAccept();
|
sendSessionAccept();
|
||||||
|
@ -364,8 +367,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
if (transition(State.SESSION_ACCEPTED)) {
|
if (transition(State.SESSION_ACCEPTED)) {
|
||||||
respondOk(jinglePacket);
|
respondOk(jinglePacket);
|
||||||
receiveSessionAccept(contentMap);
|
receiveSessionAccept(contentMap);
|
||||||
final List<String> identificationTags = contentMap.group == null ? Collections.emptyList() : contentMap.group.getIdentificationTags();
|
final List<String> identificationTags = contentMap.group == null ? contentMap.getNames() : contentMap.group.getIdentificationTags();
|
||||||
receiveCandidates(identificationTags, contentMap.contents.entrySet());
|
processCandidates(identificationTags, contentMap.contents.entrySet());
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, String.format("%s: received session-accept while in state %s", id.account.getJid().asBareJid(), state));
|
Log.d(Config.LOGTAG, String.format("%s: received session-accept while in state %s", id.account.getJid().asBareJid(), state));
|
||||||
respondOk(jinglePacket);
|
respondOk(jinglePacket);
|
||||||
|
@ -451,9 +454,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
|
|
||||||
private void addIceCandidatesFromBlackLog() {
|
private void addIceCandidatesFromBlackLog() {
|
||||||
while (!this.pendingIceCandidates.isEmpty()) {
|
while (!this.pendingIceCandidates.isEmpty()) {
|
||||||
final IceCandidate iceCandidate = this.pendingIceCandidates.poll();
|
processCandidates(this.pendingIceCandidates.poll());
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": added ICE candidate from back log " + iceCandidate);
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": added candidates from back log");
|
||||||
this.webRTCWrapper.addIceCandidate(iceCandidate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +463,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
this.responderRtpContentMap = rtpContentMap;
|
this.responderRtpContentMap = rtpContentMap;
|
||||||
this.transitionOrThrow(State.SESSION_ACCEPTED);
|
this.transitionOrThrow(State.SESSION_ACCEPTED);
|
||||||
final JinglePacket sessionAccept = rtpContentMap.toJinglePacket(JinglePacket.Action.SESSION_ACCEPT, id.sessionId);
|
final JinglePacket sessionAccept = rtpContentMap.toJinglePacket(JinglePacket.Action.SESSION_ACCEPT, id.sessionId);
|
||||||
Log.d(Config.LOGTAG, sessionAccept.toString());
|
|
||||||
send(sessionAccept);
|
send(sessionAccept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -890,7 +891,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
|
|
||||||
public synchronized void rejectCall() {
|
public synchronized void rejectCall() {
|
||||||
if (isTerminated()) {
|
if (isTerminated()) {
|
||||||
Log.w(Config.LOGTAG,id.account.getJid().asBareJid()+": received rejectCall() when session has already been terminated. nothing to do");
|
Log.w(Config.LOGTAG, id.account.getJid().asBareJid() + ": received rejectCall() when session has already been terminated. nothing to do");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (this.state) {
|
switch (this.state) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.google.common.base.Function;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
@ -13,6 +14,7 @@ import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
|
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -23,7 +25,6 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
|
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
||||||
|
|
||||||
public class RtpContentMap {
|
public class RtpContentMap {
|
||||||
|
@ -59,6 +60,10 @@ public class RtpContentMap {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getNames() {
|
||||||
|
return ImmutableList.copyOf(contents.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
void requireContentDescriptions() {
|
void requireContentDescriptions() {
|
||||||
if (this.contents.size() == 0) {
|
if (this.contents.size() == 0) {
|
||||||
throw new IllegalStateException("No contents available");
|
throw new IllegalStateException("No contents available");
|
||||||
|
|
Loading…
Reference in a new issue