parse sdp to jingle (yet w/o transport)
This commit is contained in:
parent
ef51ec2c1d
commit
b44a3aeac6
|
@ -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_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_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_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_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";
|
||||||
|
|
|
@ -592,7 +592,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
content.setTransport(new S5BTransportInfo(this.transportId, candidates));
|
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()));
|
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) -> {
|
this.sendJinglePacket(packet, (account, response) -> {
|
||||||
if (response.getType() == IqPacket.TYPE.RESULT) {
|
if (response.getType() == IqPacket.TYPE.RESULT) {
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": other party received offer");
|
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));
|
hash.setAttribute("algo", "sha-1").setContent(Base64.encodeToString(file.getSha1Sum(), Base64.NO_WRAP));
|
||||||
|
|
||||||
final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.SESSION_INFO);
|
final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.SESSION_INFO);
|
||||||
packet.setJingleChild(checksum);
|
packet.addJingleChild(checksum);
|
||||||
this.sendJinglePacket(packet);
|
this.sendJinglePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +651,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
public void failed() {
|
public void failed() {
|
||||||
Log.d(Config.LOGTAG, "connection to our own proxy65 candidate failed");
|
Log.d(Config.LOGTAG, "connection to our own proxy65 candidate failed");
|
||||||
content.setTransport(new S5BTransportInfo(transportId, getOurCandidates()));
|
content.setTransport(new S5BTransportInfo(transportId, getOurCandidates()));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
sendJinglePacket(packet);
|
sendJinglePacket(packet);
|
||||||
connectNextCandidate();
|
connectNextCandidate();
|
||||||
}
|
}
|
||||||
|
@ -661,7 +661,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
Log.d(Config.LOGTAG, "connected to proxy65 candidate");
|
Log.d(Config.LOGTAG, "connected to proxy65 candidate");
|
||||||
mergeCandidate(candidate);
|
mergeCandidate(candidate);
|
||||||
content.setTransport(new S5BTransportInfo(transportId, getOurCandidates()));
|
content.setTransport(new S5BTransportInfo(transportId, getOurCandidates()));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
sendJinglePacket(packet);
|
sendJinglePacket(packet);
|
||||||
connectNextCandidate();
|
connectNextCandidate();
|
||||||
}
|
}
|
||||||
|
@ -669,7 +669,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, "did not find a proxy65 candidate for ourselves");
|
Log.d(Config.LOGTAG, "did not find a proxy65 candidate for ourselves");
|
||||||
content.setTransport(new S5BTransportInfo(transportId, getOurCandidates()));
|
content.setTransport(new S5BTransportInfo(transportId, getOurCandidates()));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
sendJinglePacket(packet);
|
sendJinglePacket(packet);
|
||||||
connectNextCandidate();
|
connectNextCandidate();
|
||||||
}
|
}
|
||||||
|
@ -682,7 +682,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
final Content content = new Content(contentCreator, contentName);
|
final Content content = new Content(contentCreator, contentName);
|
||||||
content.setDescription(this.description);
|
content.setDescription(this.description);
|
||||||
content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize));
|
content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
this.transport.receive(file, onFileTransmissionStatusChanged);
|
this.transport.receive(file, onFileTransmissionStatusChanged);
|
||||||
this.sendJinglePacket(packet);
|
this.sendJinglePacket(packet);
|
||||||
}
|
}
|
||||||
|
@ -909,7 +909,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
Content content = new Content(this.contentCreator, this.contentName);
|
Content content = new Content(this.contentCreator, this.contentName);
|
||||||
this.transportId = JingleConnectionManager.nextRandomId();
|
this.transportId = JingleConnectionManager.nextRandomId();
|
||||||
content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize));
|
content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
this.sendJinglePacket(packet);
|
this.sendJinglePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,7 +941,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
|
|
||||||
final Content content = new Content(contentCreator, contentName);
|
final Content content = new Content(contentCreator, contentName);
|
||||||
content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize));
|
content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize));
|
||||||
answer.setJingleContent(content);
|
answer.addJingleContent(content);
|
||||||
|
|
||||||
respondToIq(packet, true);
|
respondToIq(packet, true);
|
||||||
|
|
||||||
|
@ -1122,7 +1122,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
||||||
final Content content = new Content(this.contentCreator, this.contentName);
|
final Content content = new Content(this.contentCreator, this.contentName);
|
||||||
content.setTransport(new S5BTransportInfo(this.transportId, new Element("activated").setAttribute("cid", cid)));
|
content.setTransport(new S5BTransportInfo(this.transportId, new Element("activated").setAttribute("cid", cid)));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
this.sendJinglePacket(packet);
|
this.sendJinglePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,7 +1130,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
||||||
final Content content = new Content(this.contentCreator, this.contentName);
|
final Content content = new Content(this.contentCreator, this.contentName);
|
||||||
content.setTransport(new S5BTransportInfo(this.transportId, new Element("proxy-error")));
|
content.setTransport(new S5BTransportInfo(this.transportId, new Element("proxy-error")));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
this.sendJinglePacket(packet);
|
this.sendJinglePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1138,7 +1138,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
||||||
final Content content = new Content(this.contentCreator, this.contentName);
|
final Content content = new Content(this.contentCreator, this.contentName);
|
||||||
content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-used").setAttribute("cid", cid)));
|
content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-used").setAttribute("cid", cid)));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
this.sentCandidate = true;
|
this.sentCandidate = true;
|
||||||
if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) {
|
if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) {
|
||||||
connect();
|
connect();
|
||||||
|
@ -1151,7 +1151,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
|
||||||
JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO);
|
||||||
Content content = new Content(this.contentCreator, this.contentName);
|
Content content = new Content(this.contentCreator, this.contentName);
|
||||||
content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-error")));
|
content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-error")));
|
||||||
packet.setJingleContent(content);
|
packet.addJingleContent(content);
|
||||||
this.sentCandidate = true;
|
this.sentCandidate = true;
|
||||||
this.sendJinglePacket(packet);
|
this.sendJinglePacket(packet);
|
||||||
if (receivedCandidate && mJingleStatus == JINGLE_STATUS_ACCEPTED) {
|
if (receivedCandidate && mJingleStatus == JINGLE_STATUS_ACCEPTED) {
|
||||||
|
|
|
@ -2,12 +2,9 @@ package eu.siacs.conversations.xmpp.jingle;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.AudioSource;
|
||||||
import org.webrtc.AudioTrack;
|
import org.webrtc.AudioTrack;
|
||||||
import org.webrtc.DataChannel;
|
import org.webrtc.DataChannel;
|
||||||
|
@ -26,9 +23,6 @@ import java.util.Map;
|
||||||
import eu.siacs.conversations.Config;
|
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.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.IceUdpTransportInfo;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
|
||||||
|
@ -73,18 +67,18 @@ public class JingleRtpConnection extends AbstractJingleConnection {
|
||||||
//TODO respond with out-of-order
|
//TODO respond with out-of-order
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Map<String, DescriptionTransport> contents;
|
final RtpContentMap contentMap;
|
||||||
try {
|
try {
|
||||||
contents = DescriptionTransport.of(jinglePacket.getJingleContents());
|
contentMap = RtpContentMap.of(jinglePacket);
|
||||||
} catch (IllegalArgumentException | NullPointerException e) {
|
} catch (IllegalArgumentException | NullPointerException e) {
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents", e);
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents", e);
|
||||||
return;
|
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;
|
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);
|
processContents(contentMap);
|
||||||
sendSessionAccept();
|
sendSessionAccept();
|
||||||
} else {
|
} else {
|
||||||
//TODO start ringing
|
//TODO start ringing
|
||||||
|
@ -94,9 +88,9 @@ public class JingleRtpConnection extends AbstractJingleConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processContents(final Map<String, DescriptionTransport> contents) {
|
private void processContents(final RtpContentMap contentMap) {
|
||||||
for (Map.Entry<String, DescriptionTransport> content : contents.entrySet()) {
|
for (Map.Entry<String, RtpContentMap.DescriptionTransport> content : contentMap.contents.entrySet()) {
|
||||||
final DescriptionTransport descriptionTransport = content.getValue();
|
final RtpContentMap.DescriptionTransport descriptionTransport = content.getValue();
|
||||||
final RtpDescription rtpDescription = descriptionTransport.description;
|
final RtpDescription rtpDescription = descriptionTransport.description;
|
||||||
Log.d(Config.LOGTAG, "receive content with name " + content.getKey() + " and media=" + rtpDescription.getMedia());
|
Log.d(Config.LOGTAG, "receive content with name " + content.getKey() + " and media=" + rtpDescription.getMedia());
|
||||||
for (RtpDescription.PayloadType payloadType : rtpDescription.getPayloadTypes()) {
|
for (RtpDescription.PayloadType payloadType : rtpDescription.getPayloadTypes()) {
|
||||||
|
@ -154,7 +148,11 @@ public class JingleRtpConnection extends AbstractJingleConnection {
|
||||||
|
|
||||||
private void sendSessionInitiate() {
|
private void sendSessionInitiate() {
|
||||||
setupWebRTC();
|
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() {
|
private void sendSessionAccept() {
|
||||||
|
@ -253,10 +251,8 @@ public class JingleRtpConnection extends AbstractJingleConnection {
|
||||||
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);
|
Log.d(Config.LOGTAG, "description: " + description.description);
|
||||||
for (SessionDescription.Media media : sessionDescription.media) {
|
final RtpContentMap rtpContentMap = RtpContentMap.of(sessionDescription);
|
||||||
Log.d(Config.LOGTAG, RtpDescription.of(media).toString());
|
sendSessionInitiate(rtpContentMap);
|
||||||
}
|
|
||||||
Log.d(Config.LOGTAG, sessionDescription.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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));
|
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<String, DescriptionTransport> of(final Map<String, Content> contents) {
|
|
||||||
return ImmutableMap.copyOf(Maps.transformValues(contents, new Function<Content, DescriptionTransport>() {
|
|
||||||
@NullableDecl
|
|
||||||
@Override
|
|
||||||
public DescriptionTransport apply(@NullableDecl Content content) {
|
|
||||||
return content == null ? null : of(content);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<String, DescriptionTransport> contents;
|
||||||
|
|
||||||
|
private RtpContentMap(Group group, Map<String, DescriptionTransport> 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<String, DescriptionTransport> 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<String, DescriptionTransport> 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<String, DescriptionTransport> of(final Map<String, Content> contents) {
|
||||||
|
return ImmutableMap.copyOf(Maps.transformValues(contents, new Function<Content, DescriptionTransport>() {
|
||||||
|
@NullableDecl
|
||||||
|
@Override
|
||||||
|
public DescriptionTransport apply(@NullableDecl Content content) {
|
||||||
|
return content == null ? null : of(content);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ public class SessionDescription {
|
||||||
this.media = media;
|
this.media = media;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SessionDescription parse(final Map<String, JingleRtpConnection.DescriptionTransport> contents) {
|
public static SessionDescription parse(final Map<String, RtpContentMap.DescriptionTransport> contents) {
|
||||||
final SessionDescriptionBuilder sessionDescriptionBuilder = new SessionDescriptionBuilder();
|
final SessionDescriptionBuilder sessionDescriptionBuilder = new SessionDescriptionBuilder();
|
||||||
return sessionDescriptionBuilder.createSessionDescription();
|
return sessionDescriptionBuilder.createSessionDescription();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<String> 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<String> getIdentificationTags() {
|
||||||
|
final ImmutableList.Builder<String> 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<String> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,8 +10,8 @@ import eu.siacs.conversations.xml.Namespace;
|
||||||
|
|
||||||
public class IceUdpTransportInfo extends GenericTransportInfo {
|
public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
|
|
||||||
private IceUdpTransportInfo(final String name, final String xmlns) {
|
public IceUdpTransportInfo() {
|
||||||
super(name, xmlns);
|
super("transport", Namespace.JINGLE_TRANSPORT_ICE_UDP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Fingerprint getFingerprint() {
|
public Fingerprint getFingerprint() {
|
||||||
|
@ -32,7 +32,7 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
|
||||||
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");
|
||||||
final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo("transport", Namespace.JINGLE_TRANSPORT_ICE_UDP);
|
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;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package eu.siacs.conversations.xmpp.jingle.stanzas;
|
package eu.siacs.conversations.xmpp.jingle.stanzas;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.google.common.base.CaseFormat;
|
import com.google.common.base.CaseFormat;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
@ -9,7 +8,6 @@ import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
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.stanzas.IqPacket;
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
|
@ -44,6 +42,15 @@ public class JinglePacket extends IqPacket {
|
||||||
return content == null ? null : Content.upgrade(content);
|
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<String, Content> getJingleContents() {
|
public Map<String, Content> getJingleContents() {
|
||||||
final Element jingle = findChild("jingle", Namespace.JINGLE);
|
final Element jingle = findChild("jingle", Namespace.JINGLE);
|
||||||
ImmutableMap.Builder<String, Content> builder = new ImmutableMap.Builder<>();
|
ImmutableMap.Builder<String, Content> builder = new ImmutableMap.Builder<>();
|
||||||
|
@ -56,8 +63,8 @@ public class JinglePacket extends IqPacket {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setJingleContent(final Content content) { //take content interface
|
public void addJingleContent(final Content content) { //take content interface
|
||||||
setJingleChild(content);
|
addJingleChild(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Reason getReason() {
|
public Reason getReason() {
|
||||||
|
@ -87,7 +94,7 @@ public class JinglePacket extends IqPacket {
|
||||||
return jingle == null ? null : jingle.findChild(name);
|
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);
|
final Element jingle = findChild("jingle", Namespace.JINGLE);
|
||||||
jingle.addChild(child);
|
jingle.addChild(child);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,11 @@ import eu.siacs.conversations.xmpp.jingle.SessionDescription;
|
||||||
public class RtpDescription extends GenericDescription {
|
public class RtpDescription extends GenericDescription {
|
||||||
|
|
||||||
|
|
||||||
|
private RtpDescription(final String media) {
|
||||||
|
super("description", Namespace.JINGLE_APPS_RTP);
|
||||||
|
this.setAttribute("media", media);
|
||||||
|
}
|
||||||
|
|
||||||
private RtpDescription() {
|
private RtpDescription() {
|
||||||
super("description", Namespace.JINGLE_APPS_RTP);
|
super("description", Namespace.JINGLE_APPS_RTP);
|
||||||
}
|
}
|
||||||
|
@ -447,7 +452,7 @@ 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(media.media);
|
||||||
final Map<String, List<Parameter>> parameterMap = new HashMap<>();
|
final Map<String, List<Parameter>> parameterMap = new HashMap<>();
|
||||||
final ArrayListMultimap<String, Element> feedbackNegotiationMap = ArrayListMultimap.create();
|
final ArrayListMultimap<String, Element> feedbackNegotiationMap = ArrayListMultimap.create();
|
||||||
final ArrayListMultimap<String, Source.Parameter> sourceParameterMap = ArrayListMultimap.create();
|
final ArrayListMultimap<String, Source.Parameter> sourceParameterMap = ArrayListMultimap.create();
|
||||||
|
|
Loading…
Reference in New Issue