Package javax.sound.sampled

Source Code of javax.sound.sampled.AudioSystem

/*
* This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com>
* Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/)
**
* Comment: not really modified but is a part of JSound "front-end".
*/

/*
* @(#)AudioSystem.java 1.66 03/03/21
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

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.Vector;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

import javax.sound.sampled.spi.AudioFileWriter;
import javax.sound.sampled.spi.AudioFileReader;
import javax.sound.sampled.spi.FormatConversionProvider;
import javax.sound.sampled.spi.MixerProvider;

/**
* 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.
*
* @author Kara Kytle
* @version 1.66, 03/03/21
*
* @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 strings for services classes and methods
     */
    private static final String defaultServicesClassName =
        "com.sun.media.sound.DefaultServices";
    private static final String jdk13ServicesClassName =
        "com.sun.media.sound.JDK13Services";

    private static final String servicesMethodName =
        "getProviders";
    private static final Class[] servicesParamTypes =
        new Class[] { String.class };

    /**
     * debugging
     */
    private final static boolean DEBUG = false;

    /**
     * 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() {

        int i;
        int j;

        Vector providers = getMixerProviders();
        Vector infos = new Vector();

        Mixer.Info[] someInfos; // per-mixer
        Mixer.Info[] allInfos;  // for all mixers

        //$$fb 2002-11-07: addendum fix for
        //    bug 4487550: Service providers cannot be used to replace existing providers
        for(i = providers.size() - 1; i >= 0; i-- ) {

            someInfos = (Mixer.Info[])
                ((MixerProvider)providers.elementAt(i)).getMixerInfo();

            for (j = 0; j < someInfos.length; j++) {
                infos.addElement(someInfos[j]);
            }
        }

        allInfos = new Mixer.Info[infos.size()];

        for (i = 0; i < allInfos.length; i++) {

            allInfos[i] = (Mixer.Info)infos.elementAt(i);
        }

        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;
        Vector providers = getMixerProviders();

        //$$fb 2002-11-07: addendum fix for
        //    bug 4487550: Service providers cannot be used to replace existing providers
        for(int i = providers.size() -1; i >= 0; i-- ) {

            try {
                return ((MixerProvider)providers.elementAt(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 = providers.size() -1; i >= 0; i-- ) {
                try {
                    MixerProvider provider = (MixerProvider) providers.elementAt(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.elementAt(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.elementAt(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.
     *
     * @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 {

        Mixer mixer;
        Mixer.Info[] infoArray = getMixerInfo();

        LineUnavailableException lue = null;

        for (int i = 0; i < infoArray.length; i++) {

            mixer = getMixer(infoArray[i]);

            if (mixer.isLineSupported(info)) {

                try {
                    return mixer.getLine(info);
                } catch (LineUnavailableException e) {
                    lue = e;
                }
            }
        }

        // 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.");
    }


    // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
    /**
     * Obtains the encodings that the system can obtain from an
     * audio input stream with the specified encoding using the set
     * of installed format converters.
     * @param sourceEncoding the encoding for which conversion support
     * is queried
     * @return array of encodings.  If <code>sourceEncoding</code>is not supported,
     * an array of length 0 is returned. Otherwise, the array will have a length
     * of at least 1, representing <code>sourceEncoding</code> (no conversion).
     */
    public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {

        FormatConversionProvider codecs[] = getFormatConversionProviders();
        Vector encodings = new Vector();

        int size = 0;
        int index = 0;
        AudioFormat.Encoding encs[] = null;

        // gather from all the codecs
        for(int i=0; i<codecs.length; i++ ) {
            if( codecs[i].isSourceEncodingSupported( sourceEncoding ) ) {
                encs = codecs[i].getTargetEncodings();
                size += encs.length;
                encodings.addElement( encs );
            }
        }

        // now build a new array

        AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];
        for(int i=0; i<encodings.size(); i++ ) {
            encs = (AudioFormat.Encoding [])(encodings.elementAt(i));
            for(int j=0; j<encs.length; j++ ) {
                encs2[index++] = encs[j];
            }
        }
        return encs2;
    }



    // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
    /**
     * Obtains the encodings that the system can obtain from an
     * audio input stream with the specified format using the set
     * of installed format converters.
     * @param sourceFormat the audio format for which conversion
     * is queried
     * @return array of encodings. If <code>sourceFormat</code>is not supported,
     * an array of length 0 is returned. Otherwise, the array will have a length
     * of at least 1, representing the encoding of <code>sourceFormat</code> (no conversion).
     */
    public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) {


        FormatConversionProvider codecs[] = getFormatConversionProviders();
        Vector encodings = new Vector();

        int size = 0;
        int index = 0;
        AudioFormat.Encoding encs[] = null;

        // gather from all the codecs

        for(int i=0; i<codecs.length; i++ ) {
            encs = codecs[i].getTargetEncodings(sourceFormat);
            size += encs.length;
            encodings.addElement( encs );
        }

        // now build a new array

        AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];
        for(int i=0; i<encodings.size(); i++ ) {
            encs = (AudioFormat.Encoding [])(encodings.elementAt(i));
            for(int j=0; j<encs.length; j++ ) {
                encs2[index++] = encs[j];
            }
        }
        return encs2;
    }


    /**
     * Indicates whether an audio input stream of the specified encoding
     * can be obtained from an audio input stream that has the specified
     * format.
     * @param targetEncoding the desired encoding after conversion
     * @param sourceFormat the audio format before conversion
     * @return <code>true</code> if the conversion is supported,
     * otherwise <code>false</code>
     */
    public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {


        FormatConversionProvider codecs[] = getFormatConversionProviders();

        for(int i=0; i<codecs.length; i++ ) {
            if(codecs[i].isConversionSupported(targetEncoding,sourceFormat) ) {
                return true;
            }
        }
        return false;
    }


    /**
     * Obtains an audio input stream of the indicated encoding, by converting the
     * provided audio input stream.
     * @param targetEncoding the desired encoding after conversion
     * @param sourceStream the stream to be converted
     * @return an audio input stream of the indicated encoding
     * @throws IllegalArgumentException if the conversion is not supported
     * @see #getTargetEncodings(AudioFormat.Encoding)
     * @see #getTargetEncodings(AudioFormat)
     * @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)
     * @see #getAudioInputStream(AudioFormat, AudioInputStream)
     */
    public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding,
                                                       AudioInputStream sourceStream) {

        FormatConversionProvider codecs[] = getFormatConversionProviders();

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = codecs.length-1; i >= 0; i-- ) {
            if( codecs[i].isConversionSupported( targetEncoding, sourceStream.getFormat() ) ) {
                return codecs[i].getAudioInputStream( targetEncoding, sourceStream );
            }
        }
        // we ran out of options, throw an exception
        throw new IllegalArgumentException("Unsupported conversion: " + targetEncoding + " from " + sourceStream.getFormat());
    }


    /**
     * Obtains the formats that have a particular encoding and that the system can
     * obtain from a stream of the specified format using the set of
     * installed format converters.
     * @param targetEncoding the desired encoding after conversion
     * @param sourceFormat the audio format before conversion
     * @return array of formats.  If no formats of the specified
     * encoding are supported, an array of length 0 is returned.
     */
    public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {

        FormatConversionProvider codecs[] = getFormatConversionProviders();
        Vector formats = new Vector();

        int size = 0;
        int index = 0;
        AudioFormat fmts[] = null;

        // gather from all the codecs

        for(int i=0; i<codecs.length; i++ ) {
            fmts = codecs[i].getTargetFormats(targetEncoding, sourceFormat);
            size += fmts.length;
            formats.addElement( fmts );
        }

        // now build a new array

        AudioFormat fmts2[] = new AudioFormat[size];
        for(int i=0; i<formats.size(); i++ ) {
            fmts = (AudioFormat [])(formats.elementAt(i));
            for(int j=0; j<fmts.length; j++ ) {
                fmts2[index++] = fmts[j];
            }
        }
        return fmts2;
    }


    /**
     * Indicates whether an audio input stream of a specified format
     * can be obtained from an audio input stream of another specified format.
     * @param targetFormat the desired audio format after conversion
     * @param sourceFormat the audio format before conversion
     * @return <code>true</code> if the conversion is supported,
     * otherwise <code>false</code>
     */

    public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) {

        FormatConversionProvider codecs[] = getFormatConversionProviders();

        for(int i=0; i<codecs.length; i++ ) {
            if(codecs[i].isConversionSupported(targetFormat, sourceFormat) ) {
                return true;
            }
        }
        return false;
    }


    /**
     * Obtains an audio input stream of the indicated format, by converting the
     * provided audio input stream.
     * @param targetFormat the desired audio format after conversion
     * @param sourceStream the stream to be converted
     * @return an audio input stream of the indicated format
     * @throws IllegalArgumentException if the conversion is not supported
     * #see #getTargetEncodings(AudioFormat)
     * @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)
     * @see #isConversionSupported(AudioFormat, AudioFormat)
     * @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)
     */
    public static AudioInputStream getAudioInputStream(AudioFormat targetFormat,
                                                       AudioInputStream sourceStream) {

        if (sourceStream.getFormat().matches(targetFormat)) {
            return sourceStream;
        }

        FormatConversionProvider codecs[] = getFormatConversionProviders();

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = codecs.length-1; i >= 0; i-- ) {

            if(codecs[i].isConversionSupported(targetFormat,sourceStream.getFormat()) ) {
                return codecs[i].getAudioInputStream(targetFormat,sourceStream);
            }
        }

        // we ran out of options...
        throw new IllegalArgumentException("Unsupported conversion: " + targetFormat + " from " + sourceStream.getFormat());
    }


    /**
     * Obtains the audio file format of the provided input stream.  The stream must
     * point to valid audio file data.  The implementation of this method may require
     * multiple parsers to examine the stream to determine whether they support it.
     * These parsers must be able to mark the stream, read enough data to determine whether they
     * support the stream, and, if not, reset the stream's read pointer to its original
     * position.  If the input stream does not support these operations, this method may fail
     * with an <code>IOException</code>.
     * @param stream the input stream from which file format information should be
     * extracted
     * @return an <code>AudioFileFormat</code> object describing the stream's audio file format
     * @throws UnsupportedAudioFileException if the stream does not point to valid audio
     * file data recognized by the system
     * @throws IOException if an input/output exception occurs
     * @see InputStream#markSupported
     * @see InputStream#mark
     */
    public static AudioFileFormat getAudioFileFormat(InputStream stream)
        throws UnsupportedAudioFileException, IOException {

        AudioFileReader providers[] = getAudioFileReaders();
        AudioFileFormat format = null;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                format = providers[i].getAudioFileFormat( stream ); // throws IOException
                break;
            } catch (UnsupportedAudioFileException e) {
                continue;
            }
        }

        if( format==null ) {
            throw new UnsupportedAudioFileException("file is not a supported file type");
        } else {
            return format;
        }
    }

    /**
     * Obtains the audio file format of the specified URL.  The URL must
     * point to valid audio file data.
     * @param url the URL from which file format information should be
     * extracted
     * @return an <code>AudioFileFormat</code> object describing the audio file format
     * @throws UnsupportedAudioFileException if the URL does not point to valid audio
     * file data recognized by the system
     * @throws IOException if an input/output exception occurs
     */
    public static AudioFileFormat getAudioFileFormat(URL url)
        throws UnsupportedAudioFileException, IOException {

        AudioFileReader providers[] = getAudioFileReaders();
        AudioFileFormat format = null;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                format = providers[i].getAudioFileFormat( url ); // throws IOException
                break;
            } catch (UnsupportedAudioFileException e) {
                continue;
            }
        }

        if( format==null ) {
            throw new UnsupportedAudioFileException("file is not a supported file type");
        } else {
            return format;
        }
    }

    /**
     * Obtains the audio file format of the specified <code>File</code>.  The <code>File</code> must
     * point to valid audio file data.
     * @param file the <code>File</code> from which file format information should be
     * extracted
     * @return an <code>AudioFileFormat</code> object describing the audio file format
     * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
     * file data recognized by the system
     * @throws IOException if an I/O exception occurs
     */
    public static AudioFileFormat getAudioFileFormat(File file)
        throws UnsupportedAudioFileException, IOException {

        AudioFileReader providers[] = getAudioFileReaders();
        AudioFileFormat format = null;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                format = providers[i].getAudioFileFormat( file ); // throws IOException
                break;
            } catch (UnsupportedAudioFileException e) {
                continue;
            }
        }

        if( format==null ) {
            throw new UnsupportedAudioFileException("file is not a supported file type");
        } else {
            return format;
        }
    }


    /**
     * Obtains an audio input stream from the provided input stream.  The stream must
     * point to valid audio file data.  The implementation of this method may
     * require multiple parsers to
     * examine the stream to determine whether they support it.  These parsers must
     * be able to mark the stream, read enough data to determine whether they
     * support the stream, and, if not, reset the stream's read pointer to its original
     * position.  If the input stream does not support these operation, this method may fail
     * with an <code>IOException</code>.
     * @param stream the input stream from which the <code>AudioInputStream</code> should be
     * constructed
     * @return an <code>AudioInputStream</code> object based on the audio file data contained
     * in the input stream.
     * @throws UnsupportedAudioFileException if the stream does not point to valid audio
     * file data recognized by the system
     * @throws IOException if an I/O exception occurs
     * @see InputStream#markSupported
     * @see InputStream#mark
     */
    public static AudioInputStream getAudioInputStream(InputStream stream)
        throws UnsupportedAudioFileException, IOException {

        AudioFileReader providers[] = getAudioFileReaders();
        AudioInputStream audioStream = null;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                audioStream = providers[i].getAudioInputStream( stream ); // throws IOException
                break;
            } catch (UnsupportedAudioFileException e) {
                continue;
            }
        }

        if( audioStream==null ) {
            throw new UnsupportedAudioFileException("could not get audio input stream from input stream");
        } else {
            return audioStream;
        }
    }

    /**
     * Obtains an audio input stream from the URL provided.  The URL must
     * point to valid audio file data.
     * @param url the URL for which the <code>AudioInputStream</code> should be
     * constructed
     * @return an <code>AudioInputStream</code> object based on the audio file data pointed
     * to by the URL
     * @throws UnsupportedAudioFileException if the URL does not point to valid audio
     * file data recognized by the system
     * @throws IOException if an I/O exception occurs
     */
    public static AudioInputStream getAudioInputStream(URL url)
        throws UnsupportedAudioFileException, IOException {

        AudioFileReader providers[] = getAudioFileReaders();
        AudioInputStream audioStream = null;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                audioStream = providers[i].getAudioInputStream( url ); // throws IOException
                break;
            } catch (UnsupportedAudioFileException e) {
                continue;
            }
        }

        if( audioStream==null ) {
            throw new UnsupportedAudioFileException("could not get audio input stream from input URL");
        } else {
            return audioStream;
        }
    }

    /**
     * Obtains an audio input stream from the provided <code>File</code>.  The <code>File</code> must
     * point to valid audio file data.
     * @param file the <code>File</code> for which the <code>AudioInputStream</code> should be
     * constructed
     * @return an <code>AudioInputStream</code> object based on the audio file data pointed
     * to by the <code>File</code>
     * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
     * file data recognized by the system
     * @throws IOException if an I/O exception occurs
     */
    public static AudioInputStream getAudioInputStream(File file)
        throws UnsupportedAudioFileException, IOException {

        AudioFileReader providers[] = getAudioFileReaders();
        AudioInputStream audioStream = null;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                audioStream = providers[i].getAudioInputStream( file ); // throws IOException
                break;
            } catch (UnsupportedAudioFileException e) {
                continue;
            }
        }

        if( audioStream==null ) {
            throw new UnsupportedAudioFileException("could not get audio input stream from input file");
        } else {
            return audioStream;
        }
    }


    /**
     * Obtains the file types for which file writing support is provided by the system.
     * @return array of file types.  If no file types are supported,
     * an array of length 0 is returned.
     */
    public static AudioFileFormat.Type[] getAudioFileTypes() {
        //$$fb TODO: this implementation may return duplicates!
        AudioFileWriter providers[] = getAudioFileWriters();
        AudioFileFormat.Type fileTypes[][] = new AudioFileFormat.Type[ providers.length ][];
        AudioFileFormat.Type returnTypes[] = null;
        int numTypes = 0;
        int index = 0;

        // Get all file types
        for(int i=0; i < providers.length; i++) {
            fileTypes[i] = providers[i].getAudioFileTypes();
            numTypes += fileTypes[i].length;
        }
        // Now put them in a 1-D array
        returnTypes = new AudioFileFormat.Type[ numTypes ];
        for(int i=0; i < providers.length; i++) {
            for(int j=0; j < fileTypes[i].length; j++) {
                returnTypes[ index ] = fileTypes[i][j];
                index++;
            }
        }

        return returnTypes;
    }


    /**
     * Indicates whether file writing support for the specified file type is provided
     * by the system.
     * @param fileType the file type for which write capabilities are queried
     * @return <code>true</code> if the file type is supported,
     * otherwise <code>false</code>
     */
    public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {

        AudioFileWriter providers[] = getAudioFileWriters();

        boolean isSupported = false;

        for(int i=0; i < providers.length; i++ ) {
            isSupported = providers[i].isFileTypeSupported(fileType);
            if(isSupported==true) {
                return isSupported;
            }
        }
        return isSupported;
    }


    /**
     * Obtains the file types that the system can write from the
     * audio input stream specified.
     * @param stream the audio input stream for which audio file type support
     * is queried
     * @return array of file types.  If no file types are supported,
     * an array of length 0 is returned.
     */
    public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {

        AudioFileWriter providers[] = getAudioFileWriters();
        AudioFileFormat.Type fileTypes[][] = new AudioFileFormat.Type[ providers.length ][];
        AudioFileFormat.Type returnTypes[] = null;
        int numTypes = 0;
        int index = 0;

        // Get all file types
        for(int i=0; i < providers.length; i++) {
            fileTypes[i] = providers[i].getAudioFileTypes(stream);
            numTypes += fileTypes[i].length;
        }
        // Now put them in a 1-D array
        returnTypes = new AudioFileFormat.Type[ numTypes ];
        for(int i=0; i < providers.length; i++) {
            for(int j=0; j < fileTypes[i].length; j++) {
                returnTypes[ index ] = fileTypes[i][j];
                index++;
            }
        }

        return returnTypes;
    }


    /**
     * Indicates whether an audio file of the specified file type can be written
     * from the indicated audio input stream.
     * @param fileType the file type for which write capabilities are queried
     * @param stream the stream for which file-writing support is queried
     * @return <code>true</code> if the file type is supported for this audio input stream,
     * otherwise <code>false</code>
     */
    public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
                                              AudioInputStream stream) {

        AudioFileWriter providers[] = getAudioFileWriters();

        boolean isSupported = false;

        for(int i=0; i < providers.length; i++ ) {
            isSupported = providers[i].isFileTypeSupported(fileType, stream);
            if(isSupported==true) {
                return isSupported;
            }
        }
        return isSupported;
    }


    /**
     * Writes a stream of bytes representing an audio file of the specified file type
     * to the output stream provided.  Some file types require that
     * the length be written into the file header; such files cannot be written from
     * start to finish unless the length is known in advance.  An attempt
     * to write a file of such a type will fail with an IOException if the length in
     * the audio file type is <code>AudioSystem.NOT_SPECIFIED</code>.
     *
     * @param stream the audio input stream containing audio data to be
     * written to the file
     * @param fileType the kind of audio file to write
     * @param out the stream to which the file data should be written
     * @return the number of bytes written to the output stream
     * @throws IOException if an input/output exception occurs
     * @throws IllegalArgumentException if the file type is not supported by
     * the system
     * @see #isFileTypeSupported
     * @see     #getAudioFileTypes
     */
    public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
                            OutputStream out) throws IOException {

        AudioFileWriter providers[] = getAudioFileWriters();
        int bytesWritten = 0;
        boolean flag = false;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                bytesWritten = providers[i].write( stream, fileType, out ); // throws IOException
                flag = true;
                break;
            } catch (IllegalArgumentException e) {
                // thrown if this provider cannot write the sequence, try the next
                continue;
            }
        }
        if( flag==false ) {
            throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
        } else {
            return bytesWritten;
        }
    }


    /**
     * Writes a stream of bytes representing an audio file of the specified file type
     * to the external file provided.
     * @param stream the audio input stream containing audio data to be
     * written to the file
     * @param fileType the kind of audio file to write
     * @param out the external file to which the file data should be written
     * @return the number of bytes written to the file
     * @throws IOException if an I/O exception occurs
     * @throws IllegalArgumentException if the file type is not supported by
     * the system
     * @see #isFileTypeSupported
     * @see     #getAudioFileTypes
     */
    public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
                            File out) throws IOException {

        AudioFileWriter providers[] = getAudioFileWriters();
        int bytesWritten = 0;
        boolean flag = false;

        //$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
        for(int i = providers.length-1; i >= 0; i-- ) {
            try {
                bytesWritten = providers[i].write( stream, fileType, out ); // throws IOException
                flag = true;
                break;
            } catch (IllegalArgumentException e) {
                // thrown if this provider cannot write the sequence, try the next
                continue;
            }
        }
        if( flag==false ) {
            throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
        } else {
            return bytesWritten;
        }
    }


    // METHODS FOR INTERNAL IMPLEMENTATION USE

    /**
     * Obtains the set of MixerProviders on the system.
     */
    private static Vector getMixerProviders() {

        Vector providers = null;

        try {

            Class.forName( "sun.misc.Service" );
            providers = getJDK13Services("javax.sound.sampled.spi.MixerProvider");

        } catch (Exception e) {

            if (DEBUG) e.printStackTrace();

            // we're not running with 1.3's SPI mechanism
            providers = getDefaultServices("javax.sound.sampled.spi.MixerProvider");
        }

        return providers;
    }

    /**
     * Obtains the set of format converters (codecs, transcoders, etc.)
     * that are currently installed on the system.
     * @return an array of
     * {@link javax.sound.sampled.spi.FormatConversionProvider
     * FormatConversionProvider}
     * objects representing the available format converters.  If no format
     * converters readers are available on the system, an array of length 0 is
     * returned.
     */
    private static FormatConversionProvider[] getFormatConversionProviders() {

        Vector v = new Vector();
        FormatConversionProvider varray[];

        try {

            Class.forName( "sun.misc.Service" );

            v = getJDK13Services("javax.sound.sampled.spi.FormatConversionProvider");

        } catch (Exception e) {

            if (DEBUG) e.printStackTrace();

            // we're not running with 1.3's SPI mechanism
            v = getDefaultServices("javax.sound.sampled.spi.FormatConversionProvider");
        }

        varray = new FormatConversionProvider[ v.size() ];
        for( int i=0; i < varray.length; i++ ) {
            varray[i] = (FormatConversionProvider)(v.elementAt(i));
        }
        return varray;
    }

    /**
     * Obtains the set of audio file readers that are currently installed on the system.
     * @return an array of
     * {@link javax.sound.sampled.spi.AudioFileReader
     * AudioFileReader}
     * objects representing the installed audio file readers.  If no audio file
     * readers are available on the system, an array of length 0 is returned.
     */
    private static AudioFileReader[] getAudioFileReaders() {

        Vector v = new Vector();
        AudioFileReader varray[];

        try {

            Class.forName( "sun.misc.Service" );

            v = getJDK13Services("javax.sound.sampled.spi.AudioFileReader");

        } catch (Exception e) {

            if (DEBUG) e.printStackTrace();

            // we're not running with 1.3's SPI mechanism
            v = getDefaultServices("javax.sound.sampled.spi.AudioFileReader");
        }

        varray = new AudioFileReader[ v.size() ];
        for( int i=0; i < varray.length; i++ ) {
            varray[i] = (AudioFileReader)(v.elementAt(i));
        }
        return varray;
    }

    /**
     * Obtains the set of audio file writers that are currently installed on the system.
     * @return an array of
     * {@link javax.sound.samples.spi.AudioFileWriter AudioFileWriter}
     * objects representing the available audio file writers.  If no audio file
     * writers are available on the system, an array of length 0 is returned.
     */
    private static AudioFileWriter[] getAudioFileWriters() {

        Vector v = new Vector();
        AudioFileWriter varray[];

        try {

            Class.forName( "sun.misc.Service" );

            v = getJDK13Services("javax.sound.sampled.spi.AudioFileWriter");

        } catch (Exception e) {


            if (DEBUG) e.printStackTrace();

            // we're not running with 1.3's SPI mechanism
            v = getDefaultServices("javax.sound.sampled.spi.AudioFileWriter");
        }


        varray = new AudioFileWriter[ v.size() ];
        for( int i=0; i < varray.length; i++ ) {

            varray[i] = (AudioFileWriter)(v.elementAt(i));
        }
        return varray;
    }

    /**
     * Obtains the set of services currently installed on the system
     * using sun.misc.Service, the SPI mechanism in 1.3.
     * @return a Vector of instances of providers for the requested service.
     * If no providers are available, a vector of length 0 will be returned.
     */

    private static Vector getJDK13Services( String serviceName ) {

        Vector v = null;

        try {
            Class jdk13Services =
                Class.forName( jdk13ServicesClassName );

            Method m = jdk13Services.getMethod(
                                               servicesMethodName,
                                               servicesParamTypes);

            Object[] arguments = new Object[] { serviceName };

            v = (Vector) m.invoke(jdk13Services,arguments);

        } catch(InvocationTargetException e1) {
            if (DEBUG) e1.printStackTrace();
            v = new Vector();
        } catch(ClassNotFoundException e2) {
            if (DEBUG) e2.printStackTrace();
            v = new Vector();
        } catch(IllegalAccessException e3) {
            if (DEBUG) e3.printStackTrace();
            v = new Vector();
        } catch(NoSuchMethodException e4) {
            if (DEBUG) e4.printStackTrace();
            v = new Vector();
        }
        return v;
    }
    /**
     * Obtains the default set of services currently installed on the system.
     * This method is only invoked if sun.misc.Service is not available.
     * @return a Vector of instances of providers for the requested service.
     * If no providers are available, a vector of length 0 will be returned.
     */
    private static Vector getDefaultServices( String serviceName ) {

        Vector v = null;

        try {
            Class defaultServices =
                Class.forName( defaultServicesClassName );

            Method m = defaultServices.getMethod(
                                                 servicesMethodName,
                                                 servicesParamTypes);

            Object[] arguments = new Object[] { serviceName };

            v = (Vector) m.invoke(defaultServices,arguments);

        } catch(InvocationTargetException e1) {
            if (DEBUG) e1.printStackTrace();
            v = new Vector();
        } catch(ClassNotFoundException e2) {
            if (DEBUG) e2.printStackTrace();
            v = new Vector();
        } catch(IllegalAccessException e3) {
            if (DEBUG) e3.printStackTrace();
            v = new Vector();
        } catch(NoSuchMethodException e4) {
            if (DEBUG) e4.printStackTrace();
            v = new Vector();
        }
        return v;
    }

}
TOP

Related Classes of javax.sound.sampled.AudioSystem

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.