1package eu.siacs.conversations.xmpp.jingle;
2
3import android.util.Log;
4
5import com.google.common.base.Function;
6import com.google.common.base.Preconditions;
7import com.google.common.collect.ImmutableMap;
8import com.google.common.collect.Iterables;
9import com.google.common.collect.Maps;
10
11import org.checkerframework.checker.nullness.compatqual.NullableDecl;
12
13import java.util.Map;
14
15import eu.siacs.conversations.Config;
16import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
17import eu.siacs.conversations.xmpp.jingle.stanzas.GenericDescription;
18import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo;
19import eu.siacs.conversations.xmpp.jingle.stanzas.Group;
20import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
21import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
22import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
23
24public class RtpContentMap {
25
26 public final Group group;
27 public final Map<String, DescriptionTransport> contents;
28
29 private RtpContentMap(Group group, Map<String, DescriptionTransport> contents) {
30 this.group = group;
31 this.contents = contents;
32 }
33
34 public static RtpContentMap of(final JinglePacket jinglePacket) {
35 return new RtpContentMap(jinglePacket.getGroup(), DescriptionTransport.of(jinglePacket.getJingleContents()));
36 }
37
38 public static RtpContentMap of(final SessionDescription sessionDescription) {
39 final ImmutableMap.Builder<String, DescriptionTransport> contentMapBuilder = new ImmutableMap.Builder<>();
40 for (SessionDescription.Media media : sessionDescription.media) {
41 final String id = Iterables.getFirst(media.attributes.get("mid"), null);
42 Preconditions.checkNotNull(id, "media has no mid");
43 contentMapBuilder.put(id, DescriptionTransport.of(sessionDescription, media));
44 }
45 final String groupAttribute = Iterables.getFirst(sessionDescription.attributes.get("group"), null);
46 final Group group = groupAttribute == null ? null : Group.ofSdpString(groupAttribute);
47 return new RtpContentMap(group, contentMapBuilder.build());
48 }
49
50 public JinglePacket toJinglePacket(final JinglePacket.Action action, final String sessionId) {
51 final JinglePacket jinglePacket = new JinglePacket(action, sessionId);
52 if (this.group != null) {
53 jinglePacket.addGroup(this.group);
54 }
55 for (Map.Entry<String, DescriptionTransport> entry : this.contents.entrySet()) {
56 final Content content = new Content(Content.Creator.INITIATOR, entry.getKey());
57 content.addChild(entry.getValue().description);
58 content.addChild(entry.getValue().transport);
59 jinglePacket.addJingleContent(content);
60 }
61 return jinglePacket;
62 }
63
64 public static class DescriptionTransport {
65 public final RtpDescription description;
66 public final IceUdpTransportInfo transport;
67
68 public DescriptionTransport(final RtpDescription description, final IceUdpTransportInfo transport) {
69 this.description = description;
70 this.transport = transport;
71 }
72
73 public static DescriptionTransport of(final Content content) {
74 final GenericDescription description = content.getDescription();
75 final GenericTransportInfo transportInfo = content.getTransport();
76 final RtpDescription rtpDescription;
77 final IceUdpTransportInfo iceUdpTransportInfo;
78 if (description instanceof RtpDescription) {
79 rtpDescription = (RtpDescription) description;
80 } else {
81 Log.d(Config.LOGTAG, "description was " + description);
82 throw new IllegalArgumentException("Content does not contain RtpDescription");
83 }
84 if (transportInfo instanceof IceUdpTransportInfo) {
85 iceUdpTransportInfo = (IceUdpTransportInfo) transportInfo;
86 } else {
87 throw new IllegalArgumentException("Content does not contain ICE-UDP transport");
88 }
89 return new DescriptionTransport(rtpDescription, iceUdpTransportInfo);
90 }
91
92 public static DescriptionTransport of(final SessionDescription sessionDescription, final SessionDescription.Media media) {
93 final RtpDescription rtpDescription = RtpDescription.of(media);
94 final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo();
95 return new DescriptionTransport(rtpDescription, transportInfo);
96 }
97
98 public static Map<String, DescriptionTransport> of(final Map<String, Content> contents) {
99 return ImmutableMap.copyOf(Maps.transformValues(contents, new Function<Content, DescriptionTransport>() {
100 @NullableDecl
101 @Override
102 public DescriptionTransport apply(@NullableDecl Content content) {
103 return content == null ? null : of(content);
104 }
105 }));
106 }
107 }
108}