1package eu.siacs.conversations.xmpp.jingle.stanzas;
2
3import com.google.common.base.Preconditions;
4import com.google.common.collect.ImmutableList;
5
6import java.util.List;
7import java.util.Locale;
8
9import eu.siacs.conversations.xml.Element;
10import eu.siacs.conversations.xml.Namespace;
11
12public class RtpDescription extends GenericDescription {
13
14
15 private RtpDescription(String name, String namespace) {
16 super(name, namespace);
17 }
18
19 public Media getMedia() {
20 return Media.of(this.getAttribute("media"));
21 }
22
23 public List<PayloadType> getPayloadTypes() {
24 final ImmutableList.Builder<PayloadType> builder = new ImmutableList.Builder<>();
25 for(Element child : getChildren()) {
26 if ("payload-type".equals(child.getName())) {
27 builder.add(PayloadType.of(child));
28 }
29 }
30 return builder.build();
31 }
32
33 public List<RtpHeaderExtension> getHeaderExtensions() {
34 final ImmutableList.Builder<RtpHeaderExtension> builder = new ImmutableList.Builder<>();
35 for(final Element child : getChildren()) {
36 if ("rtp-hdrext".equals(child.getName()) && Namespace.JINGLE_RTP_HEADER_EXTENSIONS.equals(child.getNamespace())) {
37 builder.add(RtpHeaderExtension.upgrade(child));
38 }
39 }
40 return builder.build();
41 }
42
43 public static RtpDescription upgrade(final Element element) {
44 Preconditions.checkArgument("description".equals(element.getName()), "Name of provided element is not description");
45 Preconditions.checkArgument(Namespace.JINGLE_APPS_RTP.equals(element.getNamespace()), "Element does not match the jingle rtp namespace");
46 final RtpDescription description = new RtpDescription("description", Namespace.JINGLE_APPS_RTP);
47 description.setAttributes(element.getAttributes());
48 description.setChildren(element.getChildren());
49 return description;
50 }
51
52 //TODO: support for https://xmpp.org/extensions/xep-0293.html
53
54
55 public static class RtpHeaderExtension extends Element {
56
57 private RtpHeaderExtension() {
58 super("rtp-hdrext", Namespace.JINGLE_RTP_HEADER_EXTENSIONS);
59 }
60
61 public String getId() {
62 return this.getAttribute("id");
63 }
64
65 public String getUri() {
66 return this.getAttribute("uri");
67 }
68
69 public static RtpHeaderExtension upgrade(final Element element) {
70 Preconditions.checkArgument("rtp-hdrext".equals(element.getName()));
71 Preconditions.checkArgument(Namespace.JINGLE_RTP_HEADER_EXTENSIONS.equals(element.getNamespace()));
72 final RtpHeaderExtension extension = new RtpHeaderExtension();
73 extension.setAttributes(element.getAttributes());
74 extension.setChildren(element.getChildren());
75 return extension;
76 }
77 }
78
79 public static class PayloadType extends Element {
80
81 private PayloadType(String name, String xmlns) {
82 super(name, xmlns);
83 }
84 public String getId() {
85 return this.getAttribute("id");
86 }
87
88 public String getPayloadTypeName() {
89 return this.getAttribute("name");
90 }
91
92 public int getClockRate() {
93 final String clockRate = this.getAttribute("clockrate");
94 if (clockRate == null) {
95 return 0;
96 }
97 try {
98 return Integer.parseInt(clockRate);
99 } catch (NumberFormatException e) {
100 return 0;
101 }
102 }
103
104 public int getChannels() {
105 final String channels = this.getAttribute("channels");
106 if (channels == null) {
107 return 1; // The number of channels; if omitted, it MUST be assumed to contain one channel
108 }
109 try {
110 return Integer.parseInt(channels);
111 } catch (NumberFormatException e) {
112 return 1;
113 }
114 }
115
116 public List<Parameter> getParameters() {
117 final ImmutableList.Builder<Parameter> builder = new ImmutableList.Builder<>();
118 for (Element child : getChildren()) {
119 if ("parameter".equals(child.getName())) {
120 builder.add(Parameter.of(child));
121 }
122 }
123 return builder.build();
124 }
125
126 public static PayloadType of(final Element element) {
127 Preconditions.checkArgument("payload-type".equals(element.getName()), "element name must be called payload-type");
128 PayloadType payloadType = new PayloadType("payload-type", Namespace.JINGLE_APPS_RTP);
129 payloadType.setAttributes(element.getAttributes());
130 payloadType.setChildren(element.getChildren());
131 return payloadType;
132 }
133 }
134
135 public static class Parameter extends Element {
136
137 private Parameter() {
138 super("parameter", Namespace.JINGLE_APPS_RTP);
139 }
140
141 public Parameter(String name, String value) {
142 super("parameter", Namespace.JINGLE_APPS_RTP);
143 this.setAttribute("name", name);
144 this.setAttribute("value", value);
145 }
146
147 public String getParameterName() {
148 return this.getAttribute("name");
149 }
150
151 public String getParameterValue() {
152 return this.getAttribute("value");
153 }
154
155 public static Parameter of(final Element element) {
156 Preconditions.checkArgument("parameter".equals(element.getName()), "element name must be called parameter");
157 Parameter parameter = new Parameter();
158 parameter.setAttributes(element.getAttributes());
159 parameter.setChildren(element.getChildren());
160 return parameter;
161 }
162 }
163
164 public enum Media {
165 VIDEO, AUDIO, UNKNOWN;
166
167 @Override
168 public String toString() {
169 return super.toString().toLowerCase(Locale.ROOT);
170 }
171
172 public static Media of(String value) {
173 try {
174 return value == null ? UNKNOWN : Media.valueOf(value.toUpperCase(Locale.ROOT));
175 } catch (IllegalArgumentException e) {
176 return UNKNOWN;
177 }
178 }
179 }
180}