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