< prev index next >

src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java

Print this page


   1 /*
   2  * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.sound.sampled;
  27 
  28 import java.io.EOFException;
  29 import java.io.File;
  30 import java.io.IOException;
  31 import java.io.InputStream;
  32 import java.io.OutputStream;
  33 import java.net.URL;
  34 import java.util.ArrayList;
  35 import java.util.Collections;
  36 import java.util.HashSet;
  37 import java.util.List;
  38 import java.util.Objects;
  39 import java.util.Properties;
  40 import java.util.Set;
  41 import java.util.Vector;
  42 
  43 import javax.sound.sampled.spi.AudioFileReader;
  44 import javax.sound.sampled.spi.AudioFileWriter;
  45 import javax.sound.sampled.spi.FormatConversionProvider;
  46 import javax.sound.sampled.spi.MixerProvider;
  47 
  48 import com.sun.media.sound.JDK13Services;


  58  * installed on the system. {@code AudioSystem} includes a number of methods for
  59  * converting audio data between different formats, and for translating between
  60  * audio files and streams. It also provides a method for obtaining a
  61  * {@link Line} directly from the {@code AudioSystem} without dealing explicitly
  62  * with mixers.
  63  * <p>
  64  * Properties can be used to specify the default mixer for specific line types.
  65  * Both system properties and a properties file are considered. The
  66  * "sound.properties" properties file is read from an implementation-specific
  67  * location (typically it is the {@code conf} directory in the Java installation
  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 specified,
  70  * a suitable default is chosen among the available devices. The syntax of the
  71  * properties file is specified in
  72  * {@link Properties#load(InputStream) Properties.load}. The following table
  73  * lists the available property keys and which methods consider them:
  74  *
  75  * <table border=0>
  76  *  <caption>Audio System Property Keys</caption>
  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}</td>
  84  *   <td>{@link Clip}</td>
  85  *   <td>{@link #getLine}, {@link #getClip}</td>
  86  *  </tr>
  87  *  <tr>
  88  *   <td>{@code javax.sound.sampled.Port}</td>
  89  *   <td>{@link Port}</td>
  90  *   <td>{@link #getLine}</td>
  91  *  </tr>
  92  *  <tr>
  93  *   <td>{@code javax.sound.sampled.SourceDataLine}</td>
  94  *   <td>{@link SourceDataLine}</td>
  95  *   <td>{@link #getLine}, {@link #getSourceDataLine}</td>
  96  *  </tr>
  97  *  <tr>
  98  *   <td>{@code javax.sound.sampled.TargetDataLine}</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 and the mixer name,
 105  * separated by the hash mark (&quot;#&quot;). The provider class name is the
 106  * fully-qualified name of a concrete {@link MixerProvider mixer provider}
 107  * class. The mixer name is matched against the {@code String} returned by the
 108  * {@code getName} method of {@code Mixer.Info}. Either the class name, or the
 109  * mixer name may be omitted. If only the class name is specified, the trailing
 110  * hash mark is optional.
 111  * <p>
 112  * If the provider class is specified, and it can be successfully retrieved from
 113  * the installed providers, the list of {@code Mixer.Info} objects is retrieved
 114  * from the provider. Otherwise, or when these mixers do not provide a
 115  * subsequent match, the list is retrieved from {@link #getMixerInfo} to contain
 116  * all available {@code Mixer.Info} objects.
 117  * <p>
 118  * If a mixer name is specified, the resulting list of {@code Mixer.Info}
 119  * objects is searched: the first one with a matching name, and whose
 120  * {@code Mixer} provides the respective line interface, will be returned. If no
 121  * matching {@code Mixer.Info} object is found, or the mixer name is not
 122  * specified, the first mixer from the resulting list, which provides the
 123  * respective line interface, will be returned.
 124  *
 125  * For example, the property {@code javax.sound.sampled.Clip} with a value
 126  * {@code "com.sun.media.sound.MixerProvider#SunClip"}
 127  * will have the following consequences when {@code getLine} is called
 128  * requesting a {@code Clip} instance: if the class
 129  * {@code com.sun.media.sound.MixerProvider} exists in the list of installed
 130  * mixer providers, the first {@code Clip} from the first mixer with name
 131  * {@code "SunClip"} will be returned. If it cannot be found, the
 132  * first {@code Clip} from the first mixer of the specified provider will be
 133  * returned, regardless of name. If there is none, the first {@code Clip} from
 134  * the first {@code Mixer} with name {@code "SunClip"} in the list of
 135  * all mixers (as returned by {@code getMixerInfo}) will be returned, or, if not
 136  * found, the first {@code Clip} of the first {@code Mixer} that can be found in
 137  * the list of all mixers is returned. If that fails, too, an
 138  * {@code IllegalArgumentException} is thrown.
 139  *
 140  * @author Kara Kytle
 141  * @author Florian Bomers
 142  * @author Matthias Pfisterer
 143  * @author Kevin P. Smith
 144  * @see AudioFormat
 145  * @see AudioInputStream
 146  * @see Mixer
 147  * @see Line
 148  * @see Line.Info
 149  * @since 1.3
 150  */
 151 public class AudioSystem {
 152 
 153     /**
 154      * An integer that stands for an unknown numeric value. This value is
 155      * appropriate only for signed quantities that do not normally take negative
 156      * values. Examples include file sizes, frame sizes, buffer sizes, and
 157      * sample rates. A number of Java Sound constructors accept a value of


 458                                              AudioSystem.NOT_SPECIFIED,
 459                                              16, 2, 4,
 460                                              AudioSystem.NOT_SPECIFIED, true);
 461         DataLine.Info info = new DataLine.Info(Clip.class, format);
 462         return (Clip) AudioSystem.getLine(info);
 463     }
 464 
 465     /**
 466      * Obtains a clip from the specified mixer that can be used for playing back
 467      * an audio file or an audio stream.
 468      * <p>
 469      * The returned clip must be opened with the {@code open(AudioFormat)} or
 470      * {@code open(AudioInputStream)} method.
 471      * <p>
 472      * This is a high-level method that uses {@code getMixer} and
 473      * {@code getLine} internally.
 474      *
 475      * @param  mixerInfo a {@code Mixer.Info} object representing the desired
 476      *         mixer, or {@code null} for the system default mixer
 477      * @return a clip object from the specified mixer
 478      *
 479      * @throws LineUnavailableException if a clip is not available from this
 480      *         mixer due to resource restrictions
 481      * @throws SecurityException if a clip is not available from this mixer due
 482      *         to security restrictions
 483      * @throws IllegalArgumentException if the system does not support at least
 484      *         one clip through the specified mixer
 485      * @see #getClip()
 486      * @since 1.5
 487      */
 488     public static Clip getClip(Mixer.Info mixerInfo) throws LineUnavailableException{
 489         AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
 490                                              AudioSystem.NOT_SPECIFIED,
 491                                              16, 2, 4,
 492                                              AudioSystem.NOT_SPECIFIED, true);
 493         DataLine.Info info = new DataLine.Info(Clip.class, format);
 494         Mixer mixer = AudioSystem.getMixer(mixerInfo);
 495         return (Clip) mixer.getLine(info);
 496     }
 497 
 498     /**


 649      * @since 1.5
 650      */
 651     public static TargetDataLine getTargetDataLine(AudioFormat format,
 652                                                    Mixer.Info mixerinfo)
 653         throws LineUnavailableException {
 654 
 655         DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
 656         Mixer mixer = AudioSystem.getMixer(mixerinfo);
 657         return (TargetDataLine) mixer.getLine(info);
 658     }
 659 
 660     // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
 661 
 662     /**
 663      * Obtains the encodings that the system can obtain from an audio input
 664      * stream with the specified encoding using the set of installed format
 665      * converters.
 666      *
 667      * @param  sourceEncoding the encoding for which conversion support is
 668      *         queried
 669      * @return array of encodings. If {@code sourceEncoding}is not supported, an
 670      *         array of length 0 is returned. Otherwise, the array will have a
 671      *         length of at least 1, representing {@code sourceEncoding}
 672      *         (no conversion).
 673      * @throws NullPointerException if {@code sourceEncoding} is {@code null}
 674      */
 675     public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {
 676         Objects.requireNonNull(sourceEncoding);
 677 
 678         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 679         Vector<AudioFormat.Encoding> encodings = new Vector<>();
 680 
 681         AudioFormat.Encoding encs[] = null;
 682 
 683         // gather from all the codecs
 684         for(int i=0; i<codecs.size(); i++ ) {
 685             FormatConversionProvider codec = codecs.get(i);
 686             if( codec.isSourceEncodingSupported( sourceEncoding ) ) {
 687                 encs = codec.getTargetEncodings();
 688                 for (int j = 0; j < encs.length; j++) {
 689                     encodings.addElement( encs[j] );
 690                 }
 691             }


 914      *         valid audio file data recognized by the system
 915      * @throws IOException if an input/output exception occurs
 916      * @throws NullPointerException if {@code stream} is {@code null}
 917      * @see InputStream#markSupported
 918      * @see InputStream#mark
 919      */
 920     public static AudioFileFormat getAudioFileFormat(final InputStream stream)
 921             throws UnsupportedAudioFileException, IOException {
 922         Objects.requireNonNull(stream);
 923 
 924         for (final AudioFileReader reader : getAudioFileReaders()) {
 925             try {
 926                 return reader.getAudioFileFormat(stream);
 927             } catch (final UnsupportedAudioFileException ignored) {
 928             }
 929         }
 930         throw new UnsupportedAudioFileException("Stream of unsupported format");
 931     }
 932 
 933     /**
 934      * Obtains the audio file format of the specified URL. The URL must point to
 935      * valid audio file data.
 936      *
 937      * @param  url the URL from which file format information should be
 938      *         extracted
 939      * @return an {@code AudioFileFormat} object describing the audio file
 940      *         format
 941      * @throws UnsupportedAudioFileException if the URL does not point to valid
 942      *         audio file data recognized by the system
 943      * @throws IOException if an input/output exception occurs
 944      * @throws NullPointerException if {@code url} is {@code null}
 945      */
 946     public static AudioFileFormat getAudioFileFormat(final URL url)
 947             throws UnsupportedAudioFileException, IOException {
 948         Objects.requireNonNull(url);
 949 
 950         for (final AudioFileReader reader : getAudioFileReaders()) {
 951             try {
 952                 return reader.getAudioFileFormat(url);
 953             } catch (final UnsupportedAudioFileException ignored) {
 954             }
 955         }
 956         throw new UnsupportedAudioFileException("URL of unsupported format");
 957     }
 958 
 959     /**
 960      * Obtains the audio file format of the specified {@code File}. The
 961      * {@code File} must point to valid audio file data.
 962      *


1000      *         valid audio file data recognized by the system
1001      * @throws IOException if an I/O exception occurs
1002      * @throws NullPointerException if {@code stream} is {@code null}
1003      * @see InputStream#markSupported
1004      * @see InputStream#mark
1005      */
1006     public static AudioInputStream getAudioInputStream(final InputStream stream)
1007             throws UnsupportedAudioFileException, IOException {
1008         Objects.requireNonNull(stream);
1009 
1010         for (final AudioFileReader reader : getAudioFileReaders()) {
1011             try {
1012                 return reader.getAudioInputStream(stream);
1013             } catch (final UnsupportedAudioFileException ignored) {
1014             }
1015         }
1016         throw new UnsupportedAudioFileException("Stream of unsupported format");
1017     }
1018 
1019     /**
1020      * Obtains an audio input stream from the URL provided. The URL must point
1021      * to valid audio file data.
1022      *
1023      * @param  url the URL for which the {@code AudioInputStream} should be
1024      *         constructed
1025      * @return an {@code AudioInputStream} object based on the audio file data
1026      *         pointed to by the URL
1027      * @throws UnsupportedAudioFileException if the URL does not point to valid
1028      *         audio file data recognized by the system
1029      * @throws IOException if an I/O exception occurs
1030      * @throws NullPointerException if {@code url} is {@code null}
1031      */
1032     public static AudioInputStream getAudioInputStream(final URL url)
1033             throws UnsupportedAudioFileException, IOException {
1034         Objects.requireNonNull(url);
1035 
1036         for (final AudioFileReader reader : getAudioFileReaders()) {
1037             try {
1038                 return reader.getAudioInputStream(url);
1039             } catch (final UnsupportedAudioFileException ignored) {
1040             }
1041         }
1042         throw new UnsupportedAudioFileException("URL of unsupported format");
1043     }
1044 
1045     /**
1046      * Obtains an audio input stream from the provided {@code File}. The
1047      * {@code File} must point to valid audio file data.
1048      *


1100      *         {@code false}
1101      * @throws NullPointerException if {@code fileType} is {@code null}
1102      */
1103     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
1104         Objects.requireNonNull(fileType);
1105         List<AudioFileWriter> providers = getAudioFileWriters();
1106 
1107         for(int i=0; i < providers.size(); i++) {
1108             AudioFileWriter writer = providers.get(i);
1109             if (writer.isFileTypeSupported(fileType)) {
1110                 return true;
1111             }
1112         }
1113         return false;
1114     }
1115 
1116     /**
1117      * Obtains the file types that the system can write from the audio input
1118      * stream specified.
1119      *
1120      * @param  stream the audio input stream for which audio file type
1121      *         support is queried
1122      * @return array of file types. If no file types are supported, an array of
1123      *         length 0 is returned.
1124      * @throws NullPointerException if {@code stream} is {@code null}
1125      */
1126     public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
1127         Objects.requireNonNull(stream);
1128         List<AudioFileWriter> providers = getAudioFileWriters();
1129         Set<AudioFileFormat.Type> returnTypesSet = new HashSet<>();
1130 
1131         for(int i=0; i < providers.size(); i++) {
1132             AudioFileWriter writer = providers.get(i);
1133             AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);
1134             for(int j=0; j < fileTypes.length; j++) {
1135                 returnTypesSet.add(fileTypes[j]);
1136             }
1137         }
1138         AudioFileFormat.Type returnTypes[] =
1139             returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1140         return returnTypes;
1141     }


1154     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
1155                                               AudioInputStream stream) {
1156         Objects.requireNonNull(fileType);
1157         Objects.requireNonNull(stream);
1158         List<AudioFileWriter> providers = getAudioFileWriters();
1159 
1160         for(int i=0; i < providers.size(); i++) {
1161             AudioFileWriter writer = providers.get(i);
1162             if(writer.isFileTypeSupported(fileType, stream)) {
1163                 return true;
1164             }
1165         }
1166         return false;
1167     }
1168 
1169     /**
1170      * Writes a stream of bytes representing an audio file of the specified file
1171      * type to the output stream provided. Some file types require that the
1172      * length be written into the file header; such files cannot be written from
1173      * start to finish unless the length is known in advance. An attempt to
1174      * write a file of such a type will fail with an IOException if the length
1175      * in the audio file type is {@code AudioSystem.NOT_SPECIFIED}.
1176      *
1177      * @param  stream the audio input stream containing audio data to be written
1178      *         to the file
1179      * @param  fileType the kind of audio file to write
1180      * @param  out the stream to which the file data should be written
1181      * @return the number of bytes written to the output stream
1182      * @throws IOException if an input/output exception occurs
1183      * @throws IllegalArgumentException if the file type is not supported by the
1184      *         system
1185      * @throws NullPointerException if {@code stream} or {@code fileType} or
1186      *         {@code out} are {@code null}
1187      * @see #isFileTypeSupported
1188      * @see #getAudioFileTypes
1189      */
1190     public static int write(final AudioInputStream stream,
1191                             final AudioFileFormat.Type fileType,
1192                             final OutputStream out) throws IOException {
1193         Objects.requireNonNull(stream);
1194         Objects.requireNonNull(fileType);
1195         Objects.requireNonNull(out);


1229                             final File out) throws IOException {
1230         Objects.requireNonNull(stream);
1231         Objects.requireNonNull(fileType);
1232         Objects.requireNonNull(out);
1233 
1234         for (final AudioFileWriter writer : getAudioFileWriters()) {
1235             try {
1236                 return writer.write(stream, fileType, out);
1237             } catch (final IllegalArgumentException ignored) {
1238                 // thrown if this provider cannot write the stream, try next
1239             }
1240         }
1241         throw new IllegalArgumentException(
1242                 "could not write audio file: file type not supported: "
1243                         + fileType);
1244     }
1245 
1246     // METHODS FOR INTERNAL IMPLEMENTATION USE
1247 
1248     /**
1249      * Obtains the set of MixerProviders on the system.


1250      */
1251     @SuppressWarnings("unchecked")
1252     private static List<MixerProvider> getMixerProviders() {
1253         return (List<MixerProvider>) getProviders(MixerProvider.class);
1254     }
1255 
1256     /**
1257      * Obtains the set of format converters (codecs, transcoders, etc.) that are
1258      * currently installed on the system.
1259      *
1260      * @return an array of {@link FormatConversionProvider} objects representing
1261      *         the available format converters. If no format converters readers
1262      *         are available on the system, an array of length 0 is returned.
1263      */
1264     @SuppressWarnings("unchecked")
1265     private static List<FormatConversionProvider> getFormatConversionProviders() {
1266         return (List<FormatConversionProvider>) getProviders(FormatConversionProvider.class);
1267     }
1268 
1269     /**


1310 
1311         if (providerClassName != null) {
1312             MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);
1313             if (defaultProvider != null) {
1314                 if (instanceName != null) {
1315                     mixer = getNamedMixer(instanceName, defaultProvider, info);
1316                     if (mixer != null) {
1317                         return mixer;
1318                     }
1319                 } else {
1320                     mixer = getFirstMixer(defaultProvider, info,
1321                                           false /* mixing not required*/);
1322                     if (mixer != null) {
1323                         return mixer;
1324                     }
1325                 }
1326 
1327             }
1328         }
1329 
1330         /* Provider class not specified or
1331            provider class cannot be found, or
1332            provider class and instance specified and instance cannot be found or is not appropriate */


1333         if (instanceName != null) {
1334             mixer = getNamedMixer(instanceName, providers, info);
1335             if (mixer != null) {
1336                 return mixer;
1337             }
1338         }
1339 
1340 
1341         /* No default are specified, or if something is specified, everything
1342            failed. */


1343         return null;
1344     }
1345 
1346     /**
1347      * Return a MixerProvider of a given class from the list of MixerProviders.
1348      * This method never requires the returned Mixer to do mixing.
1349      *
1350      * @param  providerClassName The class name of the provider to be returned
1351      * @param  providers The list of MixerProviders that is searched
1352      * @return A MixerProvider of the requested class, or null if none is found
1353      */
1354     private static MixerProvider getNamedProvider(String providerClassName,
1355                                                   List<MixerProvider> providers) {
1356         for(int i = 0; i < providers.size(); i++) {
1357             MixerProvider provider = providers.get(i);
1358             if (provider.getClass().getName().equals(providerClassName)) {
1359                 return provider;
1360             }
1361         }
1362         return null;


1415      * @param  info The type of line the returned Mixer is required to support
1416      * @param  isMixingRequired If true, only Mixers that support mixing are
1417      *         returned for line types of SourceDataLine and Clip
1418      * @return A Mixer that is considered appropriate, or null if none is found
1419      */
1420     private static Mixer getFirstMixer(MixerProvider provider,
1421                                        Line.Info info,
1422                                        boolean isMixingRequired) {
1423         Mixer.Info[] infos = provider.getMixerInfo();
1424         for (int j = 0; j < infos.length; j++) {
1425             Mixer mixer = provider.getMixer(infos[j]);
1426             if (isAppropriateMixer(mixer, info, isMixingRequired)) {
1427                 return mixer;
1428             }
1429         }
1430         return null;
1431     }
1432 
1433     /**
1434      * Checks if a Mixer is appropriate. A Mixer is considered appropriate if it
1435      * support the given line type. If isMixingRequired is true and the line
1436      * type is an output one (SourceDataLine, Clip), the mixer is appropriate if
1437      * it supports at least 2 (concurrent) lines of the given type.
1438      *




1439      * @return {@code true} if the mixer is considered appropriate according to
1440      *         the rules given above, {@code false} otherwise
1441      */
1442     private static boolean isAppropriateMixer(Mixer mixer,
1443                                               Line.Info lineInfo,
1444                                               boolean isMixingRequired) {
1445         if (! mixer.isLineSupported(lineInfo)) {
1446             return false;
1447         }
1448         Class<?> lineClass = lineInfo.getLineClass();
1449         if (isMixingRequired
1450             && (SourceDataLine.class.isAssignableFrom(lineClass) ||
1451                 Clip.class.isAssignableFrom(lineClass))) {
1452             int maxLines = mixer.getMaxLines(lineInfo);
1453             return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
1454         }
1455         return true;
1456     }
1457 
1458     /**
1459      * Like getMixerInfo, but return List.




1460      */
1461     private static List<Mixer.Info> getMixerInfoList() {
1462         List<MixerProvider> providers = getMixerProviders();
1463         return getMixerInfoList(providers);
1464     }
1465 
1466     /**
1467      * Like getMixerInfo, but return List.





1468      */
1469     private static List<Mixer.Info> getMixerInfoList(List<MixerProvider> providers) {
1470         List<Mixer.Info> infos = new ArrayList<>();
1471 
1472         Mixer.Info[] someInfos; // per-mixer
1473         Mixer.Info[] allInfos;  // for all mixers
1474 
1475         for(int i = 0; i < providers.size(); i++ ) {
1476             someInfos = providers.get(i).getMixerInfo();
1477 
1478             for (int j = 0; j < someInfos.length; j++) {
1479                 infos.add(someInfos[j]);
1480             }
1481         }
1482 
1483         return infos;
1484     }
1485 
1486     /**
1487      * Obtains the set of services currently installed on the system using the
1488      * SPI mechanism in 1.3.
1489      *





1490      * @return a List of instances of providers for the requested service. If no
1491      *         providers are available, a vector of length 0 will be returned.
1492      */
1493     private static List<?> getProviders(Class<?> providerClass) {
1494         return JDK13Services.getProviders(providerClass);
1495     }
1496 }
   1 /*
   2  * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.sound.sampled;
  27 

  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.io.OutputStream;
  32 import java.net.URL;
  33 import java.util.ArrayList;
  34 import java.util.Collections;
  35 import java.util.HashSet;
  36 import java.util.List;
  37 import java.util.Objects;
  38 import java.util.Properties;
  39 import java.util.Set;
  40 import java.util.Vector;
  41 
  42 import javax.sound.sampled.spi.AudioFileReader;
  43 import javax.sound.sampled.spi.AudioFileWriter;
  44 import javax.sound.sampled.spi.FormatConversionProvider;
  45 import javax.sound.sampled.spi.MixerProvider;
  46 
  47 import com.sun.media.sound.JDK13Services;


  57  * installed on the system. {@code AudioSystem} includes a number of methods for
  58  * converting audio data between different formats, and for translating between
  59  * audio files and streams. It also provides a method for obtaining a
  60  * {@link Line} directly from the {@code AudioSystem} without dealing explicitly
  61  * with mixers.
  62  * <p>
  63  * Properties can be used to specify the default mixer for specific line types.
  64  * Both system properties and a properties file are considered. The
  65  * "sound.properties" properties file is read from an implementation-specific
  66  * location (typically it is the {@code conf} directory in the Java installation
  67  * directory). If a property exists both as a system property and in the
  68  * properties file, the system property takes precedence. If none is specified,
  69  * a suitable default is chosen among the available devices. The syntax of the
  70  * properties file is specified in
  71  * {@link Properties#load(InputStream) Properties.load}. The following table
  72  * lists the available property keys and which methods consider them:
  73  *
  74  * <table border=0>
  75  * <caption>Audio System Property Keys</caption>
  76  *   <tr>
  77  *     <th>Property Key
  78  *     <th>Interface
  79  *     <th>Affected Method(s)

  80  *   <tr>
  81  *     <td>{@code javax.sound.sampled.Clip}
  82  *     <td>{@link Clip}
  83  *     <td>{@link #getLine}, {@link #getClip}

  84  *   <tr>
  85  *     <td>{@code javax.sound.sampled.Port}
  86  *     <td>{@link Port}
  87  *     <td>{@link #getLine}

  88  *   <tr>
  89  *     <td>{@code javax.sound.sampled.SourceDataLine}
  90  *     <td>{@link SourceDataLine}
  91  *     <td>{@link #getLine}, {@link #getSourceDataLine}

  92  *   <tr>
  93  *     <td>{@code javax.sound.sampled.TargetDataLine}
  94  *     <td>{@link TargetDataLine}
  95  *     <td>{@link #getLine}, {@link #getTargetDataLine}

  96  * </table>
  97  *
  98  * The property value consists of the provider class name and the mixer name,
  99  * separated by the hash mark (&quot;#&quot;). The provider class name is the
 100  * fully-qualified name of a concrete {@link MixerProvider mixer provider}
 101  * class. The mixer name is matched against the {@code String} returned by the
 102  * {@code getName} method of {@code Mixer.Info}. Either the class name, or the
 103  * mixer name may be omitted. If only the class name is specified, the trailing
 104  * hash mark is optional.
 105  * <p>
 106  * If the provider class is specified, and it can be successfully retrieved from
 107  * the installed providers, the list of {@code Mixer.Info} objects is retrieved
 108  * from the provider. Otherwise, or when these mixers do not provide a
 109  * subsequent match, the list is retrieved from {@link #getMixerInfo} to contain
 110  * all available {@code Mixer.Info} objects.
 111  * <p>
 112  * If a mixer name is specified, the resulting list of {@code Mixer.Info}
 113  * objects is searched: the first one with a matching name, and whose
 114  * {@code Mixer} provides the respective line interface, will be returned. If no
 115  * matching {@code Mixer.Info} object is found, or the mixer name is not
 116  * specified, the first mixer from the resulting list, which provides the
 117  * respective line interface, will be returned.
 118  * <p>
 119  * For example, the property {@code javax.sound.sampled.Clip} with a value
 120  * {@code "com.sun.media.sound.MixerProvider#SunClip"} will have the following
 121  * consequences when {@code getLine} is called requesting a {@code Clip}
 122  * instance: if the class {@code com.sun.media.sound.MixerProvider} exists in
 123  * the list of installed mixer providers, the first {@code Clip} from the first
 124  * mixer with name {@code "SunClip"} will be returned. If it cannot be found,
 125  * the first {@code Clip} from the first mixer of the specified provider will be

 126  * returned, regardless of name. If there is none, the first {@code Clip} from
 127  * the first {@code Mixer} with name {@code "SunClip"} in the list of all mixers
 128  * (as returned by {@code getMixerInfo}) will be returned, or, if not found, the
 129  * first {@code Clip} of the first {@code Mixer} that can be found in the list
 130  * of all mixers is returned. If that fails, too, an
 131  * {@code IllegalArgumentException} is thrown.
 132  *
 133  * @author Kara Kytle
 134  * @author Florian Bomers
 135  * @author Matthias Pfisterer
 136  * @author Kevin P. Smith
 137  * @see AudioFormat
 138  * @see AudioInputStream
 139  * @see Mixer
 140  * @see Line
 141  * @see Line.Info
 142  * @since 1.3
 143  */
 144 public class AudioSystem {
 145 
 146     /**
 147      * An integer that stands for an unknown numeric value. This value is
 148      * appropriate only for signed quantities that do not normally take negative
 149      * values. Examples include file sizes, frame sizes, buffer sizes, and
 150      * sample rates. A number of Java Sound constructors accept a value of


 451                                              AudioSystem.NOT_SPECIFIED,
 452                                              16, 2, 4,
 453                                              AudioSystem.NOT_SPECIFIED, true);
 454         DataLine.Info info = new DataLine.Info(Clip.class, format);
 455         return (Clip) AudioSystem.getLine(info);
 456     }
 457 
 458     /**
 459      * Obtains a clip from the specified mixer that can be used for playing back
 460      * an audio file or an audio stream.
 461      * <p>
 462      * The returned clip must be opened with the {@code open(AudioFormat)} or
 463      * {@code open(AudioInputStream)} method.
 464      * <p>
 465      * This is a high-level method that uses {@code getMixer} and
 466      * {@code getLine} internally.
 467      *
 468      * @param  mixerInfo a {@code Mixer.Info} object representing the desired
 469      *         mixer, or {@code null} for the system default mixer
 470      * @return a clip object from the specified mixer

 471      * @throws LineUnavailableException if a clip is not available from this
 472      *         mixer due to resource restrictions
 473      * @throws SecurityException if a clip is not available from this mixer due
 474      *         to security restrictions
 475      * @throws IllegalArgumentException if the system does not support at least
 476      *         one clip through the specified mixer
 477      * @see #getClip()
 478      * @since 1.5
 479      */
 480     public static Clip getClip(Mixer.Info mixerInfo) throws LineUnavailableException{
 481         AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
 482                                              AudioSystem.NOT_SPECIFIED,
 483                                              16, 2, 4,
 484                                              AudioSystem.NOT_SPECIFIED, true);
 485         DataLine.Info info = new DataLine.Info(Clip.class, format);
 486         Mixer mixer = AudioSystem.getMixer(mixerInfo);
 487         return (Clip) mixer.getLine(info);
 488     }
 489 
 490     /**


 641      * @since 1.5
 642      */
 643     public static TargetDataLine getTargetDataLine(AudioFormat format,
 644                                                    Mixer.Info mixerinfo)
 645         throws LineUnavailableException {
 646 
 647         DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
 648         Mixer mixer = AudioSystem.getMixer(mixerinfo);
 649         return (TargetDataLine) mixer.getLine(info);
 650     }
 651 
 652     // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
 653 
 654     /**
 655      * Obtains the encodings that the system can obtain from an audio input
 656      * stream with the specified encoding using the set of installed format
 657      * converters.
 658      *
 659      * @param  sourceEncoding the encoding for which conversion support is
 660      *         queried
 661      * @return array of encodings. If {@code sourceEncoding} is not supported,
 662      *         an array of length 0 is returned. Otherwise, the array will have
 663      *         a length of at least 1, representing {@code sourceEncoding}
 664      *         (no conversion).
 665      * @throws NullPointerException if {@code sourceEncoding} is {@code null}
 666      */
 667     public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {
 668         Objects.requireNonNull(sourceEncoding);
 669 
 670         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 671         Vector<AudioFormat.Encoding> encodings = new Vector<>();
 672 
 673         AudioFormat.Encoding encs[] = null;
 674 
 675         // gather from all the codecs
 676         for(int i=0; i<codecs.size(); i++ ) {
 677             FormatConversionProvider codec = codecs.get(i);
 678             if( codec.isSourceEncodingSupported( sourceEncoding ) ) {
 679                 encs = codec.getTargetEncodings();
 680                 for (int j = 0; j < encs.length; j++) {
 681                     encodings.addElement( encs[j] );
 682                 }
 683             }


 906      *         valid audio file data recognized by the system
 907      * @throws IOException if an input/output exception occurs
 908      * @throws NullPointerException if {@code stream} is {@code null}
 909      * @see InputStream#markSupported
 910      * @see InputStream#mark
 911      */
 912     public static AudioFileFormat getAudioFileFormat(final InputStream stream)
 913             throws UnsupportedAudioFileException, IOException {
 914         Objects.requireNonNull(stream);
 915 
 916         for (final AudioFileReader reader : getAudioFileReaders()) {
 917             try {
 918                 return reader.getAudioFileFormat(stream);
 919             } catch (final UnsupportedAudioFileException ignored) {
 920             }
 921         }
 922         throw new UnsupportedAudioFileException("Stream of unsupported format");
 923     }
 924 
 925     /**
 926      * Obtains the audio file format of the specified {@code URL}. The
 927      * {@code URL} must point to valid audio file data.
 928      *
 929      * @param  url the {@code URL} from which file format information should be
 930      *         extracted
 931      * @return an {@code AudioFileFormat} object describing the audio file
 932      *         format
 933      * @throws UnsupportedAudioFileException if the {@code URL} does not point
 934      *         to valid audio file data recognized by the system
 935      * @throws IOException if an input/output exception occurs
 936      * @throws NullPointerException if {@code url} is {@code null}
 937      */
 938     public static AudioFileFormat getAudioFileFormat(final URL url)
 939             throws UnsupportedAudioFileException, IOException {
 940         Objects.requireNonNull(url);
 941 
 942         for (final AudioFileReader reader : getAudioFileReaders()) {
 943             try {
 944                 return reader.getAudioFileFormat(url);
 945             } catch (final UnsupportedAudioFileException ignored) {
 946             }
 947         }
 948         throw new UnsupportedAudioFileException("URL of unsupported format");
 949     }
 950 
 951     /**
 952      * Obtains the audio file format of the specified {@code File}. The
 953      * {@code File} must point to valid audio file data.
 954      *


 992      *         valid audio file data recognized by the system
 993      * @throws IOException if an I/O exception occurs
 994      * @throws NullPointerException if {@code stream} is {@code null}
 995      * @see InputStream#markSupported
 996      * @see InputStream#mark
 997      */
 998     public static AudioInputStream getAudioInputStream(final InputStream stream)
 999             throws UnsupportedAudioFileException, IOException {
1000         Objects.requireNonNull(stream);
1001 
1002         for (final AudioFileReader reader : getAudioFileReaders()) {
1003             try {
1004                 return reader.getAudioInputStream(stream);
1005             } catch (final UnsupportedAudioFileException ignored) {
1006             }
1007         }
1008         throw new UnsupportedAudioFileException("Stream of unsupported format");
1009     }
1010 
1011     /**
1012      * Obtains an audio input stream from the {@code URL} provided. The
1013      * {@code URL} must point to valid audio file data.
1014      *
1015      * @param  url the {@code URL} for which the {@code AudioInputStream} should
1016      *         be constructed
1017      * @return an {@code AudioInputStream} object based on the audio file data
1018      *         pointed to by the {@code URL}
1019      * @throws UnsupportedAudioFileException if the {@code URL} does not point
1020      *         to valid audio file data recognized by the system
1021      * @throws IOException if an I/O exception occurs
1022      * @throws NullPointerException if {@code url} is {@code null}
1023      */
1024     public static AudioInputStream getAudioInputStream(final URL url)
1025             throws UnsupportedAudioFileException, IOException {
1026         Objects.requireNonNull(url);
1027 
1028         for (final AudioFileReader reader : getAudioFileReaders()) {
1029             try {
1030                 return reader.getAudioInputStream(url);
1031             } catch (final UnsupportedAudioFileException ignored) {
1032             }
1033         }
1034         throw new UnsupportedAudioFileException("URL of unsupported format");
1035     }
1036 
1037     /**
1038      * Obtains an audio input stream from the provided {@code File}. The
1039      * {@code File} must point to valid audio file data.
1040      *


1092      *         {@code false}
1093      * @throws NullPointerException if {@code fileType} is {@code null}
1094      */
1095     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
1096         Objects.requireNonNull(fileType);
1097         List<AudioFileWriter> providers = getAudioFileWriters();
1098 
1099         for(int i=0; i < providers.size(); i++) {
1100             AudioFileWriter writer = providers.get(i);
1101             if (writer.isFileTypeSupported(fileType)) {
1102                 return true;
1103             }
1104         }
1105         return false;
1106     }
1107 
1108     /**
1109      * Obtains the file types that the system can write from the audio input
1110      * stream specified.
1111      *
1112      * @param  stream the audio input stream for which audio file type support
1113      *         is queried
1114      * @return array of file types. If no file types are supported, an array of
1115      *         length 0 is returned.
1116      * @throws NullPointerException if {@code stream} is {@code null}
1117      */
1118     public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
1119         Objects.requireNonNull(stream);
1120         List<AudioFileWriter> providers = getAudioFileWriters();
1121         Set<AudioFileFormat.Type> returnTypesSet = new HashSet<>();
1122 
1123         for(int i=0; i < providers.size(); i++) {
1124             AudioFileWriter writer = providers.get(i);
1125             AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);
1126             for(int j=0; j < fileTypes.length; j++) {
1127                 returnTypesSet.add(fileTypes[j]);
1128             }
1129         }
1130         AudioFileFormat.Type returnTypes[] =
1131             returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1132         return returnTypes;
1133     }


1146     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
1147                                               AudioInputStream stream) {
1148         Objects.requireNonNull(fileType);
1149         Objects.requireNonNull(stream);
1150         List<AudioFileWriter> providers = getAudioFileWriters();
1151 
1152         for(int i=0; i < providers.size(); i++) {
1153             AudioFileWriter writer = providers.get(i);
1154             if(writer.isFileTypeSupported(fileType, stream)) {
1155                 return true;
1156             }
1157         }
1158         return false;
1159     }
1160 
1161     /**
1162      * Writes a stream of bytes representing an audio file of the specified file
1163      * type to the output stream provided. Some file types require that the
1164      * length be written into the file header; such files cannot be written from
1165      * start to finish unless the length is known in advance. An attempt to
1166      * write a file of such a type will fail with an {@code IOException} if the
1167      * length in the audio file type is {@code AudioSystem.NOT_SPECIFIED}.
1168      *
1169      * @param  stream the audio input stream containing audio data to be written
1170      *         to the file
1171      * @param  fileType the kind of audio file to write
1172      * @param  out the stream to which the file data should be written
1173      * @return the number of bytes written to the output stream
1174      * @throws IOException if an input/output exception occurs
1175      * @throws IllegalArgumentException if the file type is not supported by the
1176      *         system
1177      * @throws NullPointerException if {@code stream} or {@code fileType} or
1178      *         {@code out} are {@code null}
1179      * @see #isFileTypeSupported
1180      * @see #getAudioFileTypes
1181      */
1182     public static int write(final AudioInputStream stream,
1183                             final AudioFileFormat.Type fileType,
1184                             final OutputStream out) throws IOException {
1185         Objects.requireNonNull(stream);
1186         Objects.requireNonNull(fileType);
1187         Objects.requireNonNull(out);


1221                             final File out) throws IOException {
1222         Objects.requireNonNull(stream);
1223         Objects.requireNonNull(fileType);
1224         Objects.requireNonNull(out);
1225 
1226         for (final AudioFileWriter writer : getAudioFileWriters()) {
1227             try {
1228                 return writer.write(stream, fileType, out);
1229             } catch (final IllegalArgumentException ignored) {
1230                 // thrown if this provider cannot write the stream, try next
1231             }
1232         }
1233         throw new IllegalArgumentException(
1234                 "could not write audio file: file type not supported: "
1235                         + fileType);
1236     }
1237 
1238     // METHODS FOR INTERNAL IMPLEMENTATION USE
1239 
1240     /**
1241      * Obtains the list of MixerProviders currently installed on the system.
1242      *
1243      * @return the list of MixerProviders currently installed on the system
1244      */
1245     @SuppressWarnings("unchecked")
1246     private static List<MixerProvider> getMixerProviders() {
1247         return (List<MixerProvider>) getProviders(MixerProvider.class);
1248     }
1249 
1250     /**
1251      * Obtains the set of format converters (codecs, transcoders, etc.) that are
1252      * currently installed on the system.
1253      *
1254      * @return an array of {@link FormatConversionProvider} objects representing
1255      *         the available format converters. If no format converters readers
1256      *         are available on the system, an array of length 0 is returned.
1257      */
1258     @SuppressWarnings("unchecked")
1259     private static List<FormatConversionProvider> getFormatConversionProviders() {
1260         return (List<FormatConversionProvider>) getProviders(FormatConversionProvider.class);
1261     }
1262 
1263     /**


1304 
1305         if (providerClassName != null) {
1306             MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);
1307             if (defaultProvider != null) {
1308                 if (instanceName != null) {
1309                     mixer = getNamedMixer(instanceName, defaultProvider, info);
1310                     if (mixer != null) {
1311                         return mixer;
1312                     }
1313                 } else {
1314                     mixer = getFirstMixer(defaultProvider, info,
1315                                           false /* mixing not required*/);
1316                     if (mixer != null) {
1317                         return mixer;
1318                     }
1319                 }
1320 
1321             }
1322         }
1323 
1324         /*
1325          * Provider class not specified or provider class cannot be found, or
1326          * provider class and instance specified and instance cannot be found or
1327          * is not appropriate
1328          */
1329         if (instanceName != null) {
1330             mixer = getNamedMixer(instanceName, providers, info);
1331             if (mixer != null) {
1332                 return mixer;
1333             }
1334         }
1335 
1336 
1337         /*
1338          * No default are specified, or if something is specified, everything
1339          * failed.
1340          */
1341         return null;
1342     }
1343 
1344     /**
1345      * Return a MixerProvider of a given class from the list of MixerProviders.
1346      * This method never requires the returned Mixer to do mixing.
1347      *
1348      * @param  providerClassName The class name of the provider to be returned
1349      * @param  providers The list of MixerProviders that is searched
1350      * @return A MixerProvider of the requested class, or null if none is found
1351      */
1352     private static MixerProvider getNamedProvider(String providerClassName,
1353                                                   List<MixerProvider> providers) {
1354         for(int i = 0; i < providers.size(); i++) {
1355             MixerProvider provider = providers.get(i);
1356             if (provider.getClass().getName().equals(providerClassName)) {
1357                 return provider;
1358             }
1359         }
1360         return null;


1413      * @param  info The type of line the returned Mixer is required to support
1414      * @param  isMixingRequired If true, only Mixers that support mixing are
1415      *         returned for line types of SourceDataLine and Clip
1416      * @return A Mixer that is considered appropriate, or null if none is found
1417      */
1418     private static Mixer getFirstMixer(MixerProvider provider,
1419                                        Line.Info info,
1420                                        boolean isMixingRequired) {
1421         Mixer.Info[] infos = provider.getMixerInfo();
1422         for (int j = 0; j < infos.length; j++) {
1423             Mixer mixer = provider.getMixer(infos[j]);
1424             if (isAppropriateMixer(mixer, info, isMixingRequired)) {
1425                 return mixer;
1426             }
1427         }
1428         return null;
1429     }
1430 
1431     /**
1432      * Checks if a Mixer is appropriate. A Mixer is considered appropriate if it
1433      * support the given line type. If isMixingRequired is {@code true} and the
1434      * line type is an output one (SourceDataLine, Clip), the mixer is
1435      * appropriate if it supports at least 2 (concurrent) lines of the given
1436      * type.
1437      *
1438      * @param  mixer The mixer to check
1439      * @param  lineInfo The line to check
1440      * @param  isMixingRequired Is the mixing required or not
1441      * @return {@code true} if the mixer is considered appropriate according to
1442      *         the rules given above, {@code false} otherwise
1443      */
1444     private static boolean isAppropriateMixer(Mixer mixer,
1445                                               Line.Info lineInfo,
1446                                               boolean isMixingRequired) {
1447         if (! mixer.isLineSupported(lineInfo)) {
1448             return false;
1449         }
1450         Class<?> lineClass = lineInfo.getLineClass();
1451         if (isMixingRequired
1452             && (SourceDataLine.class.isAssignableFrom(lineClass) ||
1453                 Clip.class.isAssignableFrom(lineClass))) {
1454             int maxLines = mixer.getMaxLines(lineInfo);
1455             return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
1456         }
1457         return true;
1458     }
1459 
1460     /**
1461      * Like getMixerInfo, but return List.
1462      *
1463      * @return a List of info objects for the currently installed mixers. If no
1464      *         mixers are available on the system, an empty List is returned.
1465      * @see #getMixerInfo()
1466      */
1467     private static List<Mixer.Info> getMixerInfoList() {
1468         List<MixerProvider> providers = getMixerProviders();
1469         return getMixerInfoList(providers);
1470     }
1471 
1472     /**
1473      * Like getMixerInfo, but return List.
1474      *
1475      * @param  providers The list of MixerProviders
1476      * @return a List of info objects for the currently installed mixers. If no
1477      *         mixers are available on the system, an empty List is returned.
1478      * @see #getMixerInfo()
1479      */
1480     private static List<Mixer.Info> getMixerInfoList(List<MixerProvider> providers) {
1481         List<Mixer.Info> infos = new ArrayList<>();
1482 
1483         Mixer.Info[] someInfos; // per-mixer
1484         Mixer.Info[] allInfos;  // for all mixers
1485 
1486         for(int i = 0; i < providers.size(); i++ ) {
1487             someInfos = providers.get(i).getMixerInfo();
1488 
1489             for (int j = 0; j < someInfos.length; j++) {
1490                 infos.add(someInfos[j]);
1491             }
1492         }
1493 
1494         return infos;
1495     }
1496 
1497     /**
1498      * Obtains the set of services currently installed on the system using the
1499      * SPI mechanism in 1.3.
1500      *
1501      * @param  providerClass The type of providers requested. This should be one
1502      *         of AudioFileReader.class, AudioFileWriter.class,
1503      *         FormatConversionProvider.class, MixerProvider.class,
1504      *         MidiDeviceProvider.class, MidiFileReader.class,
1505      *         MidiFileWriter.class or SoundbankReader.class.
1506      * @return a List of instances of providers for the requested service. If no
1507      *         providers are available, a vector of length 0 will be returned.
1508      */
1509     private static List<?> getProviders(Class<?> providerClass) {
1510         return JDK13Services.getProviders(providerClass);
1511     }
1512 }
< prev index next >