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
26package 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 */
69public interface Line extends AutoCloseable {
70
71    /**
72     * Obtains the {@code Line.Info} object describing this line.
73     *
74     * @return description of the line
75     */
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     */
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
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     */
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     */
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     */
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     */
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     */
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     */
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         */
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         */
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         */
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
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