1 /*
2 * Copyright 1999-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.sound.sampled;
27
28 /**
29 * The <code>Line</code> interface represents a mono or multi-channel
30 * audio feed. A line is an element of the digital audio
31 * "pipeline," such as a mixer, an input or output port,
32 * or a data path into or out of a mixer.
33 * <p>
34 * A line can have controls, such as gain, pan, and reverb.
35 * The controls themselves are instances of classes that extend the
36 * base <code>{@link Control}</code> class.
37 * The <code>Line</code> interface provides two accessor methods for
38 * obtaining the line's controls: <code>{@link #getControls getControls}</code> returns the
39 * entire set, and <code>{@link #getControl getControl}</code> returns a single control of
40 * specified type.
41 * <p>
42 * Lines exist in various states at different times. When a line opens, it reserves system
43 * resources for itself, and when it closes, these resources are freed for
44 * other objects or applications. The <code>{@link #isOpen()}</code> method lets
45 * you discover whether a line is open or closed.
46 * An open line need not be processing data, however. Such processing is
47 * typically initiated by subinterface methods such as
48 * <code>{@link SourceDataLine#write SourceDataLine.write}</code> and
49 * <code>{@link TargetDataLine#read TargetDataLine.read}</code>.
50 *<p>
51 * You can register an object to receive notifications whenever the line's
52 * state changes. The object must implement the <code>{@link LineListener}</code>
53 * interface, which consists of the single method
54 * <code>{@link LineListener#update update}</code>.
55 * This method will be invoked when a line opens and closes (and, if it's a
56 * {@link DataLine}, when it starts and stops).
57 *<p>
58 * An object can be registered to listen to multiple lines. The event it
59 * receives in its <code>update</code> method will specify which line created
60 * the event, what type of event it was
61 * (<code>OPEN</code>, <code>CLOSE</code>, <code>START</code>, or <code>STOP</code>),
62 * and how many sample frames the line had processed at the time the event occurred.
63 * <p>
64 * Certain line operations, such as open and close, can generate security
65 * exceptions if invoked by unprivileged code when the line is a shared audio
66 * resource.
67 *
68 * @author Kara Kytle
69 *
70 * @see LineEvent
71 * @since 1.3
72 */
73 public interface Line {
74
75 /**
76 * Obtains the <code>Line.Info</code> object describing this
77 * line.
78 * @return description of the line
79 */
80 public Line.Info getLineInfo();
81
82 /**
83 * Opens the line, indicating that it should acquire any required
84 * system resources and become operational.
85 * If this operation
86 * succeeds, the line is marked as open, and an <code>OPEN</code> event is dispatched
87 * to the line's listeners.
88 * <p>
89 * Note that some lines, once closed, cannot be reopened. Attempts
90 * to reopen such a line will always result in an <code>LineUnavailableException</code>.
91 * <p>
92 * Some types of lines have configurable properties that may affect
93 * resource allocation. For example, a <code>DataLine</code> must
94 * be opened with a particular format and buffer size. Such lines
95 * should provide a mechanism for configuring these properties, such
96 * as an additional <code>open</code> method or methods which allow
97 * an application to specify the desired settings.
98 * <p>
99 * This method takes no arguments, and opens the line with the current
100 * settings. For <code>{@link SourceDataLine}</code> and
101 * <code>{@link TargetDataLine}</code> objects, this means that the line is
102 * opened with default settings. For a <code>{@link Clip}</code>, however,
103 * the buffer size is determined when data is loaded. Since this method does not
104 * allow the application to specify any data to load, an IllegalArgumentException
105 * is thrown. Therefore, you should instead use one of the <code>open</code> methods
106 * provided in the <code>Clip</code> interface to load data into the <code>Clip</code>.
107 * <p>
108 * For <code>DataLine</code>'s, if the <code>DataLine.Info</code>
109 * object which was used to retrieve the line, specifies at least
110 * one fully qualified audio format, the last one will be used
111 * as the default format.
112 *
113 * @throws IllegalArgumentException if this method is called on a Clip instance.
114 * @throws LineUnavailableException if the line cannot be
115 * opened due to resource restrictions.
116 * @throws SecurityException if the line cannot be
117 * opened due to security restrictions.
118 *
119 * @see #close
120 * @see #isOpen
121 * @see LineEvent
122 * @see DataLine
123 * @see Clip#open(AudioFormat, byte[], int, int)
124 * @see Clip#open(AudioInputStream)
125 */
126 public void open() throws LineUnavailableException;
127
128
129 /**
130 * Closes the line, indicating that any system resources
131 * in use by the line can be released. If this operation
132 * succeeds, the line is marked closed and a <code>CLOSE</code> event is dispatched
133 * to the line's listeners.
134 * @throws SecurityException if the line cannot be
135 * closed due to security restrictions.
136 *
137 * @see #open
138 * @see #isOpen
139 * @see LineEvent
140 */
141 public void close();
142
143
144
145 /**
146 * Indicates whether the line is open, meaning that it has reserved
147 * system resources and is operational, although it might not currently be
148 * playing or capturing sound.
149 * @return <code>true</code> if the line is open, otherwise <code>false</code>
150 *
151 * @see #open()
152 * @see #close()
153 */
154 public boolean isOpen();
155
156
157 /**
158 * Obtains the set of controls associated with this line.
159 * Some controls may only be available when the line is open.
160 * If there are no controls, this method returns an array of length 0.
161 * @return the array of controls
162 * @see #getControl
163 */
164 public Control[] getControls();
165
166 /**
167 * Indicates whether the line supports a control of the specified type.
168 * Some controls may only be available when the line is open.
169 * @param control the type of the control for which support is queried
170 * @return <code>true</code> if at least one control of the specified type is
171 * supported, otherwise <code>false</code>.
172 */
173 public boolean isControlSupported(Control.Type control);
174
175
176 /**
177 * Obtains a control of the specified type,
178 * if there is any.
179 * Some controls may only be available when the line is open.
180 * @param control the type of the requested control
181 * @return a control of the specified type
182 * @throws IllegalArgumentException if a control of the specified type
183 * is not supported
184 * @see #getControls
185 * @see #isControlSupported(Control.Type control)
186 */
187 public Control getControl(Control.Type control);
188
189
190 /**
191 * Adds a listener to this line. Whenever the line's status changes, the
192 * listener's <code>update()</code> method is called with a <code>LineEvent</code> object
193 * that describes the change.
194 * @param listener the object to add as a listener to this line
195 * @see #removeLineListener
196 * @see LineListener#update
197 * @see LineEvent
198 */
199 public void addLineListener(LineListener listener);
200
201
202 /**
203 * Removes the specified listener from this line's list of listeners.
204 * @param listener listener to remove
205 * @see #addLineListener
206 */
207 public void removeLineListener(LineListener listener);
208
209
210 /**
211 * A <code>Line.Info</code> object contains information about a line.
212 * The only information provided by <code>Line.Info</code> itself
213 * is the Java class of the line.
214 * A subclass of <code>Line.Info</code> adds other kinds of information
215 * about the line. This additional information depends on which <code>Line</code>
216 * subinterface is implemented by the kind of line that the <code>Line.Info</code>
217 * subclass describes.
218 * <p>
219 * A <code>Line.Info</code> can be retrieved using various methods of
220 * the <code>Line</code>, <code>Mixer</code>, and <code>AudioSystem</code>
221 * interfaces. Other such methods let you pass a <code>Line.Info</code> as
222 * an argument, to learn whether lines matching the specified configuration
223 * are available and to obtain them.
224 *
225 * @author Kara Kytle
226 *
227 * @see Line#getLineInfo
228 * @see Mixer#getSourceLineInfo
229 * @see Mixer#getTargetLineInfo
230 * @see Mixer#getLine <code>Mixer.getLine(Line.Info)</code>
231 * @see Mixer#getSourceLineInfo(Line.Info) <code>Mixer.getSourceLineInfo(Line.Info)</code>
232 * @see Mixer#getSourceLineInfo(Line.Info) <code>Mixer.getTargetLineInfo(Line.Info)</code>
233 * @see Mixer#isLineSupported <code>Mixer.isLineSupported(Line.Info)</code>
234 * @see AudioSystem#getLine <code>AudioSystem.getLine(Line.Info)</code>
235 * @see AudioSystem#getSourceLineInfo <code>AudioSystem.getSourceLineInfo(Line.Info)</code>
236 * @see AudioSystem#getTargetLineInfo <code>AudioSystem.getTargetLineInfo(Line.Info)</code>
237 * @see AudioSystem#isLineSupported <code>AudioSystem.isLineSupported(Line.Info)</code>
238 * @since 1.3
239 */
240 public static class Info {
241
242 /**
243 * The class of the line described by the info object.
244 */
245 private final Class lineClass;
246
247
248 /**
249 * Constructs an info object that describes a line of the specified class.
250 * This constructor is typically used by an application to
251 * describe a desired line.
252 * @param lineClass the class of the line that the new Line.Info object describes
253 */
254 public Info(Class<?> lineClass) {
255
256 if (lineClass == null) {
257 this.lineClass = Line.class;
258 } else {
259 this.lineClass = lineClass;
260 }
261 }
262
263
264
265 /**
266 * Obtains the class of the line that this Line.Info object describes.
267 * @return the described line's class
268 */
269 public Class<?> getLineClass() {
270 return lineClass;
271 }
272
273
274 /**
275 * Indicates whether the specified info object matches this one.
276 * To match, the specified object must be identical to or
277 * a special case of this one. The specified info object
278 * must be either an instance of the same class as this one,
279 * or an instance of a sub-type of this one. In addition, the
280 * attributes of the specified object must be compatible with the
281 * capabilities of this one. Specifically, the routing configuration
282 * for the specified info object must be compatible with that of this
283 * one.
284 * Subclasses may add other criteria to determine whether the two objects
285 * match.
286 *
287 * @param info the info object which is being compared to this one
288 * @return <code>true</code> if the specified object matches this one,
289 * <code>false</code> otherwise
290 */
291 public boolean matches(Info info) {
292
293 // $$kk: 08.30.99: is this backwards?
294 // dataLine.matches(targetDataLine) == true: targetDataLine is always dataLine
295 // targetDataLine.matches(dataLine) == false
296 // so if i want to make sure i get a targetDataLine, i need:
297 // targetDataLine.matches(prospective_match) == true
298 // => prospective_match may be other things as well, but it is at least a targetDataLine
299 // targetDataLine defines the requirements which prospective_match must meet.
300
301
302 // "if this Class object represents a declared class, this method returns
303 // true if the specified Object argument is an instance of the represented
304 // class (or of any of its subclasses)"
305 // GainControlClass.isInstance(MyGainObj) => true
306 // GainControlClass.isInstance(MySpecialGainInterfaceObj) => true
307
308 // this_class.isInstance(that_object) => that object can by cast to this class
309 // => that_object's class may be a subtype of this_class
310 // => that may be more specific (subtype) of this
311
312 // "If this Class object represents an interface, this method returns true
313 // if the class or any superclass of the specified Object argument implements
314 // this interface"
315 // GainControlClass.isInstance(MyGainObj) => true
316 // GainControlClass.isInstance(GenericControlObj) => may be false
317 // => that may be more specific
318
319 if (! (this.getClass().isInstance(info)) ) {
320 return false;
321 }
322
323
324 // this.isAssignableFrom(that) => this is same or super to that
325 // => this is at least as general as that
326 // => that may be subtype of this
327
328 if (! (getLineClass().isAssignableFrom(info.getLineClass())) ) {
329 return false;
330 }
331
332 return true;
333 }
334
335
336 /**
337 * Obtains a textual description of the line info.
338 * @return a string description
339 */
340 public String toString() {
341
342 String fullPackagePath = "javax.sound.sampled.";
343 String initialString = new String(getLineClass().toString());
344 String finalString;
345
346 int index = initialString.indexOf(fullPackagePath);
347
348 if (index != -1) {
349 finalString = initialString.substring(0, index) + initialString.substring( (index + fullPackagePath.length()), initialString.length() );
350 } else {
351 finalString = initialString;
352 }
353
354 return finalString;
355 }
356
357 } // class Info
358
359 } // interface Line