0001 /*
0002 * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.sound.sampled;
0027
0028 import java.io.File;
0029 import java.io.InputStream;
0030 import java.io.IOException;
0031 import java.io.OutputStream;
0032 import java.net.URL;
0033
0034 import java.util.HashSet;
0035 import java.util.List;
0036 import java.util.Set;
0037 import java.util.Vector;
0038 import java.util.ArrayList;
0039
0040 import javax.sound.sampled.spi.AudioFileWriter;
0041 import javax.sound.sampled.spi.AudioFileReader;
0042 import javax.sound.sampled.spi.FormatConversionProvider;
0043 import javax.sound.sampled.spi.MixerProvider;
0044
0045 import com.sun.media.sound.JDK13Services;
0046
0047 /* $fb TODO:
0048 * - consistent usage of (typed) collections
0049 */
0050
0051 /**
0052 * The <code>AudioSystem</code> class acts as the entry point to the
0053 * sampled-audio system resources. This class lets you query and
0054 * access the mixers that are installed on the system.
0055 * <code>AudioSystem</code> includes a number of
0056 * methods for converting audio data between different formats, and for
0057 * translating between audio files and streams. It also provides a method
0058 * for obtaining a <code>{@link Line}</code> directly from the
0059 * <code>AudioSystem</code> without dealing explicitly
0060 * with mixers.
0061 *
0062 * <p>Properties can be used to specify the default mixer
0063 * for specific line types.
0064 * Both system properties and a properties file are considered.
0065 * In the Sun reference implementation, the properties file is
0066 * "lib/sound.properties" in the JRE
0067 * directory. If a property exists both as a system property and in the
0068 * properties file, the system property takes precedence. If none is
0069 * specified, a suitable default is chosen among the available devices.
0070 * The syntax of the properties file is specified in
0071 * {@link java.util.Properties#load(InputStream) Properties.load}. The
0072 * following table lists the available property keys and which methods
0073 * consider them:
0074 *
0075 * <table border=0>
0076 * <tr>
0077 * <th>Property Key</th>
0078 * <th>Interface</th>
0079 * <th>Affected Method(s)</th>
0080 * </tr>
0081 * <tr>
0082 * <td><code>javax.sound.sampled.Clip</code></td>
0083 * <td>{@link Clip}</td>
0084 * <td>{@link #getLine}, {@link #getClip}</td>
0085 * </tr>
0086 * <tr>
0087 * <td><code>javax.sound.sampled.Port</code></td>
0088 * <td>{@link Port}</td>
0089 * <td>{@link #getLine}</td>
0090 * </tr>
0091 * <tr>
0092 * <td><code>javax.sound.sampled.SourceDataLine</code></td>
0093 * <td>{@link SourceDataLine}</td>
0094 * <td>{@link #getLine}, {@link #getSourceDataLine}</td>
0095 * </tr>
0096 * <tr>
0097 * <td><code>javax.sound.sampled.TargetDataLine</code></td>
0098 * <td>{@link TargetDataLine}</td>
0099 * <td>{@link #getLine}, {@link #getTargetDataLine}</td>
0100 * </tr>
0101 * </table>
0102 *
0103 * The property value consists of the provider class name
0104 * and the mixer name, separated by the hash mark ("#").
0105 * The provider class name is the fully-qualified
0106 * name of a concrete {@link javax.sound.sampled.spi.MixerProvider
0107 * mixer provider} class. The mixer name is matched against
0108 * the <code>String</code> returned by the <code>getName</code>
0109 * method of <code>Mixer.Info</code>.
0110 * Either the class name, or the mixer name may be omitted.
0111 * If only the class name is specified, the trailing hash mark
0112 * is optional.
0113 *
0114 * <p>If the provider class is specified, and it can be
0115 * successully retrieved from the installed providers, the list of
0116 * <code>Mixer.Info</code> objects is retrieved
0117 * from the provider. Otherwise, or when these mixers
0118 * do not provide a subsequent match, the list is retrieved
0119 * from {@link #getMixerInfo} to contain
0120 * all available <code>Mixer.Info</code> objects.
0121 *
0122 * <p>If a mixer name is specified, the resulting list of
0123 * <code>Mixer.Info</code> objects is searched:
0124 * the first one with a matching name, and whose
0125 * <code>Mixer</code> provides the
0126 * respective line interface, will be returned.
0127 * If no matching <code>Mixer.Info</code> object
0128 * is found, or the mixer name is not specified,
0129 * the first mixer from the resulting
0130 * list, which provides the respective line
0131 * interface, will be returned.
0132 *
0133 * For example, the property <code>javax.sound.sampled.Clip</code>
0134 * with a value
0135 * <code>"com.sun.media.sound.MixerProvider#SunClip"</code>
0136 * will have the following consequences when
0137 * <code>getLine</code> is called requesting a <code>Clip</code>
0138 * instance:
0139 * if the class <code>com.sun.media.sound.MixerProvider</code> exists
0140 * in the list of installed mixer providers,
0141 * the first <code>Clip</code> from the first mixer with name
0142 * <code>"SunClip"</code> will be returned. If it cannot
0143 * be found, the first <code>Clip</code> from the first mixer
0144 * of the specified provider will be returned, regardless of name.
0145 * If there is none, the first <code>Clip</code> from the first
0146 * <code>Mixer</code> with name
0147 * <code>"SunClip"</code> in the list of all mixers
0148 * (as returned by <code>getMixerInfo</code>) will be returned,
0149 * or, if not found, the first <code>Clip</code> of the first
0150 * <code>Mixer</code>that can be found in the list of all
0151 * mixers is returned.
0152 * If that fails, too, an <code>IllegalArgumentException</code>
0153 * is thrown.
0154 *
0155 * @author Kara Kytle
0156 * @author Florian Bomers
0157 * @author Matthias Pfisterer
0158 * @author Kevin P. Smith
0159 * @version 1.89, 07/05/05
0160 *
0161 * @see AudioFormat
0162 * @see AudioInputStream
0163 * @see Mixer
0164 * @see Line
0165 * @see Line.Info
0166 * @since 1.3
0167 */
0168 public class AudioSystem {
0169
0170 /**
0171 * An integer that stands for an unknown numeric value.
0172 * This value is appropriate only for signed quantities that do not
0173 * normally take negative values. Examples include file sizes, frame
0174 * sizes, buffer sizes, and sample rates.
0175 * A number of Java Sound constructors accept
0176 * a value of <code>NOT_SPECIFIED</code> for such parameters. Other
0177 * methods may also accept or return this value, as documented.
0178 */
0179 public static final int NOT_SPECIFIED = -1;
0180
0181 /**
0182 * Private no-args constructor for ensuring against instantiation.
0183 */
0184 private AudioSystem() {
0185 }
0186
0187 /**
0188 * Obtains an array of mixer info objects that represents
0189 * the set of audio mixers that are currently installed on the system.
0190 * @return an array of info objects for the currently installed mixers. If no mixers
0191 * are available on the system, an array of length 0 is returned.
0192 * @see #getMixer
0193 */
0194 public static Mixer.Info[] getMixerInfo() {
0195
0196 List infos = getMixerInfoList();
0197 Mixer.Info[] allInfos = (Mixer.Info[]) infos
0198 .toArray(new Mixer.Info[infos.size()]);
0199 return allInfos;
0200 }
0201
0202 /**
0203 * Obtains the requested audio mixer.
0204 * @param info a <code>Mixer.Info</code> object representing the desired
0205 * mixer, or <code>null</code> for the system default mixer
0206 * @return the requested mixer
0207 * @throws SecurityException if the requested mixer
0208 * is unavailable because of security restrictions
0209 * @throws IllegalArgumentException if the info object does not represent
0210 * a mixer installed on the system
0211 * @see #getMixerInfo
0212 */
0213 public static Mixer getMixer(Mixer.Info info) {
0214
0215 Mixer mixer = null;
0216 List providers = getMixerProviders();
0217
0218 for (int i = 0; i < providers.size(); i++) {
0219
0220 try {
0221 return ((MixerProvider) providers.get(i))
0222 .getMixer(info);
0223
0224 } catch (IllegalArgumentException e) {
0225 } catch (NullPointerException e) {
0226 // $$jb 08.20.99: If the strings in the info object aren't
0227 // set, then Netscape (using jdk1.1.5) tends to throw
0228 // NPE's when doing some string manipulation. This is
0229 // probably not the best fix, but is solves the problem
0230 // of the NPE in Netscape using local classes
0231 // $$jb 11.01.99: Replacing this patch.
0232 }
0233 }
0234
0235 //$$fb if looking for default mixer, and not found yet, add a round of looking
0236 if (info == null) {
0237 for (int i = 0; i < providers.size(); i++) {
0238 try {
0239 MixerProvider provider = (MixerProvider) providers
0240 .get(i);
0241 Mixer.Info[] infos = provider.getMixerInfo();
0242 // start from 0 to last device (do not reverse this order)
0243 for (int ii = 0; ii < infos.length; ii++) {
0244 try {
0245 return provider.getMixer(infos[ii]);
0246 } catch (IllegalArgumentException e) {
0247 // this is not a good default device :)
0248 }
0249 }
0250 } catch (IllegalArgumentException e) {
0251 } catch (NullPointerException e) {
0252 }
0253 }
0254 }
0255
0256 throw new IllegalArgumentException("Mixer not supported: "
0257 + (info != null ? info.toString() : "null"));
0258 }
0259
0260 //$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous
0261 /**
0262 * Obtains information about all source lines of a particular type that are supported
0263 * by the installed mixers.
0264 * @param info a <code>Line.Info</code> object that specifies the kind of
0265 * lines about which information is requested
0266 * @return an array of <code>Line.Info</code> objects describing source lines matching
0267 * the type requested. If no matching source lines are supported, an array of length 0
0268 * is returned.
0269 *
0270 * @see Mixer#getSourceLineInfo(Line.Info)
0271 */
0272 public static Line.Info[] getSourceLineInfo(Line.Info info) {
0273
0274 Vector vector = new Vector();
0275 Line.Info[] currentInfoArray;
0276
0277 Mixer mixer;
0278 Line.Info fullInfo = null;
0279 Mixer.Info[] infoArray = getMixerInfo();
0280
0281 for (int i = 0; i < infoArray.length; i++) {
0282
0283 mixer = getMixer(infoArray[i]);
0284
0285 currentInfoArray = mixer.getSourceLineInfo(info);
0286 for (int j = 0; j < currentInfoArray.length; j++) {
0287 vector.addElement(currentInfoArray[j]);
0288 }
0289 }
0290
0291 Line.Info[] returnedArray = new Line.Info[vector.size()];
0292
0293 for (int i = 0; i < returnedArray.length; i++) {
0294 returnedArray[i] = (Line.Info) vector.get(i);
0295 }
0296
0297 return returnedArray;
0298 }
0299
0300 /**
0301 * Obtains information about all target lines of a particular type that are supported
0302 * by the installed mixers.
0303 * @param info a <code>Line.Info</code> object that specifies the kind of
0304 * lines about which information is requested
0305 * @return an array of <code>Line.Info</code> objects describing target lines matching
0306 * the type requested. If no matching target lines are supported, an array of length 0
0307 * is returned.
0308 *
0309 * @see Mixer#getTargetLineInfo(Line.Info)
0310 */
0311 public static Line.Info[] getTargetLineInfo(Line.Info info) {
0312
0313 Vector vector = new Vector();
0314 Line.Info[] currentInfoArray;
0315
0316 Mixer mixer;
0317 Line.Info fullInfo = null;
0318 Mixer.Info[] infoArray = getMixerInfo();
0319
0320 for (int i = 0; i < infoArray.length; i++) {
0321
0322 mixer = getMixer(infoArray[i]);
0323
0324 currentInfoArray = mixer.getTargetLineInfo(info);
0325 for (int j = 0; j < currentInfoArray.length; j++) {
0326 vector.addElement(currentInfoArray[j]);
0327 }
0328 }
0329
0330 Line.Info[] returnedArray = new Line.Info[vector.size()];
0331
0332 for (int i = 0; i < returnedArray.length; i++) {
0333 returnedArray[i] = (Line.Info) vector.get(i);
0334 }
0335
0336 return returnedArray;
0337 }
0338
0339 /**
0340 * Indicates whether the system supports any lines that match
0341 * the specified <code>Line.Info</code> object. A line is supported if
0342 * any installed mixer supports it.
0343 * @param info a <code>Line.Info</code> object describing the line for which support is queried
0344 * @return <code>true</code> if at least one matching line is
0345 * supported, otherwise <code>false</code>
0346 *
0347 * @see Mixer#isLineSupported(Line.Info)
0348 */
0349 public static boolean isLineSupported(Line.Info info) {
0350
0351 Mixer mixer;
0352 Mixer.Info[] infoArray = getMixerInfo();
0353
0354 for (int i = 0; i < infoArray.length; i++) {
0355
0356 if (infoArray[i] != null) {
0357 mixer = getMixer(infoArray[i]);
0358 if (mixer.isLineSupported(info)) {
0359 return true;
0360 }
0361 }
0362 }
0363
0364 return false;
0365 }
0366
0367 /**
0368 * Obtains a line that matches the description in the specified
0369 * <code>Line.Info</code> object.
0370 *
0371 * <p>If a <code>DataLine</code> is requested, and <code>info</code>
0372 * is an instance of <code>DataLine.Info</code> specifying at least
0373 * one fully qualified audio format, the last one
0374 * will be used as the default format of the returned
0375 * <code>DataLine</code>.
0376 *
0377 * <p>If system properties
0378 * <code>javax.sound.sampled.Clip</code>,
0379 * <code>javax.sound.sampled.Port</code>,
0380 * <code>javax.sound.sampled.SourceDataLine</code> and
0381 * <code>javax.sound.sampled.TargetDataLine</code> are defined
0382 * or they are defined in the file "sound.properties",
0383 * they are used to retrieve default lines.
0384 * For details, refer to the {@link AudioSystem class description}.
0385 *
0386 * If the respective property is not set, or the mixer
0387 * requested in the property is not installed or does not provide the
0388 * requested line, all installed mixers are queried for the
0389 * requested line type. A Line will be returned from the first mixer
0390 * providing the requested line type.
0391 *
0392 * @param info a <code>Line.Info</code> object describing the desired kind of line
0393 * @return a line of the requested kind
0394 *
0395 * @throws LineUnavailableException if a matching line
0396 * is not available due to resource restrictions
0397 * @throws SecurityException if a matching line
0398 * is not available due to security restrictions
0399 * @throws IllegalArgumentException if the system does not
0400 * support at least one line matching the specified
0401 * <code>Line.Info</code> object
0402 * through any installed mixer
0403 */
0404 public static Line getLine(Line.Info info)
0405 throws LineUnavailableException {
0406 LineUnavailableException lue = null;
0407 List providers = getMixerProviders();
0408
0409 // 1: try from default mixer for this line class
0410 try {
0411 Mixer mixer = getDefaultMixer(providers, info);
0412 if (mixer != null && mixer.isLineSupported(info)) {
0413 return mixer.getLine(info);
0414 }
0415 } catch (LineUnavailableException e) {
0416 lue = e;
0417 } catch (IllegalArgumentException iae) {
0418 // must not happen... but better to catch it here,
0419 // if plug-ins are badly written
0420 }
0421
0422 // 2: if that doesn't work, try to find any mixing mixer
0423 for (int i = 0; i < providers.size(); i++) {
0424 MixerProvider provider = (MixerProvider) providers.get(i);
0425 Mixer.Info[] infos = provider.getMixerInfo();
0426
0427 for (int j = 0; j < infos.length; j++) {
0428 try {
0429 Mixer mixer = provider.getMixer(infos[j]);
0430 // see if this is an appropriate mixer which can mix
0431 if (isAppropriateMixer(mixer, info, true)) {
0432 return mixer.getLine(info);
0433 }
0434 } catch (LineUnavailableException e) {
0435 lue = e;
0436 } catch (IllegalArgumentException iae) {
0437 // must not happen... but better to catch it here,
0438 // if plug-ins are badly written
0439 }
0440 }
0441 }
0442
0443 // 3: if that didn't work, try to find any non-mixing mixer
0444 for (int i = 0; i < providers.size(); i++) {
0445 MixerProvider provider = (MixerProvider) providers.get(i);
0446 Mixer.Info[] infos = provider.getMixerInfo();
0447 for (int j = 0; j < infos.length; j++) {
0448 try {
0449 Mixer mixer = provider.getMixer(infos[j]);
0450 // see if this is an appropriate mixer which can mix
0451 if (isAppropriateMixer(mixer, info, false)) {
0452 return mixer.getLine(info);
0453 }
0454 } catch (LineUnavailableException e) {
0455 lue = e;
0456 } catch (IllegalArgumentException iae) {
0457 // must not happen... but better to catch it here,
0458 // if plug-ins are badly written
0459 }
0460 }
0461 }
0462
0463 // if this line was supported but was not available, throw the last
0464 // LineUnavailableException we got (??).
0465 if (lue != null) {
0466 throw lue;
0467 }
0468
0469 // otherwise, the requested line was not supported, so throw
0470 // an Illegal argument exception
0471 throw new IllegalArgumentException("No line matching "
0472 + info.toString() + " is supported.");
0473 }
0474
0475 /**
0476 * Obtains a clip that can be used for playing back
0477 * an audio file or an audio stream. The returned clip
0478 * will be provided by the default system mixer, or,
0479 * if not possible, by any other mixer installed in the
0480 * system that supports a <code>Clip</code>
0481 * object.
0482 *
0483 * <p>The returned clip must be opened with the
0484 * <code>open(AudioFormat)</code> or
0485 * <code>open(AudioInputStream)</code> method.
0486 *
0487 * <p>This is a high-level method that uses <code>getMixer</code>
0488 * and <code>getLine</code> internally.
0489 *
0490 * <p>If the system property
0491 * <code>javax.sound.sampled.Clip</code>
0492 * is defined or it is defined in the file "sound.properties",
0493 * it is used to retrieve the default clip.
0494 * For details, refer to the {@link AudioSystem class description}.
0495 *
0496 * @return the desired clip object
0497 *
0498 * @throws LineUnavailableException if a clip object
0499 * is not available due to resource restrictions
0500 * @throws SecurityException if a clip object
0501 * is not available due to security restrictions
0502 * @throws IllegalArgumentException if the system does not
0503 * support at least one clip instance through any installed mixer
0504 *
0505 * @see #getClip(Mixer.Info)
0506 * @since 1.5
0507 */
0508 public static Clip getClip() throws LineUnavailableException {
0509 AudioFormat format = new AudioFormat(
0510 AudioFormat.Encoding.PCM_SIGNED,
0511 AudioSystem.NOT_SPECIFIED, 16, 2, 4,
0512 AudioSystem.NOT_SPECIFIED, true);
0513 DataLine.Info info = new DataLine.Info(Clip.class, format);
0514 return (Clip) AudioSystem.getLine(info);
0515 }
0516
0517 /**
0518 * Obtains a clip from the specified mixer that can be
0519 * used for playing back an audio file or an audio stream.
0520 *
0521 * <p>The returned clip must be opened with the
0522 * <code>open(AudioFormat)</code> or
0523 * <code>open(AudioInputStream)</code> method.
0524 *
0525 * <p>This is a high-level method that uses <code>getMixer</code>
0526 * and <code>getLine</code> internally.
0527 *
0528 * @param mixerInfo a <code>Mixer.Info</code> object representing the
0529 * desired mixer, or <code>null</code> for the system default mixer
0530 * @return a clip object from the specified mixer
0531 *
0532 * @throws LineUnavailableException if a clip
0533 * is not available from this mixer due to resource restrictions
0534 * @throws SecurityException if a clip
0535 * is not available from this mixer due to security restrictions
0536 * @throws IllegalArgumentException if the system does not
0537 * support at least one clip through the specified mixer
0538 *
0539 * @see #getClip()
0540 * @since 1.5
0541 */
0542 public static Clip getClip(Mixer.Info mixerInfo)
0543 throws LineUnavailableException {
0544 AudioFormat format = new AudioFormat(
0545 AudioFormat.Encoding.PCM_SIGNED,
0546 AudioSystem.NOT_SPECIFIED, 16, 2, 4,
0547 AudioSystem.NOT_SPECIFIED, true);
0548 DataLine.Info info = new DataLine.Info(Clip.class, format);
0549 Mixer mixer = AudioSystem.getMixer(mixerInfo);
0550 return (Clip) mixer.getLine(info);
0551 }
0552
0553 /**
0554 * Obtains a source data line that can be used for playing back
0555 * audio data in the format specified by the
0556 * <code>AudioFormat</code> object. The returned line
0557 * will be provided by the default system mixer, or,
0558 * if not possible, by any other mixer installed in the
0559 * system that supports a matching
0560 * <code>SourceDataLine</code> object.
0561 *
0562 * <p>The returned line should be opened with the
0563 * <code>open(AudioFormat)</code> or
0564 * <code>open(AudioFormat, int)</code> method.
0565 *
0566 * <p>This is a high-level method that uses <code>getMixer</code>
0567 * and <code>getLine</code> internally.
0568 *
0569 * <p>The returned <code>SourceDataLine</code>'s default
0570 * audio format will be initialized with <code>format</code>.
0571 *
0572 * <p>If the system property
0573 * <code>javax.sound.sampled.SourceDataLine</code>
0574 * is defined or it is defined in the file "sound.properties",
0575 * it is used to retrieve the default source data line.
0576 * For details, refer to the {@link AudioSystem class description}.
0577 *
0578 * @param format an <code>AudioFormat</code> object specifying
0579 * the supported audio format of the returned line,
0580 * or <code>null</code> for any audio format
0581 * @return the desired <code>SourceDataLine</code> object
0582 *
0583 * @throws LineUnavailableException if a matching source data line
0584 * is not available due to resource restrictions
0585 * @throws SecurityException if a matching source data line
0586 * is not available due to security restrictions
0587 * @throws IllegalArgumentException if the system does not
0588 * support at least one source data line supporting the
0589 * specified audio format through any installed mixer
0590 *
0591 * @see #getSourceDataLine(AudioFormat, Mixer.Info)
0592 * @since 1.5
0593 */
0594 public static SourceDataLine getSourceDataLine(AudioFormat format)
0595 throws LineUnavailableException {
0596 DataLine.Info info = new DataLine.Info(SourceDataLine.class,
0597 format);
0598 return (SourceDataLine) AudioSystem.getLine(info);
0599 }
0600
0601 /**
0602 * Obtains a source data line that can be used for playing back
0603 * audio data in the format specified by the
0604 * <code>AudioFormat</code> object, provided by the mixer
0605 * specified by the <code>Mixer.Info</code> object.
0606 *
0607 * <p>The returned line should be opened with the
0608 * <code>open(AudioFormat)</code> or
0609 * <code>open(AudioFormat, int)</code> method.
0610 *
0611 * <p>This is a high-level method that uses <code>getMixer</code>
0612 * and <code>getLine</code> internally.
0613 *
0614 * <p>The returned <code>SourceDataLine</code>'s default
0615 * audio format will be initialized with <code>format</code>.
0616 *
0617 * @param format an <code>AudioFormat</code> object specifying
0618 * the supported audio format of the returned line,
0619 * or <code>null</code> for any audio format
0620 * @param mixerinfo a <code>Mixer.Info</code> object representing
0621 * the desired mixer, or <code>null</code> for the system
0622 * default mixer
0623 * @return the desired <code>SourceDataLine</code> object
0624 *
0625 * @throws LineUnavailableException if a matching source data
0626 * line is not available from the specified mixer due
0627 * to resource restrictions
0628 * @throws SecurityException if a matching source data line
0629 * is not available from the specified mixer due to
0630 * security restrictions
0631 * @throws IllegalArgumentException if the specified mixer does
0632 * not support at least one source data line supporting
0633 * the specified audio format
0634 *
0635 * @see #getSourceDataLine(AudioFormat)
0636 * @since 1.5
0637 */
0638 public static SourceDataLine getSourceDataLine(AudioFormat format,
0639 Mixer.Info mixerinfo) throws LineUnavailableException {
0640 DataLine.Info info = new DataLine.Info(SourceDataLine.class,
0641 format);
0642 Mixer mixer = AudioSystem.getMixer(mixerinfo);
0643 return (SourceDataLine) mixer.getLine(info);
0644 }
0645
0646 /**
0647 * Obtains a target data line that can be used for recording
0648 * audio data in the format specified by the
0649 * <code>AudioFormat</code> object. The returned line
0650 * will be provided by the default system mixer, or,
0651 * if not possible, by any other mixer installed in the
0652 * system that supports a matching
0653 * <code>TargetDataLine</code> object.
0654 *
0655 * <p>The returned line should be opened with the
0656 * <code>open(AudioFormat)</code> or
0657 * <code>open(AudioFormat, int)</code> method.
0658 *
0659 * <p>This is a high-level method that uses <code>getMixer</code>
0660 * and <code>getLine</code> internally.
0661 *
0662 * <p>The returned <code>TargetDataLine</code>'s default
0663 * audio format will be initialized with <code>format</code>.
0664 *
0665 * @param format an <code>AudioFormat</code> object specifying
0666 * the supported audio format of the returned line,
0667 * or <code>null</code> for any audio format
0668 * @return the desired <code>TargetDataLine</code> object
0669 *
0670 * @throws LineUnavailableException if a matching target data line
0671 * is not available due to resource restrictions
0672 * @throws SecurityException if a matching target data line
0673 * is not available due to security restrictions
0674 * @throws IllegalArgumentException if the system does not
0675 * support at least one target data line supporting the
0676 * specified audio format through any installed mixer
0677 *
0678 * @see #getTargetDataLine(AudioFormat, Mixer.Info)
0679 * @see AudioPermission
0680 * @since 1.5
0681 */
0682 public static TargetDataLine getTargetDataLine(AudioFormat format)
0683 throws LineUnavailableException {
0684
0685 DataLine.Info info = new DataLine.Info(TargetDataLine.class,
0686 format);
0687 return (TargetDataLine) AudioSystem.getLine(info);
0688 }
0689
0690 /**
0691 * Obtains a target data line that can be used for recording
0692 * audio data in the format specified by the
0693 * <code>AudioFormat</code> object, provided by the mixer
0694 * specified by the <code>Mixer.Info</code> object.
0695 *
0696 * <p>The returned line should be opened with the
0697 * <code>open(AudioFormat)</code> or
0698 * <code>open(AudioFormat, int)</code> method.
0699 *
0700 * <p>This is a high-level method that uses <code>getMixer</code>
0701 * and <code>getLine</code> internally.
0702 *
0703 * <p>The returned <code>TargetDataLine</code>'s default
0704 * audio format will be initialized with <code>format</code>.
0705 *
0706 * <p>If the system property
0707 * <code>javax.sound.sampled.TargetDataLine</code>
0708 * is defined or it is defined in the file "sound.properties",
0709 * it is used to retrieve the default target data line.
0710 * For details, refer to the {@link AudioSystem class description}.
0711 *
0712 * @param format an <code>AudioFormat</code> object specifying
0713 * the supported audio format of the returned line,
0714 * or <code>null</code> for any audio format
0715 * @param mixerinfo a <code>Mixer.Info</code> object representing the
0716 * desired mixer, or <code>null</code> for the system default mixer
0717 * @return the desired <code>TargetDataLine</code> object
0718 *
0719 * @throws LineUnavailableException if a matching target data
0720 * line is not available from the specified mixer due
0721 * to resource restrictions
0722 * @throws SecurityException if a matching target data line
0723 * is not available from the specified mixer due to
0724 * security restrictions
0725 * @throws IllegalArgumentException if the specified mixer does
0726 * not support at least one target data line supporting
0727 * the specified audio format
0728 *
0729 * @see #getTargetDataLine(AudioFormat)
0730 * @see AudioPermission
0731 * @since 1.5
0732 */
0733 public static TargetDataLine getTargetDataLine(AudioFormat format,
0734 Mixer.Info mixerinfo) throws LineUnavailableException {
0735
0736 DataLine.Info info = new DataLine.Info(TargetDataLine.class,
0737 format);
0738 Mixer mixer = AudioSystem.getMixer(mixerinfo);
0739 return (TargetDataLine) mixer.getLine(info);
0740 }
0741
0742 // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
0743 /**
0744 * Obtains the encodings that the system can obtain from an
0745 * audio input stream with the specified encoding using the set
0746 * of installed format converters.
0747 * @param sourceEncoding the encoding for which conversion support
0748 * is queried
0749 * @return array of encodings. If <code>sourceEncoding</code>is not supported,
0750 * an array of length 0 is returned. Otherwise, the array will have a length
0751 * of at least 1, representing <code>sourceEncoding</code> (no conversion).
0752 */
0753 public static AudioFormat.Encoding[] getTargetEncodings(
0754 AudioFormat.Encoding sourceEncoding) {
0755
0756 List codecs = getFormatConversionProviders();
0757 Vector encodings = new Vector();
0758
0759 AudioFormat.Encoding encs[] = null;
0760
0761 // gather from all the codecs
0762 for (int i = 0; i < codecs.size(); i++) {
0763 FormatConversionProvider codec = (FormatConversionProvider) codecs
0764 .get(i);
0765 if (codec.isSourceEncodingSupported(sourceEncoding)) {
0766 encs = codec.getTargetEncodings();
0767 for (int j = 0; j < encs.length; j++) {
0768 encodings.addElement(encs[j]);
0769 }
0770 }
0771 }
0772 AudioFormat.Encoding encs2[] = (AudioFormat.Encoding[]) encodings
0773 .toArray(new AudioFormat.Encoding[0]);
0774 return encs2;
0775 }
0776
0777 // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
0778 /**
0779 * Obtains the encodings that the system can obtain from an
0780 * audio input stream with the specified format using the set
0781 * of installed format converters.
0782 * @param sourceFormat the audio format for which conversion
0783 * is queried
0784 * @return array of encodings. If <code>sourceFormat</code>is not supported,
0785 * an array of length 0 is returned. Otherwise, the array will have a length
0786 * of at least 1, representing the encoding of <code>sourceFormat</code> (no conversion).
0787 */
0788 public static AudioFormat.Encoding[] getTargetEncodings(
0789 AudioFormat sourceFormat) {
0790
0791 List codecs = getFormatConversionProviders();
0792 Vector encodings = new Vector();
0793
0794 int size = 0;
0795 int index = 0;
0796 AudioFormat.Encoding encs[] = null;
0797
0798 // gather from all the codecs
0799
0800 for (int i = 0; i < codecs.size(); i++) {
0801 encs = ((FormatConversionProvider) codecs.get(i))
0802 .getTargetEncodings(sourceFormat);
0803 size += encs.length;
0804 encodings.addElement(encs);
0805 }
0806
0807 // now build a new array
0808
0809 AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];
0810 for (int i = 0; i < encodings.size(); i++) {
0811 encs = (AudioFormat.Encoding[]) (encodings.get(i));
0812 for (int j = 0; j < encs.length; j++) {
0813 encs2[index++] = encs[j];
0814 }
0815 }
0816 return encs2;
0817 }
0818
0819 /**
0820 * Indicates whether an audio input stream of the specified encoding
0821 * can be obtained from an audio input stream that has the specified
0822 * format.
0823 * @param targetEncoding the desired encoding after conversion
0824 * @param sourceFormat the audio format before conversion
0825 * @return <code>true</code> if the conversion is supported,
0826 * otherwise <code>false</code>
0827 */
0828 public static boolean isConversionSupported(
0829 AudioFormat.Encoding targetEncoding,
0830 AudioFormat sourceFormat) {
0831
0832 List codecs = getFormatConversionProviders();
0833
0834 for (int i = 0; i < codecs.size(); i++) {
0835 FormatConversionProvider codec = (FormatConversionProvider) codecs
0836 .get(i);
0837 if (codec.isConversionSupported(targetEncoding,
0838 sourceFormat)) {
0839 return true;
0840 }
0841 }
0842 return false;
0843 }
0844
0845 /**
0846 * Obtains an audio input stream of the indicated encoding, by converting the
0847 * provided audio input stream.
0848 * @param targetEncoding the desired encoding after conversion
0849 * @param sourceStream the stream to be converted
0850 * @return an audio input stream of the indicated encoding
0851 * @throws IllegalArgumentException if the conversion is not supported
0852 * @see #getTargetEncodings(AudioFormat.Encoding)
0853 * @see #getTargetEncodings(AudioFormat)
0854 * @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)
0855 * @see #getAudioInputStream(AudioFormat, AudioInputStream)
0856 */
0857 public static AudioInputStream getAudioInputStream(
0858 AudioFormat.Encoding targetEncoding,
0859 AudioInputStream sourceStream) {
0860
0861 List codecs = getFormatConversionProviders();
0862
0863 for (int i = 0; i < codecs.size(); i++) {
0864 FormatConversionProvider codec = (FormatConversionProvider) codecs
0865 .get(i);
0866 if (codec.isConversionSupported(targetEncoding,
0867 sourceStream.getFormat())) {
0868 return codec.getAudioInputStream(targetEncoding,
0869 sourceStream);
0870 }
0871 }
0872 // we ran out of options, throw an exception
0873 throw new IllegalArgumentException("Unsupported conversion: "
0874 + targetEncoding + " from " + sourceStream.getFormat());
0875 }
0876
0877 /**
0878 * Obtains the formats that have a particular encoding and that the system can
0879 * obtain from a stream of the specified format using the set of
0880 * installed format converters.
0881 * @param targetEncoding the desired encoding after conversion
0882 * @param sourceFormat the audio format before conversion
0883 * @return array of formats. If no formats of the specified
0884 * encoding are supported, an array of length 0 is returned.
0885 */
0886 public static AudioFormat[] getTargetFormats(
0887 AudioFormat.Encoding targetEncoding,
0888 AudioFormat sourceFormat) {
0889
0890 List codecs = getFormatConversionProviders();
0891 Vector formats = new Vector();
0892
0893 int size = 0;
0894 int index = 0;
0895 AudioFormat fmts[] = null;
0896
0897 // gather from all the codecs
0898
0899 for (int i = 0; i < codecs.size(); i++) {
0900 FormatConversionProvider codec = (FormatConversionProvider) codecs
0901 .get(i);
0902 fmts = codec.getTargetFormats(targetEncoding, sourceFormat);
0903 size += fmts.length;
0904 formats.addElement(fmts);
0905 }
0906
0907 // now build a new array
0908
0909 AudioFormat fmts2[] = new AudioFormat[size];
0910 for (int i = 0; i < formats.size(); i++) {
0911 fmts = (AudioFormat[]) (formats.get(i));
0912 for (int j = 0; j < fmts.length; j++) {
0913 fmts2[index++] = fmts[j];
0914 }
0915 }
0916 return fmts2;
0917 }
0918
0919 /**
0920 * Indicates whether an audio input stream of a specified format
0921 * can be obtained from an audio input stream of another specified format.
0922 * @param targetFormat the desired audio format after conversion
0923 * @param sourceFormat the audio format before conversion
0924 * @return <code>true</code> if the conversion is supported,
0925 * otherwise <code>false</code>
0926 */
0927
0928 public static boolean isConversionSupported(
0929 AudioFormat targetFormat, AudioFormat sourceFormat) {
0930
0931 List codecs = getFormatConversionProviders();
0932
0933 for (int i = 0; i < codecs.size(); i++) {
0934 FormatConversionProvider codec = (FormatConversionProvider) codecs
0935 .get(i);
0936 if (codec.isConversionSupported(targetFormat, sourceFormat)) {
0937 return true;
0938 }
0939 }
0940 return false;
0941 }
0942
0943 /**
0944 * Obtains an audio input stream of the indicated format, by converting the
0945 * provided audio input stream.
0946 * @param targetFormat the desired audio format after conversion
0947 * @param sourceStream the stream to be converted
0948 * @return an audio input stream of the indicated format
0949 * @throws IllegalArgumentException if the conversion is not supported
0950 * #see #getTargetEncodings(AudioFormat)
0951 * @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)
0952 * @see #isConversionSupported(AudioFormat, AudioFormat)
0953 * @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)
0954 */
0955 public static AudioInputStream getAudioInputStream(
0956 AudioFormat targetFormat, AudioInputStream sourceStream) {
0957
0958 if (sourceStream.getFormat().matches(targetFormat)) {
0959 return sourceStream;
0960 }
0961
0962 List codecs = getFormatConversionProviders();
0963
0964 for (int i = 0; i < codecs.size(); i++) {
0965 FormatConversionProvider codec = (FormatConversionProvider) codecs
0966 .get(i);
0967 if (codec.isConversionSupported(targetFormat, sourceStream
0968 .getFormat())) {
0969 return codec.getAudioInputStream(targetFormat,
0970 sourceStream);
0971 }
0972 }
0973
0974 // we ran out of options...
0975 throw new IllegalArgumentException("Unsupported conversion: "
0976 + targetFormat + " from " + sourceStream.getFormat());
0977 }
0978
0979 /**
0980 * Obtains the audio file format of the provided input stream. The stream must
0981 * point to valid audio file data. The implementation of this method may require
0982 * multiple parsers to examine the stream to determine whether they support it.
0983 * These parsers must be able to mark the stream, read enough data to determine whether they
0984 * support the stream, and, if not, reset the stream's read pointer to its original
0985 * position. If the input stream does not support these operations, this method may fail
0986 * with an <code>IOException</code>.
0987 * @param stream the input stream from which file format information should be
0988 * extracted
0989 * @return an <code>AudioFileFormat</code> object describing the stream's audio file format
0990 * @throws UnsupportedAudioFileException if the stream does not point to valid audio
0991 * file data recognized by the system
0992 * @throws IOException if an input/output exception occurs
0993 * @see InputStream#markSupported
0994 * @see InputStream#mark
0995 */
0996 public static AudioFileFormat getAudioFileFormat(InputStream stream)
0997 throws UnsupportedAudioFileException, IOException {
0998
0999 List providers = getAudioFileReaders();
1000 AudioFileFormat format = null;
1001
1002 for (int i = 0; i < providers.size(); i++) {
1003 AudioFileReader reader = (AudioFileReader) providers.get(i);
1004 try {
1005 format = reader.getAudioFileFormat(stream); // throws IOException
1006 break;
1007 } catch (UnsupportedAudioFileException e) {
1008 continue;
1009 }
1010 }
1011
1012 if (format == null) {
1013 throw new UnsupportedAudioFileException(
1014 "file is not a supported file type");
1015 } else {
1016 return format;
1017 }
1018 }
1019
1020 /**
1021 * Obtains the audio file format of the specified URL. The URL must
1022 * point to valid audio file data.
1023 * @param url the URL from which file format information should be
1024 * extracted
1025 * @return an <code>AudioFileFormat</code> object describing the audio file format
1026 * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1027 * file data recognized by the system
1028 * @throws IOException if an input/output exception occurs
1029 */
1030 public static AudioFileFormat getAudioFileFormat(URL url)
1031 throws UnsupportedAudioFileException, IOException {
1032
1033 List providers = getAudioFileReaders();
1034 AudioFileFormat format = null;
1035
1036 for (int i = 0; i < providers.size(); i++) {
1037 AudioFileReader reader = (AudioFileReader) providers.get(i);
1038 try {
1039 format = reader.getAudioFileFormat(url); // throws IOException
1040 break;
1041 } catch (UnsupportedAudioFileException e) {
1042 continue;
1043 }
1044 }
1045
1046 if (format == null) {
1047 throw new UnsupportedAudioFileException(
1048 "file is not a supported file type");
1049 } else {
1050 return format;
1051 }
1052 }
1053
1054 /**
1055 * Obtains the audio file format of the specified <code>File</code>. The <code>File</code> must
1056 * point to valid audio file data.
1057 * @param file the <code>File</code> from which file format information should be
1058 * extracted
1059 * @return an <code>AudioFileFormat</code> object describing the audio file format
1060 * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1061 * file data recognized by the system
1062 * @throws IOException if an I/O exception occurs
1063 */
1064 public static AudioFileFormat getAudioFileFormat(File file)
1065 throws UnsupportedAudioFileException, IOException {
1066
1067 List providers = getAudioFileReaders();
1068 AudioFileFormat format = null;
1069
1070 for (int i = 0; i < providers.size(); i++) {
1071 AudioFileReader reader = (AudioFileReader) providers.get(i);
1072 try {
1073 format = reader.getAudioFileFormat(file); // throws IOException
1074 break;
1075 } catch (UnsupportedAudioFileException e) {
1076 continue;
1077 }
1078 }
1079
1080 if (format == null) {
1081 throw new UnsupportedAudioFileException(
1082 "file is not a supported file type");
1083 } else {
1084 return format;
1085 }
1086 }
1087
1088 /**
1089 * Obtains an audio input stream from the provided input stream. The stream must
1090 * point to valid audio file data. The implementation of this method may
1091 * require multiple parsers to
1092 * examine the stream to determine whether they support it. These parsers must
1093 * be able to mark the stream, read enough data to determine whether they
1094 * support the stream, and, if not, reset the stream's read pointer to its original
1095 * position. If the input stream does not support these operation, this method may fail
1096 * with an <code>IOException</code>.
1097 * @param stream the input stream from which the <code>AudioInputStream</code> should be
1098 * constructed
1099 * @return an <code>AudioInputStream</code> object based on the audio file data contained
1100 * in the input stream.
1101 * @throws UnsupportedAudioFileException if the stream does not point to valid audio
1102 * file data recognized by the system
1103 * @throws IOException if an I/O exception occurs
1104 * @see InputStream#markSupported
1105 * @see InputStream#mark
1106 */
1107 public static AudioInputStream getAudioInputStream(
1108 InputStream stream) throws UnsupportedAudioFileException,
1109 IOException {
1110
1111 List providers = getAudioFileReaders();
1112 AudioInputStream audioStream = null;
1113
1114 for (int i = 0; i < providers.size(); i++) {
1115 AudioFileReader reader = (AudioFileReader) providers.get(i);
1116 try {
1117 audioStream = reader.getAudioInputStream(stream); // throws IOException
1118 break;
1119 } catch (UnsupportedAudioFileException e) {
1120 continue;
1121 }
1122 }
1123
1124 if (audioStream == null) {
1125 throw new UnsupportedAudioFileException(
1126 "could not get audio input stream from input stream");
1127 } else {
1128 return audioStream;
1129 }
1130 }
1131
1132 /**
1133 * Obtains an audio input stream from the URL provided. The URL must
1134 * point to valid audio file data.
1135 * @param url the URL for which the <code>AudioInputStream</code> should be
1136 * constructed
1137 * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1138 * to by the URL
1139 * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1140 * file data recognized by the system
1141 * @throws IOException if an I/O exception occurs
1142 */
1143 public static AudioInputStream getAudioInputStream(URL url)
1144 throws UnsupportedAudioFileException, IOException {
1145
1146 List providers = getAudioFileReaders();
1147 AudioInputStream audioStream = null;
1148
1149 for (int i = 0; i < providers.size(); i++) {
1150 AudioFileReader reader = (AudioFileReader) providers.get(i);
1151 try {
1152 audioStream = reader.getAudioInputStream(url); // throws IOException
1153 break;
1154 } catch (UnsupportedAudioFileException e) {
1155 continue;
1156 }
1157 }
1158
1159 if (audioStream == null) {
1160 throw new UnsupportedAudioFileException(
1161 "could not get audio input stream from input URL");
1162 } else {
1163 return audioStream;
1164 }
1165 }
1166
1167 /**
1168 * Obtains an audio input stream from the provided <code>File</code>. The <code>File</code> must
1169 * point to valid audio file data.
1170 * @param file the <code>File</code> for which the <code>AudioInputStream</code> should be
1171 * constructed
1172 * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1173 * to by the <code>File</code>
1174 * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1175 * file data recognized by the system
1176 * @throws IOException if an I/O exception occurs
1177 */
1178 public static AudioInputStream getAudioInputStream(File file)
1179 throws UnsupportedAudioFileException, IOException {
1180
1181 List providers = getAudioFileReaders();
1182 AudioInputStream audioStream = null;
1183
1184 for (int i = 0; i < providers.size(); i++) {
1185 AudioFileReader reader = (AudioFileReader) providers.get(i);
1186 try {
1187 audioStream = reader.getAudioInputStream(file); // throws IOException
1188 break;
1189 } catch (UnsupportedAudioFileException e) {
1190 continue;
1191 }
1192 }
1193
1194 if (audioStream == null) {
1195 throw new UnsupportedAudioFileException(
1196 "could not get audio input stream from input file");
1197 } else {
1198 return audioStream;
1199 }
1200 }
1201
1202 /**
1203 * Obtains the file types for which file writing support is provided by the system.
1204 * @return array of unique file types. If no file types are supported,
1205 * an array of length 0 is returned.
1206 */
1207 public static AudioFileFormat.Type[] getAudioFileTypes() {
1208 List providers = getAudioFileWriters();
1209 Set returnTypesSet = new HashSet();
1210
1211 for (int i = 0; i < providers.size(); i++) {
1212 AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1213 AudioFileFormat.Type[] fileTypes = writer
1214 .getAudioFileTypes();
1215 for (int j = 0; j < fileTypes.length; j++) {
1216 returnTypesSet.add(fileTypes[j]);
1217 }
1218 }
1219 AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[]) returnTypesSet
1220 .toArray(new AudioFileFormat.Type[0]);
1221 return returnTypes;
1222 }
1223
1224 /**
1225 * Indicates whether file writing support for the specified file type is provided
1226 * by the system.
1227 * @param fileType the file type for which write capabilities are queried
1228 * @return <code>true</code> if the file type is supported,
1229 * otherwise <code>false</code>
1230 */
1231 public static boolean isFileTypeSupported(
1232 AudioFileFormat.Type fileType) {
1233
1234 List providers = getAudioFileWriters();
1235
1236 for (int i = 0; i < providers.size(); i++) {
1237 AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1238 if (writer.isFileTypeSupported(fileType)) {
1239 return true;
1240 }
1241 }
1242 return false;
1243 }
1244
1245 /**
1246 * Obtains the file types that the system can write from the
1247 * audio input stream specified.
1248 * @param stream the audio input stream for which audio file type support
1249 * is queried
1250 * @return array of file types. If no file types are supported,
1251 * an array of length 0 is returned.
1252 */
1253 public static AudioFileFormat.Type[] getAudioFileTypes(
1254 AudioInputStream stream) {
1255 List providers = getAudioFileWriters();
1256 Set returnTypesSet = new HashSet();
1257
1258 for (int i = 0; i < providers.size(); i++) {
1259 AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1260 AudioFileFormat.Type[] fileTypes = writer
1261 .getAudioFileTypes(stream);
1262 for (int j = 0; j < fileTypes.length; j++) {
1263 returnTypesSet.add(fileTypes[j]);
1264 }
1265 }
1266 AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[]) returnTypesSet
1267 .toArray(new AudioFileFormat.Type[0]);
1268 return returnTypes;
1269 }
1270
1271 /**
1272 * Indicates whether an audio file of the specified file type can be written
1273 * from the indicated audio input stream.
1274 * @param fileType the file type for which write capabilities are queried
1275 * @param stream the stream for which file-writing support is queried
1276 * @return <code>true</code> if the file type is supported for this audio input stream,
1277 * otherwise <code>false</code>
1278 */
1279 public static boolean isFileTypeSupported(
1280 AudioFileFormat.Type fileType, AudioInputStream stream) {
1281
1282 List providers = getAudioFileWriters();
1283
1284 for (int i = 0; i < providers.size(); i++) {
1285 AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1286 if (writer.isFileTypeSupported(fileType, stream)) {
1287 return true;
1288 }
1289 }
1290 return false;
1291 }
1292
1293 /**
1294 * Writes a stream of bytes representing an audio file of the specified file type
1295 * to the output stream provided. Some file types require that
1296 * the length be written into the file header; such files cannot be written from
1297 * start to finish unless the length is known in advance. An attempt
1298 * to write a file of such a type will fail with an IOException if the length in
1299 * the audio file type is <code>AudioSystem.NOT_SPECIFIED</code>.
1300 *
1301 * @param stream the audio input stream containing audio data to be
1302 * written to the file
1303 * @param fileType the kind of audio file to write
1304 * @param out the stream to which the file data should be written
1305 * @return the number of bytes written to the output stream
1306 * @throws IOException if an input/output exception occurs
1307 * @throws IllegalArgumentException if the file type is not supported by
1308 * the system
1309 * @see #isFileTypeSupported
1310 * @see #getAudioFileTypes
1311 */
1312 public static int write(AudioInputStream stream,
1313 AudioFileFormat.Type fileType, OutputStream out)
1314 throws IOException {
1315
1316 List providers = getAudioFileWriters();
1317 int bytesWritten = 0;
1318 boolean flag = false;
1319
1320 for (int i = 0; i < providers.size(); i++) {
1321 AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1322 try {
1323 bytesWritten = writer.write(stream, fileType, out); // throws IOException
1324 flag = true;
1325 break;
1326 } catch (IllegalArgumentException e) {
1327 // thrown if this provider cannot write the sequence, try the next
1328 continue;
1329 }
1330 }
1331 if (!flag) {
1332 throw new IllegalArgumentException(
1333 "could not write audio file: file type not supported: "
1334 + fileType);
1335 } else {
1336 return bytesWritten;
1337 }
1338 }
1339
1340 /**
1341 * Writes a stream of bytes representing an audio file of the specified file type
1342 * to the external file provided.
1343 * @param stream the audio input stream containing audio data to be
1344 * written to the file
1345 * @param fileType the kind of audio file to write
1346 * @param out the external file to which the file data should be written
1347 * @return the number of bytes written to the file
1348 * @throws IOException if an I/O exception occurs
1349 * @throws IllegalArgumentException if the file type is not supported by
1350 * the system
1351 * @see #isFileTypeSupported
1352 * @see #getAudioFileTypes
1353 */
1354 public static int write(AudioInputStream stream,
1355 AudioFileFormat.Type fileType, File out) throws IOException {
1356
1357 List providers = getAudioFileWriters();
1358 int bytesWritten = 0;
1359 boolean flag = false;
1360
1361 for (int i = 0; i < providers.size(); i++) {
1362 AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1363 try {
1364 bytesWritten = writer.write(stream, fileType, out); // throws IOException
1365 flag = true;
1366 break;
1367 } catch (IllegalArgumentException e) {
1368 // thrown if this provider cannot write the sequence, try the next
1369 continue;
1370 }
1371 }
1372 if (!flag) {
1373 throw new IllegalArgumentException(
1374 "could not write audio file: file type not supported: "
1375 + fileType);
1376 } else {
1377 return bytesWritten;
1378 }
1379 }
1380
1381 // METHODS FOR INTERNAL IMPLEMENTATION USE
1382
1383 /**
1384 * Obtains the set of MixerProviders on the system.
1385 */
1386 private static List getMixerProviders() {
1387 return getProviders(MixerProvider.class);
1388 }
1389
1390 /**
1391 * Obtains the set of format converters (codecs, transcoders, etc.)
1392 * that are currently installed on the system.
1393 * @return an array of
1394 * {@link javax.sound.sampled.spi.FormatConversionProvider
1395 * FormatConversionProvider}
1396 * objects representing the available format converters. If no format
1397 * converters readers are available on the system, an array of length 0 is
1398 * returned.
1399 */
1400 private static List getFormatConversionProviders() {
1401 return getProviders(FormatConversionProvider.class);
1402 }
1403
1404 /**
1405 * Obtains the set of audio file readers that are currently installed on the system.
1406 * @return a List of
1407 * {@link javax.sound.sampled.spi.AudioFileReader
1408 * AudioFileReader}
1409 * objects representing the installed audio file readers. If no audio file
1410 * readers are available on the system, an empty List is returned.
1411 */
1412 private static List getAudioFileReaders() {
1413 return getProviders(AudioFileReader.class);
1414 }
1415
1416 /**
1417 * Obtains the set of audio file writers that are currently installed on the system.
1418 * @return a List of
1419 * {@link javax.sound.samples.spi.AudioFileWriter AudioFileWriter}
1420 * objects representing the available audio file writers. If no audio file
1421 * writers are available on the system, an empty List is returned.
1422 */
1423 private static List getAudioFileWriters() {
1424 return getProviders(AudioFileWriter.class);
1425 }
1426
1427 /** Attempts to locate and return a default Mixer that provides lines
1428 * of the specified type.
1429 *
1430 * @param providers the installed mixer providers
1431 * @param info The requested line type
1432 * TargetDataLine.class, Clip.class or Port.class.
1433 * @return a Mixer that matches the requirements, or null if no default mixer found
1434 */
1435 private static Mixer getDefaultMixer(List providers, Line.Info info) {
1436 Class lineClass = info.getLineClass();
1437 String providerClassName = JDK13Services
1438 .getDefaultProviderClassName(lineClass);
1439 String instanceName = JDK13Services
1440 .getDefaultInstanceName(lineClass);
1441 Mixer mixer;
1442
1443 if (providerClassName != null) {
1444 MixerProvider defaultProvider = getNamedProvider(
1445 providerClassName, providers);
1446 if (defaultProvider != null) {
1447 if (instanceName != null) {
1448 mixer = getNamedMixer(instanceName,
1449 defaultProvider, info);
1450 if (mixer != null) {
1451 return mixer;
1452 }
1453 } else {
1454 mixer = getFirstMixer(defaultProvider, info, false /* mixing not required*/);
1455 if (mixer != null) {
1456 return mixer;
1457 }
1458 }
1459
1460 }
1461 }
1462
1463 /* Provider class not specified or
1464 provider class cannot be found, or
1465 provider class and instance specified and instance cannot be found or is not appropriate */
1466 if (instanceName != null) {
1467 mixer = getNamedMixer(instanceName, providers, info);
1468 if (mixer != null) {
1469 return mixer;
1470 }
1471 }
1472
1473 /* No default are specified, or if something is specified, everything
1474 failed. */
1475 return null;
1476 }
1477
1478 /** Return a MixerProvider of a given class from the list of
1479 MixerProviders.
1480
1481 This method never requires the returned Mixer to do mixing.
1482 @param providerClassName The class name of the provider to be returned.
1483 @param providers The list of MixerProviders that is searched.
1484 @return A MixerProvider of the requested class, or null if none is
1485 found.
1486 */
1487 private static MixerProvider getNamedProvider(
1488 String providerClassName, List providers) {
1489 for (int i = 0; i < providers.size(); i++) {
1490 MixerProvider provider = (MixerProvider) providers.get(i);
1491 if (provider.getClass().getName().equals(providerClassName)) {
1492 return provider;
1493 }
1494 }
1495 return null;
1496 }
1497
1498 /** Return a Mixer with a given name from a given MixerProvider.
1499 This method never requires the returned Mixer to do mixing.
1500 @param mixerName The name of the Mixer to be returned.
1501 @param provider The MixerProvider to check for Mixers.
1502 @param info The type of line the returned Mixer is required to
1503 support.
1504
1505 @return A Mixer matching the requirements, or null if none is found.
1506 */
1507 private static Mixer getNamedMixer(String mixerName,
1508 MixerProvider provider, Line.Info info) {
1509 Mixer.Info[] infos = provider.getMixerInfo();
1510 for (int i = 0; i < infos.length; i++) {
1511 if (infos[i].getName().equals(mixerName)) {
1512 Mixer mixer = provider.getMixer(infos[i]);
1513 if (isAppropriateMixer(mixer, info, false)) {
1514 return mixer;
1515 }
1516 }
1517 }
1518 return null;
1519 }
1520
1521 /** From a List of MixerProviders, return a Mixer with a given name.
1522 This method never requires the returned Mixer to do mixing.
1523 @param mixerName The name of the Mixer to be returned.
1524 @param providers The List of MixerProviders to check for Mixers.
1525 @param info The type of line the returned Mixer is required to
1526 support.
1527 @return A Mixer matching the requirements, or null if none is found.
1528 */
1529 private static Mixer getNamedMixer(String mixerName,
1530 List providers, Line.Info info) {
1531 for (int i = 0; i < providers.size(); i++) {
1532 MixerProvider provider = (MixerProvider) providers.get(i);
1533 Mixer mixer = getNamedMixer(mixerName, provider, info);
1534 if (mixer != null) {
1535 return mixer;
1536 }
1537 }
1538 return null;
1539 }
1540
1541 /** From a given MixerProvider, return the first appropriate Mixer.
1542 @param provider The MixerProvider to check for Mixers.
1543 @param info The type of line the returned Mixer is required to
1544 support.
1545 @param isMixingRequired If true, only Mixers that support mixing are
1546 returned for line types of SourceDataLine and Clip.
1547
1548 @return A Mixer that is considered appropriate, or null
1549 if none is found.
1550 */
1551 private static Mixer getFirstMixer(MixerProvider provider,
1552 Line.Info info, boolean isMixingRequired) {
1553 Mixer.Info[] infos = provider.getMixerInfo();
1554 for (int j = 0; j < infos.length; j++) {
1555 Mixer mixer = provider.getMixer(infos[j]);
1556 if (isAppropriateMixer(mixer, info, isMixingRequired)) {
1557 return mixer;
1558 }
1559 }
1560 return null;
1561 }
1562
1563 /** Checks if a Mixer is appropriate.
1564 A Mixer is considered appropriate if it support the given line type.
1565 If isMixingRequired is true and the line type is an output one
1566 (SourceDataLine, Clip), the mixer is appropriate if it supports
1567 at least 2 (concurrent) lines of the given type.
1568
1569 @return true if the mixer is considered appropriate according to the
1570 rules given above, false otherwise.
1571 */
1572 private static boolean isAppropriateMixer(Mixer mixer,
1573 Line.Info lineInfo, boolean isMixingRequired) {
1574 if (!mixer.isLineSupported(lineInfo)) {
1575 return false;
1576 }
1577 Class lineClass = lineInfo.getLineClass();
1578 if (isMixingRequired
1579 && (SourceDataLine.class.isAssignableFrom(lineClass) || Clip.class
1580 .isAssignableFrom(lineClass))) {
1581 int maxLines = mixer.getMaxLines(lineInfo);
1582 return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
1583 }
1584 return true;
1585 }
1586
1587 /**
1588 * Like getMixerInfo, but return List
1589 */
1590 private static List getMixerInfoList() {
1591 List providers = getMixerProviders();
1592 return getMixerInfoList(providers);
1593 }
1594
1595 /**
1596 * Like getMixerInfo, but return List
1597 */
1598 private static List getMixerInfoList(List providers) {
1599 List infos = new ArrayList();
1600
1601 Mixer.Info[] someInfos; // per-mixer
1602 Mixer.Info[] allInfos; // for all mixers
1603
1604 for (int i = 0; i < providers.size(); i++) {
1605 someInfos = (Mixer.Info[]) ((MixerProvider) providers
1606 .get(i)).getMixerInfo();
1607
1608 for (int j = 0; j < someInfos.length; j++) {
1609 infos.add(someInfos[j]);
1610 }
1611 }
1612
1613 return infos;
1614 }
1615
1616 /**
1617 * Obtains the set of services currently installed on the system
1618 * using sun.misc.Service, the SPI mechanism in 1.3.
1619 * @return a List of instances of providers for the requested service.
1620 * If no providers are available, a vector of length 0 will be returned.
1621 */
1622 private static List getProviders(Class providerClass) {
1623 return JDK13Services.getProviders(providerClass);
1624 }
1625 }
|