process content-modify for pending content-adds
This commit is contained in:
parent
a8241c72df
commit
601a8cb3bc
|
@ -503,6 +503,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
sendSessionTerminate(Reason.FAILED_APPLICATION, cause.getMessage());
|
sendSessionTerminate(Reason.FAILED_APPLICATION, cause.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
processCandidates(receivedContentAccept.contents.entrySet());
|
||||||
updateEndUserState();
|
updateEndUserState();
|
||||||
Log.d(
|
Log.d(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
|
@ -516,7 +517,31 @@ public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
Maps.transformEntries(
|
Maps.transformEntries(
|
||||||
jinglePacket.getJingleContents(), (key, value) -> value.getSenders());
|
jinglePacket.getJingleContents(), (key, value) -> value.getSenders());
|
||||||
respondOk(jinglePacket);
|
respondOk(jinglePacket);
|
||||||
|
final RtpContentMap currentOutgoing = this.outgoingContentAdd;
|
||||||
|
final Set<String> currentOutgoingMediaIds = currentOutgoing == null ? Collections.emptySet() : currentOutgoing.contents.keySet();
|
||||||
Log.d(Config.LOGTAG, "receiveContentModification(" + modification + ")");
|
Log.d(Config.LOGTAG, "receiveContentModification(" + modification + ")");
|
||||||
|
if (currentOutgoing != null && currentOutgoingMediaIds.containsAll(modification.keySet())) {
|
||||||
|
final boolean isInitiator = isInitiator();
|
||||||
|
final RtpContentMap modifiedContentMap;
|
||||||
|
try {
|
||||||
|
modifiedContentMap = currentOutgoing.modifiedSendersChecked(isInitiator, modification);
|
||||||
|
} catch (final IllegalArgumentException e) {
|
||||||
|
webRTCWrapper.close();
|
||||||
|
sendSessionTerminate(Reason.FAILED_APPLICATION, e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.outgoingContentAdd = modifiedContentMap;
|
||||||
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid()+": processed content-modification for pending content-add");
|
||||||
|
} else {
|
||||||
|
webRTCWrapper.close();
|
||||||
|
sendSessionTerminate(
|
||||||
|
Reason.FAILED_APPLICATION,
|
||||||
|
String.format(
|
||||||
|
"%s only supports %s as a means to modify a not yet accepted %s",
|
||||||
|
BuildConfig.APP_NAME,
|
||||||
|
JinglePacket.Action.CONTENT_MODIFY,
|
||||||
|
JinglePacket.Action.CONTENT_ADD));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receiveContentReject(final JinglePacket jinglePacket) {
|
private void receiveContentReject(final JinglePacket jinglePacket) {
|
||||||
|
@ -613,7 +638,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
"%s only supports %s as a means to retract a not yet accepted %s",
|
"%s only supports %s as a means to retract a not yet accepted %s",
|
||||||
BuildConfig.APP_NAME,
|
BuildConfig.APP_NAME,
|
||||||
JinglePacket.Action.CONTENT_REMOVE,
|
JinglePacket.Action.CONTENT_REMOVE,
|
||||||
JinglePacket.Action.CONTENT_ACCEPT));
|
JinglePacket.Action.CONTENT_ADD));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -796,6 +821,8 @@ public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
// ICE-restart
|
// ICE-restart
|
||||||
// and if that's the case we are seeing an answer.
|
// and if that's the case we are seeing an answer.
|
||||||
// This might be more spec compliant but also more error prone potentially
|
// This might be more spec compliant but also more error prone potentially
|
||||||
|
final boolean isSignalStateStable = this.webRTCWrapper.getSignalingState() == PeerConnection.SignalingState.STABLE;
|
||||||
|
// TODO a stable signal state can be another indicator that we have an offer to restart ICE
|
||||||
final boolean isOffer = rtpContentMap.emptyCandidates();
|
final boolean isOffer = rtpContentMap.emptyCandidates();
|
||||||
final RtpContentMap restartContentMap;
|
final RtpContentMap restartContentMap;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -13,14 +13,6 @@ import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo;
|
||||||
|
@ -30,6 +22,14 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.OmemoVerifiedIceUdpTransportInfo;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.OmemoVerifiedIceUdpTransportInfo;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public class RtpContentMap {
|
public class RtpContentMap {
|
||||||
|
|
||||||
public final Group group;
|
public final Group group;
|
||||||
|
@ -94,7 +94,7 @@ public class RtpContentMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Content.Senders> getSenders() {
|
public Set<Content.Senders> getSenders() {
|
||||||
return ImmutableSet.copyOf(Collections2.transform(contents.values(),dt -> dt.senders));
|
return ImmutableSet.copyOf(Collections2.transform(contents.values(), dt -> dt.senders));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getNames() {
|
public List<String> getNames() {
|
||||||
|
@ -300,6 +300,57 @@ public class RtpContentMap {
|
||||||
dt -> new DescriptionTransport(senders, dt.description, dt.transport)));
|
dt -> new DescriptionTransport(senders, dt.description, dt.transport)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RtpContentMap modifiedSendersChecked(
|
||||||
|
final boolean isInitiator, final Map<String, Content.Senders> modification) {
|
||||||
|
final ImmutableMap.Builder<String, DescriptionTransport> contentMapBuilder =
|
||||||
|
new ImmutableMap.Builder<>();
|
||||||
|
for (final Map.Entry<String, DescriptionTransport> content : contents.entrySet()) {
|
||||||
|
final String id = content.getKey();
|
||||||
|
final DescriptionTransport descriptionTransport = content.getValue();
|
||||||
|
final Content.Senders currentSenders = descriptionTransport.senders;
|
||||||
|
final Content.Senders targetSenders = modification.get(id);
|
||||||
|
if (targetSenders == null || currentSenders == targetSenders) {
|
||||||
|
contentMapBuilder.put(id, descriptionTransport);
|
||||||
|
} else {
|
||||||
|
checkSenderModification(isInitiator, currentSenders, targetSenders);
|
||||||
|
contentMapBuilder.put(
|
||||||
|
id,
|
||||||
|
new DescriptionTransport(
|
||||||
|
targetSenders,
|
||||||
|
descriptionTransport.description,
|
||||||
|
descriptionTransport.transport));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new RtpContentMap(this.group, contentMapBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkSenderModification(
|
||||||
|
final boolean isInitiator,
|
||||||
|
final Content.Senders current,
|
||||||
|
final Content.Senders target) {
|
||||||
|
if (isInitiator) {
|
||||||
|
// we were both sending and now other party only wants to receive
|
||||||
|
if (current == Content.Senders.BOTH && target == Content.Senders.INITIATOR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// only we were sending but now other party wants to send too
|
||||||
|
if (current == Content.Senders.INITIATOR && target == Content.Senders.BOTH) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we were both sending and now other party only wants to receive
|
||||||
|
if (current == Content.Senders.BOTH && target == Content.Senders.RESPONDER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// only we were sending but now other party wants to send too
|
||||||
|
if (current == Content.Senders.RESPONDER && target == Content.Senders.BOTH) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format("Unsupported senders modification %s -> %s", current, target));
|
||||||
|
}
|
||||||
|
|
||||||
public RtpContentMap toContentModification(final Collection<String> modifications) {
|
public RtpContentMap toContentModification(final Collection<String> modifications) {
|
||||||
return new RtpContentMap(
|
return new RtpContentMap(
|
||||||
this.group,
|
this.group,
|
||||||
|
@ -323,7 +374,8 @@ public class RtpContentMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RtpContentMap activeContents() {
|
public RtpContentMap activeContents() {
|
||||||
return new RtpContentMap(group, Maps.filterValues(this.contents, dt -> dt.senders != Content.Senders.NONE));
|
return new RtpContentMap(
|
||||||
|
group, Maps.filterValues(this.contents, dt -> dt.senders != Content.Senders.NONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Diff diff(final RtpContentMap rtpContentMap) {
|
public Diff diff(final RtpContentMap rtpContentMap) {
|
||||||
|
@ -347,15 +399,32 @@ public class RtpContentMap {
|
||||||
final IceUdpTransportInfo.Credentials credentials = getDistinctCredentials();
|
final IceUdpTransportInfo.Credentials credentials = getDistinctCredentials();
|
||||||
final Collection<String> iceOptions = getCombinedIceOptions();
|
final Collection<String> iceOptions = getCombinedIceOptions();
|
||||||
final DTLS dtls = getDistinctDtls();
|
final DTLS dtls = getDistinctDtls();
|
||||||
final IceUdpTransportInfo iceUdpTransportInfo =
|
|
||||||
IceUdpTransportInfo.of(credentials, iceOptions, setup, dtls.hash, dtls.fingerprint);
|
|
||||||
final Map<String, DescriptionTransport> combined = merge(contents, modification.contents);
|
final Map<String, DescriptionTransport> combined = merge(contents, modification.contents);
|
||||||
final Map<String, DescriptionTransport> combinedFixedTransport =
|
final Map<String, DescriptionTransport> combinedFixedTransport =
|
||||||
Maps.transformValues(
|
Maps.transformValues(
|
||||||
combined,
|
combined,
|
||||||
dt ->
|
dt -> {
|
||||||
new DescriptionTransport(
|
final IceUdpTransportInfo iceUdpTransportInfo;
|
||||||
dt.senders, dt.description, iceUdpTransportInfo));
|
if (dt.transport.emptyCredentials()) {
|
||||||
|
iceUdpTransportInfo =
|
||||||
|
IceUdpTransportInfo.of(
|
||||||
|
credentials,
|
||||||
|
iceOptions,
|
||||||
|
setup,
|
||||||
|
dtls.hash,
|
||||||
|
dtls.fingerprint);
|
||||||
|
} else {
|
||||||
|
iceUdpTransportInfo =
|
||||||
|
IceUdpTransportInfo.of(
|
||||||
|
dt.transport.getCredentials(),
|
||||||
|
iceOptions,
|
||||||
|
setup,
|
||||||
|
dtls.hash,
|
||||||
|
dtls.fingerprint);
|
||||||
|
}
|
||||||
|
return new DescriptionTransport(
|
||||||
|
dt.senders, dt.description, iceUdpTransportInfo);
|
||||||
|
});
|
||||||
return new RtpContentMap(modification.group, combinedFixedTransport);
|
return new RtpContentMap(modification.group, combinedFixedTransport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,10 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
return new Credentials(ufrag, password);
|
return new Credentials(ufrag, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean emptyCredentials() {
|
||||||
|
return Strings.isNullOrEmpty(this.getAttribute("ufrag")) || Strings.isNullOrEmpty(this.getAttribute("pwd"));
|
||||||
|
}
|
||||||
|
|
||||||
public List<Candidate> getCandidates() {
|
public List<Candidate> getCandidates() {
|
||||||
final ImmutableList.Builder<Candidate> builder = new ImmutableList.Builder<>();
|
final ImmutableList.Builder<Candidate> builder = new ImmutableList.Builder<>();
|
||||||
for (final Element child : getChildren()) {
|
for (final Element child : getChildren()) {
|
||||||
|
|
Loading…
Reference in a new issue