add helper methods for content modification to RtpContentMap
This commit is contained in:
parent
e2f98f6bbc
commit
f4be142e4d
|
@ -1,7 +1,9 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle;
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
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.ImmutableList;
|
||||||
|
@ -236,6 +238,23 @@ public class RtpContentMap {
|
||||||
throw new IllegalStateException("Content map doesn't have distinct DTLS setup");
|
throw new IllegalStateException("Content map doesn't have distinct DTLS setup");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DTLS getDistinctDtls() {
|
||||||
|
final Set<DTLS> dtlsSet =
|
||||||
|
ImmutableSet.copyOf(
|
||||||
|
Collections2.transform(
|
||||||
|
contents.values(),
|
||||||
|
dt -> {
|
||||||
|
final IceUdpTransportInfo.Fingerprint fp =
|
||||||
|
dt.transport.getFingerprint();
|
||||||
|
return new DTLS(fp.getHash(), fp.getSetup(), fp.getContent());
|
||||||
|
}));
|
||||||
|
final DTLS dtls = Iterables.getFirst(dtlsSet, null);
|
||||||
|
if (dtlsSet.size() == 1 && dtls != null) {
|
||||||
|
return dtls;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Content map doesn't have distinct DTLS setup");
|
||||||
|
}
|
||||||
|
|
||||||
public boolean emptyCandidates() {
|
public boolean emptyCandidates() {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (DescriptionTransport descriptionTransport : contents.values()) {
|
for (DescriptionTransport descriptionTransport : contents.values()) {
|
||||||
|
@ -262,12 +281,22 @@ public class RtpContentMap {
|
||||||
return new RtpContentMap(this.group, contentMapBuilder.build());
|
return new RtpContentMap(this.group, contentMapBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RtpContentMap toContentModification(final Collection<String> modifications) {
|
||||||
|
return new RtpContentMap(
|
||||||
|
this.group,
|
||||||
|
Maps.transformValues(
|
||||||
|
Maps.filterKeys(contents, Predicates.in(modifications)),
|
||||||
|
dt ->
|
||||||
|
new DescriptionTransport(
|
||||||
|
dt.senders, dt.description, IceUdpTransportInfo.STUB)));
|
||||||
|
}
|
||||||
|
|
||||||
public Diff diff(final RtpContentMap rtpContentMap) {
|
public Diff diff(final RtpContentMap rtpContentMap) {
|
||||||
final Set<String> existingContentIds = this.contents.keySet();
|
final Set<String> existingContentIds = this.contents.keySet();
|
||||||
final Set<String> newContentIds = rtpContentMap.contents.keySet();
|
final Set<String> newContentIds = rtpContentMap.contents.keySet();
|
||||||
return new Diff(
|
return new Diff(
|
||||||
Sets.difference(newContentIds, existingContentIds),
|
ImmutableSet.copyOf(Sets.difference(newContentIds, existingContentIds)),
|
||||||
Sets.difference(existingContentIds, newContentIds));
|
ImmutableSet.copyOf(Sets.difference(existingContentIds, newContentIds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean iceRestart(final RtpContentMap rtpContentMap) {
|
public boolean iceRestart(final RtpContentMap rtpContentMap) {
|
||||||
|
@ -278,6 +307,26 @@ public class RtpContentMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RtpContentMap addContent(final RtpContentMap modification) {
|
||||||
|
final IceUdpTransportInfo.Credentials credentials = getDistinctCredentials();
|
||||||
|
final DTLS dtls = getDistinctDtls();
|
||||||
|
final IceUdpTransportInfo iceUdpTransportInfo =
|
||||||
|
IceUdpTransportInfo.of(credentials, dtls.setup, dtls.hash, dtls.fingerprint);
|
||||||
|
final Map<String, DescriptionTransport> combined =
|
||||||
|
new ImmutableMap.Builder<String, DescriptionTransport>()
|
||||||
|
.putAll(contents)
|
||||||
|
.putAll(
|
||||||
|
Maps.transformValues(
|
||||||
|
modification.contents,
|
||||||
|
dt ->
|
||||||
|
new DescriptionTransport(
|
||||||
|
dt.senders,
|
||||||
|
dt.description,
|
||||||
|
iceUdpTransportInfo)))
|
||||||
|
.build();
|
||||||
|
return new RtpContentMap(modification.group, combined);
|
||||||
|
}
|
||||||
|
|
||||||
public static class DescriptionTransport {
|
public static class DescriptionTransport {
|
||||||
public final Content.Senders senders;
|
public final Content.Senders senders;
|
||||||
public final RtpDescription description;
|
public final RtpDescription description;
|
||||||
|
@ -370,4 +419,31 @@ public class RtpContentMap {
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class DTLS {
|
||||||
|
public final String hash;
|
||||||
|
public final IceUdpTransportInfo.Setup setup;
|
||||||
|
public final String fingerprint;
|
||||||
|
|
||||||
|
private DTLS(String hash, IceUdpTransportInfo.Setup setup, String fingerprint) {
|
||||||
|
this.hash = hash;
|
||||||
|
this.setup = setup;
|
||||||
|
this.fingerprint = fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
DTLS dtls = (DTLS) o;
|
||||||
|
return Objects.equal(hash, dtls.hash)
|
||||||
|
&& setup == dtls.setup
|
||||||
|
&& Objects.equal(fingerprint, dtls.fingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(hash, setup, fingerprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,15 +186,22 @@ public class WebRTCWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrack(RtpTransceiver transceiver) {
|
public void onTrack(final RtpTransceiver transceiver) {
|
||||||
Log.d(
|
Log.d(
|
||||||
EXTENDED_LOGGING_TAG,
|
EXTENDED_LOGGING_TAG,
|
||||||
"onTrack(mid="
|
"onTrack(mid="
|
||||||
+ transceiver.getMid()
|
+ transceiver.getMid()
|
||||||
+ ",media="
|
+ ",media="
|
||||||
+ transceiver.getMediaType()
|
+ transceiver.getMediaType()
|
||||||
|
+ ",direction="
|
||||||
|
+ transceiver.getDirection()
|
||||||
+ ")");
|
+ ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemoveTrack(final RtpReceiver receiver) {
|
||||||
|
Log.d(EXTENDED_LOGGING_TAG, "onRemoveTrack(" + receiver.id() + ")");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@Nullable private PeerConnectionFactory peerConnectionFactory = null;
|
@Nullable private PeerConnectionFactory peerConnectionFactory = null;
|
||||||
@Nullable private PeerConnection peerConnection = null;
|
@Nullable private PeerConnection peerConnection = null;
|
||||||
|
|
|
@ -12,8 +12,6 @@ import com.google.common.collect.Collections2;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -28,23 +26,29 @@ import eu.siacs.conversations.xmpp.jingle.SessionDescription;
|
||||||
|
|
||||||
public class IceUdpTransportInfo extends GenericTransportInfo {
|
public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
|
|
||||||
|
public static final IceUdpTransportInfo STUB = new IceUdpTransportInfo();
|
||||||
|
|
||||||
public IceUdpTransportInfo() {
|
public IceUdpTransportInfo() {
|
||||||
super("transport", Namespace.JINGLE_TRANSPORT_ICE_UDP);
|
super("transport", Namespace.JINGLE_TRANSPORT_ICE_UDP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IceUdpTransportInfo upgrade(final Element element) {
|
public static IceUdpTransportInfo upgrade(final Element element) {
|
||||||
Preconditions.checkArgument("transport".equals(element.getName()), "Name of provided element is not transport");
|
Preconditions.checkArgument(
|
||||||
Preconditions.checkArgument(Namespace.JINGLE_TRANSPORT_ICE_UDP.equals(element.getNamespace()), "Element does not match ice-udp transport namespace");
|
"transport".equals(element.getName()), "Name of provided element is not transport");
|
||||||
|
Preconditions.checkArgument(
|
||||||
|
Namespace.JINGLE_TRANSPORT_ICE_UDP.equals(element.getNamespace()),
|
||||||
|
"Element does not match ice-udp transport namespace");
|
||||||
final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo();
|
final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo();
|
||||||
transportInfo.setAttributes(element.getAttributes());
|
transportInfo.setAttributes(element.getAttributes());
|
||||||
transportInfo.setChildren(element.getChildren());
|
transportInfo.setChildren(element.getChildren());
|
||||||
return transportInfo;
|
return transportInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IceUdpTransportInfo of(SessionDescription sessionDescription, SessionDescription.Media media) {
|
public static IceUdpTransportInfo of(
|
||||||
|
SessionDescription sessionDescription, SessionDescription.Media media) {
|
||||||
final String ufrag = Iterables.getFirst(media.attributes.get("ice-ufrag"), null);
|
final String ufrag = Iterables.getFirst(media.attributes.get("ice-ufrag"), null);
|
||||||
final String pwd = Iterables.getFirst(media.attributes.get("ice-pwd"), null);
|
final String pwd = Iterables.getFirst(media.attributes.get("ice-pwd"), null);
|
||||||
IceUdpTransportInfo iceUdpTransportInfo = new IceUdpTransportInfo();
|
final IceUdpTransportInfo iceUdpTransportInfo = new IceUdpTransportInfo();
|
||||||
if (ufrag != null) {
|
if (ufrag != null) {
|
||||||
iceUdpTransportInfo.setAttribute("ufrag", ufrag);
|
iceUdpTransportInfo.setAttribute("ufrag", ufrag);
|
||||||
}
|
}
|
||||||
|
@ -56,7 +60,15 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
iceUdpTransportInfo.addChild(fingerprint);
|
iceUdpTransportInfo.addChild(fingerprint);
|
||||||
}
|
}
|
||||||
return iceUdpTransportInfo;
|
return iceUdpTransportInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IceUdpTransportInfo of(
|
||||||
|
final Credentials credentials, final Setup setup, final String hash, final String fingerprint) {
|
||||||
|
final IceUdpTransportInfo iceUdpTransportInfo = new IceUdpTransportInfo();
|
||||||
|
iceUdpTransportInfo.addChild(Fingerprint.of(setup, hash, fingerprint));
|
||||||
|
iceUdpTransportInfo.setAttribute("ufrag", credentials.ufrag);
|
||||||
|
iceUdpTransportInfo.setAttribute("pwd", credentials.password);
|
||||||
|
return iceUdpTransportInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Fingerprint getFingerprint() {
|
public Fingerprint getFingerprint() {
|
||||||
|
@ -91,7 +103,8 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
transportInfo.setAttribute("ufrag", credentials.ufrag);
|
transportInfo.setAttribute("ufrag", credentials.ufrag);
|
||||||
transportInfo.setAttribute("pwd", credentials.password);
|
transportInfo.setAttribute("pwd", credentials.password);
|
||||||
for (final Element child : getChildren()) {
|
for (final Element child : getChildren()) {
|
||||||
if (child.getName().equals("fingerprint") && Namespace.JINGLE_APPS_DTLS.equals(child.getNamespace())) {
|
if (child.getName().equals("fingerprint")
|
||||||
|
&& Namespace.JINGLE_APPS_DTLS.equals(child.getNamespace())) {
|
||||||
final Fingerprint fingerprint = new Fingerprint();
|
final Fingerprint fingerprint = new Fingerprint();
|
||||||
fingerprint.setAttributes(new Hashtable<>(child.getAttributes()));
|
fingerprint.setAttributes(new Hashtable<>(child.getAttributes()));
|
||||||
fingerprint.setContent(child.getContent());
|
fingerprint.setContent(child.getContent());
|
||||||
|
@ -231,7 +244,7 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
return getAttributeAsInt("rel-port");
|
return getAttributeAsInt("rel-port");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getType() { //TODO might be converted to enum
|
public String getType() { // TODO might be converted to enum
|
||||||
return getAttribute("type");
|
return getAttribute("type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +269,8 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
checkNotNullNoWhitespace(protocol, "protocol");
|
checkNotNullNoWhitespace(protocol, "protocol");
|
||||||
final String transport = protocol.toLowerCase(Locale.ROOT);
|
final String transport = protocol.toLowerCase(Locale.ROOT);
|
||||||
if (!"udp".equals(transport)) {
|
if (!"udp".equals(transport)) {
|
||||||
throw new IllegalArgumentException(String.format("'%s' is not a supported protocol", transport));
|
throw new IllegalArgumentException(
|
||||||
|
String.format("'%s' is not a supported protocol", transport));
|
||||||
}
|
}
|
||||||
final String priority = this.getAttribute("priority");
|
final String priority = this.getAttribute("priority");
|
||||||
checkNotNullNoWhitespace(priority, "priority");
|
checkNotNullNoWhitespace(priority, "priority");
|
||||||
|
@ -284,7 +298,15 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
if (ufrag != null) {
|
if (ufrag != null) {
|
||||||
additionalParameter.put("ufrag", ufrag);
|
additionalParameter.put("ufrag", ufrag);
|
||||||
}
|
}
|
||||||
final String parametersString = Joiner.on(' ').join(Collections2.transform(additionalParameter.entrySet(), input -> String.format("%s %s", input.getKey(), input.getValue())));
|
final String parametersString =
|
||||||
|
Joiner.on(' ')
|
||||||
|
.join(
|
||||||
|
Collections2.transform(
|
||||||
|
additionalParameter.entrySet(),
|
||||||
|
input ->
|
||||||
|
String.format(
|
||||||
|
"%s %s",
|
||||||
|
input.getKey(), input.getValue())));
|
||||||
return String.format(
|
return String.format(
|
||||||
"candidate:%s %s %s %s %s %s %s",
|
"candidate:%s %s %s %s %s %s %s",
|
||||||
foundation,
|
foundation,
|
||||||
|
@ -293,20 +315,19 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
priority,
|
priority,
|
||||||
connectionAddress,
|
connectionAddress,
|
||||||
port,
|
port,
|
||||||
parametersString
|
parametersString);
|
||||||
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkNotNullNoWhitespace(final String value, final String name) {
|
private static void checkNotNullNoWhitespace(final String value, final String name) {
|
||||||
if (Strings.isNullOrEmpty(value)) {
|
if (Strings.isNullOrEmpty(value)) {
|
||||||
throw new IllegalArgumentException(String.format("Parameter %s is missing or empty", name));
|
throw new IllegalArgumentException(
|
||||||
|
String.format("Parameter %s is missing or empty", name));
|
||||||
}
|
}
|
||||||
SessionDescription.checkNoWhitespace(value, String.format("Parameter %s contains white spaces", name));
|
SessionDescription.checkNoWhitespace(
|
||||||
|
value, String.format("Parameter %s contains white spaces", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Fingerprint extends Element {
|
public static class Fingerprint extends Element {
|
||||||
|
|
||||||
private Fingerprint() {
|
private Fingerprint() {
|
||||||
|
@ -340,11 +361,20 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Fingerprint of(final SessionDescription sessionDescription, final SessionDescription.Media media) {
|
public static Fingerprint of(
|
||||||
|
final SessionDescription sessionDescription, final SessionDescription.Media media) {
|
||||||
final Fingerprint fingerprint = of(media.attributes);
|
final Fingerprint fingerprint = of(media.attributes);
|
||||||
return fingerprint == null ? of(sessionDescription.attributes) : fingerprint;
|
return fingerprint == null ? of(sessionDescription.attributes) : fingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Fingerprint of(final Setup setup, final String hash, final String content) {
|
||||||
|
final Fingerprint fingerprint = new Fingerprint();
|
||||||
|
fingerprint.setContent(content);
|
||||||
|
fingerprint.setAttribute("hash", hash);
|
||||||
|
fingerprint.setAttribute("setup", setup.toString().toLowerCase(Locale.ROOT));
|
||||||
|
return fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHash() {
|
public String getHash() {
|
||||||
return this.getAttribute("hash");
|
return this.getAttribute("hash");
|
||||||
}
|
}
|
||||||
|
@ -356,7 +386,9 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Setup {
|
public enum Setup {
|
||||||
ACTPASS, PASSIVE, ACTIVE;
|
ACTPASS,
|
||||||
|
PASSIVE,
|
||||||
|
ACTIVE;
|
||||||
|
|
||||||
public static Setup of(String setup) {
|
public static Setup of(String setup) {
|
||||||
try {
|
try {
|
||||||
|
@ -373,7 +405,7 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
if (this == ACTIVE) {
|
if (this == ACTIVE) {
|
||||||
return PASSIVE;
|
return PASSIVE;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException(this.name()+" can not be flipped");
|
throw new IllegalStateException(this.name() + " can not be flipped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue