create objects for ssma (xep-0339)

This commit is contained in:
Daniel Gultsch 2020-04-05 08:23:38 +02:00
parent 28ead10ca4
commit ef51ec2c1d
2 changed files with 99 additions and 3 deletions

View file

@ -40,6 +40,7 @@ public final class Namespace {
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 JINGLE_RTP_HEADER_EXTENSIONS = "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0";
public static final String JINGLE_RTP_FEEDBACK_NEGOTIATION = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0"; public static final String JINGLE_RTP_FEEDBACK_NEGOTIATION = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0";
public static final String JINGLE_RTP_SOURCE_SPECIFIC_MEDIA_ATTRIBUTES = "urn:xmpp:jingle:apps:rtp:ssma: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

@ -1,18 +1,17 @@
package eu.siacs.conversations.xmpp.jingle.stanzas; package eu.siacs.conversations.xmpp.jingle.stanzas;
import android.util.Log;
import android.util.Pair; import android.util.Pair;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import eu.siacs.conversations.Config;
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.jingle.SessionDescription; import eu.siacs.conversations.xmpp.jingle.SessionDescription;
@ -56,6 +55,16 @@ public class RtpDescription extends GenericDescription {
return builder.build(); return builder.build();
} }
public List<Source> getSources() {
final ImmutableList.Builder<Source> builder = new ImmutableList.Builder<>();
for (final Element child : this.children) {
if ("source".equals(child.getName()) && Namespace.JINGLE_RTP_SOURCE_SPECIFIC_MEDIA_ATTRIBUTES.equals(child.getNamespace())) {
builder.add(Source.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");
@ -348,6 +357,78 @@ public class RtpDescription extends GenericDescription {
} }
} }
//XEP-0339: Source-Specific Media Attributes in Jingle
//maps to `a=ssrc:<ssrc-id> <attribute>:<value>`
public static class Source extends Element {
private Source() {
super("source", Namespace.JINGLE_RTP_SOURCE_SPECIFIC_MEDIA_ATTRIBUTES);
}
public Source(String ssrcId, Collection<Parameter> parameters) {
super("source", Namespace.JINGLE_RTP_SOURCE_SPECIFIC_MEDIA_ATTRIBUTES);
this.setAttribute("ssrc", ssrcId);
for (Parameter parameter : parameters) {
this.addChild(parameter);
}
}
public String getSsrcId() {
return this.getAttribute("ssrc");
}
public List<Parameter> getParameters() {
ImmutableList.Builder<Parameter> builder = new ImmutableList.Builder<>();
for (Element child : this.children) {
if ("parameter".equals(child.getName())) {
builder.add(Parameter.upgrade(child));
}
}
return builder.build();
}
public static Source upgrade(final Element element) {
Preconditions.checkArgument("source".equals(element.getName()));
Preconditions.checkArgument(Namespace.JINGLE_RTP_SOURCE_SPECIFIC_MEDIA_ATTRIBUTES.equals(element.getNamespace()));
final Source source = new Source();
source.setChildren(element.getChildren());
source.setAttributes(element.getAttributes());
return source;
}
public static class Parameter extends Element {
public String getParameterName() {
return this.getAttribute("name");
}
public String getParameterValue() {
return this.getAttribute("value");
}
private Parameter() {
super("parameter");
}
public Parameter(final String attribute, final String value) {
super("parameter");
this.setAttribute("name", attribute);
if (value != null) {
this.setAttribute("value", value);
}
}
public static Parameter upgrade(final Element element) {
Preconditions.checkArgument("parameter".equals(element.getName()));
Parameter parameter = new Parameter();
parameter.setAttributes(element.getAttributes());
parameter.setChildren(element.getChildren());
return parameter;
}
}
}
public enum Media { public enum Media {
VIDEO, AUDIO, UNKNOWN; VIDEO, AUDIO, UNKNOWN;
@ -368,7 +449,8 @@ public class RtpDescription extends GenericDescription {
public static RtpDescription of(final SessionDescription.Media media) { public static RtpDescription of(final SessionDescription.Media media) {
final RtpDescription rtpDescription = new RtpDescription(); final RtpDescription rtpDescription = new RtpDescription();
final Map<String, List<Parameter>> parameterMap = new HashMap<>(); final Map<String, List<Parameter>> parameterMap = new HashMap<>();
ArrayListMultimap<String, Element> feedbackNegotiationMap = ArrayListMultimap.create(); final ArrayListMultimap<String, Element> feedbackNegotiationMap = ArrayListMultimap.create();
final ArrayListMultimap<String, Source.Parameter> sourceParameterMap = ArrayListMultimap.create();
for (final String rtcpFb : media.attributes.get("rtcp-fb")) { for (final String rtcpFb : media.attributes.get("rtcp-fb")) {
final String[] parts = rtcpFb.split(" "); final String[] parts = rtcpFb.split(" ");
if (parts.length >= 2) { if (parts.length >= 2) {
@ -384,6 +466,16 @@ public class RtpDescription extends GenericDescription {
} }
} }
} }
for (final String ssrc : media.attributes.get(("ssrc"))) {
final String[] parts = ssrc.split(" ", 2);
if (parts.length == 2) {
final String id = parts[0];
final String[] subParts = parts[1].split(":", 2);
final String attribute = subParts[0];
final String value = subParts.length == 2 ? subParts[1] : null;
sourceParameterMap.put(id, new Source.Parameter(attribute, value));
}
}
for (final String fmtp : media.attributes.get("fmtp")) { for (final String fmtp : media.attributes.get("fmtp")) {
final Pair<String, List<Parameter>> pair = Parameter.ofSdpString(fmtp); final Pair<String, List<Parameter>> pair = Parameter.ofSdpString(fmtp);
if (pair != null) { if (pair != null) {
@ -405,6 +497,9 @@ public class RtpDescription extends GenericDescription {
rtpDescription.addChild(extension); rtpDescription.addChild(extension);
} }
} }
for (Map.Entry<String, Collection<Source.Parameter>> source : sourceParameterMap.asMap().entrySet()) {
rtpDescription.addChild(new Source(source.getKey(), source.getValue()));
}
return rtpDescription; return rtpDescription;
} }