create stub objects for most of what’s in description and transport

This commit is contained in:
Daniel Gultsch 2020-04-03 15:25:19 +02:00
parent 43cf1783a4
commit 4e13893662
7 changed files with 314 additions and 6 deletions

View file

@ -38,6 +38,7 @@ public final class Namespace {
public static final String JINGLE_APPS_DTLS = "urn:xmpp:jingle:apps:dtls:0"; public static final String JINGLE_APPS_DTLS = "urn:xmpp:jingle:apps:dtls:0";
public static final String JINGLE_FEATURE_AUDIO = "urn:xmpp:jingle:apps:rtp:audio"; public static final String JINGLE_FEATURE_AUDIO = "urn:xmpp:jingle:apps:rtp:audio";
public static final String JINGLE_FEATURE_VIDEO = "urn:xmpp:jingle:apps:rtp:video"; public static final String JINGLE_FEATURE_VIDEO = "urn:xmpp:jingle:apps:rtp:video";
public static final String JINGLE_RTP_HEADER_EXTENSIONS = "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0";
public static final String IBB = "http://jabber.org/protocol/ibb"; public static final String IBB = "http://jabber.org/protocol/ibb";
public static final String PING = "urn:xmpp:ping"; public static final String PING = "urn:xmpp:ping";
public static final String PUSH = "urn:xmpp:push:0"; public static final String PUSH = "urn:xmpp:push:0";

View file

@ -73,6 +73,7 @@ public class JingleRtpConnection extends AbstractJingleConnection {
final State oldState = this.state; final State oldState = this.state;
if (transition(State.SESSION_INITIALIZED)) { if (transition(State.SESSION_INITIALIZED)) {
if (oldState == State.PROCEED) { if (oldState == State.PROCEED) {
processContents(contents);
sendSessionAccept(); sendSessionAccept();
} else { } else {
//TODO start ringing //TODO start ringing
@ -82,6 +83,23 @@ public class JingleRtpConnection extends AbstractJingleConnection {
} }
} }
private void processContents(final Map<String,DescriptionTransport> contents) {
for(Map.Entry<String,DescriptionTransport> content : contents.entrySet()) {
final DescriptionTransport descriptionTransport = content.getValue();
final RtpDescription rtpDescription = descriptionTransport.description;
Log.d(Config.LOGTAG,"receive content with name "+content.getKey()+" and media="+rtpDescription.getMedia());
for(RtpDescription.PayloadType payloadType : rtpDescription.getPayloadTypes()) {
Log.d(Config.LOGTAG,"payload type: "+payloadType.toString());
}
for(RtpDescription.RtpHeaderExtension extension : rtpDescription.getHeaderExtensions()) {
Log.d(Config.LOGTAG,"extension: "+extension.toString());
}
final IceUdpTransportInfo iceUdpTransportInfo = descriptionTransport.transport;
Log.d(Config.LOGTAG,"transport: "+descriptionTransport.transport);
Log.d(Config.LOGTAG,"fingerprint "+iceUdpTransportInfo.getFingerprint());
}
}
void deliveryMessage(final Jid from, final Element message) { void deliveryMessage(final Jid from, final Element message) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": delivered message to JingleRtpConnection " + message); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": delivered message to JingleRtpConnection " + message);
switch (message.getName()) { switch (message.getName()) {
@ -175,7 +193,7 @@ public class JingleRtpConnection extends AbstractJingleConnection {
} }
} }
private static class DescriptionTransport { public static class DescriptionTransport {
private final RtpDescription description; private final RtpDescription description;
private final IceUdpTransportInfo transport; private final IceUdpTransportInfo transport;
@ -192,6 +210,7 @@ public class JingleRtpConnection extends AbstractJingleConnection {
if (description instanceof RtpDescription) { if (description instanceof RtpDescription) {
rtpDescription = (RtpDescription) description; rtpDescription = (RtpDescription) description;
} else { } else {
Log.d(Config.LOGTAG,"description was "+description);
throw new IllegalArgumentException("Content does not contain RtpDescription"); throw new IllegalArgumentException("Content does not contain RtpDescription");
} }
if (transportInfo instanceof IceUdpTransportInfo) { if (transportInfo instanceof IceUdpTransportInfo) {
@ -203,13 +222,13 @@ public class JingleRtpConnection extends AbstractJingleConnection {
} }
public static Map<String, DescriptionTransport> of(final Map<String,Content> contents) { public static Map<String, DescriptionTransport> of(final Map<String,Content> contents) {
return Maps.transformValues(contents, new Function<Content, DescriptionTransport>() { return ImmutableMap.copyOf(Maps.transformValues(contents, new Function<Content, DescriptionTransport>() {
@NullableDecl @NullableDecl
@Override @Override
public DescriptionTransport apply(@NullableDecl Content content) { public DescriptionTransport apply(@NullableDecl Content content) {
return content == null ? null : of(content); return content == null ? null : of(content);
} }
}); }));
} }
} }

View file

@ -0,0 +1,11 @@
package eu.siacs.conversations.xmpp.jingle;
import java.util.Map;
public class SdpUtils {
public static String toSdpString(Map<String, JingleRtpConnection.DescriptionTransport> contents) {
return "";
}
}

View file

@ -51,9 +51,11 @@ public class Content extends Element {
if (description == null) { if (description == null) {
return null; return null;
} }
final String xmlns = description.getNamespace(); final String namespace = description.getNamespace();
if (FileTransferDescription.NAMESPACES.contains(xmlns)) { if (FileTransferDescription.NAMESPACES.contains(namespace)) {
return FileTransferDescription.upgrade(description); return FileTransferDescription.upgrade(description);
} else if (Namespace.JINGLE_APPS_RTP.equals(namespace)) {
return RtpDescription.upgrade(description);
} else { } else {
return GenericDescription.upgrade(description); return GenericDescription.upgrade(description);
} }

View file

@ -1,6 +1,9 @@
package eu.siacs.conversations.xmpp.jingle.stanzas; package eu.siacs.conversations.xmpp.jingle.stanzas;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.List;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Namespace;
@ -11,6 +14,21 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
super(name, xmlns); super(name, xmlns);
} }
public Fingerprint getFingerprint() {
final Element fingerprint = this.findChild("fingerprint", Namespace.JINGLE_APPS_DTLS);
return fingerprint == null ? null : Fingerprint.upgrade(fingerprint);
}
public List<Candidate> getCandidates() {
final ImmutableList.Builder<Candidate> builder = new ImmutableList.Builder<>();
for(final Element child : getChildren()) {
if ("candidate".equals(child.getName())) {
builder.add(Candidate.upgrade(child));
}
}
return builder.build();
}
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("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"); Preconditions.checkArgument(Namespace.JINGLE_TRANSPORT_ICE_UDP.equals(element.getNamespace()), "Element does not match ice-udp transport namespace");
@ -19,4 +37,104 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
transportInfo.setChildren(element.getChildren()); transportInfo.setChildren(element.getChildren());
return transportInfo; return transportInfo;
} }
public static class Candidate extends Element {
private Candidate() {
super("candidate");
}
public int getComponent() {
return getAttributeAsInt("component");
}
public int getFoundation() {
return getAttributeAsInt("foundation");
}
public int getGeneration() {
return getAttributeAsInt("generation");
}
public String getId() {
return getAttribute("id");
}
public String getIp() {
return getAttribute("ip");
}
public int getNetwork() {
return getAttributeAsInt("network");
}
public int getPort() {
return getAttributeAsInt("port");
}
public int getPriority() {
return getAttributeAsInt("priority");
}
public String getProtocol() {
return getAttribute("protocol");
}
public String getRelAddr() {
return getAttribute("rel-addr");
}
public int getRelPort() {
return getAttributeAsInt("rel-port");
}
public String getType() { //TODO might be converted to enum
return getAttribute("type");
}
private int getAttributeAsInt(final String name) {
final String value = this.getAttribute(name);
if (value == null) {
return 0;
}
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return 0;
}
}
public static Candidate upgrade(final Element element) {
Preconditions.checkArgument("candidate".equals(element.getName()));
final Candidate candidate = new Candidate();
candidate.setAttributes(element.getAttributes());
candidate.setChildren(element.getChildren());
return candidate;
}
}
public static class Fingerprint extends Element {
public String getHash() {
return this.getAttribute("hash");
}
public String getSetup() {
return this.getAttribute("setup");
}
private Fingerprint() {
super("fingerprint", Namespace.JINGLE_APPS_DTLS);
}
public static Fingerprint upgrade(final Element element) {
Preconditions.checkArgument("fingerprint".equals(element.getName()));
Preconditions.checkArgument(Namespace.JINGLE_APPS_DTLS.equals(element.getNamespace()));
final Fingerprint fingerprint = new Fingerprint();
fingerprint.setAttributes(element.getAttributes());
fingerprint.setContent(element.getContent());
return fingerprint;
}
}
} }

View file

@ -38,7 +38,7 @@ public class JinglePacket extends IqPacket {
return jinglePacket; return jinglePacket;
} }
//TODO can have multiple contents //TODO deprecate this somehow and make file transfer fail if there are multiple (or something)
public Content getJingleContent() { public Content getJingleContent() {
final Element content = getJingleChild("content"); final Element content = getJingleChild("content");
return content == null ? null : Content.upgrade(content); return content == null ? null : Content.upgrade(content);

View file

@ -1,6 +1,10 @@
package eu.siacs.conversations.xmpp.jingle.stanzas; package eu.siacs.conversations.xmpp.jingle.stanzas;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Locale;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Namespace;
@ -12,6 +16,30 @@ public class RtpDescription extends GenericDescription {
super(name, namespace); super(name, namespace);
} }
public Media getMedia() {
return Media.of(this.getAttribute("media"));
}
public List<PayloadType> getPayloadTypes() {
final ImmutableList.Builder<PayloadType> builder = new ImmutableList.Builder<>();
for(Element child : getChildren()) {
if ("payload-type".equals(child.getName())) {
builder.add(PayloadType.of(child));
}
}
return builder.build();
}
public List<RtpHeaderExtension> getHeaderExtensions() {
final ImmutableList.Builder<RtpHeaderExtension> builder = new ImmutableList.Builder<>();
for(final Element child : getChildren()) {
if ("rtp-hdrext".equals(child.getName()) && Namespace.JINGLE_RTP_HEADER_EXTENSIONS.equals(child.getNamespace())) {
builder.add(RtpHeaderExtension.upgrade(child));
}
}
return builder.build();
}
public static RtpDescription upgrade(final Element element) { public static RtpDescription upgrade(final Element element) {
Preconditions.checkArgument("description".equals(element.getName()), "Name of provided element is not description"); Preconditions.checkArgument("description".equals(element.getName()), "Name of provided element is not description");
Preconditions.checkArgument(Namespace.JINGLE_APPS_RTP.equals(element.getNamespace()), "Element does not match the jingle rtp namespace"); Preconditions.checkArgument(Namespace.JINGLE_APPS_RTP.equals(element.getNamespace()), "Element does not match the jingle rtp namespace");
@ -20,4 +48,133 @@ public class RtpDescription extends GenericDescription {
description.setChildren(element.getChildren()); description.setChildren(element.getChildren());
return description; return description;
} }
//TODO: support for https://xmpp.org/extensions/xep-0293.html
public static class RtpHeaderExtension extends Element {
private RtpHeaderExtension() {
super("rtp-hdrext", Namespace.JINGLE_RTP_HEADER_EXTENSIONS);
}
public String getId() {
return this.getAttribute("id");
}
public String getUri() {
return this.getAttribute("uri");
}
public static RtpHeaderExtension upgrade(final Element element) {
Preconditions.checkArgument("rtp-hdrext".equals(element.getName()));
Preconditions.checkArgument(Namespace.JINGLE_RTP_HEADER_EXTENSIONS.equals(element.getNamespace()));
final RtpHeaderExtension extension = new RtpHeaderExtension();
extension.setAttributes(element.getAttributes());
extension.setChildren(element.getChildren());
return extension;
}
}
public static class PayloadType extends Element {
private PayloadType(String name, String xmlns) {
super(name, xmlns);
}
public String getId() {
return this.getAttribute("id");
}
public String getPayloadTypeName() {
return this.getAttribute("name");
}
public int getClockRate() {
final String clockRate = this.getAttribute("clockrate");
if (clockRate == null) {
return 0;
}
try {
return Integer.parseInt(clockRate);
} catch (NumberFormatException e) {
return 0;
}
}
public int getChannels() {
final String channels = this.getAttribute("channels");
if (channels == null) {
return 1; // The number of channels; if omitted, it MUST be assumed to contain one channel
}
try {
return Integer.parseInt(channels);
} catch (NumberFormatException e) {
return 1;
}
}
public List<Parameter> getParameters() {
final ImmutableList.Builder<Parameter> builder = new ImmutableList.Builder<>();
for (Element child : getChildren()) {
if ("parameter".equals(child.getName())) {
builder.add(Parameter.of(child));
}
}
return builder.build();
}
public static PayloadType of(final Element element) {
Preconditions.checkArgument("payload-type".equals(element.getName()), "element name must be called payload-type");
PayloadType payloadType = new PayloadType("payload-type", Namespace.JINGLE_APPS_RTP);
payloadType.setAttributes(element.getAttributes());
payloadType.setChildren(element.getChildren());
return payloadType;
}
}
public static class Parameter extends Element {
private Parameter() {
super("parameter", Namespace.JINGLE_APPS_RTP);
}
public Parameter(String name, String value) {
super("parameter", Namespace.JINGLE_APPS_RTP);
this.setAttribute("name", name);
this.setAttribute("value", value);
}
public String getParameterName() {
return this.getAttribute("name");
}
public String getParameterValue() {
return this.getAttribute("value");
}
public static Parameter of(final Element element) {
Preconditions.checkArgument("parameter".equals(element.getName()), "element name must be called parameter");
Parameter parameter = new Parameter();
parameter.setAttributes(element.getAttributes());
parameter.setChildren(element.getChildren());
return parameter;
}
}
public enum Media {
VIDEO, AUDIO, UNKNOWN;
@Override
public String toString() {
return super.toString().toLowerCase(Locale.ROOT);
}
public static Media of(String value) {
try {
return value == null ? UNKNOWN : Media.valueOf(value.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
return UNKNOWN;
}
}
}
} }