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 ("#"). 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 ("#"). 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 }
|