View Javadoc

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>&lt;field value&gt;</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>&lt;media&gt;</i> <i>&lt;port&gt;</i>/<i>&lt;portsCount&gt;</i>
361      * <i>&lt;protocol&gt;</i> <i>&lt;formats&gt;</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 }