Save This Page
Home » openjdk-7 » javax.sound » sampled » [javadoc | source]
    1   /*
    2    * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.sound.sampled;
   27   
   28   import java.io.File;
   29   import java.io.InputStream;
   30   import java.io.IOException;
   31   import java.io.OutputStream;
   32   import java.net.URL;
   33   
   34   import java.util.HashSet;
   35   import java.util.List;
   36   import java.util.Set;
   37   import java.util.Vector;
   38   import java.util.ArrayList;
   39   
   40   import javax.sound.sampled.spi.AudioFileWriter;
   41   import javax.sound.sampled.spi.AudioFileReader;
   42   import javax.sound.sampled.spi.FormatConversionProvider;
   43   import javax.sound.sampled.spi.MixerProvider;
   44   
   45   import com.sun.media.sound.JDK13Services;
   46   
   47   /* $fb TODO:
   48    * - consistent usage of (typed) collections
   49    */
   50   
   51   
   52   /**
   53    * The <code>AudioSystem</code> class acts as the entry point to the
   54    * sampled-audio system resources. This class lets you query and
   55    * access the mixers that are installed on the system.
   56    * <code>AudioSystem</code> includes a number of
   57    * methods for converting audio data between different formats, and for
   58    * translating between audio files and streams. It also provides a method
   59    * for obtaining a <code>{@link Line}</code> directly from the
   60    * <code>AudioSystem</code> without dealing explicitly
   61    * with mixers.
   62    *
   63    * <p>Properties can be used to specify the default mixer
   64    * for specific line types.
   65    * Both system properties and a properties file are considered.
   66    * In the Sun reference implementation, the properties file is
   67    * &quot;lib/sound.properties&quot; in the JRE
   68    * directory. If a property exists both as a system property and in the
   69    * properties file, the system property takes precedence. If none is
   70    * specified, a suitable default is chosen among the available devices.
   71    * The syntax of the properties file is specified in
   72    * {@link java.util.Properties#load(InputStream) Properties.load}. The
   73    * following table lists the available property keys and which methods
   74    * consider them:
   75    *
   76    * <table border=0>
   77    *  <tr>
   78    *   <th>Property Key</th>
   79    *   <th>Interface</th>
   80    *   <th>Affected Method(s)</th>
   81    *  </tr>
   82    *  <tr>
   83    *   <td><code>javax.sound.sampled.Clip</code></td>
   84    *   <td>{@link Clip}</td>
   85    *   <td>{@link #getLine}, {@link #getClip}</td>
   86    *  </tr>
   87    *  <tr>
   88    *   <td><code>javax.sound.sampled.Port</code></td>
   89    *   <td>{@link Port}</td>
   90    *   <td>{@link #getLine}</td>
   91    *  </tr>
   92    *  <tr>
   93    *   <td><code>javax.sound.sampled.SourceDataLine</code></td>
   94    *   <td>{@link SourceDataLine}</td>
   95    *   <td>{@link #getLine}, {@link #getSourceDataLine}</td>
   96    *  </tr>
   97    *  <tr>
   98    *   <td><code>javax.sound.sampled.TargetDataLine</code></td>
   99    *   <td>{@link TargetDataLine}</td>
  100    *   <td>{@link #getLine}, {@link #getTargetDataLine}</td>
  101    *  </tr>
  102    * </table>
  103    *
  104    * The property value consists of the provider class name
  105    * and the mixer name, separated by the hash mark (&quot;#&quot;).
  106    * The provider class name is the fully-qualified
  107    * name of a concrete {@link javax.sound.sampled.spi.MixerProvider
  108    * mixer provider} class. The mixer name is matched against
  109    * the <code>String</code> returned by the <code>getName</code>
  110    * method of <code>Mixer.Info</code>.
  111    * Either the class name, or the mixer name may be omitted.
  112    * If only the class name is specified, the trailing hash mark
  113    * is optional.
  114    *
  115    * <p>If the provider class is specified, and it can be
  116    * successully retrieved from the installed providers, the list of
  117    * <code>Mixer.Info</code> objects is retrieved
  118    * from the provider. Otherwise, or when these mixers
  119    * do not provide a subsequent match, the list is retrieved
  120    * from {@link #getMixerInfo} to contain
  121    * all available <code>Mixer.Info</code> objects.
  122    *
  123    * <p>If a mixer name is specified, the resulting list of
  124    * <code>Mixer.Info</code> objects is searched:
  125    * the first one with a matching name, and whose
  126    * <code>Mixer</code> provides the
  127    * respective line interface, will be returned.
  128    * If no matching <code>Mixer.Info</code> object
  129    * is found, or the mixer name is not specified,
  130    * the first mixer from the resulting
  131    * list, which provides the respective line
  132    * interface, will be returned.
  133    *
  134    * For example, the property <code>javax.sound.sampled.Clip</code>
  135    * with a value
  136    * <code>&quot;com.sun.media.sound.MixerProvider#SunClip&quot;</code>
  137    * will have the following consequences when
  138    * <code>getLine</code> is called requesting a <code>Clip</code>
  139    * instance:
  140    * if the class <code>com.sun.media.sound.MixerProvider</code> exists
  141    * in the list of installed mixer providers,
  142    * the first <code>Clip</code> from the first mixer with name
  143    * <code>&quot;SunClip&quot;</code> will be returned. If it cannot
  144    * be found, the first <code>Clip</code> from the first mixer
  145    * of the specified provider will be returned, regardless of name.
  146    * If there is none, the first <code>Clip</code> from the first
  147    * <code>Mixer</code> with name
  148    * <code>&quot;SunClip&quot;</code> in the list of all mixers
  149    * (as returned by <code>getMixerInfo</code>) will be returned,
  150    * or, if not found, the first <code>Clip</code> of the first
  151    * <code>Mixer</code>that can be found in the list of all
  152    * mixers is returned.
  153    * If that fails, too, an <code>IllegalArgumentException</code>
  154    * is thrown.
  155    *
  156    * @author Kara Kytle
  157    * @author Florian Bomers
  158    * @author Matthias Pfisterer
  159    * @author Kevin P. Smith
  160    *
  161    * @see AudioFormat
  162    * @see AudioInputStream
  163    * @see Mixer
  164    * @see Line
  165    * @see Line.Info
  166    * @since 1.3
  167    */
  168   public class AudioSystem {
  169   
  170       /**
  171        * An integer that stands for an unknown numeric value.
  172        * This value is appropriate only for signed quantities that do not
  173        * normally take negative values.  Examples include file sizes, frame
  174        * sizes, buffer sizes, and sample rates.
  175        * A number of Java Sound constructors accept
  176        * a value of <code>NOT_SPECIFIED</code> for such parameters.  Other
  177        * methods may also accept or return this value, as documented.
  178        */
  179       public static final int NOT_SPECIFIED = -1;
  180   
  181       /**
  182        * Private no-args constructor for ensuring against instantiation.
  183        */
  184       private AudioSystem() {
  185       }
  186   
  187   
  188       /**
  189        * Obtains an array of mixer info objects that represents
  190        * the set of audio mixers that are currently installed on the system.
  191        * @return an array of info objects for the currently installed mixers.  If no mixers
  192        * are available on the system, an array of length 0 is returned.
  193        * @see #getMixer
  194        */
  195       public static Mixer.Info[] getMixerInfo() {
  196   
  197           List infos = getMixerInfoList();
  198           Mixer.Info[] allInfos = (Mixer.Info[]) infos.toArray(new Mixer.Info[infos.size()]);
  199           return allInfos;
  200       }
  201   
  202   
  203       /**
  204        * Obtains the requested audio mixer.
  205        * @param info a <code>Mixer.Info</code> object representing the desired
  206        * mixer, or <code>null</code> for the system default mixer
  207        * @return the requested mixer
  208        * @throws SecurityException if the requested mixer
  209        * is unavailable because of security restrictions
  210        * @throws IllegalArgumentException if the info object does not represent
  211        * a mixer installed on the system
  212        * @see #getMixerInfo
  213        */
  214       public static Mixer getMixer(Mixer.Info info) {
  215   
  216           Mixer mixer = null;
  217           List providers = getMixerProviders();
  218   
  219           for(int i = 0; i < providers.size(); i++ ) {
  220   
  221               try {
  222                   return ((MixerProvider)providers.get(i)).getMixer(info);
  223   
  224               } catch (IllegalArgumentException e) {
  225               } catch (NullPointerException e) {
  226                   // $$jb 08.20.99:  If the strings in the info object aren't
  227                   // set, then Netscape (using jdk1.1.5) tends to throw
  228                   // NPE's when doing some string manipulation.  This is
  229                   // probably not the best fix, but is solves the problem
  230                   // of the NPE in Netscape using local classes
  231                   // $$jb 11.01.99: Replacing this patch.
  232               }
  233           }
  234   
  235           //$$fb if looking for default mixer, and not found yet, add a round of looking
  236           if (info == null) {
  237               for(int i = 0; i < providers.size(); i++ ) {
  238                   try {
  239                       MixerProvider provider = (MixerProvider) providers.get(i);
  240                       Mixer.Info[] infos = provider.getMixerInfo();
  241                       // start from 0 to last device (do not reverse this order)
  242                       for (int ii = 0; ii < infos.length; ii++) {
  243                           try {
  244                               return provider.getMixer(infos[ii]);
  245                           } catch (IllegalArgumentException e) {
  246                               // this is not a good default device :)
  247                           }
  248                       }
  249                   } catch (IllegalArgumentException e) {
  250                   } catch (NullPointerException e) {
  251                   }
  252               }
  253           }
  254   
  255   
  256           throw new IllegalArgumentException("Mixer not supported: "
  257                                              + (info!=null?info.toString():"null"));
  258       }
  259   
  260   
  261       //$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous
  262       /**
  263        * Obtains information about all source lines of a particular type that are supported
  264        * by the installed mixers.
  265        * @param info a <code>Line.Info</code> object that specifies the kind of
  266        * lines about which information is requested
  267        * @return an array of <code>Line.Info</code> objects describing source lines matching
  268        * the type requested.  If no matching source lines are supported, an array of length 0
  269        * is returned.
  270        *
  271        * @see Mixer#getSourceLineInfo(Line.Info)
  272        */
  273       public static Line.Info[] getSourceLineInfo(Line.Info info) {
  274   
  275           Vector vector = new Vector();
  276           Line.Info[] currentInfoArray;
  277   
  278           Mixer mixer;
  279           Line.Info fullInfo = null;
  280           Mixer.Info[] infoArray = getMixerInfo();
  281   
  282           for (int i = 0; i < infoArray.length; i++) {
  283   
  284               mixer = getMixer(infoArray[i]);
  285   
  286               currentInfoArray = mixer.getSourceLineInfo(info);
  287               for (int j = 0; j < currentInfoArray.length; j++) {
  288                   vector.addElement(currentInfoArray[j]);
  289               }
  290           }
  291   
  292           Line.Info[] returnedArray = new Line.Info[vector.size()];
  293   
  294           for (int i = 0; i < returnedArray.length; i++) {
  295               returnedArray[i] = (Line.Info)vector.get(i);
  296           }
  297   
  298           return returnedArray;
  299       }
  300   
  301   
  302       /**
  303        * Obtains information about all target lines of a particular type that are supported
  304        * by the installed mixers.
  305        * @param info a <code>Line.Info</code> object that specifies the kind of
  306        * lines about which information is requested
  307        * @return an array of <code>Line.Info</code> objects describing target lines matching
  308        * the type requested.  If no matching target lines are supported, an array of length 0
  309        * is returned.
  310        *
  311        * @see Mixer#getTargetLineInfo(Line.Info)
  312        */
  313       public static Line.Info[] getTargetLineInfo(Line.Info info) {
  314   
  315           Vector vector = new Vector();
  316           Line.Info[] currentInfoArray;
  317   
  318           Mixer mixer;
  319           Line.Info fullInfo = null;
  320           Mixer.Info[] infoArray = getMixerInfo();
  321   
  322           for (int i = 0; i < infoArray.length; i++) {
  323   
  324               mixer = getMixer(infoArray[i]);
  325   
  326               currentInfoArray = mixer.getTargetLineInfo(info);
  327               for (int j = 0; j < currentInfoArray.length; j++) {
  328                   vector.addElement(currentInfoArray[j]);
  329               }
  330           }
  331   
  332           Line.Info[] returnedArray = new Line.Info[vector.size()];
  333   
  334           for (int i = 0; i < returnedArray.length; i++) {
  335               returnedArray[i] = (Line.Info)vector.get(i);
  336           }
  337   
  338           return returnedArray;
  339       }
  340   
  341   
  342       /**
  343        * Indicates whether the system supports any lines that match
  344        * the specified <code>Line.Info</code> object.  A line is supported if
  345        * any installed mixer supports it.
  346        * @param info a <code>Line.Info</code> object describing the line for which support is queried
  347        * @return <code>true</code> if at least one matching line is
  348        * supported, otherwise <code>false</code>
  349        *
  350        * @see Mixer#isLineSupported(Line.Info)
  351        */
  352       public static boolean isLineSupported(Line.Info info) {
  353   
  354           Mixer mixer;
  355           Mixer.Info[] infoArray = getMixerInfo();
  356   
  357           for (int i = 0; i < infoArray.length; i++) {
  358   
  359               if( infoArray[i] != null ) {
  360                   mixer = getMixer(infoArray[i]);
  361                   if (mixer.isLineSupported(info)) {
  362                       return true;
  363                   }
  364               }
  365           }
  366   
  367           return false;
  368       }
  369   
  370       /**
  371        * Obtains a line that matches the description in the specified
  372        * <code>Line.Info</code> object.
  373        *
  374        * <p>If a <code>DataLine</code> is requested, and <code>info</code>
  375        * is an instance of <code>DataLine.Info</code> specifying at least
  376        * one fully qualified audio format, the last one
  377        * will be used as the default format of the returned
  378        * <code>DataLine</code>.
  379        *
  380        * <p>If system properties
  381        * <code>javax.sound.sampled.Clip</code>,
  382        * <code>javax.sound.sampled.Port</code>,
  383        * <code>javax.sound.sampled.SourceDataLine</code> and
  384        * <code>javax.sound.sampled.TargetDataLine</code> are defined
  385        * or they are defined in the file &quot;sound.properties&quot;,
  386        * they are used to retrieve default lines.
  387        * For details, refer to the {@link AudioSystem class description}.
  388        *
  389        * If the respective property is not set, or the mixer
  390        * requested in the property is not installed or does not provide the
  391        * requested line, all installed mixers are queried for the
  392        * requested line type. A Line will be returned from the first mixer
  393        * providing the requested line type.
  394        *
  395        * @param info a <code>Line.Info</code> object describing the desired kind of line
  396        * @return a line of the requested kind
  397        *
  398        * @throws LineUnavailableException if a matching line
  399        * is not available due to resource restrictions
  400        * @throws SecurityException if a matching line
  401        * is not available due to security restrictions
  402        * @throws IllegalArgumentException if the system does not
  403        * support at least one line matching the specified
  404        * <code>Line.Info</code> object
  405        * through any installed mixer
  406        */
  407       public static Line getLine(Line.Info info) throws LineUnavailableException {
  408           LineUnavailableException lue = null;
  409           List providers = getMixerProviders();
  410   
  411   
  412           // 1: try from default mixer for this line class
  413           try {
  414               Mixer mixer = getDefaultMixer(providers, info);
  415               if (mixer != null && mixer.isLineSupported(info)) {
  416                   return mixer.getLine(info);
  417               }
  418           } catch (LineUnavailableException e) {
  419               lue = e;
  420           } catch (IllegalArgumentException iae) {
  421               // must not happen... but better to catch it here,
  422               // if plug-ins are badly written
  423           }
  424   
  425   
  426           // 2: if that doesn't work, try to find any mixing mixer
  427           for(int i = 0; i < providers.size(); i++) {
  428               MixerProvider provider = (MixerProvider) providers.get(i);
  429               Mixer.Info[] infos = provider.getMixerInfo();
  430   
  431               for (int j = 0; j < infos.length; j++) {
  432                   try {
  433                       Mixer mixer = provider.getMixer(infos[j]);
  434                       // see if this is an appropriate mixer which can mix
  435                       if (isAppropriateMixer(mixer, info, true)) {
  436                           return mixer.getLine(info);
  437                       }
  438                   } catch (LineUnavailableException e) {
  439                       lue = e;
  440                   } catch (IllegalArgumentException iae) {
  441                       // must not happen... but better to catch it here,
  442                       // if plug-ins are badly written
  443                   }
  444               }
  445           }
  446   
  447   
  448           // 3: if that didn't work, try to find any non-mixing mixer
  449           for(int i = 0; i < providers.size(); i++) {
  450               MixerProvider provider = (MixerProvider) providers.get(i);
  451               Mixer.Info[] infos = provider.getMixerInfo();
  452               for (int j = 0; j < infos.length; j++) {
  453                   try {
  454                       Mixer mixer = provider.getMixer(infos[j]);
  455                       // see if this is an appropriate mixer which can mix
  456                       if (isAppropriateMixer(mixer, info, false)) {
  457                           return mixer.getLine(info);
  458                       }
  459                   } catch (LineUnavailableException e) {
  460                       lue = e;
  461                   } catch (IllegalArgumentException iae) {
  462                       // must not happen... but better to catch it here,
  463                       // if plug-ins are badly written
  464                   }
  465               }
  466           }
  467   
  468           // if this line was supported but was not available, throw the last
  469           // LineUnavailableException we got (??).
  470           if (lue != null) {
  471               throw lue;
  472           }
  473   
  474           // otherwise, the requested line was not supported, so throw
  475           // an Illegal argument exception
  476           throw new IllegalArgumentException("No line matching " +
  477                                              info.toString() + " is supported.");
  478       }
  479   
  480   
  481       /**
  482        * Obtains a clip that can be used for playing back
  483        * an audio file or an audio stream. The returned clip
  484        * will be provided by the default system mixer, or,
  485        * if not possible, by any other mixer installed in the
  486        * system that supports a <code>Clip</code>
  487        * object.
  488        *
  489        * <p>The returned clip must be opened with the
  490        * <code>open(AudioFormat)</code> or
  491        * <code>open(AudioInputStream)</code> method.
  492        *
  493        * <p>This is a high-level method that uses <code>getMixer</code>
  494        * and <code>getLine</code> internally.
  495        *
  496        * <p>If the system property
  497        * <code>javax.sound.sampled.Clip</code>
  498        * is defined or it is defined in the file &quot;sound.properties&quot;,
  499        * it is used to retrieve the default clip.
  500        * For details, refer to the {@link AudioSystem class description}.
  501        *
  502        * @return the desired clip object
  503        *
  504        * @throws LineUnavailableException if a clip object
  505        * is not available due to resource restrictions
  506        * @throws SecurityException if a clip object
  507        * is not available due to security restrictions
  508        * @throws IllegalArgumentException if the system does not
  509        * support at least one clip instance through any installed mixer
  510        *
  511        * @see #getClip(Mixer.Info)
  512        * @since 1.5
  513        */
  514       public static Clip getClip() throws LineUnavailableException{
  515           AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
  516                                                AudioSystem.NOT_SPECIFIED,
  517                                                16, 2, 4,
  518                                                AudioSystem.NOT_SPECIFIED, true);
  519           DataLine.Info info = new DataLine.Info(Clip.class, format);
  520           return (Clip) AudioSystem.getLine(info);
  521       }
  522   
  523   
  524       /**
  525        * Obtains a clip from the specified mixer that can be
  526        * used for playing back an audio file or an audio stream.
  527        *
  528        * <p>The returned clip must be opened with the
  529        * <code>open(AudioFormat)</code> or
  530        * <code>open(AudioInputStream)</code> method.
  531        *
  532        * <p>This is a high-level method that uses <code>getMixer</code>
  533        * and <code>getLine</code> internally.
  534        *
  535        * @param mixerInfo a <code>Mixer.Info</code> object representing the
  536        * desired mixer, or <code>null</code> for the system default mixer
  537        * @return a clip object from the specified mixer
  538        *
  539        * @throws LineUnavailableException if a clip
  540        * is not available from this mixer due to resource restrictions
  541        * @throws SecurityException if a clip
  542        * is not available from this mixer due to security restrictions
  543        * @throws IllegalArgumentException if the system does not
  544        * support at least one clip through the specified mixer
  545        *
  546        * @see #getClip()
  547        * @since 1.5
  548        */
  549       public static Clip getClip(Mixer.Info mixerInfo) throws LineUnavailableException{
  550           AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
  551                                                AudioSystem.NOT_SPECIFIED,
  552                                                16, 2, 4,
  553                                                AudioSystem.NOT_SPECIFIED, true);
  554           DataLine.Info info = new DataLine.Info(Clip.class, format);
  555           Mixer mixer = AudioSystem.getMixer(mixerInfo);
  556           return (Clip) mixer.getLine(info);
  557       }
  558   
  559   
  560       /**
  561        * Obtains a source data line that can be used for playing back
  562        * audio data in the format specified by the
  563        * <code>AudioFormat</code> object. The returned line
  564        * will be provided by the default system mixer, or,
  565        * if not possible, by any other mixer installed in the
  566        * system that supports a matching
  567        * <code>SourceDataLine</code> object.
  568        *
  569        * <p>The returned line should be opened with the
  570        * <code>open(AudioFormat)</code> or
  571        * <code>open(AudioFormat, int)</code> method.
  572        *
  573        * <p>This is a high-level method that uses <code>getMixer</code>
  574        * and <code>getLine</code> internally.
  575        *
  576        * <p>The returned <code>SourceDataLine</code>'s default
  577        * audio format will be initialized with <code>format</code>.
  578        *
  579        * <p>If the system property
  580        * <code>javax.sound.sampled.SourceDataLine</code>
  581        * is defined or it is defined in the file &quot;sound.properties&quot;,
  582        * it is used to retrieve the default source data line.
  583        * For details, refer to the {@link AudioSystem class description}.
  584        *
  585        * @param format an <code>AudioFormat</code> object specifying
  586        *        the supported audio format of the returned line,
  587        *        or <code>null</code> for any audio format
  588        * @return the desired <code>SourceDataLine</code> object
  589        *
  590        * @throws LineUnavailableException if a matching source data line
  591        *         is not available due to resource restrictions
  592        * @throws SecurityException if a matching source data line
  593        *         is not available due to security restrictions
  594        * @throws IllegalArgumentException if the system does not
  595        *         support at least one source data line supporting the
  596        *         specified audio format through any installed mixer
  597        *
  598        * @see #getSourceDataLine(AudioFormat, Mixer.Info)
  599        * @since 1.5
  600        */
  601       public static SourceDataLine getSourceDataLine(AudioFormat format)
  602           throws LineUnavailableException{
  603           DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
  604           return (SourceDataLine) AudioSystem.getLine(info);
  605       }
  606   
  607   
  608       /**
  609        * Obtains a source data line that can be used for playing back
  610        * audio data in the format specified by the
  611        * <code>AudioFormat</code> object, provided by the mixer
  612        * specified by the <code>Mixer.Info</code> object.
  613        *
  614        * <p>The returned line should be opened with the
  615        * <code>open(AudioFormat)</code> or
  616        * <code>open(AudioFormat, int)</code> method.
  617        *
  618        * <p>This is a high-level method that uses <code>getMixer</code>
  619        * and <code>getLine</code> internally.
  620        *
  621        * <p>The returned <code>SourceDataLine</code>'s default
  622        * audio format will be initialized with <code>format</code>.
  623        *
  624        * @param format an <code>AudioFormat</code> object specifying
  625        *        the supported audio format of the returned line,
  626        *        or <code>null</code> for any audio format
  627        * @param mixerinfo a <code>Mixer.Info</code> object representing
  628        *        the desired mixer, or <code>null</code> for the system
  629        *        default mixer
  630        * @return the desired <code>SourceDataLine</code> object
  631        *
  632        * @throws LineUnavailableException if a matching source data
  633        *         line is not available from the specified mixer due
  634        *         to resource restrictions
  635        * @throws SecurityException if a matching source data line
  636        *         is not available from the specified mixer due to
  637        *         security restrictions
  638        * @throws IllegalArgumentException if the specified mixer does
  639        *         not support at least one source data line supporting
  640        *         the specified audio format
  641        *
  642        * @see #getSourceDataLine(AudioFormat)
  643        * @since 1.5
  644        */
  645       public static SourceDataLine getSourceDataLine(AudioFormat format,
  646                                                      Mixer.Info mixerinfo)
  647           throws LineUnavailableException{
  648           DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
  649           Mixer mixer = AudioSystem.getMixer(mixerinfo);
  650           return (SourceDataLine) mixer.getLine(info);
  651     }
  652   
  653   
  654       /**
  655        * Obtains a target data line that can be used for recording
  656        * audio data in the format specified by the
  657        * <code>AudioFormat</code> object. The returned line
  658        * will be provided by the default system mixer, or,
  659        * if not possible, by any other mixer installed in the
  660        * system that supports a matching
  661        * <code>TargetDataLine</code> object.
  662        *
  663        * <p>The returned line should be opened with the
  664        * <code>open(AudioFormat)</code> or
  665        * <code>open(AudioFormat, int)</code> method.
  666        *
  667        * <p>This is a high-level method that uses <code>getMixer</code>
  668        * and <code>getLine</code> internally.
  669        *
  670        * <p>The returned <code>TargetDataLine</code>'s default
  671        * audio format will be initialized with <code>format</code>.
  672        *
  673        * @param format an <code>AudioFormat</code> object specifying
  674        *        the supported audio format of the returned line,
  675        *        or <code>null</code> for any audio format
  676        * @return the desired <code>TargetDataLine</code> object
  677        *
  678        * @throws LineUnavailableException if a matching target data line
  679        *         is not available due to resource restrictions
  680        * @throws SecurityException if a matching target data line
  681        *         is not available due to security restrictions
  682        * @throws IllegalArgumentException if the system does not
  683        *         support at least one target data line supporting the
  684        *         specified audio format through any installed mixer
  685        *
  686        * @see #getTargetDataLine(AudioFormat, Mixer.Info)
  687        * @see AudioPermission
  688        * @since 1.5
  689        */
  690       public static TargetDataLine getTargetDataLine(AudioFormat format)
  691           throws LineUnavailableException{
  692   
  693           DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
  694           return (TargetDataLine) AudioSystem.getLine(info);
  695       }
  696   
  697   
  698   
  699       /**
  700        * Obtains a target data line that can be used for recording
  701        * audio data in the format specified by the
  702        * <code>AudioFormat</code> object, provided by the mixer
  703        * specified by the <code>Mixer.Info</code> object.
  704        *
  705        * <p>The returned line should be opened with the
  706        * <code>open(AudioFormat)</code> or
  707        * <code>open(AudioFormat, int)</code> method.
  708        *
  709        * <p>This is a high-level method that uses <code>getMixer</code>
  710        * and <code>getLine</code> internally.
  711        *
  712        * <p>The returned <code>TargetDataLine</code>'s default
  713        * audio format will be initialized with <code>format</code>.
  714        *
  715        * <p>If the system property
  716        * <code>javax.sound.sampled.TargetDataLine</code>
  717        * is defined or it is defined in the file &quot;sound.properties&quot;,
  718        * it is used to retrieve the default target data line.
  719        * For details, refer to the {@link AudioSystem class description}.
  720        *
  721        * @param format an <code>AudioFormat</code> object specifying
  722        *        the supported audio format of the returned line,
  723        *        or <code>null</code> for any audio format
  724        * @param mixerinfo a <code>Mixer.Info</code> object representing the
  725        *        desired mixer, or <code>null</code> for the system default mixer
  726        * @return the desired <code>TargetDataLine</code> object
  727        *
  728        * @throws LineUnavailableException if a matching target data
  729        *         line is not available from the specified mixer due
  730        *         to resource restrictions
  731        * @throws SecurityException if a matching target data line
  732        *         is not available from the specified mixer due to
  733        *         security restrictions
  734        * @throws IllegalArgumentException if the specified mixer does
  735        *         not support at least one target data line supporting
  736        *         the specified audio format
  737        *
  738        * @see #getTargetDataLine(AudioFormat)
  739        * @see AudioPermission
  740        * @since 1.5
  741        */
  742       public static TargetDataLine getTargetDataLine(AudioFormat format,
  743                                                      Mixer.Info mixerinfo)
  744           throws LineUnavailableException {
  745   
  746           DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
  747           Mixer mixer = AudioSystem.getMixer(mixerinfo);
  748           return (TargetDataLine) mixer.getLine(info);
  749       }
  750   
  751   
  752       // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
  753       /**
  754        * Obtains the encodings that the system can obtain from an
  755        * audio input stream with the specified encoding using the set
  756        * of installed format converters.
  757        * @param sourceEncoding the encoding for which conversion support
  758        * is queried
  759        * @return array of encodings.  If <code>sourceEncoding</code>is not supported,
  760        * an array of length 0 is returned. Otherwise, the array will have a length
  761        * of at least 1, representing <code>sourceEncoding</code> (no conversion).
  762        */
  763       public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {
  764   
  765           List codecs = getFormatConversionProviders();
  766           Vector encodings = new Vector();
  767   
  768           AudioFormat.Encoding encs[] = null;
  769   
  770           // gather from all the codecs
  771           for(int i=0; i<codecs.size(); i++ ) {
  772               FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
  773               if( codec.isSourceEncodingSupported( sourceEncoding ) ) {
  774                   encs = codec.getTargetEncodings();
  775                   for (int j = 0; j < encs.length; j++) {
  776                       encodings.addElement( encs[j] );
  777                   }
  778               }
  779           }
  780           AudioFormat.Encoding encs2[] = (AudioFormat.Encoding[]) encodings.toArray(new AudioFormat.Encoding[0]);
  781           return encs2;
  782       }
  783   
  784   
  785   
  786       // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
  787       /**
  788        * Obtains the encodings that the system can obtain from an
  789        * audio input stream with the specified format using the set
  790        * of installed format converters.
  791        * @param sourceFormat the audio format for which conversion
  792        * is queried
  793        * @return array of encodings. If <code>sourceFormat</code>is not supported,
  794        * an array of length 0 is returned. Otherwise, the array will have a length
  795        * of at least 1, representing the encoding of <code>sourceFormat</code> (no conversion).
  796        */
  797       public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) {
  798   
  799   
  800           List codecs = getFormatConversionProviders();
  801           Vector encodings = new Vector();
  802   
  803           int size = 0;
  804           int index = 0;
  805           AudioFormat.Encoding encs[] = null;
  806   
  807           // gather from all the codecs
  808   
  809           for(int i=0; i<codecs.size(); i++ ) {
  810               encs = ((FormatConversionProvider) codecs.get(i)).getTargetEncodings(sourceFormat);
  811               size += encs.length;
  812               encodings.addElement( encs );
  813           }
  814   
  815           // now build a new array
  816   
  817           AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];
  818           for(int i=0; i<encodings.size(); i++ ) {
  819               encs = (AudioFormat.Encoding [])(encodings.get(i));
  820               for(int j=0; j<encs.length; j++ ) {
  821                   encs2[index++] = encs[j];
  822               }
  823           }
  824           return encs2;
  825       }
  826   
  827   
  828       /**
  829        * Indicates whether an audio input stream of the specified encoding
  830        * can be obtained from an audio input stream that has the specified
  831        * format.
  832        * @param targetEncoding the desired encoding after conversion
  833        * @param sourceFormat the audio format before conversion
  834        * @return <code>true</code> if the conversion is supported,
  835        * otherwise <code>false</code>
  836        */
  837       public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
  838   
  839   
  840           List codecs = getFormatConversionProviders();
  841   
  842           for(int i=0; i<codecs.size(); i++ ) {
  843               FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
  844               if(codec.isConversionSupported(targetEncoding,sourceFormat) ) {
  845                   return true;
  846               }
  847           }
  848           return false;
  849       }
  850   
  851   
  852       /**
  853        * Obtains an audio input stream of the indicated encoding, by converting the
  854        * provided audio input stream.
  855        * @param targetEncoding the desired encoding after conversion
  856        * @param sourceStream the stream to be converted
  857        * @return an audio input stream of the indicated encoding
  858        * @throws IllegalArgumentException if the conversion is not supported
  859        * @see #getTargetEncodings(AudioFormat.Encoding)
  860        * @see #getTargetEncodings(AudioFormat)
  861        * @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)
  862        * @see #getAudioInputStream(AudioFormat, AudioInputStream)
  863        */
  864       public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding,
  865                                                          AudioInputStream sourceStream) {
  866   
  867           List codecs = getFormatConversionProviders();
  868   
  869           for(int i = 0; i < codecs.size(); i++) {
  870               FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
  871               if( codec.isConversionSupported( targetEncoding, sourceStream.getFormat() ) ) {
  872                   return codec.getAudioInputStream( targetEncoding, sourceStream );
  873               }
  874           }
  875           // we ran out of options, throw an exception
  876           throw new IllegalArgumentException("Unsupported conversion: " + targetEncoding + " from " + sourceStream.getFormat());
  877       }
  878   
  879   
  880       /**
  881        * Obtains the formats that have a particular encoding and that the system can
  882        * obtain from a stream of the specified format using the set of
  883        * installed format converters.
  884        * @param targetEncoding the desired encoding after conversion
  885        * @param sourceFormat the audio format before conversion
  886        * @return array of formats.  If no formats of the specified
  887        * encoding are supported, an array of length 0 is returned.
  888        */
  889       public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
  890   
  891           List codecs = getFormatConversionProviders();
  892           Vector formats = new Vector();
  893   
  894           int size = 0;
  895           int index = 0;
  896           AudioFormat fmts[] = null;
  897   
  898           // gather from all the codecs
  899   
  900           for(int i=0; i<codecs.size(); i++ ) {
  901               FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
  902               fmts = codec.getTargetFormats(targetEncoding, sourceFormat);
  903               size += fmts.length;
  904               formats.addElement( fmts );
  905           }
  906   
  907           // now build a new array
  908   
  909           AudioFormat fmts2[] = new AudioFormat[size];
  910           for(int i=0; i<formats.size(); i++ ) {
  911               fmts = (AudioFormat [])(formats.get(i));
  912               for(int j=0; j<fmts.length; j++ ) {
  913                   fmts2[index++] = fmts[j];
  914               }
  915           }
  916           return fmts2;
  917       }
  918   
  919   
  920       /**
  921        * Indicates whether an audio input stream of a specified format
  922        * can be obtained from an audio input stream of another specified format.
  923        * @param targetFormat the desired audio format after conversion
  924        * @param sourceFormat the audio format before conversion
  925        * @return <code>true</code> if the conversion is supported,
  926        * otherwise <code>false</code>
  927        */
  928   
  929       public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) {
  930   
  931           List codecs = getFormatConversionProviders();
  932   
  933           for(int i=0; i<codecs.size(); i++ ) {
  934               FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
  935               if(codec.isConversionSupported(targetFormat, sourceFormat) ) {
  936                   return true;
  937               }
  938           }
  939           return false;
  940       }
  941   
  942   
  943       /**
  944        * Obtains an audio input stream of the indicated format, by converting the
  945        * provided audio input stream.
  946        * @param targetFormat the desired audio format after conversion
  947        * @param sourceStream the stream to be converted
  948        * @return an audio input stream of the indicated format
  949        * @throws IllegalArgumentException if the conversion is not supported
  950        * #see #getTargetEncodings(AudioFormat)
  951        * @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)
  952        * @see #isConversionSupported(AudioFormat, AudioFormat)
  953        * @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)
  954        */
  955       public static AudioInputStream getAudioInputStream(AudioFormat targetFormat,
  956                                                          AudioInputStream sourceStream) {
  957   
  958           if (sourceStream.getFormat().matches(targetFormat)) {
  959               return sourceStream;
  960           }
  961   
  962           List codecs = getFormatConversionProviders();
  963   
  964           for(int i = 0; i < codecs.size(); i++) {
  965               FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
  966               if(codec.isConversionSupported(targetFormat,sourceStream.getFormat()) ) {
  967                   return codec.getAudioInputStream(targetFormat,sourceStream);
  968               }
  969           }
  970   
  971           // we ran out of options...
  972           throw new IllegalArgumentException("Unsupported conversion: " + targetFormat + " from " + sourceStream.getFormat());
  973       }
  974   
  975   
  976       /**
  977        * Obtains the audio file format of the provided input stream.  The stream must
  978        * point to valid audio file data.  The implementation of this method may require
  979        * multiple parsers to examine the stream to determine whether they support it.
  980        * These parsers must be able to mark the stream, read enough data to determine whether they
  981        * support the stream, and, if not, reset the stream's read pointer to its original
  982        * position.  If the input stream does not support these operations, this method may fail
  983        * with an <code>IOException</code>.
  984        * @param stream the input stream from which file format information should be
  985        * extracted
  986        * @return an <code>AudioFileFormat</code> object describing the stream's audio file format
  987        * @throws UnsupportedAudioFileException if the stream does not point to valid audio
  988        * file data recognized by the system
  989        * @throws IOException if an input/output exception occurs
  990        * @see InputStream#markSupported
  991        * @see InputStream#mark
  992        */
  993       public static AudioFileFormat getAudioFileFormat(InputStream stream)
  994           throws UnsupportedAudioFileException, IOException {
  995   
  996           List providers = getAudioFileReaders();
  997           AudioFileFormat format = null;
  998   
  999           for(int i = 0; i < providers.size(); i++ ) {
 1000               AudioFileReader reader = (AudioFileReader) providers.get(i);
 1001               try {
 1002                   format = reader.getAudioFileFormat( stream ); // throws IOException
 1003                   break;
 1004               } catch (UnsupportedAudioFileException e) {
 1005                   continue;
 1006               }
 1007           }
 1008   
 1009           if( format==null ) {
 1010               throw new UnsupportedAudioFileException("file is not a supported file type");
 1011           } else {
 1012               return format;
 1013           }
 1014       }
 1015   
 1016       /**
 1017        * Obtains the audio file format of the specified URL.  The URL must
 1018        * point to valid audio file data.
 1019        * @param url the URL from which file format information should be
 1020        * extracted
 1021        * @return an <code>AudioFileFormat</code> object describing the audio file format
 1022        * @throws UnsupportedAudioFileException if the URL does not point to valid audio
 1023        * file data recognized by the system
 1024        * @throws IOException if an input/output exception occurs
 1025        */
 1026       public static AudioFileFormat getAudioFileFormat(URL url)
 1027           throws UnsupportedAudioFileException, IOException {
 1028   
 1029           List providers = getAudioFileReaders();
 1030           AudioFileFormat format = null;
 1031   
 1032           for(int i = 0; i < providers.size(); i++ ) {
 1033               AudioFileReader reader = (AudioFileReader) providers.get(i);
 1034               try {
 1035                   format = reader.getAudioFileFormat( url ); // throws IOException
 1036                   break;
 1037               } catch (UnsupportedAudioFileException e) {
 1038                   continue;
 1039               }
 1040           }
 1041   
 1042           if( format==null ) {
 1043               throw new UnsupportedAudioFileException("file is not a supported file type");
 1044           } else {
 1045               return format;
 1046           }
 1047       }
 1048   
 1049       /**
 1050        * Obtains the audio file format of the specified <code>File</code>.  The <code>File</code> must
 1051        * point to valid audio file data.
 1052        * @param file the <code>File</code> from which file format information should be
 1053        * extracted
 1054        * @return an <code>AudioFileFormat</code> object describing the audio file format
 1055        * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
 1056        * file data recognized by the system
 1057        * @throws IOException if an I/O exception occurs
 1058        */
 1059       public static AudioFileFormat getAudioFileFormat(File file)
 1060           throws UnsupportedAudioFileException, IOException {
 1061   
 1062           List providers = getAudioFileReaders();
 1063           AudioFileFormat format = null;
 1064   
 1065           for(int i = 0; i < providers.size(); i++ ) {
 1066               AudioFileReader reader = (AudioFileReader) providers.get(i);
 1067               try {
 1068                   format = reader.getAudioFileFormat( file ); // throws IOException
 1069                   break;
 1070               } catch (UnsupportedAudioFileException e) {
 1071                   continue;
 1072               }
 1073           }
 1074   
 1075           if( format==null ) {
 1076               throw new UnsupportedAudioFileException("file is not a supported file type");
 1077           } else {
 1078               return format;
 1079           }
 1080       }
 1081   
 1082   
 1083       /**
 1084        * Obtains an audio input stream from the provided input stream.  The stream must
 1085        * point to valid audio file data.  The implementation of this method may
 1086        * require multiple parsers to
 1087        * examine the stream to determine whether they support it.  These parsers must
 1088        * be able to mark the stream, read enough data to determine whether they
 1089        * support the stream, and, if not, reset the stream's read pointer to its original
 1090        * position.  If the input stream does not support these operation, this method may fail
 1091        * with an <code>IOException</code>.
 1092        * @param stream the input stream from which the <code>AudioInputStream</code> should be
 1093        * constructed
 1094        * @return an <code>AudioInputStream</code> object based on the audio file data contained
 1095        * in the input stream.
 1096        * @throws UnsupportedAudioFileException if the stream does not point to valid audio
 1097        * file data recognized by the system
 1098        * @throws IOException if an I/O exception occurs
 1099        * @see InputStream#markSupported
 1100        * @see InputStream#mark
 1101        */
 1102       public static AudioInputStream getAudioInputStream(InputStream stream)
 1103           throws UnsupportedAudioFileException, IOException {
 1104   
 1105           List providers = getAudioFileReaders();
 1106           AudioInputStream audioStream = null;
 1107   
 1108           for(int i = 0; i < providers.size(); i++ ) {
 1109               AudioFileReader reader = (AudioFileReader) providers.get(i);
 1110               try {
 1111                   audioStream = reader.getAudioInputStream( stream ); // throws IOException
 1112                   break;
 1113               } catch (UnsupportedAudioFileException e) {
 1114                   continue;
 1115               }
 1116           }
 1117   
 1118           if( audioStream==null ) {
 1119               throw new UnsupportedAudioFileException("could not get audio input stream from input stream");
 1120           } else {
 1121               return audioStream;
 1122           }
 1123       }
 1124   
 1125       /**
 1126        * Obtains an audio input stream from the URL provided.  The URL must
 1127        * point to valid audio file data.
 1128        * @param url the URL for which the <code>AudioInputStream</code> should be
 1129        * constructed
 1130        * @return an <code>AudioInputStream</code> object based on the audio file data pointed
 1131        * to by the URL
 1132        * @throws UnsupportedAudioFileException if the URL does not point to valid audio
 1133        * file data recognized by the system
 1134        * @throws IOException if an I/O exception occurs
 1135        */
 1136       public static AudioInputStream getAudioInputStream(URL url)
 1137           throws UnsupportedAudioFileException, IOException {
 1138   
 1139           List providers = getAudioFileReaders();
 1140           AudioInputStream audioStream = null;
 1141   
 1142           for(int i = 0; i < providers.size(); i++ ) {
 1143               AudioFileReader reader = (AudioFileReader) providers.get(i);
 1144               try {
 1145                   audioStream = reader.getAudioInputStream( url ); // throws IOException
 1146                   break;
 1147               } catch (UnsupportedAudioFileException e) {
 1148                   continue;
 1149               }
 1150           }
 1151   
 1152           if( audioStream==null ) {
 1153               throw new UnsupportedAudioFileException("could not get audio input stream from input URL");
 1154           } else {
 1155               return audioStream;
 1156           }
 1157       }
 1158   
 1159       /**
 1160        * Obtains an audio input stream from the provided <code>File</code>.  The <code>File</code> must
 1161        * point to valid audio file data.
 1162        * @param file the <code>File</code> for which the <code>AudioInputStream</code> should be
 1163        * constructed
 1164        * @return an <code>AudioInputStream</code> object based on the audio file data pointed
 1165        * to by the <code>File</code>
 1166        * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
 1167        * file data recognized by the system
 1168        * @throws IOException if an I/O exception occurs
 1169        */
 1170       public static AudioInputStream getAudioInputStream(File file)
 1171           throws UnsupportedAudioFileException, IOException {
 1172   
 1173           List providers = getAudioFileReaders();
 1174           AudioInputStream audioStream = null;
 1175   
 1176           for(int i = 0; i < providers.size(); i++ ) {
 1177               AudioFileReader reader = (AudioFileReader) providers.get(i);
 1178               try {
 1179                   audioStream = reader.getAudioInputStream( file ); // throws IOException
 1180                   break;
 1181               } catch (UnsupportedAudioFileException e) {
 1182                   continue;
 1183               }
 1184           }
 1185   
 1186           if( audioStream==null ) {
 1187               throw new UnsupportedAudioFileException("could not get audio input stream from input file");
 1188           } else {
 1189               return audioStream;
 1190           }
 1191       }
 1192   
 1193   
 1194       /**
 1195        * Obtains the file types for which file writing support is provided by the system.
 1196        * @return array of unique file types.  If no file types are supported,
 1197        * an array of length 0 is returned.
 1198        */
 1199       public static AudioFileFormat.Type[] getAudioFileTypes() {
 1200           List providers = getAudioFileWriters();
 1201           Set returnTypesSet = new HashSet();
 1202   
 1203           for(int i=0; i < providers.size(); i++) {
 1204               AudioFileWriter writer = (AudioFileWriter) providers.get(i);
 1205               AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes();
 1206               for(int j=0; j < fileTypes.length; j++) {
 1207                   returnTypesSet.add(fileTypes[j]);
 1208               }
 1209           }
 1210           AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])
 1211               returnTypesSet.toArray(new AudioFileFormat.Type[0]);
 1212           return returnTypes;
 1213       }
 1214   
 1215   
 1216       /**
 1217        * Indicates whether file writing support for the specified file type is provided
 1218        * by the system.
 1219        * @param fileType the file type for which write capabilities are queried
 1220        * @return <code>true</code> if the file type is supported,
 1221        * otherwise <code>false</code>
 1222        */
 1223       public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
 1224   
 1225           List providers = getAudioFileWriters();
 1226   
 1227           for(int i=0; i < providers.size(); i++) {
 1228               AudioFileWriter writer = (AudioFileWriter) providers.get(i);
 1229               if (writer.isFileTypeSupported(fileType)) {
 1230                   return true;
 1231               }
 1232           }
 1233           return false;
 1234       }
 1235   
 1236   
 1237       /**
 1238        * Obtains the file types that the system can write from the
 1239        * audio input stream specified.
 1240        * @param stream the audio input stream for which audio file type support
 1241        * is queried
 1242        * @return array of file types.  If no file types are supported,
 1243        * an array of length 0 is returned.
 1244        */
 1245       public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
 1246           List providers = getAudioFileWriters();
 1247           Set returnTypesSet = new HashSet();
 1248   
 1249           for(int i=0; i < providers.size(); i++) {
 1250               AudioFileWriter writer = (AudioFileWriter) providers.get(i);
 1251               AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);
 1252               for(int j=0; j < fileTypes.length; j++) {
 1253                   returnTypesSet.add(fileTypes[j]);
 1254               }
 1255           }
 1256           AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])
 1257               returnTypesSet.toArray(new AudioFileFormat.Type[0]);
 1258           return returnTypes;
 1259       }
 1260   
 1261   
 1262       /**
 1263        * Indicates whether an audio file of the specified file type can be written
 1264        * from the indicated audio input stream.
 1265        * @param fileType the file type for which write capabilities are queried
 1266        * @param stream the stream for which file-writing support is queried
 1267        * @return <code>true</code> if the file type is supported for this audio input stream,
 1268        * otherwise <code>false</code>
 1269        */
 1270       public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
 1271                                                 AudioInputStream stream) {
 1272   
 1273           List providers = getAudioFileWriters();
 1274   
 1275           for(int i=0; i < providers.size(); i++) {
 1276               AudioFileWriter writer = (AudioFileWriter) providers.get(i);
 1277               if(writer.isFileTypeSupported(fileType, stream)) {
 1278                   return true;
 1279               }
 1280           }
 1281           return false;
 1282       }
 1283   
 1284   
 1285       /**
 1286        * Writes a stream of bytes representing an audio file of the specified file type
 1287        * to the output stream provided.  Some file types require that
 1288        * the length be written into the file header; such files cannot be written from
 1289        * start to finish unless the length is known in advance.  An attempt
 1290        * to write a file of such a type will fail with an IOException if the length in
 1291        * the audio file type is <code>AudioSystem.NOT_SPECIFIED</code>.
 1292        *
 1293        * @param stream the audio input stream containing audio data to be
 1294        * written to the file
 1295        * @param fileType the kind of audio file to write
 1296        * @param out the stream to which the file data should be written
 1297        * @return the number of bytes written to the output stream
 1298        * @throws IOException if an input/output exception occurs
 1299        * @throws IllegalArgumentException if the file type is not supported by
 1300        * the system
 1301        * @see #isFileTypeSupported
 1302        * @see     #getAudioFileTypes
 1303        */
 1304       public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
 1305                               OutputStream out) throws IOException {
 1306   
 1307           List providers = getAudioFileWriters();
 1308           int bytesWritten = 0;
 1309           boolean flag = false;
 1310   
 1311           for(int i=0; i < providers.size(); i++) {
 1312               AudioFileWriter writer = (AudioFileWriter) providers.get(i);
 1313               try {
 1314                   bytesWritten = writer.write( stream, fileType, out ); // throws IOException
 1315                   flag = true;
 1316                   break;
 1317               } catch (IllegalArgumentException e) {
 1318                   // thrown if this provider cannot write the sequence, try the next
 1319                   continue;
 1320               }
 1321           }
 1322           if(!flag) {
 1323               throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
 1324           } else {
 1325               return bytesWritten;
 1326           }
 1327       }
 1328   
 1329   
 1330       /**
 1331        * Writes a stream of bytes representing an audio file of the specified file type
 1332        * to the external file provided.
 1333        * @param stream the audio input stream containing audio data to be
 1334        * written to the file
 1335        * @param fileType the kind of audio file to write
 1336        * @param out the external file to which the file data should be written
 1337        * @return the number of bytes written to the file
 1338        * @throws IOException if an I/O exception occurs
 1339        * @throws IllegalArgumentException if the file type is not supported by
 1340        * the system
 1341        * @see #isFileTypeSupported
 1342        * @see     #getAudioFileTypes
 1343        */
 1344       public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
 1345                               File out) throws IOException {
 1346   
 1347           List providers = getAudioFileWriters();
 1348           int bytesWritten = 0;
 1349           boolean flag = false;
 1350   
 1351           for(int i=0; i < providers.size(); i++) {
 1352               AudioFileWriter writer = (AudioFileWriter) providers.get(i);
 1353               try {
 1354                   bytesWritten = writer.write( stream, fileType, out ); // throws IOException
 1355                   flag = true;
 1356                   break;
 1357               } catch (IllegalArgumentException e) {
 1358                   // thrown if this provider cannot write the sequence, try the next
 1359                   continue;
 1360               }
 1361           }
 1362           if (!flag) {
 1363               throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
 1364           } else {
 1365               return bytesWritten;
 1366           }
 1367       }
 1368   
 1369   
 1370       // METHODS FOR INTERNAL IMPLEMENTATION USE
 1371   
 1372       /**
 1373        * Obtains the set of MixerProviders on the system.
 1374        */
 1375       private static List getMixerProviders() {
 1376           return getProviders(MixerProvider.class);
 1377       }
 1378   
 1379   
 1380       /**
 1381        * Obtains the set of format converters (codecs, transcoders, etc.)
 1382        * that are currently installed on the system.
 1383        * @return an array of
 1384        * {@link javax.sound.sampled.spi.FormatConversionProvider
 1385        * FormatConversionProvider}
 1386        * objects representing the available format converters.  If no format
 1387        * converters readers are available on the system, an array of length 0 is
 1388        * returned.
 1389        */
 1390       private static List getFormatConversionProviders() {
 1391           return getProviders(FormatConversionProvider.class);
 1392       }
 1393   
 1394   
 1395       /**
 1396        * Obtains the set of audio file readers that are currently installed on the system.
 1397        * @return a List of
 1398        * {@link javax.sound.sampled.spi.AudioFileReader
 1399        * AudioFileReader}
 1400        * objects representing the installed audio file readers.  If no audio file
 1401        * readers are available on the system, an empty List is returned.
 1402        */
 1403       private static List getAudioFileReaders() {
 1404           return getProviders(AudioFileReader.class);
 1405       }
 1406   
 1407   
 1408       /**
 1409        * Obtains the set of audio file writers that are currently installed on the system.
 1410        * @return a List of
 1411        * {@link javax.sound.samples.spi.AudioFileWriter AudioFileWriter}
 1412        * objects representing the available audio file writers.  If no audio file
 1413        * writers are available on the system, an empty List is returned.
 1414        */
 1415       private static List getAudioFileWriters() {
 1416           return getProviders(AudioFileWriter.class);
 1417       }
 1418   
 1419   
 1420   
 1421       /** Attempts to locate and return a default Mixer that provides lines
 1422        * of the specified type.
 1423        *
 1424        * @param providers the installed mixer providers
 1425        * @param info The requested line type
 1426        * TargetDataLine.class, Clip.class or Port.class.
 1427        * @return a Mixer that matches the requirements, or null if no default mixer found
 1428        */
 1429       private static Mixer getDefaultMixer(List providers, Line.Info info) {
 1430           Class lineClass = info.getLineClass();
 1431           String providerClassName = JDK13Services.getDefaultProviderClassName(lineClass);
 1432           String instanceName = JDK13Services.getDefaultInstanceName(lineClass);
 1433           Mixer mixer;
 1434   
 1435           if (providerClassName != null) {
 1436               MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);
 1437               if (defaultProvider != null) {
 1438                   if (instanceName != null) {
 1439                       mixer = getNamedMixer(instanceName, defaultProvider, info);
 1440                       if (mixer != null) {
 1441                           return mixer;
 1442                       }
 1443                   } else {
 1444                       mixer = getFirstMixer(defaultProvider, info,
 1445                                             false /* mixing not required*/);
 1446                       if (mixer != null) {
 1447                           return mixer;
 1448                       }
 1449                   }
 1450   
 1451               }
 1452           }
 1453   
 1454           /* Provider class not specified or
 1455              provider class cannot be found, or
 1456              provider class and instance specified and instance cannot be found or is not appropriate */
 1457           if (instanceName != null) {
 1458               mixer = getNamedMixer(instanceName, providers, info);
 1459               if (mixer != null) {
 1460                   return mixer;
 1461               }
 1462           }
 1463   
 1464   
 1465           /* No default are specified, or if something is specified, everything
 1466              failed. */
 1467           return null;
 1468       }
 1469   
 1470   
 1471   
 1472       /** Return a MixerProvider of a given class from the list of
 1473           MixerProviders.
 1474   
 1475           This method never requires the returned Mixer to do mixing.
 1476           @param providerClassName The class name of the provider to be returned.
 1477           @param providers The list of MixerProviders that is searched.
 1478           @return A MixerProvider of the requested class, or null if none is
 1479           found.
 1480        */
 1481       private static MixerProvider getNamedProvider(String providerClassName,
 1482                                                     List providers) {
 1483           for(int i = 0; i < providers.size(); i++) {
 1484               MixerProvider provider = (MixerProvider) providers.get(i);
 1485               if (provider.getClass().getName().equals(providerClassName)) {
 1486                   return provider;
 1487               }
 1488           }
 1489           return null;
 1490       }
 1491   
 1492   
 1493       /** Return a Mixer with a given name from a given MixerProvider.
 1494         This method never requires the returned Mixer to do mixing.
 1495         @param mixerName The name of the Mixer to be returned.
 1496         @param provider The MixerProvider to check for Mixers.
 1497         @param info The type of line the returned Mixer is required to
 1498         support.
 1499   
 1500         @return A Mixer matching the requirements, or null if none is found.
 1501        */
 1502       private static Mixer getNamedMixer(String mixerName,
 1503                                          MixerProvider provider,
 1504                                          Line.Info info) {
 1505           Mixer.Info[] infos = provider.getMixerInfo();
 1506           for (int i = 0; i < infos.length; i++) {
 1507               if (infos[i].getName().equals(mixerName)) {
 1508                   Mixer mixer = provider.getMixer(infos[i]);
 1509                   if (isAppropriateMixer(mixer, info, false)) {
 1510                       return mixer;
 1511                   }
 1512               }
 1513           }
 1514           return null;
 1515       }
 1516   
 1517   
 1518       /** From a List of MixerProviders, return a Mixer with a given name.
 1519           This method never requires the returned Mixer to do mixing.
 1520           @param mixerName The name of the Mixer to be returned.
 1521           @param providers The List of MixerProviders to check for Mixers.
 1522           @param info The type of line the returned Mixer is required to
 1523           support.
 1524           @return A Mixer matching the requirements, or null if none is found.
 1525        */
 1526       private static Mixer getNamedMixer(String mixerName,
 1527                                          List providers,
 1528                                          Line.Info info) {
 1529           for(int i = 0; i < providers.size(); i++) {
 1530               MixerProvider provider = (MixerProvider) providers.get(i);
 1531               Mixer mixer = getNamedMixer(mixerName, provider, info);
 1532               if (mixer != null) {
 1533                   return mixer;
 1534               }
 1535           }
 1536           return null;
 1537       }
 1538   
 1539   
 1540       /** From a given MixerProvider, return the first appropriate Mixer.
 1541           @param provider The MixerProvider to check for Mixers.
 1542           @param info The type of line the returned Mixer is required to
 1543           support.
 1544           @param isMixingRequired If true, only Mixers that support mixing are
 1545           returned for line types of SourceDataLine and Clip.
 1546   
 1547           @return A Mixer that is considered appropriate, or null
 1548           if none is found.
 1549        */
 1550       private static Mixer getFirstMixer(MixerProvider provider,
 1551                                          Line.Info info,
 1552                                          boolean isMixingRequired) {
 1553           Mixer.Info[] infos = provider.getMixerInfo();
 1554           for (int j = 0; j < infos.length; j++) {
 1555               Mixer mixer = provider.getMixer(infos[j]);
 1556               if (isAppropriateMixer(mixer, info, isMixingRequired)) {
 1557                   return mixer;
 1558               }
 1559           }
 1560           return null;
 1561       }
 1562   
 1563   
 1564       /** Checks if a Mixer is appropriate.
 1565           A Mixer is considered appropriate if it support the given line type.
 1566           If isMixingRequired is true and the line type is an output one
 1567           (SourceDataLine, Clip), the mixer is appropriate if it supports
 1568           at least 2 (concurrent) lines of the given type.
 1569   
 1570           @return true if the mixer is considered appropriate according to the
 1571           rules given above, false otherwise.
 1572        */
 1573       private static boolean isAppropriateMixer(Mixer mixer,
 1574                                                 Line.Info lineInfo,
 1575                                                 boolean isMixingRequired) {
 1576           if (! mixer.isLineSupported(lineInfo)) {
 1577               return false;
 1578           }
 1579           Class lineClass = lineInfo.getLineClass();
 1580           if (isMixingRequired
 1581               && (SourceDataLine.class.isAssignableFrom(lineClass) ||
 1582                   Clip.class.isAssignableFrom(lineClass))) {
 1583               int maxLines = mixer.getMaxLines(lineInfo);
 1584               return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
 1585           }
 1586           return true;
 1587       }
 1588   
 1589   
 1590   
 1591       /**
 1592        * Like getMixerInfo, but return List
 1593        */
 1594       private static List getMixerInfoList() {
 1595           List providers = getMixerProviders();
 1596           return getMixerInfoList(providers);
 1597       }
 1598   
 1599   
 1600       /**
 1601        * Like getMixerInfo, but return List
 1602        */
 1603       private static List getMixerInfoList(List providers) {
 1604           List infos = new ArrayList();
 1605   
 1606           Mixer.Info[] someInfos; // per-mixer
 1607           Mixer.Info[] allInfos;  // for all mixers
 1608   
 1609           for(int i = 0; i < providers.size(); i++ ) {
 1610               someInfos = (Mixer.Info[])
 1611                   ((MixerProvider)providers.get(i)).getMixerInfo();
 1612   
 1613               for (int j = 0; j < someInfos.length; j++) {
 1614                   infos.add(someInfos[j]);
 1615               }
 1616           }
 1617   
 1618           return infos;
 1619       }
 1620   
 1621   
 1622       /**
 1623        * Obtains the set of services currently installed on the system
 1624        * using sun.misc.Service, the SPI mechanism in 1.3.
 1625        * @return a List of instances of providers for the requested service.
 1626        * If no providers are available, a vector of length 0 will be returned.
 1627        */
 1628       private static List getProviders(Class providerClass) {
 1629           return JDK13Services.getProviders(providerClass);
 1630       }
 1631   }

Save This Page
Home » openjdk-7 » javax.sound » sampled » [javadoc | source]