payload-type and rtp-hdrext sdp parsing
This commit is contained in:
parent
5b1d86d67e
commit
18059345c8
|
@ -39,6 +39,7 @@ public final class Namespace {
|
||||||
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 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 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";
|
||||||
|
|
|
@ -252,11 +252,9 @@ public class JingleRtpConnection extends AbstractJingleConnection {
|
||||||
@Override
|
@Override
|
||||||
public void onCreateSuccess(org.webrtc.SessionDescription description) {
|
public void onCreateSuccess(org.webrtc.SessionDescription description) {
|
||||||
final SessionDescription sessionDescription = SessionDescription.parse(description.description);
|
final SessionDescription sessionDescription = SessionDescription.parse(description.description);
|
||||||
|
Log.d(Config.LOGTAG,"description: "+description.description);
|
||||||
for (SessionDescription.Media media : sessionDescription.media) {
|
for (SessionDescription.Media media : sessionDescription.media) {
|
||||||
Log.d(Config.LOGTAG, "media: " + media.protocol);
|
Log.d(Config.LOGTAG, RtpDescription.of(media).toString());
|
||||||
for (SessionDescription.Attribute attribute : media.attributes) {
|
|
||||||
Log.d(Config.LOGTAG, "attribute key=" + attribute.key + ", value=" + attribute.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Log.d(Config.LOGTAG, sessionDescription.toString());
|
Log.d(Config.LOGTAG, sessionDescription.toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle;
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MediaBuilder {
|
public class MediaBuilder {
|
||||||
|
@ -8,7 +10,7 @@ public class MediaBuilder {
|
||||||
private String protocol;
|
private String protocol;
|
||||||
private List<Integer> formats;
|
private List<Integer> formats;
|
||||||
private String connectionData;
|
private String connectionData;
|
||||||
private List<SessionDescription.Attribute> attributes;
|
private ArrayListMultimap<String,String> attributes;
|
||||||
|
|
||||||
public MediaBuilder setMedia(String media) {
|
public MediaBuilder setMedia(String media) {
|
||||||
this.media = media;
|
this.media = media;
|
||||||
|
@ -35,7 +37,7 @@ public class MediaBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaBuilder setAttributes(List<SessionDescription.Attribute> attributes) {
|
public MediaBuilder setAttributes(ArrayListMultimap<String,String> attributes) {
|
||||||
this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle;
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -14,11 +16,11 @@ public class SessionDescription {
|
||||||
public final int version;
|
public final int version;
|
||||||
public final String name;
|
public final String name;
|
||||||
public final String connectionData;
|
public final String connectionData;
|
||||||
public final List<Attribute> attributes;
|
public final ArrayListMultimap<String, String> attributes;
|
||||||
public final List<Media> media;
|
public final List<Media> media;
|
||||||
|
|
||||||
|
|
||||||
public SessionDescription(int version, String name, String connectionData, List<Attribute> attributes, List<Media> media) {
|
public SessionDescription(int version, String name, String connectionData, ArrayListMultimap<String, String> attributes, List<Media> media) {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.connectionData = connectionData;
|
this.connectionData = connectionData;
|
||||||
|
@ -34,10 +36,10 @@ public class SessionDescription {
|
||||||
public static SessionDescription parse(final String input) {
|
public static SessionDescription parse(final String input) {
|
||||||
final SessionDescriptionBuilder sessionDescriptionBuilder = new SessionDescriptionBuilder();
|
final SessionDescriptionBuilder sessionDescriptionBuilder = new SessionDescriptionBuilder();
|
||||||
MediaBuilder currentMediaBuilder = null;
|
MediaBuilder currentMediaBuilder = null;
|
||||||
ImmutableList.Builder<Attribute> attributeBuilder = new ImmutableList.Builder<>();
|
ArrayListMultimap<String, String> attributeMap = ArrayListMultimap.create();
|
||||||
ImmutableList.Builder<Media> mediaBuilder = new ImmutableList.Builder<>();
|
ImmutableList.Builder<Media> mediaBuilder = new ImmutableList.Builder<>();
|
||||||
for (final String line : input.split("\n")) {
|
for (final String line : input.split("\n")) {
|
||||||
final String[] pair = line.split("=", 2);
|
final String[] pair = line.trim().split("=", 2);
|
||||||
if (pair.length < 2 || pair[0].length() != 1) {
|
if (pair.length < 2 || pair[0].length() != 1) {
|
||||||
Log.d(Config.LOGTAG, "skipping sdp parsing on line " + line);
|
Log.d(Config.LOGTAG, "skipping sdp parsing on line " + line);
|
||||||
continue;
|
continue;
|
||||||
|
@ -59,17 +61,18 @@ public class SessionDescription {
|
||||||
sessionDescriptionBuilder.setName(value);
|
sessionDescriptionBuilder.setName(value);
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
attributeBuilder.add(Attribute.parse(value));
|
final Pair<String, String> attribute = parseAttribute(value);
|
||||||
|
attributeMap.put(attribute.first, attribute.second);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if (currentMediaBuilder == null) {
|
if (currentMediaBuilder == null) {
|
||||||
sessionDescriptionBuilder.setAttributes(attributeBuilder.build());
|
sessionDescriptionBuilder.setAttributes(attributeMap);
|
||||||
;
|
;
|
||||||
} else {
|
} else {
|
||||||
currentMediaBuilder.setAttributes(attributeBuilder.build());
|
currentMediaBuilder.setAttributes(attributeMap);
|
||||||
mediaBuilder.add(currentMediaBuilder.createMedia());
|
mediaBuilder.add(currentMediaBuilder.createMedia());
|
||||||
}
|
}
|
||||||
attributeBuilder = new ImmutableList.Builder<>();
|
attributeMap = ArrayListMultimap.create();
|
||||||
currentMediaBuilder = new MediaBuilder();
|
currentMediaBuilder = new MediaBuilder();
|
||||||
final String[] parts = value.split(" ");
|
final String[] parts = value.split(" ");
|
||||||
if (parts.length >= 3) {
|
if (parts.length >= 3) {
|
||||||
|
@ -89,14 +92,14 @@ public class SessionDescription {
|
||||||
|
|
||||||
}
|
}
|
||||||
if (currentMediaBuilder != null) {
|
if (currentMediaBuilder != null) {
|
||||||
currentMediaBuilder.setAttributes(attributeBuilder.build());
|
currentMediaBuilder.setAttributes(attributeMap);
|
||||||
mediaBuilder.add(currentMediaBuilder.createMedia());
|
mediaBuilder.add(currentMediaBuilder.createMedia());
|
||||||
}
|
}
|
||||||
sessionDescriptionBuilder.setMedia(mediaBuilder.build());
|
sessionDescriptionBuilder.setMedia(mediaBuilder.build());
|
||||||
return sessionDescriptionBuilder.createSessionDescription();
|
return sessionDescriptionBuilder.createSessionDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ignorantIntParser(final String input) {
|
public static int ignorantIntParser(final String input) {
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt(input);
|
return Integer.parseInt(input);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
|
@ -104,25 +107,13 @@ public class SessionDescription {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Attribute {
|
public static Pair<String, String> parseAttribute(final String input) {
|
||||||
public final String key;
|
final String[] pair = input.split(":", 2);
|
||||||
public final String value;
|
if (pair.length == 2) {
|
||||||
|
return new Pair<>(pair[0], pair[1]);
|
||||||
public Attribute(String key, String value) {
|
} else {
|
||||||
this.key = key;
|
return new Pair<>(pair[0], "");
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Attribute parse(String input) {
|
|
||||||
final String[] pair = input.split(":", 2);
|
|
||||||
if (pair.length == 2) {
|
|
||||||
return new Attribute(pair[0], pair[1]);
|
|
||||||
} else {
|
|
||||||
return new Attribute(pair[0], null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Media {
|
public static class Media {
|
||||||
|
@ -131,9 +122,9 @@ public class SessionDescription {
|
||||||
public final String protocol;
|
public final String protocol;
|
||||||
public final List<Integer> formats;
|
public final List<Integer> formats;
|
||||||
public final String connectionData;
|
public final String connectionData;
|
||||||
public final List<Attribute> attributes;
|
public final ArrayListMultimap<String, String> attributes;
|
||||||
|
|
||||||
public Media(String media, int port, String protocol, List<Integer> formats, String connectionData, List<Attribute> attributes) {
|
public Media(String media, int port, String protocol, List<Integer> formats, String connectionData, ArrayListMultimap<String, String> attributes) {
|
||||||
this.media = media;
|
this.media = media;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle;
|
package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SessionDescriptionBuilder {
|
public class SessionDescriptionBuilder {
|
||||||
private int version;
|
private int version;
|
||||||
private String name;
|
private String name;
|
||||||
private String connectionData;
|
private String connectionData;
|
||||||
private List<SessionDescription.Attribute> attributes;
|
private ArrayListMultimap<String,String> attributes;
|
||||||
private List<SessionDescription.Media> media;
|
private List<SessionDescription.Media> media;
|
||||||
|
|
||||||
public SessionDescriptionBuilder setVersion(int version) {
|
public SessionDescriptionBuilder setVersion(int version) {
|
||||||
|
@ -24,7 +26,7 @@ public class SessionDescriptionBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SessionDescriptionBuilder setAttributes(List<SessionDescription.Attribute> attributes) {
|
public SessionDescriptionBuilder setAttributes(ArrayListMultimap<String,String> attributes) {
|
||||||
this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle.stanzas;
|
package eu.siacs.conversations.xmpp.jingle.stanzas;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
public class RtpDescription extends GenericDescription {
|
public class RtpDescription extends GenericDescription {
|
||||||
|
|
||||||
|
|
||||||
private RtpDescription(String name, String namespace) {
|
private RtpDescription() {
|
||||||
super(name, namespace);
|
super("description", Namespace.JINGLE_APPS_RTP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Media getMedia() {
|
public Media getMedia() {
|
||||||
|
@ -22,7 +26,7 @@ public class RtpDescription extends GenericDescription {
|
||||||
|
|
||||||
public List<PayloadType> getPayloadTypes() {
|
public List<PayloadType> getPayloadTypes() {
|
||||||
final ImmutableList.Builder<PayloadType> builder = new ImmutableList.Builder<>();
|
final ImmutableList.Builder<PayloadType> builder = new ImmutableList.Builder<>();
|
||||||
for(Element child : getChildren()) {
|
for (Element child : getChildren()) {
|
||||||
if ("payload-type".equals(child.getName())) {
|
if ("payload-type".equals(child.getName())) {
|
||||||
builder.add(PayloadType.of(child));
|
builder.add(PayloadType.of(child));
|
||||||
}
|
}
|
||||||
|
@ -30,9 +34,17 @@ public class RtpDescription extends GenericDescription {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<FeedbackNegotiation> getFeedbackNegotiations() {
|
||||||
|
return FeedbackNegotiation.fromChildren(this.getChildren());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FeedbackNegotiationTrrInt> feedbackNegotiationTrrInts() {
|
||||||
|
return FeedbackNegotiationTrrInt.fromChildren(this.getChildren());
|
||||||
|
}
|
||||||
|
|
||||||
public List<RtpHeaderExtension> getHeaderExtensions() {
|
public List<RtpHeaderExtension> getHeaderExtensions() {
|
||||||
final ImmutableList.Builder<RtpHeaderExtension> builder = new ImmutableList.Builder<>();
|
final ImmutableList.Builder<RtpHeaderExtension> builder = new ImmutableList.Builder<>();
|
||||||
for(final Element child : getChildren()) {
|
for (final Element child : getChildren()) {
|
||||||
if ("rtp-hdrext".equals(child.getName()) && Namespace.JINGLE_RTP_HEADER_EXTENSIONS.equals(child.getNamespace())) {
|
if ("rtp-hdrext".equals(child.getName()) && Namespace.JINGLE_RTP_HEADER_EXTENSIONS.equals(child.getNamespace())) {
|
||||||
builder.add(RtpHeaderExtension.upgrade(child));
|
builder.add(RtpHeaderExtension.upgrade(child));
|
||||||
}
|
}
|
||||||
|
@ -43,13 +55,82 @@ public class RtpDescription extends GenericDescription {
|
||||||
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");
|
||||||
final RtpDescription description = new RtpDescription("description", Namespace.JINGLE_APPS_RTP);
|
final RtpDescription description = new RtpDescription();
|
||||||
description.setAttributes(element.getAttributes());
|
description.setAttributes(element.getAttributes());
|
||||||
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 FeedbackNegotiation extends Element {
|
||||||
|
private FeedbackNegotiation() {
|
||||||
|
super("rtcp-fb", Namespace.JINGLE_RTP_FEEDBACK_NEGOTIATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return this.getAttribute("type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubType() {
|
||||||
|
return this.getAttribute("subtype");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FeedbackNegotiation upgrade(final Element element) {
|
||||||
|
Preconditions.checkArgument("rtcp-fb".equals(element.getName()));
|
||||||
|
Preconditions.checkArgument(Namespace.JINGLE_RTP_FEEDBACK_NEGOTIATION.equals(element.getNamespace()));
|
||||||
|
final FeedbackNegotiation feedback = new FeedbackNegotiation();
|
||||||
|
feedback.setAttributes(element.getAttributes());
|
||||||
|
feedback.setChildren(element.getChildren());
|
||||||
|
return feedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FeedbackNegotiation> fromChildren(final List<Element> children) {
|
||||||
|
ImmutableList.Builder<FeedbackNegotiation> builder = new ImmutableList.Builder<>();
|
||||||
|
for (final Element child : children) {
|
||||||
|
if ("rtcp-fb".equals(child.getName()) && Namespace.JINGLE_RTP_FEEDBACK_NEGOTIATION.equals(child.getNamespace())) {
|
||||||
|
builder.add(upgrade(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FeedbackNegotiationTrrInt extends Element {
|
||||||
|
private FeedbackNegotiationTrrInt() {
|
||||||
|
super("rtcp-fb-trr-int", Namespace.JINGLE_RTP_FEEDBACK_NEGOTIATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
final String value = getAttribute("value");
|
||||||
|
if (value == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FeedbackNegotiationTrrInt upgrade(final Element element) {
|
||||||
|
Preconditions.checkArgument("rtcp-fb-trr-int".equals(element.getName()));
|
||||||
|
Preconditions.checkArgument(Namespace.JINGLE_RTP_FEEDBACK_NEGOTIATION.equals(element.getNamespace()));
|
||||||
|
final FeedbackNegotiationTrrInt trr = new FeedbackNegotiationTrrInt();
|
||||||
|
trr.setAttributes(element.getAttributes());
|
||||||
|
trr.setChildren(element.getChildren());
|
||||||
|
return trr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FeedbackNegotiationTrrInt> fromChildren(final List<Element> children) {
|
||||||
|
ImmutableList.Builder<FeedbackNegotiationTrrInt> builder = new ImmutableList.Builder<>();
|
||||||
|
for (final Element child : children) {
|
||||||
|
if ("rtcp-fb-trr-int".equals(child.getName()) && Namespace.JINGLE_RTP_FEEDBACK_NEGOTIATION.equals(child.getNamespace())) {
|
||||||
|
builder.add(upgrade(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//XEP-0294: Jingle RTP Header Extensions Negotiation
|
//XEP-0294: Jingle RTP Header Extensions Negotiation
|
||||||
|
@ -60,6 +141,12 @@ public class RtpDescription extends GenericDescription {
|
||||||
super("rtp-hdrext", Namespace.JINGLE_RTP_HEADER_EXTENSIONS);
|
super("rtp-hdrext", Namespace.JINGLE_RTP_HEADER_EXTENSIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RtpHeaderExtension(String id, String uri) {
|
||||||
|
super("rtp-hdrext", Namespace.JINGLE_RTP_HEADER_EXTENSIONS);
|
||||||
|
this.setAttribute("id", id);
|
||||||
|
this.setAttribute("uri", uri);
|
||||||
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return this.getAttribute("id");
|
return this.getAttribute("id");
|
||||||
}
|
}
|
||||||
|
@ -76,14 +163,36 @@ public class RtpDescription extends GenericDescription {
|
||||||
extension.setChildren(element.getChildren());
|
extension.setChildren(element.getChildren());
|
||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RtpHeaderExtension ofSdpString(final String sdp) {
|
||||||
|
final String[] pair = sdp.split(" ", 2);
|
||||||
|
if (pair.length == 2) {
|
||||||
|
final String id = pair[0];
|
||||||
|
final String uri = pair[1];
|
||||||
|
return new RtpHeaderExtension(id,uri);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//maps to `rtpmap $id $name/$clockrate/$channels`
|
//maps to `rtpmap $id $name/$clockrate/$channels`
|
||||||
public static class PayloadType extends Element {
|
public static class PayloadType extends Element {
|
||||||
|
|
||||||
private PayloadType(String name, String xmlns) {
|
private PayloadType() {
|
||||||
super(name, xmlns);
|
super("payload-type", Namespace.JINGLE_APPS_RTP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PayloadType(String id, String name, int clockRate, int channels) {
|
||||||
|
super("payload-type", Namespace.JINGLE_APPS_RTP);
|
||||||
|
this.setAttribute("id",id);
|
||||||
|
this.setAttribute("name", name);
|
||||||
|
this.setAttribute("clockrate", clockRate);
|
||||||
|
if (channels != 1) {
|
||||||
|
this.setAttribute("channels", channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return this.getAttribute("id");
|
return this.getAttribute("id");
|
||||||
}
|
}
|
||||||
|
@ -126,13 +235,41 @@ public class RtpDescription extends GenericDescription {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<FeedbackNegotiation> getFeedbackNegotiations() {
|
||||||
|
return FeedbackNegotiation.fromChildren(this.getChildren());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FeedbackNegotiationTrrInt> feedbackNegotiationTrrInts() {
|
||||||
|
return FeedbackNegotiationTrrInt.fromChildren(this.getChildren());
|
||||||
|
}
|
||||||
|
|
||||||
public static PayloadType of(final Element element) {
|
public static PayloadType of(final Element element) {
|
||||||
Preconditions.checkArgument("payload-type".equals(element.getName()), "element name must be called payload-type");
|
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 payloadType = new PayloadType();
|
||||||
payloadType.setAttributes(element.getAttributes());
|
payloadType.setAttributes(element.getAttributes());
|
||||||
payloadType.setChildren(element.getChildren());
|
payloadType.setChildren(element.getChildren());
|
||||||
return payloadType;
|
return payloadType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PayloadType ofSdpString(final String sdp) {
|
||||||
|
final String[] pair = sdp.split(" ",2);
|
||||||
|
if (pair.length == 2) {
|
||||||
|
final String id = pair[0];
|
||||||
|
final String[] parts = pair[1].split("/");
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
final String name = parts[0];
|
||||||
|
final int clockRate = SessionDescription.ignorantIntParser(parts[1]);
|
||||||
|
final int channels;
|
||||||
|
if (parts.length >= 3) {
|
||||||
|
channels = SessionDescription.ignorantIntParser(parts[2]);
|
||||||
|
} else {
|
||||||
|
channels =1;
|
||||||
|
}
|
||||||
|
return new PayloadType(id,name,clockRate,channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//map to `fmtp $id key=value;key=value
|
//map to `fmtp $id key=value;key=value
|
||||||
|
@ -182,4 +319,21 @@ public class RtpDescription extends GenericDescription {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RtpDescription of(final SessionDescription.Media media) {
|
||||||
|
final RtpDescription rtpDescription = new RtpDescription();
|
||||||
|
for(final String rtpmap : media.attributes.get("rtpmap")) {
|
||||||
|
final PayloadType payloadType = PayloadType.ofSdpString(rtpmap);
|
||||||
|
if (payloadType != null) {
|
||||||
|
rtpDescription.addChild(payloadType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(final String extmap : media.attributes.get("extmap")) {
|
||||||
|
final RtpHeaderExtension extension = RtpHeaderExtension.ofSdpString(extmap);
|
||||||
|
if (extension != null) {
|
||||||
|
rtpDescription.addChild(extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtpDescription;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue