1631 lines · 63.1 KB · Java
RawDownload
/* * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.sound.sampled; import java.io.File;import java.io.InputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URL; import java.util.HashSet;import java.util.List;import java.util.Set;import java.util.Vector;import java.util.ArrayList; import javax.sound.sampled.spi.AudioFileWriter;import javax.sound.sampled.spi.AudioFileReader;import javax.sound.sampled.spi.FormatConversionProvider;import javax.sound.sampled.spi.MixerProvider; import com.sun.media.sound.JDK13Services; /* $fb TODO: * - consistent usage of (typed) collections */  /** * The <code>AudioSystem</code> class acts as the entry point to the * sampled-audio system resources. This class lets you query and * access the mixers that are installed on the system. * <code>AudioSystem</code> includes a number of * methods for converting audio data between different formats, and for * translating between audio files and streams. It also provides a method * for obtaining a <code>{@link Line}</code> directly from the * <code>AudioSystem</code> without dealing explicitly * with mixers. * * <p>Properties can be used to specify the default mixer * for specific line types. * Both system properties and a properties file are considered. * In the Oracle reference implementation, the properties file is * &quot;lib/sound.properties&quot; in the JRE * directory. If a property exists both as a system property and in the * properties file, the system property takes precedence. If none is * specified, a suitable default is chosen among the available devices. * The syntax of the properties file is specified in * {@link java.util.Properties#load(InputStream) Properties.load}. The * following table lists the available property keys and which methods * consider them: * * <table border=0> *  <tr> *   <th>Property Key</th> *   <th>Interface</th> *   <th>Affected Method(s)</th> *  </tr> *  <tr> *   <td><code>javax.sound.sampled.Clip</code></td> *   <td>{@link Clip}</td> *   <td>{@link #getLine}, {@link #getClip}</td> *  </tr> *  <tr> *   <td><code>javax.sound.sampled.Port</code></td> *   <td>{@link Port}</td> *   <td>{@link #getLine}</td> *  </tr> *  <tr> *   <td><code>javax.sound.sampled.SourceDataLine</code></td> *   <td>{@link SourceDataLine}</td> *   <td>{@link #getLine}, {@link #getSourceDataLine}</td> *  </tr> *  <tr> *   <td><code>javax.sound.sampled.TargetDataLine</code></td> *   <td>{@link TargetDataLine}</td> *   <td>{@link #getLine}, {@link #getTargetDataLine}</td> *  </tr> * </table> * * The property value consists of the provider class name * and the mixer name, separated by the hash mark (&quot;#&quot;). * The provider class name is the fully-qualified * name of a concrete {@link javax.sound.sampled.spi.MixerProvider * mixer provider} class. The mixer name is matched against * the <code>String</code> returned by the <code>getName</code> * method of <code>Mixer.Info</code>. * Either the class name, or the mixer name may be omitted. * If only the class name is specified, the trailing hash mark * is optional. * * <p>If the provider class is specified, and it can be * successully retrieved from the installed providers, the list of * <code>Mixer.Info</code> objects is retrieved * from the provider. Otherwise, or when these mixers * do not provide a subsequent match, the list is retrieved * from {@link #getMixerInfo} to contain * all available <code>Mixer.Info</code> objects. * * <p>If a mixer name is specified, the resulting list of * <code>Mixer.Info</code> objects is searched: * the first one with a matching name, and whose * <code>Mixer</code> provides the * respective line interface, will be returned. * If no matching <code>Mixer.Info</code> object * is found, or the mixer name is not specified, * the first mixer from the resulting * list, which provides the respective line * interface, will be returned. * * For example, the property <code>javax.sound.sampled.Clip</code> * with a value * <code>&quot;com.sun.media.sound.MixerProvider#SunClip&quot;</code> * will have the following consequences when * <code>getLine</code> is called requesting a <code>Clip</code> * instance: * if the class <code>com.sun.media.sound.MixerProvider</code> exists * in the list of installed mixer providers, * the first <code>Clip</code> from the first mixer with name * <code>&quot;SunClip&quot;</code> will be returned. If it cannot * be found, the first <code>Clip</code> from the first mixer * of the specified provider will be returned, regardless of name. * If there is none, the first <code>Clip</code> from the first * <code>Mixer</code> with name * <code>&quot;SunClip&quot;</code> in the list of all mixers * (as returned by <code>getMixerInfo</code>) will be returned, * or, if not found, the first <code>Clip</code> of the first * <code>Mixer</code>that can be found in the list of all * mixers is returned. * If that fails, too, an <code>IllegalArgumentException</code> * is thrown. * * @author Kara Kytle * @author Florian Bomers * @author Matthias Pfisterer * @author Kevin P. Smith * * @see AudioFormat * @see AudioInputStream * @see Mixer * @see Line * @see Line.Info * @since 1.3 */public class AudioSystem {     /**     * An integer that stands for an unknown numeric value.     * This value is appropriate only for signed quantities that do not     * normally take negative values.  Examples include file sizes, frame     * sizes, buffer sizes, and sample rates.     * A number of Java Sound constructors accept     * a value of <code>NOT_SPECIFIED</code> for such parameters.  Other     * methods may also accept or return this value, as documented.     */    public static final int NOT_SPECIFIED = -1;     /**     * Private no-args constructor for ensuring against instantiation.     */    private AudioSystem() {    }      /**     * Obtains an array of mixer info objects that represents     * the set of audio mixers that are currently installed on the system.     * @return an array of info objects for the currently installed mixers.  If no mixers     * are available on the system, an array of length 0 is returned.     * @see #getMixer     */    public static Mixer.Info[] getMixerInfo() {         List infos = getMixerInfoList();        Mixer.Info[] allInfos = (Mixer.Info[]) infos.toArray(new Mixer.Info[infos.size()]);        return allInfos;    }      /**     * Obtains the requested audio mixer.     * @param info a <code>Mixer.Info</code> object representing the desired     * mixer, or <code>null</code> for the system default mixer     * @return the requested mixer     * @throws SecurityException if the requested mixer     * is unavailable because of security restrictions     * @throws IllegalArgumentException if the info object does not represent     * a mixer installed on the system     * @see #getMixerInfo     */    public static Mixer getMixer(Mixer.Info info) {         Mixer mixer = null;        List providers = getMixerProviders();         for(int i = 0; i < providers.size(); i++ ) {             try {                return ((MixerProvider)providers.get(i)).getMixer(info);             } catch (IllegalArgumentException e) {            } catch (NullPointerException e) {                // $$jb 08.20.99:  If the strings in the info object aren't                // set, then Netscape (using jdk1.1.5) tends to throw                // NPE's when doing some string manipulation.  This is                // probably not the best fix, but is solves the problem                // of the NPE in Netscape using local classes                // $$jb 11.01.99: Replacing this patch.            }        }         //$$fb if looking for default mixer, and not found yet, add a round of looking        if (info == null) {            for(int i = 0; i < providers.size(); i++ ) {                try {                    MixerProvider provider = (MixerProvider) providers.get(i);                    Mixer.Info[] infos = provider.getMixerInfo();                    // start from 0 to last device (do not reverse this order)                    for (int ii = 0; ii < infos.length; ii++) {                        try {                            return provider.getMixer(infos[ii]);                        } catch (IllegalArgumentException e) {                            // this is not a good default device :)                        }                    }                } catch (IllegalArgumentException e) {                } catch (NullPointerException e) {                }            }        }          throw new IllegalArgumentException("Mixer not supported: "                                           + (info!=null?info.toString():"null"));    }      //$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous    /**     * Obtains information about all source lines of a particular type that are supported     * by the installed mixers.     * @param info a <code>Line.Info</code> object that specifies the kind of     * lines about which information is requested     * @return an array of <code>Line.Info</code> objects describing source lines matching     * the type requested.  If no matching source lines are supported, an array of length 0     * is returned.     *     * @see Mixer#getSourceLineInfo(Line.Info)     */    public static Line.Info[] getSourceLineInfo(Line.Info info) {         Vector vector = new Vector();        Line.Info[] currentInfoArray;         Mixer mixer;        Line.Info fullInfo = null;        Mixer.Info[] infoArray = getMixerInfo();         for (int i = 0; i < infoArray.length; i++) {             mixer = getMixer(infoArray[i]);             currentInfoArray = mixer.getSourceLineInfo(info);            for (int j = 0; j < currentInfoArray.length; j++) {                vector.addElement(currentInfoArray[j]);            }        }         Line.Info[] returnedArray = new Line.Info[vector.size()];         for (int i = 0; i < returnedArray.length; i++) {            returnedArray[i] = (Line.Info)vector.get(i);        }         return returnedArray;    }      /**     * Obtains information about all target lines of a particular type that are supported     * by the installed mixers.     * @param info a <code>Line.Info</code> object that specifies the kind of     * lines about which information is requested     * @return an array of <code>Line.Info</code> objects describing target lines matching     * the type requested.  If no matching target lines are supported, an array of length 0     * is returned.     *     * @see Mixer#getTargetLineInfo(Line.Info)     */    public static Line.Info[] getTargetLineInfo(Line.Info info) {         Vector vector = new Vector();        Line.Info[] currentInfoArray;         Mixer mixer;        Line.Info fullInfo = null;        Mixer.Info[] infoArray = getMixerInfo();         for (int i = 0; i < infoArray.length; i++) {             mixer = getMixer(infoArray[i]);             currentInfoArray = mixer.getTargetLineInfo(info);            for (int j = 0; j < currentInfoArray.length; j++) {                vector.addElement(currentInfoArray[j]);            }        }         Line.Info[] returnedArray = new Line.Info[vector.size()];         for (int i = 0; i < returnedArray.length; i++) {            returnedArray[i] = (Line.Info)vector.get(i);        }         return returnedArray;    }      /**     * Indicates whether the system supports any lines that match     * the specified <code>Line.Info</code> object.  A line is supported if     * any installed mixer supports it.     * @param info a <code>Line.Info</code> object describing the line for which support is queried     * @return <code>true</code> if at least one matching line is     * supported, otherwise <code>false</code>     *     * @see Mixer#isLineSupported(Line.Info)     */    public static boolean isLineSupported(Line.Info info) {         Mixer mixer;        Mixer.Info[] infoArray = getMixerInfo();         for (int i = 0; i < infoArray.length; i++) {             if( infoArray[i] != null ) {                mixer = getMixer(infoArray[i]);                if (mixer.isLineSupported(info)) {                    return true;                }            }        }         return false;    }     /**     * Obtains a line that matches the description in the specified     * <code>Line.Info</code> object.     *     * <p>If a <code>DataLine</code> is requested, and <code>info</code>     * is an instance of <code>DataLine.Info</code> specifying at least     * one fully qualified audio format, the last one     * will be used as the default format of the returned     * <code>DataLine</code>.     *     * <p>If system properties     * <code>javax.sound.sampled.Clip</code>,     * <code>javax.sound.sampled.Port</code>,     * <code>javax.sound.sampled.SourceDataLine</code> and     * <code>javax.sound.sampled.TargetDataLine</code> are defined     * or they are defined in the file &quot;sound.properties&quot;,     * they are used to retrieve default lines.     * For details, refer to the {@link AudioSystem class description}.     *     * If the respective property is not set, or the mixer     * requested in the property is not installed or does not provide the     * requested line, all installed mixers are queried for the     * requested line type. A Line will be returned from the first mixer     * providing the requested line type.     *     * @param info a <code>Line.Info</code> object describing the desired kind of line     * @return a line of the requested kind     *     * @throws LineUnavailableException if a matching line     * is not available due to resource restrictions     * @throws SecurityException if a matching line     * is not available due to security restrictions     * @throws IllegalArgumentException if the system does not     * support at least one line matching the specified     * <code>Line.Info</code> object     * through any installed mixer     */    public static Line getLine(Line.Info info) throws LineUnavailableException {        LineUnavailableException lue = null;        List providers = getMixerProviders();          // 1: try from default mixer for this line class        try {            Mixer mixer = getDefaultMixer(providers, info);            if (mixer != null && mixer.isLineSupported(info)) {                return mixer.getLine(info);            }        } catch (LineUnavailableException e) {            lue = e;        } catch (IllegalArgumentException iae) {            // must not happen... but better to catch it here,            // if plug-ins are badly written        }          // 2: if that doesn't work, try to find any mixing mixer        for(int i = 0; i < providers.size(); i++) {            MixerProvider provider = (MixerProvider) providers.get(i);            Mixer.Info[] infos = provider.getMixerInfo();             for (int j = 0; j < infos.length; j++) {                try {                    Mixer mixer = provider.getMixer(infos[j]);                    // see if this is an appropriate mixer which can mix                    if (isAppropriateMixer(mixer, info, true)) {                        return mixer.getLine(info);                    }                } catch (LineUnavailableException e) {                    lue = e;                } catch (IllegalArgumentException iae) {                    // must not happen... but better to catch it here,                    // if plug-ins are badly written                }            }        }          // 3: if that didn't work, try to find any non-mixing mixer        for(int i = 0; i < providers.size(); i++) {            MixerProvider provider = (MixerProvider) providers.get(i);            Mixer.Info[] infos = provider.getMixerInfo();            for (int j = 0; j < infos.length; j++) {                try {                    Mixer mixer = provider.getMixer(infos[j]);                    // see if this is an appropriate mixer which can mix                    if (isAppropriateMixer(mixer, info, false)) {                        return mixer.getLine(info);                    }                } catch (LineUnavailableException e) {                    lue = e;                } catch (IllegalArgumentException iae) {                    // must not happen... but better to catch it here,                    // if plug-ins are badly written                }            }        }         // if this line was supported but was not available, throw the last        // LineUnavailableException we got (??).        if (lue != null) {            throw lue;        }         // otherwise, the requested line was not supported, so throw        // an Illegal argument exception        throw new IllegalArgumentException("No line matching " +                                           info.toString() + " is supported.");    }      /**     * Obtains a clip that can be used for playing back     * an audio file or an audio stream. The returned clip     * will be provided by the default system mixer, or,     * if not possible, by any other mixer installed in the     * system that supports a <code>Clip</code>     * object.     *     * <p>The returned clip must be opened with the     * <code>open(AudioFormat)</code> or     * <code>open(AudioInputStream)</code> method.     *     * <p>This is a high-level method that uses <code>getMixer</code>     * and <code>getLine</code> internally.     *     * <p>If the system property     * <code>javax.sound.sampled.Clip</code>     * is defined or it is defined in the file &quot;sound.properties&quot;,     * it is used to retrieve the default clip.     * For details, refer to the {@link AudioSystem class description}.

Lines 1–500 of 1631.