diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index fb3261ab6..a53362168 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -36,6 +36,7 @@ public final class Namespace { public static final String JINGLE_TRANSPORT_ICE_UDP = "urn:xmpp:jingle:transports:ice-udp:1"; public static final String JINGLE_APPS_RTP = "urn:xmpp:jingle:apps:rtp:1"; public static final String JINGLE_APPS_DTLS = "urn:xmpp:jingle:apps:dtls:0"; + public static final String JINGLE_APPS_GROUPING = "urn:xmpp:jingle:apps:grouping:0"; 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_RTP_HEADER_EXTENSIONS = "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java index f2cb85d27..68964d131 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java @@ -592,7 +592,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple content.setTransport(new S5BTransportInfo(this.transportId, candidates)); Log.d(Config.LOGTAG, String.format("%s: sending S5B offer with %d candidates", id.account.getJid().asBareJid(), candidates.size())); } - packet.setJingleContent(content); + packet.addJingleContent(content); this.sendJinglePacket(packet, (account, response) -> { if (response.getType() == IqPacket.TYPE.RESULT) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": other party received offer"); @@ -617,7 +617,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple hash.setAttribute("algo", "sha-1").setContent(Base64.encodeToString(file.getSha1Sum(), Base64.NO_WRAP)); final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.SESSION_INFO); - packet.setJingleChild(checksum); + packet.addJingleChild(checksum); this.sendJinglePacket(packet); } @@ -651,7 +651,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple public void failed() { Log.d(Config.LOGTAG, "connection to our own proxy65 candidate failed"); content.setTransport(new S5BTransportInfo(transportId, getOurCandidates())); - packet.setJingleContent(content); + packet.addJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); } @@ -661,7 +661,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple Log.d(Config.LOGTAG, "connected to proxy65 candidate"); mergeCandidate(candidate); content.setTransport(new S5BTransportInfo(transportId, getOurCandidates())); - packet.setJingleContent(content); + packet.addJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); } @@ -669,7 +669,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } else { Log.d(Config.LOGTAG, "did not find a proxy65 candidate for ourselves"); content.setTransport(new S5BTransportInfo(transportId, getOurCandidates())); - packet.setJingleContent(content); + packet.addJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); } @@ -682,7 +682,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final Content content = new Content(contentCreator, contentName); content.setDescription(this.description); content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); - packet.setJingleContent(content); + packet.addJingleContent(content); this.transport.receive(file, onFileTransmissionStatusChanged); this.sendJinglePacket(packet); } @@ -909,7 +909,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple Content content = new Content(this.contentCreator, this.contentName); this.transportId = JingleConnectionManager.nextRandomId(); content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); - packet.setJingleContent(content); + packet.addJingleContent(content); this.sendJinglePacket(packet); } @@ -941,7 +941,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final Content content = new Content(contentCreator, contentName); content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); - answer.setJingleContent(content); + answer.addJingleContent(content); respondToIq(packet, true); @@ -1122,7 +1122,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); content.setTransport(new S5BTransportInfo(this.transportId, new Element("activated").setAttribute("cid", cid))); - packet.setJingleContent(content); + packet.addJingleContent(content); this.sendJinglePacket(packet); } @@ -1130,7 +1130,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); content.setTransport(new S5BTransportInfo(this.transportId, new Element("proxy-error"))); - packet.setJingleContent(content); + packet.addJingleContent(content); this.sendJinglePacket(packet); } @@ -1138,7 +1138,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-used").setAttribute("cid", cid))); - packet.setJingleContent(content); + packet.addJingleContent(content); this.sentCandidate = true; if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) { connect(); @@ -1151,7 +1151,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); Content content = new Content(this.contentCreator, this.contentName); content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-error"))); - packet.setJingleContent(content); + packet.addJingleContent(content); this.sentCandidate = true; this.sendJinglePacket(packet); if (receivedCandidate && mJingleStatus == JINGLE_STATUS_ACCEPTED) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index faba08e48..6165fde34 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -2,12 +2,9 @@ package eu.siacs.conversations.xmpp.jingle; import android.util.Log; -import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; -import org.checkerframework.checker.nullness.compatqual.NullableDecl; import org.webrtc.AudioSource; import org.webrtc.AudioTrack; import org.webrtc.DataChannel; @@ -26,9 +23,6 @@ import java.util.Map; import eu.siacs.conversations.Config; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; -import eu.siacs.conversations.xmpp.jingle.stanzas.Content; -import eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription; -import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo; import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription; @@ -73,18 +67,18 @@ public class JingleRtpConnection extends AbstractJingleConnection { //TODO respond with out-of-order return; } - final Map contents; + final RtpContentMap contentMap; try { - contents = DescriptionTransport.of(jinglePacket.getJingleContents()); + contentMap = RtpContentMap.of(jinglePacket); } catch (IllegalArgumentException | NullPointerException e) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents", e); return; } - Log.d(Config.LOGTAG, "processing session-init with " + contents.size() + " contents"); + Log.d(Config.LOGTAG, "processing session-init with " + contentMap.contents.size() + " contents"); final State oldState = this.state; if (transition(State.SESSION_INITIALIZED)) { if (oldState == State.PROCEED) { - processContents(contents); + processContents(contentMap); sendSessionAccept(); } else { //TODO start ringing @@ -94,9 +88,9 @@ public class JingleRtpConnection extends AbstractJingleConnection { } } - private void processContents(final Map contents) { - for (Map.Entry content : contents.entrySet()) { - final DescriptionTransport descriptionTransport = content.getValue(); + private void processContents(final RtpContentMap contentMap) { + for (Map.Entry content : contentMap.contents.entrySet()) { + final RtpContentMap.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()) { @@ -154,7 +148,11 @@ public class JingleRtpConnection extends AbstractJingleConnection { private void sendSessionInitiate() { setupWebRTC(); - Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": sending session-initiate"); + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": prepare session-initiate"); + } + + private void sendSessionInitiate(RtpContentMap rtpContentMap) { + Log.d(Config.LOGTAG, rtpContentMap.toJinglePacket(JinglePacket.Action.SESSION_INITIATE, id.sessionId).toString()); } private void sendSessionAccept() { @@ -252,11 +250,9 @@ public class JingleRtpConnection extends AbstractJingleConnection { @Override public void onCreateSuccess(org.webrtc.SessionDescription description) { final SessionDescription sessionDescription = SessionDescription.parse(description.description); - Log.d(Config.LOGTAG,"description: "+description.description); - for (SessionDescription.Media media : sessionDescription.media) { - Log.d(Config.LOGTAG, RtpDescription.of(media).toString()); - } - Log.d(Config.LOGTAG, sessionDescription.toString()); + Log.d(Config.LOGTAG, "description: " + description.description); + final RtpContentMap rtpContentMap = RtpContentMap.of(sessionDescription); + sendSessionInitiate(rtpContentMap); } @Override @@ -306,44 +302,4 @@ public class JingleRtpConnection extends AbstractJingleConnection { throw new IllegalStateException(String.format("Unable to transition from %s to %s", this.state, target)); } } - - public static class DescriptionTransport { - private final RtpDescription description; - private final IceUdpTransportInfo transport; - - public DescriptionTransport(final RtpDescription description, final IceUdpTransportInfo transport) { - this.description = description; - this.transport = transport; - } - - public static DescriptionTransport of(final Content content) { - final GenericDescription description = content.getDescription(); - final GenericTransportInfo transportInfo = content.getTransport(); - final RtpDescription rtpDescription; - final IceUdpTransportInfo iceUdpTransportInfo; - if (description instanceof RtpDescription) { - rtpDescription = (RtpDescription) description; - } else { - Log.d(Config.LOGTAG, "description was " + description); - throw new IllegalArgumentException("Content does not contain RtpDescription"); - } - if (transportInfo instanceof IceUdpTransportInfo) { - iceUdpTransportInfo = (IceUdpTransportInfo) transportInfo; - } else { - throw new IllegalArgumentException("Content does not contain ICE-UDP transport"); - } - return new DescriptionTransport(rtpDescription, iceUdpTransportInfo); - } - - public static Map of(final Map contents) { - return ImmutableMap.copyOf(Maps.transformValues(contents, new Function() { - @NullableDecl - @Override - public DescriptionTransport apply(@NullableDecl Content content) { - return content == null ? null : of(content); - } - })); - } - } - } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/RtpContentMap.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/RtpContentMap.java new file mode 100644 index 000000000..681686fb9 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/RtpContentMap.java @@ -0,0 +1,108 @@ +package eu.siacs.conversations.xmpp.jingle; + +import android.util.Log; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; + +import org.checkerframework.checker.nullness.compatqual.NullableDecl; + +import java.util.Map; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.xmpp.jingle.stanzas.Content; +import eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription; +import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo; +import eu.siacs.conversations.xmpp.jingle.stanzas.Group; +import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo; +import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; +import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription; + +public class RtpContentMap { + + public final Group group; + public final Map contents; + + private RtpContentMap(Group group, Map contents) { + this.group = group; + this.contents = contents; + } + + public static RtpContentMap of(final JinglePacket jinglePacket) { + return new RtpContentMap(jinglePacket.getGroup(), DescriptionTransport.of(jinglePacket.getJingleContents())); + } + + public static RtpContentMap of(final SessionDescription sessionDescription) { + final ImmutableMap.Builder contentMapBuilder = new ImmutableMap.Builder<>(); + for (SessionDescription.Media media : sessionDescription.media) { + final String id = Iterables.getFirst(media.attributes.get("mid"), null); + Preconditions.checkNotNull(id, "media has no mid"); + contentMapBuilder.put(id, DescriptionTransport.of(sessionDescription, media)); + } + final String groupAttribute = Iterables.getFirst(sessionDescription.attributes.get("group"), null); + final Group group = groupAttribute == null ? null : Group.ofSdpString(groupAttribute); + return new RtpContentMap(group, contentMapBuilder.build()); + } + + public JinglePacket toJinglePacket(final JinglePacket.Action action, final String sessionId) { + final JinglePacket jinglePacket = new JinglePacket(action, sessionId); + if (this.group != null) { + jinglePacket.addGroup(this.group); + } + for (Map.Entry entry : this.contents.entrySet()) { + final Content content = new Content(Content.Creator.INITIATOR, entry.getKey()); + content.addChild(entry.getValue().description); + content.addChild(entry.getValue().transport); + jinglePacket.addJingleContent(content); + } + return jinglePacket; + } + + public static class DescriptionTransport { + public final RtpDescription description; + public final IceUdpTransportInfo transport; + + public DescriptionTransport(final RtpDescription description, final IceUdpTransportInfo transport) { + this.description = description; + this.transport = transport; + } + + public static DescriptionTransport of(final Content content) { + final GenericDescription description = content.getDescription(); + final GenericTransportInfo transportInfo = content.getTransport(); + final RtpDescription rtpDescription; + final IceUdpTransportInfo iceUdpTransportInfo; + if (description instanceof RtpDescription) { + rtpDescription = (RtpDescription) description; + } else { + Log.d(Config.LOGTAG, "description was " + description); + throw new IllegalArgumentException("Content does not contain RtpDescription"); + } + if (transportInfo instanceof IceUdpTransportInfo) { + iceUdpTransportInfo = (IceUdpTransportInfo) transportInfo; + } else { + throw new IllegalArgumentException("Content does not contain ICE-UDP transport"); + } + return new DescriptionTransport(rtpDescription, iceUdpTransportInfo); + } + + public static DescriptionTransport of(final SessionDescription sessionDescription, final SessionDescription.Media media) { + final RtpDescription rtpDescription = RtpDescription.of(media); + final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo(); + return new DescriptionTransport(rtpDescription, transportInfo); + } + + public static Map of(final Map contents) { + return ImmutableMap.copyOf(Maps.transformValues(contents, new Function() { + @NullableDecl + @Override + public DescriptionTransport apply(@NullableDecl Content content) { + return content == null ? null : of(content); + } + })); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/SessionDescription.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/SessionDescription.java index 4381a4816..3d028a439 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/SessionDescription.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/SessionDescription.java @@ -28,7 +28,7 @@ public class SessionDescription { this.media = media; } - public static SessionDescription parse(final Map contents) { + public static SessionDescription parse(final Map contents) { final SessionDescriptionBuilder sessionDescriptionBuilder = new SessionDescriptionBuilder(); return sessionDescriptionBuilder.createSessionDescription(); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Group.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Group.java new file mode 100644 index 000000000..eb5c32252 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Group.java @@ -0,0 +1,64 @@ +package eu.siacs.conversations.xmpp.jingle.stanzas; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.Collection; +import java.util.List; + +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; + +public class Group extends Element { + + private Group() { + super("group", Namespace.JINGLE_APPS_GROUPING); + } + + public Group(final String semantics, final Collection identificationTags) { + super("group", Namespace.JINGLE_APPS_GROUPING); + this.setAttribute("semantics", semantics); + for (String tag : identificationTags) { + this.addChild(new Element("content").setAttribute("name", tag)); + } + } + + public String getSemantics() { + return this.getAttribute("semantics"); + } + + public List getIdentificationTags() { + final ImmutableList.Builder builder = new ImmutableList.Builder<>(); + for (final Element child : this.children) { + if ("content".equals(child.getName())) { + final String name = child.getAttribute("name"); + if (name != null) { + builder.add(name); + } + } + } + return builder.build(); + } + + public static Group ofSdpString(final String input) { + ImmutableList.Builder tagBuilder = new ImmutableList.Builder<>(); + final String[] parts = input.split(" "); + if (parts.length >= 2) { + final String semantics = parts[0]; + for(int i = 1; i < parts.length; ++i) { + tagBuilder.add(parts[i]); + } + return new Group(semantics,tagBuilder.build()); + } + return null; + } + + public static Group upgrade(final Element element) { + Preconditions.checkArgument("group".equals(element.getName())); + Preconditions.checkArgument(Namespace.JINGLE_APPS_GROUPING.equals(element.getNamespace())); + final Group group = new Group(); + group.setAttributes(element.getAttributes()); + group.setChildren(element.getChildren()); + return group; + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java index 84734b924..52868f136 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java @@ -10,8 +10,8 @@ import eu.siacs.conversations.xml.Namespace; public class IceUdpTransportInfo extends GenericTransportInfo { - private IceUdpTransportInfo(final String name, final String xmlns) { - super(name, xmlns); + public IceUdpTransportInfo() { + super("transport", Namespace.JINGLE_TRANSPORT_ICE_UDP); } public Fingerprint getFingerprint() { @@ -32,7 +32,7 @@ public class IceUdpTransportInfo extends GenericTransportInfo { public static IceUdpTransportInfo upgrade(final Element element) { 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"); - final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo("transport", Namespace.JINGLE_TRANSPORT_ICE_UDP); + final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo(); transportInfo.setAttributes(element.getAttributes()); transportInfo.setChildren(element.getChildren()); return transportInfo; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java index e4fb88ecb..1c15af27f 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java @@ -1,7 +1,6 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; import android.support.annotation.NonNull; -import android.util.Log; import com.google.common.base.CaseFormat; import com.google.common.base.Preconditions; @@ -9,7 +8,6 @@ import com.google.common.collect.ImmutableMap; import java.util.Map; -import eu.siacs.conversations.Config; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.stanzas.IqPacket; @@ -44,6 +42,15 @@ public class JinglePacket extends IqPacket { return content == null ? null : Content.upgrade(content); } + public Group getGroup() { + final Element group = this.findChild("group", Namespace.JINGLE_APPS_GROUPING); + return group == null ? null : Group.upgrade(group); + } + + public void addGroup(final Group group) { + this.addJingleChild(group); + } + public Map getJingleContents() { final Element jingle = findChild("jingle", Namespace.JINGLE); ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); @@ -56,8 +63,8 @@ public class JinglePacket extends IqPacket { return builder.build(); } - public void setJingleContent(final Content content) { //take content interface - setJingleChild(content); + public void addJingleContent(final Content content) { //take content interface + addJingleChild(content); } public Reason getReason() { @@ -87,7 +94,7 @@ public class JinglePacket extends IqPacket { return jingle == null ? null : jingle.findChild(name); } - public void setJingleChild(final Element child) { + public void addJingleChild(final Element child) { final Element jingle = findChild("jingle", Namespace.JINGLE); jingle.addChild(child); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/RtpDescription.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/RtpDescription.java index 062a58523..8b9296993 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/RtpDescription.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/RtpDescription.java @@ -19,6 +19,11 @@ import eu.siacs.conversations.xmpp.jingle.SessionDescription; public class RtpDescription extends GenericDescription { + private RtpDescription(final String media) { + super("description", Namespace.JINGLE_APPS_RTP); + this.setAttribute("media", media); + } + private RtpDescription() { super("description", Namespace.JINGLE_APPS_RTP); } @@ -447,7 +452,7 @@ public class RtpDescription extends GenericDescription { } public static RtpDescription of(final SessionDescription.Media media) { - final RtpDescription rtpDescription = new RtpDescription(); + final RtpDescription rtpDescription = new RtpDescription(media.media); final Map> parameterMap = new HashMap<>(); final ArrayListMultimap feedbackNegotiationMap = ArrayListMultimap.create(); final ArrayListMultimap sourceParameterMap = ArrayListMultimap.create();