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