1 /*
2 * jSDP: A Java implementation of SDP protocol Copyright (C) 2007 Claudio Di
3 * Vita
4 */
5 package net.sourceforge.jsdp;
6
7 import java.util.Vector;
8 import java.util.regex.Pattern;
9
10 /**
11 * A <tt>Media</tt> represents a <b>m=<i><field value></i></b> field
12 * contained in a SDP message. The media field identifies information about the
13 * formats of the media associated with the session. A media field includes:
14 * <ul>
15 * <li>A media type (audio, video, etc.)</li>
16 * <li>A port number (or set of ports)</li>
17 * <li>A protocol to be used (like RTP/AVP)</li>
18 * </ul>
19 *
20 * @since 0.1.0
21 *
22 * @version 1.0
23 *
24 * @author <a href="mailto:cdivita@users.sourceforge.net">Claudio Di Vita</a>
25 */
26 public class Media implements Field {
27
28 /** The class Stream Unique Identifier, SUID */
29 private static final long serialVersionUID = 8009552820375695269L;
30
31 /** The pattern used to validate media type and formats */
32 private static final Pattern mediaPattern = Pattern.compile("\\w+");
33
34 /** The pattern used to validate the transport protocol */
35 private static final Pattern protocolPattern = Pattern.compile("[\\w/]+");
36
37 /** The media type */
38 protected String media;
39
40 /** The transport port to which the media stream will be sent */
41 protected int port;
42
43 /** The number of transport port where the media stream will be sent */
44 protected int portsCount;
45
46 /** The transport protocol */
47 protected String protocol;
48
49 /** The media formats */
50 protected Vector formats;
51
52 /**
53 * Creates a new <tt>Media</tt>.
54 */
55 protected Media() {
56
57 super();
58 }
59
60 /**
61 * Creates a new <tt>Media</tt>.
62 *
63 * @param media the media type
64 *
65 * @param port the transport port to which the media stream will be sent
66 *
67 * @param portsCount the number of transport ports where the media stream
68 * will be sent
69 *
70 * @param protocol the transport protocol
71 *
72 * @param format the media default format
73 *
74 * @throws SDPException if the parameters are not valid
75 */
76 public Media(final String media, final int port, final int portsCount, final String protocol, final String format) throws SDPException {
77
78 super();
79
80 setMediaType(media);
81 setPort(port);
82 setPortsCount(portsCount);
83 setProtocol(protocol);
84
85 formats = new Vector(3);
86 addMediaFormat(format);
87 }
88
89 /**
90 * Creates a new <tt>Media</tt>.
91 *
92 * @param media the media type
93 *
94 * @param port the transport port to which the media stream will be sent
95 *
96 * @param protocol the transport protocol
97 *
98 * @param format the media default format
99 *
100 * @throws SDPException if the parameters are not valid
101 */
102 public Media(final String media, final int port, final String protocol, final String format) throws SDPException {
103
104 this(media, port, 1, protocol, format);
105 }
106
107 /**
108 * Parse an input string and constructs the equivalent media field.
109 *
110 * @param field the string to parse
111 *
112 * @return a new <tt>Origin</tt> instance
113 *
114 * @throws SDPParseException if an error occurs while parsing
115 */
116 public static Media parse(final String field) throws SDPParseException {
117
118 if (!field.startsWith("m=")) {
119 throw new SDPParseException("The string \"" + field + "\" isn't a media field");
120 }
121
122 Media m = null;
123
124 /* Split the values */
125 String[] values = field.substring(2).split(" ");
126
127 try {
128
129 /* Each media field must have at least 4 parameters */
130 if (values.length < 4) {
131 throw new SDPException("Some media field parameters are missing");
132 }
133
134 String portInfo = values[1];
135 String[] portInfoValues = portInfo.split("/");
136
137 if (portInfoValues.length == 1) {
138 m = new Media(values[0], Integer.parseInt(values[1]), values[2], values[3]);
139 }
140 else if (portInfoValues.length == 2) {
141 m = new Media(values[0], Integer.parseInt(portInfoValues[0]), Integer.parseInt(portInfoValues[1]), values[2], values[3]);
142 }
143
144 /* Add the media formats, if present */
145 try {
146 for (int i = 4; i < values.length; i++) {
147 m.addMediaFormat(values[i]);
148 }
149 }
150 catch (SDPException invalidMediaFormat) {
151 /*
152 * The media format is not valid, but because it's optional the
153 * exception is not throwed
154 */
155 }
156 }
157 catch (SDPException parseException) {
158 throw new SDPParseException("The string \"" + field + "\" isn't a valid origin field", parseException);
159 }
160
161 return m;
162 }
163
164 /**
165 * Adds a media format.
166 *
167 * @param format the media format to add
168 *
169 * @throws SDPException if the media format is not valid
170 */
171 public void addMediaFormat(final String format) throws SDPException {
172
173 if (!mediaPattern.matcher(format).matches()) {
174 throw new SDPException("Invalid media format: " + format);
175 }
176
177 formats.add(format);
178 }
179
180 /**
181 * Returns a clone of this field.
182 *
183 * @return a clone of this field
184 */
185 public Object clone() {
186
187 Media field = new Media();
188
189 field.media = new String(media);
190 field.port = port;
191 field.portsCount = portsCount;
192 field.protocol = new String(protocol);
193 field.formats = (Vector) formats.clone();
194
195 return field;
196 }
197
198 /**
199 * Returns the media formats
200 *
201 * @return the media formats
202 */
203 public String[] getMediaFormats() {
204
205 return (String[]) formats.toArray(new String[formats.size()]);
206 }
207
208 /**
209 * Returns the type of the media.
210 *
211 * @return the media tpye
212 */
213 public String getMediaType() {
214
215 return media;
216 }
217
218 /**
219 * Returns the transport port to which the media stream will be sent.
220 *
221 * @return the transport port
222 */
223 public int getPort() {
224
225 return port;
226 }
227
228 /**
229 * Returns the number of ports associated with this media.
230 *
231 * @return the ports count
232 */
233 public int getPortsCount() {
234
235 return portsCount;
236 }
237
238 /**
239 * Returns the protocol over which this media should be transmitted.
240 *
241 * @return the transport protocol
242 */
243 public String getProtocol() {
244
245 return protocol;
246 }
247
248 /**
249 * Returns the type character for the field.
250 *
251 * @return the field type character: <tt>m</tt>
252 */
253 public char getType() {
254
255 return Field.MEDIA_FIELD;
256 }
257
258 /**
259 * Sets the media formats.
260 *
261 * @param formats the formats to set
262 *
263 * @throws SDPException if one or more media formats are not valid
264 *
265 * @throws IllegalArgumentException if the media formats are <tt>null</tt>
266 */
267 public void setMediaFormats(final String[] formats) throws SDPException {
268
269 if (formats == null) {
270 throw new IllegalArgumentException("The media formats cannot be null");
271 }
272
273 /* Make a copoy of the current formats */
274 Vector elements = (Vector) this.formats.clone();
275
276 /* Clear the current formats */
277 this.formats.clear();
278
279 try {
280 for (int i = 0; i < formats.length; i++) {
281 addMediaFormat(formats[i]);
282 }
283 }
284 catch (SDPException invalidFormat) {
285
286 /* Restore the previous formats */
287 this.formats = elements;
288
289 /* Throw the exception */
290 throw new SDPException("Invalid media formats", invalidFormat);
291 }
292 }
293
294 /**
295 * Sets the media type.
296 *
297 * @param media the media type to set
298 *
299 * @throws SDPException if the media type is not valid
300 */
301 public void setMediaType(final String media) throws SDPException {
302
303 if (!mediaPattern.matcher(media).matches()) {
304 throw new SDPException("Invalid media type: " + media);
305 }
306
307 this.media = media;
308 }
309
310 /**
311 * Sets the media transport port.
312 *
313 * @param port the transport port
314 *
315 * @throws SDPException if the transport port is less than <tt>1</tt>
316 */
317 public void setPort(final int port) throws SDPException {
318
319 if (port < 0) {
320 throw new SDPException("The transport port must be greater than 0");
321 }
322
323 this.port = port;
324 }
325
326 /**
327 * Sets the number of transport ports where the media stream will be sent.
328 *
329 * @param n the number of ports
330 *
331 * @throws SDPException if the number of ports is less than <tt>1</tt>
332 */
333 public void setPortsCount(final int n) throws SDPException {
334
335 if (n < 1) {
336 throw new SDPException("The ports count must be greater than 0");
337 }
338
339 portsCount = n;
340 }
341
342 /**
343 * Sets the protocol over which this media should be transmitted.
344 *
345 * @param protocol the transport protocol
346 *
347 * @throws SDPException if the transport protocol is not valid
348 */
349 public void setProtocol(final String protocol) throws SDPException {
350
351 if (!protocolPattern.matcher(protocol).matches()) {
352 throw new SDPException("Invalid protocol: " + protocol);
353 }
354
355 this.protocol = protocol;
356 }
357
358 /**
359 * Returns a string representation of the field.The representation has the
360 * form: <b>m=<i><media></i> <i><port></i>/<i><portsCount></i>
361 * <i><protocol></i> <i><formats></i></b>
362 *
363 * @return the string representation of the field
364 */
365 public String toString() {
366
367 StringBuffer result = new StringBuffer(getType() + "=");
368
369 result.append(media);
370 result.append(" " + port);
371
372 if (portsCount > 1) {
373 result.append("/" + portsCount);
374 }
375
376 result.append(" " + protocol);
377 for (int i = 0; i < formats.size(); i++) {
378 result.append(" " + formats.get(i));
379 }
380
381 return result.toString();
382 }
383 }