< prev index next >

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

Print this page




   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;


  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 class="striped">
  76  * <caption>Audio System Property Keys</caption>
  77  * <thead>
  78  *  <tr>
  79  *   <th>Property Key</th>
  80  *   <th>Interface</th>
  81  *   <th>Affected Method(s)</th>
  82  *  </tr>
  83  * </thead>
  84  * <tbody>
  85  *  <tr>
  86  *   <td>{@code javax.sound.sampled.Clip}</td>
  87  *   <td>{@link Clip}</td>
  88  *   <td>{@link #getLine}, {@link #getClip}</td>
  89  *  </tr>
  90  *  <tr>
  91  *   <td>{@code javax.sound.sampled.Port}</td>
  92  *   <td>{@link Port}</td>
  93  *   <td>{@link #getLine}</td>
  94  *  </tr>
  95  *  <tr>
  96  *   <td>{@code javax.sound.sampled.SourceDataLine}</td>
  97  *   <td>{@link SourceDataLine}</td>
  98  *   <td>{@link #getLine}, {@link #getSourceDataLine}</td>
  99  *  </tr>
 100  *  <tr>
 101  *   <td>{@code javax.sound.sampled.TargetDataLine}</td>
 102  *   <td>{@link TargetDataLine}</td>
 103  *   <td>{@link #getLine}, {@link #getTargetDataLine}</td>
 104  *  </tr>
 105  * </tbody>
 106  * </table>
 107  *
 108  * The property value consists of the provider class name and the mixer name,
 109  * separated by the hash mark (&quot;#&quot;). The provider class name is the
 110  * fully-qualified name of a concrete {@link MixerProvider mixer provider}
 111  * class. The mixer name is matched against the {@code String} returned by the
 112  * {@code getName} method of {@code Mixer.Info}. Either the class name, or the
 113  * mixer name may be omitted. If only the class name is specified, the trailing
 114  * hash mark is optional.
 115  * <p>
 116  * If the provider class is specified, and it can be successfully retrieved from
 117  * the installed providers, the list of {@code Mixer.Info} objects is retrieved
 118  * from the provider. Otherwise, or when these mixers do not provide a
 119  * subsequent match, the list is retrieved from {@link #getMixerInfo} to contain
 120  * all available {@code Mixer.Info} objects.
 121  * <p>
 122  * If a mixer name is specified, the resulting list of {@code Mixer.Info}
 123  * objects is searched: the first one with a matching name, and whose
 124  * {@code Mixer} provides the respective line interface, will be returned. If no
 125  * matching {@code Mixer.Info} object is found, or the mixer name is not
 126  * specified, the first mixer from the resulting list, which provides the
 127  * respective line interface, will be returned.
 128  *
 129  * For example, the property {@code javax.sound.sampled.Clip} with a value
 130  * {@code "com.sun.media.sound.MixerProvider#SunClip"}
 131  * will have the following consequences when {@code getLine} is called
 132  * requesting a {@code Clip} instance: if the class
 133  * {@code com.sun.media.sound.MixerProvider} exists in the list of installed
 134  * mixer providers, the first {@code Clip} from the first mixer with name
 135  * {@code "SunClip"} will be returned. If it cannot be found, the
 136  * first {@code Clip} from the first mixer of the specified provider will be
 137  * returned, regardless of name. If there is none, the first {@code Clip} from
 138  * the first {@code Mixer} with name {@code "SunClip"} in the list of
 139  * all mixers (as returned by {@code getMixerInfo}) will be returned, or, if not
 140  * found, the first {@code Clip} of the first {@code Mixer} that can be found in
 141  * the list of all mixers is returned. If that fails, too, an
 142  * {@code IllegalArgumentException} is thrown.
 143  *
 144  * @author Kara Kytle
 145  * @author Florian Bomers
 146  * @author Matthias Pfisterer
 147  * @author Kevin P. Smith
 148  * @see AudioFormat
 149  * @see AudioInputStream
 150  * @see Mixer
 151  * @see Line
 152  * @see Line.Info
 153  * @since 1.3
 154  */
 155 public class AudioSystem {
 156 
 157     /**
 158      * An integer that stands for an unknown numeric value. This value is
 159      * appropriate only for signed quantities that do not normally take negative
 160      * values. Examples include file sizes, frame sizes, buffer sizes, and
 161      * sample rates. A number of Java Sound constructors accept a value of


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


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


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


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


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


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


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


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


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


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


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


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




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




1464      */
1465     private static List<Mixer.Info> getMixerInfoList() {
1466         List<MixerProvider> providers = getMixerProviders();
1467         return getMixerInfoList(providers);
1468     }
1469 
1470     /**
1471      * Like getMixerInfo, but return List.





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





1494      * @return a List of instances of providers for the requested service. If no
1495      *         providers are available, a vector of length 0 will be returned.
1496      */
1497     private static List<?> getProviders(Class<?> providerClass) {
1498         return JDK13Services.getProviders(providerClass);
1499     }
1500 }


   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;


  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 class="striped">
  75  * <caption>Audio System Property Keys</caption>
  76  * <thead>
  77  *   <tr>
  78  *     <th>Property Key
  79  *     <th>Interface
  80  *     <th>Affected Method(s)

  81  * </thead>
  82  * <tbody>
  83  *   <tr>
  84  *     <td>{@code javax.sound.sampled.Clip}
  85  *     <td>{@link Clip}
  86  *     <td>{@link #getLine}, {@link #getClip}

  87  *   <tr>
  88  *     <td>{@code javax.sound.sampled.Port}
  89  *     <td>{@link Port}
  90  *     <td>{@link #getLine}

  91  *   <tr>
  92  *     <td>{@code javax.sound.sampled.SourceDataLine}
  93  *     <td>{@link SourceDataLine}
  94  *     <td>{@link #getLine}, {@link #getSourceDataLine}

  95  *   <tr>
  96  *     <td>{@code javax.sound.sampled.TargetDataLine}
  97  *     <td>{@link TargetDataLine}
  98  *     <td>{@link #getLine}, {@link #getTargetDataLine}

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

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


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

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


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


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


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


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


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


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


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


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